diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..2a6af7156 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +Telegram/GeneratedFiles/ +Telegram/*.user +Telegram.*.suo +Telegram.sdf +Telegram.opensdf +Win32/ +ipch/ + +Telegram/log.txt +Telegram/data +Telegram/data_config +Telegram/DebugLogs/ +Telegram/tdata/ +Telegram/tdumps/ diff --git a/README.md b/README.md index 602727044..62d3eda88 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,198 @@ -tdesktop -======== +## [Telegram D](https://tdesktop.com) – Unofficial Telegram Desktop App -Telegram Desktop messaging app +This is complete source code and build instructions for alpha version of unofficial desktop client for [Telegram](https://telegram.org) messenger, based on [Telegram API](https://core.telegram.org/) and [MTProto](https://core.telegram.org/mtproto) secure protocol. + +###Supported systems + +Only Windows systems are supported at this moment, OS X and Linux builds are on their way. + +* Windows XP +* Windows Vista +* Windows 7 +* Windows 8 (**not** RT) +* Windows 8.1 (**not** RT) + +###Third-party libraries + +* Qt 5.3.0, slightly patched +* OpenSSL 1.0.1g +* zlib 1.2.8 +* libexif 0.6.20 +* LZMA SDK 9.20 + +##Build instructions for Visual Studio 2013 + +###Prepare folder + +Choose a folder for the future build, for example **D:\TBuild\**. There you will have two folders, **Libraries** for third-party libs and **tdesktop** (or **tdesktop-master**) for the app. + +###Clone source code + +By git – in [Git Bash](http://git-scm.com/downloads) go to **/d/tbuild** and run + + git clone https://github.com/telegramdesktop/tdesktop.git + +or download in ZIP and extract to **D:\TBuild\**, rename **tdesktop-master** to **tdesktop** to have **D:\TBuild\tdesktop\Telegram.sln** solution + +###Prepare libraries + +####OpenSSL 1.0.1g + +https://www.openssl.org/related/binaries.html > **OpenSSL for Windows** > Download [**Win32 OpenSSL v1.0.1g** (16 Mb)](http://slproweb.com/download/Win32OpenSSL-1_0_1g.exe) + +Install to **D:\TBuild\Libraries\OpenSSL-Win32**, while installing **Copy OpenSSL DLLs to** choose **The OpenSSL binaries (/bin) directory** + +####LZMA SDK 9.20 + +http://www.7-zip.org/sdk.html > Download [**LZMA SDK (C, C++, C#, Java)** 9.20](http://downloads.sourceforge.net/sevenzip/lzma920.tar.bz2) + +Extract to **D:\TBuild\Libraries** + +#####Building library + +* Open in VS2013 **D:\TBuild\Libraries\lzma\C\Util\LzmaLib\LzmaLib.dsw** > One-way upgrade – **OK** +* For **Debug** and **Release** configurations + * LzmaLib Properties > General > Configuration Type = **Static library (.lib)** – **OK** + * LzmaLib Properties > Librarian > General > Target Machine = **MachineX86 (/MACHINE:X86)** – **OK** +* Build Debug configuration +* Build Release configuration + +####zlib 1.2.8 + +http://www.zlib.net/ > Download [**zlib source code, version 1.2.8, zipfile format**](http://zlib.net/zlib128.zip) + +Extract to **D:\TBuild\Libraries\** + +#####Building library + +* Open in VS2013 **D:\TBuild\Libraries\zlib-1.2.8\contrib\vstudio\vc11\zlibvc.sln** > One-way upgrade – **OK** +* We are interested only in **zlibstat** project, but it depends on some custom pre-build step, so build all +* For **Debug** configuration + * zlibstat Properties > C/C++ > Code Generation > Runtime Library = **Multi-threaded Debug (/MTd)** – **OK** +* For **Release** configuration + * zlibstat Properties > C/C++ > Code Generation > Runtime Library = **Multi-threaded (/MT)** – **OK** +* Build Solution for Debug configuration – only **zlibstat** project builds successfully +* Build Solution for Release configuration – only **zlibstat** project builds successfully + +####libexif 0.6.20 + +Get sources from https://github.com/telegramdesktop/libexif-0.6.20, by git – in [Git Bash](http://git-scm.com/downloads) go to **/d/tbuild/libraries** and run + + git clone https://github.com/telegramdesktop/libexif-0.6.20.git + +or download in ZIP and extract to **D:\TBuild\Libraries\**, rename **libexif-0.6.20-master** to **libexif-0.6.20** to have **D:\TBuild\Libraries\libexif-0.6.20\win32\lib_exif.sln** solution + +#####Building library + +* Open in VS2013 **D:\TBuild\Libraries\libexif-0.6.20\win32\lib_exif.sln** +* Build Debug configuration +* Build Release configuration + +####Qt 5.3.0, slightly patched + +http://download.qt-project.org/official_releases/qt/5.3/5.3.0/single/qt-everywhere-opensource-src-5.3.0.zip + +Extract to **D:\TBuild\Libraries\**, rename **qt-everywhere-opensource-src-5.3.0** to **QtStatic** to have **D:\TBuild\Libraries\QtStatic\qtbase\** folder + +Apply patch – copy (with overwrite!) everything from **D:\TBuild\tdesktop\\\_qt\_5\_3\_0\_patch\** to **D:\TBuild\Libraries\QtStatic\** + +#####Building library + +* Install Python 3.3.2 from https://www.python.org/download/releases/3.3.2 > [**Windows x86 MSI Installer (3.3.2)**](https://www.python.org/ftp/python/3.3.2/python-3.3.2.msi) +* Open **VS2013 x86 Native Tools Command Prompt.bat** (should be in **\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\Shortcuts\** folder) + +There go to Qt directory + + D: + cd TBuild\Libraries\QtStatic + +and after that run configure + + configure -debug-and-release -opensource -static -opengl desktop -mp -nomake examples -platform win32-msvc2013 + y + +to configure Qt build. After configuration is complete run + + nmake + nmake install + +building (**nmake** command) will take really long time. + +####Qt Visual Studio Addin 1.2.3 + +http://download.qt-project.org/official_releases/vsaddin/qt-vs-addin-1.2.3-opensource.exe + +Close all VS2013 instances and install to default location + +###Building Telegram Desktop + +* Launch VS2013 for configuring Qt Addin +* QT5 > Qt Options > Add + * Version name: **QtStatic.5.3.0** + * Path: **D:\TBuild\Libraries\QtStatic\qtbase** +* Default Qt/Win version: **QtStatic.5.3.0** – **OK** +* File > Open > Project/Solution > **D:\TBuild\tdesktop\Telegram.sln** +* Build \ Build Solution (Debug and Release configurations) + +##Projects in Telegram solution + +####Telegram + +tdesktop messenger + +####Updater + +little app, that is launched by Telegram when update is ready, replaces all files and launches it back + +####Packer + +compiles given files to single update file, compresses it with lzma and signs with a private key, it was not included to Telegram solution, because private key is inaccessible + +####Prepare + +prepares a release for deployment, puts all files to deploy/{version} folder +* current tsetup{version}exe installer +* current Telegram.exe +* current Telegram.pdb (debug info for crash minidumps view) +* current tupdate{updversion} binary lzma update archive + +####MetaEmoji + +from two folders +* SourceFiles/art/Emoji +* SourceFiles/art/Emoji_200x + +and some inner config creates four sprites and text2emoji replace code +* SourceFiles/art/emoji.png +* SourceFiles/art/emoji_125x.png +* SourceFiles/art/emoji_150x.png +* SourceFiles/art/emoji_200x.png +* SourceFiles/gui/emoji_config.cpp + +####MetaStyle + +from two files and two sprites +* Resources/style_classes.txt +* Resources/style.txt +* SourceFiles/art/sprite.png +* SourceFiles/art/sprite_200x.png + +creates two other sprites, four sprite grids and style constants code +* SourceFiles/art/sprite_125x.png +* SourceFiles/art/sprite_150x.png +* SourceFiles/art/grid.png +* SourceFiles/art/grid_125x.png +* SourceFiles/art/grid_150x.png +* SourceFiles/art/grid_200x.png +* GeneratedFiles/style_classes.h +* GeneratedFiles/style_auto.h +* GeneratedFiles/style_auto.cpp + +####MetaLang + +from langpack file +* Resources/lang.txt + +creates lang constants code and lang file parse code +* GeneratedFiles/lang.h +* GeneratedFiles/lang.cpp \ No newline at end of file diff --git a/Telegram.sln b/Telegram.sln new file mode 100644 index 000000000..19aece280 --- /dev/null +++ b/Telegram.sln @@ -0,0 +1,72 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30110.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Telegram", "Telegram\Telegram.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" + ProjectSection(ProjectDependencies) = postProject + {6F483617-7C84-4E7E-91D8-1FF28A4CE3A0} = {6F483617-7C84-4E7E-91D8-1FF28A4CE3A0} + {E417CAA4-259B-4C99-88E3-805F1300E8EB} = {E417CAA4-259B-4C99-88E3-805F1300E8EB} + {EB7D16AC-EACF-4577-B05A-F28E5F356794} = {EB7D16AC-EACF-4577-B05A-F28E5F356794} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MetaStyle", "Telegram\MetaStyle.vcxproj", "{6F483617-7C84-4E7E-91D8-1FF28A4CE3A0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MetaEmoji", "Telegram\MetaEmoji.vcxproj", "{EB7D16AC-EACF-4577-B05A-F28E5F356794}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Updater", "Telegram\Updater.vcxproj", "{6B4BA3BE-7B15-4B4C-B200-81ABFDEF2C76}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Prepare", "Telegram\Prepare.vcxproj", "{88AB1138-143A-4CFB-A0E6-79B646B5E1B0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MetaLang", "Telegram\MetaLang.vcxproj", "{E417CAA4-259B-4C99-88E3-805F1300E8EB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Win32.ActiveCfg = Debug|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Win32.Build.0 = Debug|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Win32.Deploy.0 = Debug|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Win32.ActiveCfg = Release|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Win32.Build.0 = Release|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|Win32 + {6F483617-7C84-4E7E-91D8-1FF28A4CE3A0}.Debug|Win32.ActiveCfg = Debug|Win32 + {6F483617-7C84-4E7E-91D8-1FF28A4CE3A0}.Debug|Win32.Build.0 = Debug|Win32 + {6F483617-7C84-4E7E-91D8-1FF28A4CE3A0}.Debug|x64.ActiveCfg = Debug|Win32 + {6F483617-7C84-4E7E-91D8-1FF28A4CE3A0}.Release|Win32.ActiveCfg = Release|Win32 + {6F483617-7C84-4E7E-91D8-1FF28A4CE3A0}.Release|Win32.Build.0 = Release|Win32 + {6F483617-7C84-4E7E-91D8-1FF28A4CE3A0}.Release|x64.ActiveCfg = Release|Win32 + {EB7D16AC-EACF-4577-B05A-F28E5F356794}.Debug|Win32.ActiveCfg = Debug|Win32 + {EB7D16AC-EACF-4577-B05A-F28E5F356794}.Debug|Win32.Build.0 = Debug|Win32 + {EB7D16AC-EACF-4577-B05A-F28E5F356794}.Debug|x64.ActiveCfg = Debug|Win32 + {EB7D16AC-EACF-4577-B05A-F28E5F356794}.Release|Win32.ActiveCfg = Release|Win32 + {EB7D16AC-EACF-4577-B05A-F28E5F356794}.Release|Win32.Build.0 = Release|Win32 + {EB7D16AC-EACF-4577-B05A-F28E5F356794}.Release|x64.ActiveCfg = Release|Win32 + {6B4BA3BE-7B15-4B4C-B200-81ABFDEF2C76}.Debug|Win32.ActiveCfg = Debug|Win32 + {6B4BA3BE-7B15-4B4C-B200-81ABFDEF2C76}.Debug|Win32.Build.0 = Debug|Win32 + {6B4BA3BE-7B15-4B4C-B200-81ABFDEF2C76}.Debug|x64.ActiveCfg = Debug|Win32 + {6B4BA3BE-7B15-4B4C-B200-81ABFDEF2C76}.Release|Win32.ActiveCfg = Release|Win32 + {6B4BA3BE-7B15-4B4C-B200-81ABFDEF2C76}.Release|Win32.Build.0 = Release|Win32 + {6B4BA3BE-7B15-4B4C-B200-81ABFDEF2C76}.Release|x64.ActiveCfg = Release|Win32 + {88AB1138-143A-4CFB-A0E6-79B646B5E1B0}.Debug|Win32.ActiveCfg = Debug|Win32 + {88AB1138-143A-4CFB-A0E6-79B646B5E1B0}.Debug|Win32.Build.0 = Debug|Win32 + {88AB1138-143A-4CFB-A0E6-79B646B5E1B0}.Debug|x64.ActiveCfg = Debug|Win32 + {88AB1138-143A-4CFB-A0E6-79B646B5E1B0}.Release|Win32.ActiveCfg = Release|Win32 + {88AB1138-143A-4CFB-A0E6-79B646B5E1B0}.Release|Win32.Build.0 = Release|Win32 + {88AB1138-143A-4CFB-A0E6-79B646B5E1B0}.Release|x64.ActiveCfg = Release|Win32 + {E417CAA4-259B-4C99-88E3-805F1300E8EB}.Debug|Win32.ActiveCfg = Debug|Win32 + {E417CAA4-259B-4C99-88E3-805F1300E8EB}.Debug|Win32.Build.0 = Debug|Win32 + {E417CAA4-259B-4C99-88E3-805F1300E8EB}.Debug|x64.ActiveCfg = Debug|Win32 + {E417CAA4-259B-4C99-88E3-805F1300E8EB}.Release|Win32.ActiveCfg = Release|Win32 + {E417CAA4-259B-4C99-88E3-805F1300E8EB}.Release|Win32.Build.0 = Release|Win32 + {E417CAA4-259B-4C99-88E3-805F1300E8EB}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Telegram/MetaEmoji.vcxproj b/Telegram/MetaEmoji.vcxproj new file mode 100644 index 000000000..3c61c633d --- /dev/null +++ b/Telegram/MetaEmoji.vcxproj @@ -0,0 +1,115 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + true + + + true + + + + + + + Moc%27ing genemoji.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." + Moc%27ing genemoji.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + + {EB7D16AC-EACF-4577-B05A-F28E5F356794} + Qt4VSv1.0 + + + + Application + v120_xp + + + Application + v120_xp + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Platform)\$(Configuration)Emoji\ + $(SolutionDir)$(Platform)\$(Configuration)IntermediateEmoji\ + + + $(SolutionDir)$(Platform)\$(Configuration)Emoji\ + $(SolutionDir)$(Platform)\$(Configuration)IntermediateEmoji\ + + + + UNICODE;WIN32;WIN64;%(PreprocessorDefinitions) + Disabled + ProgramDatabase + MultiThreadedDebug + .;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);%(AdditionalIncludeDirectories) + false + + + Console + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;imm32.lib;winmm.lib;qtmaind.lib;glu32.lib;opengl32.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5PlatformSupportd.lib;platforms\qwindowsd.lib;%(AdditionalDependencies) + true + $(IntDir)$(TargetName).pdb + $(IntDir)$(TargetName).pgd + + + + + UNICODE;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;%(PreprocessorDefinitions) + + MultiThreaded + .;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);%(AdditionalIncludeDirectories) + false + + + Console + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;glu32.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies) + false + $(IntDir)$(TargetName).pdb + $(IntDir)$(TargetName).pgd + + + + + + + + + + + \ No newline at end of file diff --git a/Telegram/MetaEmoji.vcxproj.filters b/Telegram/MetaEmoji.vcxproj.filters new file mode 100644 index 000000000..34a46ccae --- /dev/null +++ b/Telegram/MetaEmoji.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;cxx;c;def + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h + + + {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} + qrc;* + false + + + {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} + moc;h;cpp + False + + + {d43dc9f2-202b-4a47-b396-e7e2882cd611} + cpp;moc + False + + + {6a90eef7-d2c6-46bd-8158-a8c5185190a7} + cpp;moc + False + + + + + Source Files + + + Source Files + + + Generated Files\Debug + + + Generated Files\Release + + + + + Header Files + + + + + Header Files + + + \ No newline at end of file diff --git a/Telegram/MetaLang.vcxproj b/Telegram/MetaLang.vcxproj new file mode 100644 index 000000000..10523275d --- /dev/null +++ b/Telegram/MetaLang.vcxproj @@ -0,0 +1,113 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + true + + + true + + + + + + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing genlang.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing genlang.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." + + + + + {E417CAA4-259B-4C99-88E3-805F1300E8EB} + Qt4VSv1.0 + + + + Application + v120_xp + + + Application + v120_xp + + + + + + + + + + + + + <_ProjectFileVersion>12.0.21005.1 + + + $(SolutionDir)$(Platform)\$(Configuration)Lang\ + $(SolutionDir)$(Platform)\$(Configuration)IntermediateLang\ + + + $(SolutionDir)$(Platform)\$(Configuration)Lang\ + $(SolutionDir)$(Platform)\$(Configuration)IntermediateLang\ + + + + UNICODE;WIN32;WIN64;%(PreprocessorDefinitions) + Disabled + ProgramDatabase + MultiThreadedDebug + .;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);%(AdditionalIncludeDirectories) + false + + + Console + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;imm32.lib;winmm.lib;qtmaind.lib;glu32.lib;opengl32.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;Qt5Networkd.lib;Qt5PlatformSupportd.lib;platforms\qwindowsd.lib;%(AdditionalDependencies) + true + $(IntDir)$(TargetName).pdb + $(IntDir)$(TargetName).pgd + + + + + UNICODE;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;%(PreprocessorDefinitions) + + MultiThreaded + .;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);%(AdditionalIncludeDirectories) + false + + + Console + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies) + false + + + + + + + + + + + \ No newline at end of file diff --git a/Telegram/MetaLang.vcxproj.filters b/Telegram/MetaLang.vcxproj.filters new file mode 100644 index 000000000..4de4918b2 --- /dev/null +++ b/Telegram/MetaLang.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;cxx;c;def + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h + + + {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} + qrc;* + false + + + {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} + moc;h;cpp + False + + + {3c9f729e-b8c7-4b14-b2df-4a3eda27c074} + cpp;moc + False + + + {3e5a3edb-4328-4310-aec6-a3c6449e1aab} + cpp;moc + False + + + + + Source Files + + + Generated Files\Debug + + + Source Files + + + Generated Files\Release + + + + + Header Files + + + + + Header Files + + + \ No newline at end of file diff --git a/Telegram/MetaStyle.vcxproj b/Telegram/MetaStyle.vcxproj new file mode 100644 index 000000000..cefb3f878 --- /dev/null +++ b/Telegram/MetaStyle.vcxproj @@ -0,0 +1,129 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + true + + + true + + + + + + + + + + + + + + + + + + + + + + Moc%27ing genstyles.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." + Moc%27ing genstyles.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + {6F483617-7C84-4E7E-91D8-1FF28A4CE3A0} + Qt4VSv1.0 + + + + Application + v120_xp + + + Application + v120_xp + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Platform)\$(Configuration)IntermediateMeta\ + $(SolutionDir)$(Platform)\$(Configuration)Meta\ + + + $(SolutionDir)$(Platform)\$(Configuration)Meta\ + $(SolutionDir)$(Platform)\$(Configuration)IntermediateMeta\ + + + + UNICODE;WIN32;WIN64;%(PreprocessorDefinitions) + Disabled + ProgramDatabase + MultiThreadedDebug + .;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);%(AdditionalIncludeDirectories) + false + + + Console + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;imm32.lib;winmm.lib;qtmaind.lib;glu32.lib;opengl32.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;Qt5Networkd.lib;Qt5PlatformSupportd.lib;platforms\qwindowsd.lib;%(AdditionalDependencies) + true + $(IntDir)$(TargetName).pdb + $(IntDir)$(TargetName).pgd + + + + + + UNICODE;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;%(PreprocessorDefinitions) + + MultiThreaded + .;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);%(AdditionalIncludeDirectories) + false + + + Console + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;opengl32.lib;imm32.lib;winmm.lib;Qt5Core.lib;Qt5Gui.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;%(AdditionalDependencies) + false + + + + + + + + + + + \ No newline at end of file diff --git a/Telegram/MetaStyle.vcxproj.filters b/Telegram/MetaStyle.vcxproj.filters new file mode 100644 index 000000000..9210ed15a --- /dev/null +++ b/Telegram/MetaStyle.vcxproj.filters @@ -0,0 +1,55 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;cxx;c;def + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h + + + {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} + qrc;* + false + + + {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} + moc;h;cpp + False + + + {1ace0630-c46a-4299-a4c3-d155a4cb04bb} + cpp;moc + False + + + {2473bf06-b2ba-4f68-9bfe-72a58da61f94} + cpp;moc + False + + + + + Source Files + + + Source Files + + + Generated Files\Debug + + + Generated Files\Release + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/Telegram/Packer.vcxproj b/Telegram/Packer.vcxproj new file mode 100644 index 000000000..7bd010bc1 --- /dev/null +++ b/Telegram/Packer.vcxproj @@ -0,0 +1,96 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + {56A9A4B2-21E5-4360-AFA8-85B43AC43B08} + Qt4VSv1.0 + + + + Application + v120_xp + + + Application + v120_xp + + + + + + + + + + + + + <_ProjectFileVersion>11.0.61030.0 + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)IntermediatePacker\ + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)IntermediatePacker\ + + + + UNICODE;WIN32;WIN64;QT_CORE_LIB;ZLIB_WINAPI;%(PreprocessorDefinitions) + Disabled + ProgramDatabase + MultiThreadedDebug + .\..\..\Libraries\lzma\C;.;$(QTDIR)\include;.\..\..\Libraries\zlib-1.2.8;.\..\..\Libraries\OpenSSL-32-Debug\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories) + false + + + Console + $(OutDir)\$(ProjectName).exe + .\..\..\Libraries\lzma\C\Util\LzmaLib\Debug;$(QTDIR)\lib;.\..\..\Libraries\zlib-1.2.8\contrib\vstudio\vc11\x86\ZlibStatQtDebug;.\..\..\Libraries\OpenSSL-32-Debug\lib;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmaind.lib;zlibstat_qt.lib;libeay32.lib;Qt5Cored.lib;LzmaLib.lib;%(AdditionalDependencies) + true + + + + + + UNICODE;WIN32;WIN64;QT_NO_DEBUG;ZLIB_WINAPI;NDEBUG;QT_CORE_LIB;%(PreprocessorDefinitions) + + MultiThreaded + .\..\..\Libraries\lzma\C;.;$(QTDIR)\include;.\..\..\Libraries\zlib-1.2.8;.\..\..\Libraries\OpenSSL-32\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories) + false + + + Console + $(OutDir)\$(ProjectName).exe + .\..\..\Libraries\lzma\C\Util\LzmaLib\Release;$(QTDIR)\lib;.\..\..\Libraries\zlib-1.2.8\contrib\vstudio\vc11\x86\ZlibStatQtRelease;.\..\..\Libraries\OpenSSL-32\lib;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;zlibstat_qt.lib;libeay32.lib;Qt5Core.lib;LzmaLib.lib;%(AdditionalDependencies) + false + + + + + + + + + + + + \ No newline at end of file diff --git a/Telegram/Packer.vcxproj.filters b/Telegram/Packer.vcxproj.filters new file mode 100644 index 000000000..9ba4d3460 --- /dev/null +++ b/Telegram/Packer.vcxproj.filters @@ -0,0 +1,16 @@ + + + + + {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} + moc;h;cpp + False + + + + + + + + + \ No newline at end of file diff --git a/Telegram/Prepare.bat b/Telegram/Prepare.bat new file mode 100644 index 000000000..d7364a119 --- /dev/null +++ b/Telegram/Prepare.bat @@ -0,0 +1 @@ +Prepare.exe -path Telegram.exe -path Updater.exe \ No newline at end of file diff --git a/Telegram/Prepare.vcxproj b/Telegram/Prepare.vcxproj new file mode 100644 index 000000000..2a76b8bcc --- /dev/null +++ b/Telegram/Prepare.vcxproj @@ -0,0 +1,94 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + {88AB1138-143A-4CFB-A0E6-79B646B5E1B0} + Qt4VSv1.0 + + + + Application + v120_xp + + + Application + v120_xp + + + + + + + + + + + + + <_ProjectFileVersion>11.0.61030.0 + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)IntermediatePrepare\ + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)IntermediatePrepare\ + + + + UNICODE;WIN32;WIN64;QT_CORE_LIB;%(PreprocessorDefinitions) + Disabled + ProgramDatabase + MultiThreadedDebug + .;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories) + false + + + Console + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmaind.lib;Qt5Cored.lib;%(AdditionalDependencies) + true + + + + + UNICODE;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;%(PreprocessorDefinitions) + + MultiThreaded + .;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories) + false + + + Console + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;qtmain.lib;Qt5Core.lib;%(AdditionalDependencies) + false + + + + + + + + + + + \ No newline at end of file diff --git a/Telegram/Prepare.vcxproj.filters b/Telegram/Prepare.vcxproj.filters new file mode 100644 index 000000000..c4a106555 --- /dev/null +++ b/Telegram/Prepare.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;cxx;c;def + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h + + + {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} + qrc;* + false + + + {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} + moc;h;cpp + False + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/Telegram/Resources/lang.txt b/Telegram/Resources/lang.txt new file mode 100644 index 000000000..b14eb0580 --- /dev/null +++ b/Telegram/Resources/lang.txt @@ -0,0 +1,379 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +direction: "LTR"; + +lng_maintitle: "Telegram D"; + +lng_menu_contacts: "Contacts"; +lng_menu_settings: "Settings"; +lng_menu_about: "About"; + +lng_open_from_tray: "Open Telegram"; +lng_quit_from_tray: "Quit Telegram"; +lng_tray_icon_text: "Telegram is still running here, +you can change this from settings page. + +If this icon disappears from tray menu, +you can drag it back here from hidden icons."; + +lng_month1: "January"; +lng_month2: "February"; +lng_month3: "March"; +lng_month4: "April"; +lng_month5: "May"; +lng_month6: "June"; +lng_month7: "July"; +lng_month8: "August"; +lng_month9: "September"; +lng_month10: "October"; +lng_month11: "November"; +lng_month12: "December"; + +lng_weekday1: "Mon"; +lng_weekday2: "Tue"; +lng_weekday3: "Wed"; +lng_weekday4: "Thu"; +lng_weekday5: "Fri"; +lng_weekday6: "Sat"; +lng_weekday7: "Sun"; + +lng_month_day: "{month} {day}"; + +lng_cancel: "Cancel"; +lng_continue: "Continue"; +lng_connecting: "Connecting..."; +lng_reconnecting: "Reconnect in %1 s..."; +lng_reconnecting_try_now: "Try now"; + +lng_status_offline: "offline"; +lng_status_invisible: "invisible"; +lng_status_lastseen: "last seen {when}"; +lng_status_lastseen_now: "just now"; +lng_status_lastseen_minute: "%1 minute ago"; +lng_status_lastseen_minutes: "%1 minutes ago"; +lng_status_lastseen_hour: "%1 hour ago"; +lng_status_lastseen_hours: "%1 hours ago"; +lng_status_lastseen_today: "today at {time}"; +lng_status_lastseen_yesterday: "yesterday at {time}"; +lng_status_lastseen_date: "{date}"; +lng_status_online: "online"; + +lng_chat_no_members: "Group is unaccessible"; +lng_chat_members: "%1 members"; +lng_chat_members_online: "%1 members, %2 online"; + +lng_server_error: "Internal server error."; +lng_flood_error: "Too much tries. Please try again later."; +lng_deleted: "Unknown"; + +lng_intro1: "Welcome to an unofficial [b]desktop[/b] client +of [b]Telegram[/b] mobile messenger."; +lng_intro2: "Visit [a href=\"https://telegram.org/\"]telegram.org[/a] to learn more."; +lng_start_msgs: "Start Messaging"; + +lng_intro_back: "Back"; +lng_intro_next: "Next"; +lng_intro_finish: "Finish"; + +lng_phone_ph: "Your phone number"; +lng_phone_title: "Your Phone"; +lng_phone_desc: "Please confirm your country code and +enter your phone number."; +lng_phone_notreg: "Note: if you don't have a Telegram account yet, +please [b]sign up[/b] with your [a href=\"https://telegram.org/\"]iOS / Android[/a] or {signup}here »{/signup}"; +lng_country_code: "Country Code"; +lng_bad_country_code: "Invalid Country Code"; +lng_country_ph: "Search"; +lng_country_done: "Done"; +lng_country_none: "Country not found"; +lng_country_select: "Select Country"; + +lng_code_ph: "Your code"; +lng_code_desc: "We have sent you an SMS with activation +code to your phone. Please enter it below."; +lng_code_call: "Telegram will dial your number in %1:%2"; +lng_code_calling: "Requesting a call from Telegram..."; +lng_code_called: "Telegram dialed your number"; + +lng_bad_phone: "Invalid phone number. Please try again."; +lng_bad_phone_noreg: "Phone number not registered."; +lng_bad_code: "You have entered an invalid code. Please try again."; +lng_bad_name: "Please enter your first and last name."; +lng_bad_chat_title: "Please enter new chat title."; +lng_bad_photo: "Bad image selected."; + +lng_signup_title: "Information and photo"; +lng_signup_firstname: "First Name"; +lng_signup_lastname: "Last Name"; + +lng_dlg_filter: "Search"; +lng_dlg_new_group_name: "Group name"; +lng_dlg_create_group: "Create"; + +lng_settings_profile: "Profile"; +lng_settings_edit: "Edit"; +lng_settings_save: "Save"; +lng_settings_cancel: "Cancel"; +lng_settings_upload: "Set Profile Photo"; +lng_settings_badsize: "This image has bad size, please try other."; +lng_settings_crop_profile: "Select square area for your profile photo"; +lng_settings_uploading_photo: "Uploading photo..."; + +lng_settings_section_notify: "Notifications"; +lng_settings_desktop_notify: "Desktop notifications"; +lng_settings_sound_notify: "Sound"; + +lng_settings_section_general: "General"; +lng_settings_auto_update: "Update automatically"; +lng_settings_current_version: "Version {version}"; +lng_settings_check_now: "Check for updates"; +lng_settings_update_checking: "Checking for updates..."; +lng_settings_latest_installed: "Latest version is installed"; +lng_settings_downloading: "Downloading update {ready} / {total} Mb..."; +lng_settings_update_ready: "New version is ready"; +lng_settings_update_now: "Restart Now"; +lng_settings_update_fail: "Update check failed :("; +lng_settings_workmode_tray: "Show tray icon"; +lng_settings_workmode_window: "Show taskbar icon"; +lng_settings_auto_start: "Launch Telegram when system starts"; +lng_settings_start_min: "Launch minimized"; +lng_settings_scale_label: "Interface scale"; +lng_settings_scale_auto: "Auto ({cur})"; + +lng_settings_section_chat: "Chat options"; +lng_settings_replace_emojis: "Replace emojis"; +lng_settings_view_emojis: "View list"; +lng_settings_emoji_list: "List of supported emojis"; +lng_settings_send_enter: "Send by Enter"; +lng_settings_send_ctrlenter: "Send by Ctrl+Enter"; +lng_settings_cats_and_dogs: "Allow cats and dogs"; + +lng_download_path_dont_ask: "Don't ask download path for each file"; +lng_download_path_label: "Download path: "; +lng_download_path_temp: "temp folder"; +lng_download_path_clear: "Clear All"; +lng_download_path_header: "Choose download path"; +lng_download_path_temp_radio: "Temp folder, cleared on logout or uninstall"; +lng_download_path_dir_radio: "Custom folder, cleared only manually"; +lng_download_path_choose: "Choose download path"; +lng_sure_clear_downloads: "Do you want to remove all downloaded files from temp folder? It is done automatically on logout or program uninstall."; +lng_download_path_failed: "File download could not be started. It could happen because of a bad download location. + +You can change download path in Settings."; +lng_download_path_settings: "Go to Settings"; +lng_download_finish_failed: "File download could not be finished. + +Would you like to try again?"; +lng_download_path_clearing: "Clearing..."; +lng_download_path_cleared: "Cleared!"; +lng_download_path_clear_failed: "Clear failed :("; + +lng_settings_section_advanced: "Advanced"; +lng_connection_type: "Connection type:"; +lng_connection_auto_connecting: "Default (connecting..)"; +lng_connection_auto: "Default ({type} used)"; +lng_connection_http_proxy: "HTTP with proxy"; +lng_connection_tcp_proxy: "TCP with proxy"; +lng_connection_header: "Connection type"; +lng_connection_auto_rb: "Auto (TCP if available or HTTP)"; +lng_connection_http_proxy_rb: "HTTP with custom http-proxy"; +lng_connection_tcp_proxy_rb: "TCP with custom socks5-proxy"; +lng_connection_host_ph: "Hostname"; +lng_connection_port_ph: "Port"; +lng_connection_user_ph: "Username"; +lng_connection_password_ph: "Password"; +lng_connection_save: "Save"; +lng_settings_reset: "Reset other sessions"; +lng_settings_reset_done: "Sessions reset done"; +lng_settings_logout: "Log Out"; + +lng_settings_need_restart: "You need to restart for applying +some of the new settings. Restart now?"; +lng_settings_restart_now: "Restart"; +lng_settings_restart_later: "Later"; + +lng_profile_settings_section: "Settings"; +lng_profile_participants_section: "Participants"; +lng_profile_info: "Contact info"; +lng_profile_group_info: "Group info"; +lng_profile_add_contact: "Add Contact"; +lng_profile_edit_contact: "Edit"; +lng_profile_edit_group: "Edit"; +lng_profile_phone: "Phone number: {phone}"; +lng_profile_enable_notifications: "Notifications"; +lng_profile_clear_history: "Clear history"; +lng_profile_send_message: "Send Message"; +lng_profile_share_contact: "Share Contact"; +lng_profile_delete_contact: "Delete"; +lng_profile_set_group_photo: "Set Photo"; +lng_profile_add_participant: "Add Member"; +lng_profile_delete_and_exit: "Leave"; +lng_profile_kick: "Kick"; +lng_profile_sure_kick: "Kick {user} from the group?"; +lng_profile_loading: "Loading..."; + +lng_participant_filter: "Search"; +lng_participant_invite: "Invite"; +lng_create_new_group: "New Group"; +lng_create_group_next: "Next"; +lng_create_group_title: "New Group"; + +lng_sure_delete_contact: "Are you sure, you want to delete {contact} from your contact list?"; +lng_sure_delete_history: "Are you sure, you want to delete all message history with {contact}? + +This action cannot be undone."; + +lng_sure_delete_and_exit: "Are you sure, you want to delete all message history and leave «{group}»? + +This action cannot be undone."; + +lng_sure_enable_debug: "Do you want to enable DEBUG mode? + +All network events will be logged."; + +lng_message_empty: "(empty)"; + +lng_action_add_user: "{from} added {user}"; +lng_action_kick_user: "{from} kicked {user}"; +lng_action_user_left: "{from} left the group"; +lng_action_user_joined: "{from} joined the group"; +lng_action_user_photo: "{from} added a new profile photo"; +lng_action_user_registered: "{from} just joined Telegram"; +lng_action_removed_photo: "{from} removed group photo"; +lng_action_changed_photo: "{from} changed group photo"; +lng_action_changed_title: "{from} changed group name to «{title}»"; +lng_action_created_chat: "{from} created group «{title}»"; +lng_action_checked_in: "{from} checked in"; + +lng_forwarded_from: "Forwarded from "; + +lng_attach_failed: "Failed"; +lng_attach_file: "File"; +lng_attach_photo: "Photo"; + +lng_media_open_with: "Open With"; +lng_media_download: "Download"; +lng_media_cancel: "Cancel"; +lng_media_video: "Video"; +lng_media_audio: "Audio"; + +lng_in_dlg_photo: "Photo"; +lng_in_dlg_video: "Video"; +lng_in_dlg_geo: "Map"; +lng_in_dlg_contact: "Contact"; +lng_in_dlg_audio: "Audio"; +lng_in_dlg_document: "File"; + +lng_send_button: "Send"; +lng_message_ph: "Write a message..."; +lng_empty_history: ""; +lng_willbe_history: "Please select chat to start messaging"; +lng_message_with_from: "[c]{from}:[/c] {message}"; +lng_from_you: "You"; + +lng_typing: "typing"; +lng_user_typing: "{user} is typing"; +lng_users_typing: "{user1} and {user2} are typing"; +lng_many_typing: "{n} are typing"; +lng_unread_bar: "%1 unread messages"; + +lng_maps_point: "Location"; +lng_save_photo: "Save image"; +lng_save_video: "Save video"; +lng_save_audio: "Save audio"; +lng_save_document: "Save document"; +lng_save_downloaded: "{ready} / {total} {mb}"; +lng_duration_and_size: "{duration}, {size}"; +lng_choose_images: "Choose images"; + +lng_context_open_link: "Open Link"; +lng_context_copy_link: "Copy Link"; +lng_context_open_email: "Write to this address"; +lng_context_copy_email: "Copy email address"; +lng_context_open_image: "Open Image"; +lng_context_save_image: "Save Image As..."; +lng_context_forward_image: "Forward Image"; +lng_context_delete_image: "Delete Image"; +lng_context_copy_image: "Copy Image"; +lng_context_close_image: "Close Image"; +lng_context_cancel_download: "Cancel Download"; +lng_context_show_in_folder: "Show in Folder"; +lng_context_open_video: "Open Video"; +lng_context_save_video: "Save Video As..."; +lng_context_open_audio: "Open Audio"; +lng_context_save_audio: "Save Audio As..."; +lng_context_open_document: "Open File"; +lng_context_save_document: "Save File As..."; +lng_context_copy_text: "Copy Message Text"; +lng_context_forward_msg: "Forward Message"; +lng_context_delete_msg: "Delete Message"; +lng_context_cancel_upload: "Cancel Upload"; +lng_context_copy_selected: "Copy Selected Text"; +lng_context_forward_selected: "Forward Selected"; +lng_context_delete_selected: "Delete Selected"; +lng_context_clear_selection: "Clear Selection"; +lng_really_send_image: "Do you want to send this image?"; + +lng_forward_choose: "Choose recipient..."; +lng_forward_confirm: "Forward to {recipient}?"; +lng_forward_share_contact: "Share contact to {recipient}?"; +lng_forward: "Forward"; + +lng_contact_phone: "Phone number"; +lng_enter_contact_data: "New Contact"; +lng_edit_group_title: "Edit group name"; +lng_edit_contact_title: "Edit contact name"; +lng_edit_self_title: "Edit your name"; +lng_confirm_contact_data: "New Contact"; +lng_add_contact: "Create"; +lng_add_contact_button: "Add Contact"; +lng_contacts_header: "Contacts"; +lng_contact_not_joined: "Unfortunately {name} did not join Telegram yet, but you can send your friend an invitation. + +We will notify you about any of your contacts who is joining Telegram."; +lng_try_other_contact: "Try other"; +lng_contacts_done: "Cancel"; + +lng_drag_images_here: "Drop images here"; +lng_drag_photos_here: "Drop photos here"; +lng_drag_files_here: "Drop files here"; + +lng_drag_to_send_quick: "to send them in a quick way"; +lng_drag_to_send_no_compression: "to send them without compression"; +lng_drag_to_send_documents: "to send them as documents"; + +lng_selected_clear: "Cancel"; +lng_selected_delete: "Delete"; +lng_selected_forward: "Forward"; +lng_selected_count_1: "%1 message"; +lng_selected_count_5: "%1 messages"; +lng_selected_cancel_sure_this: "Do you want to cancel this upload?"; +lng_selected_delete_sure_this: "Do you want to delete this message?"; +lng_selected_delete_sure_1: "Do you want to delete %1 message?"; +lng_selected_delete_sure_5: "Do you want to delete %1 messages?"; +lng_selected_delete_confirm: "Delete"; + +lng_emoji_no_recent: "Recent emojis will be here"; + +lng_about_version: "Version {version}"; +lng_about_text: "Unofficial free messaging app based on [a href=\"https://core.telegram.org/mtproto\"]MTProto[/a] and +[a href=\"https://core.telegram.org/api\"]Telegram API[/a] for speed and security + +This software is licensed under [a href=\"https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\"]GNU GPL[/a] version 3, +source code is available on [a href=\"https://github.com/telegramdesktop/tdesktop\"]GitHub[/a]."; +lng_about_done: "Done"; diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt new file mode 100644 index 000000000..7df2b7ac3 --- /dev/null +++ b/Telegram/Resources/style.txt @@ -0,0 +1,1388 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +defaultFontFamily: 'Segoe UI'; +//defaultFontFamily: 'ThoolikaTraditionalUnicode'; +semibold: 'Segoe WP Semibold'; + +spriteFile: ':/gui/art/sprite.png' / 2:':/gui/art/sprite_125x.png' / 3:':/gui/art/sprite_150x.png' / 4:':/gui/art/sprite_200x.png'; +emojisFile: ':/gui/art/emoji.png' / 2:':/gui/art/emoji_125x.png' / 3:':/gui/art/emoji_150x.png' / 4:':/gui/art/emoji_200x.png'; +emojiSize: 16px; +emojiPadding: 1px; + +counterBG: #b42f35; +counterMuteBG: #777; +counterColor: #fff; + +transparent: rgba(255, 255, 255, 0); +white: rgba(255, 255, 255, 255); +black: rgba(0, 0, 0, 255); + +color1: #c03d33; // red +color2: #4fad2d; // green +color3: #d09306; // yellow +color4: #348cd4; // blue +color5: #8544d6; // purple +color6: #cd4073; // pink +color7: #2996ad; // sea +color8: #ce671b; // orange + +wndMinWidth: 640px; +wndMinHeight: 480px; +wndDefWidth: 800px; +wndDefHeight: 600px; +wndBG: #FFF; +wndShadow: sprite(184px, 21px, 19px, 19px); +wndShadowShift: 1px; + +layerAlpha: 0.3; +layerBG: #000; + +titleBG: #6389a8; +titleColor: #0f8dcc;//rgb(20, 136, 210); +titleHeight: 39px; +titleShadowColor: rgba(0, 0, 0, 24);//#ebebeb +titleShadow: 1px; +titleIconPos: point(7px, 7px); +titleIconRect: sprite(160px, 100px, 26px, 26px); +titleFont: font(17px); +titlePos: point(44px, 29px); +titleMenuOffset: 36px; + +titleRed: #ee4928; +titleGray: #777; +titleGreen: #41a903; + +titleStatusColor: #999; +titleTypingColor: #0080c0; + +statusFont: font(14px); +versionColor: #777; + +sysBtnDelta: 6px; +sysUpd: sysButton { + size: size(31px, 39px); + img: sprite(184px, 1px, 19px, 19px); + color: #c4d8e9; + overColor: white; + duration: 150; +} +sysMin: sysButton(sysUpd) { + img: sprite(207px, 1px, 19px, 19px); +} +sysMax: sysButton(sysUpd) { + img: sprite(230px, 1px, 19px, 19px); +} +sysRes: sysButton(sysUpd) { + img: sprite(253px, 1px, 19px, 19px); +} +sysCls: sysButton(sysUpd) { + img: sprite(276px, 1px, 19px, 19px); +} + +btnWhiteHover: #f5f5f5; +btnBoxWhiteHover: #fafafa; +btnYesColor: #0080c0; +btnYesHover: #0073ad; +btnNoColor: #8b8b8b; +btnNoHover: #777; + +btnDefIconed: iconedButton { + color: white; + bgColor: white; + overBgColor: white; + font: font(14px); + + opacity: 0.78; + overOpacity: 1; + + textPos: point(0px, 0px); + downTextPos: point(0px, 0px); + + duration: 150; + cursor: cursor(pointer); +} + +titleTextButton: flatButton { + color: #d4e3ef; + overColor: #fff; + downColor: #fff; + bgColor: transparent; + overBgColor: transparent; + downBgColor: transparent; + + width: -14px; + height: 39px; + + textTop: 10px; + overTextTop: 10px; + downTextTop: 11px; + + font: font(13px); + overFont: font(13px); + duration: 150; + cursor: cursor(default); +} + +btnDefFlat: flatButton { + duration: 200; + cursor: cursor(pointer); +} +btnDefBig: flatButton(btnDefFlat) { + textTop: 11px; + overTextTop: 11px; + downTextTop: 12px; + + font: font(23px); + overFont: font(23px); + height: 56px; +} +btnDefNext: flatButton(btnDefFlat) { + color: white; + overColor: white; + downColor: white; + bgColor: #2fa9e2; + overBgColor: #279ad0; + downBgColor: #279ad0; +} +btnDefBack: flatButton(btnDefFlat) { + color: white; + overColor: white; + downColor: white; + bgColor: #c7c7c7; + overBgColor: #b9b9b9; + downBgColor: #b9b9b9; +} + +linkFont: font(14px); +linkOverFont: font(14px underline); +btnDefLink: linkButton { + color: btnYesColor; + overColor: btnYesColor; + downColor: btnYesHover; + font: linkFont; + overFont: linkOverFont; +} + +cbDefFlat: flatCheckbox { + textColor: #000; + bgColor: transparent; + disColor: #999; + + height: 22px; + textTop: 0px; + textLeft: 34px; + font: font(14px); + duration: 200; + bgFunc: transition(easeOutCirc); + cursor: cursor(pointer); + + disabledCursor: cursor(default); + + imageRect: sprite(144px, 68px, 22px, 22px); + chkImageRect: sprite(119px, 68px, 22px, 22px); + overImageRect: sprite(144px, 68px, 22px, 22px); + chkOverImageRect: sprite(119px, 68px, 22px, 22px); + disImageRect: sprite(193px, 68px, 22px, 22px); + chkDisImageRect: sprite(193px, 68px, 22px, 22px); + + imagePos: point(0px, 0px); +} + +rbDefFlat: flatCheckbox(cbDefFlat) { + chkImageRect: sprite(169px, 68px, 22px, 22px); + chkOverImageRect: sprite(169px, 68px, 22px, 22px); +} + +inpDefFont: font(17px); +inpDefFlat: flatInput { + textColor: #000; + bgColor: #FFF; + bgActive: #FFF; + width: 210px; + height: 40px; + align: align(left); + textMrg: margins(5px, 5px, 5px, 5px); + font: inpDefFont; + cursor: cursor(text); + + borderWidth: 0px; + borderColor: black; + borderActive: black; + borderError: black; + + phColor: #949494; + phFocusColor: #AAA; + phAlign: align(left); + phPos: point(2px, 0px); + phShift: 50px; + phDuration: 100; + phLeftFunc: transition(linear); + phAlphaFunc: transition(linear); + phColorFunc: transition(linear); +} + +inpDefGray: flatInput(inpDefFlat) { + bgColor: #ebebeb; + borderWidth: 2px; + borderColor: #ebebeb; + borderActive: #80cff9; + borderError: #ed8080; + phColor: #808080; +} + +taDefFlat: flatTextarea { + textColor: #000; + bgColor: #FFF; + align: align(left); + textMrg: margins(5px, 5px, 5px, 5px); + font: inpDefFont; + cursor: cursor(text); + + phColor: #AAA; + phFocusColor: #CCC; + phAlign: align(topleft); + phPos: point(2px, 0px); + phShift: 50px; + phDuration: 100; + phLeftFunc: transition(linear); + phAlphaFunc: transition(linear); + phColorFunc: transition(linear); +} + +scrollDef: flatScroll { + barColor: rgba(0, 0, 0, 83); + bgColor: rgba(0, 0, 0, 26); + barOverColor: rgba(0, 0, 0, 122); + bgOverColor: rgba(0, 0, 0, 44); + + round: 0px; + + width: 10px; + minHeight: 20px; + deltax: 3px; + deltay: 3px; + + topsh: 2px; + bottomsh: 2px; + shColor: rgba(0, 0, 0, 18); + + duration: 150; + hiding: 1000; +} +scrollCountries: flatScroll(scrollDef) { + topsh: 0px; + bottomsh: -2px; +} + +lnkText: #0f7dc7; + +labelDefFlat: flatLabel { + font: font(14px); + minWidth: 100px; + width: 0px; + align: align(left); +} + +introSkip: 20px; +introFinishSkip: 15px; +introHeaderFont: font(28px); +introHeaderSkip: 14px; +introFont: font(17px); +introVersionFont: introFont; +introVersionColor: #9b9b9b; +introVersionSkip: 10px; +intro2Skip: 60px; +intro1Skip: 14px; +introColor: black; + +introLabel: flatLabel(labelDefFlat) { + font: introFont; +} + +introPointsTop: -30px; // intro steps bottom points +introPointWidth: 4px; +introPointHeight: 4px; +introPointHoverWidth: 10px; +introPointHoverHeight: 10px; +introPointLeft: 3px; +introPointTop: 3px; +introPointDelta: 10px; +introPointColor: rgb(0, 0, 0); +introPointAlpha: 0.5; +introPointHoverColor: rgb(47, 158, 218); +introPointHoverAlpha: 0.5; +introPointStepT: transition(sineInOut); +introPointAlphaT: transition(linear); +introPointShowStepT: transition(easeOutCirc); +introPointHideStepT: transition(easeInCirc); +introPointShowAlphaT: transition(easeInCirc); +introPointHideAlphaT: transition(easeOutCirc); + +introStepSize: size(400px, 200px); +introSize: size(400px, 400px); +introSlideShift: 500px; // intro hiding animation +introSlideDuration: 200; +introSlideDelta: 0; // between hide start and show start +introHideFunc: transition(easeInCirc); +introShowFunc: transition(easeOutCirc); +introAlphaHideFunc: transition(easeOutCirc); +introAlphaShowFunc: transition(easeInCirc); +introTextSize: size(400px, 97px); + +introTitleFont: font(24px); +introDescFont: font(18px); + +btnIntroSep: 12px; +btnIntroNext: flatButton(btnDefNext, btnDefBig) { + width: 144px; +} +btnIntroBack: flatButton(btnIntroNext, btnDefBack) { +} + +btnIntroStart: flatButton(btnIntroNext) { + width: 300px; +} +btnIntroFinish: flatButton(btnIntroNext) { + width: 240px; +} + +boxShadow: sprite(240px, 21px, 9px, 9px); + +introCountry: countryInput { + width: 300px; + height: 41px; + top: 24px; + bgColor: #ebebeb; + ptrSize: size(15px, 8px); + textMrg: margins(16px, 5px, 16px, 15px); + font: inpDefFont; + align: align(left); +} + +introPhoneTop: 8px; +inpIntroCountryCode: flatInput(inpDefGray) { + width: 70px; + height: 41px; + align: align(center); +} +inpIntroPhone: flatInput(inpDefGray) { + textMrg: margins(12px, 5px, 12px, 6px); + width: 225px; + height: 41px; +} +inpIntroCode: flatInput(inpDefGray) { + textMrg: margins(12px, 5px, 12px, 6px); + width: 106px; + height: 41px; + + phPos: point(0px, 0px); + phAlign: align(center); + phShift: 0px; +} +inpIntroName: flatInput(inpIntroPhone) { + width: 240px; +} + +introSelectDelta: 30px; +introSelectMaxHeight: 550px; +btnSelectDone: flatButton(btnDefFlat) { + color: btnYesColor; + overColor: btnYesHover; + downColor: btnYesHover; + + bgColor: white; + overBgColor: btnBoxWhiteHover; + downBgColor: btnBoxWhiteHover; + + width: 182px; + height: 52px; + + textTop: 14px; + overTextTop: 14px; + downTextTop: 15px; + + font: font(17px); + overFont: font(17px); +} +btnSelectCancel: flatButton(btnSelectDone) { + width: 181px; + color: btnNoColor; + overColor: btnNoHover; + downColor: btnNoHover; +} +btnSelectSep: #e0e0e0; + +countryList: countryList { + notFoundColor: #aaa;//rgb(20, 136, 210); + notFoundFont: font(18px); + + verticalMargin: 0px; + + font: font(18px); + codeFont: font(16px); + rowHeight: 42px; + color: #000; + codeColor: #aaaaaa;//rgb(20, 136, 210); + bgColor: #FFF; + bgHovered: #f1f1f1; + margin: 13px; + codeWidth: 60px; + + borderMargin: 0px; + borderColor: rgba(228, 233, 240, 127); + borderWidth: 0px; +} + +countriesSlideShift: 500px; +countriesSlideDuration: 200; +countriesHideFunc: transition(easeInCirc); +countriesShowFunc: transition(easeOutCirc); +countriesBackHideFunc: transition(linear); +countriesBackShowFunc: transition(linear); +countriesAlphaHideFunc: transition(easeOutCirc); +countriesAlphaShowFunc: transition(easeInCirc); + +introBtnTop: 244px; + +introErrWidth: 450px; +introErrDuration: 200; +introErrFunc: transition(linear); +introErrBG: #ffa5a5; +introErrColor: black;//#800000; +introErrTop: 15px; +introErrHeight: 40px; +introErrFont: font(16px); + +introErrLabel: flatLabel(labelDefFlat) { + font: introErrFont; +} + +setWidth: 356px; +setTop: 26px; +setNameLeft: 3px; +setNameTop: 0px; +setNameFont: font(23px); +setPhoneFont: font(16px); +setPhoneColor: #999; +setPhoneTop: 38px; +setPhoneLeft: 1px; +setPhotoSize: 120px; +setHeaderFont: font(20px); +setHeaderColor: black; +setHeaderSkip: 59px; +setHeaderLeft: -1px; +setHeaderTop: 21px; +setLittleSkip: 9px; +setSectionSkip: 25px; +setVersionHeight: 41px; +setVersionLeft: 36px; +setVersionTop: 2px; +setVersionColor: #999; +setBottom: 130px; +setScroll: flatScroll(scrollDef) { + bottomsh: 0px; + topsh: 0px; +} +setClose: iconedButton(btnDefIconed) { + icon: sprite(245px, 221px, 43px, 43px); + iconPos: point(0px, 0px); + downIcon: sprite(245px, 221px, 43px, 43px); + downIconPos: point(0px, 0px); + + width: 43px; + height: 43px; +} +setClosePos: point(18px, 18px); +setPhotoImg: sprite(0px, 220px, 120px, 120px); +setOverPhotoImg: sprite(122px, 220px, 120px, 120px); +setPhotoDuration: 150; + +setPadding: 26px; +setBG: #FFF; +setSh: #000; +setTitleFrom: point(20px, 20px); +setTitleFont: font(24px); +setTitleColor: #000; +setNameInput: flatInput(inpDefFlat) { + font: font(14px); + height: 25px; + width: 170px; + textMrg: margins(3px, 3px, 3px, 3px); +} +setErrBG: #ffa5a5; +setErrColor: #800000; +setErrHeight: 30px; +setErrFont: font(14px); + +btnSetUpload: flatButton(btnDefNext, btnDefBig) { + width: 206px; + height: 42px; + font: font(18px); + overFont: font(18px); + + textTop: 9px; + overTextTop: 9px; + downTextTop: 10px; +} + +btnEditSave: flatButton(btnSetUpload) { + width: 115px; +} +btnEditCancel: flatButton(btnDefFlat, btnDefBig) { + color: #666d78; + overColor: #666d78; + downColor: #50565e; + + bgColor: rgba(0, 0, 0, 63); + overBgColor: rgba(0, 0, 0, 47); + downBgColor: rgba(0, 0, 0, 95); + + width: 115px; + height: 40px; + + textTop: 9px; + overTextTop: 9px; + downTextTop: 10px; + + font: font(18px); + overFont: font(18px); +} + +btnLogout: flatButton(btnDefFlat, btnDefBig) { + color: white; + overColor: white; + downColor: white; + + bgColor: #db6352; + overBgColor: #d15948; + downBgColor: #c74d3b; + + width: 148px; + height: 42px; + + textTop: 8px; + overTextTop: 8px; + downTextTop: 9px; + + font: font(18px); + overFont: font(18px); +} + +//// dialogs +dlgFilterPadding: 10px; +dlgPhotoSize: 46px; +dlgPaddingHor: 10px; +dlgPaddingVer: 8px; +dlgHeight: 62px; +dlgPhotoPadding: 12px; + +dlgSep: 6px; + +dlgShadowColor: rgba(0, 0, 0, 24);//#ebebeb +dlgShadow: 1px; + +dlgMinWidth: 260px; +dlgRichMinWidth: 150px; +dlgMaxWidth: 540px; +dlgFilter: flatInput(inpDefGray) { + font: font(14px); + height: 34px; + bgColor: #f2f2f2; + phColor: #949494; + phFocusColor: #a4a4a4; + textMrg: margins(34px, 2px, 5px, 4px); + imgRect: sprite(208px, 28px, 24px, 24px); + imgPos: point(6px, 5px); + width: 240px; + + borderWidth: 2px; + borderColor: #f2f2f2; + borderActive: #80cff9; + borderError: #ed8080; +} +dlgScroll: flatScroll(scrollDef) { + topsh: 0px; + bottomsh: 0px; +} +dlgFont: font(14px); + +dlgDblCheckImg: sprite(302px, 23px, 17px, 11px); +dlgCheckImg: sprite(320px, 23px, 17px, 11px); +dlgActiveDblCheckImg: sprite(302px, 36px, 17px, 11px); +dlgActiveCheckImg: sprite(320px, 36px, 17px, 11px); +dlgSendImg: sprite(122px, 25px, 17px, 11px); +dlgActiveSendImg: sprite(142px, 25px, 17px, 11px); +dlgChatImg: sprite(302px, 51px, 16px, 11px); +dlgActiveChatImg: sprite(322px, 51px, 16px, 11px); + +dlgChatImgLeft: 1px; +dlgChatImgTop: 5px; +dlgChatImgSkip: 22px; + +dlgCheckLeft: 5px; +dlgCheckTop: 5px; +dlgCheckSkip: 3px; + +dlgFromFont: font(12px bold); +dlgFromColor: #4981af; + +dlgHistFont: font(14px); +dlgNameColor: #000; +dlgNameTop: 1px; +dlgSystemColor: #4981af; +dlgTextColor: #888888; + +dlgDateFont: font(13px); +dlgDateColor: #a8a8a8; +dlgDateSkip: 5px; + +dlgUnreadColor: #FFF; +dlgUnreadBG: #6fc766; +dlgUnreadFont: font(12px bold); +dlgUnreadPaddingHor: 5px; +dlgUnreadPaddingVer: 1px; +dlgUnreadRadius: 2px; +dlgBG: #FFF; +dlgHoverBG: #f5f5f5; + +dlgActiveBG: #6a91b1; +dlgActiveUnreadColor: #5b94bf; +dlgActiveUnreadBG: white; +dlgActiveColor: white; +dlgActiveDateColor: #d3e2ee; + +topBarHeight: 54px; +topBarBG: white; +topBarDuration: 200; +topBarForwardPadding: margins(17px, 7px, 40px, 8px); +topBarForwardAlpha: 0.6; +topBarForwardImg: sprite(45px, 112px, 9px, 16px); +topBarBackPadding: margins(15px, 7px, 9px, 7px); +topBarBackAlpha: 0.8; +topBarBackImg: sprite(65px, 112px, 9px, 16px); +topBarBackColor: #005faf; +topBarBackFont: font(16px); +topBarButton: flatButton(btnDefFlat) { + color: btnYesColor; + overColor: btnYesHover; + downColor: btnYesHover; + + bgColor: white; + overBgColor: white; + downBgColor: white; + + width: -40px; + height: 54px; + + textTop: 18px; + overTextTop: 18px; + downTextTop: 19px; + + font: font(14px); + overFont: font(14px underline); +} +topBarActionButton: flatButton(btnDefNext, btnDefBig) { + textTop: 8px; + overTextTop: 8px; + downTextTop: 9px; + + font: font(14px); + overFont: font(14px); + width: 101px; + height: 34px; +} +topBarActionSkip: 13px; +topBarSelectedPos: point(18px, 18px); + +historyBG: #dfe4e8; +msgMaxWidth: 550px; +msgFont: font(14px); +msgNameFont: font(14px semibold); +msgServiceFont: font(14px semibold); +msgServiceNameFont: font(14px semibold); +msgDateFont: font(13px); +msgMinWidth: 190px; +msgPhotoSize: 30px; +msgPhotoSkip: 40px; +msgPadding: margins(13px, 7px, 13px, 8px); +msgMargin: margins(13px, 4px, 53px, 4px); +msgLnkPadding: 2px; // for media open / save links +msgBorder: #f0f0f0; +msgOutBG: #effdde; +msgInBG: #fff; +msgOutSelectBG: #b7dbdb; +msgInSelectBG: #c2dcf2; // #358cd4 with 30% opacity +msgOutSelectOverlay: #358cd44c; +msgInSelectOverlay: #358cd44c; +msgOutServiceColor: #3a8e26; +msgInServiceColor: #0e7acd; +msgShadow: 2px; +msgInShadow: #748ea229; +msgOutShadow: #3ac34740; +msgInSelectShadow: #548dbb29; +msgOutSelectShadow: #37a78e40; +msgInDateColor: #a0acb6; +msgOutDateColor: #6cc264; +msgInSelectDateColor: #6a9cc5; +msgOutSelectDateColor: #50a79c; + +msgServiceSelectBG: #fff4; +msgServiceRadius: 2px; + +msgServiceBG: #89a0b47f; +msgServiceColor: #FFF; +msgServicePadding: margins(12px, 3px, 12px, 4px); +msgServiceMargin: margins(10px, 7px, 80px, 7px); + +msgColor: #000; +msgDateColor: #000; +msgLinkColor: #2a6dc2; +msgPressedLinkColor: #004bad; +msgSkip: 40px; +msgPtr: 8px; +msgBG: ':/gui/art/bg.png' / 2:':/gui/art/bg_125x.png' / 3:':/gui/art/bg_150x.png' / 4:':/gui/art/bg_200x.png'; + +msgSendingRect: sprite(260px, 20px, 20px, 20px); +msgCheckRect: sprite(320px, 0px, 20px, 20px); +msgDblCheckRect: sprite(300px, 0px, 20px, 20px); +msgSelectCheckRect: sprite(160px, 0px, 20px, 20px); +msgSelectDblCheckRect: sprite(140px, 0px, 20px, 20px); +msgDateSpace: 19px; +msgDateCheckSpace: 4px; +msgDateDelta: point(2px, 5px); + +msgImgSendingRect: sprite(280px, 40px, 20px, 20px); +msgImgCheckRect: sprite(280px, 20px, 20px, 20px); +msgImgDblCheckRect: sprite(260px, 40px, 20px, 20px); +msgDateImgDelta: 4px; +msgDateImgColor: #fff; +msgDateImgBg: #00000054; +msgDateImgPadding: point(8px, 2px); +msgDateImgCheckSpace: 4px; + +msgDogImg: sprite(213px, 93px, 126px, 126px); +historyPadding: 10px; + +defaultTextStyle: textStyle { + lnkFlags: font(14px); + lnkOverFlags: font(14px underline); + lnkColor: btnYesColor; + lnkDownColor: btnYesHover; + selectBG: msgInSelectBG; + selectOverlay: msgInSelectOverlay; + lineHeight: 0px; +} +serviceTextStyle: textStyle(defaultTextStyle) { + lnkColor: msgServiceColor; + lnkDownColor: msgServiceColor; + selectBG: msgServiceSelectBG; + selectOverlay: msgServiceSelectBG; +} +inTextStyle: textStyle(defaultTextStyle) { + selectBG: msgInSelectBG; + selectOverlay: msgInSelectOverlay; +} +outTextStyle: textStyle(defaultTextStyle) { + selectBG: msgOutSelectBG; + selectOverlay: msgOutSelectOverlay; +} + +dlgTextStyle: textStyle(defaultTextStyle) { + lnkColor: dlgSystemColor; + lnkDownColor: dlgSystemColor; + lnkOverFlags: font(14px); +} +dlgActiveTextStyle: textStyle(defaultTextStyle) { + lnkColor: dlgActiveColor; + lnkDownColor: dlgActiveColor; + lnkOverFlags: font(14px); +} + +mediaMaxWidth: 250px; +mediaFont: font(14px); +mediaPadding: margins(7px, 6px, 11px, 6px); +mediaThumbSize: 48px; +mediaDocOutImg: sprite(6px, 146px, 48px, 48px); +mediaDocInImg: sprite(56px, 146px, 48px, 48px); +mediaAudioOutImg: sprite(106px, 146px, 48px, 48px); +mediaAudioInImg: sprite(156px, 146px, 48px, 48px); +mediaInColor: msgInDateColor; +mediaOutColor: msgOutDateColor; +mediaInSelectColor: msgInSelectDateColor; +mediaOutSelectColor: msgOutSelectDateColor; +mediaSaveDelta: 14px; // between bubble and download +mediaSaveButton: flatButton(btnDefFlat) { + color: btnYesColor; + overColor: btnYesHover; + downColor: btnYesHover; + + bgColor: white; + overBgColor: btnWhiteHover; + downBgColor: btnWhiteHover; + + width: -28px; + height: 34px; + + textTop: 7px; + overTextTop: 7px; + downTextTop: 8px; + + font: font(14px); + overFont: font(14px); +} + +sendPadding: 8px; +btnSend: flatButton(btnDefFlat) { + color: btnYesColor; + overColor: btnYesHover; + downColor: btnYesHover; + + bgColor: white; + overBgColor: btnWhiteHover; + downBgColor: btnWhiteHover; + + width: -32px; + height: 46px; + + textTop: 13px; + overTextTop: 13px; + downTextTop: 14px; + + font: font(16px); + overFont: font(16px); +} + +btnAttachDocument: iconedButton(btnDefIconed) { + icon: sprite(218px, 68px, 24px, 24px); + iconPos: point(11px, 11px); + downIcon: sprite(218px, 68px, 24px, 24px); + downIconPos: point(11px, 12px); + + overBgColor: btnWhiteHover; + width: 46px; + height: 46px; +} +btnAttachPhoto: iconedButton(btnAttachDocument) { + icon: sprite(278px, 68px, 24px, 24px); + downIcon: sprite(278px, 68px, 24px, 24px); +} +btnAttachEmoji: iconedButton(btnAttachDocument) { + overBgColor: white; + icon: sprite(311px, 221px, 20px, 20px); + iconPos: point(6px, 13px); + downIcon: sprite(311px, 221px, 20px, 20px); + downIconPos: point(6px, 13px); + + width: 32px; +} + +historyScroll: flatScroll(scrollDef) { + barColor: #89a0b47a; + bgColor: #89a0b44c; + barOverColor: #89a0b4bc; + bgOverColor: #89a0b46b; + + round: 2px; + + width: 12px; + deltax: 3px; + deltay: 3px; + + topsh: 0px; + bottomsh: -1px; +} +textRectMargins: margins(-2px, -1px, -2px, -1px); +taMsgField: flatTextarea(taDefFlat) { + font: msgFont; +} +maxFieldHeight: 250px; +minFieldHeight: 30px; + +newMsgSound: ':/gui/art/newmsg.wav'; + +unreadBarHeight: 32px; +unreadBarFont: font(14px semibold); +unreadBarBG: #fcfbfa; +unreadBarBorder: titleShadowColor; +unreadBarColor: #538bb4; + +layerSlideDuration: 200; +layerHideDuration: 200; +layerPadding: margins(10px, 10px, 10px, 10px); + +boxFont: font(16px); +boxPadding: margins(18px, 18px, 18px, 18px); +boxBG: white;//rgb(228, 233, 240); +boxGrayTitle: #777; + +confirmWidth: 364px; +addContactWidth: 364px; +addContactPadding: margins(18px, 24px, 18px, 24px); +addContactDelta: 14px; +addContactTitleHeight: 52px; +addContactTitlePos: point(20px, 15px); +addContactTitleFont: font(17px); +inpAddContact: flatInput(inpDefGray) { + height: 42px; + textMrg: margins(10px, 5px, 10px, 5px); + font: font(15px); +} + +btnNewGroup: iconedButton(btnDefIconed) { + icon: sprite(189px, 118px, 18px, 17px); + iconPos: point(8px, 8px); + downIcon: sprite(189px, 118px, 18px, 17px); + downIconPos: point(8px, 9px); + + bgColor: transparent; + overBgColor: transparent; + width: 36px; + height: 36px; +} +btnAddContact: iconedButton(btnNewGroup) { + icon: sprite(188px, 93px, 18px, 18px); + downIcon: sprite(188px, 93px, 18px, 18px); +} + +notifyBG: white; +notifyBorder: #f1f1f1; +notifySlowHide: 4000; +notifyPhotoSize: 62px; +notifyPhotoPos: point(9px, 9px); +notifyClosePos: point(1px, 2px); +notifyClose: iconedButton(btnDefIconed) { + icon: sprite(167px, 130px, 10px, 10px); + iconPos: point(10px, 10px); + downIcon: sprite(167px, 130px, 10px, 10px); + downIconPos: point(10px, 11px); + + width: 30px; + height: 30px; +} +notifyItemTop: 12px; +notifyTextLeft: 12px; +notifyTextTop: 7px; +notifySlowHideFunc: transition(easeInCirc); +notifyWaitShortHide: 0; +notifyWaitLongHide: 20000; +notifyFastAnim: 100; +notifyFastAnimFunc: transition(linear); +notifyWidth: 316px; +notifyHeight: 80px; +notifyDeltaX: 6px; +notifyDeltaY: 7px; + +cropBoxWidth: 364px; +cropPointSize: 10px; +cropMinSize: 20px; + +profileMaxWidth: 410px; +profilePadding: margins(28px, 30px, 28px, 0px); +profilePhotoSize: 120px; +profileNameLeft: 21px; +profileNameTop: -2px; +profileNameFont: font(20px); +profileStatusLeft: 22px; +profileStatusTop: 30px; +profileStatusFont: font(14px); +profilePhoneLeft: 20px; +profilePhoneTop: 62px; +profilePhoneFont: font(16px); +profileButtonTop: 18px; +profileButtonSkip: 10px; +profileHeaderFont: font(20px); +profileHeaderColor: black; +profileHeaderSkip: 59px; +profileHeaderLeft: -1px; +profileHeaderTop: 21px; + +profileListPhotoSize: 46px; +profileListPadding: size(12px, 6px); +profileListNameTop: 7px; +profileListStatusBottom: 6px; +profileHoverBG: #f1f1f1; +profileActiveBG: #6294b9; +profileSubFont: font(14px); +profileCheckRect: sprite(88px, 108px, 24px, 24px); +profileCheckActiveRect: sprite(128px, 108px, 24px, 24px); +profileCheckDeltaX: 18px; +profileCheckDeltaY: 1px; +profileListNameFont: font(14px semibold); +profileListNameColor: #000; +profileOnlineColor: titleTypingColor; +profileOfflineColor: titleStatusColor; +btnShareContact: flatButton(btnDefNext, btnDefBig) { + width: 145px; + height: 42px; + + textTop: 9px; + overTextTop: 9px; + downTextTop: 10px; + + font: font(17px); + overFont: font(17px); +} + +forwardWidth: 364px; +forwardRadius: 2px; +forwardMargins: margins(30px, 10px, 30px, 10px); +forwardFont: font(16px); +forwardBG: rgba(0, 0, 0, 76); +btnProfileCancel: flatButton(btnDefFlat, btnDefBig) { + color: #666d78; + overColor: #666d78; + downColor: #50565e; + + bgColor: rgba(0, 0, 0, 63); + overBgColor: rgba(0, 0, 0, 47); + downBgColor: rgba(0, 0, 0, 95); + + width: 145px; + height: 40px; + + textTop: 9px; + overTextTop: 9px; + downTextTop: 10px; + + font: font(18px); + overFont: font(18px); +} + +btnDeleteContact: flatButton(btnDefFlat, btnDefBig) { + color: #fff; + overColor: #fff; + downColor: #ffcbc1; + + bgColor: #ee4928bf; + overBgColor: #ee4928; + downBgColor: #d14024; + + width: 300px; + height: 40px; + + textTop: 9px; + overTextTop: 9px; + downTextTop: 10px; + + font: font(18px); + overFont: font(18px); +} + +profileNameInput: flatInput(setNameInput) { + width: 230px; +} + +newGroupScroll: flatScroll(scrollDef) { + topsh: 0px; + bottomsh: -2px; +} + +participantInnerAdd: flatButton(btnDefNext) { + width: 145px; + height: 40px; + font: font(18px); + overFont: font(18px); + textTop: 9px; + overTextTop: 9px; + downTextTop: 10px; +} +participantInnerCancel: flatButton(participantInnerAdd, btnDefBack) { +} +participantCancel: flatButton(participantInnerAdd, btnDefBack) { + width: 300px; +} +participantWidth: 364px; +participantMaxHeight: 600px; +participantFilter: flatInput(inpDefFlat) { + width: 364px; + height: 52px; + font: font(16px); + textMrg: margins(39px, 11px, 10px, 10px); + imgRect: sprite(208px, 28px, 24px, 24px); + imgPos: point(10px, 15px); +} +participantDelta: 12px; + +contactsFilter: flatInput(dlgFilter) { + width: 340px; + height: 38px; + textMrg: margins(34px, 3px, 5px, 4px); + imgPos: point(6px, 7px); +} +newGroupName: flatInput(inpDefGray) { + width: 340px; + height: 44px; + font: font(15px); + textMrg: margins(12px, 5px, 12px, 5px); +} +inpCountry: flatInput(contactsFilter) { +} +newGroupNamePadding: margins(12px, 15px, 12px, 13px); + +connectionSkip: 20px; +inpConnectionHost: flatInput(inpDefGray) { + font: font(14px); + height: 34px; + bgColor: #f2f2f2; + phColor: #949494; + phFocusColor: #a4a4a4; + textMrg: margins(4px, 2px, 5px, 4px); + width: 205px; + + borderWidth: 2px; + borderColor: #f2f2f2; + borderActive: #80cff9; + borderError: #ed8080; +} +inpConnectionPort: flatInput(inpConnectionHost) { + width: 80px; +} +inpConnectionUser: flatInput(inpConnectionHost) { + width: 130px; +} +inpConnectionPassword: flatInput(inpConnectionHost) { + width: 155px; +} + +contactsClose: flatButton { + color: btnYesColor; + overColor: btnYesHover; + downColor: btnYesHover; + + bgColor: #fffe; + overBgColor: white; + downBgColor: white; + + width: 364px; + height: 46px; + + textTop: 12px; + overTextTop: 12px; + downTextTop: 13px; + + font: font(16px); + overFont: font(16px); +} +contactsImg: sprite(45px, 112px, 9px, 16px); +contactsAdd: flatButton(topBarButton) { + width: -40px; + height: 52px; + + textTop: 18px; + overTextTop: 18px; + downTextTop: 19px; +} + +aboutIcon: sprite(2px, 2px, 104px, 104px); +aboutIconTop: 28px; +aboutWidth: 448px; +aboutHeight: 441px; +aboutHeaderFont: font(24px semibold); +aboutSubheaderFont: font(24px); +aboutHeaderTop: 139px; +aboutVersionFont: font(16px); +aboutVersionColor: #999; +aboutVersionTop: 178px; +aboutTextFont: font(15px); +aboutTextTop: 221px; +aboutLabel: flatLabel(labelDefFlat) { + font: aboutTextFont; + width: aboutWidth; + align: align(center); +} +aboutTextStyle: textStyle(defaultTextStyle) { + lineHeight: 24px; +} +aboutCloseButton: flatButton(contactsClose) { + width: aboutWidth; + height: 52px; + textTop: 15px; + overTextTop: 15px; + downTextTop: 16px; +} + +emojiTextFont: font(16px); +emojiReplaceWidth: 56px; +emojiReplaceHeight: 56px; +emojiReplaceInnerHeight: 38px; + +connectingBG: #fffe; +connectingColor: #777; +connectingPadding: margins(5px, 5px, 5px, 5px); + +dropdownPadding: margins(10px, 10px, 10px, 10px); +dropdownShadow: sprite(240px, 35px, 6px, 6px); +dropdownBorder: 1px; +dropdownBorderColor: #ebebeb; +dropdownBackground: white; + +dropdownAttachDocument: iconedButton(btnAttachDocument) { + iconPos: point(14px, 13px); + downIconPos: point(14px, 14px); + + width: 172px; + height: 49px; + + color: black; + + font: font(16px); + + textPos: point(50px, 13px); + downTextPos: point(50px, 14px); +} +dropdownAttachPhoto: iconedButton(dropdownAttachDocument) { + icon: sprite(278px, 68px, 24px, 24px); + downIcon: sprite(278px, 68px, 24px, 24px); +} + +dragFont: font(28px semibold); +dragSubfont: font(20px semibold); +dragColor: #777; +dragDropColor: btnYesColor; + +dragMargin: margins(0px, 10px, 0px, 10px); +dragPadding: margins(20px, 10px, 20px, 10px); + +dragHeight: 72px; + +selectedFont: font(14px); +selectedColor: #777; +selectedTop: 14px; + +downloadSkip: 20px; +inpDownloadDir: flatInput(inpDefGray) { + font: font(14px); + height: 34px; + bgColor: #fff; + textMrg: margins(5px, 2px, 5px, 4px); + width: 295px; + + borderWidth: 2px; + borderColor: #f2f2f2; +} + +dpiSlider: slider { + color: #ccc; + thikness: 2px; + + width: 260px; + bar: sprite(6px, 110px, 9px, 22px); +} +dpiActive: black; +dpiInactive: #999; +dpiFont1: linkFont; +dpiFont2: linkFont; +dpiFont3: linkFont; +dpiFont4: linkFont; + +emojiScroll: flatScroll(scrollDef) { + topsh: 0px; + bottomsh: 0px; +} +emojiRecentActive: sprite(290px, 287px, 20px, 20px); +emojiRecentOver: sprite(311px, 287px, 20px, 20px); +emojiRecent: sprite(6px, 197px, 20px, 20px); +emojiPeopleActive: sprite(290px, 221px, 20px, 20px); +emojiPeopleOver: sprite(311px, 221px, 20px, 20px); +emojiPeople: sprite(27px, 197px, 20px, 20px); +emojiNatureActive: sprite(245px, 266px, 20px, 20px); +emojiNatureOver: sprite(266px, 266px, 20px, 20px); +emojiNature: sprite(48px, 197px, 20px, 20px); +emojiObjectsActive: sprite(290px, 242px, 20px, 20px); +emojiObjectsOver: sprite(311px, 242px, 20px, 20px); +emojiObjects: sprite(69px, 197px, 20px, 20px); +emojiPlacesActive: sprite(245px, 287px, 20px, 20px); +emojiPlacesOver: sprite(266px, 287px, 20px, 20px); +emojiPlaces: sprite(90px, 197px, 20px, 20px); +emojiSymbolsActive: sprite(290px, 266px, 20px, 20px); +emojiSymbolsOver: sprite(311px, 266px, 20px, 20px); +emojiSymbols: sprite(111px, 197px, 20px, 20px); +rbEmoji: flatCheckbox { + textColor: transparent; + bgColor: transparent; + disColor: transparent; + + width: 36px; + height: 36px; + + textTop: 0px; + textLeft: 0px; + font: font(14px); + duration: 200; + bgFunc: transition(easeOutCirc); + cursor: cursor(pointer); + + disabledCursor: cursor(default); + imagePos: point(8px, 8px); +} +rbEmojiRecent: flatCheckbox(rbEmoji) { + imageRect: emojiRecent; + chkImageRect: emojiRecentActive; + overImageRect: emojiRecentOver; + chkOverImageRect: emojiRecentActive; + disImageRect: emojiRecent; + chkDisImageRect: emojiRecentActive; +} +rbEmojiPeople: flatCheckbox(rbEmoji) { + imageRect: emojiPeople; + chkImageRect: emojiPeopleActive; + overImageRect: emojiPeopleOver; + chkOverImageRect: emojiPeopleActive; + disImageRect: emojiPeople; + chkDisImageRect: emojiPeopleActive; +} +rbEmojiNature: flatCheckbox(rbEmoji) { + imageRect: emojiNature; + chkImageRect: emojiNatureActive; + overImageRect: emojiNatureOver; + chkOverImageRect: emojiNatureActive; + disImageRect: emojiNature; + chkDisImageRect: emojiNatureActive; +} +rbEmojiObjects: flatCheckbox(rbEmoji) { + imageRect: emojiObjects; + chkImageRect: emojiObjectsActive; + overImageRect: emojiObjectsOver; + chkOverImageRect: emojiObjectsActive; + disImageRect: emojiObjects; + chkDisImageRect: emojiObjectsActive; +} +rbEmojiPlaces: flatCheckbox(rbEmoji) { + imageRect: emojiPlaces; + chkImageRect: emojiPlacesActive; + overImageRect: emojiPlacesOver; + chkOverImageRect: emojiPlacesActive; + disImageRect: emojiPlaces; + chkDisImageRect: emojiPlacesActive; +} +rbEmojiSymbols: flatCheckbox(rbEmoji) { + imageRect: emojiSymbols; + chkImageRect: emojiSymbolsActive; + overImageRect: emojiSymbolsOver; + chkOverImageRect: emojiSymbolsActive; + disImageRect: emojiSymbols; + chkDisImageRect: emojiSymbolsActive; +} +emojiPanPadding: margins(10px, 5px, 0px, 5px); +emojiPanSize: size(28px, 28px); +emojiPanFont: font(14px); +emojiPanText: #999; +emojiPanSub: 0px; +emojiPanDuration: 200; +emojiPanHover: #f0f0f0; +emojiPanRound: 2px; diff --git a/Telegram/Resources/style_classes.txt b/Telegram/Resources/style_classes.txt new file mode 100644 index 000000000..568e08ace --- /dev/null +++ b/Telegram/Resources/style_classes.txt @@ -0,0 +1,231 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +textStyle { + lnkFlags: font; + lnkOverFlags: font; + lnkColor: color; + lnkDownColor: color; + selectBG: color; + selectOverlay: color; + lineHeight: number; +} + +linkButton { + color: color; + overColor: color; + downColor: color; + font: font; + overFont: font; +} + +sysButton { + size: size; + img: sprite; + color: color; + overColor: color; + duration: number; +} + +flatButton { + color: color; + overColor: color; + downColor: color; + + bgColor: color; + overBgColor: color; + downBgColor: color; + + width: number; + height: number; + + textTop: number; + overTextTop: number; + downTextTop: number; + + font: font; + overFont: font; + duration: number; + cursor: cursor; +} + +iconedButton { + icon: sprite; + iconPos: point; + downIcon: sprite; + downIconPos: point; + + color: color; + bgColor: color; + overBgColor: color; + width: number; + height: number; + font: font; + + opacity: number; + overOpacity: number; + + textPos: point; + downTextPos: point; + + duration: number; + cursor: cursor; +} + +flatCheckbox { + textColor: color; + bgColor: color; + disColor: color; + + width: number; + height: number; + textTop: number; + textLeft: number; + font: font; + duration: number; + bgFunc: transition; + cursor: cursor; + + disabledCursor: cursor; + + imageRect: sprite; + chkImageRect: sprite; + overImageRect: sprite; + chkOverImageRect: sprite; + disImageRect: sprite; + chkDisImageRect: sprite; + + imagePos: point; +} + +flatInput { + textColor: color; + bgColor: color; + bgActive: color; + width: number; + height: number; + textMrg: margins; + align: align; + font: font; + cursor: cursor; + + imgRect: sprite; + imgPos: point; + + borderWidth: number; + borderColor: color; + borderActive: color; + borderError: color; + + phColor: color; + phFocusColor: color; + phPos: point; + phAlign: align; + phShift: number; + phDuration: number; + phLeftFunc: transition; + phAlphaFunc: transition; + phColorFunc: transition; +} + +flatTextarea { + textColor: color; + bgColor: color; + width: number; + textMrg: margins; + align: align; + font: font; + cursor: cursor; + + phColor: color; + phFocusColor: color; + phPos: point; + phAlign: align; + phShift: number; + phDuration: number; + phLeftFunc: transition; + phAlphaFunc: transition; + phColorFunc: transition; +} + +flatScroll { + barColor: color; + bgColor: color; + barOverColor: color; + bgOverColor: color; + + round: number; + + width: number; + minHeight: number; + deltax: number; + deltay: number; + + topsh: number; + bottomsh: number; + shColor: color; + + duration: number; + hiding: number; +} + +countryInput { + width: number; + height: number; + top: number; + bgColor: color; + ptrSize: size; + textMrg: margins; + font: font; + align: align; +} + +countryList { + notFoundColor: color; + notFoundFont: font; + + verticalMargin: number; + + font: font; + codeFont: font; + rowHeight: number; + color: color; + codeColor: color; + bgColor: color; + bgHovered: color; + margin: number; + codeWidth: number; + + borderMargin: number; + borderColor: color; + borderWidth: number; +} + +slider { + color: color; + thikness: number; + + width: number; + bar: sprite; +} + +flatLabel { + font: font; + minWidth: number; + width: number; + align: align; +} diff --git a/Telegram/Setup.iss b/Telegram/Setup.iss new file mode 100644 index 000000000..d8963573c --- /dev/null +++ b/Telegram/Setup.iss @@ -0,0 +1,116 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +#define MyAppShortName "Telegram" +#define MyAppName "Telegram Win (Unofficial)" +#define MyAppVersion "0.4.18" +#define MyAppVersionZero "0.4.18" +#define MyAppFullVersion "0.4.18.0" +#define MyAppPublisher "Telegram (Unofficial)" +#define MyAppURL "https://tdesktop.com" +#define MyAppExeName "Telegram.exe" +#define MyAppId "53F49750-6209-4FBF-9CA8-7A333C87D1ED" + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. +; Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +AppId={{{#MyAppId}} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +;AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} +DefaultDirName={userappdata}\{#MyAppName} +DefaultGroupName={#MyAppName} +AllowNoIcons=yes +OutputDir=.\..\Win32\Release +OutputBaseFilename=tsetup.{#MyAppVersionZero} +SetupIconFile=.\SourceFiles\art\iconround256.ico +UninstallDisplayIcon={app}\Telegram.exe +Compression=lzma +SolidCompression=yes +DisableStartupPrompt=yes +PrivilegesRequired=lowest +VersionInfoVersion={#MyAppFullVersion} + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}" +Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; OnlyBelowVersion: 0,6.1 + +[Files] +Source: ".\..\Win32\Release\Telegram.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: ".\..\Win32\Release\Updater.exe"; DestDir: "{app}"; Flags: ignoreversion +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{group}\{#MyAppShortName}"; Filename: "{app}\{#MyAppExeName}" +Name: "{group}\{cm:UninstallProgram,{#MyAppShortName}}"; Filename: "{uninstallexe}" +Name: "{userdesktop}\{#MyAppShortName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon +Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppShortName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon + +[Run] +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppShortName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent + +[UninstallDelete] +Type: files; Name: "{app}\data" +Type: files; Name: "{app}\data_config" +Type: files; Name: "{app}\log.txt" +Type: filesandordirs; Name: "{app}\DebugLogs" +Type: filesandordirs; Name: "{app}\tupdates" +Type: filesandordirs; Name: "{app}\tdata" +Type: filesandordirs; Name: "{app}\tdumps" +Type: dirifempty; Name: "{app}" +Type: files; Name: "{userappdata}\{#MyAppName}\data" +Type: files; Name: "{userappdata}\{#MyAppName}\data_config" +Type: files; Name: "{userappdata}\{#MyAppName}\log.txt" +Type: filesandordirs; Name: "{userappdata}\{#MyAppName}\DebugLogs" +Type: filesandordirs; Name: "{userappdata}\{#MyAppName}\tupdates" +Type: filesandordirs; Name: "{userappdata}\{#MyAppName}\tdata" +Type: filesandordirs; Name: "{userappdata}\{#MyAppName}\tdumps" +Type: dirifempty; Name: "{userappdata}\{#MyAppName}" + +[Code] +procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); +var ResultCode: Integer; +begin + if CurUninstallStep = usUninstall then + begin + ShellExec('', ExpandConstant('{app}\{#MyAppExeName}'), '-cleanup', '', SW_SHOW, ewWaitUntilTerminated, ResultCode); + end; +end; + +const CSIDL_DESKTOPDIRECTORY = $0010; + CSIDL_COMMON_DESKTOPDIRECTORY = $0019; + +procedure CurStepChanged(CurStep: TSetupStep); +var ResultCode: Integer; + HasOldKey: Boolean; + HasNewKey: Boolean; + HasOldLnk: Boolean; + HasNewLnk: Boolean; + UserDesktopLnk: String; + CommonDesktopLnk: String; +begin + if CurStep = ssPostInstall then + begin + HasNewKey := RegKeyExists(HKEY_CURRENT_USER, 'Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{{#MyAppId}}_is1') or RegKeyExists(HKEY_CURRENT_USER, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{{#MyAppId}}_is1'); + HasOldKey := RegKeyExists(HKEY_LOCAL_MACHINE, 'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{{#MyAppId}}_is1') or RegKeyExists(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{{#MyAppId}}_is1'); + UserDesktopLnk := ExpandFileName(GetShellFolderByCSIDL(CSIDL_DESKTOPDIRECTORY, False) + '\{#MyAppShortName}.lnk'); + CommonDesktopLnk := ExpandFileName(GetShellFolderByCSIDL(CSIDL_COMMON_DESKTOPDIRECTORY, False) + '\{#MyAppShortName}.lnk'); + HasNewLnk := FileExists(UserDesktopLnk); + HasOldLnk := FileExists(CommonDesktopLnk) and (UserDesktopLnk <> CommonDesktopLnk); + if (HasOldKey and HasNewKey) or (HasOldLnk and HasNewLnk) then + begin + if (GetWindowsVersion >= $06000000) then // Vista or later + ShellExec('runas', ExpandConstant('{app}\{#MyAppExeName}'), '-fixprevious', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) + else + ShellExec('', ExpandConstant('{app}\{#MyAppExeName}'), '-fixprevious', '', SW_SHOW, ewWaitUntilTerminated, ResultCode); + end; + end; +end; diff --git a/Telegram/SetupFiles/data b/Telegram/SetupFiles/data new file mode 100644 index 000000000..e69de29bb diff --git a/Telegram/SetupFiles/log.txt b/Telegram/SetupFiles/log.txt new file mode 100644 index 000000000..e69de29bb diff --git a/Telegram/SourceFiles/_other/genemoji.cpp b/Telegram/SourceFiles/_other/genemoji.cpp new file mode 100644 index 000000000..817e23a24 --- /dev/null +++ b/Telegram/SourceFiles/_other/genemoji.cpp @@ -0,0 +1,1280 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "genemoji.h" + +#include +Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin) + +typedef unsigned int uint32; + +struct EmojiData { + uint32 code, code2; + int x, y; + QString name, name_200x; +}; + +// copied from emojibox.cpp +struct EmojiReplace { + uint32 code; + const char *replace; +}; + +EmojiReplace replaces[] = { + {0xD83DDE0A, ":-)"}, + {0xD83DDE03, ":-D"}, + {0xD83DDE09, ";-)"}, + {0xD83DDE06, "xD"}, + {0xD83DDE1C, ";-P"}, + {0xD83DDE0B, ":-p"}, + {0xD83DDE0D, "8-)"}, + {0xD83DDE0E, "B-)"}, + {0xD83DDE12, ":-("}, + {0xD83DDE0F, ":]"}, + {0xD83DDE14, "3("}, + {0xD83DDE22, ":'("}, + {0xD83DDE2D, ":_("}, + {0xD83DDE29, ":(("}, + {0xD83DDE28, ":o"}, + {0xD83DDE10, ":|"}, + {0xD83DDE0C, "3-)"}, + {0xD83DDE20, ">("}, + {0xD83DDE21, ">(("}, + {0xD83DDE07, "O:)"}, + {0xD83DDE30, ";o"}, + {0xD83DDE33, "8|"}, + {0xD83DDE32, "8o"}, + {0xD83DDE37, ":X"}, + {0xD83DDE1A, ":-*"}, + {0xD83DDE08, "}:)"}, + {0x2764, "<3"}, + {0xD83DDC4D, ":like:"}, + {0xD83DDC4E, ":dislike:"}, + {0x261D, ":up:"}, + {0x270C, ":v:"}, + {0xD83DDC4C, ":ok:"} +}; +const uint32 replacesCount = sizeof(replaces) / sizeof(EmojiReplace); +typedef QMap ReplaceMap; +ReplaceMap replaceMap; + +static const int variantsCount = 4, variants[] = { 0, 2, 3, 4 }, inRow = 40, imSizes[] = { 16, 20, 24, 32 }; +static const char *variantPostfix[] = { "", "_125x", "_150x", "_200x" }; +static const char *variantNames[] = { "dbisOne", "dbisOneAndQuarter", "dbisOneAndHalf", "dbisTwo" }; + +typedef QMap EmojisData; +EmojisData emojisData; + +uint32 emojiCategory0[] = { + 0xD83DDE04, + 0xD83DDE03, + 0xD83DDE00, + 0xD83DDE0A, + 0x263A, + 0xD83DDE09, + 0xD83DDE0D, + 0xD83DDE18, + 0xD83DDE1A, + 0xD83DDE17, + 0xD83DDE19, + 0xD83DDE1C, + 0xD83DDE1D, + 0xD83DDE1B, + 0xD83DDE33, + 0xD83DDE01, + 0xD83DDE14, + 0xD83DDE0C, + 0xD83DDE12, + 0xD83DDE1E, + 0xD83DDE23, + 0xD83DDE22, + 0xD83DDE02, + 0xD83DDE2D, + 0xD83DDE2A, + 0xD83DDE25, + 0xD83DDE30, + 0xD83DDE05, + 0xD83DDE13, + 0xD83DDE29, + 0xD83DDE2B, + 0xD83DDE28, + 0xD83DDE31, + 0xD83DDE20, + 0xD83DDE21, + 0xD83DDE24, + 0xD83DDE16, + 0xD83DDE06, + 0xD83DDE0B, + 0xD83DDE37, + 0xD83DDE0E, + 0xD83DDE34, + 0xD83DDE35, + 0xD83DDE32, + 0xD83DDE1F, + 0xD83DDE26, + 0xD83DDE27, + 0xD83DDE08, + 0xD83DDC7F, + 0xD83DDE2E, + 0xD83DDE2C, + 0xD83DDE10, + 0xD83DDE15, + 0xD83DDE2F, + 0xD83DDE36, + 0xD83DDE07, + 0xD83DDE0F, + 0xD83DDE11, + 0xD83DDC72, + 0xD83DDC73, + 0xD83DDC6E, + 0xD83DDC77, + 0xD83DDC82, + 0xD83DDC76, + 0xD83DDC66, + 0xD83DDC67, + 0xD83DDC68, + 0xD83DDC69, + 0xD83DDC74, + 0xD83DDC75, + 0xD83DDC71, + 0xD83DDC7C, + 0xD83DDC78, + 0xD83DDE3A, + 0xD83DDE38, + 0xD83DDE3B, + 0xD83DDE3D, + 0xD83DDE3C, + 0xD83DDE40, + 0xD83DDE3F, + 0xD83DDE39, + 0xD83DDE3E, + 0xD83DDC79, + 0xD83DDC7A, + 0xD83DDE48, + 0xD83DDE49, + 0xD83DDE4A, + 0xD83DDC80, + 0xD83DDC7D, + 0xD83DDCA9, + 0xD83DDD25, + 0x2728, + 0xD83CDF1F, + 0xD83DDCAB, + 0xD83DDCA5, + 0xD83DDCA2, + 0xD83DDCA6, + 0xD83DDCA7, + 0xD83DDCA4, + 0xD83DDCA8, + 0xD83DDC42, + 0xD83DDC40, + 0xD83DDC43, + 0xD83DDC45, + 0xD83DDC44, + 0xD83DDC4D, + 0xD83DDC4E, + 0xD83DDC4C, + 0xD83DDC4A, + 0x270A, + 0x270C, + 0xD83DDC4B, + 0x270B, + 0xD83DDC50, + 0xD83DDC46, + 0xD83DDC47, + 0xD83DDC49, + 0xD83DDC48, + 0xD83DDE4C, + 0xD83DDE4F, + 0x261D, + 0xD83DDC4F, + 0xD83DDCAA, + 0xD83DDEB6, + 0xD83CDFC3, + 0xD83DDC83, + 0xD83DDC6B, + 0xD83DDC6A, + 0xD83DDC6C, + 0xD83DDC6D, + 0xD83DDC8F, + 0xD83DDC91, + 0xD83DDC6F, + 0xD83DDE46, + 0xD83DDE45, + 0xD83DDC81, + 0xD83DDE4B, + 0xD83DDC86, + 0xD83DDC87, + 0xD83DDC85, + 0xD83DDC70, + 0xD83DDE4E, + 0xD83DDE4D, + 0xD83DDE47, + 0xD83CDFA9, + 0xD83DDC51, + 0xD83DDC52, + 0xD83DDC5F, + 0xD83DDC5E, + 0xD83DDC61, + 0xD83DDC60, + 0xD83DDC62, + 0xD83DDC55, + 0xD83DDC54, + 0xD83DDC5A, + 0xD83DDC57, + 0xD83CDFBD, + 0xD83DDC56, + 0xD83DDC58, + 0xD83DDC59, + 0xD83DDCBC, + 0xD83DDC5C, + 0xD83DDC5D, + 0xD83DDC5B, + 0xD83DDC53, + 0xD83CDF80, + 0xD83CDF02, + 0xD83DDC84, + 0xD83DDC9B, + 0xD83DDC99, + 0xD83DDC9C, + 0xD83DDC9A, + 0x2764, + 0xD83DDC94, + 0xD83DDC97, + 0xD83DDC93, + 0xD83DDC95, + 0xD83DDC96, + 0xD83DDC9E, + 0xD83DDC98, + 0xD83DDC8C, + 0xD83DDC8B, + 0xD83DDC8D, + 0xD83DDC8E, + 0xD83DDC64, + 0xD83DDC65, + 0xD83DDCAC, + 0xD83DDC63, + 0xD83DDCAD, +}; + +uint32 emojiCategory1[] = { + 0xD83DDC36, + 0xD83DDC3A, + 0xD83DDC31, + 0xD83DDC2D, + 0xD83DDC39, + 0xD83DDC30, + 0xD83DDC38, + 0xD83DDC2F, + 0xD83DDC28, + 0xD83DDC3B, + 0xD83DDC37, + 0xD83DDC3D, + 0xD83DDC2E, + 0xD83DDC17, + 0xD83DDC35, + 0xD83DDC12, + 0xD83DDC34, + 0xD83DDC11, + 0xD83DDC18, + 0xD83DDC3C, + 0xD83DDC27, + 0xD83DDC26, + 0xD83DDC24, + 0xD83DDC25, + 0xD83DDC23, + 0xD83DDC14, + 0xD83DDC0D, + 0xD83DDC22, + 0xD83DDC1B, + 0xD83DDC1D, + 0xD83DDC1C, + 0xD83DDC1E, + 0xD83DDC0C, + 0xD83DDC19, + 0xD83DDC1A, + 0xD83DDC20, + 0xD83DDC1F, + 0xD83DDC2C, + 0xD83DDC33, + 0xD83DDC0B, + 0xD83DDC04, + 0xD83DDC0F, + 0xD83DDC00, + 0xD83DDC03, + 0xD83DDC05, + 0xD83DDC07, + 0xD83DDC09, + 0xD83DDC0E, + 0xD83DDC10, + 0xD83DDC13, + 0xD83DDC15, + 0xD83DDC16, + 0xD83DDC01, + 0xD83DDC02, + 0xD83DDC32, + 0xD83DDC21, + 0xD83DDC0A, + 0xD83DDC2B, + 0xD83DDC2A, + 0xD83DDC06, + 0xD83DDC08, + 0xD83DDC29, + 0xD83DDC3E, + 0xD83DDC90, + 0xD83CDF38, + 0xD83CDF37, + 0xD83CDF40, + 0xD83CDF39, + 0xD83CDF3B, + 0xD83CDF3A, + 0xD83CDF41, + 0xD83CDF43, + 0xD83CDF42, + 0xD83CDF3F, + 0xD83CDF3E, + 0xD83CDF44, + 0xD83CDF35, + 0xD83CDF34, + 0xD83CDF32, + 0xD83CDF33, + 0xD83CDF30, + 0xD83CDF31, + 0xD83CDF3C, + 0xD83CDF10, + 0xD83CDF1E, + 0xD83CDF1D, + 0xD83CDF1A, + 0xD83CDF11, + 0xD83CDF12, + 0xD83CDF13, + 0xD83CDF14, + 0xD83CDF15, + 0xD83CDF16, + 0xD83CDF17, + 0xD83CDF18, + 0xD83CDF1C, + 0xD83CDF1B, + 0xD83CDF19, + 0xD83CDF0D, + 0xD83CDF0E, + 0xD83CDF0F, + 0xD83CDF0B, + 0xD83CDF0C, + 0xD83CDF0D, + 0x2B50, + 0x2600, + 0x26C5, + 0x2601, + 0x26A1, + 0x2614, + 0x2744, + 0x26C4, + 0xD83CDF00, + 0xD83CDF01, + 0xD83CDF08, + 0xD83CDF0A, +}; + +uint32 emojiCategory2[] = { + 0xD83CDF8D, + 0xD83DDC9D, + 0xD83CDF8E, + 0xD83CDF92, + 0xD83CDF93, + 0xD83CDF8F, + 0xD83CDF86, + 0xD83CDF87, + 0xD83CDF90, + 0xD83CDF91, + 0xD83CDF83, + 0xD83DDC7B, + 0xD83CDF85, + 0xD83CDF84, + 0xD83CDF81, + 0xD83CDF8B, + 0xD83CDF89, + 0xD83CDF8A, + 0xD83CDF88, + 0xD83CDF8C, + 0xD83DDD2E, + 0xD83CDFA5, + 0xD83DDCF7, + 0xD83DDCF9, + 0xD83DDCFC, + 0xD83DDCBF, + 0xD83DDCC0, + 0xD83DDCBD, + 0xD83DDCBE, + 0xD83DDCBB, + 0xD83DDCF1, + 0x260E, + 0xD83DDCDE, + 0xD83DDCDF, + 0xD83DDCE0, + 0xD83DDCE1, + 0xD83DDCFA, + 0xD83DDCFB, + 0xD83DDD0A, + 0xD83DDD09, + 0xD83DDD09, + 0xD83DDD07, + 0xD83DDD14, + 0xD83DDD14, + 0xD83DDCE2, + 0xD83DDCE3, + 0x23F3, + 0x231B, + 0x23F0, + 0x231A, + 0xD83DDD13, + 0xD83DDD12, + 0xD83DDD0F, + 0xD83DDD10, + 0xD83DDD11, + 0xD83DDD0E, + 0xD83DDCA1, + 0xD83DDD26, + 0xD83DDD06, + 0xD83DDD05, + 0xD83DDD0C, + 0xD83DDD0B, + 0xD83DDD0D, + 0xD83DDEC0, + 0xD83DDEBF, + 0xD83DDEBD, + 0xD83DDD27, + 0xD83DDD29, + 0xD83DDD28, + 0xD83DDEAA, + 0xD83DDEAC, + 0xD83DDCA3, + 0xD83DDD2B, + 0xD83DDD2A, + 0xD83DDC8A, + 0xD83DDC89, + 0xD83DDCB0, + 0xD83DDCB4, + 0xD83DDCB5, + 0xD83DDCB7, + 0xD83DDCB6, + 0xD83DDCB3, + 0xD83DDCB8, + 0xD83DDCF2, + 0xD83DDCE7, + 0xD83DDCE5, + 0xD83DDCE4, + 0x2709, + 0xD83DDCE9, + 0xD83DDCE8, + 0xD83DDCEF, + 0xD83DDCEB, + 0xD83DDCEA, + 0xD83DDCEC, + 0xD83DDCED, + 0xD83DDCEE, + 0xD83DDCE6, + 0xD83DDCDD, + 0xD83DDCC4, + 0xD83DDCC3, + 0xD83DDCD1, + 0xD83DDCCA, + 0xD83DDCC8, + 0xD83DDCC9, + 0xD83DDCDC, + 0xD83DDCCB, + 0xD83DDCC5, + 0xD83DDCC6, + 0xD83DDCC7, + 0xD83DDCC1, + 0xD83DDCC2, + 0x2702, + 0xD83DDCCC, + 0xD83DDCCE, + 0x2712, + 0x270F, + 0xD83DDCCF, + 0xD83DDCD0, + 0xD83DDCD5, + 0xD83DDCD7, + 0xD83DDCD8, + 0xD83DDCD9, + 0xD83DDCD3, + 0xD83DDCD4, + 0xD83DDCD2, + 0xD83DDCDA, + 0xD83DDCD6, + 0xD83DDD16, + 0xD83DDCDB, + 0xD83DDD2C, + 0xD83DDD2D, + 0xD83DDCF0, + 0xD83CDFA8, + 0xD83CDFAC, + 0xD83CDFA4, + 0xD83CDFA7, + 0xD83CDFBC, + 0xD83CDFB5, + 0xD83CDFB6, + 0xD83CDFB9, + 0xD83CDFBB, + 0xD83CDFBA, + 0xD83CDFB7, + 0xD83CDFB8, + 0xD83DDC7E, + 0xD83CDFAE, + 0xD83CDCCF, + 0xD83CDFB4, + 0xD83CDC04, + 0xD83CDFB2, + 0xD83CDFAF, + 0xD83CDFC8, + 0xD83CDFC0, + 0x26BD, + 0x26BE, + 0xD83CDFBE, + 0xD83CDFB1, + 0xD83CDFC9, + 0xD83CDFB3, + 0x26F3, + 0xD83DDEB5, + 0xD83DDEB4, + 0xD83CDFC1, + 0xD83CDFC7, + 0xD83CDFC6, + 0xD83CDFBF, + 0xD83CDFC2, + 0xD83CDFCA, + 0xD83CDFC4, + 0xD83CDFA3, + 0x2615, + 0xD83CDF75, + 0xD83CDF76, + 0xD83CDF7C, + 0xD83CDF7A, + 0xD83CDF7B, + 0xD83CDF78, + 0xD83CDF79, + 0xD83CDF77, + 0xD83CDF74, + 0xD83CDF55, + 0xD83CDF54, + 0xD83CDF5F, + 0xD83CDF57, + 0xD83CDF56, + 0xD83CDF5D, + 0xD83CDF5B, + 0xD83CDF64, + 0xD83CDF71, + 0xD83CDF63, + 0xD83CDF65, + 0xD83CDF59, + 0xD83CDF58, + 0xD83CDF5A, + 0xD83CDF5C, + 0xD83CDF72, + 0xD83CDF62, + 0xD83CDF61, + 0xD83CDF73, + 0xD83CDF5E, + 0xD83CDF69, + 0xD83CDF6E, + 0xD83CDF66, + 0xD83CDF68, + 0xD83CDF67, + 0xD83CDF82, + 0xD83CDF70, + 0xD83CDF6A, + 0xD83CDF6B, + 0xD83CDF6C, + 0xD83CDF6D, + 0xD83CDF6F, + 0xD83CDF4E, + 0xD83CDF4F, + 0xD83CDF4A, + 0xD83CDF4B, + 0xD83CDF52, + 0xD83CDF47, + 0xD83CDF49, + 0xD83CDF53, + 0xD83CDF51, + 0xD83CDF48, + 0xD83CDF4C, + 0xD83CDF50, + 0xD83CDF4D, + 0xD83CDF60, + 0xD83CDF46, + 0xD83CDF45, + 0xD83CDF3D, +}; + +uint32 emojiCategory3[] = { + 0xD83CDFE0, + 0xD83CDFE1, + 0xD83CDFEB, + 0xD83CDFE2, + 0xD83CDFE3, + 0xD83CDFE5, + 0xD83CDFE6, + 0xD83CDFEA, + 0xD83CDFE9, + 0xD83CDFE8, + 0xD83DDC92, + 0x26EA, + 0xD83CDFEC, + 0xD83CDFE4, + 0xD83CDF07, + 0xD83CDF06, + 0xD83CDFEF, + 0xD83CDFF0, + 0x26FA, + 0xD83CDFED, + 0xD83DDDFC, + 0xD83DDDFE, + 0xD83DDDFB, + 0xD83CDF04, + 0xD83CDF05, + 0xD83CDF03, + 0xD83DDDFD, + 0xD83CDF09, + 0xD83CDFA0, + 0xD83CDFA1, + 0x26F2, + 0xD83CDFA2, + 0xD83DDEA2, + 0x26F5, + 0xD83DDEA4, + 0xD83DDEA3, + 0x2693, + 0xD83DDE80, + 0x2708, + 0xD83DDCBA, + 0xD83DDE81, + 0xD83DDE82, + 0xD83DDE8A, + 0xD83DDE89, + 0xD83DDE9E, + 0xD83DDE86, + 0xD83DDE84, + 0xD83DDE85, + 0xD83DDE88, + 0xD83DDE87, + 0xD83DDE9D, + 0xD83DDE9D, + 0xD83DDE83, + 0xD83DDE8E, + 0xD83DDE8C, + 0xD83DDE8D, + 0xD83DDE99, + 0xD83DDE98, + 0xD83DDE97, + 0xD83DDE95, + 0xD83DDE96, + 0xD83DDE9B, + 0xD83DDE9A, + 0xD83DDEA8, + 0xD83DDE93, + 0xD83DDE94, + 0xD83DDE92, + 0xD83DDE91, + 0xD83DDE90, + 0xD83DDEB2, + 0xD83DDEA1, + 0xD83DDE9F, + 0xD83DDEA0, + 0xD83DDE9C, + 0xD83DDC88, + 0xD83DDE8F, + 0xD83CDFAB, + 0xD83DDEA6, + 0xD83DDEA5, + 0x26A0, + 0xD83DDEA7, + 0xD83DDD30, + 0x26FD, + 0xD83CDFEE, + 0xD83CDFB0, + 0x2668, + 0xD83DDDFF, + 0xD83CDFAA, + 0xD83CDFAD, + 0xD83DDCCD, + 0xD83DDEA9, + 0xD83CDDEF, + 0xD83CDDF0, + 0xD83CDDE9, + 0xD83CDDE8, + 0xD83CDDFA, + 0xD83CDDEB, + 0xD83CDDEA, + 0xD83CDDEE, + 0xD83CDDF7, + 0xD83CDDEC, +}; + +uint32 emojiCategory4[] = { + 0x3120E3, + 0x3220E3, + 0x3320E3, + 0x3420E3, + 0x3520E3, + 0x3620E3, + 0x3720E3, + 0x3820E3, + 0x3920E3, + 0x3020E3, + 0xD83DDD1F, + 0xD83DDD22, + 0x2320E3, + 0xD83DDD23, + 0x2B06, + 0x2B07, + 0x2B05, + 0x27A1, + 0xD83DDD20, + 0xD83DDD21, + 0xD83DDD24, + 0x2197, + 0x2196, + 0x2198, + 0x2199, + 0x2194, + 0x2195, + 0xD83DDD04, + 0x25C0, + 0x25B6, + 0xD83DDD3C, + 0xD83DDD3D, + 0x21A9, + 0x21AA, + 0x2139, + 0x23EA, + 0x23E9, + 0x23EB, + 0x23EC, + 0x2935, + 0x2934, + 0xD83CDD97, + 0xD83DDD00, + 0xD83DDD01, + 0xD83DDD02, + 0xD83CDD95, + 0xD83CDD99, + 0xD83CDD92, + 0xD83CDD93, + 0xD83CDD96, + 0xD83DDCF6, + 0xD83CDFA6, + 0xD83CDE01, + 0xD83CDE2F, + 0xD83CDE33, + 0xD83CDE35, + 0xD83CDE32, + 0xD83CDE34, + 0xD83CDE32, + 0xD83CDE50, + 0xD83CDE39, + 0xD83CDE3A, + 0xD83CDE36, + 0xD83CDE1A, + 0xD83DDEBB, + 0xD83DDEB9, + 0xD83DDEBA, + 0xD83DDEBC, + 0xD83DDEBE, + 0xD83DDEB0, + 0xD83DDEAE, + 0xD83CDD7F, + 0x267F, + 0xD83DDEAD, + 0xD83CDE37, + 0xD83CDE38, + 0xD83CDE02, + 0x24C2, + 0xD83CDE51, + 0x3299, + 0x3297, + 0xD83CDD91, + 0xD83CDD98, + 0xD83CDD94, + 0xD83DDEAB, + 0xD83DDD1E, + 0xD83DDCF5, + 0xD83DDEAF, + 0xD83DDEB1, + 0xD83DDEB3, + 0xD83DDEB7, + 0xD83DDEB8, + 0x26D4, + 0x2733, + 0x2747, + 0x274E, + 0x2705, + 0x2734, + 0xD83DDC9F, + 0xD83CDD9A, + 0xD83DDCF3, + 0xD83DDCF4, + 0xD83CDD70, + 0xD83CDD71, + 0xD83CDD8E, + 0xD83CDD7E, + 0xD83DDCA0, + 0x27BF, + 0x267B, + 0x2648, + 0x2649, + 0x264A, + 0x264B, + 0x264C, + 0x264D, + 0x264E, + 0x264F, + 0x2650, + 0x2651, + 0x2652, + 0x2653, + 0x26CE, + 0xD83DDD2F, + 0xD83CDFE7, + 0xD83DDCB9, + 0xD83DDCB2, + 0xD83DDCB1, + 0xA9, + 0xAE, + 0x2122, + 0x303D, + 0x3030, + 0xD83DDD1D, + 0xD83DDD1A, + 0xD83DDD19, + 0xD83DDD1B, + 0xD83DDD1C, + 0x274C, + 0x2B55, + 0x2757, + 0x2753, + 0x2755, + 0x2754, + 0xD83DDD03, + 0xD83DDD5B, + 0xD83DDD67, + 0xD83DDD50, + 0xD83DDD5C, + 0xD83DDD51, + 0xD83DDD5D, + 0xD83DDD52, + 0xD83DDD5E, + 0xD83DDD53, + 0xD83DDD5F, + 0xD83DDD54, + 0xD83DDD60, + 0xD83DDD55, + 0xD83DDD56, + 0xD83DDD57, + 0xD83DDD58, + 0xD83DDD59, + 0xD83DDD5A, + 0xD83DDD61, + 0xD83DDD62, + 0xD83DDD63, + 0xD83DDD64, + 0xD83DDD65, + 0xD83DDD66, + 0x2716, + 0x2795, + 0x2796, + 0x2797, + 0x2660, + 0x2665, + 0x2663, + 0x2666, + 0xD83DDCAE, + 0xD83DDCAF, + 0x2714, + 0x2611, + 0xD83DDD18, + 0xD83DDD17, + 0x27B0, + 0xD83DDD31, + 0xD83DDD32, + 0xD83DDD33, + 0x25FC, + 0x25FB, + 0x25FE, + 0x25FD, + 0x25AA, + 0x25AB, + 0xD83DDD3A, + 0x2B1C, + 0x2B1B, + 0x26AB, + 0x26AA, + 0xD83DDD34, + 0xD83DDD35, + 0xD83DDD3B, + 0xD83DDD36, + 0xD83DDD37, + 0xD83DDD38, + 0xD83DDD39, +}; + +void writeEmojiCategory(QTextStream &tcpp, uint32 *emojiCategory, uint32 size, const char *name) { + tcpp << "\tcase dbiet" << name << ": {\n"; + tcpp << "\t\tstatic QVector v" << name << ";\n"; + tcpp << "\t\tif (v" << name << ".isEmpty()) {\n"; + tcpp << "\t\t\tv" << name << ".resize(" << size << ");\n"; + for (int i = 0; i < size; ++i) { + int index = 0; + for (EmojisData::const_iterator j = emojisData.cbegin(), e = emojisData.cend(); j != e; ++j) { + if (j->code == emojiCategory[i]) { + break; + } + ++index; + } + if (index == emojisData.size()) { + throw exception(QString("Could not find emoji from category '%1' with index %2, code %3").arg(name).arg(i).arg(emojiCategory[i]).toUtf8().constData()); + } + tcpp << "\t\t\tv" << name << "[" << i << "] = &emojis[" << index << "];\n"; + } + tcpp << "\t\t}\n"; + tcpp << "\t\treturn v" << name << ";\n"; + tcpp << "\t} break;\n\n"; +} + +bool genEmoji(QString emoji_in, const QString &emoji_out) { + QDir d(emoji_in); + if (!d.exists()) { + cout << "Could not open emoji input dir '" << emoji_in.toUtf8().constData() << "'!\n"; + QCoreApplication::exit(1); + return false; + } + emoji_in = d.absolutePath() + '/'; + QString emoji_in_200x = d.absolutePath() + "_200x/"; + QDir d_200x(emoji_in_200x); + if (!d.exists()) { + cout << "Could not open emoji _200x input dir '" << emoji_in_200x.toUtf8().constData() << "'!\n"; + QCoreApplication::exit(1); + return false; + } + + int currentRow = 0, currentColumn = 0; + uint32 min1 = 0xFFFFFFFF, max1 = 0, min2 = 0xFFFFFFFF, max2 = 0; + + QStringList filters; + filters << "*.png" << "*.gif"; + QFileInfoList emojis = d.entryInfoList(filters, QDir::Files | QDir::NoDotAndDotDot | QDir::Readable); + for (QFileInfoList::const_iterator i = emojis.cbegin(), e = emojis.cend(); i != e; ++i) { + QString s = i->fileName(); + QRegularExpressionMatch m = QRegularExpression("^([A-F0-9]+)\\.(png|gif)$").match(s); + if (m.hasMatch()) { + EmojiData data; + QString num = m.captured(1); + if (num.size() != 4 && num.size() != 8 && num.size() != 16) { + cout << "Bad name found '" << s.toUtf8().constData() << "'!\n"; + continue; + } + + data.code = ("0x" + num.mid(0, 8)).toUInt(0, 16); + if (num.size() > 8) { + data.code2 = ("0x" + num.mid(8)).toUInt(0, 16); + } else { + data.code2 = 0; + } + data.name = emoji_in + s; + data.name_200x = emoji_in_200x + s; + data.x = currentColumn; + data.y = currentRow; + ++currentColumn; + + if (currentColumn == inRow) { + ++currentRow; + currentColumn = 0; + } + uint32 high = data.code >> 16; + if (!high) { // small codes + if (data.code == 169 || data.code == 174) { // two small + } else { + if (data.code < min1) min1 = data.code; + if (data.code > max1) max1 = data.code; + } + } else if (high == 35 || high >= 48 && high < 58) { // digits + } else { + if (data.code < min2) min2 = data.code; + if (data.code > max2) max2 = data.code; + } + EmojisData::const_iterator i = emojisData.constFind(data.code); + if (i != emojisData.cend()) { + cout << QString("Bad emoji code (duplicate) %1 %2 and %3 %4").arg(data.code).arg(data.code2).arg(i->code).arg(i->code2).toUtf8().constData() << "\n"; + continue; + } + emojisData.insert(data.code, data); + } else { + cout << QString("Bad emoji file found: %1").arg(s).toUtf8().constData() << "\n"; + } + } + + if (currentColumn) ++currentRow; + if (!currentRow) { + cout << "No emojis written..\n"; + return true; + } + + for (int variantIndex = 0; variantIndex < variantsCount; variantIndex++) { + int variant = variants[variantIndex], imSize = imSizes[variantIndex]; + + QImage emojisImg(inRow * imSize, currentRow * imSize, QImage::Format_ARGB32); + QPainter p(&emojisImg); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(0, 0, emojisImg.width(), emojisImg.height(), Qt::transparent); + for (EmojisData::const_iterator i = emojisData.cbegin(), e = emojisData.cend(); i != e; ++i) { + QString name = variant ? i->name_200x : i->name; + int emojiSize = variant ? imSizes[3] : imSizes[0]; + + QPixmap emoji(name); + if (emoji.width() == emojiSize && emoji.height() == emojiSize) { + if (emojiSize != imSize) { + emoji = QPixmap::fromImage(emoji.toImage().scaled(imSize, imSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + } + p.drawPixmap(i->x * imSize, i->y * imSize, emoji); + } else { + cout << "Could not read image '" << name.toUtf8().constData() << "'!\n"; + } + } + QString postfix = variantPostfix[variantIndex], emojif = "./SourceFiles/art/emoji" + postfix + ".png"; + QByteArray emojib; + { + QBuffer ebuf(&emojib); + if (!emojisImg.save(&ebuf, "PNG")) { + cout << "Could not save 'emoji" << postfix.toUtf8().constData() << ".png'!\n"; + return false; + } + } + bool needResave = !QFileInfo(emojif).exists(); + if (!needResave) { + QFile ef(emojif); + if (!ef.open(QIODevice::ReadOnly)) { + needResave = true; + } else { + QByteArray already(ef.readAll()); + if (already.size() != emojib.size() || memcmp(already.constData(), emojib.constData(), already.size())) { + needResave = true; + } + } + } + if (needResave) { + QFile ef(emojif); + if (!ef.open(QIODevice::WriteOnly)) { + cout << "Could not save 'emoji" << postfix.toUtf8().constData() << ".png'!\n"; + return false; + } else { + if (ef.write(emojib) != emojib.size()) { + cout << "Could not save 'emoji" << postfix.toUtf8().constData() << ".png'!\n"; + return false; + } + } + } + } + + try { + + QByteArray cppText; + { + QTextStream tcpp(&cppText); + tcpp << "\ +/*\n\ +Created from emoji config by \'/MetaEmoji\' project\n\ +\n\ +WARNING! All changes made in this file will be lost!\n\ +\n\ +This file is part of Telegram Desktop, \n\ +an unofficial desktop messaging app, see https://telegram.org\n\ +\n\ +Telegram Desktop is free software: you can redistribute it and/or modify\n\ +it under the terms of the GNU General Public License as published by\n\ +the Free Software Foundation, either version 3 of the License, or\n\ +(at your option) any later version.\n\ +\n\ +It is distributed in the hope that it will be useful,\n\ +but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ +GNU General Public License for more details.\n\ +\n\ +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\ +Copyright (c) 2014 John Preston, https://tdesktop.com\n\ +*/\n"; + tcpp << "#include \"stdafx.h\"\n#include \"gui/emoji_config.h\"\n\n"; + + tcpp << "namespace {\n"; // namespace with data + tcpp << "\tEmojiData *emojis = 0;\n"; + tcpp << "\tchar emojisData[sizeof(EmojiData) * " << emojisData.size() << "];\n"; + tcpp << "}\n\n"; + + tcpp << "void initEmoji() {\n"; + tcpp << "\tEmojiData *toFill = emojis = (EmojiData*)emojisData;\n\n"; + tcpp << "\tswitch (cScale()) {\n\n"; + for (int variantIndex = 0; variantIndex < variantsCount; ++variantIndex) { + int imSize = imSizes[variantIndex]; + tcpp << "\tcase " << variantNames[variantIndex] << ":\n"; + for (EmojisData::const_iterator i = emojisData.cbegin(), e = emojisData.cend(); i != e; ++i) { + int len = i->code2 ? 4 : ((i->code >> 16) ? 2 : 1); + tcpp << "\t\tnew (toFill++) EmojiData(" << (i->x * imSize) << ", " << (i->y * imSize) << ", " << i->code << ", " << i->code2 << ", " << len << ");\n"; + } + tcpp << "\tbreak;\n\n"; + } + tcpp << "\t};\n"; + tcpp << "};\n\n"; + + tcpp << "const EmojiData *getEmoji(uint32 code) {\n"; // getter + tcpp << "\tif (!emojis) return 0;\n\n"; + tcpp << "\tuint32 highCode = code >> 16;\n"; + + uint32 index = 0; + EmojisData::const_iterator i = emojisData.cbegin(), e = emojisData.cend(); + + tcpp << "\tif (!highCode) {\n"; // small codes + tcpp << "\t\tswitch (code) {\n"; + for (; i != e; ++i) { // two small + if (i->code2) break; + if (i->code != 169 && i->code != 174) break; + + tcpp << "\t\t\tcase " << i->code << ": return &emojis[" << (index++) << "];\n"; + } + tcpp << "\t\t}\n\n"; + tcpp << "\t\tif (code < " << min1 << " || code > " << max1 << ") return 0;\n\n"; + tcpp << "\t\tswitch (code) {\n"; + for (; i != e; ++i) { + if (i->code2 || (i->code >> 16)) break; + tcpp << "\t\t\tcase " << i->code << ": return &emojis[" << (index++) << "];\n"; + } + tcpp << "\t\t}\n\n"; + tcpp << "\t\treturn 0;\n"; + tcpp << "\t}\n\n"; + + tcpp << "\tif (highCode == 35 || highCode >= 48 && highCode < 58) {\n"; // digits + tcpp << "\t\tif ((code & 0xFFFF) != 0x20E3) return 0;\n\n"; + tcpp << "\t\tswitch (code) {\n"; + for (; i != e; ++i) { + if (i->code2) break; + uint32 high = i->code >> 16; + if (high != 35 && (high < 48 || high >= 58)) break; + + tcpp << "\t\t\tcase " << i->code << ": return &emojis[" << (index++) << "];\n"; + } + tcpp << "\t\t}\n\n"; + tcpp << "\t\treturn 0;\n"; + tcpp << "\t}\n\n"; + + tcpp << "\tif (code < " << min2 << " || code > " << max2 << ") return 0;\n\n"; + tcpp << "\tswitch (code) {\n"; + for (; i != e; ++i) { + tcpp << "\tcase " << i->code << ": return &emojis[" << (index++) << "];\n"; + } + tcpp << "\t}\n\n"; + + tcpp << "\treturn 0;\n"; + tcpp << "}\n\n"; + + // emoji autoreplace + tcpp << "void findEmoji(const QChar *ch, const QChar *e, const QChar *&newEmojiEnd, uint32 &emojiCode) {\n"; + tcpp << "\tswitch (ch->unicode()) {\n"; + + QString tab("\t"); + for (int i = 0; i < replacesCount; ++i) { + QString key = QString::fromUtf8(replaces[i].replace); + replaceMap[key] = replaces[i].code; + } + QString chars; + for (ReplaceMap::const_iterator i = replaceMap.cend(), e = replaceMap.cbegin(); i != e;) { + --i; + QString key = i.key(); + if (key == chars) { + tcpp << tab.repeated(1 + chars.size()) << "}\n"; + } + bool needSwitch = chars.size(); + while (chars.size() && key.midRef(0, chars.size()) != chars) { + needSwitch = false; + chars.resize(chars.size() - 1); + tcpp << tab.repeated(1 + chars.size()) << "break;\n"; + if (chars.size() && (key.midRef(0, chars.size()) != chars || key == chars)) { + tcpp << tab.repeated(1 + chars.size()) << "}\n"; + } + } + for (int j = chars.size(); j < key.size(); ++j) { + if (needSwitch) { + tcpp << tab.repeated(1 + chars.size()) << "if (ch + " << chars.size() << " != e) switch ((ch + " << chars.size() << ")->unicode()) {\n"; + } + tcpp << tab.repeated(1 + chars.size()) << "case '" << ((key.at(j) == '\\' || key.at(j) == '\'') ? "\\" : "") << key.at(j) << "':\n"; + chars.push_back(key.at(j)); + needSwitch = true; + } + tcpp << tab.repeated(1 + chars.size()) << "newEmojiEnd = ch + " << chars.size() << ";\n"; + tcpp << tab.repeated(1 + chars.size()) << "if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') {\n"; + tcpp << tab.repeated(1 + chars.size()) << "\temojiCode = " << i.value() << ";\n"; + tcpp << tab.repeated(1 + chars.size()) << "\treturn;\n"; + tcpp << tab.repeated(1 + chars.size()) << "}\n"; + } + while (chars.size()) { + chars.resize(chars.size() - 1); + tcpp << tab.repeated(1 + chars.size()) << "break;\n"; + if (chars.size()) { + tcpp << tab.repeated(1 + chars.size()) << "}\n"; + } + } + + tcpp << "\t}\n"; + tcpp << "}\n\n"; + + tcpp << "EmojiPack emojiPack(DBIEmojiTab tab) {\n"; + tcpp << "\tswitch (tab) {\n\n"; + writeEmojiCategory(tcpp, emojiCategory0, sizeof(emojiCategory0) / sizeof(emojiCategory0[0]), "People"); + writeEmojiCategory(tcpp, emojiCategory1, sizeof(emojiCategory1) / sizeof(emojiCategory1[0]), "Nature"); + writeEmojiCategory(tcpp, emojiCategory2, sizeof(emojiCategory2) / sizeof(emojiCategory2[0]), "Objects"); + writeEmojiCategory(tcpp, emojiCategory3, sizeof(emojiCategory3) / sizeof(emojiCategory3[0]), "Places"); + writeEmojiCategory(tcpp, emojiCategory4, sizeof(emojiCategory4) / sizeof(emojiCategory4[0]), "Symbols"); + tcpp << "\t};\n\n"; + tcpp << "\tEmojiPack result;\n"; + tcpp << "\tresult.reserve(cGetRecentEmojis().size());\n"; + tcpp << "\tfor (RecentEmojiPack::const_iterator i = cGetRecentEmojis().cbegin(), e = cGetRecentEmojis().cend(); i != e; ++i) {\n"; + tcpp << "\t\tresult.push_back(i->first);\n"; + tcpp << "\t}\n"; + tcpp << "\treturn result;"; + tcpp << "}\n\n"; + } + QFile cpp(emoji_out); + bool write_cpp = true; + if (cpp.open(QIODevice::ReadOnly)) { + QByteArray wasCpp = cpp.readAll(); + if (wasCpp.size() == cppText.size()) { + if (!memcmp(wasCpp.constData(), cppText.constData(), cppText.size())) { + write_cpp = false; + } + } + cpp.close(); + } + if (write_cpp) { + cout << "Emoji updated, writing " << currentRow << " rows, full count " << emojisData.size() << " emojis.\n"; + if (!cpp.open(QIODevice::WriteOnly)) throw exception("Could not open style_auto.cpp for writing!"); + if (cpp.write(cppText) != cppText.size()) throw exception("Could not open style_auto.cpp for writing!"); + }/**/ + } catch (exception &e) { + cout << e.what() << "\n"; + QCoreApplication::exit(1); + return false; + } + return true; +} diff --git a/Telegram/SourceFiles/_other/genemoji.h b/Telegram/SourceFiles/_other/genemoji.h new file mode 100644 index 000000000..029c62e41 --- /dev/null +++ b/Telegram/SourceFiles/_other/genemoji.h @@ -0,0 +1,63 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::string; +using std::cout; +using std::cerr; +using std::exception; + +bool genEmoji(QString emoji_in, const QString &emoji_out); + +class GenEmoji : public QObject { + Q_OBJECT + +public: + GenEmoji(const QString &emoji_in, const QString &emoji_out) : QObject(0), + _emoji_in(emoji_in), _emoji_out(emoji_out) { + } + + public slots : + void run() { + if (genEmoji(_emoji_in, _emoji_out)) { + emit finished(); + } + } + +signals: + void finished(); + +private: + + QString _emoji_in, _emoji_out; +}; diff --git a/Telegram/SourceFiles/_other/genlang.cpp b/Telegram/SourceFiles/_other/genlang.cpp new file mode 100644 index 000000000..c92b48309 --- /dev/null +++ b/Telegram/SourceFiles/_other/genlang.cpp @@ -0,0 +1,454 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "genlang.h" + +#include +Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin) + +typedef unsigned int uint32; + +QString layoutDirection; +typedef QMap LangKeys; +LangKeys keys; +typedef QVector KeysOrder; +KeysOrder keysOrder; + +bool skipWhitespaces(const char *&from, const char *end) { + while (from < end && (*from == ' ' || *from == '\n' || *from == '\t' || *from == '\r')) { + ++from; + } + return (from < end); +} + +bool skipComment(const char *&from, const char *end) { + if (from >= end) return false; + if (*from == '/') { + if (from + 1 >= end) return true; + if (*(from + 1) == '*') { + from += 2; + while (from + 1 < end && (*from != '*' || *(from + 1) != '/')) { + ++from; + } + from += 2; + return (from < end); + } else if (*(from + 1) == '/') { + from += 2; + while (from < end && *from != '\n' && *from != '\r') { + ++from; + } + ++from; + return (from < end); + } else { + return true; + } + } + return true; +} + +bool skipJunk(const char *&from, const char *end) { + const char *start; + do { + start = from; + if (!skipWhitespaces(from, end)) return false; + if (!skipComment(from, end)) throw exception("Unexpected end of comment!"); + } while (start != from); + return true; +} + +void readKeyValue(const char *&from, const char *end) { + if (!skipJunk(from, end)) return; + + const char *nameStart = from; + while (from < end && (*from >= 'a' && *from <= 'z' || *from >= 'A' && *from <= 'Z' || *from == '_' || *from >= '0' && *from <= '9')) { + ++from; + } + + QString varName = QString::fromUtf8(nameStart, from - nameStart); + + if (!skipJunk(from, end)) throw exception("Unexpected end of file!"); + if (*from != ':') throw exception(QString("':' expected after '%1'").arg(varName).toUtf8().constData()); + + if (!skipJunk(++from, end)) throw exception("Unexpected end of file!"); + if (*from != '"') throw exception(QString("Expected string after '%1:'").arg(varName).toUtf8().constData()); + + QByteArray varValue; + const char *start = ++from; + while (from < end && *from != '"') { + if (*from == '\\') { + if (from + 1 >= end) throw exception("Unexpected end of file!"); + if (*(from + 1) == '"' || *(from + 1) == '\\') { + if (from > start) varValue.append(start, from - start); + start = ++from; + } + } + ++from; + } + if (from >= end) throw exception("Unexpected end of file!"); + if (from > start) varValue.append(start, from - start); + + if (!skipJunk(++from, end)) throw exception("Unexpected end of file!"); + if (*from != ';') throw exception(QString("';' expected after '%1: \"value\"'").arg(varName).toUtf8().constData()); + + skipJunk(++from, end); + + if (varName == "direction") { + if (varValue == "LTR" || varValue == "RTL") { + layoutDirection = QString::fromUtf8(varValue); + } else { + throw exception(QString("Unexpected value for 'direction' key: '%1'").arg(QString::fromUtf8(varValue)).toUtf8().constData()); + } + } else if (varName.midRef(0, 4) != "lng_") { + throw exception(QString("Bad key '%1'").arg(varName).toUtf8().constData()); + } else if (keys.constFind(varName) != keys.cend()) { + throw exception(QString("Key doubled '%1'").arg(varName).toUtf8().constData()); + } else { + keys.insert(varName, QString::fromUtf8(varValue)); + keysOrder.push_back(varName); + } +} + +QString escapeCpp(const QString &key, QString value, bool wideChar) { + if (value.isEmpty()) return "QString()"; + value = value.replace('\\', "\\\\").replace('\n', "\\n").replace('\r', "").replace('"', "\\\""); + QString res; + res.reserve(value.size() * 10); + bool instr = false; + for (const QChar *ch = value.constData(), *e = value.constData() + value.size(); ch != e; ++ch) { + if (ch->unicode() < 32) { + throw exception(QString("Bad value for key '%1'").arg(key).toUtf8().constData()); + } else if (ch->unicode() > 127) { + if (instr) { + res.append('"'); + instr = false; + } + res.append(' '); + if (wideChar) { + res.append('L').append('"').append('\\').append('x').append(QString("%1").arg(ch->unicode(), 4, 16, QChar('0'))).append('"'); + } else { + res.append('"'); + QByteArray utf(QString(*ch).toUtf8()); + for (const unsigned char *uch = (const unsigned char *)utf.constData(), *ue = (const unsigned char *)utf.constData() + utf.size(); uch != ue; ++uch) { + res.append('\\').append('x').append(QString("%1").arg(ushort(*uch), 2, 16, QChar('0'))); + } + res.append('"'); + } + } else { + if (!instr) { + res.append(' '); + if (wideChar) res.append('L'); + res.append('"'); + instr = true; + } + res.append(*ch); + } + } + if (instr) res.append('"'); + return (wideChar ? "qsl(" : "QString::fromUtf8(") + res.mid(wideChar ? 2 : 1) + ")"; +} + +void writeCppKey(QTextStream &tcpp, const QString &key, const QString &val) { + QString wide = escapeCpp(key, val, true), utf = escapeCpp(key, val, false); + if (wide.indexOf(" L\"") < 0) { + tcpp << "\t\t\tset(" << key << ", " << wide << ");\n"; + } else { + tcpp << "#ifdef Q_OS_WIN\n"; + tcpp << "\t\t\tset(" << key << ", " << wide << ");\n"; + tcpp << "#else\n"; + tcpp << "\t\t\tset(" << key << ", " << utf << ");\n"; + tcpp << "#endif\n"; + } +} + +bool genLang(const QString &lang_in, const QString &lang_out) { + QString lang_cpp = lang_out + ".cpp", lang_h = lang_out + ".h"; + QFile f(lang_in); + if (!f.open(QIODevice::ReadOnly)) { + cout << "Could not open styles input file '" << lang_in.toUtf8().constData() << "'!\n"; + QCoreApplication::exit(1); + return false; + } + + QByteArray blob = f.readAll(); + const char *text = blob.constData(), *end = blob.constData() + blob.size(); + f.close(); + + try { + while (text != end) { + readKeyValue(text, end); + } + + QByteArray cppText, hText; + { + QTextStream tcpp(&cppText), th(&hText); + tcpp.setCodec("ISO 8859-1"); + th.setCodec("ISO 8859-1"); + th << "\ +/*\n\ +Created from \'/Resources/lang.txt\' by \'/MetaLang\' project\n\ +\n\ +WARNING! All changes made in this file will be lost!\n\ +\n\ +This file is part of Telegram Desktop,\n\ +an unofficial desktop messaging app, see https://telegram.org\n\ +\n\ +Telegram Desktop is free software: you can redistribute it and/or modify\n\ +it under the terms of the GNU General Public License as published by\n\ +the Free Software Foundation, either version 3 of the License, or\n\ +(at your option) any later version.\n\ +\n\ +It is distributed in the hope that it will be useful,\n\ +but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ +GNU General Public License for more details.\n\ +\n\ +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\ +Copyright (c) 2014 John Preston, https://tdesktop.com\n\ +*/\n"; + th << "#pragma once\n\n"; + th << "enum LangKey {\n"; + for (int i = 0, l = keysOrder.size(); i < l; ++i) { + th << "\t" << keysOrder[i] << (i ? "" : " = 0") << ",\n"; + } + th << "\n\tlng_keys_cnt\n"; + th << "};\n\n"; + th << "QString lang(LangKey key);\n"; + th << "inline QString langDayOfMonth(const QDate &date) {\n"; + th << "\tint32 month = date.month(), day = date.day();\n"; + th << "\treturn (month > 0 && month <= 12) ? lang(lng_month_day).replace(qsl(\"{month}\"), lang(LangKey(lng_month1 + month - 1))).replace(qsl(\"{day}\"), QString::number(day)) : qsl(\"{err}\");\n"; + th << "}\n\n"; + th << "inline QString langDayOfWeek(const QDate &date) {\n"; + th << "\tint32 day = date.dayOfWeek();\n"; + th << "\treturn (day > 0 && day <= 7) ? lang(LangKey(lng_weekday1 + day - 1)) : qsl(\"{err}\");\n"; + th << "}\n\n"; + th << "Qt::LayoutDirection langDir();\n\n"; + th << "class LangLoader {\n"; + th << "public:\n"; + th << "\tconst QString &errors() const;\n"; + th << "\tconst QString &warnings() const;\n\n"; + th << "protected:\n"; + th << "\tLangLoader() : _checked(false) {\n"; + th << "\t\tmemset(_found, 0, sizeof(_found));\n"; + th << "\t}\n\n"; + th << "\tbool feedKeyValue(const QString &key, const QString &value);\n\n"; + th << "\tvoid error(const QString &text) {\n"; + th << "\t\t_err.push_back(text);\n"; + th << "\t}\n"; + th << "\tvoid warning(const QString &text) {\n"; + th << "\t\t_warn.push_back(text);\n"; + th << "\t}\n\n"; + th << "private:\n"; + th << "\tmutable QStringList _err, _warn;\n"; + th << "\tmutable QString _errors, _warnings;\n"; + th << "\tmutable bool _checked;\n"; + th << "\tbool _found[lng_keys_cnt];\n\n"; + th << "\tLangLoader(const LangLoader &);\n"; + th << "\tLangLoader &operator=(const LangLoader &);\n"; + th << "};\n"; + + tcpp << "\ +/*\n\ +Created from \'/Resources/lang.txt\' by \'/MetaLang\' project\n\ +\n\ +WARNING! All changes made in this file will be lost!\n\ +\n\ +This file is part of Telegram Desktop,\n\ +an unofficial desktop messaging app, see https://telegram.org\n\ +\n\ +Telegram Desktop is free software: you can redistribute it and/or modify\n\ +it under the terms of the GNU General Public License as published by\n\ +the Free Software Foundation, either version 3 of the License, or\n\ +(at your option) any later version.\n\ +\n\ +It is distributed in the hope that it will be useful,\n\ +but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ +GNU General Public License for more details.\n\ +\n\ +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\ +Copyright (c) 2014 John Preston, https://tdesktop.com\n\ +*/\n"; + tcpp << "#include \"stdafx.h\"\n#include \"lang.h\"\n\n"; + tcpp << "namespace {\n"; + tcpp << "\tQt::LayoutDirection _langDir = Qt::" << (layoutDirection == "LTR" ? "LeftToRight" : "RightToLeft") << ";\n"; + tcpp << "\tconst char *_langKeyNames[lng_keys_cnt + 1] = {\n"; + for (int i = 0, l = keysOrder.size(); i < l; ++i) { + tcpp << "\t\t\"" << keysOrder[i] << "\",\n"; + } + tcpp << "\t\t\"lng_keys_cnt\"\n"; + tcpp << "\t};\n\n"; + tcpp << "\tQString _langValues[lng_keys_cnt + 1];\n\n"; + tcpp << "\tvoid set(LangKey key, const QString &val) {\n"; + tcpp << "\t\t_langValues[key] = val;\n"; + tcpp << "\t}\n\n"; + tcpp << "\tclass LangInit {\n"; + tcpp << "\tpublic:\n"; + tcpp << "\t\tLangInit() {\n"; + for (int i = 0, l = keysOrder.size(); i < l; ++i) { + writeCppKey(tcpp, keysOrder[i], keys[keysOrder[i]]); + } + tcpp << "\t\t\tset(lng_keys_cnt, QString());\n"; + tcpp << "\t\t}\n"; + tcpp << "\t};\n\n"; + tcpp << "\tLangInit _langInit;\n"; + tcpp << "}\n\n"; + + tcpp << "QString lang(LangKey key) {\n"; + tcpp << "\treturn _langValues[(key < 0 || key > lng_keys_cnt) ? lng_keys_cnt : key];\n"; + tcpp << "}\n\n"; + + tcpp << "Qt::LayoutDirection langDir() {\n"; + tcpp << "\treturn _langDir;\n"; + tcpp << "}\n\n"; + + tcpp << "bool LangLoader::feedKeyValue(const QString &key, const QString &value) {\n"; + tcpp << "\tif (key == qsl(\"direction\")) {\n"; + tcpp << "\t\tif (value == qsl(\"LTR\")) {\n"; + tcpp << "\t\t\t_langDir = Qt::LeftToRight;\n"; + tcpp << "\t\t\treturn true;\n"; + tcpp << "\t\t} else if (value == qsl(\"RTL\")) {\n"; + tcpp << "\t\t\t_langDir = Qt::RightToLeft;\n"; + tcpp << "\t\t\treturn true;\n"; + tcpp << "\t\t} else {\n"; + tcpp << "\t\t\t_err.push_back(qsl(\"Bad value for 'direction' key.\"));\n"; + tcpp << "\t\t\treturn false;\n"; + tcpp << "\t\t}\n"; + tcpp << "\t}\n"; + tcpp << "\tif (key.size() < 5 || key.midRef(0, 4) != qsl(\"lng_\")) {\n"; + tcpp << "\t\t_err.push_back(qsl(\"Bad key name '%1'\").arg(key));\n"; + tcpp << "\t\treturn false;\n"; + tcpp << "\t}\n\n"; + if (!keys.isEmpty()) { + QString tab("\t"); + tcpp << "\tLangKey keyIndex = lng_keys_cnt;\n"; + tcpp << "\tconst QChar *ch = key.constData(), *e = key.constData() + key.size();\n"; + QString current("lng_"); + int depth = current.size(); + tcpp << "\tswitch ((ch + " << depth << ")->unicode()) {\n"; + for (LangKeys::const_iterator i = keys.cbegin(), j = i + 1, e = keys.cend(); i != e; ++i) { + QString key = i.key(); + while (key.midRef(0, depth) != current) { + tcpp << tab.repeated(depth - 3) << "}\n"; + current.chop(1); + --depth; + tcpp << tab.repeated(depth - 3) << "break;\n"; + } + do { + if (key == current) break; + + QChar ich = i.key().at(current.size()); + tcpp << tab.repeated(current.size() - 3) << "case '" << ich << "':\n"; + if (j == e || ich != ((j.key().size() > depth) ? j.key().at(depth) : 0)) { + if (key == current + ich) { + tcpp << tab.repeated(depth - 3) << "\tif (ch + " << (depth + 1) << " == e) keyIndex = " << key << ";\n"; + } else { + tcpp << tab.repeated(depth - 3) << "\tif (key.midRef(" << (depth + 1) << ") == qsl(\"" << i.key().mid(depth + 1) << "\")) keyIndex = " << key << ";\n"; + } + tcpp << tab.repeated(depth - 3) << "break;\n"; + break; + } + + ++depth; + current += ich; + + if (key == current) { + tcpp << tab.repeated(depth - 3) << "if (ch + " << depth << " == e) {\n"; + tcpp << tab.repeated(depth - 3) << "\tkeyIndex = " << key << ";\n"; + tcpp << tab.repeated(depth - 3) << "}\n"; + } + + tcpp << tab.repeated(depth - 3) << "if (ch + " << depth << " < e) switch ((ch + " << depth << ")->unicode()) {\n"; + } while (true); + ++j; + } + while (QString("lng_") != current) { + tcpp << tab.repeated(depth - 3) << "}\n"; + current.chop(1); + --depth; + tcpp << tab.repeated(depth - 3) << "break;\n"; + } + tcpp << "\t}\n\n"; + tcpp << "\tif (keyIndex < lng_keys_cnt) {\n"; + tcpp << "\t\t_found[keyIndex] = 1;\n"; + tcpp << "\t\t_langValues[keyIndex] = value;\n"; + tcpp << "\t\treturn true;\n"; + tcpp << "\t}\n\n"; + } + tcpp << "\t_err.push_back(qsl(\"Unknown key name '%1'\").arg(key));\n"; + tcpp << "\treturn false;\n"; + tcpp << "}\n\n"; + + tcpp << "const QString &LangLoader::errors() const {\n"; + tcpp << "\tif (_errors.isEmpty() && !_err.isEmpty()) {\n"; + tcpp << "\t\t_errors = _err.join('\\n');\n"; + tcpp << "\t}\n"; + tcpp << "\treturn _errors;\n"; + tcpp << "}\n\n"; + + tcpp << "const QString &LangLoader::warnings() const {\n"; + tcpp << "\tif (!_checked) {\n"; + tcpp << "\t\tfor (int32 i = 0; i < lng_keys_cnt; ++i) {\n"; + tcpp << "\t\t\tif (!_found[i]) {\n"; + tcpp << "\t\t\t\t_warn.push_back(qsl(\"No value found for key '%1'\").arg(_langKeyNames[i]));\n"; + tcpp << "\t\t\t}\n"; + tcpp << "\t\t}\n"; + tcpp << "\t\t_checked = true;\n"; + tcpp << "\t}\n"; + tcpp << "\tif (_warnings.isEmpty() && !_warn.isEmpty()) {\n"; + tcpp << "\t\t_warnings = _warn.join('\\n');\n"; + tcpp << "\t}\n"; + tcpp << "\treturn _warnings;\n"; + tcpp << "}\n"; + } + + QFile cpp(lang_cpp), h(lang_h); + bool write_cpp = true, write_h = true; + if (cpp.open(QIODevice::ReadOnly)) { + QByteArray wasCpp = cpp.readAll(); + if (wasCpp.size() == cppText.size()) { + if (!memcmp(wasCpp.constData(), cppText.constData(), cppText.size())) { + write_cpp = false; + } + } + cpp.close(); + } + if (write_cpp) { + cout << "lang.cpp updated, writing " << keysOrder.size() << " rows.\n"; + if (!cpp.open(QIODevice::WriteOnly)) throw exception("Could not open lang.cpp for writing!"); + if (cpp.write(cppText) != cppText.size()) throw exception("Could not open lang.cpp for writing!"); + } + if (h.open(QIODevice::ReadOnly)) { + QByteArray wasH = h.readAll(); + if (wasH.size() == hText.size()) { + if (!memcmp(wasH.constData(), hText.constData(), hText.size())) { + write_h = false; + } + } + h.close(); + } + if (write_h) { + cout << "lang.h updated, writing " << keysOrder.size() << " rows.\n"; + if (!h.open(QIODevice::WriteOnly)) throw exception("Could not open lang.h for writing!"); + if (h.write(hText) != hText.size()) throw exception("Could not open lang.h for writing!"); + } + } catch (exception &e) { + cout << e.what() << "\n"; + QCoreApplication::exit(1); + return false; + } + return true; +} diff --git a/Telegram/SourceFiles/_other/genlang.h b/Telegram/SourceFiles/_other/genlang.h new file mode 100644 index 000000000..31f8b4609 --- /dev/null +++ b/Telegram/SourceFiles/_other/genlang.h @@ -0,0 +1,61 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::string; +using std::cout; +using std::cerr; +using std::exception; + +bool genLang(const QString &lang_in, const QString &lang_out); + +class GenLang : public QObject { + Q_OBJECT + +public: + GenLang(const QString &lang_in, const QString &lang_out) : QObject(0), + _lang_in(lang_in), _lang_out(lang_out) { + } + + public slots : + void run() { + if (genLang(_lang_in, _lang_out)) { + emit finished(); + } + } + +signals: + void finished(); + +private: + + QString _lang_in, _lang_out; +}; diff --git a/Telegram/SourceFiles/_other/genstyles.cpp b/Telegram/SourceFiles/_other/genstyles.cpp new file mode 100644 index 000000000..23b2cf3f6 --- /dev/null +++ b/Telegram/SourceFiles/_other/genstyles.cpp @@ -0,0 +1,1817 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "genstyles.h" + +#include +Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin) + +enum ScalarType { + scNumber, + scString, + scColor, + scPoint, + scRect, + scSprite, + scSize, + scTransition, + scCursor, + scAlign, + scMargins, + scFont, + + scTypesCount, +}; + +string scalarTypeNames[] = { + "number", + "string", + "color", + "point", + "rect", + "sprite", + "size", + "transition", + "cursor", + "align", + "margins", + "font", +}; + +string outputTypeNames[] = { + "number", + "string", + "color", + "point", + "rect", + "rect", + "size", + "transition", + "cursor", + "align", + "margins", + "font", +}; + +enum ClassGenTokenType { + csName, // [a-zA-Z_][a-zA-Z0-9_]* + csDelimeter, // ':' + csFieldFinish, // ';' + csClassStart, // '{' + csClassFinish, // '}' +}; + +bool skipWhitespaces(const char *&from, const char *end) { + while (from < end && (*from == ' ' || *from == '\n' || *from == '\t' || *from == '\r')) { + ++from; + } + return (from < end); +} + +bool skipComment(const char *&from, const char *end) { + if (from >= end) return false; + if (*from == '/') { + if (from + 1 >= end) return true; + if (*(from + 1) == '*') { + from += 2; + while (from + 1 < end && (*from != '*' || *(from + 1) != '/')) { + ++from; + } + from += 2; + return (from < end); + } else if (*(from + 1) == '/') { + from += 2; + while (from < end && *from != '\n' && *from != '\r') { + ++from; + } + ++from; + return (from < end); + } else { + return true; + } + } + return true; +} + +void readName(const char *&from, const char *end, string &token) { + if (from >= end) throw exception("Unexpected end of file!"); + + const char *start = from; + char ch = *from; + if (!((ch >= 'a' && ch <= 'z') || ((ch >= 'A') && (ch <= 'Z')))) { + throw exception("Unknown error :("); + } + while (++from < end) { + ch = *from; + if (!((ch >= 'a' && ch <= 'z') || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) || ch == '_')) break; + } + token = string(start, from); +} + +void readString(const char *&from, const char *end, string &token) { + if (from + 1 >= end) throw exception("Unexpected end of file!"); + + token = ""; + char border = *from; + if (border != '"' && border != '\'') { + throw exception("Unknown error :("); + } + + bool spec = false; + for (++from; spec || (*from != border); ) { + if (*from == '\\') { + spec = true; + } else if (spec) { + if (*from == 'n') { + token += '\n'; + } else if (*from == 't') { + token += '\t'; + } else if (*from == '\\' || *from == '"' || *from == '\'') { + token += *from; + } else { + throw exception(QString("Unexpected escaped character in string: %1").arg(*from).toUtf8().constData()); + } + spec = false; + } else { + token += *from; + } + if (++from >= end) throw exception("Unexpected end of file!"); + } + ++from; +} + +char hexChar(char ch) { + if (ch >= 'a' && ch <= 'f') { + return ch + ('A' - 'a'); + } + return ch; +} + +void readColor(const char *&from, const char *end, string &token) { + if (from + 3 >= end) throw exception("Unexpected end of file!"); + + token.resize(8); + + int len = 0; + for (const char *ch = from + 1; ch < end; ++ch) { + if (*ch >= '0' && *ch <= '9' || *ch >= 'A' && *ch <= 'F' || *ch >= 'a' && *ch <= 'f') { + ++len; + } else { + break; + } + } + if (len != 3 && len != 4 && len != 6 && len != 8) { + throw exception("Bad color token"); + } + if (len == 3 || len == 4) { + token[0] = token[1] = hexChar(*(++from)); + token[2] = token[3] = hexChar(*(++from)); + token[4] = token[5] = hexChar(*(++from)); + if (len == 3) { + token[6] = token[7] = 'F'; + } else { + token[6] = token[7] = hexChar(*(++from)); + } + } else { + token[0] = hexChar(*(++from)); + token[1] = hexChar(*(++from)); + token[2] = hexChar(*(++from)); + token[3] = hexChar(*(++from)); + token[4] = hexChar(*(++from)); + token[5] = hexChar(*(++from)); + if (len == 6) { + token[6] = token[7] = 'F'; + } else { + token[6] = hexChar(*(++from)); + token[7] = hexChar(*(++from)); + } + } + ++from; +} + +void readNumber(const char *&from, const char *end, string &token) { + if (from >= end) throw exception("Unexpected end of file!"); + + bool neg = false; + if (*from == '-') { + neg = true; + if (++from >= end) throw exception("Unexpected end of file!"); + } + + if (*from == '0' && from < end && *(from + 1) >= '0' && *(from + 1) <= '9') throw exception("Bad number token!"); + + bool wasDot = false; + token = neg ? "-" : ""; + for (bool wasDot = false; from < end; ++from) { + if (*from == '.') { + if (wasDot) throw exception("Unexpected dot in number!"); + wasDot = true; + } else if (*from < '0' || *from > '9') { + break; + } + token += *from; + } +} + +void readClassGenToken(const char *&from, const char *end, ClassGenTokenType &tokenType, string &token) { + const char *start; + do { + start = from; + if (!skipWhitespaces(from, end)) throw exception("Unexpected end of file!"); + if (!skipComment(from, end)) throw exception("Unexpected end of comment!"); + } while (start != from); + + if ((*from >= 'a' && *from <= 'z') || ((*from >= 'A') && (*from <= 'Z'))) { + tokenType = csName; + return readName(from, end, token); + } else if (*from == ':') { + tokenType = csDelimeter; + } else if (*from == ';') { + tokenType = csFieldFinish; + } else if (*from == '{') { + tokenType = csClassStart; + } else if (*from == '}') { + tokenType = csClassFinish; + } else { + throw exception("Could not parse token!"); + } + ++from; + return; +} + +typedef QMap FieldTypesMap; +struct ClassData { + string name; + FieldTypesMap fields; +}; + +typedef QMap Classes; +Classes classes; + +typedef QMap ByName; + +bool genClasses(const QString &classes_in, const QString &classes_out) { + QFile f(classes_in); + if (!f.open(QIODevice::ReadOnly)) { + cout << "Could not open style classes input file '" << classes_in.toUtf8().constData() << "'!\n"; + QCoreApplication::exit(1); + return false; + } + + QByteArray blob = f.readAll(); + const char *text = blob.constData(), *end = blob.constData() + blob.size(); + ByName byName; + QVector byIndex; + string token; + ClassGenTokenType type; + try { + while (true) { + try { + readClassGenToken(text, end, type, token); + } catch (exception &e) { + if (e.what() != string("Unexpected end of file!")) { + throw; + } + break; + } + if (type != csName) { + throw exception(QString("Unexpected token, type %1: %2").arg(type).arg(token.c_str()).toUtf8().constData()); + } + + byIndex.push_back(ClassData()); + ClassData &cls(byIndex.back()); + cls.name = token; + readClassGenToken(text, end, type, token); + if (type == csDelimeter) { + readClassGenToken(text, end, type, token); + if (type != csName) throw exception(QString("Unexpected token after '%1:', type %2").arg(cls.name.c_str()).arg(type).toUtf8().constData()); + + QMap::const_iterator i = byName.constFind(token); + if (i == byName.cend()) throw exception(QString("Parent class '%1' not found for class '%2'").arg(token.c_str()).arg(cls.name.c_str()).toUtf8().constData()); + cls.fields = byIndex[i.value()].fields; + readClassGenToken(text, end, type, token); + } + if (type != csClassStart) throw exception(QString("Unexpected token after '%1:%2', type %3").arg(cls.name.c_str()).arg(token.c_str()).arg(type).toUtf8().constData()); + + do { + string fname, ftype; + readClassGenToken(text, end, type, fname); + if (type == csClassFinish) { + byName.insert(cls.name, byIndex.size() - 1); + break; + } + if (type != csName) throw exception(QString("Unexpected token %1 while reading class '%2'").arg(type).arg(cls.name.c_str()).toUtf8().constData()); + readClassGenToken(text, end, type, token); + if (type != csDelimeter) throw exception(QString("Unexpected token %1 while reading field '%2' in class '%3'").arg(type).arg(fname.c_str()).arg(cls.name.c_str()).toUtf8().constData()); + readClassGenToken(text, end, type, ftype); + if (type != csName) throw exception(QString("Unexpected token %1 while reading field '%2' in class '%3'").arg(type).arg(fname.c_str()).arg(cls.name.c_str()).toUtf8().constData()); + readClassGenToken(text, end, type, token); + if (type != csFieldFinish) throw exception(QString("Unexpected token %1 while reading field '%2:%3' in class '%4'").arg(type).arg(fname.c_str()).arg(ftype.c_str()).arg(cls.name.c_str()).toUtf8().constData()); + + ScalarType typeIndex = scTypesCount; + for (int t = 0; t < scTypesCount; ++t) { + if (ftype == scalarTypeNames[t]) { + typeIndex = ScalarType(t); + break; + } + } + if (typeIndex == scTypesCount) throw exception(QString("Unknown field type %1 while reading field '%2' in class '%3'").arg(ftype.c_str()).arg(fname.c_str()).arg(cls.name.c_str()).toUtf8().constData()); + FieldTypesMap::const_iterator alr = cls.fields.find(fname); + if (alr != cls.fields.cend()) throw exception(QString("Redeclaration of field '%1' in class '%2'").arg(fname.c_str()).arg(cls.name.c_str()).toUtf8().constData()); + cls.fields.insert(fname, typeIndex); + } while(true); + } + + QByteArray outText; + { + QTextStream tout(&outText); + tout << "\ +/*\n\ +Created from \'/Resources/style_classes.txt\' by \'/MetaStyle\' project\n\ +\n\ +WARNING! All changes made in this file will be lost!\n\ +\n\ +This file is part of Telegram Desktop,\n\ +an unofficial desktop messaging app, see https://telegram.org\n\ +\n\ +Telegram Desktop is free software: you can redistribute it and/or modify\n\ +it under the terms of the GNU General Public License as published by\n\ +the Free Software Foundation, either version 3 of the License, or\n\ +(at your option) any later version.\n\ +\n\ +It is distributed in the hope that it will be useful,\n\ +but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ +GNU General Public License for more details.\n\ +\n\ +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\ +Copyright (c) 2014 John Preston, https://tdesktop.com\n\ +*/\n"; + tout << "#pragma once\n\n#include \"style.h\"\n\nnamespace style {\n"; + for (int i = 0, l = byIndex.size(); i < l; ++i) { + ClassData &cls(byIndex[i]); + classes.insert(cls.name, cls); + tout << "\n\tclass " << cls.name.c_str() << " {\n\tpublic:\n\t\t" << cls.name.c_str() << "("; + for (FieldTypesMap::const_iterator j = cls.fields.cbegin(), e = cls.fields.cend(); j != e;) { + tout << "const style::" << outputTypeNames[j.value()].c_str() << " &_" << j.key().c_str(); + if (++j != e) { + tout << ", "; + } + } + tout << ", Qt::Initialization = Qt::Uninitialized)"; + if (!cls.fields.isEmpty()) { + tout << " : "; + } + for (FieldTypesMap::const_iterator j = cls.fields.cbegin(), e = cls.fields.cend(); j != e;) { + tout << j.key().c_str() << "(_" << j.key().c_str() << ")"; + if (++j != e) { + tout << ", "; + } + } + tout << " {\n\t\t}\n\n"; + for (FieldTypesMap::const_iterator j = cls.fields.cbegin(), e = cls.fields.cend(); j != e;) { + tout << "\t\tstyle::" << outputTypeNames[j.value()].c_str() << " " << j.key().c_str() << ";\n"; + ++j; + } + tout << "\t};\n"; + } + tout << "\n};\n"; + } + QFile out(classes_out); + if (out.open(QIODevice::ReadOnly)) { + QByteArray wasOut = out.readAll(); + if (wasOut.size() == outText.size()) { + if (!memcmp(wasOut.constData(), outText.constData(), outText.size())) { + return true; + } + } + out.close(); + } + cout << "Style classes compiled, writing " << byIndex.size() << " classes.\n"; + if (!out.open(QIODevice::WriteOnly)) throw exception("Could not open style_classes.h for writing!"); + if (out.write(outText) != outText.size()) throw exception("Could not open style_classes.h for writing!"); + } catch (exception &e) { + cout << e.what() << "\n"; + QCoreApplication::exit(1); + return false; + } + return true; +} + +enum StyleGenTokenType { + stName, // [a-zA-Z_][a-zA-Z0-9_]* + stDelimeter, // ':' + stFieldFinish, // ';' + stObjectStart, // '{' + stObjectFinish, // '}' + stConsStart, // '(' + stConsFinish, // ')' + stComma, // ',' + stVariant, // '/' + stString, // "text" or 'text' + stColor, // #rgb or #rrggbb + stNumber, // -?([1-9][0-9]+(\.[0-9]+)?|\.[0-9]+) +}; + +static const int variants[] = { 0, 2, 3, 4 }, variantsCount = sizeof(variants) / sizeof(variants[0]); +static const char *variantNames[] = { "dbisOne", "dbisOneAndQuarter", "dbisOneAndHalf", "dbisTwo" }; + +static const char *variantPostfixes[] = { "", "_125x", "_150x", "_200x" }; +QPixmap *spriteMax = 0; +QImage *variantSprites = 0; +QImage *variantGrids = 0; + +void readStyleGenToken(const char *&from, const char *end, StyleGenTokenType &tokenType, string &token) { + const char *start; + do { + start = from; + if (!skipWhitespaces(from, end)) throw exception("Unexpected end of file!"); + if (!skipComment(from, end)) throw exception("Unexpected end of comment!"); + } while (start != from); + + if ((*from >= 'a' && *from <= 'z') || ((*from >= 'A') && (*from <= 'Z'))) { + tokenType = stName; + return readName(from, end, token); + } else if (*from == '"' || *from == '\'') { + tokenType = stString; + return readString(from, end, token); + } else if (*from == '#') { + tokenType = stColor; + return readColor(from, end, token); + } else if (*from == '.' || *from >= '0' && *from <= '9' || *from == '-') { + tokenType = stNumber; + return readNumber(from, end, token); + } else if (*from == ':') { + tokenType = stDelimeter; + } else if (*from == ';') { + tokenType = stFieldFinish; + } else if (*from == '{') { + tokenType = stObjectStart; + } else if (*from == '}') { + tokenType = stObjectFinish; + } else if (*from == '(') { + tokenType = stConsStart; + } else if (*from == ')') { + tokenType = stConsFinish; + } else if (*from == ',') { + tokenType = stComma; + } else if (*from == '/') { + tokenType = stVariant; + } else { + throw exception("Could not parse token!"); + } + ++from; + return; +} + +bool readPxAfterNumber(const char *&from, const char *end) { + if (from + 2 <= end && *from == 'p' && *(from + 1) == 'x') { + from += 2; + return true; + } + return false; +} + +typedef QMap ScalarValue; +typedef QPair ScalarData; +typedef QPair Scalar; +typedef QMap Fields; +typedef QPair ObjectData; +typedef QPair Object; +typedef QVector Objects; +typedef QVector Scalars; + +string findScalarVariant(const ScalarValue &value, int variant) { + ScalarValue::const_iterator i = value.constFind(variant); + if (i != value.cend()) return i.value(); + + return value[0]; + //string result; + //for (ScalarValue::const_iterator i = value.cbegin(), e = value.cend(); i != e; ++i) { + // if (i.key() > variant) { + // break; + // } + // result = i.value(); + //} + //return result; +} + +Objects objects; +Scalars scalars; + +ByName objectsMap; +ByName scalarsMap; + +ScalarValue fillPrepareResult(int variant, const string &result) { + ScalarValue r; + r[variant] = result; + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + r[variants[i]] = result; + } + } + return r; +} + +int adjustPx(int variant, int number, bool ispx) { + if (!ispx || !variant) return number; + + switch (variant) { + case 2: return qRound(number * 1.25 + (number > 0 ? -0.01 : 0.01)); + case 3: return qRound(number * 1.5 + (number > 0 ? -0.01 : 0.01)); + case 4: return number * 2; + } + return number; +} + +string adjustPx(int variant, const string &number, bool ispx) { + if (!variant || !ispx) return number; + return QString::number(adjustPx(variant, QString(number.c_str()).toInt(), ispx)).toUtf8().constData(); +} + +ScalarValue prepareString(int variant, const string &token) { + string result; + result.reserve(token.length() * 2); + result += "(qsl(\""; + for (int i = 0, l = token.length(); i < l; ++i) { + if (token[i] == '\n') { + result += "\\n"; + } else if (token[i] == '\r') { + result += "\\r"; + } else if (token[i] == '\t') { + result += "\\t"; + } else { + if (token[i] == '\\' || token[i] == '"') { + result += '\\'; + } + result += token[i]; + } + } + result += "\"))"; + return fillPrepareResult(variant, result); + +} + +int hexDec(char a, char b) { + int da = (a >= '0' && a <= '9') ? (a - '0') : (10 + a - 'A'); + int db = (b >= '0' && b <= '9') ? (b - '0') : (10 + b - 'A'); + return da * 16 + db; +} + +typedef QMap > Named; +QMap named; + +struct Color { + string color; +}; + +typedef QMap Colors; +QMap colors; + +ScalarValue prepareColor(int variant, const string &name, const string &token) { + QString result; + result.reserve(20); + + int r = hexDec(token[0], token[1]), g = hexDec(token[2], token[3]), b = hexDec(token[4], token[5]), a = hexDec(token[6], token[7]); + if (a == 255) { + Color c; + c.color = QString("%1, %2, %3, 255").arg(r).arg(g).arg(b).toUtf8().constData(); + colors[variant][name] = c; + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + colors[variants[i]][name] = c; + } + } + return fillPrepareResult(variant, "(Qt::Uninitialized)"); + } + Color c; + c.color = QString("%1, %2, %3, %4").arg(r).arg(g).arg(b).arg(a).toUtf8().constData(); + colors[variant][name] = c; + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + colors[variants[i]][name] = c; + } + } + return fillPrepareResult(variant, "(Qt::Uninitialized)"); +} + +ScalarValue prepareNumber(int variant, const string &token, const char *&text, const char *end) { + bool ispx = readPxAfterNumber(text, end); + ScalarValue r; + r[variant] = '(' + token + ')'; + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + r[variants[i]] = '(' + adjustPx(variants[i], token, ispx) + ')'; + } + } + return r; +} + +ScalarValue prepareColorRGB(int variant, const string &name, const char *&text, const char *end) { + StyleGenTokenType type; + string token; + + readStyleGenToken(text, end, type, token); + if (type != stConsStart) throw exception(QString("Unexpected token %1 while reading rgb() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading rgb() cons!").arg(type).toUtf8().constData()); + string r = token; + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading rgb() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading rgb() cons!").arg(type).toUtf8().constData()); + string g = token; + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading rgb() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading rgb() cons!").arg(type).toUtf8().constData()); + string b = token; + + readStyleGenToken(text, end, type, token); + if (type != stConsFinish) throw exception(QString("Unexpected token %1 while reading rgb() cons!").arg(type).toUtf8().constData()); + + Color c; + c.color = QString("%1, %2, %3, 255").arg(r.c_str()).arg(g.c_str()).arg(b.c_str()).toUtf8().constData(); + colors[variant][name] = c; + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + colors[variants[i]][name] = c; + } + } + return fillPrepareResult(variant, "(Qt::Uninitialized)"); +} + +ScalarValue prepareColorRGBA(int variant, const string &name, const char *&text, const char *end) { + StyleGenTokenType type; + string token; + + readStyleGenToken(text, end, type, token); + if (type != stConsStart) throw exception(QString("Unexpected token %1 while reading rgba() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading rgba() cons!").arg(type).toUtf8().constData()); + string r = token; + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading rgba() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading rgba() cons!").arg(type).toUtf8().constData()); + string g = token; + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading rgba() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading rgba() cons!").arg(type).toUtf8().constData()); + string b = token; + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading rgba() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading rgba() cons!").arg(type).toUtf8().constData()); + string a = token; + + readStyleGenToken(text, end, type, token); + if (type != stConsFinish) throw exception(QString("Unexpected token %1 while reading rgba() cons!").arg(type).toUtf8().constData()); + + Color c; + c.color = QString("%1, %2, %3, %4").arg(r.c_str()).arg(g.c_str()).arg(b.c_str()).arg(a.c_str()).toUtf8().constData(); + colors[variant][name] = c; + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + colors[variants[i]][name] = c; + } + } + return fillPrepareResult(variant, "(Qt::Uninitialized)"); +} + +ScalarValue prepareRect(int variant, const char *&text, const char *end) { + StyleGenTokenType type; + string token; + + readStyleGenToken(text, end, type, token); + if (type != stConsStart) throw exception(QString("Unexpected token %1 while reading rect() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading rect() cons!").arg(type).toUtf8().constData()); + string x = token; + bool xpx = readPxAfterNumber(text, end); + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading rect() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading rect() cons!").arg(type).toUtf8().constData()); + string y = token; + bool ypx = readPxAfterNumber(text, end); + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading rect() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading rect() cons!").arg(type).toUtf8().constData()); + string w = token; + bool wpx = readPxAfterNumber(text, end); + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading rect() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading rect() cons!").arg(type).toUtf8().constData()); + string h = token; + bool hpx = readPxAfterNumber(text, end); + + readStyleGenToken(text, end, type, token); + if (type != stConsFinish) throw exception(QString("Unexpected token %1 while reading rect() cons!").arg(type).toUtf8().constData()); + + ScalarValue r; + r[variant] = QString("(%1, %2, %3, %4)").arg(x.c_str()).arg(y.c_str()).arg(w.c_str()).arg(h.c_str()).toUtf8().constData(); + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + r[variants[i]] = QString("(%1, %2, %3, %4)").arg(adjustPx(variants[i], x, xpx).c_str()).arg(adjustPx(variants[i], y, ypx).c_str()).arg(adjustPx(variants[i], w, wpx).c_str()).arg(adjustPx(variants[i], h, hpx).c_str()).toUtf8().constData(); + } + } + return r; +} + +typedef QVector > SpriteRects; +SpriteRects sprites; + +ScalarValue prepareSprite(int variant, const char *&text, const char *end) { + StyleGenTokenType type; + string token; + + if (variant) throw exception(QString("Unexpected variant in sprite rectangle!").toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stConsStart) throw exception(QString("Unexpected token %1 while reading sprite() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading sprite() cons!").arg(type).toUtf8().constData()); + string x = token; + if (!readPxAfterNumber(text, end)) throw exception(QString("All number in sprite() cons must be in px!").toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading sprite() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading sprite() cons!").arg(type).toUtf8().constData()); + string y = token; + if (!readPxAfterNumber(text, end)) throw exception(QString("All number in sprite() cons must be in px!").toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading sprite() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading sprite() cons!").arg(type).toUtf8().constData()); + string w = token; + if (!readPxAfterNumber(text, end)) throw exception(QString("All number in sprite() cons must be in px!").toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading sprite() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading sprite() cons!").arg(type).toUtf8().constData()); + string h = token; + if (!readPxAfterNumber(text, end)) throw exception(QString("All number in sprite() cons must be in px!").toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stConsFinish) throw exception(QString("Unexpected token %1 while reading sprite() cons!").arg(type).toUtf8().constData()); + + ScalarValue r; + r[variant] = QString("(%1, %2, %3, %4)").arg(x.c_str()).arg(y.c_str()).arg(w.c_str()).arg(h.c_str()).toUtf8().constData(); + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + r[variants[i]] = QString("(%1, %2, %3, %4)").arg(adjustPx(variants[i], x, true).c_str()).arg(adjustPx(variants[i], y, true).c_str()).arg(adjustPx(variants[i], w, true).c_str()).arg(adjustPx(variants[i], h, true).c_str()).toUtf8().constData(); + } + } + + bool found = false; + QRect sprite(QString(x.c_str()).toInt(), QString(y.c_str()).toInt(), QString(w.c_str()).toInt(), QString(h.c_str()).toInt()); + for (SpriteRects::const_iterator i = sprites.cbegin(), e = sprites.cend(); i != e; ++i) { + if (i->first == sprite) { + found = true; + break; + } + if (i->first.intersects(sprite)) { + cout << QString("Sprites intersection, %1 intersects with %2").arg(i->second).arg(r[variant].c_str()).toUtf8().constData() << "\n"; +// throw exception(QString("Sprites intersection, %1 intersects with %2").arg(i->second).arg(r[variant].c_str()).toUtf8().constData()); + } + } + if (!found) { + sprites.push_back(QPair(sprite, QString(r[variant].c_str()))); + + if (sprite.x() < 0 || sprite.y() < 0 || sprite.x() + sprite.width() > variantSprites[0].width() || sprite.y() + sprite.height() > variantSprites[0].height()) { + throw exception(QString("Bad sprite size %1").arg(r[variant].c_str()).toUtf8().constData()); + } + + int varLast = variants[variantsCount - 1]; + QImage lastCopy = variantSprites[variantsCount - 1].copy(adjustPx(varLast, sprite.x(), true), adjustPx(varLast, sprite.y(), true), adjustPx(varLast, sprite.width(), true), adjustPx(varLast, sprite.height(), true)); + for (int i = 1; i < variantsCount - 1; ++i) { + QPainter p(&variantSprites[i]); + QPixmap copy = QPixmap::fromImage(lastCopy.scaled(adjustPx(variants[i], sprite.width(), true), adjustPx(variants[i], sprite.height(), true), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + p.drawPixmap(QPoint(adjustPx(variants[i], sprite.x(), true), adjustPx(variants[i], sprite.y(), true)), copy); + } + + for (int i = 0; i < variantsCount; ++i) { + QPainter p(&variantGrids[i]); + p.setBrush(Qt::NoBrush); + p.setPen(QColor(0, 255, 255)); + p.drawRect(QRect(adjustPx(variants[i], sprite.x(), true), adjustPx(variants[i], sprite.y(), true), adjustPx(variants[i], sprite.width(), true) - 1, adjustPx(variants[i], sprite.height(), true) - 1)); + } + } + + return r; +} + +ScalarValue preparePoint(int variant, const char *&text, const char *end) { + StyleGenTokenType type; + string token; + + readStyleGenToken(text, end, type, token); + if (type != stConsStart) throw exception(QString("Unexpected token %1 while reading point() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading point() cons!").arg(type).toUtf8().constData()); + string x = token; + bool xpx = readPxAfterNumber(text, end); + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading point() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading point() cons!").arg(type).toUtf8().constData()); + string y = token; + bool ypx = readPxAfterNumber(text, end); + + readStyleGenToken(text, end, type, token); + if (type != stConsFinish) throw exception(QString("Unexpected token %1 while reading point() cons!").arg(type).toUtf8().constData()); + + ScalarValue r; + r[variant] = QString("(%1, %2)").arg(x.c_str()).arg(y.c_str()).toUtf8().constData(); + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + r[variants[i]] = QString("(%1, %2)").arg(adjustPx(variants[i], x, xpx).c_str()).arg(adjustPx(variants[i], y, ypx).c_str()).toUtf8().constData(); + } + } + return r; +} + +ScalarValue prepareSize(int variant, const char *&text, const char *end) { + StyleGenTokenType type; + string token; + + readStyleGenToken(text, end, type, token); + if (type != stConsStart) throw exception(QString("Unexpected token %1 while reading size() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading size() cons!").arg(type).toUtf8().constData()); + string x = token; + bool xpx = readPxAfterNumber(text, end); + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading size() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading size() cons!").arg(type).toUtf8().constData()); + string y = token; + bool ypx = readPxAfterNumber(text, end); + + readStyleGenToken(text, end, type, token); + if (type != stConsFinish) throw exception(QString("Unexpected token %1 while reading size() cons!").arg(type).toUtf8().constData()); + + ScalarValue r; + r[variant] = QString("(%1, %2)").arg(x.c_str()).arg(y.c_str()).toUtf8().constData(); + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + r[variants[i]] = QString("(%1, %2)").arg(adjustPx(variants[i], x, xpx).c_str()).arg(adjustPx(variants[i], y, ypx).c_str()).toUtf8().constData(); + } + } + return r; +} + +ScalarValue prepareTransition(int variant, const char *&text, const char *end) { + StyleGenTokenType type; + string token; + + readStyleGenToken(text, end, type, token); + if (type != stConsStart) throw exception(QString("Unexpected token %1 while reading transition() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stName) throw exception(QString("Unexpected token %1 while reading transition() cons!").arg(type).toUtf8().constData()); + string func = token; + + readStyleGenToken(text, end, type, token); + if (type != stConsFinish) throw exception(QString("Unexpected token %1 while reading transition() cons!").arg(type).toUtf8().constData()); + + return fillPrepareResult(variant, QString("(anim::%1)").arg(func.c_str()).toUtf8().constData()); +} + +ScalarValue prepareCursor(int variant, const char *&text, const char *end) { + StyleGenTokenType type; + string token; + + readStyleGenToken(text, end, type, token); + if (type != stConsStart) throw exception(QString("Unexpected token %1 while reading cursor() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stName) throw exception(QString("Unexpected token %1 while reading cursor() cons!").arg(type).toUtf8().constData()); + string func = token; + + readStyleGenToken(text, end, type, token); + if (type != stConsFinish) throw exception(QString("Unexpected token %1 while reading cursor() cons!").arg(type).toUtf8().constData()); + + return fillPrepareResult(variant, QString("(style::cur_%1)").arg(func.c_str()).toUtf8().constData()); +} + +ScalarValue prepareAlign(int variant, const char *&text, const char *end) { + StyleGenTokenType type; + string token; + + readStyleGenToken(text, end, type, token); + if (type != stConsStart) throw exception(QString("Unexpected token %1 while reading align() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stName) throw exception(QString("Unexpected token %1 while reading align() cons!").arg(type).toUtf8().constData()); + string func = token; + + readStyleGenToken(text, end, type, token); + if (type != stConsFinish) throw exception(QString("Unexpected token %1 while reading align() cons!").arg(type).toUtf8().constData()); + + return fillPrepareResult(variant, QString("(style::al_%1)").arg(func.c_str()).toUtf8().constData()); +} + +ScalarValue prepareMargins(int variant, const char *&text, const char *end) { + StyleGenTokenType type; + string token; + + readStyleGenToken(text, end, type, token); + if (type != stConsStart) throw exception(QString("Unexpected token %1 while reading margins() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading margins() cons!").arg(type).toUtf8().constData()); + string x = token; + bool xpx = readPxAfterNumber(text, end); + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading margins() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading margins() cons!").arg(type).toUtf8().constData()); + string y = token; + bool ypx = readPxAfterNumber(text, end); + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading margins() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading margins() cons!").arg(type).toUtf8().constData()); + string w = token; + bool wpx = readPxAfterNumber(text, end); + + readStyleGenToken(text, end, type, token); + if (type != stComma) throw exception(QString("Unexpected token %1 while reading margins() cons!").arg(type).toUtf8().constData()); + + readStyleGenToken(text, end, type, token); + if (type != stNumber) throw exception(QString("Unexpected token %1 while reading margins() cons!").arg(type).toUtf8().constData()); + string h = token; + bool hpx = readPxAfterNumber(text, end); + + readStyleGenToken(text, end, type, token); + if (type != stConsFinish) throw exception(QString("Unexpected token %1 while reading margins() cons!").arg(type).toUtf8().constData()); + + ScalarValue r; + r[variant] = QString("(%1, %2, %3, %4)").arg(x.c_str()).arg(y.c_str()).arg(w.c_str()).arg(h.c_str()).toUtf8().constData(); + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + r[variants[i]] = QString("(%1, %2, %3, %4)").arg(adjustPx(variants[i], x, xpx).c_str()).arg(adjustPx(variants[i], y, ypx).c_str()).arg(adjustPx(variants[i], w, wpx).c_str()).arg(adjustPx(variants[i], h, hpx).c_str()).toUtf8().constData(); + } + } + return r; +} + +enum FontFlagBits { + FontBoldBit, + FontItalicBit, + FontUnderlineBit, + + FontFlagsBits +}; + +enum FontFlags { + FontBold = (1 << FontBoldBit), + FontItalic = (1 << FontItalicBit), + FontUnderline = (1 << FontUnderlineBit), + + FontDifferentFlags = (1 << FontFlagsBits) +}; + +struct Font { + string family, size; + int flags; +}; + +typedef QMap Fonts; +QMap fonts; + +ScalarValue prepareFont(int variant, const string &name, const char *&text, const char *end) { + StyleGenTokenType type; + string token; + + ScalarValue sizeScalar, familyScalar; + + string size, family; + int flags = 0; + bool sizepx; + + readStyleGenToken(text, end, type, token); + if (type != stConsStart) throw exception(QString("Unexpected token %1 (%2) while reading font() cons!").arg(type).arg(token.c_str()).toUtf8().constData()); + + do { + readStyleGenToken(text, end, type, token); + if (type == stNumber) { + if (size.empty() && sizeScalar.isEmpty()) { + size = token; + sizepx = readPxAfterNumber(text, end); + } else { + throw exception(QString("Unexpected second number %1 while reading font() cons!").arg(token.c_str()).toUtf8().constData()); + } + } else if (type == stName) { + int bit = 0; + if (token == "bold") { + bit = FontBold; + } else if (token == "italic") { + bit = FontItalic; + } else if (token == "underline") { + bit = FontUnderline; + } else { + ByName::const_iterator j = scalarsMap.constFind(token); + if (j != scalarsMap.cend()) { + if (scalars[j.value()].second.first == scNumber) { + if (size.empty() && sizeScalar.isEmpty()) { + sizeScalar = scalars[j.value()].second.second; +// size = findScalarVariant(scalars[j.value()].second.second, variant); + } else { + throw exception(QString("Unexpected second number %1 while reading font() cons!").arg(token.c_str()).toUtf8().constData()); + } + } else if (scalars[j.value()].second.first == scString) { + if (scalars[j.value()].second.second.empty()) { + throw exception(QString("Unexpected empty string %1 while reading font() cons!").arg(token.c_str()).toUtf8().constData()); + } else if (!family.empty() || !familyScalar.empty()) { + throw exception(QString("Unexpected second string %1 while reading font() cons!").arg(token.c_str()).toUtf8().constData()); + } + familyScalar = scalars[j.value()].second.second; +// family = findScalarVariant(scalars[j.value()].second.second, variant); + } else { + throw exception(QString("Unexpected name token %1 type %2 while reading font() cons!").arg(token.c_str()).arg(scalars[j.value()].second.first).toUtf8().constData()); + } + } else { + throw exception(QString("Unexpected name token %1 while reading font() cons!").arg(token.c_str()).toUtf8().constData()); + } + } + if (flags & bit) { + throw exception(QString("Unexpected second time token %1 while reading font() cons!").arg(token.c_str()).toUtf8().constData()); + } + flags |= bit; + } else if (type == stString) { + if (token.empty()) { + throw exception(QString("Unexpected empty string while reading font() cons!").toUtf8().constData()); + } else if (!family.empty() || !familyScalar.empty()) { + throw exception(QString("Unexpected second string %1 while reading font() cons!").arg(token.c_str()).toUtf8().constData()); + } + family = token; + } else if (type == stConsFinish) { + break; + } else { + throw exception(QString("Unexpected token %1 while reading font() cons!").arg(type).toUtf8().constData()); + } + } while (true); + + if (family.empty() && familyScalar.isEmpty()) { + ByName::const_iterator j = scalarsMap.constFind("defaultFontFamily"); + if (j != scalarsMap.cend()) { + if (scalars[j.value()].second.first == scString) { + if (scalars[j.value()].second.second.empty()) { + throw exception(QString("Unexpected empty string %1 while reading font() cons!").arg(token.c_str()).toUtf8().constData()); + } else if (!family.empty() || !familyScalar.isEmpty()) { + throw exception(QString("Unexpected second string %1 while reading font() cons!").arg(token.c_str()).toUtf8().constData()); + } +// family = findScalarVariant(scalars[j.value()].second.second, variant); + familyScalar = scalars[j.value()].second.second; + } else { + throw exception(QString("Font family not found while reading font() cons!").toUtf8().constData()); + } + } else { + throw exception(QString("Font family not found while reading font() cons!").toUtf8().constData()); + } + } + if (size.empty() && sizeScalar.isEmpty()) throw exception(QString("Font size not found while reading font() cons!").toUtf8().constData()); + + Font font; + font.family = familyScalar.empty() ? family : findScalarVariant(familyScalar, variant); + font.size = sizeScalar.empty() ? size : findScalarVariant(sizeScalar, variant); + font.flags = flags; + fonts[variant][name] = font; + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + Font varFont = font; + if (!familyScalar.empty()) varFont.family = findScalarVariant(familyScalar, variants[i]); + varFont.size = sizeScalar.empty() ? adjustPx(variants[i], size, sizepx) : findScalarVariant(sizeScalar, variants[i]); + fonts[variants[i]][name] = varFont; + } + } + + return fillPrepareResult(variant, "(Qt::Uninitialized)"); +} + +ScalarData readScalarElement(string name, const char *&text, const char *end, string objName, const Fields *objFields, int variant) { + string fullName = objFields ? (objName + '.' + name) : name; + ScalarData result; + StyleGenTokenType type; + string token; + readStyleGenToken(text, end, type, token); + if (type == stString) { + result.first = scString; + result.second = prepareString(variant, token); + } else if (type == stNumber) { + result.first = scNumber; + result.second = prepareNumber(variant, token, text, end); + } else if (type == stColor) { + result.first = scColor; + result.second = prepareColor(variant, fullName, token); + } else if (type == stName) { + if (token == "rgb") { + result.first = scColor; + result.second = prepareColorRGB(variant, fullName, text, end); + } else if (token == "rgba") { + result.first = scColor; + result.second = prepareColorRGBA(variant, fullName, text, end); + } else if (token == "rect") { + result.first = scRect; + result.second = prepareRect(variant, text, end); + } else if (token == "sprite") { + result.first = scSprite; + result.second = prepareSprite(variant, text, end); + } else if (token == "point") { + result.first = scPoint; + result.second = preparePoint(variant, text, end); + } else if (token == "size") { + result.first = scSize; + result.second = preparePoint(variant, text, end); + } else if (token == "transition") { + result.first = scTransition; + result.second = prepareTransition(variant, text, end); + } else if (token == "cursor") { + result.first = scCursor; + result.second = prepareCursor(variant, text, end); + } else if (token == "align") { + result.first = scAlign; + result.second = prepareAlign(variant, text, end); + } else if (token == "margins") { + result.first = scMargins; + result.second = prepareMargins(variant, text, end); + } else if (token == "font") { + result.first = scFont; + result.second = prepareFont(variant, fullName, text, end); + } else { + bool found = false; + if (objFields) { + //Fields::const_iterator j = objFields->constFind(token); + //if (j != objFields->cend()) { + // found = true; + // result.second = j.value(); + //} + } + if (!found) { + ByName::const_iterator j = scalarsMap.constFind(token); + if (j != scalarsMap.cend()) { + found = true; + result.first = scalars[j.value()].second.first; + result.second = scalars[j.value()].second.second; + if (result.first == scFont) { + named[variant][fullName] = QPair(result.first, token); + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + named[variants[i]][fullName] = QPair(result.first, token); + } + } + } else if (result.first == scColor) { + named[variant][fullName] = QPair(result.first, token); + if (!variant) { + for (int i = 1; i < variantsCount; ++i) { + named[variants[i]][fullName] = QPair(result.first, token); + } + } + } + } + } + if (!found) { + result.first = scTypesCount; + result.second = fillPrepareResult(variant, token); + } + } + } else { + throw exception(QString("Unexpected token after '%1:', type %2").arg(name.c_str()).arg(type).toUtf8().constData()); + } + return result; +} + + +Scalar readScalarData(StyleGenTokenType &type, string &token, const char *&text, const char *end, string objName = string(), const Fields *objFields = 0) { + if (type != stName) { + throw exception(QString("Unexpected token, type %1: %2").arg(type).arg(token.c_str()).toUtf8().constData()); + } + + string name = token; + if (!objFields) { + ByName::const_iterator i = objectsMap.constFind(name); + if (i != objectsMap.cend()) throw exception(QString("Redefinition of style object %1").arg(name.c_str()).toUtf8().constData()); + + ByName::const_iterator j = scalarsMap.constFind(name); + if (j != scalarsMap.cend()) throw exception(QString("Redefinition of style scalar %1").arg(name.c_str()).toUtf8().constData()); + } + + readStyleGenToken(text, end, type, token); + if (type != stDelimeter) { + throw exception(QString("Unexpected token, type %1: %2").arg(type).arg(token.c_str()).toUtf8().constData()); + } + + string fullName = objFields ? (objName + '.' + name) : name; + Scalar result; + result.first = name; + result.second = readScalarElement(name, text, end, objName, objFields, 0); + + readStyleGenToken(text, end, type, token); + while (type == stVariant) { + readStyleGenToken(text, end, type, token); + if (type != stNumber) { + throw exception(QString("Unexpected token '%1' reading variants of '%2' scalar").arg(token.c_str()).arg(name.c_str()).toUtf8().constData()); + } + int variant = QString(token.c_str()).toInt(); + if (variant != 2 && variant != 3 && variant != 4) { + throw exception(QString("Unexpected variant index '%1' in '%2' scalar").arg(token.c_str()).arg(name.c_str()).toUtf8().constData()); + } + readStyleGenToken(text, end, type, token); + if (type != stDelimeter) { + throw exception(QString("Unexpected token '%1' reading variants of '%2' scalar, expected delimeter").arg(token.c_str()).arg(name.c_str()).toUtf8().constData()); + } + ScalarData el = readScalarElement(name, text, end, objName, objFields, variant); + if (el.first != result.second.first) { + throw exception(QString("Type changed in variant for '%1'").arg(name.c_str()).toUtf8().constData()); + } + result.second.second.insert(variant, el.second[variant]); + + readStyleGenToken(text, end, type, token); + } + return result; +} + +string prepareObject(const string &cls, Fields fields, const string &obj, int variant) { + string result = "("; + Classes::const_iterator i = classes.constFind(cls); + if (i == classes.cend()) throw exception("Unknown error :("); + + for (FieldTypesMap::const_iterator j = i.value().fields.cbegin(), e = i.value().fields.cend(); j != e;) { + result += "style::" + outputTypeNames[j.value()]; + + Fields::iterator f = fields.find(j.key()); + if (f == fields.end()) { + result += "()"; + } else if (f.value().first != j.value()) { + throw exception(QString("Bad type of field %1 while parsing %2").arg(j.key().c_str()).arg(obj.c_str()).toUtf8().constData()); + } else { + result += findScalarVariant(f.value().second, variant); + } + fields.erase(f); + if (++j != e) { + result += ", "; + } + } + + if (fields.size()) { + throw exception(QString("Unknown fields found in %1, for example %2").arg(obj.c_str()).arg(fields.begin().key().c_str()).toUtf8().constData()); + } + + return result + ", Qt::Uninitialized)"; +} + +bool genStyles(const QString &classes_in, const QString &classes_out, const QString &styles_in, const QString &styles_out) { + if (!genClasses(classes_in, classes_out)) return false; + + QString styles_cpp = QString(styles_out).replace(".h", ".cpp"); + if (styles_cpp == styles_out) { + cout << "Bad output file name '" << styles_out.toUtf8().constData() << "'!\n"; + QCoreApplication::exit(1); + return false; + } + + QFile f(styles_in); + if (!f.open(QIODevice::ReadOnly)) { + cout << "Could not open styles input file '" << styles_in.toUtf8().constData() << "'!\n"; + QCoreApplication::exit(1); + return false; + } + + QImage sprites[variantsCount]; + variantSprites = sprites; + + QString sprite0("./SourceFiles/art/sprite" + QString(variantPostfixes[0]) + ".png"), spriteLast("./SourceFiles/art/sprite" + QString(variantPostfixes[variantsCount - 1]) + ".png"); + variantSprites[0] = QImage(sprite0); + for (int i = 1; i < variantsCount - 1; ++i) { + variantSprites[i] = QImage(adjustPx(variants[i], variantSprites[0].width(), true), adjustPx(variants[i], variantSprites[0].height(), true), QImage::Format_ARGB32_Premultiplied); + QPainter p(&variantSprites[i]); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(0, 0, variantSprites[i].width(), variantSprites[i].height(), Qt::transparent); + } + variantSprites[variantsCount - 1] = QImage(spriteLast); + + QPixmap spriteMaxPix = QPixmap::fromImage(variantSprites[variantsCount - 1]); + spriteMax = &spriteMaxPix; + + if (!variantSprites[0].width() || !variantSprites[0].height()) { + cout << "Could not open input sprite file '" << sprite0.toUtf8().constData() << "'!\n"; + QCoreApplication::exit(1); + return false; + } + if (!variantSprites[variantsCount - 1].width() || !variantSprites[variantsCount - 1].height()) { + cout << "Could not open input sprite file '" << spriteLast.toUtf8().constData() << "'!\n"; + QCoreApplication::exit(1); + return false; + } + if (adjustPx(variants[variantsCount - 1], variantSprites[0].width(), true) != variantSprites[variantsCount - 1].width()) { + cout << "Bad sprite file width '" << spriteLast.toUtf8().constData() << "'!\n"; + QCoreApplication::exit(1); + return false; + } + if (adjustPx(variants[variantsCount - 1], variantSprites[0].height(), true) != variantSprites[variantsCount - 1].height()) { + cout << "Bad sprite file height '" << spriteLast.toUtf8().constData() << "'!\n"; + QCoreApplication::exit(1); + return false; + } + + QImage grids[variantsCount]; + variantGrids = grids; + for (int i = 0; i < variantsCount; ++i) { + variantGrids[i] = QImage(variantSprites[i].width(), variantSprites[i].height(), QImage::Format_ARGB32_Premultiplied); + QPainter p(&variantGrids[i]); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(0, 0, variantSprites[i].width(), variantSprites[i].height(), Qt::transparent); + } + + QByteArray blob = f.readAll(); + const char *text = blob.constData(), *end = blob.constData() + blob.size(); + QMap byName; + QVector byIndex; + string token; + StyleGenTokenType type; + try { + while (true) { + try { + readStyleGenToken(text, end, type, token); + } catch (exception &e) { + if (e.what() != string("Unexpected end of file!")) { + throw; + } + break; + } + string name = token; + Scalar scalar = readScalarData(type, token, text, end); + if (scalar.second.first != scTypesCount) { + scalarsMap.insert(scalar.first, scalars.size()); + scalars.push_back(scalar); + if (type != stFieldFinish) throw exception(QString("Unexpected token after scalar %1, type %2").arg(name.c_str()).arg(type).toUtf8().constData()); + continue; + } + + string objType = scalar.second.second[0]; + + Object obj; + obj.first = name; + obj.second.first = objType; + + Classes::const_iterator c = classes.constFind(objType); + if (c == classes.cend()) throw exception(QString("Unknown type %1 used for object %2").arg(objType.c_str()).arg(name.c_str()).toUtf8().constData()); + if (type == stConsStart) { + do { + readStyleGenToken(text, end, type, token); + string parent = token; + if (type != stName) throw exception(QString("Unexpected token %1 while parsing object %2").arg(type).arg(name.c_str()).toUtf8().constData()); + + ByName::const_iterator p = objectsMap.constFind(parent); + if (p == objectsMap.cend()) throw exception(QString("Parent object %1 not found, while parsing object %2").arg(parent.c_str()).arg(name.c_str()).toUtf8().constData()); + + const ObjectData &alr(objects[p.value()].second); + for (Fields::const_iterator f = alr.second.cbegin(), e = alr.second.cend(); f != e; ++f) { + Fields::const_iterator a = obj.second.second.constFind(f.key()); +// if (a == obj.second.second.cend()) { + obj.second.second.insert(f.key(), f.value()); + if (f.value().first == scFont) { + for (int v = 0; v < variantsCount; ++v) { + named[variants[v]][name + '.' + f.key()] = QPair(f.value().first, parent + '.' + f.key()); + } + } else if (f.value().first == scColor) { + for (int v = 0; v < variantsCount; ++v) { + named[variants[v]][name + '.' + f.key()] = QPair(f.value().first, parent + '.' + f.key()); + } + } +// } + } + + readStyleGenToken(text, end, type, token); + if (type == stConsFinish) break; + if (type != stComma) throw exception(QString("Unexpected token %1, expected , or ) while parsing object %2").arg(type).arg(name.c_str()).toUtf8().constData()); + } while (true); + readStyleGenToken(text, end, type, token); + } + if (type != stObjectStart) throw exception(QString("Unexpected token %1, expected { while parsing object %2").arg(type).arg(name.c_str()).toUtf8().constData()); + + while (true) { + readStyleGenToken(text, end, type, token); + if (type == stObjectFinish) { + objectsMap.insert(name, objects.size()); + objects.push_back(obj); + break; + } + + for (int v = 0; v < variantsCount; ++v) { + named[variants[v]].remove(name + '.' + token); + } + + Scalar scalar = readScalarData(type, token, text, end, name, &obj.second.second); + if (scalar.second.first == scTypesCount) throw exception(QString("Unexpected type name %1 while parsing object %2").arg(scalar.second.second[0].c_str()).arg(name.c_str()).toUtf8().constData()); + + obj.second.second.insert(scalar.first, scalar.second); + + if (type != stFieldFinish) throw exception(QString("Unexpected token after scalar %1 in object %2, type %3").arg(scalar.first.c_str()).arg(name.c_str()).arg(type).toUtf8().constData()); + } + } + + QByteArray outText, cppText; + { + int variant = 0; + + QTextStream tout(&outText), tcpp(&cppText); + tout << "\ +/*\n\ +Created from \'/Resources/style.txt\' by \'/MetaStyle\' project\n\ +\n\ +WARNING! All changes made in this file will be lost!\n\ +\n\ +This file is part of Telegram Desktop,\n\ +an unofficial desktop messaging app, see https://telegram.org\n\ +\n\ +Telegram Desktop is free software: you can redistribute it and/or modify\n\ +it under the terms of the GNU General Public License as published by\n\ +the Free Software Foundation, either version 3 of the License, or\n\ +(at your option) any later version.\n\ +\n\ +It is distributed in the hope that it will be useful,\n\ +but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ +GNU General Public License for more details.\n\ +\n\ +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\ +Copyright (c) 2014 John Preston, https://tdesktop.com\n\ +*/\n"; + tout << "#pragma once\n\n#include \"style.h\"\n\nnamespace st {\n"; + tcpp << "\ +/*\n\ +Created from \'/Resources/style.txt\' by \'/MetaStyle\' project\n\ +\n\ +WARNING! All changes made in this file will be lost!\n\ +\n\ +This file is part of Telegram Desktop,\n\ +an unofficial desktop messaging app, see https://telegram.org\n\ +\n\ +Telegram Desktop is free software: you can redistribute it and/or modify\n\ +it under the terms of the GNU General Public License as published by\n\ +the Free Software Foundation, either version 3 of the License, or\n\ +(at your option) any later version.\n\ +\n\ +It is distributed in the hope that it will be useful,\n\ +but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ +GNU General Public License for more details.\n\ +\n\ +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\ +Copyright (c) 2014 John Preston, https://tdesktop.com\n\ +*/\n"; + tcpp << "#include \"stdafx.h\"\n#include \"style_auto.h\"\n\n"; + for (int i = 0, l = scalars.size(); i < l; ++i) { + Scalar &sc(scalars[i]); + tout << "\textern const style::" << outputTypeNames[sc.second.first].c_str() << " &" << sc.first.c_str() << ";\n"; + tcpp << "\tstyle::" << outputTypeNames[sc.second.first].c_str() << " _" << sc.first.c_str() << findScalarVariant(sc.second.second, variant).c_str() << ";\n"; + } + tout << "\n"; + tcpp << "\n"; + for (int i = 0, l = objects.size(); i < l; ++i) { + Object &obj(objects[i]); + tout << "\textern const style::" << obj.second.first.c_str() << " &" << obj.first.c_str() << ";\n"; + tcpp << "\tstyle::" << obj.second.first.c_str() << " _" << obj.first.c_str() << prepareObject(obj.second.first, obj.second.second, obj.first, variant).c_str() << ";\n"; + } + tout << "\n};\n"; + + tcpp << "\nnamespace st {\n"; + for (int i = 0, l = scalars.size(); i < l; ++i) { + Scalar &sc(scalars[i]); + tcpp << "\tconst style::" << outputTypeNames[sc.second.first].c_str() << " &" << sc.first.c_str() << "(_" << sc.first.c_str() << ");\n"; + } + tcpp << "\n"; + for (int i = 0, l = objects.size(); i < l; ++i) { + Object &obj(objects[i]); + tcpp << "\tconst style::" << obj.second.first.c_str() << " &" << obj.first.c_str() << "(_" << obj.first.c_str() << ");\n"; + } + tcpp << "\n};\n"; + + tcpp << "\nnamespace style {\n\n"; + tcpp << "\tFontFamilies _fontFamilies;\n"; + tcpp << "\tFontDatas _fontsMap;\n"; + tcpp << "\tColorDatas _colorsMap;\n\n"; + tcpp << "\tvoid startManager() {\n"; + + tcpp << "\n\t\tswitch (cScale()) {\n\n"; + for (int i = 1; i < variantsCount; ++i) { + variant = variants[i]; + const char *varName = variantNames[i]; + + tcpp << "\t\tcase " << varName << ":\n"; + + typedef QMap FontFamilies; + FontFamilies fontFamilies; + int familyIndex = 0; + + for (int i = 0, l = scalars.size(); i < l; ++i) { + Scalar &sc(scalars[i]); + string v = findScalarVariant(sc.second.second, variant); + if (v != findScalarVariant(sc.second.second, 0)) { + tcpp << "\t\t\t_" << sc.first.c_str() << " = style::" << outputTypeNames[sc.second.first].c_str() << v.c_str() << ";\n"; + } + } + + for (int i = 0, l = objects.size(); i < l; ++i) { + Object &obj(objects[i]); + string v = prepareObject(obj.second.first, obj.second.second, obj.first, variant); + if (v != prepareObject(obj.second.first, obj.second.second, obj.first, 0)) { + tcpp << "\t\t\t_" << obj.first.c_str() << " = style::" << obj.second.first.c_str() << v.c_str() << ";\n"; + } + } + tcpp << "\t\tbreak;\n\n"; + } + tcpp << "\t\t}\n\n"; + + Colors &clrs(colors[variant]); + for (Colors::const_iterator i = clrs.cbegin(), e = clrs.cend(); i != e; ++i) { + bool differ = false; + for (int j = 1; j < variantsCount; ++j) { + const Colors &otherClrs(colors[variants[j]]); + Colors::const_iterator k = otherClrs.constFind(i.key()); + if (k == otherClrs.cend() || k.value().color != i.value().color) { + differ = true; + break; + } + } + if (!differ) { + tcpp << "\t\t_" << i.key().c_str() << ".init(" << i.value().color.c_str() << ");\n"; + } + } + + for (int i = 0; i < variantsCount; ++i) { + variant = variants[i]; + Named &nmd(named[variant]); + while (true) { + bool found = false; + for (Named::iterator i = nmd.begin(), e = nmd.end(); i != e; ++i) { + if (i.key() == i.value().second) { + throw exception(QString("Object '%1' is equal to itself!").arg(i.key().c_str()).toUtf8().constData()); + } + Named::const_iterator j = nmd.constFind(i.value().second); + if (j != nmd.cend()) { + *i = *j; + found = true; + } + } + if (!found) break; + } + } + + tcpp << "\n\t\tswitch (cScale()) {\n\n"; + for (int i = 0; i < variantsCount; ++i) { + variant = variants[i]; + const char *varName = variantNames[i]; + + tcpp << "\t\tcase " << varName << ":\n"; + + typedef QMap FontFamilies; + FontFamilies fontFamilies; + int familyIndex = 0; + ByName::const_iterator j = scalarsMap.constFind("defaultFontFamily"); + if (j != scalarsMap.cend()) { + if (scalars[j.value()].second.first == scString) { + if (scalars[j.value()].second.second.empty()) { + throw exception(QString("Unexpected empty string in defaultFontFamily!").arg(token.c_str()).toUtf8().constData()); + } + string v = findScalarVariant(scalars[j.value()].second.second, variant); + tcpp << "\t\t\t_fontFamilies.push_back" << v.c_str() << ";\n"; + fontFamilies.insert(v, familyIndex++); + } else { + throw exception(QString("defaultFontFamily has bad type!").toUtf8().constData()); + } + } else { + throw exception(QString("defaultFontFamily not found!").toUtf8().constData()); + } + + Fonts &fnts(fonts[variant]); + for (Fonts::const_iterator i = fnts.cbegin(), e = fnts.cend(); i != e; ++i) { + FontFamilies::const_iterator j = fontFamilies.constFind(i.value().family); + if (j == fontFamilies.cend()) { + tcpp << "\n\t\t\t_fontFamilies.push_back" << i.value().family.c_str() << ";\n"; + j = fontFamilies.insert(i.value().family, familyIndex++); + } + tcpp << "\t\t\t_" << i.key().c_str() << ".init(" << i.value().size.c_str() << ", " << i.value().flags << ", " << j.value() << ", 0);\n"; + } + + Colors &clrs(colors[variant]); + if (!clrs.empty()) tcpp << "\n"; + for (Colors::const_iterator i = clrs.cbegin(), e = clrs.cend(); i != e; ++i) { + bool differ = false; + for (int j = 0; j < variantsCount; ++j) { + if (variant == variants[j]) continue; + + const Colors &otherClrs(colors[variants[j]]); + Colors::const_iterator k = otherClrs.constFind(i.key()); + if (k == otherClrs.cend() || k.value().color != i.value().color) { + differ = true; + break; + } + } + if (differ) { + tcpp << "\t\t\t_" << i.key().c_str() << ".init(" << i.value().color.c_str() << ");\n"; + } + } + + Named &nmd(named[variant]); + for (Named::const_iterator i = nmd.cbegin(), e = nmd.cend(); i != e; ++i) { + bool differ = false; + for (int j = 0; j < variantsCount; ++j) { + if (variant == variants[j]) continue; + + const Named &otherNmd(named[variants[j]]); + Named::const_iterator k = otherNmd.constFind(i.key()); + if (k == otherNmd.cend() || k.value().second != i.value().second) { + differ = true; + break; + } + } + if (differ) { + tcpp << "\t\t\t_" << i.key().c_str() << " = _" << i.value().second.c_str() << ";\n"; + } + } + tcpp << "\t\tbreak;\n\n"; + } + tcpp << "\t\t}\n\n"; + + variant = 0; + Named &nmd(named[variant]); + for (Named::const_iterator i = nmd.cbegin(), e = nmd.cend(); i != e; ++i) { + bool differ = false; + for (int j = 1; j < variantsCount; ++j) { + const Named &otherNmd(named[variants[j]]); + Named::const_iterator k = otherNmd.constFind(i.key()); + if (k == otherNmd.cend() || k.value().second != i.value().second) { + differ = true; + break; + } + } + if (!differ) { + tcpp << "\t\t_" << i.key().c_str() << " = _" << i.value().second.c_str() << ";\n"; + } + } + + tcpp << "\t}\n"; + tcpp << "\n};\n"; + } + + for (int i = 1; i < variantsCount - 1; ++i) { + QString spritei("./SourceFiles/art/sprite" + QString(variantPostfixes[i]) + ".png"), spriteLast("./SourceFiles/art/sprite" + QString(variantPostfixes[i]) + ".png"); + QByteArray sprite; + { + QBuffer sbuf(&sprite); + if (!variantSprites[i].save(&sbuf, "PNG")) { + throw exception(("Could not write intermediate sprite '" + spritei + "'!").toUtf8().constData()); + } + } + bool needResave = !QFileInfo(spritei).exists(); + if (!needResave) { + QFile sf(spritei); + if (!sf.open(QIODevice::ReadOnly)) { + needResave = true; + } else { + QByteArray already(sf.readAll()); + if (already.size() != sprite.size() || memcmp(already.constData(), sprite.constData(), already.size())) { + needResave = true; + } + } + } + if (needResave) { + QFile sf(spritei); + if (!sf.open(QIODevice::WriteOnly)) { + throw exception(("Could not write intermediate sprite '" + spritei + "'!").toUtf8().constData()); + } else { + if (sf.write(sprite) != sprite.size()) { + throw exception(("Could not write intermediate sprite '" + spritei + "'!").toUtf8().constData()); + } + } + } + } + for (int i = 0; i < variantsCount; ++i) { + QString spritei("./SourceFiles/art/grid" + QString(variantPostfixes[i]) + ".png"), spriteLast("./SourceFiles/art/sprite" + QString(variantPostfixes[i]) + ".png"); + QByteArray grid; + { + QBuffer gbuf(&grid); + if (!variantGrids[i].save(&gbuf, "PNG")) { + throw exception(("Could not write intermediate grid '" + spritei + "'!").toUtf8().constData()); + } + } + bool needResave = !QFileInfo(spritei).exists(); + if (!needResave) { + QFile gf(spritei); + if (!gf.open(QIODevice::ReadOnly)) { + needResave = true; + } else { + QByteArray already(gf.readAll()); + if (already.size() != grid.size() || memcmp(already.constData(), grid.constData(), already.size())) { + needResave = true; + } + } + } + if (needResave) { + QFile gf(spritei); + if (!gf.open(QIODevice::WriteOnly)) { + throw exception(("Could not write intermediate grid '" + spritei + "'!").toUtf8().constData()); + } else { + if (gf.write(grid) != grid.size()) { + throw exception(("Could not write intermediate grid '" + spritei + "'!").toUtf8().constData()); + } + } + } + } + + QFile out(styles_out), cpp(styles_cpp); + bool write_out = true; + if (out.open(QIODevice::ReadOnly)) { + QByteArray wasOut = out.readAll(); + if (wasOut.size() == outText.size()) { + if (!memcmp(wasOut.constData(), outText.constData(), outText.size())) { + write_out = false; + } + } + out.close(); + } + if (write_out) { + cout << "Style compiled, writing " << scalars.size() << " scalars and " << objects.size() << " objects.\n"; + if (!out.open(QIODevice::WriteOnly)) throw exception("Could not open style_auto.h for writing!"); + if (out.write(outText) != outText.size()) throw exception("Could not open style_auto.h for writing!"); + } + bool write_cpp = true; + if (cpp.open(QIODevice::ReadOnly)) { + QByteArray wasCpp = cpp.readAll(); + if (wasCpp.size() == cppText.size()) { + if (!memcmp(wasCpp.constData(), cppText.constData(), cppText.size())) { + write_cpp = false; + } + } + cpp.close(); + } + if (write_cpp) { + if (!write_out) cout << "Style updated, writing " << scalars.size() << " scalars and " << objects.size() << " objects.\n"; + if (!cpp.open(QIODevice::WriteOnly)) throw exception("Could not open style_auto.cpp for writing!"); + if (cpp.write(cppText) != cppText.size()) throw exception("Could not open style_auto.cpp for writing!"); + } + } catch (exception &e) { + cout << e.what() << "\n"; + QCoreApplication::exit(1); + return false; + } + return true; +} diff --git a/Telegram/SourceFiles/_other/genstyles.h b/Telegram/SourceFiles/_other/genstyles.h new file mode 100644 index 000000000..a6f398b58 --- /dev/null +++ b/Telegram/SourceFiles/_other/genstyles.h @@ -0,0 +1,60 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::string; +using std::cout; +using std::cerr; +using std::exception; + +bool genStyles(const QString &classes_in, const QString &classes_out, const QString &styles_in, const QString &styles_out); + +class GenStyles : public QObject { + Q_OBJECT + +public: + GenStyles(const QString &classes_in, const QString &classes_out, const QString &styles_in, const QString styles_out) : QObject(0), + _classes_in(classes_in), _classes_out(classes_out), _styles_in(styles_in), _styles_out(styles_out) { + } + +public slots: + void run() { + if (genStyles(_classes_in, _classes_out, _styles_in, _styles_out)) { + emit finished(); + } + } + +signals: + void finished(); + +private: + + QString _classes_in, _classes_out, _styles_in, _styles_out; +}; diff --git a/Telegram/SourceFiles/_other/memain.cpp b/Telegram/SourceFiles/_other/memain.cpp new file mode 100644 index 000000000..0db58a523 --- /dev/null +++ b/Telegram/SourceFiles/_other/memain.cpp @@ -0,0 +1,37 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "memain.h" + +int main(int argc, char *argv[]) { + QString emoji_in("."), emoji_out("emoji_config.cpp"); + for (int i = 0; i < argc; ++i) { + if (string("-emoji_in") == argv[i]) { + if (++i < argc) emoji_in = argv[i]; + } else if (string("-emoji_out") == argv[i]) { + if (++i < argc) emoji_out = argv[i]; + } + } + QObject *taskImpl = new GenEmoji(emoji_in, emoji_out); + + QGuiApplication a(argc, argv); + + QObject::connect(taskImpl, SIGNAL(finished()), &a, SLOT(quit())); + QTimer::singleShot(0, taskImpl, SLOT(run())); + + return a.exec(); +} diff --git a/Telegram/SourceFiles/_other/memain.h b/Telegram/SourceFiles/_other/memain.h new file mode 100644 index 000000000..971a6ab6d --- /dev/null +++ b/Telegram/SourceFiles/_other/memain.h @@ -0,0 +1,20 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include + +#include "genemoji.h" diff --git a/Telegram/SourceFiles/_other/mlmain.cpp b/Telegram/SourceFiles/_other/mlmain.cpp new file mode 100644 index 000000000..3f789dd32 --- /dev/null +++ b/Telegram/SourceFiles/_other/mlmain.cpp @@ -0,0 +1,37 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "mlmain.h" + +int main(int argc, char *argv[]) { + QString lang_in("lang.txt"), lang_out("lang"); + for (int i = 0; i < argc; ++i) { + if (string("-lang_in") == argv[i]) { + if (++i < argc) lang_in = argv[i]; + } else if (string("-lang_out") == argv[i]) { + if (++i < argc) lang_out = argv[i]; + } + } + QObject *taskImpl = new GenLang(lang_in, lang_out); + + QCoreApplication a(argc, argv); + + QObject::connect(taskImpl, SIGNAL(finished()), &a, SLOT(quit())); + QTimer::singleShot(0, taskImpl, SLOT(run())); + + return a.exec(); +} diff --git a/Telegram/SourceFiles/_other/mlmain.h b/Telegram/SourceFiles/_other/mlmain.h new file mode 100644 index 000000000..04ab1cb4e --- /dev/null +++ b/Telegram/SourceFiles/_other/mlmain.h @@ -0,0 +1,20 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include + +#include "genlang.h" diff --git a/Telegram/SourceFiles/_other/msmain.cpp b/Telegram/SourceFiles/_other/msmain.cpp new file mode 100644 index 000000000..de901708a --- /dev/null +++ b/Telegram/SourceFiles/_other/msmain.cpp @@ -0,0 +1,41 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "msmain.h" + +int main(int argc, char *argv[]) { + QString classes_in("style_classes.txt"), classes_out("style_classes.h"), styles_in("style.txt"), styles_out("style_auto.h"); + for (int i = 0; i < argc; ++i) { + if (string("-classes_in") == argv[i]) { + if (++i < argc) classes_in = argv[i]; + } else if (string("-classes_out") == argv[i]) { + if (++i < argc) classes_out = argv[i]; + } else if (string("-styles_in") == argv[i]) { + if (++i < argc) styles_in = argv[i]; + } else if (string("-styles_out") == argv[i]) { + if (++i < argc) styles_out = argv[i]; + } + } + QObject *taskImpl = new GenStyles(classes_in, classes_out, styles_in, styles_out); + + QGuiApplication a(argc, argv); + + QObject::connect(taskImpl, SIGNAL(finished()), &a, SLOT(quit())); + QTimer::singleShot(0, taskImpl, SLOT(run())); + + return a.exec(); +} diff --git a/Telegram/SourceFiles/_other/msmain.h b/Telegram/SourceFiles/_other/msmain.h new file mode 100644 index 000000000..6b7cdedd8 --- /dev/null +++ b/Telegram/SourceFiles/_other/msmain.h @@ -0,0 +1,20 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include + +#include "genstyles.h" diff --git a/Telegram/SourceFiles/_other/packer.cpp b/Telegram/SourceFiles/_other/packer.cpp new file mode 100644 index 000000000..b3b6097fb --- /dev/null +++ b/Telegram/SourceFiles/_other/packer.cpp @@ -0,0 +1,298 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "packer.h" + +const char *publicKey = "\ +-----BEGIN RSA PUBLIC KEY-----\n\ +MIGJAoGBAMA4ViQrjkPZ9xj0lrer3r23JvxOnrtE8nI69XLGSr+sRERz9YnUptnU\n\ +BZpkIfKaRcl6XzNJiN28cVwO1Ui5JSa814UAiDHzWUqCaXUiUEQ6NmNTneiGx2sQ\n\ ++9PKKlb8mmr3BB9A45ZNwLT6G9AK3+qkZLHojeSA+m84/a6GP4svAgMBAAE=\n\ +-----END RSA PUBLIC KEY-----\ +"; + +extern const char *privateKey; +#include "../../../../TelegramPrivate/packer_private.h" // RSA PRIVATE KEY for update signing + +// sha1 hash +typedef unsigned char uchar; +typedef unsigned int uint32; +typedef signed int int32; +namespace{ + inline uint32 sha1Shift(uint32 v, uint32 shift) { + return ((v << shift) | (v >> (32 - shift))); + } + void sha1PartHash(uint32 *sha, uint32 *temp) + { + uint32 a = sha[0], b = sha[1], c = sha[2], d = sha[3], e = sha[4], round = 0; + + #define _shiftswap(f, v) { \ + uint32 t = sha1Shift(a, 5) + (f) + e + v + temp[round]; \ + e = d; \ + d = c; \ + c = sha1Shift(b, 30); \ + b = a; \ + a = t; \ + ++round; \ + } + #define _shiftshiftswap(f, v) { \ + temp[round] = sha1Shift((temp[round - 3] ^ temp[round - 8] ^ temp[round - 14] ^ temp[round - 16]), 1); \ + _shiftswap(f, v) \ + } + + while (round < 16) _shiftswap((b & c) | (~b & d), 0x5a827999) + while (round < 20) _shiftshiftswap((b & c) | (~b & d), 0x5a827999) + while (round < 40) _shiftshiftswap(b ^ c ^ d, 0x6ed9eba1) + while (round < 60) _shiftshiftswap((b & c) | (b & d) | (c & d), 0x8f1bbcdc) + while (round < 80) _shiftshiftswap(b ^ c ^ d, 0xca62c1d6) + + #undef _shiftshiftswap + #undef _shiftswap + + sha[0] += a; + sha[1] += b; + sha[2] += c; + sha[3] += d; + sha[4] += e; + } +} + +int32 *hashSha1(const void *data, uint32 len, void *dest) { + const uchar *buf = (const uchar *)data; + + uint32 temp[80], block = 0, end; + uint32 sha[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; + for (end = block + 64; block + 64 <= len; end = block + 64) { + for (uint32 i = 0; block < end; block += 4) { + temp[i++] = (uint32) buf[block + 3] + | (((uint32) buf[block + 2]) << 8) + | (((uint32) buf[block + 1]) << 16) + | (((uint32) buf[block]) << 24); + } + sha1PartHash(sha, temp); + } + + end = len - block; + memset(temp, 0, sizeof(uint32) * 16); + uint32 last = 0; + for (; last < end; ++last) { + temp[last >> 2] |= (uint32)buf[last + block] << ((3 - (last & 0x03)) << 3); + } + temp[last >> 2] |= 0x80 << ((3 - (last & 3)) << 3); + if (end >= 56) { + sha1PartHash(sha, temp); + memset(temp, 0, sizeof(uint32) * 16); + } + temp[15] = len << 3; + sha1PartHash(sha, temp); + + uchar *sha1To = (uchar*)dest; + + for (int32 i = 19; i >= 0; --i) { + sha1To[i] = (sha[i >> 2] >> (((3 - i) & 0x03) << 3)) & 0xFF; + } + + return (int32*)sha1To; +} + +int main(int argc, char *argv[]) +{ + QString remove; + int version = 0; + QFileInfoList files; + for (int i = 0; i < argc; ++i) { + if (string("-path") == argv[i] && i + 1 < argc) { + QString path = QString(argv[i + 1]); + QFileInfo info(path); + files.push_back(info); + if (remove.isEmpty()) remove = info.canonicalPath() + "/"; + } else if (string("-version") == argv[i] && i + 1 < argc) { + version = QString(argv[i + 1]).toInt(); + } + } + + if (files.isEmpty() || remove.isEmpty() || version <= 1016 || version > 999999) { // not for release =) + cout << "Usage: Packer.exe -path {file} -version {version} OR Packer.exe -path {dir} -version {version}\n"; + return 0; + } + + bool hasDirs = true; + while (hasDirs) { + hasDirs = false; + for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { + QFileInfo info(*i); + QString fullPath = info.canonicalFilePath(); + if (info.isDir()) { + hasDirs = true; + files.erase(i); + QDir d = QDir(info.absoluteFilePath()); + QString fullDir = d.canonicalPath(); + QStringList entries = d.entryList(QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); + files.append(d.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot)); + break; + } else if (!info.isReadable()) { + cout << "Can't read: " << info.absoluteFilePath().toUtf8().constData() << "\n"; + return -1; + } + } + } + for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { + QFileInfo info(*i); + if (info.canonicalFilePath().indexOf(remove) != 0) { + cout << "Can't find '" << remove.toUtf8().constData() << "' in file '" << info.canonicalFilePath().toUtf8().constData() << "' :(\n"; + return -1; + } + } + + QByteArray result; + { + QBuffer buffer(&result); + buffer.open(QIODevice::WriteOnly); + QDataStream stream(&buffer); + stream.setVersion(QDataStream::Qt_5_1); + + stream << quint32(version); + + stream << quint32(files.size()); + cout << "Found " << files.size() << " file" << (files.size() == 1 ? "" : "s") << "..\n"; + for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { + QFileInfo info(*i); + QString fullName = info.canonicalFilePath(); + QString name = fullName.mid(remove.length()); + cout << name.toUtf8().constData() << " (" << info.size() << ")\n"; + + QFile f(fullName); + if (!f.open(QIODevice::ReadOnly)) { + cout << "Can't open '" << fullName.toUtf8().constData() << "' for read..\n"; + return -1; + } + QByteArray inner = f.readAll(); + stream << name << quint32(inner.size()) << inner; + } + if (stream.status() != QDataStream::Ok) { + cout << "Stream status is bad: " << stream.status() << "\n"; + return -1; + } + } + + int32 resultSize = result.size(); + cout << "Compression start, size: " << resultSize << "\n"; + + QByteArray compressed, resultCheck; + + const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header + + compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size + + size_t compressedLen = compressed.size() - hSize; + uchar outProps[LZMA_PROPS_SIZE]; + size_t outPropsSize = LZMA_PROPS_SIZE; + int res = LzmaCompress((uchar*)(compressed.data() + hSize), &compressedLen, (const uchar*)(result.constData()), result.size(), (uchar*)(compressed.data() + hSigLen + hShaLen), &outPropsSize, 9, 64 * 1024 * 1024, 0, 0, 0, 0, 0); + if (res != SZ_OK) { + cout << "Error in compression: " << res << "\n"; + return -1; + } + compressed.resize(hSize + compressedLen); + memcpy(compressed.data() + hSigLen + hShaLen + hPropsLen, &resultSize, hOriginalSizeLen); + + cout << "Compressed to size: " << compressedLen << "\n"; + + cout << "Checking uncompressed..\n"; + + int32 resultCheckLen; + memcpy(&resultCheckLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen); + if (resultCheckLen <= 0 || resultCheckLen > 1024 * 1024 * 1024) { + cout << "Bad result len: " << resultCheckLen << "\n"; + return -1; + } + resultCheck.resize(resultCheckLen); + + size_t resultLen = resultCheck.size(); + SizeT srcLen = compressedLen; + int uncompressRes = LzmaUncompress((uchar*)resultCheck.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); + if (uncompressRes != SZ_OK) { + cout << "Uncompress failed: " << uncompressRes << "\n"; + return -1; + } + if (resultLen != result.size()) { + cout << "Uncompress bad size: " << resultLen << ", was: " << result.size() << "\n"; + return -1; + } + if (memcmp(result.constData(), resultCheck.constData(), resultLen)) { + cout << "Data differ :(\n"; + return -1; + } + /**/ + result = resultCheck = QByteArray(); + + cout << "Counting SHA1 hash..\n"; + + uchar sha1Buffer[20]; + memcpy(compressed.data() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen); // count sha1 + + uint32 siglen = 0; + + cout << "Signing..\n"; + RSA *prKey = PEM_read_bio_RSAPrivateKey(BIO_new_mem_buf(const_cast(privateKey), -1), 0, 0, 0); + if (!prKey) { + cout << "Could not read RSA private key!\n"; + return -1; + } + if (RSA_size(prKey) != hSigLen) { + RSA_free(prKey); + cout << "Bad private key, size: " << RSA_size(prKey) << "\n"; + return -1; + } + if (RSA_sign(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (uchar*)(compressed.data()), &siglen, prKey) != 1) { // count signature + RSA_free(prKey); + cout << "Signing failed!\n"; + return -1; + } + RSA_free(prKey); + + if (siglen != hSigLen) { + cout << "Bad signature length: " << siglen << "\n"; + return -1; + } + + cout << "Checking signature..\n"; + RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast(publicKey), -1), 0, 0, 0); + if (!pbKey) { + cout << "Could not read RSA public key!\n"; + return -1; + } + if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), siglen, pbKey) != 1) { // verify signature + RSA_free(pbKey); + cout << "Signature verification failed!\n"; + return -1; + } + cout << "Signature verified!\n"; + RSA_free(pbKey); + + QString outName(QString("tupdate%1").arg(version)); + QFile out(outName); + if (!out.open(QIODevice::WriteOnly)) { + cout << "Can't open '" << outName.toUtf8().constData() << "' for write..\n"; + return -1; + } + out.write(compressed); + out.close(); + + cout << "Update file '" << outName.toUtf8().constData() << "' written successfully!\n"; + + return 0; +} diff --git a/Telegram/SourceFiles/_other/packer.h b/Telegram/SourceFiles/_other/packer.h new file mode 100644 index 000000000..5679cfdad --- /dev/null +++ b/Telegram/SourceFiles/_other/packer.h @@ -0,0 +1,44 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +using std::string; +using std::wstring; +using std::cout; \ No newline at end of file diff --git a/Telegram/SourceFiles/_other/prepare.cpp b/Telegram/SourceFiles/_other/prepare.cpp new file mode 100644 index 000000000..5d814b14a --- /dev/null +++ b/Telegram/SourceFiles/_other/prepare.cpp @@ -0,0 +1,99 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "prepare.h" + +int prepare(QFileInfo f, QStringList paths) { + if (paths.isEmpty()) { + cout << "No -path args were passed :(\n"; + return -1; + } + + int lastVersion = 0; + QString lastVersionStr; + QFileInfo last; + QFileInfoList l = f.absoluteDir().entryInfoList(QDir::Files); + for (QFileInfoList::iterator i = l.begin(), e = l.end(); i != e; ++i) { + QRegularExpressionMatch m = QRegularExpression("/tsetup.((\\d+).(\\d+).(\\d+)).exe$").match(i->absoluteFilePath()); + if (!m.hasMatch()) continue; + + int version = m.captured(2).toInt() * 1000000 + m.captured(3).toInt() * 1000 + m.captured(4).toInt(); + if (version > lastVersion) { + lastVersion = version; + lastVersionStr = m.captured(1); + last = *i; + } + } + + if (!lastVersion) { + cout << "No tsetup.X.Y.Z.exe found :(\n"; + return -1; + } + + cout << "Last version: " << lastVersionStr.toUtf8().constData() << " (" << lastVersion << "), executing packer..\n"; + + QDir dir("deploy/" + lastVersionStr); + if (dir.exists()) { + cout << "Version " << lastVersionStr.toUtf8().constData() << " already exists in /deploy..\n"; + return -1; + } + + QString packer = QString("Packer.exe -version %1").arg(lastVersion); + for (QStringList::iterator i = paths.begin(), e = paths.end(); i != e; ++i) { + packer += " -path " + *i; + } + + int res = system(packer.toUtf8().constData()); + + if (res) return res; + + dir.mkpath("."); + + paths.push_back("Telegram.pdb"); + paths.push_back("Updater.pdb"); + paths.push_back("tsetup." + lastVersionStr + ".exe"); + paths.push_back(QString("tupdate%1").arg(lastVersion)); + for (QStringList::iterator i = paths.begin(), e = paths.end(); i != e; ++i) { + if (!QFile::copy(*i, "deploy/" + lastVersionStr + "/" + *i)) { + cout << "Could not copy " << i->toUtf8().constData() << " to deploy/" << lastVersionStr.toUtf8().constData() << "\n"; + return -1; + } + cout << "Copied " << i->toUtf8().constData() << "..\n"; + } + for (QStringList::iterator i = paths.begin(), e = paths.end(); i != e; ++i) { + QFile::remove(*i); + } + + cout << "Update created in deploy/" << lastVersionStr.toUtf8().constData() << "\n"; + + return 0; +} + +int main(int argc, char *argv[]) +{ + QFileInfo f(argv[0]); + + QStringList paths; + for (int i = 1; i < argc; ++i) { + if (string(argv[i]) == "-path" && i + 1 < argc) { + paths.push_back(QString(argv[i + 1])); + } + } + int res = prepare(f, paths); + system("PAUSE"); + return res; +} diff --git a/Telegram/SourceFiles/_other/prepare.h b/Telegram/SourceFiles/_other/prepare.h new file mode 100644 index 000000000..df1738cbb --- /dev/null +++ b/Telegram/SourceFiles/_other/prepare.h @@ -0,0 +1,37 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +using std::string; +using std::wstring; +using std::cout; \ No newline at end of file diff --git a/Telegram/SourceFiles/_other/updater.cpp b/Telegram/SourceFiles/_other/updater.cpp new file mode 100644 index 000000000..8af7bb729 --- /dev/null +++ b/Telegram/SourceFiles/_other/updater.cpp @@ -0,0 +1,459 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "updater.h" + +bool _debug = false; + +wstring exeName, exeDir; + +bool equal(const wstring &a, const wstring &b) { + return !_wcsicmp(a.c_str(), b.c_str()); +} + +void updateError(const WCHAR *msg, DWORD errorCode) { + WCHAR errMsg[2048]; + LPTSTR errorText = NULL, errorTextDefault = L"(Unknown error)"; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&errorText, 0, 0); + if (!errorText) { + errorText = errorTextDefault; + } + wsprintf(errMsg, L"%s, error code: %d\nError message: %s", msg, errorCode, errorText); + + MessageBox(0, errMsg, L"Update error!", MB_ICONERROR); + + if (errorText != errorTextDefault) { + LocalFree(errorText); + } +} + +HANDLE _logFile = 0; +void openLog() { + if (!_debug || _logFile) return; + wstring logPath = L"DebugLogs"; + if (!CreateDirectory(logPath.c_str(), NULL)) { + DWORD errorCode = GetLastError(); + if (errorCode && errorCode != ERROR_ALREADY_EXISTS) { + updateError(L"Failed to create log directory", errorCode); + return; + } + } + + SYSTEMTIME stLocalTime; + + GetLocalTime(&stLocalTime); + + static const int maxFileLen = MAX_PATH * 10; + WCHAR logName[maxFileLen]; + wsprintf(logName, L"DebugLogs\\%04d%02d%02d_%02d%02d%02d_upd.txt", + stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, + stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond); + _logFile = CreateFile(logName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (_logFile == INVALID_HANDLE_VALUE) { // :( + updateError(L"Failed to create log file", GetLastError()); + _logFile = 0; + return; + } +} + +void closeLog() { + if (!_logFile) return; + + CloseHandle(_logFile); + _logFile = 0; +} + +void writeLog(const wstring &msg) { + if (!_logFile) return; + + wstring full = msg + L'\n'; + DWORD written = 0; + BOOL result = WriteFile(_logFile, full.c_str(), full.size() * sizeof(wchar_t), &written, 0); + if (!result) { + updateError((L"Failed to write log entry '" + msg + L"'").c_str(), GetLastError()); + closeLog(); + return; + } + BOOL flushr = FlushFileBuffers(_logFile); + if (!flushr) { + updateError((L"Failed to flush log on entry '" + msg + L"'").c_str(), GetLastError()); + closeLog(); + return; + } +} + +void delFolder() { + wstring delPath = L"tupdates\\ready", delFolder = L"tupdates"; + WCHAR path[4096]; + memcpy(path, delPath.c_str(), (delPath.size() + 1) * sizeof(WCHAR)); + path[delPath.size() + 1] = 0; + writeLog(L"Fully clearing path '" + delPath + L"'.."); + SHFILEOPSTRUCT file_op = { + NULL, + FO_DELETE, + path, + L"", + FOF_NOCONFIRMATION | + FOF_NOERRORUI | + FOF_SILENT, + false, + 0, + L"" + }; + int res = SHFileOperation(&file_op); + if (res) writeLog(L"Error: failed to clear path! :("); + RemoveDirectory(delFolder.c_str()); +} + +bool update() { + writeLog(L"Update started.."); + + wstring updDir = L"tupdates\\ready"; + + deque dirs; + dirs.push_back(updDir); + + deque from, to, forcedirs; + + do { + wstring dir = dirs.front(); + dirs.pop_front(); + + wstring toDir = exeDir; + if (dir.size() > updDir.size() + 1) { + toDir += (dir.substr(updDir.size() + 1) + L"\\"); + forcedirs.push_back(toDir); + writeLog(L"Parsing dir '" + toDir + L"' in update tree.."); + } + + WIN32_FIND_DATA findData; + HANDLE findHandle = FindFirstFileEx((dir + L"\\*").c_str(), FindExInfoStandard, &findData, FindExSearchNameMatch, 0, 0); + if (findHandle == INVALID_HANDLE_VALUE) { + DWORD errorCode = GetLastError(); + if (errorCode == ERROR_PATH_NOT_FOUND) { // no update is ready + return true; + } + writeLog(L"Error: failed to find update files :("); + updateError(L"Failed to find update files", errorCode); + delFolder(); + return false; + } + + do { + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (findData.cFileName != wstring(L".") && findData.cFileName != wstring(L"..")) { + dirs.push_back(dir + L"\\" + findData.cFileName); + writeLog(L"Added dir '" + dir + L"\\" + findData.cFileName + L"' in update tree.."); + } + } else { + wstring fname = dir + L"\\" + findData.cFileName; + wstring tofname = exeDir + fname.substr(updDir.size() + 1); + if (equal(tofname, exeName)) { // bad update - has Updater.exe - delete all dir + writeLog(L"Error: bad update, has Updater.exe! '" + tofname + L"' equal '" + exeName + L"'"); + delFolder(); + return false; + } + from.push_back(fname); + to.push_back(tofname); + writeLog(L"Added file '" + fname + L"' to be copied to '" + tofname + L"'"); + } + } while (FindNextFile(findHandle, &findData)); + DWORD errorCode = GetLastError(); + if (errorCode && errorCode != ERROR_NO_MORE_FILES) { // everything is found + writeLog(L"Error: failed to find next update file :("); + updateError(L"Failed to find next update file", errorCode); + delFolder(); + return false; + } + FindClose(findHandle); + } while (!dirs.empty()); + + for (size_t i = 0; i < forcedirs.size(); ++i) { + wstring forcedir = forcedirs[i]; + writeLog(L"Forcing dir '" + forcedir + L"'.."); + if (!forcedir.empty() && !CreateDirectory(forcedir.c_str(), NULL)) { + DWORD errorCode = GetLastError(); + if (errorCode && errorCode != ERROR_ALREADY_EXISTS) { + writeLog(L"Error: failed to create dir '" + forcedir + L"'.."); + updateError(L"Failed to create directory", errorCode); + delFolder(); + return false; + } + writeLog(L"Already exists!"); + } + } + + for (size_t i = 0; i < from.size(); ++i) { + wstring fname = from[i], tofname = to[i]; + BOOL copyResult; + do { + writeLog(L"Copying file '" + fname + L"' to '" + tofname + L"'.."); + int copyTries = 0; + do { + copyResult = CopyFile(fname.c_str(), tofname.c_str(), FALSE); + if (copyResult == FALSE) { + ++copyTries; + Sleep(100); + } else { + break; + } + } while (copyTries < 30); + if (copyResult == FALSE) { + writeLog(L"Error: failed to copy, asking to retry.."); + WCHAR errMsg[2048]; + wsprintf(errMsg, L"Failed to update Telegram :(\n%s is not accessible.", tofname); + if (MessageBox(0, errMsg, L"Update error!", MB_ICONERROR | MB_RETRYCANCEL) != IDRETRY) { + delFolder(); + return false; + } + } + } while (copyResult == FALSE); + } + + writeLog(L"Update succeed! Clearing folder.."); + delFolder(); + return true; +} + +void updateRegistry() { + writeLog(L"Updating registry.."); + + HANDLE versionFile = CreateFile(L"tdata\\version", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (versionFile != INVALID_HANDLE_VALUE) { + DWORD versionNum = 0, versionLen = 0, readLen = 0; + WCHAR versionStr[32]; + if (ReadFile(versionFile, &versionNum, sizeof(DWORD), &readLen, NULL) != TRUE || readLen != sizeof(DWORD)) { + versionNum = 0; + } else if (ReadFile(versionFile, &versionLen, sizeof(DWORD), &readLen, NULL) != TRUE || readLen != sizeof(DWORD) || versionLen > 63) { + versionNum = 0; + } else if (ReadFile(versionFile, versionStr, versionLen, &readLen, NULL) != TRUE || readLen != versionLen) { + versionNum = 0; + } + CloseHandle(versionFile); + writeLog(L"Version file read."); + if (versionNum) { + versionStr[versionLen / 2] = 0; + HKEY rkey; + LSTATUS status = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{53F49750-6209-4FBF-9CA8-7A333C87D1ED}_is1", 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &rkey); + if (status == ERROR_SUCCESS) { + writeLog(L"Checking registry install location.."); + static const int bufSize = 4096; + DWORD locationType, locationSize = bufSize * 2; + WCHAR locationStr[bufSize], exp[bufSize]; + if (RegQueryValueEx(rkey, L"InstallLocation", 0, &locationType, (BYTE*)locationStr, &locationSize) == ERROR_SUCCESS) { + locationSize /= 2; + if (locationStr[locationSize - 1]) { + locationStr[locationSize++] = 0; + } + if (locationType == REG_EXPAND_SZ) { + DWORD copy = ExpandEnvironmentStrings(locationStr, exp, bufSize); + if (copy <= bufSize) { + memcpy(locationStr, exp, copy * sizeof(WCHAR)); + } + } + if (locationType == REG_EXPAND_SZ || locationType == REG_SZ) { + if (PathCanonicalize(exp, locationStr) == TRUE) { + memcpy(locationStr, exp, bufSize * sizeof(WCHAR)); + if (GetFullPathName(L".", bufSize, exp, 0) < bufSize) { + wstring installpath = locationStr, mypath = exp; + if (installpath == mypath + L"\\" || true) { // always update reg info, if we found it + WCHAR nameStr[bufSize], dateStr[bufSize]; + SYSTEMTIME stLocalTime; + GetLocalTime(&stLocalTime); + RegSetValueEx(rkey, L"DisplayVersion", 0, REG_SZ, (BYTE*)versionStr, ((versionLen / 2) + 1) * sizeof(WCHAR)); + wsprintf(nameStr, L"Telegram Win (Unofficial) version %s", versionStr); + RegSetValueEx(rkey, L"DisplayName", 0, REG_SZ, (BYTE*)nameStr, (wcslen(nameStr) + 1) * sizeof(WCHAR)); + wsprintf(dateStr, L"%04d%02d%02d", stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay); + RegSetValueEx(rkey, L"InstallDate", 0, REG_SZ, (BYTE*)dateStr, (wcslen(dateStr) + 1) * sizeof(WCHAR)); + + WCHAR *appURL = L"https://tdesktop.com"; + RegSetValueEx(rkey, L"HelpLink", 0, REG_SZ, (BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR)); + RegSetValueEx(rkey, L"URLInfoAbout", 0, REG_SZ, (BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR)); + RegSetValueEx(rkey, L"URLUpdateInfo", 0, REG_SZ, (BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR)); + } + } + } + } + } + RegCloseKey(rkey); + } + } + } +} + +#include + +int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParamarg, int cmdShow) { + openLog(); + +#ifdef _NEED_WIN_GENERATE_DUMP + _oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter); +#endif + + writeLog(L"Updaters started.."); + + LPWSTR *args; + int argsCount; + + bool needupdate = false, autostart = false, debug = false; + args = CommandLineToArgvW(GetCommandLine(), &argsCount); + if (args) { + for (int i = 1; i < argsCount; ++i) { + if (equal(args[i], L"-update")) { + needupdate = true; + } else if (equal(args[i], L"-autostart")) { + autostart = true; + } else if (equal(args[i], L"-debug")) { + debug = _debug = true; + openLog(); + } + } + if (needupdate) writeLog(L"Need to update!"); + if (autostart) writeLog(L"From autostart!"); + + exeName = args[0]; + writeLog(L"Exe name is: " + exeName); + if (exeName.size() > 11) { + if (equal(exeName.substr(exeName.size() - 11), L"Updater.exe")) { + exeDir = exeName.substr(0, exeName.size() - 11); + writeLog(L"Exe dir is: " + exeDir); + if (needupdate && update()) { + updateRegistry(); + } + } else { + writeLog(L"Error: bad exe name!"); + } + } else { + writeLog(L"Error: short exe name!"); + } + LocalFree(args); + } else { + writeLog(L"Error: No command line arguments!"); + } + + wstring targs = L"-noupdate"; + if (autostart) targs += L" -autostart"; + if (debug) targs += L" -debug"; + + ShellExecute(0, 0, (exeDir + L"Telegram.exe").c_str(), targs.c_str(), 0, SW_SHOWNORMAL); + + writeLog(L"Executed Telegram.exe, closing log and quiting.."); + closeLog(); + + return 0; +} + +#ifdef _NEED_WIN_GENERATE_DUMP +static const WCHAR *_programName = L"Telegram Win (Unofficial)"; // folder in APPDATA, if current path is unavailable for writing +static const WCHAR *_exeName = L"Updater.exe"; + +LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter = 0; + +typedef BOOL (FAR STDAPICALLTYPE *t_miniDumpWriteDump)( + _In_ HANDLE hProcess, + _In_ DWORD ProcessId, + _In_ HANDLE hFile, + _In_ MINIDUMP_TYPE DumpType, + _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam +); +t_miniDumpWriteDump miniDumpWriteDump = 0; + +HANDLE _generateDumpFileAtPath(const WCHAR *path) { + static const int maxFileLen = MAX_PATH * 10; + + WCHAR szPath[maxFileLen]; + wsprintf(szPath, L"%stdumps\\", path); + + if (!CreateDirectory(szPath, NULL)) { + if (GetLastError() != ERROR_ALREADY_EXISTS) { + return 0; + } + } + + WCHAR szFileName[maxFileLen]; + WCHAR szExeName[maxFileLen]; + + wcscpy_s(szExeName, _exeName); + WCHAR *dotFrom = wcschr(szExeName, WCHAR(L'.')); + if (dotFrom) { + wsprintf(dotFrom, L""); + } + + SYSTEMTIME stLocalTime; + + GetLocalTime(&stLocalTime); + + wsprintf(szFileName, L"%s%s-%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp", + szPath, szExeName, updaterVersionStr, + stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, + stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond, + GetCurrentProcessId(), GetCurrentThreadId()); + return CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); +} + +void _generateDump(EXCEPTION_POINTERS* pExceptionPointers) { + static const int maxFileLen = MAX_PATH * 10; + + closeLog(); + + HMODULE hDll = LoadLibrary(L"DBGHELP.DLL"); + if (!hDll) return; + + miniDumpWriteDump = (t_miniDumpWriteDump)GetProcAddress(hDll, "MiniDumpWriteDump"); + if (!miniDumpWriteDump) return; + + HANDLE hDumpFile = 0; + + WCHAR szPath[maxFileLen]; + DWORD len = GetModuleFileName(GetModuleHandle(0), szPath, maxFileLen); + if (!len) return; + + WCHAR *pathEnd = szPath + len; + + if (!_wcsicmp(pathEnd - wcslen(_exeName), _exeName)) { + wsprintf(pathEnd - wcslen(_exeName), L""); + hDumpFile = _generateDumpFileAtPath(szPath); + } + if (!hDumpFile || hDumpFile == INVALID_HANDLE_VALUE) { + WCHAR wstrPath[maxFileLen]; + DWORD wstrPathLen; + if (wstrPathLen = GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen)) { + wsprintf(wstrPath + wstrPathLen, L"\\%s\\", _programName); + hDumpFile = _generateDumpFileAtPath(wstrPath); + } + } + + if (!hDumpFile || hDumpFile == INVALID_HANDLE_VALUE) { + return; + } + + MINIDUMP_EXCEPTION_INFORMATION ExpParam = {0}; + ExpParam.ThreadId = GetCurrentThreadId(); + ExpParam.ExceptionPointers = pExceptionPointers; + ExpParam.ClientPointers = TRUE; + + miniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL); +} + +LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers) { + _generateDump(pExceptionPointers); + return _oldWndExceptionFilter ? (*_oldWndExceptionFilter)(pExceptionPointers) : EXCEPTION_CONTINUE_SEARCH; +} + +#endif diff --git a/Telegram/SourceFiles/_other/updater.h b/Telegram/SourceFiles/_other/updater.h new file mode 100644 index 000000000..920f14262 --- /dev/null +++ b/Telegram/SourceFiles/_other/updater.h @@ -0,0 +1,40 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +using std::deque; +using std::wstring; + +#define _NEED_WIN_GENERATE_DUMP + +#ifdef _NEED_WIN_GENERATE_DUMP +extern LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter; +LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers); +#endif _NEED_WIN_GENERATE_DUMP + +static int updaterVersion = 1000; +static const WCHAR *updaterVersionStr = L"0.1.0"; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp new file mode 100644 index 000000000..0b9be11de --- /dev/null +++ b/Telegram/SourceFiles/app.cpp @@ -0,0 +1,1925 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" + +#include "app.h" + +#include "application.h" +#include "fileuploader.h" +#include "mainwidget.h" +#include +#include + +namespace { + bool quiting = false; + + UserData *self = 0; + + typedef QHash PeersData; + PeersData peersData; + + typedef QHash PhotosData; + PhotosData photosData; + + typedef QHash VideosData; + VideosData videosData; + + typedef QHash AudiosData; + AudiosData audiosData; + + typedef QHash DocumentsData; + DocumentsData documentsData; + + VideoItems videoItems; + AudioItems audioItems; + DocumentItems documentItems; + + Histories histories; + + typedef QHash MsgsData; + MsgsData msgsData; + int32 maxMsgId = 0; + + typedef QMap RandomData; + RandomData randomData; + + HistoryItem *hoveredItem = 0, *pressedItem = 0, *hoveredLinkItem = 0, *pressedLinkItem = 0, *contextItem = 0, *mousedItem = 0; + + QSoundEffect *newMsgSound = 0; + QPixmap *sprite = 0, *emojis = 0; + + typedef QMap EmojisMap; + EmojisMap mainEmojisMap; + QMap otherEmojisMap; + + int32 serviceImageCacheSize = 0; + + typedef QLinkedList LastPhotosList; + LastPhotosList lastPhotos; + typedef QHash LastPhotosMap; + LastPhotosMap lastPhotosMap; +} + +namespace App { + + QString formatPhone(QString phone) { + return '+' + phone.replace(QRegularExpression(qsl("[^\\d]")), QString()); + } + + Application *app() { + return Application::app(); + } + + Window *wnd() { + return Application::wnd(); + } + + MainWidget *main() { + Window *w(wnd()); + return w ? w->mainWidget() : 0; + } + + Settings *settings() { + Window *w(wnd()); + return w ? w->settingsWidget() : 0; + } + + FileUploader *uploader() { + return app() ? app()->uploader() : 0; + } + + void showSettings() { + Window *w(wnd()); + if (w) w->showSettings(); + } + + bool loggedOut() { + Window *w(wnd()); + if (w) { + w->tempDirDelete(); + w->psClearNotifyFast(); + w->setupIntro(true); + } + MainWidget *m(main()); + if (m) m->destroyData(); + MTP::authed(0); + histories().clear(); + globalNotifyAllPtr = UnknownNotifySettings; + globalNotifyUsersPtr = UnknownNotifySettings; + globalNotifyChatsPtr = UnknownNotifySettings; + App::uploader()->clear(); + clearStorageImages(); + if (w) { + w->updateTitleStatus(); + w->getTitle()->resizeEvent(0); + } + return true; + } + + void logOut() { + MTP::send(MTPauth_LogOut(), rpcDone(&loggedOut), rpcFail(&loggedOut)); + } + + PeerId peerFromMTP(const MTPPeer &peer_id) { + switch (peer_id.type()) { + case mtpc_peerChat: return peerFromChat(peer_id.c_peerChat().vchat_id); + case mtpc_peerUser: return peerFromUser(peer_id.c_peerUser().vuser_id); + } + return 0; + } + + PeerId peerFromChat(int32 chat_id) { + return 0x100000000L | uint64(uint32(chat_id)); + } + + PeerId peerFromUser(int32 user_id) { + return uint64(uint32(user_id)); + } + + MTPpeer peerToMTP(const PeerId &peer_id) { + return (peer_id & 0x100000000L) ? MTP_peerChat(MTP_int(int32(peer_id & 0xFFFFFFFFL))) : MTP_peerUser(MTP_int(int32(peer_id & 0xFFFFFFFFL))); + } + + int32 onlineWillChangeIn(int32 online, int32 now) { + if (online <= 0) return 86400; + if (online > now) { + return online - now; + } + int32 minutes = (now - online) / 60; + if (minutes < 60) { + return (minutes + 1) * 60 - (now - online); + } + int32 hours = (now - online) / 3600; + if (hours < 12) { + return (hours + 1) * 3600 - (now - online); + } + QDateTime dNow(date(now)), dTomorrow(dNow.date().addDays(1)); + return dNow.secsTo(dTomorrow); + } + + QString onlineText(int32 online, int32 now) { + if (!online) return lang(lng_status_offline); + if (online < 0) return lang(lng_status_invisible); + if (online > now) { + return lang(lng_status_online); + } + int32 minutes = (now - online) / 60; + QString when; + if (!minutes) { + when = lang(lng_status_lastseen_now); + } else if (minutes == 1) { + when = lang(lng_status_lastseen_minute).arg(minutes); + } else if (minutes < 60) { + when = lang(lng_status_lastseen_minutes).arg(minutes); + } else { + int32 hours = (now - online) / 3600; + if (hours == 1) { + when = lang(lng_status_lastseen_hour).arg(hours); + } else if (hours < 12) { + when = lang(lng_status_lastseen_hours).arg(hours); + } else { + QDateTime dOnline(date(online)), dNow(date(now)); + if (dOnline.date() == dNow.date()) { + when = lang(lng_status_lastseen_today).replace(qsl("{time}"), dOnline.time().toString(qsl("hh:mm"))); + } else if (dOnline.date().addDays(1) == dNow.date()) { + when = lang(lng_status_lastseen_yesterday).replace(qsl("{time}"), dOnline.time().toString(qsl("hh:mm"))); + } else { + when = lang(lng_status_lastseen_date).replace(qsl("{date}"), dOnline.date().toString(qsl("dd.MM.yy"))); + } + } + } + if (when.isEmpty()) { + int a = 0; + } + return lang(lng_status_lastseen).replace(qsl("{when}"), when); + } + + void feedUsers(const MTPVector &users) { + const QVector &v(users.c_vector().v); + for (QVector::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) { + const MTPuser &user(*i); + UserData *data; + bool wasContact = false; + const MTPUserStatus *status = 0; + + switch (user.type()) { + case mtpc_userEmpty: { + const MTPDuserEmpty &d(user.c_userEmpty()); + + PeerId peer(peerFromUser(d.vid.v)); + data = App::user(peer); + data->input = MTP_inputPeerContact(d.vid); + data->inputUser = MTP_inputUserContact(d.vid); + data->setName(lang(lng_deleted), QString(), QString()); + data->setPhoto(MTP_userProfilePhotoEmpty()); + data->access = 0; + wasContact = (data->contact > 0); + data->contact = -1; + } break; + case mtpc_userDeleted: { + const MTPDuserDeleted &d(user.c_userDeleted()); + + PeerId peer(peerFromUser(d.vid.v)); + data = App::user(peer); + data->input = MTP_inputPeerContact(d.vid); + data->inputUser = MTP_inputUserContact(d.vid); + data->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), QString()); + data->setPhoto(MTP_userProfilePhotoEmpty()); + data->access = 0; + wasContact = (data->contact > 0); + data->contact = -1; + } break; + case mtpc_userSelf: { + const MTPDuserSelf &d(user.c_userSelf()); + + PeerId peer(peerFromUser(d.vid.v)); + data = App::user(peer); + data->input = MTP_inputPeerSelf(); + data->inputUser = MTP_inputUserSelf(); + data->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), QString()); + data->setPhoto(d.vphoto); + data->setPhone(qs(d.vphone)); + data->access = 0; + wasContact = (data->contact > 0); + data->contact = -1; + status = &d.vstatus; + + ::self = data; + } break; + case mtpc_userContact: { + const MTPDuserContact &d(user.c_userContact()); + + PeerId peer(peerFromUser(d.vid.v)); + data = App::user(peer); + data->input = MTP_inputPeerContact(d.vid); + data->inputUser = MTP_inputUserContact(d.vid); + data->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), QString()); + data->setPhoto(d.vphoto); + data->setPhone(qs(d.vphone)); + data->access = d.vaccess_hash.v; + wasContact = (data->contact > 0); + data->contact = 1; + status = &d.vstatus; + } break; + case mtpc_userRequest: { + const MTPDuserRequest &d(user.c_userRequest()); + + PeerId peer(peerFromUser(d.vid.v)); + data = App::user(peer); + data->input = MTP_inputPeerForeign(d.vid, d.vaccess_hash); + data->inputUser = MTP_inputUserForeign(d.vid, d.vaccess_hash); + data->setPhone(qs(d.vphone)); + data->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), (data->id != 333000 && !data->phone.isEmpty()) ? formatPhone(data->phone) : QString()); + data->setPhoto(d.vphoto); + data->access = d.vaccess_hash.v; + wasContact = (data->contact > 0); + data->contact = 0; + status = &d.vstatus; + } break; + case mtpc_userForeign: { + const MTPDuserForeign &d(user.c_userForeign()); + + PeerId peer(peerFromUser(d.vid.v)); + data = App::user(peer); + data->input = MTP_inputPeerForeign(d.vid, d.vaccess_hash); + data->inputUser = MTP_inputUserForeign(d.vid, d.vaccess_hash); + data->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), QString()); + data->setPhoto(d.vphoto); + data->access = d.vaccess_hash.v; + wasContact = (data->contact > 0); + data->contact = -1; + status = &d.vstatus; + } break; + } + + data->loaded = true; + if (status) switch (status->type()) { + case mtpc_userStatusOffline: data->onlineTill = status->c_userStatusOffline().vwas_online.v; break; + case mtpc_userStatusOnline: data->onlineTill = status->c_userStatusOnline().vexpires.v; break; + } + + if (data->contact < 0 && !data->phone.isEmpty() && data->id != MTP::authedId()) { + data->contact = 0; + } + if (data->contact > 0 && !wasContact) { + App::main()->addNewContact(data->id & 0xFFFFFFFF, false); + } else if (wasContact && data->contact <= 0) { + App::main()->removeContact(data); + } + + if (App::main()) App::main()->peerUpdated(data); + } + } + + void feedChats(const MTPVector &chats) { + const QVector &v(chats.c_vector().v); + for (QVector::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) { + const MTPchat &chat(*i); + ChatData *data; + QString title; + switch (chat.type()) { + case mtpc_chat: { + const MTPDchat &d(chat.c_chat()); + title = qs(d.vtitle); + + PeerId peer(peerFromChat(d.vid.v)); + data = App::chat(peer); + data->input = MTP_inputPeerChat(d.vid); + data->setPhoto(d.vphoto); + data->date = d.vdate.v; + data->count = d.vparticipants_count.v; + data->left = false; + data->forbidden = false; + data->access = 0; + if (data->version < d.vversion.v) { + data->version = d.vversion.v; + data->participants = ChatData::Participants(); + } + } break; + case mtpc_chatForbidden: { + const MTPDchatForbidden &d(chat.c_chatForbidden()); + title = qs(d.vtitle); + + PeerId peer(peerFromChat(d.vid.v)); + data = App::chat(peer); + data->input = MTP_inputPeerChat(d.vid); + data->setPhoto(MTP_chatPhotoEmpty()); + data->date = 0; + data->count = -1; + data->left = false; + data->forbidden = true; + data->access = 0; + } break; + case mtpc_geoChat: { + const MTPDgeoChat &d(chat.c_geoChat()); + data = 0; +/* title = qs(d.vtitle); + + PeerId peer(peerFromChat(d.vid.v)); + data = App::chat(peer); + data->input = MTP_inputPeerChat(d.vid); + data->setPhoto(d.vphoto); + data->date = d.vdate.v; + data->count = d.vparticipants_count.v; + data->left = false; + data->forbidden = false; + data->access = d.vaccess_hash.v; + if (data->version < d.vversion.v) { + data->version = d.vversion.v; + data->participants = ChatData::Participants(); + }/**/ + } break; + } + if (!data) continue; + + data->loaded = true; + data->updateName(title.trimmed(), QString()); + + if (App::main()) App::main()->peerUpdated(data); + } + } + + void feedParticipants(const MTPChatParticipants &p) { + switch (p.type()) { + case mtpc_chatParticipantsForbidden: { + const MTPDchatParticipantsForbidden &d(p.c_chatParticipantsForbidden()); + ChatData *chat = App::chat(d.vchat_id.v); + chat->count = -1; + if (App::main()) App::main()->peerUpdated(chat); + } break; + case mtpc_chatParticipants: { + const MTPDchatParticipants &d(p.c_chatParticipants()); + ChatData *chat = App::chat(d.vchat_id.v); + chat->admin = d.vadmin_id.v; + if (chat->version <= d.vversion.v) { + chat->version = d.vversion.v; + const QVector &v(d.vparticipants.c_vector().v); + chat->count = v.size(); + int32 pversion = chat->participants.isEmpty() ? 1 : (chat->participants.begin().value() + 1); + chat->cankick = ChatData::CanKick(); + for (QVector::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) { + UserData *user = App::userLoaded(i->c_chatParticipant().vuser_id.v); + if (user) { + chat->participants[user] = pversion; + if (i->c_chatParticipant().vinviter_id.v == MTP::authedId()) { + chat->cankick[user] = true; + } + } else { + chat->participants = ChatData::Participants(); + break; + } + } + if (!chat->participants.isEmpty()) { + for (ChatData::Participants::iterator i = chat->participants.begin(), e = chat->participants.end(); i != e;) { + if (i.value() < pversion) { + i = chat->participants.erase(i); + } else { + ++i; + } + } + } + if (App::main()) App::main()->peerUpdated(chat); + } + } break; + } + } + + void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d) { + ChatData *chat = App::chat(d.vchat_id.v); + if (chat->version <= d.vversion.v && chat->count >= 0) { + chat->version = d.vversion.v; + UserData *user = App::userLoaded(d.vuser_id.v); + if (user) { + if (chat->participants.isEmpty() && chat->count) { + chat->count++; + } else if (chat->participants.find(user) == chat->participants.end()) { + chat->participants[user] = (chat->participants.isEmpty() ? 1 : chat->participants.begin().value()); + if (d.vinviter_id.v == MTP::authedId()) { + chat->cankick[user] = true; + } else { + chat->cankick.remove(user); + } + chat->count++; + } + } else { + chat->participants = ChatData::Participants(); + chat->count++; + } + if (App::main()) App::main()->peerUpdated(chat); + } + } + + void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d) { + ChatData *chat = App::chat(d.vchat_id.v); + if (chat->version <= d.vversion.v && chat->count > 0) { + chat->version = d.vversion.v; + UserData *user = App::userLoaded(d.vuser_id.v); + if (user) { + if (chat->participants.isEmpty()) { + chat->count--; + } else { + ChatData::Participants::iterator i = chat->participants.find(user); + if (i != chat->participants.end()) { + chat->participants.erase(i); + chat->count--; + } + } + } else { + chat->participants = ChatData::Participants(); + chat->count--; + } + if (App::main()) App::main()->peerUpdated(chat); + } + } + + void feedMsgs(const MTPVector &msgs, bool newMsgs) { + const QVector &v(msgs.c_vector().v); + QMap msgsIds; + for (int32 i = 0, l = v.size(); i < l; ++i) { + const MTPMessage &msg(v[i]); + switch (msg.type()) { + case mtpc_message: msgsIds.insert(msg.c_message().vid.v, i); break; + case mtpc_messageEmpty: msgsIds.insert(msg.c_messageEmpty().vid.v, i); break; + case mtpc_messageForwarded: msgsIds.insert(msg.c_messageForwarded().vid.v, i); break; + case mtpc_messageService: msgsIds.insert(msg.c_messageService().vid.v, i); break; + } + } + for (QMap::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) { + histories().addToBack(v[*i], newMsgs); + } + } + + int32 maxMsgId() { + return ::maxMsgId; + } + + ImagePtr image(const MTPPhotoSize &size) { + switch (size.type()) { + case mtpc_photoSize: { + const MTPDphotoSize &d(size.c_photoSize()); + if (d.vlocation.type() == mtpc_fileLocation) { + const MTPDfileLocation &l(d.vlocation.c_fileLocation()); + return ImagePtr(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v); + } + } break; + case mtpc_photoCachedSize: { + const MTPDphotoCachedSize &d(size.c_photoCachedSize()); + if (d.vlocation.type() == mtpc_fileLocation) { + const MTPDfileLocation &l(d.vlocation.c_fileLocation()); + const string &s(d.vbytes.c_string().v); + QByteArray bytes(s.data(), s.size()); + return ImagePtr(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v, bytes); + } else if (d.vlocation.type() == mtpc_fileLocationUnavailable) { + const string &s(d.vbytes.c_string().v); + QByteArray bytes(s.data(), s.size()); + return ImagePtr(d.vw.v, d.vh.v, 0, 0, 0, 0, bytes); + } + } break; + } + return ImagePtr(); + } + + void feedWereRead(const QVector &msgsIds) { + for (QVector::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) { + MsgsData::const_iterator j = msgsData.constFind(i->v); + if (j != msgsData.cend()) { + (*j)->markRead(); + } + } + } + + void feedWereDeleted(const QVector &msgsIds) { + for (QVector::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) { + MsgsData::const_iterator j = msgsData.constFind(i->v); + if (j != msgsData.cend()) { + History *h = (*j)->history(); + (*j)->destroy(); + if (h->isEmpty()) { + if (App::main()) App::main()->checkPeerHistory(h->peer); + } + } + } + } + + void feedUserLinks(const MTPVector &links) { + const QVector &v(links.c_vector().v); + for (QVector::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) { + const MTPDcontacts_link &dv(i->c_contacts_link()); + feedUsers(MTP_vector(QVector(1, dv.vuser))); + MTPint userId(MTP_int(0)); + switch (dv.vuser.type()) { + case mtpc_userEmpty: userId = dv.vuser.c_userEmpty().vid; break; + case mtpc_userDeleted: userId = dv.vuser.c_userDeleted().vid; break; + case mtpc_userContact: userId = dv.vuser.c_userContact().vid; break; + case mtpc_userSelf: userId = dv.vuser.c_userSelf().vid; break; + case mtpc_userRequest: userId = dv.vuser.c_userRequest().vid; break; + case mtpc_userForeign: userId = dv.vuser.c_userForeign().vid; break; + } + if (userId.v) { + feedUserLink(userId, dv.vmy_link, dv.vforeign_link); + } + } + } + + void feedUserLink(MTPint userId, const MTPcontacts_MyLink &myLink, const MTPcontacts_ForeignLink &foreignLink) { + UserData *user = userLoaded(userId.v); + if (user) { + bool wasContact = (user->contact > 0); + switch (myLink.type()) { + case mtpc_contacts_myLinkContact: + user->contact = 1; + break; + case mtpc_contacts_myLinkEmpty: + case mtpc_contacts_myLinkRequested: + if (myLink.c_contacts_myLinkRequested().vcontact.v) { + user->contact = 1; + } else { + switch (foreignLink.type()) { + case mtpc_contacts_foreignLinkRequested: + if (foreignLink.c_contacts_foreignLinkRequested().vhas_phone.v) { + user->contact = 0; + } else { + user->contact = -1; + } + break; + default: user->contact = -1; break; + } + } + break; + } + if (user->contact > 0) { + if (!wasContact) { + App::main()->addNewContact(user->id & 0xFFFFFFFF, false); + user->input = MTP_inputPeerContact(userId); + user->inputUser = MTP_inputUserContact(userId); + } + } else { + if (user->access) { + user->input = MTP_inputPeerForeign(userId, MTP_long(user->access)); + user->inputUser = MTP_inputUserForeign(userId, MTP_long(user->access)); + } + if (user->contact < 0 && !user->phone.isEmpty() && user->id != MTP::authedId()) { + user->contact = 0; + } + if (wasContact) { + App::main()->removeContact(user); + } + } + user->setName(textOneLine(user->firstName), textOneLine(user->lastName), (user->contact || user->id == 333000 || user->phone.isEmpty()) ? QString() : App::formatPhone(user->phone)); + if (App::main()) App::main()->peerUpdated(user); + } + } + + void feedMessageMedia(MsgId msgId, const MTPMessage &msg) { + const MTPMessageMedia *media = 0; + switch (msg.type()) { + case mtpc_message: media = &msg.c_message().vmedia; break; + case mtpc_messageForwarded: media = &msg.c_messageForwarded().vmedia; break; + } + if (media) { + MsgsData::iterator i = msgsData.find(msgId); + if (i != msgsData.cend()) { + i.value()->updateMedia(*media); + } + } + } + + PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert) { + switch (photo.type()) { + case mtpc_photo: { + return feedPhoto(photo.c_photo(), convert); + } break; + case mtpc_photoEmpty: { + return App::photo(photo.c_photoEmpty().vid.v, convert); + } break; + } + return App::photo(0); + } + + PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs) { + const QPixmap *thumb = 0, *full = 0; + int32 thumbLevel = -1, fullLevel = -1; + for (PreparedPhotoThumbs::const_iterator i = thumbs.cbegin(), e = thumbs.cend(); i != e; ++i) { + int32 newThumbLevel = -1, newFullLevel = -1; + switch (i.key()) { + case 's': newThumbLevel = 0; newFullLevel = 4; break; // box 100x100 + case 'm': newThumbLevel = 2; newFullLevel = 3; break; // box 320x320 + case 'x': newThumbLevel = 5; newFullLevel = 0; break; // box 800x800 + case 'y': newThumbLevel = 6; newFullLevel = 1; break; // box 1280x1280 + case 'w': newThumbLevel = 8; newFullLevel = 2; break; // box 2560x2560 + case 'a': newThumbLevel = 1; newFullLevel = 8; break; // crop 160x160 + case 'b': newThumbLevel = 3; newFullLevel = 7; break; // crop 320x320 + case 'c': newThumbLevel = 4; newFullLevel = 6; break; // crop 640x640 + case 'd': newThumbLevel = 7; newFullLevel = 5; break; // crop 1280x1280 + } + if (newThumbLevel < 0 || newFullLevel < 0) { + continue; + } + if (thumbLevel < 0 || newThumbLevel < thumbLevel) { + thumbLevel = newThumbLevel; + thumb = &i.value(); + } + if (fullLevel < 0 || newFullLevel < fullLevel) { + fullLevel = newFullLevel; + full = &i.value(); + } + } + if (!thumb || !full) { + return App::photo(0); + } + switch (photo.type()) { + case mtpc_photo: { + const MTPDphoto &ph(photo.c_photo()); + return App::photo(ph.vid.v, 0, ph.vaccess_hash.v, ph.vuser_id.v, ph.vdate.v, ImagePtr(*thumb, "JPG"), ImagePtr(*full, "JPG")); + } break; + case mtpc_photoEmpty: return App::photo(photo.c_photoEmpty().vid.v); + } + return App::photo(0); + } + + PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert) { + const QVector &sizes(photo.vsizes.c_vector().v); + const MTPPhotoSize *thumb = 0, *full = 0; + int32 thumbLevel = -1, fullLevel = -1; + for (QVector::const_iterator i = sizes.cbegin(), e = sizes.cend(); i != e; ++i) { + char size = 0; + switch (i->type()) { + case mtpc_photoSize: { + const string &s(i->c_photoSize().vtype.c_string().v); + if (s.size()) size = s[0]; + } break; + + case mtpc_photoCachedSize: { + const string &s(i->c_photoCachedSize().vtype.c_string().v); + if (s.size()) size = s[0]; + } break; + } + if (!size) continue; + + int32 newThumbLevel = -1, newFullLevel = -1; + switch (size) { + case 's': newThumbLevel = 0; newFullLevel = 4; break; // box 100x100 + case 'm': newThumbLevel = 2; newFullLevel = 3; break; // box 320x320 + case 'x': newThumbLevel = 5; newFullLevel = 0; break; // box 800x800 + case 'y': newThumbLevel = 6; newFullLevel = 1; break; // box 1280x1280 + case 'w': newThumbLevel = 8; newFullLevel = 2; break; // box 2560x2560 + case 'a': newThumbLevel = 1; newFullLevel = 8; break; // crop 160x160 + case 'b': newThumbLevel = 3; newFullLevel = 7; break; // crop 320x320 + case 'c': newThumbLevel = 4; newFullLevel = 6; break; // crop 640x640 + case 'd': newThumbLevel = 7; newFullLevel = 5; break; // crop 1280x1280 + } + if (newThumbLevel < 0 || newFullLevel < 0) { + continue; + } + if (thumbLevel < 0 || newThumbLevel < thumbLevel) { + thumbLevel = newThumbLevel; + thumb = &(*i); + } + if (fullLevel < 0 || newFullLevel < fullLevel) { + fullLevel = newFullLevel; + full = &(*i); + } + } + if (thumb && full) { + return App::photo(photo.vid.v, convert, photo.vaccess_hash.v, photo.vuser_id.v, photo.vdate.v, App::image(*thumb), App::image(*full)); + } + return App::photo(photo.vid.v, convert); + } + + VideoData *feedVideo(const MTPDvideo &video, VideoData *convert) { + return App::video(video.vid.v, convert, video.vaccess_hash.v, video.vuser_id.v, video.vdate.v, video.vduration.v, video.vw.v, video.vh.v, App::image(video.vthumb), video.vdc_id.v, video.vsize.v); + } + + AudioData *feedAudio(const MTPDaudio &audio, AudioData *convert) { + return App::audio(audio.vid.v, convert, audio.vaccess_hash.v, audio.vuser_id.v, audio.vdate.v, audio.vduration.v, audio.vdc_id.v, audio.vsize.v); + } + + DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb) { + switch (document.type()) { + case mtpc_document: { + const MTPDdocument &d(document.c_document()); + return App::document(d.vid.v, 0, d.vaccess_hash.v, d.vuser_id.v, d.vdate.v, qs(d.vfile_name), qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v); + } break; + case mtpc_documentEmpty: return App::document(document.c_documentEmpty().vid.v); + } + return App::document(0); + } + + DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert) { + switch (document.type()) { + case mtpc_document: { + return feedDocument(document.c_document(), convert); + } break; + case mtpc_documentEmpty: { + return App::document(document.c_documentEmpty().vid.v, convert); + } break; + } + return App::document(0); + } + + DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert) { + return App::document(document.vid.v, convert, document.vaccess_hash.v, document.vuser_id.v, document.vdate.v, qs(document.vfile_name), qs(document.vmime_type), App::image(document.vthumb), document.vdc_id.v, document.vsize.v); + } + + UserData *userLoaded(const PeerId &user) { + PeerData *peer = peerLoaded(user); + return (peer && peer->loaded) ? peer->asUser() : 0; + } + + ChatData *chatLoaded(const PeerId &chat) { + PeerData *peer = peerLoaded(chat); + return (peer && peer->loaded) ? peer->asChat() : 0; + } + + PeerData *peerLoaded(const PeerId &peer) { + PeersData::const_iterator i = peersData.constFind(peer); + return (i != peersData.cend()) ? i.value() : 0; + } + + UserData *userLoaded(int32 user) { + return userLoaded(App::peerFromUser(user)); + } + + ChatData *chatLoaded(int32 chat) { + return chatLoaded(App::peerFromChat(chat)); + } + + UserData *curUser() { + return user(MTP::authedId()); + } + + PeerData *peer(const PeerId &peer) { + PeersData::const_iterator i = peersData.constFind(peer); + if (i == peersData.cend()) { + PeerData *newData = App::isChat(peer) ? (PeerData*)(new ChatData(peer)) : (PeerData*)(new UserData(peer)); + newData->input = MTPinputPeer(MTP_inputPeerEmpty()); + i = peersData.insert(peer, newData); + } + return i.value(); + } + + UserData *user(const PeerId &peer) { + PeerData *d = App::peer(peer); + return d->asUser(); + } + + UserData *user(int32 user) { + return App::peer(App::peerFromUser(user))->asUser(); + } + + UserData *self() { + return ::self; + } + + ChatData *chat(const PeerId &peer) { + PeerData *d = App::peer(peer); + return d->asChat(); + } + + ChatData *chat(int32 chat) { + return App::peer(App::peerFromChat(chat))->asChat(); + } + + PhotoData *photo(const PhotoId &photo, PhotoData *convert, const uint64 &access, int32 user, int32 date, const ImagePtr &thumb, const ImagePtr &full) { + if (convert) { + if (convert->id != photo) { + PhotosData::iterator i = photosData.find(convert->id); + if (i != photosData.cend() && i.value() == convert) { + photosData.erase(i); + } + convert->id = photo; + } + convert->access = access; + if (!convert->user && !convert->date && (user || date)) { + convert->user = user; + convert->date = date; + convert->thumb = thumb; + convert->full = full; + } + } + PhotosData::const_iterator i = photosData.constFind(photo); + PhotoData *result; + LastPhotosMap::iterator inLastIter = lastPhotosMap.end(); + if (i == photosData.cend()) { + if (convert) { + result = convert; + } else { + result = new PhotoData(photo, access, user, date, thumb, full); + } + photosData.insert(photo, result); + } else { + result = i.value(); + if (result != convert && !result->user && !result->date && (user || date)) { + result->access = access; + result->user = user; + result->date = date; + result->thumb = thumb; + result->full = full; + } + inLastIter = lastPhotosMap.find(result); + } + if (inLastIter == lastPhotosMap.end()) { // insert new one + if (lastPhotos.size() == MaxPhotosInMemory) { + lastPhotos.front()->forget(); + lastPhotosMap.remove(lastPhotos.front()); + lastPhotos.pop_front(); + } + lastPhotosMap.insert(result, lastPhotos.insert(lastPhotos.end(), result)); + } else { + lastPhotos.erase(inLastIter.value()); // move to back + (*inLastIter) = lastPhotos.insert(lastPhotos.end(), result); + } + return result; + } + + void forgetPhotos() { + lastPhotos.clear(); + lastPhotosMap.clear(); + for (PhotosData::const_iterator i = photosData.cbegin(), e = photosData.cend(); i != e; ++i) { + i.value()->forget(); + } + } + + VideoData *video(const VideoId &video, VideoData *convert, const uint64 &access, int32 user, int32 date, int32 duration, int32 w, int32 h, const ImagePtr &thumb, int32 dc, int32 size) { + if (convert) { + if (convert->id != video) { + VideosData::iterator i = videosData.find(convert->id); + if (i != videosData.cend() && i.value() == convert) { + videosData.erase(i); + } + convert->id = video; + convert->status = FileReady; + } + convert->access = access; + if (!convert->user && !convert->date && (user || date)) { + convert->user = user; + convert->date = date; + convert->duration = duration; + convert->w = w; + convert->h = h; + convert->thumb = thumb; + convert->dc = dc; + convert->size = size; + } + } + VideosData::const_iterator i = videosData.constFind(video); + VideoData *result; + if (i == videosData.cend()) { + if (convert) { + result = convert; + } else { + result = new VideoData(video, access, user, date, duration, w, h, thumb, dc, size); + } + videosData.insert(video, result); + } else { + result = i.value(); + if (result != convert && !result->user && !result->date && (user || date)) { + result->access = access; + result->user = user; + result->date = date; + result->duration = duration; + result->w = w; + result->h = h; + result->thumb = thumb; + result->dc = dc; + result->size = size; + } + } + return result; + } + + void forgetVideos() { + for (VideosData::const_iterator i = videosData.cbegin(), e = videosData.cend(); i != e; ++i) { + i.value()->forget(); + } + } + + AudioData *audio(const AudioId &audio, AudioData *convert, const uint64 &access, int32 user, int32 date, int32 duration, int32 dc, int32 size) { + if (convert) { + if (convert->id != audio) { + AudiosData::iterator i = audiosData.find(convert->id); + if (i != audiosData.cend() && i.value() == convert) { + audiosData.erase(i); + } + convert->id = audio; + convert->status = FileReady; + } + convert->access = access; + if (!convert->user && !convert->date && (user || date)) { + convert->user = user; + convert->date = date; + convert->duration = duration; + convert->dc = dc; + convert->size = size; + } + } + AudiosData::const_iterator i = audiosData.constFind(audio); + AudioData *result; + if (i == audiosData.cend()) { + if (convert) { + result = convert; + } else { + result = new AudioData(audio, access, user, date, duration, dc, size); + } + audiosData.insert(audio, result); + } else { + result = i.value(); + if (result != convert && !result->user && !result->date && (user || date)) { + result->access = access; + result->user = user; + result->date = date; + result->duration = duration; + result->dc = dc; + result->size = size; + } + } + return result; + } + + void forgetAudios() { + for (AudiosData::const_iterator i = audiosData.cbegin(), e = audiosData.cend(); i != e; ++i) { + i.value()->forget(); + } + } + + DocumentData *document(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 user, int32 date, const QString &name, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) { + if (convert) { + if (convert->id != document) { + DocumentsData::iterator i = documentsData.find(convert->id); + if (i != documentsData.cend() && i.value() == convert) { + documentsData.erase(i); + } + convert->id = document; + convert->status = FileReady; + } + convert->access = access; + if (!convert->user && !convert->date && (user || date)) { + convert->user = user; + convert->date = date; + convert->name = name; + convert->mime = mime; + convert->thumb = thumb; + convert->dc = dc; + convert->size = size; + } + } + DocumentsData::const_iterator i = documentsData.constFind(document); + DocumentData *result; + if (i == documentsData.cend()) { + if (convert) { + result = convert; + } else { + result = new DocumentData(document, access, user, date, name, mime, thumb, dc, size); + } + documentsData.insert(document, result); + } else { + result = i.value(); + if (result != convert && !result->user && !result->date && (user || date)) { + result->access = access; + result->user = user; + result->date = date; + result->name = name; + result->mime = mime; + result->thumb = thumb; + result->dc = dc; + result->size = size; + } + } + return result; + } + + void forgetDocuments() { + for (DocumentsData::const_iterator i = documentsData.cbegin(), e = documentsData.cend(); i != e; ++i) { + i.value()->forget(); + } + } + + MTPPhoto photoFromUserPhoto(MTPint userId, MTPint date, const MTPUserProfilePhoto &photo) { + if (photo.type() == mtpc_userProfilePhoto) { + const MTPDuserProfilePhoto &uphoto(photo.c_userProfilePhoto()); + + QVector photoSizes; + photoSizes.push_back(MTP_photoSize(MTP_string("a"), uphoto.vphoto_small, MTP_int(160), MTP_int(160), MTP_int(0))); + photoSizes.push_back(MTP_photoSize(MTP_string("c"), uphoto.vphoto_big, MTP_int(640), MTP_int(640), MTP_int(0))); + + return MTP_photo(uphoto.vphoto_id, MTP_long(0), userId, date, MTP_string(""), MTP_geoPointEmpty(), MTP_vector(photoSizes)); + } + return MTP_photoEmpty(MTP_long(0)); + } + + QString peerName(const PeerData *peer, bool forDialogs) { + return peer ? (forDialogs ? peer->nameOrPhone : peer->name) : lang(lng_deleted); + } + + Histories &histories() { + return ::histories; + } + + History *history(const PeerId &peer, int32 unreadCnt) { + Histories::const_iterator i = ::histories.constFind(peer); + if (i == ::histories.cend()) { + i = App::histories().insert(peer, new History(peer)); + i.value()->setUnreadCount(unreadCnt, false); + } + return i.value(); + } + + History *historyLoaded(const PeerId &peer) { + Histories::const_iterator i = ::histories.constFind(peer); + return (i == ::histories.cend()) ? 0 : i.value(); + } + + HistoryItem *histItemById(MsgId itemId) { + MsgsData::const_iterator i = msgsData.constFind(itemId); + if (i != msgsData.cend()) { + return i.value(); + } + return 0; + } + + bool historyRegItem(HistoryItem *item) { + MsgsData::const_iterator i = msgsData.constFind(item->id); + if (i == msgsData.cend()) { + msgsData.insert(item->id, item); + if (item->id > ::maxMsgId) ::maxMsgId = item->id; + return true; + } + return (i.value() == item); + } + + void historyUnregItem(HistoryItem *item) { + MsgsData::iterator i = msgsData.find(item->id); + if (i != msgsData.cend()) { + if (i.value() == item) { + msgsData.erase(i); + } + } + if (::hoveredItem == item) { + hoveredItem(0); + } + if (::pressedItem == item) { + pressedItem(0); + } + if (::hoveredLinkItem == item) { + hoveredLinkItem(0); + } + if (::pressedLinkItem == item) { + pressedLinkItem(0); + } + if (::contextItem == item) { + contextItem(0); + } + if (::mousedItem == item) { + mousedItem(0); + } + if (App::main()) { + emit App::main()->historyItemDeleted(item); + } + } + + void historyClearMsgs() { + msgsData.clear(); + ::maxMsgId = 0; + ::hoveredItem = ::pressedItem = ::hoveredLinkItem = ::pressedLinkItem = ::contextItem = 0; + } + + void historyClearItems() { + historyClearMsgs(); + randomData.clear(); + for (PeersData::const_iterator i = peersData.cbegin(), e = peersData.cend(); i != e; ++i) { + delete *i; + } + peersData.clear(); + for (PhotosData::const_iterator i = photosData.cbegin(), e = photosData.cend(); i != e; ++i) { + delete *i; + } + photosData.clear(); + for (VideosData::const_iterator i = videosData.cbegin(), e = videosData.cend(); i != e; ++i) { + delete *i; + } + videosData.clear(); + for (AudiosData::const_iterator i = audiosData.cbegin(), e = audiosData.cend(); i != e; ++i) { + delete *i; + } + audiosData.clear(); + for (DocumentsData::const_iterator i = documentsData.cbegin(), e = documentsData.cend(); i != e; ++i) { + delete *i; + } + documentsData.clear(); + ::videoItems.clear(); + ::audioItems.clear(); + ::documentItems.clear(); + lastPhotos.clear(); + lastPhotosMap.clear(); + ::self = 0; + } +/* // don't delete history without deleting its' peerdata + void deleteHistory(const PeerId &peer) { + Histories::iterator i = ::histories.find(peer); + if (i != ::histories.end()) { + ::histories.typing.remove(i.value()); + ::histories.erase(i); + } + } +/**/ + void historyRegRandom(uint64 randomId, MsgId itemId) { + randomData.insert(randomId, itemId); + } + + void historyUnregRandom(uint64 randomId) { + randomData.remove(randomId); + } + + MsgId histItemByRandom(uint64 randomId) { + RandomData::const_iterator i = randomData.constFind(randomId); + if (i != randomData.cend()) { + return i.value(); + } + return 0; + } + + void initMedia() { + deinitMedia(false); + if (!newMsgSound) { + newMsgSound = new QSoundEffect(); + newMsgSound->setSource(QUrl::fromLocalFile(st::newMsgSound)); + newMsgSound->setVolume(1); + } + + if (!::sprite) { + ::sprite = new QPixmap(st::spriteFile); + } + if (!::emojis) { + ::emojis = new QPixmap(st::emojisFile); + } + initEmoji(); + } + + void deinitMedia(bool completely) { + textlnkOver(TextLinkPtr()); + textlnkDown(TextLinkPtr()); + + if (completely) { + delete newMsgSound; + newMsgSound = 0; + + delete ::sprite; + ::sprite = 0; + delete ::emojis; + ::emojis = 0; + mainEmojisMap.clear(); + otherEmojisMap.clear(); + + clearAllImages(); + } else { + clearStorageImages(); + } + + if (App::main()) { + App::main()->disconnect(SIGNAL(historyItemDeleted(HistoryItem*))); + } + + histories().clear(); + + serviceImageCacheSize = imageCacheSize(); + } + + void hoveredItem(HistoryItem *item) { + ::hoveredItem = item; + } + + HistoryItem *hoveredItem() { + return ::hoveredItem; + } + + void pressedItem(HistoryItem *item) { + ::pressedItem = item; + } + + HistoryItem *pressedItem() { + return ::pressedItem; + } + + void hoveredLinkItem(HistoryItem *item) { + ::hoveredLinkItem = item; + } + + HistoryItem *hoveredLinkItem() { + return ::hoveredLinkItem; + } + + void pressedLinkItem(HistoryItem *item) { + ::pressedLinkItem = item; + } + + HistoryItem *pressedLinkItem() { + return ::pressedLinkItem; + } + + void contextItem(HistoryItem *item) { + ::contextItem = item; + } + + HistoryItem *contextItem() { + return ::contextItem; + } + + void mousedItem(HistoryItem *item) { + ::mousedItem = item; + } + + HistoryItem *mousedItem() { + return ::mousedItem; + } + + QPixmap &sprite() { + return *::sprite; + } + + QPixmap &emojis() { + return *::emojis; + } + + const QPixmap &emojiSingle(const EmojiData *emoji, int32 fontHeight) { + EmojisMap *map = &(fontHeight == st::taDefFlat.font->height ? mainEmojisMap : otherEmojisMap[fontHeight]); + EmojisMap::const_iterator i = map->constFind(emoji->code); + if (i == map->cend()) { + QImage img(st::emojiSize + st::emojiPadding * 2, fontHeight, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&img); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(0, 0, img.width(), img.height(), Qt::transparent); + p.drawPixmap(QPoint(st::emojiPadding, (fontHeight - st::emojiSize) / 2), App::emojis(), QRect(emoji->x, emoji->y, st::emojiSize, st::emojiSize)); + } + i = map->insert(emoji->code, QPixmap::fromImage(img)); + } + return i.value(); + } + + void playSound() { + if (cSoundNotify() && newMsgSound) newMsgSound->play(); + } + + void writeConfig() { + QDir().mkdir(cWorkingDir() + qsl("tdata")); + QFile configFile(cWorkingDir() + qsl("tdata/config")); + if (configFile.open(QIODevice::WriteOnly)) { + DEBUG_LOG(("App Info: writing config file")); + QDataStream configStream(&configFile); + configStream.setVersion(QDataStream::Qt_5_1); + configStream << quint32(dbiVersion) << qint32(AppVersion); + + configStream << quint32(dbiAutoStart) << qint32(cAutoStart()); + configStream << quint32(dbiStartMinimized) << qint32(cStartMinimized()); + configStream << quint32(dbiWorkMode) << qint32(cWorkMode()); + configStream << quint32(dbiSeenTrayTooltip) << qint32(cSeenTrayTooltip()); + configStream << quint32(dbiAutoUpdate) << qint32(cAutoUpdate()); + configStream << quint32(dbiLastUpdateCheck) << qint32(cLastUpdateCheck()); + configStream << quint32(dbiScale) << qint32(cConfigScale()); + + configStream << quint32(dbiConnectionType) << qint32(cConnectionType()); + if (cConnectionType() == dbictHttpProxy || cConnectionType() == dbictTcpProxy) { + const ConnectionProxy &proxy(cConnectionProxy()); + configStream << proxy.host << qint32(proxy.port) << proxy.user << proxy.password; + } + + TWindowPos pos(cWindowPos()); + configStream << quint32(dbiWindowPosition) << qint32(pos.x) << qint32(pos.y) << qint32(pos.w) << qint32(pos.h) << qint32(pos.moncrc) << qint32(pos.maximized); + + if (configStream.status() != QDataStream::Ok) { + LOG(("App Error: could not write user config file, status: %1").arg(configStream.status())); + } + } else { + LOG(("App Error: could not open user config file for writing")); + } + } + + void readConfig() { + QFile configFile(cWorkingDir() + qsl("tdata/config")); + if (configFile.open(QIODevice::ReadOnly)) { + DEBUG_LOG(("App Info: config file opened for reading")); + QDataStream configStream(&configFile); + configStream.setVersion(QDataStream::Qt_5_1); + + qint32 configVersion = 0; + while (true) { + quint32 blockId; + configStream >> blockId; + if (configStream.status() == QDataStream::ReadPastEnd) { + DEBUG_LOG(("App Info: config file read end")); + break; + } else if (configStream.status() != QDataStream::Ok) { + LOG(("App Error: could not read block id, status: %1 - config file is corrupted?..").arg(configStream.status())); + break; + } + + if (blockId == dbiVersion) { + configStream >> configVersion; + if (configVersion > AppVersion) break; + continue; + } + + switch (blockId) { + case dbiAutoStart: { + qint32 v; + configStream >> v; + cSetAutoStart(v == 1); + } break; + + case dbiStartMinimized: { + qint32 v; + configStream >> v; + cSetStartMinimized(v == 1); + } break; + + case dbiSoundNotify: { + if (configVersion < 3008) { + qint32 v; + configStream >> v; + cSetSoundNotify(v == 1); + cSetNeedConfigResave(true); + } + } break; + + case dbiDesktopNotify: { + if (configVersion < 3008) { + qint32 v; + configStream >> v; + cSetDesktopNotify(v == 1); + cSetNeedConfigResave(true); + } + } break; + + case dbiWorkMode: { + qint32 v; + configStream >> v; + switch (v) { + case dbiwmTrayOnly: cSetWorkMode(dbiwmTrayOnly); break; + case dbiwmWindowOnly: cSetWorkMode(dbiwmWindowOnly); break; + default: cSetWorkMode(dbiwmWindowAndTray); break; + }; + } break; + + case dbiConnectionType: { + qint32 v; + configStream >> v; + + switch (v) { + case dbictHttpProxy: + case dbictTcpProxy: { + ConnectionProxy p; + qint32 port; + configStream >> p.host >> port >> p.user >> p.password; + p.port = uint32(port); + cSetConnectionProxy(p); + } + cSetConnectionType(DBIConnectionType(v)); + break; + case dbictHttpAuto: + default: cSetConnectionType(dbictAuto); break; + }; + } break; + + case dbiSeenTrayTooltip: { + qint32 v; + configStream >> v; + cSetSeenTrayTooltip(v == 1); + } break; + + case dbiAutoUpdate: { + qint32 v; + configStream >> v; + cSetAutoUpdate(v == 1); + } break; + + case dbiLastUpdateCheck: { + qint32 v; + configStream >> v; + cSetLastUpdateCheck(v); + } break; + + case dbiScale: { + qint32 v; + configStream >> v; + + DBIScale s = cRealScale(); + switch (v) { + case dbisAuto: s = dbisAuto; break; + case dbisOne: s = dbisOne; break; + case dbisOneAndQuarter: s = dbisOneAndQuarter; break; + case dbisOneAndHalf: s = dbisOneAndHalf; break; + case dbisTwo: s = dbisTwo; break; + } + cSetConfigScale(s); + cSetRealScale(s); + } break; + + case dbiWindowPosition: { + TWindowPos pos; + configStream >> pos.x >> pos.y >> pos.w >> pos.h >> pos.moncrc >> pos.maximized; + cSetWindowPos(pos); + } break; + } + + if (configStream.status() != QDataStream::Ok) { + LOG(("App Error: could not read data, status: %1 - user config file is corrupted?..").arg(configStream.status())); + break; + } + } + } + } + + void writeUserConfig() { + QFile configFile(cWorkingDir() + cDataFile() + qsl("_config")); + if (configFile.open(QIODevice::WriteOnly)) { + DEBUG_LOG(("App Info: writing user config data for encrypt")); + QByteArray toEncrypt; + toEncrypt.reserve(65536); + toEncrypt.resize(4); + { + QBuffer buffer(&toEncrypt); + buffer.open(QIODevice::Append); + + QDataStream stream(&buffer); + stream.setVersion(QDataStream::Qt_5_1); + + if (MTP::authedId()) { + stream << quint32(dbiUser) << qint32(MTP::authedId()) << quint32(MTP::maindc()); + } + + stream << quint32(dbiSendKey) << qint32(cCtrlEnter() ? dbiskCtrlEnter : dbiskEnter); + stream << quint32(dbiCatsAndDogs) << qint32(cCatsAndDogs() ? 1 : 0); + stream << quint32(dbiReplaceEmojis) << qint32(cReplaceEmojis() ? 1 : 0); + stream << quint32(dbiDefaultAttach) << qint32(cDefaultAttach()); + stream << quint32(dbiSoundNotify) << qint32(cSoundNotify()); + stream << quint32(dbiDesktopNotify) << qint32(cDesktopNotify()); + stream << quint32(dbiAskDownloadPath) << qint32(cAskDownloadPath()); + stream << quint32(dbiDownloadPath) << (cAskDownloadPath() ? QString() : cDownloadPath()); + stream << quint32(dbiEmojiTab) << qint32(cEmojiTab()); + + RecentEmojiPreload v; + v.reserve(cGetRecentEmojis().size()); + for (RecentEmojiPack::const_iterator i = cGetRecentEmojis().cbegin(), e = cGetRecentEmojis().cend(); i != e; ++i) { + v.push_back(qMakePair(i->first->code, i->second)); + } + stream << quint32(dbiRecentEmojis) << v; + + writeAllMuted(stream); + + MTP::writeConfig(stream); + if (stream.status() != QDataStream::Ok) { + LOG(("App Error: could not write user config to memory buf, status: %1").arg(stream.status())); + return; + } + } + *(uint32*)(toEncrypt.data()) = toEncrypt.size(); + + uint32 size = toEncrypt.size(), fullSize = size; + if (fullSize & 0x0F) { + fullSize += 0x10 - (fullSize & 0x0F); + toEncrypt.resize(fullSize); + memset_rand(toEncrypt.data() + size, fullSize - size); + } + QByteArray encrypted(16 + fullSize, Qt::Uninitialized); // 128bit of sha1 - key128, sizeof(data), data + hashSha1(toEncrypt.constData(), toEncrypt.size(), encrypted.data()); + aesEncryptLocal(toEncrypt.constData(), encrypted.data() + 16, fullSize, &MTP::localKey(), encrypted.constData()); + + DEBUG_LOG(("App Info: writing user config file")); + QDataStream configStream(&configFile); + configStream.setVersion(QDataStream::Qt_5_1); + configStream << quint32(dbiVersion) << qint32(AppVersion); + + configStream << quint32(dbiEncryptedWithSalt) << cLocalSalt() << encrypted; // write all encrypted data + + if (configStream.status() != QDataStream::Ok) { + LOG(("App Error: could not write user config file, status: %1").arg(configStream.status())); + } + } else { + LOG(("App Error: could not open user config file for writing")); + } + } + + void readUserConfigFields(QIODevice *io) { + if (!io->isOpen()) io->open(QIODevice::ReadOnly); + + QDataStream stream(io); + stream.setVersion(QDataStream::Qt_5_1); + + while (true) { + quint32 blockId; + stream >> blockId; + if (stream.status() == QDataStream::ReadPastEnd) { + DEBUG_LOG(("App Info: config file read end")); + break; + } else if (stream.status() != QDataStream::Ok) { + LOG(("App Error: could not read block id, status: %1 - user config file is corrupted?..").arg(stream.status())); + break; + } + + if (blockId == dbiVersion) { // should not be in encrypted part, just ignore + qint32 configVersion; + stream >> configVersion; + continue; + } + + switch (blockId) { + case dbiEncryptedWithSalt: { + QByteArray salt, data, decrypted; + stream >> salt >> data; + + if (salt.size() != 32) { + LOG(("App Error: bad salt in encrypted part, size: %1").arg(salt.size())); + continue; + } + + cSetLocalSalt(salt); + MTP::createLocalKey(QByteArray(), &salt); + + if (data.size() <= 16 || (data.size() & 0x0F)) { + LOG(("App Error: bad encrypted part size: %1").arg(data.size())); + continue; + } + uint32 fullDataLen = data.size() - 16; + decrypted.resize(fullDataLen); + const char *dataKey = data.constData(), *encrypted = data.constData() + 16; + aesDecryptLocal(encrypted, decrypted.data(), fullDataLen, &MTP::localKey(), dataKey); + uchar sha1Buffer[20]; + if (memcmp(hashSha1(decrypted.constData(), decrypted.size(), sha1Buffer), dataKey, 16)) { + LOG(("App Error: bad decrypt key, data from user-config not decrypted")); + continue; + } + uint32 dataLen = *(const uint32*)decrypted.constData(); + if (dataLen > decrypted.size() || dataLen <= fullDataLen - 16 || dataLen < 4) { + LOG(("App Error: bad decrypted part size: %1, fullDataLen: %2, decrypted size: %3").arg(dataLen).arg(fullDataLen).arg(decrypted.size())); + continue; + } + decrypted.resize(dataLen); + QBuffer decryptedStream(&decrypted); + decryptedStream.open(QIODevice::ReadOnly); + decryptedStream.seek(4); // skip size + readUserConfigFields(&decryptedStream); + } break; + + case dbiLoggedPhoneNumber: { + QString v; + stream >> v; + if (stream.status() == QDataStream::Ok) { + cSetLoggedPhoneNumber(v); + } + } break; + + case dbiMutePeer: { + readOneMuted(stream); + } break; + + case dbiMutedPeers: { + readAllMuted(stream); + } break; + + case dbiSendKey: { + qint32 v; + stream >> v; + cSetCtrlEnter(v == dbiskCtrlEnter); + } break; + + case dbiCatsAndDogs: { + qint32 v; + stream >> v; + cSetCatsAndDogs(v == 1); + } break; + + case dbiReplaceEmojis: { + qint32 v; + stream >> v; + cSetReplaceEmojis(v == 1); + } break; + + case dbiDefaultAttach: { + qint32 v; + stream >> v; + switch (v) { + case dbidaPhoto: cSetDefaultAttach(dbidaPhoto); break; + default: cSetDefaultAttach(dbidaDocument); break; + } + } break; + + case dbiSoundNotify: { + qint32 v; + stream >> v; + cSetSoundNotify(v == 1); + } break; + + case dbiDesktopNotify: { + qint32 v; + stream >> v; + cSetDesktopNotify(v == 1); + } break; + + case dbiAskDownloadPath: { + qint32 v; + stream >> v; + cSetAskDownloadPath(v == 1); + } break; + + case dbiDownloadPath: { + QString v; + stream >> v; + cSetDownloadPath(v); + } break; + + case dbiEmojiTab: { + qint32 v; + stream >> v; + switch (v) { + case dbietRecent : cSetEmojiTab(dbietRecent); break; + case dbietPeople : cSetEmojiTab(dbietPeople); break; + case dbietNature : cSetEmojiTab(dbietNature); break; + case dbietObjects: cSetEmojiTab(dbietObjects); break; + case dbietPlaces : cSetEmojiTab(dbietPlaces); break; + case dbietSymbols: cSetEmojiTab(dbietSymbols); break; + } + } break; + + case dbiRecentEmojis: { + RecentEmojiPreload v; + stream >> v; + cSetRecentEmojisPreload(v); + } break; + + default: + if (!MTP::readConfigElem(blockId, stream)) { + } + break; + } + + if (stream.status() != QDataStream::Ok) { + LOG(("App Error: could not read data, status: %1 - user config file is corrupted?..").arg(stream.status())); + break; + } + } + } + + void readUserConfig() { + QFile configFile(cWorkingDir() + cDataFile() + qsl("_config")); + if (configFile.open(QIODevice::ReadOnly)) { + DEBUG_LOG(("App Info: user config file opened for reading")); + { + QDataStream configStream(&configFile); + configStream.setVersion(QDataStream::Qt_5_1); + + quint32 blockId; + configStream >> blockId; + if (configStream.status() == QDataStream::ReadPastEnd) { + DEBUG_LOG(("App Info: config file read end")); + return; + } else if (configStream.status() != QDataStream::Ok) { + LOG(("App Error: could not read block id, status: %1 - user config file is corrupted?..").arg(configStream.status())); + return; + } + + if (blockId == dbiVersion) { + qint32 configVersion; + configStream >> configVersion; + if (configVersion > AppVersion) return; + + configStream >> blockId; + if (configStream.status() == QDataStream::ReadPastEnd) { + DEBUG_LOG(("App Info: config file read end")); + return; + } else if (configStream.status() != QDataStream::Ok) { + LOG(("App Error: could not read block id, status: %1 - user config file is corrupted?..").arg(configStream.status())); + return; + } + if (blockId != dbiEncryptedWithSalt) { // old version data - not encrypted + cSetNeedConfigResave(true); + } + } else { + cSetNeedConfigResave(true); + } + } + + configFile.reset(); + readUserConfigFields(&configFile); + } + } + + void writeAllMuted(QDataStream &stream) { // deprecated + } + + void readOneMuted(QDataStream &stream) { // deprecated + quint64 peerId; + stream >> peerId; + } + + void readAllMuted(QDataStream &stream) { + quint32 count; + stream >> count; + + for (int32 i = 0; i < count; ++i) { + readOneMuted(stream); + } + } + + void checkImageCacheSize() { + int64 nowImageCacheSize = imageCacheSize(); + if (nowImageCacheSize > serviceImageCacheSize + MemoryForImageCache) { + App::forgetPhotos(); + App::forgetVideos(); + App::forgetAudios(); + App::forgetDocuments(); + serviceImageCacheSize = imageCacheSize(); + } + } + + bool isValidPhone(QString phone) { + phone = phone.replace(QRegularExpression(qsl("[^\\d]")), QString()); + return phone.length() >= 8 || phone == qsl("777") || phone == qsl("333") || phone == qsl("42") || phone == qsl("111"); + } + + void quit() { + if (quiting()) return; + + setQuiting(); + if (wnd()) { + wnd()->psClearNotifyFast(); + } + if (app()) { + app()->quit(); + } + } + + bool quiting() { + return ::quiting; + } + + void setQuiting() { + ::quiting = true; + } + + + QImage readImage(QByteArray data, QByteArray *format) { + QByteArray tmpFormat; + QImage result; + QBuffer buffer(&data); + if (!format) { + format = &tmpFormat; + } + QImageReader reader(&buffer, *format); + if (!reader.read(&result)) { + return QImage(); + } + + buffer.seek(0); + *format = reader.format(); + QString fmt = QString::fromUtf8(*format).toLower() ; + if (fmt == "jpg" || fmt == "jpeg") { + ExifData *exifData = exif_data_new_from_data((const uchar*)(data.constData()), data.size()); + if (exifData) { + ExifByteOrder byteOrder = exif_data_get_byte_order(exifData); + ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION); + if (exifEntry) { + QTransform orientationFix; + int orientation = exif_get_short(exifEntry->data, byteOrder); + switch (orientation) { + case 2: orientationFix = QTransform(-1, 0, 0, 1, 0, 0); break; + case 3: orientationFix = QTransform(-1, 0, 0, -1, 0, 0); break; + case 4: orientationFix = QTransform(1, 0, 0, -1, 0, 0); break; + case 5: orientationFix = QTransform(0, -1, -1, 0, 0, 0); break; + case 6: orientationFix = QTransform(0, 1, -1, 0, 0, 0); break; + case 7: orientationFix = QTransform(0, 1, 1, 0, 0, 0); break; + case 8: orientationFix = QTransform(0, -1, 1, 0, 0, 0); break; + } + result = result.transformed(orientationFix); + } + exif_data_free(exifData); + } + } else { + QImage solid(result.width(), result.height(), QImage::Format_ARGB32_Premultiplied); + solid.fill(st::white->c); + { + QPainter(&solid).drawImage(0, 0, result); + } + result = solid; + } + return result; + } + + QImage readImage(const QString &file, QByteArray *format) { + QFile f(file); + if (!f.open(QIODevice::ReadOnly)) { + return QImage(); + } + return readImage(f.readAll(), format); + } + + void regVideoItem(VideoData *data, HistoryItem *item) { + ::videoItems[data][item] = true; + } + + void unregVideoItem(VideoData *data, HistoryItem *item) { + ::videoItems[data].remove(item); + } + + const VideoItems &videoItems() { + return ::videoItems; + } + + void regAudioItem(AudioData *data, HistoryItem *item) { + ::audioItems[data][item] = true; + } + + void unregAudioItem(AudioData*data, HistoryItem *item) { + ::audioItems[data].remove(item); + } + + const AudioItems &audioItems() { + return ::audioItems; + } + + void regDocumentItem(DocumentData *data, HistoryItem *item) { + ::documentItems[data][item] = true; + } + + void unregDocumentItem(DocumentData *data, HistoryItem *item) { + ::documentItems[data].remove(item); + } + + const DocumentItems &documentItems() { + return ::documentItems; + } + + void setProxySettings(QNetworkAccessManager &manager) { + if (cConnectionType() == dbictHttpProxy) { + const ConnectionProxy &p(cConnectionProxy()); + manager.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, p.host, p.port, p.user, p.password)); + } else { + manager.setProxy(QNetworkProxy(QNetworkProxy::DefaultProxy)); + } + } + + void setProxySettings(QTcpSocket &socket) { + if (cConnectionType() == dbictTcpProxy) { + const ConnectionProxy &p(cConnectionProxy()); + socket.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, p.host, p.port, p.user, p.password)); + } else { + socket.setProxy(QNetworkProxy(QNetworkProxy::NoProxy)); + } + } + +} diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h new file mode 100644 index 000000000..ee74e191e --- /dev/null +++ b/Telegram/SourceFiles/app.h @@ -0,0 +1,187 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "types.h" + +class Application; +class Window; +class MainWidget; +class Settings; +class Font; +class Color; +class FileUploader; + +#include "history.h" + +typedef QMap HistoryItemsMap; +typedef QHash VideoItems; +typedef QHash AudioItems; +typedef QHash DocumentItems; + +namespace App { + Application *app(); + Window *wnd(); + MainWidget *main(); + Settings *settings(); + FileUploader *uploader(); + + void showSettings(); + void logOut(); + bool loggedOut(); + + QString formatPhone(QString phone); + + inline bool isChat(const PeerId &peer) { + return peer & 0x100000000L; + } + PeerId peerFromMTP(const MTPPeer &peer_id); + PeerId peerFromChat(int32 chat_id); + inline PeerId peerFromChat(const MTPint &chat_id) { + return peerFromChat(chat_id.v); + } + PeerId peerFromUser(int32 user_id); + inline PeerId peerFromUser(const MTPint &user_id) { + return peerFromUser(user_id.v); + } + MTPpeer peerToMTP(const PeerId &peer_id); + + int32 onlineWillChangeIn(int32 onlineOnServer, int32 nowOnServer); + QString onlineText(int32 onlineOnServer, int32 nowOnServer); + + void feedUsers(const MTPVector &users); + void feedChats(const MTPVector &chats); + void feedParticipants(const MTPChatParticipants &p); + void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d); + void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d); + void feedMsgs(const MTPVector &msgs, bool newMsgs = false); + void feedWereRead(const QVector &msgsIds); + void feedWereDeleted(const QVector &msgsIds); + void feedUserLinks(const MTPVector &links); + void feedUserLink(MTPint userId, const MTPcontacts_MyLink &myLink, const MTPcontacts_ForeignLink &foreignLink); + void feedMessageMedia(MsgId msgId, const MTPMessage &msg); + int32 maxMsgId(); + + PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs); + PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = 0); + PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = 0); + VideoData *feedVideo(const MTPDvideo &video, VideoData *convert = 0); + AudioData *feedAudio(const MTPDaudio &audio, AudioData *convert = 0); + DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb); + DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = 0); + DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert = 0); + + UserData *userLoaded(const PeerId &user); + ChatData *chatLoaded(const PeerId &chat); + PeerData *peerLoaded(const PeerId &peer); + UserData *userLoaded(int32 user); + ChatData *chatLoaded(int32 chat); + + PeerData *peer(const PeerId &peer); + UserData *user(const PeerId &peer); + UserData *user(int32 user); + UserData *self(); + ChatData *chat(const PeerId &peer); + ChatData *chat(int32 chat); + QString peerName(const PeerData *peer, bool forDialogs = false); + PhotoData *photo(const PhotoId &photo, PhotoData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, const ImagePtr &thumb = ImagePtr(), const ImagePtr &full = ImagePtr()); + void forgetPhotos(); + VideoData *video(const VideoId &video, VideoData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 w = 0, int32 h = 0, const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0); + void forgetVideos(); + AudioData *audio(const AudioId &audio, AudioData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 dc = 0, int32 size = 0); + void forgetAudios(); + DocumentData *document(const DocumentId &document, DocumentData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, const QString &name = QString(), const QString &mime = QString(), const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0); + void forgetDocuments(); + + MTPPhoto photoFromUserPhoto(MTPint userId, MTPint date, const MTPUserProfilePhoto &photo); + + Histories &histories(); + History *history(const PeerId &peer, int32 unreadCnt = 0); + History *historyLoaded(const PeerId &peer); + HistoryItem *histItemById(MsgId itemId); + bool historyRegItem(HistoryItem *item); + void historyUnregItem(HistoryItem *item); + void historyClearMsgs(); + void historyClearItems(); +// void deleteHistory(const PeerId &peer); + + void historyRegRandom(uint64 randomId, MsgId itemId); + void historyUnregRandom(uint64 randomId); + MsgId histItemByRandom(uint64 randomId); + + void hoveredItem(HistoryItem *item); + HistoryItem *hoveredItem(); + void pressedItem(HistoryItem *item); + HistoryItem *pressedItem(); + void hoveredLinkItem(HistoryItem *item); + HistoryItem *hoveredLinkItem(); + void pressedLinkItem(HistoryItem *item); + HistoryItem *pressedLinkItem(); + void contextItem(HistoryItem *item); + HistoryItem *contextItem(); + void mousedItem(HistoryItem *item); + HistoryItem *mousedItem(); + + QPixmap &sprite(); + QPixmap &emojis(); + const QPixmap &emojiSingle(const EmojiData *emoji, int32 fontHeight); + + void initMedia(); + void deinitMedia(bool completely = true); + void playSound(); + + void writeConfig(); + void readConfig(); + void writeUserConfig(); + void readUserConfig(); + + void muteHistory(History *history); + void unmuteHistory(History *history); + void writeAllMuted(QDataStream &stream); + void readAllMuted(QDataStream &stream); + void readOneMuted(QDataStream &stream); + bool isPeerMuted(const PeerId &peer); + + void checkImageCacheSize(); + + bool isValidPhone(QString phone); + + void quit(); + bool quiting(); + void setQuiting(); + + + QImage readImage(QByteArray data, QByteArray *format = 0); + QImage readImage(const QString &file, QByteArray *format = 0); + + void regVideoItem(VideoData *data, HistoryItem *item); + void unregVideoItem(VideoData *data, HistoryItem *item); + const VideoItems &videoItems(); + + void regAudioItem(AudioData *data, HistoryItem *item); + void unregAudioItem(AudioData*data, HistoryItem *item); + const AudioItems &audioItems(); + + void regDocumentItem(DocumentData *data, HistoryItem *item); + void unregDocumentItem(DocumentData *data, HistoryItem *item); + const DocumentItems &documentItems(); + + void setProxySettings(QNetworkAccessManager &manager); + void setProxySettings(QTcpSocket &socket); + +}; diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp new file mode 100644 index 000000000..df7b9d773 --- /dev/null +++ b/Telegram/SourceFiles/application.cpp @@ -0,0 +1,644 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "application.h" +#include "style.h" + +#include "pspecific.h" +#include "fileuploader.h" +#include "mainwidget.h" +#include "supporttl.h" + +#include "lang.h" +#include "boxes/confirmbox.h" +#include "langloaderplain.h" + +namespace { + Application *mainApp = 0; + FileUploader *uploader = 0; + QString lng; + + void mtpStateChanged(int32 dc, int32 state) { + if (App::wnd()) { + App::wnd()->mtpStateChanged(dc, state); + } + } + + class _DebugWaiter : public QObject { + public: + + _DebugWaiter(QObject *parent) : QObject(parent), _debugState(0) { + + } + bool eventFilter(QObject *o, QEvent *e) { + if (e->type() == QEvent::KeyPress) { + QKeyEvent *ev = static_cast(e); + switch (_debugState) { + case 0: if (ev->key() == Qt::Key_F12) _debugState = 1; break; + case 1: if (ev->key() == Qt::Key_F11) _debugState = 2; else if (ev->key() != Qt::Key_F12) _debugState = 0; break; + case 2: if (ev->key() == Qt::Key_F10) _debugState = 3; else if (ev->key() != Qt::Key_F11) _debugState = 0; break; + case 3: if (ev->key() == Qt::Key_F11) _debugState = 4; else if (ev->key() != Qt::Key_F10) _debugState = 0; break; + case 4: if (ev->key() == Qt::Key_F12) offerDebug(); if (ev->key() != Qt::Key_F11) _debugState = 0; break; + } + } + return QObject::eventFilter(o, e); + } + void offerDebug() { + ConfirmBox *box = new ConfirmBox(lang(lng_sure_enable_debug)); + connect(box, SIGNAL(confirmed()), App::app(), SLOT(onEnableDebugMode())); + App::wnd()->showLayer(box); + } + + private: + + int _debugState; + }; +} + +Application::Application(int argc, char *argv[]) : PsApplication(argc, argv), + serverName(psServerPrefix() + cGUIDStr()), closing(false), + updateRequestId(0), updateThread(0), updateDownloader(0), updateReply(0) { + if (mainApp) { + DEBUG_LOG(("Application Error: another Application was created, terminating..")); + exit(0); + } + mainApp = this; + + installEventFilter(new _DebugWaiter(this)); + + QFontDatabase::addApplicationFont(qsl(":/gui/art/segoe_ui.ttf")); + QFontDatabase::addApplicationFont(qsl(":/gui/art/segoe_ui_semibold.ttf")); + QFontDatabase::addApplicationFont(qsl(":/gui/art/segoe_wp_semibold.ttf")); + QFontDatabase::addApplicationFont(qsl(":/gui/art/ThoolikaTrditionalUnicode.ttf")); + + float64 dpi = primaryScreen()->logicalDotsPerInch(); + if (dpi <= 108) { // 0-96-108 + cSetScreenScale(dbisOne); + } else if (dpi <= 132) { // 108-120-132 + cSetScreenScale(dbisOneAndQuarter); + } else if (dpi <= 168) { // 132-144-168 + cSetScreenScale(dbisOneAndHalf); + } else { // 168-192-inf + cSetScreenScale(dbisTwo); + } + + if (!cLangFile().isEmpty()) { + LangLoaderPlain loader(cLangFile()); + if (!loader.errors().isEmpty()) { + LOG(("Lang load errors: %1").arg(loader.errors())); + } else if (!loader.warnings().isEmpty()) { + LOG(("Lang load warnings: %1").arg(loader.warnings())); + } + } + + style::startManager(); + anim::startManager(); + historyInit(); + + window = new Window(); + + psInstallEventFilter(); + + updateCheckTimer.setSingleShot(true); + + connect(&socket, SIGNAL(connected()), this, SLOT(socketConnected())); + connect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); + connect(&socket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(socketError(QLocalSocket::LocalSocketError))); + connect(&socket, SIGNAL(bytesWritten(qint64)), this, SLOT(socketWritten(qint64))); + connect(&socket, SIGNAL(readyRead()), this, SLOT(socketReading())); + connect(&server, SIGNAL(newConnection()), this, SLOT(newInstanceConnected())); + connect(this, SIGNAL(aboutToQuit()), this, SLOT(closeApplication())); + connect(&updateCheckTimer, SIGNAL(timeout()), this, SLOT(startUpdateCheck())); + connect(this, SIGNAL(updateFailed()), this, SLOT(onUpdateFailed())); + connect(this, SIGNAL(updateReady()), this, SLOT(onUpdateReady())); + connect(&writeUserConfigTimer, SIGNAL(timeout()), this, SLOT(onWriteUserConfig())); + writeUserConfigTimer.setSingleShot(true); + + if (cManyInstance()) { + startApp(); + } else { + DEBUG_LOG(("Application Info: connecting local socket to %1..").arg(serverName)); + socket.connectToServer(serverName); + } +} + +void Application::onAppUpdate(const MTPhelp_AppUpdate &response) { + updateRequestId = 0; + cSetLastUpdateCheck(unixtime()); + App::writeConfig(); + if (response.type() == mtpc_help_noAppUpdate) { + startUpdateCheck(); + } else { + updateThread = new QThread(); + updateDownloader = new PsUpdateDownloader(updateThread, response.c_help_appUpdate()); + updateThread->start(); + } +} + +bool Application::onAppUpdateFail() { + updateRequestId = 0; + cSetLastUpdateCheck(unixtime()); + App::writeConfig(); + startUpdateCheck(); + return true; +} + +void Application::updateGotCurrent() { + if (!updateReply || updateThread) return; + + cSetLastUpdateCheck(unixtime()); + QRegularExpressionMatch m = QRegularExpression(qsl("^\\s*(\\d+)\\s*:\\s*([\\x21-\\x7f]+)\\s*$")).match(QString::fromUtf8(updateReply->readAll())); + if (m.hasMatch()) { + int32 currentVersion = m.captured(1).toInt(); + if (currentVersion > AppVersion) { + updateThread = new QThread(); + updateDownloader = new PsUpdateDownloader(updateThread, m.captured(2)); + updateThread->start(); + } + } + if (updateReply) updateReply->deleteLater(); + updateReply = 0; + if (!updateThread) { + QDir updates(cWorkingDir() + "tupdates"); + if (updates.exists()) { + QFileInfoList list = updates.entryInfoList(QDir::Files); + for (QFileInfoList::iterator i = list.begin(), e = list.end(); i != e; ++i) { + if (QRegularExpression("^tupdate\\d+$", QRegularExpression::CaseInsensitiveOption).match(i->fileName()).hasMatch()) { + QFile(i->absoluteFilePath()).remove(); + } + } + } + emit updateLatest(); + } + startUpdateCheck(true); +} + +void Application::updateFailedCurrent(QNetworkReply::NetworkError e) { + LOG(("App Error: could not get current version (update check): %1").arg(e)); + if (updateReply) updateReply->deleteLater(); + updateReply = 0; + + emit updateFailed(); + startUpdateCheck(true); +} + +void Application::onUpdateReady() { + if (updateDownloader) { + updateDownloader->deleteLater(); + updateDownloader = 0; + } + updateCheckTimer.stop(); + + cSetLastUpdateCheck(unixtime()); + App::writeConfig(); +} + +void Application::onUpdateFailed() { + if (updateDownloader) { + updateDownloader->deleteLater(); + updateDownloader = 0; + if (updateThread) updateThread->deleteLater(); + updateThread = 0; + } + + cSetLastUpdateCheck(unixtime()); + App::writeConfig(); +} + +void Application::regPhotoUpdate(const PeerId &peer, MsgId msgId) { + photoUpdates.insert(msgId, peer); +} + +void Application::clearPhotoUpdates() { + photoUpdates.clear(); +} + +bool Application::isPhotoUpdating(const PeerId &peer) { + for (QMap::iterator i = photoUpdates.begin(), e = photoUpdates.end(); i != e; ++i) { + if (i.value() == peer) { + return true; + } + } + return false; +} + +void Application::cancelPhotoUpdate(const PeerId &peer) { + for (QMap::iterator i = photoUpdates.begin(), e = photoUpdates.end(); i != e;) { + if (i.value() == peer) { + i = photoUpdates.erase(i); + } else { + ++i; + } + } +} + +void Application::selfPhotoCleared(const MTPUserProfilePhoto &result) { + if (!App::self()) return; + App::self()->setPhoto(result); + emit peerPhotoDone(App::self()->id); +} + +void Application::chatPhotoCleared(PeerId peer, const MTPmessages_StatedMessage &result) { + if (App::main()) { + App::main()->sentFullDataReceived(0, result); + } + cancelPhotoUpdate(peer); + emit peerPhotoDone(peer); +} + +void Application::selfPhotoDone(const MTPphotos_Photo &result) { + if (!App::self()) return; + const MTPDphotos_photo &photo(result.c_photos_photo()); + App::feedPhoto(photo.vphoto); + App::feedUsers(photo.vusers); + cancelPhotoUpdate(App::self()->id); + emit peerPhotoDone(App::self()->id); +} + +void Application::chatPhotoDone(PeerId peer, const MTPmessages_StatedMessage &result) { + if (App::main()) { + App::main()->sentFullDataReceived(0, result); + } + cancelPhotoUpdate(peer); + emit peerPhotoDone(peer); +} + +bool Application::peerPhotoFail(PeerId peer, const RPCError &e) { + LOG(("Application Error: update photo failed %1: %2").arg(e.type()).arg(e.description())); + cancelPhotoUpdate(peer); + emit peerPhotoFail(peer); + return true; +} + +void Application::peerClearPhoto(PeerId peer) { + if (App::self() && App::self()->id == peer) { + MTP::send(MTPphotos_UpdateProfilePhoto(MTP_inputPhotoEmpty(), MTP_inputPhotoCropAuto()), rpcDone(&Application::selfPhotoCleared), rpcFail(&Application::peerPhotoFail, peer)); + } else { + MTP::send(MTPmessages_EditChatPhoto(MTP_int(int32(peer & 0xFFFFFFFF)), MTP_inputChatPhotoEmpty()), rpcDone(&Application::chatPhotoCleared, peer), rpcFail(&Application::peerPhotoFail, peer)); + } +} + +void Application::writeUserConfigIn(uint64 ms) { + if (!writeUserConfigTimer.isActive()) { + writeUserConfigTimer.start(ms); + } +} + +void Application::onWriteUserConfig() { + App::writeUserConfig(); +} + +void Application::photoUpdated(MsgId msgId, const MTPInputFile &file) { + if (!App::self()) return; + + QMap::iterator i = photoUpdates.find(msgId); + if (i != photoUpdates.end()) { + PeerId peer = i.value(); + if (peer == App::self()->id) { + MTP::send(MTPphotos_UploadProfilePhoto(file, MTP_string(""), MTP_inputGeoPointEmpty(), MTP_inputPhotoCrop(MTP_double(0), MTP_double(0), MTP_double(100))), rpcDone(&Application::selfPhotoDone), rpcFail(&Application::peerPhotoFail, peer)); + } else { + MTP::send(MTPmessages_EditChatPhoto(MTP_int(peer & 0xFFFFFFFF), MTP_inputChatUploadedPhoto(file, MTP_inputPhotoCrop(MTP_double(0), MTP_double(0), MTP_double(100)))), rpcDone(&Application::chatPhotoDone, peer), rpcFail(&Application::peerPhotoFail, peer)); + } + } +} + +void Application::onEnableDebugMode() { + if (!cDebug()) { + logsInitDebug(); + cSetDebug(true); + } + App::wnd()->hideLayer(); +} + +Application::UpdatingState Application::updatingState() { + if (!updateThread) return Application::UpdatingNone; + if (!updateDownloader) return Application::UpdatingReady; + return Application::UpdatingDownload; +} + +int32 Application::updatingSize() { + if (!updateDownloader) return 0; + return updateDownloader->size(); +} + +int32 Application::updatingReady() { + if (!updateDownloader) return 0; + return updateDownloader->ready(); +} + +FileUploader *Application::uploader() { + if (!::uploader) ::uploader = new FileUploader(); + return ::uploader; +} + +void Application::uploadProfilePhoto(const QImage &tosend, const PeerId &peerId) { + PreparedPhotoThumbs photoThumbs; + QVector photoSizes; + + QPixmap thumb = QPixmap::fromImage(tosend.scaled(160, 160, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + photoThumbs.insert('a', thumb); + photoSizes.push_back(MTP_photoSize(MTP_string("a"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0))); + + QPixmap full = QPixmap::fromImage(tosend); + photoThumbs.insert('c', full); + photoSizes.push_back(MTP_photoSize(MTP_string("c"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0))); + + QByteArray jpeg; + QBuffer jpegBuffer(&jpeg); + full.save(&jpegBuffer, "JPG", 87); + + PhotoId id = MTP::nonce(); + + MTPPhoto photo(MTP_photo(MTP_long(id), MTP_long(0), MTP_int(MTP::authedId()), MTP_int(unixtime()), MTP_string(""), MTP_geoPointEmpty(), MTP_vector(photoSizes))); + + QString file, filename; + int32 filesize = 0; + QByteArray data; + + ReadyLocalMedia ready(ToPreparePhoto, file, filename, filesize, data, id, id, peerId, photo, photoThumbs, MTP_documentEmpty(MTP_long(0)), jpeg); + + connect(App::uploader(), SIGNAL(photoReady(MsgId, const MTPInputFile &)), App::app(), SLOT(photoUpdated(MsgId, const MTPInputFile &)), Qt::UniqueConnection); + + MsgId newId = clientMsgId(); + App::app()->regPhotoUpdate(peerId, newId); + App::uploader()->uploadMedia(newId, ready); +} + +void Application::stopUpdate() { + if (updateReply) { + updateReply->abort(); + updateReply->deleteLater(); + updateReply = 0; + } + if (updateDownloader) { + updateDownloader->deleteLater(); + updateDownloader = 0; + if (updateThread) updateThread->deleteLater(); + updateThread = 0; + } +} + +void Application::startUpdateCheck(bool forceWait) { + updateCheckTimer.stop(); + if (updateRequestId || updateThread || updateReply || !cAutoUpdate()) return; + + int32 updateInSecs = cLastUpdateCheck() + 3600 + (rand() % 3600) - unixtime(); + bool sendRequest = (updateInSecs <= 0 || updateInSecs > 7200); + if (!sendRequest && !forceWait) { + QDir updates(cWorkingDir() + "tupdates"); + if (updates.exists()) { + QFileInfoList list = updates.entryInfoList(QDir::Files); + for (QFileInfoList::iterator i = list.begin(), e = list.end(); i != e; ++i) { + if (QRegularExpression("^tupdate\\d+$", QRegularExpression::CaseInsensitiveOption).match(i->fileName()).hasMatch()) { + sendRequest = true; + } + } + } + } + if (cManyInstance() && !cDebug()) return; // only main instance is updating + + if (sendRequest) { + QNetworkRequest checkVersion(QUrl(qsl("http://tdesktop.com/win/tupdates/current"))); + if (updateReply) updateReply->deleteLater(); + + App::setProxySettings(updateManager); + updateReply = updateManager.get(checkVersion); + connect(updateReply, SIGNAL(finished()), this, SLOT(updateGotCurrent())); + connect(updateReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(updateFailedCurrent(QNetworkReply::NetworkError))); +// updateRequestId = MTP::send(MTPhelp_GetAppUpdate(MTP_string(cApiDeviceModel()), MTP_string(cApiSystemVersion()), MTP_string(cApiAppVersion()), MTP_string(cApiLang())), rpcDone(&Application::onAppUpdate), rpcFail(&Application::onAppUpdateFail); + emit updateChecking(); + } else { + updateCheckTimer.start((updateInSecs + 5) * 1000); + } +} + +void Application::socketConnected() { + DEBUG_LOG(("Application Info: socket connected, this is not the first application instance, sending show command..")); + closing = true; + socket.write("CMD:show;"); +} + +void Application::socketWritten(qint64/* bytes*/) { + if (socket.state() != QLocalSocket::ConnectedState) { + DEBUG_LOG(("Application Error: socket is not connected %1").arg(socket.state())); + return; + } + if (socket.bytesToWrite()) { + return; + } + DEBUG_LOG(("Application Info: show command written, waiting response..")); +} + +void Application::socketReading() { + if (socket.state() != QLocalSocket::ConnectedState) { + DEBUG_LOG(("Application Error: socket is not connected %1").arg(socket.state())); + return; + } + socketRead.append(socket.readAll()); + if (QRegularExpression("RES:(\\d+);").match(socketRead).hasMatch()) { + uint64 pid = socketRead.mid(4, socketRead.length() - 5).toULongLong(); + psActivateProcess(pid); + DEBUG_LOG(("Application Info: show command response received, pid = %1, activating and quiting..").arg(pid)); + return App::quit(); + } +} + +void Application::socketError(QLocalSocket::LocalSocketError e) { + if (closing) { + DEBUG_LOG(("Application Error: could not write show command, error %1, quiting..").arg(e)); + return App::quit(); + } + + if (e == QLocalSocket::ServerNotFoundError) { + DEBUG_LOG(("Application Info: this is the only instance of Telegram, starting server and app..")); + } else { + DEBUG_LOG(("Application Info: socket connect error %1, starting server and app..").arg(e)); + } + socket.close(); + + psCheckLocalSocket(serverName); + + if (!server.listen(serverName)) { + DEBUG_LOG(("Application Error: failed to start listening to %1 server").arg(serverName)); + return App::quit(); + } + + if (!cNoStartUpdate() && psCheckReadyUpdate()) { + cSetRestartingUpdate(true); + DEBUG_LOG(("Application Info: installing update instead of starting app..")); + return App::quit(); + } + + startApp(); +} + +void Application::startApp() { + App::readUserConfig(); + if (!MTP::localKey().created()) { + MTP::createLocalKey(QByteArray()); + cSetNeedConfigResave(true); + } + if (cNeedConfigResave()) { + App::writeConfig(); + App::writeUserConfig(); + cSetNeedConfigResave(false); + } + + window->createWinId(); + window->init(); + + readSupportTemplates(); + + MTP::setLayer(mtpLayerMax); + MTP::start(); + + MTP::setStateChangedHandler(mtpStateChanged); + + App::initMedia(); + + if (MTP::authedId()) { + window->setupMain(false); + } else { + window->setupIntro(false); + } + + window->psFirstShow(); + + if (cStartToSettings()) { + window->showSettings(); + } + + QNetworkProxyFactory::setUseSystemConfiguration(true); +} + +void Application::socketDisconnected() { + if (closing) { + DEBUG_LOG(("Application Error: socket disconnected before command response received, quiting..")); + return App::quit(); + } +} + +void Application::newInstanceConnected() { + DEBUG_LOG(("Application Info: new local socket connected")); + for (QLocalSocket *client = server.nextPendingConnection(); client; client = server.nextPendingConnection()) { + clients.push_back(ClientSocket(client, QByteArray())); + connect(client, SIGNAL(readyRead()), this, SLOT(readClients())); + connect(client, SIGNAL(disconnected()), this, SLOT(removeClients())); + } +} + +void Application::readClients() { + for (ClientSockets::iterator i = clients.begin(), e = clients.end(); i != e; ++i) { + i->second.append(i->first->readAll()); + if (i->second.size()) { + QString cmds(i->second); + int32 from = 0, l = cmds.length(); + for (int32 to = cmds.indexOf(QChar(';'), from); to >= from; to = (from < l) ? cmds.indexOf(QChar(';'), from) : -1) { + QStringRef cmd(&cmds, from, to - from); + if (cmd.indexOf("CMD:") == 0) { + execExternal(cmds.mid(from + 4, to - from - 4)); + QByteArray response(QString("RES:%1;").arg(QCoreApplication::applicationPid()).toUtf8()); + i->first->write(response.data(), response.size()); + } else { + LOG(("Application Error: unknown command %1 passed in local socket").arg(QString(cmd.constData(), cmd.length()))); + } + from = to + 1; + } + if (from > 0) { + i->second = i->second.mid(from); + } + } + } +} + +void Application::removeClients() { + DEBUG_LOG(("Application Info: remove clients slot called, clients %1").arg(clients.size())); + for (ClientSockets::iterator i = clients.begin(), e = clients.end(); i != e;) { + if (i->first->state() != QLocalSocket::ConnectedState) { + DEBUG_LOG(("Application Info: removing client")); + i = clients.erase(i); + e = clients.end(); + } else { + ++i; + } + } +} + +void Application::execExternal(const QString &cmd) { + DEBUG_LOG(("Application Info: executing external command '%1'").arg(cmd)); + if (cmd == "show") { + window->activate(); + } +} + +void Application::closeApplication() { + // close server + server.close(); + for (ClientSockets::iterator i = clients.begin(), e = clients.end(); i != e; ++i) { + disconnect(i->first, SIGNAL(disconnected()), this, SLOT(removeClients())); + i->first->close(); + } + clients.clear(); + + MTP::stop(); +} + +Application::~Application() { + App::setQuiting(); + window->setParent(0); + + anim::stopManager(); + + socket.close(); + closeApplication(); + App::deinitMedia(); + mainApp = 0; + delete updateReply; + delete ::uploader; + updateReply = 0; + delete updateDownloader; + updateDownloader = 0; + delete updateThread; + updateThread = 0; + + delete window; + + style::stopManager(); +} + +Application *Application::app() { + return mainApp; +} + +Window *Application::wnd() { + return mainApp ? mainApp->window : 0; +} + +QString Application::lang() { + if (!lng.length()) { + lng = psCurrentLanguage(); + } + if (!lng.length()) { + lng = "en"; + } + return lng; +} + +MainWidget *Application::main() { + return mainApp ? mainApp->window->mainWidget() : 0; +} diff --git a/Telegram/SourceFiles/application.h b/Telegram/SourceFiles/application.h new file mode 100644 index 000000000..2c229fe19 --- /dev/null +++ b/Telegram/SourceFiles/application.h @@ -0,0 +1,132 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include +#include + +#include "window.h" +#include "pspecific.h" + +class MainWidget; +class FileUploader; + +class Application : public PsApplication, public RPCSender { + Q_OBJECT + +public: + + Application(int argc, char *argv[]); + ~Application(); + + static Application *app(); + static Window *wnd(); + static QString lang(); + static MainWidget *main(); + + void onAppUpdate(const MTPhelp_AppUpdate &response); + bool onAppUpdateFail(); + + enum UpdatingState { + UpdatingNone, + UpdatingDownload, + UpdatingReady, + }; + UpdatingState updatingState(); + int32 updatingSize(); + int32 updatingReady(); + + FileUploader *uploader(); + void uploadProfilePhoto(const QImage &tosend, const PeerId &peerId); + void regPhotoUpdate(const PeerId &peer, MsgId msgId); + void clearPhotoUpdates(); + bool isPhotoUpdating(const PeerId &peer); + void cancelPhotoUpdate(const PeerId &peer); + + void stopUpdate(); + + void selfPhotoCleared(const MTPUserProfilePhoto &result); + void chatPhotoCleared(PeerId peer, const MTPmessages_StatedMessage &result); + void selfPhotoDone(const MTPphotos_Photo &result); + void chatPhotoDone(PeerId peerId, const MTPmessages_StatedMessage &rersult); + bool peerPhotoFail(PeerId peerId, const RPCError &e); + void peerClearPhoto(PeerId peer); + + void writeUserConfigIn(uint64 ms); + +signals: + + void peerPhotoDone(PeerId peer); + void peerPhotoFail(PeerId peer); + +public slots: + + void startUpdateCheck(bool forceWait = false); + void socketConnected(); + void socketError(QLocalSocket::LocalSocketError e); + void socketDisconnected(); + void socketWritten(qint64 bytes); + void socketReading(); + void newInstanceConnected(); + void closeApplication(); + + void readClients(); + void removeClients(); + + void updateGotCurrent(); + void updateFailedCurrent(QNetworkReply::NetworkError e); + + void onUpdateReady(); + void onUpdateFailed(); + + void photoUpdated(MsgId msgId, const MTPInputFile &file); + + void onEnableDebugMode(); + void onWriteUserConfig(); + +private: + + QMap photoUpdates; + + void startApp(); + + typedef QPair ClientSocket; + typedef QVector ClientSockets; + + QString serverName; + QLocalSocket socket; + QString socketRead; + QLocalServer server; + ClientSockets clients; + bool closing; + + void execExternal(const QString &cmd); + + Window *window; + + mtpRequestId updateRequestId; + QNetworkAccessManager updateManager; + QNetworkReply *updateReply; + QTimer updateCheckTimer; + QThread *updateThread; + PsUpdateDownloader *updateDownloader; + + QTimer writeUserConfigTimer; + +}; diff --git a/Telegram/SourceFiles/art/Emoji/002320E3.png b/Telegram/SourceFiles/art/Emoji/002320E3.png new file mode 100644 index 000000000..4660d4cb1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/002320E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/003020E3.png b/Telegram/SourceFiles/art/Emoji/003020E3.png new file mode 100644 index 000000000..a196fa1dd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/003020E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/003120E3.png b/Telegram/SourceFiles/art/Emoji/003120E3.png new file mode 100644 index 000000000..26d6754a9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/003120E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/003220E3.png b/Telegram/SourceFiles/art/Emoji/003220E3.png new file mode 100644 index 000000000..645c904ee Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/003220E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/003320E3.png b/Telegram/SourceFiles/art/Emoji/003320E3.png new file mode 100644 index 000000000..1674b6944 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/003320E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/003420E3.png b/Telegram/SourceFiles/art/Emoji/003420E3.png new file mode 100644 index 000000000..ef6483034 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/003420E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/003520E3.png b/Telegram/SourceFiles/art/Emoji/003520E3.png new file mode 100644 index 000000000..782ee47aa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/003520E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/003620E3.png b/Telegram/SourceFiles/art/Emoji/003620E3.png new file mode 100644 index 000000000..07f549a29 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/003620E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/003720E3.png b/Telegram/SourceFiles/art/Emoji/003720E3.png new file mode 100644 index 000000000..509362982 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/003720E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/003820E3.png b/Telegram/SourceFiles/art/Emoji/003820E3.png new file mode 100644 index 000000000..aea2c90eb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/003820E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/003920E3.png b/Telegram/SourceFiles/art/Emoji/003920E3.png new file mode 100644 index 000000000..5a19d1b6e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/003920E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/00A9.png b/Telegram/SourceFiles/art/Emoji/00A9.png new file mode 100644 index 000000000..64f1f9a2d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/00A9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/00AE.png b/Telegram/SourceFiles/art/Emoji/00AE.png new file mode 100644 index 000000000..48fa74efa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/00AE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/203C.png b/Telegram/SourceFiles/art/Emoji/203C.png new file mode 100644 index 000000000..e1c30571c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/203C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2049.png b/Telegram/SourceFiles/art/Emoji/2049.png new file mode 100644 index 000000000..0bacbe987 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2049.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2122.png b/Telegram/SourceFiles/art/Emoji/2122.png new file mode 100644 index 000000000..8b5e91a3f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2122.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2139.png b/Telegram/SourceFiles/art/Emoji/2139.png new file mode 100644 index 000000000..89e6eb401 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2139.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2194.png b/Telegram/SourceFiles/art/Emoji/2194.png new file mode 100644 index 000000000..87aa87320 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2194.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2195.png b/Telegram/SourceFiles/art/Emoji/2195.png new file mode 100644 index 000000000..beb8b2c4c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2195.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2196.png b/Telegram/SourceFiles/art/Emoji/2196.png new file mode 100644 index 000000000..a1769d447 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2196.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2197.png b/Telegram/SourceFiles/art/Emoji/2197.png new file mode 100644 index 000000000..2b637fe50 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2197.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2198.png b/Telegram/SourceFiles/art/Emoji/2198.png new file mode 100644 index 000000000..d868dd76c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2198.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2199.png b/Telegram/SourceFiles/art/Emoji/2199.png new file mode 100644 index 000000000..377567308 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2199.png differ diff --git a/Telegram/SourceFiles/art/Emoji/21A9.png b/Telegram/SourceFiles/art/Emoji/21A9.png new file mode 100644 index 000000000..9f9af80cc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/21A9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/21AA.png b/Telegram/SourceFiles/art/Emoji/21AA.png new file mode 100644 index 000000000..c13226bce Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/21AA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/231A.png b/Telegram/SourceFiles/art/Emoji/231A.png new file mode 100644 index 000000000..699ddddf6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/231A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/231B.png b/Telegram/SourceFiles/art/Emoji/231B.png new file mode 100644 index 000000000..b69f1ed8a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/231B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/23E9.png b/Telegram/SourceFiles/art/Emoji/23E9.png new file mode 100644 index 000000000..f4b575aa7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/23E9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/23EA.png b/Telegram/SourceFiles/art/Emoji/23EA.png new file mode 100644 index 000000000..557b09fea Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/23EA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/23EB.png b/Telegram/SourceFiles/art/Emoji/23EB.png new file mode 100644 index 000000000..80b209b2a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/23EB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/23EC.png b/Telegram/SourceFiles/art/Emoji/23EC.png new file mode 100644 index 000000000..36688b290 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/23EC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/23F0.png b/Telegram/SourceFiles/art/Emoji/23F0.png new file mode 100644 index 000000000..c8ec471c1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/23F0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/23F3.png b/Telegram/SourceFiles/art/Emoji/23F3.png new file mode 100644 index 000000000..eadb18c48 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/23F3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/24C2.png b/Telegram/SourceFiles/art/Emoji/24C2.png new file mode 100644 index 000000000..8af22067d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/24C2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/25AA.png b/Telegram/SourceFiles/art/Emoji/25AA.png new file mode 100644 index 000000000..baed68614 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/25AA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/25AB.png b/Telegram/SourceFiles/art/Emoji/25AB.png new file mode 100644 index 000000000..34a504fb5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/25AB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/25B6.png b/Telegram/SourceFiles/art/Emoji/25B6.png new file mode 100644 index 000000000..7ffe84e84 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/25B6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/25C0.png b/Telegram/SourceFiles/art/Emoji/25C0.png new file mode 100644 index 000000000..ea2a965ca Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/25C0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/25FB.png b/Telegram/SourceFiles/art/Emoji/25FB.png new file mode 100644 index 000000000..1a9b1e4e1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/25FB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/25FC.png b/Telegram/SourceFiles/art/Emoji/25FC.png new file mode 100644 index 000000000..8ae60bfa4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/25FC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/25FD.png b/Telegram/SourceFiles/art/Emoji/25FD.png new file mode 100644 index 000000000..66144a8d1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/25FD.png differ diff --git a/Telegram/SourceFiles/art/Emoji/25FE.png b/Telegram/SourceFiles/art/Emoji/25FE.png new file mode 100644 index 000000000..300b92dd3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/25FE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2600.png b/Telegram/SourceFiles/art/Emoji/2600.png new file mode 100644 index 000000000..ad91b055b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2600.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2601.png b/Telegram/SourceFiles/art/Emoji/2601.png new file mode 100644 index 000000000..14ee8fd38 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2601.png differ diff --git a/Telegram/SourceFiles/art/Emoji/260E.png b/Telegram/SourceFiles/art/Emoji/260E.png new file mode 100644 index 000000000..ae88c82b8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/260E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2611.png b/Telegram/SourceFiles/art/Emoji/2611.png new file mode 100644 index 000000000..21f462ca0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2611.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2614.png b/Telegram/SourceFiles/art/Emoji/2614.png new file mode 100644 index 000000000..154540cc4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2614.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2615.png b/Telegram/SourceFiles/art/Emoji/2615.png new file mode 100644 index 000000000..f3ac6c989 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2615.png differ diff --git a/Telegram/SourceFiles/art/Emoji/261D.png b/Telegram/SourceFiles/art/Emoji/261D.png new file mode 100644 index 000000000..caf5e7fb5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/261D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/263A.png b/Telegram/SourceFiles/art/Emoji/263A.png new file mode 100644 index 000000000..b758b747d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/263A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2648.png b/Telegram/SourceFiles/art/Emoji/2648.png new file mode 100644 index 000000000..36ca321ff Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2648.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2649.png b/Telegram/SourceFiles/art/Emoji/2649.png new file mode 100644 index 000000000..4e0687e0a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2649.png differ diff --git a/Telegram/SourceFiles/art/Emoji/264A.png b/Telegram/SourceFiles/art/Emoji/264A.png new file mode 100644 index 000000000..1e131e0ab Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/264A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/264B.png b/Telegram/SourceFiles/art/Emoji/264B.png new file mode 100644 index 000000000..b02cca613 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/264B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/264C.png b/Telegram/SourceFiles/art/Emoji/264C.png new file mode 100644 index 000000000..6354aa459 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/264C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/264D.png b/Telegram/SourceFiles/art/Emoji/264D.png new file mode 100644 index 000000000..19cd5dcb1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/264D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/264E.png b/Telegram/SourceFiles/art/Emoji/264E.png new file mode 100644 index 000000000..e000b39c9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/264E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/264F.png b/Telegram/SourceFiles/art/Emoji/264F.png new file mode 100644 index 000000000..82eb8eb5b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/264F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2650.png b/Telegram/SourceFiles/art/Emoji/2650.png new file mode 100644 index 000000000..2b4fa50f5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2650.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2651.png b/Telegram/SourceFiles/art/Emoji/2651.png new file mode 100644 index 000000000..ce713d815 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2651.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2652.png b/Telegram/SourceFiles/art/Emoji/2652.png new file mode 100644 index 000000000..003221119 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2652.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2653.png b/Telegram/SourceFiles/art/Emoji/2653.png new file mode 100644 index 000000000..85c701aa0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2653.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2660.png b/Telegram/SourceFiles/art/Emoji/2660.png new file mode 100644 index 000000000..3ed037327 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2660.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2663.png b/Telegram/SourceFiles/art/Emoji/2663.png new file mode 100644 index 000000000..4dd8e0b23 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2663.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2665.png b/Telegram/SourceFiles/art/Emoji/2665.png new file mode 100644 index 000000000..1088ec55c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2665.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2666.png b/Telegram/SourceFiles/art/Emoji/2666.png new file mode 100644 index 000000000..0fa97e6e2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2666.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2668.png b/Telegram/SourceFiles/art/Emoji/2668.png new file mode 100644 index 000000000..244e9543a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2668.png differ diff --git a/Telegram/SourceFiles/art/Emoji/267B.png b/Telegram/SourceFiles/art/Emoji/267B.png new file mode 100644 index 000000000..39e485d47 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/267B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/267F.png b/Telegram/SourceFiles/art/Emoji/267F.png new file mode 100644 index 000000000..8e0341d58 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/267F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2693.png b/Telegram/SourceFiles/art/Emoji/2693.png new file mode 100644 index 000000000..0a2095000 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2693.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26A0.png b/Telegram/SourceFiles/art/Emoji/26A0.png new file mode 100644 index 000000000..da04fd67f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26A0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26A1.png b/Telegram/SourceFiles/art/Emoji/26A1.png new file mode 100644 index 000000000..aa730a714 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26A1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26AA.png b/Telegram/SourceFiles/art/Emoji/26AA.png new file mode 100644 index 000000000..5a7d5c379 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26AA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26AB.png b/Telegram/SourceFiles/art/Emoji/26AB.png new file mode 100644 index 000000000..4cf20983c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26AB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26BD.png b/Telegram/SourceFiles/art/Emoji/26BD.png new file mode 100644 index 000000000..7bfd0406f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26BD.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26BE.png b/Telegram/SourceFiles/art/Emoji/26BE.png new file mode 100644 index 000000000..ef49d5589 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26BE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26C4.png b/Telegram/SourceFiles/art/Emoji/26C4.png new file mode 100644 index 000000000..93bef58ac Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26C4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26C5.png b/Telegram/SourceFiles/art/Emoji/26C5.png new file mode 100644 index 000000000..eb04e5d42 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26C5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26CE.png b/Telegram/SourceFiles/art/Emoji/26CE.png new file mode 100644 index 000000000..0ad227f3b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26CE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26D4.png b/Telegram/SourceFiles/art/Emoji/26D4.png new file mode 100644 index 000000000..e28fadac4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26D4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26EA.png b/Telegram/SourceFiles/art/Emoji/26EA.png new file mode 100644 index 000000000..17727e0b3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26EA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26F2.png b/Telegram/SourceFiles/art/Emoji/26F2.png new file mode 100644 index 000000000..720ad2386 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26F2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26F3.png b/Telegram/SourceFiles/art/Emoji/26F3.png new file mode 100644 index 000000000..50e4a270c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26F3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26F5.png b/Telegram/SourceFiles/art/Emoji/26F5.png new file mode 100644 index 000000000..4a5c0293e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26F5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26FA.png b/Telegram/SourceFiles/art/Emoji/26FA.png new file mode 100644 index 000000000..516ad1074 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26FA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/26FD.png b/Telegram/SourceFiles/art/Emoji/26FD.png new file mode 100644 index 000000000..dbd528b07 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/26FD.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2702.png b/Telegram/SourceFiles/art/Emoji/2702.png new file mode 100644 index 000000000..082248819 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2702.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2705.png b/Telegram/SourceFiles/art/Emoji/2705.png new file mode 100644 index 000000000..0f82df985 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2705.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2708.png b/Telegram/SourceFiles/art/Emoji/2708.png new file mode 100644 index 000000000..509fa7b20 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2708.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2709.png b/Telegram/SourceFiles/art/Emoji/2709.png new file mode 100644 index 000000000..40357543f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2709.png differ diff --git a/Telegram/SourceFiles/art/Emoji/270A.png b/Telegram/SourceFiles/art/Emoji/270A.png new file mode 100644 index 000000000..43d7ca87b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/270A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/270B.png b/Telegram/SourceFiles/art/Emoji/270B.png new file mode 100644 index 000000000..984f829b7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/270B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/270C.png b/Telegram/SourceFiles/art/Emoji/270C.png new file mode 100644 index 000000000..7fe482fbb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/270C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/270F.png b/Telegram/SourceFiles/art/Emoji/270F.png new file mode 100644 index 000000000..a86cf25c1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/270F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2712.png b/Telegram/SourceFiles/art/Emoji/2712.png new file mode 100644 index 000000000..cc6c6ab2e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2712.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2714.png b/Telegram/SourceFiles/art/Emoji/2714.png new file mode 100644 index 000000000..b6753966f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2714.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2716.png b/Telegram/SourceFiles/art/Emoji/2716.png new file mode 100644 index 000000000..7fac6725d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2716.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2728.png b/Telegram/SourceFiles/art/Emoji/2728.png new file mode 100644 index 000000000..82aad355c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2728.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2733.png b/Telegram/SourceFiles/art/Emoji/2733.png new file mode 100644 index 000000000..d9b1f0814 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2733.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2734.png b/Telegram/SourceFiles/art/Emoji/2734.png new file mode 100644 index 000000000..f95730ed7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2734.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2744.png b/Telegram/SourceFiles/art/Emoji/2744.png new file mode 100644 index 000000000..f88a35d19 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2744.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2747.png b/Telegram/SourceFiles/art/Emoji/2747.png new file mode 100644 index 000000000..6179ee0da Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2747.png differ diff --git a/Telegram/SourceFiles/art/Emoji/274C.png b/Telegram/SourceFiles/art/Emoji/274C.png new file mode 100644 index 000000000..64036e1cd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/274C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/274E.png b/Telegram/SourceFiles/art/Emoji/274E.png new file mode 100644 index 000000000..9a337afad Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/274E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2753.png b/Telegram/SourceFiles/art/Emoji/2753.png new file mode 100644 index 000000000..303b2f562 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2753.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2754.png b/Telegram/SourceFiles/art/Emoji/2754.png new file mode 100644 index 000000000..ce83bb601 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2754.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2755.png b/Telegram/SourceFiles/art/Emoji/2755.png new file mode 100644 index 000000000..74b34e077 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2755.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2757.png b/Telegram/SourceFiles/art/Emoji/2757.png new file mode 100644 index 000000000..09323192b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2757.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2764.png b/Telegram/SourceFiles/art/Emoji/2764.png new file mode 100644 index 000000000..db9de9e4f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2764.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2795.png b/Telegram/SourceFiles/art/Emoji/2795.png new file mode 100644 index 000000000..33bb432cc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2795.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2796.png b/Telegram/SourceFiles/art/Emoji/2796.png new file mode 100644 index 000000000..ca89edf55 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2796.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2797.png b/Telegram/SourceFiles/art/Emoji/2797.png new file mode 100644 index 000000000..04ca48962 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2797.png differ diff --git a/Telegram/SourceFiles/art/Emoji/27A1.png b/Telegram/SourceFiles/art/Emoji/27A1.png new file mode 100644 index 000000000..36fad95c2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/27A1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/27B0.png b/Telegram/SourceFiles/art/Emoji/27B0.png new file mode 100644 index 000000000..8460f2e02 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/27B0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/27BF.png b/Telegram/SourceFiles/art/Emoji/27BF.png new file mode 100644 index 000000000..1245f996e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/27BF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2934.png b/Telegram/SourceFiles/art/Emoji/2934.png new file mode 100644 index 000000000..7b52ecdf8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2934.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2935.png b/Telegram/SourceFiles/art/Emoji/2935.png new file mode 100644 index 000000000..0aba0d08a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2935.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2B05.png b/Telegram/SourceFiles/art/Emoji/2B05.png new file mode 100644 index 000000000..8bacddafc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2B05.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2B06.png b/Telegram/SourceFiles/art/Emoji/2B06.png new file mode 100644 index 000000000..b39443023 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2B06.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2B07.png b/Telegram/SourceFiles/art/Emoji/2B07.png new file mode 100644 index 000000000..bc9532a7e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2B07.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2B1B.png b/Telegram/SourceFiles/art/Emoji/2B1B.png new file mode 100644 index 000000000..6a833f522 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2B1B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2B1C.png b/Telegram/SourceFiles/art/Emoji/2B1C.png new file mode 100644 index 000000000..94275fda8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2B1C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2B50.png b/Telegram/SourceFiles/art/Emoji/2B50.png new file mode 100644 index 000000000..358da2bce Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2B50.png differ diff --git a/Telegram/SourceFiles/art/Emoji/2B55.png b/Telegram/SourceFiles/art/Emoji/2B55.png new file mode 100644 index 000000000..ff62f1b4e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/2B55.png differ diff --git a/Telegram/SourceFiles/art/Emoji/3030.png b/Telegram/SourceFiles/art/Emoji/3030.png new file mode 100644 index 000000000..aeb952e9a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/3030.png differ diff --git a/Telegram/SourceFiles/art/Emoji/303D.png b/Telegram/SourceFiles/art/Emoji/303D.png new file mode 100644 index 000000000..6701f7649 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/303D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/3297.png b/Telegram/SourceFiles/art/Emoji/3297.png new file mode 100644 index 000000000..16586722d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/3297.png differ diff --git a/Telegram/SourceFiles/art/Emoji/3299.png b/Telegram/SourceFiles/art/Emoji/3299.png new file mode 100644 index 000000000..216bd9153 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/3299.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDC04.png b/Telegram/SourceFiles/art/Emoji/D83CDC04.png new file mode 100644 index 000000000..6521d64e4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDC04.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDCCF.png b/Telegram/SourceFiles/art/Emoji/D83CDCCF.png new file mode 100644 index 000000000..754d3c23f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDCCF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD70.png b/Telegram/SourceFiles/art/Emoji/D83CDD70.png new file mode 100644 index 000000000..dd8262411 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD70.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD71.png b/Telegram/SourceFiles/art/Emoji/D83CDD71.png new file mode 100644 index 000000000..84f20f313 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD71.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD7E.png b/Telegram/SourceFiles/art/Emoji/D83CDD7E.png new file mode 100644 index 000000000..9a5632993 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD7E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD7F.png b/Telegram/SourceFiles/art/Emoji/D83CDD7F.png new file mode 100644 index 000000000..aa5dca172 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD7F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD8E.png b/Telegram/SourceFiles/art/Emoji/D83CDD8E.png new file mode 100644 index 000000000..3e3a43e06 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD8E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD91.png b/Telegram/SourceFiles/art/Emoji/D83CDD91.png new file mode 100644 index 000000000..2f37aaca0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD91.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD92.png b/Telegram/SourceFiles/art/Emoji/D83CDD92.png new file mode 100644 index 000000000..6727be384 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD92.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD93.png b/Telegram/SourceFiles/art/Emoji/D83CDD93.png new file mode 100644 index 000000000..47a754e8c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD93.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD94.png b/Telegram/SourceFiles/art/Emoji/D83CDD94.png new file mode 100644 index 000000000..0b710e1dc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD94.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD95.png b/Telegram/SourceFiles/art/Emoji/D83CDD95.png new file mode 100644 index 000000000..25149a72f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD95.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD96.png b/Telegram/SourceFiles/art/Emoji/D83CDD96.png new file mode 100644 index 000000000..14d0d3f19 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD96.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD97.png b/Telegram/SourceFiles/art/Emoji/D83CDD97.png new file mode 100644 index 000000000..8ffef1207 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD97.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD98.png b/Telegram/SourceFiles/art/Emoji/D83CDD98.png new file mode 100644 index 000000000..7288cbbaa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD98.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD99.png b/Telegram/SourceFiles/art/Emoji/D83CDD99.png new file mode 100644 index 000000000..6d7180d41 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD99.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDD9A.png b/Telegram/SourceFiles/art/Emoji/D83CDD9A.png new file mode 100644 index 000000000..7c34f12e8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDD9A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDDE8D83CDDF3.png b/Telegram/SourceFiles/art/Emoji/D83CDDE8D83CDDF3.png new file mode 100644 index 000000000..b2b9a105a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDDE8D83CDDF3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDDE9D83CDDEA.png b/Telegram/SourceFiles/art/Emoji/D83CDDE9D83CDDEA.png new file mode 100644 index 000000000..8653cb9c4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDDE9D83CDDEA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDDEAD83CDDF8.png b/Telegram/SourceFiles/art/Emoji/D83CDDEAD83CDDF8.png new file mode 100644 index 000000000..9d999865e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDDEAD83CDDF8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDDEBD83CDDF7.png b/Telegram/SourceFiles/art/Emoji/D83CDDEBD83CDDF7.png new file mode 100644 index 000000000..d1d5671f7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDDEBD83CDDF7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDDECD83CDDE7.png b/Telegram/SourceFiles/art/Emoji/D83CDDECD83CDDE7.png new file mode 100644 index 000000000..cbee6683f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDDECD83CDDE7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDDEED83CDDF9.png b/Telegram/SourceFiles/art/Emoji/D83CDDEED83CDDF9.png new file mode 100644 index 000000000..8a327dd33 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDDEED83CDDF9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDDEFD83CDDF5.png b/Telegram/SourceFiles/art/Emoji/D83CDDEFD83CDDF5.png new file mode 100644 index 000000000..7cc5ee298 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDDEFD83CDDF5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDDF0D83CDDF7.png b/Telegram/SourceFiles/art/Emoji/D83CDDF0D83CDDF7.png new file mode 100644 index 000000000..7d809aeaa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDDF0D83CDDF7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDDF7D83CDDFA.png b/Telegram/SourceFiles/art/Emoji/D83CDDF7D83CDDFA.png new file mode 100644 index 000000000..be2ff94a7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDDF7D83CDDFA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDDFAD83CDDF8.png b/Telegram/SourceFiles/art/Emoji/D83CDDFAD83CDDF8.png new file mode 100644 index 000000000..61a28abb5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDDFAD83CDDF8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE01.png b/Telegram/SourceFiles/art/Emoji/D83CDE01.png new file mode 100644 index 000000000..93c9689ad Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE01.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE02.png b/Telegram/SourceFiles/art/Emoji/D83CDE02.png new file mode 100644 index 000000000..8e6962a74 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE02.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE1A.png b/Telegram/SourceFiles/art/Emoji/D83CDE1A.png new file mode 100644 index 000000000..730d6266a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE1A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE2F.png b/Telegram/SourceFiles/art/Emoji/D83CDE2F.png new file mode 100644 index 000000000..1a2f230da Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE2F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE32.png b/Telegram/SourceFiles/art/Emoji/D83CDE32.png new file mode 100644 index 000000000..a261ad596 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE32.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE33.png b/Telegram/SourceFiles/art/Emoji/D83CDE33.png new file mode 100644 index 000000000..e8e932986 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE33.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE34.png b/Telegram/SourceFiles/art/Emoji/D83CDE34.png new file mode 100644 index 000000000..8371f7671 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE34.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE35.png b/Telegram/SourceFiles/art/Emoji/D83CDE35.png new file mode 100644 index 000000000..30d4a5b99 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE35.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE36.png b/Telegram/SourceFiles/art/Emoji/D83CDE36.png new file mode 100644 index 000000000..1d743d7f0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE36.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE37.png b/Telegram/SourceFiles/art/Emoji/D83CDE37.png new file mode 100644 index 000000000..dc984f6dd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE37.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE38.png b/Telegram/SourceFiles/art/Emoji/D83CDE38.png new file mode 100644 index 000000000..05787e22f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE38.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE39.png b/Telegram/SourceFiles/art/Emoji/D83CDE39.png new file mode 100644 index 000000000..e7411403b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE39.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE3A.png b/Telegram/SourceFiles/art/Emoji/D83CDE3A.png new file mode 100644 index 000000000..9027e5170 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE3A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE50.png b/Telegram/SourceFiles/art/Emoji/D83CDE50.png new file mode 100644 index 000000000..b9fa8097d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE50.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDE51.png b/Telegram/SourceFiles/art/Emoji/D83CDE51.png new file mode 100644 index 000000000..93ee75ffc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDE51.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF00.png b/Telegram/SourceFiles/art/Emoji/D83CDF00.png new file mode 100644 index 000000000..bec5f142a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF00.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF01.png b/Telegram/SourceFiles/art/Emoji/D83CDF01.png new file mode 100644 index 000000000..ac39b56c9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF01.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF02.png b/Telegram/SourceFiles/art/Emoji/D83CDF02.png new file mode 100644 index 000000000..c4c186709 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF02.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF03.png b/Telegram/SourceFiles/art/Emoji/D83CDF03.png new file mode 100644 index 000000000..cfbe0c04c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF03.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF04.png b/Telegram/SourceFiles/art/Emoji/D83CDF04.png new file mode 100644 index 000000000..fdc05fee6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF04.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF05.png b/Telegram/SourceFiles/art/Emoji/D83CDF05.png new file mode 100644 index 000000000..4ee1bf482 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF05.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF06.png b/Telegram/SourceFiles/art/Emoji/D83CDF06.png new file mode 100644 index 000000000..47856c72a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF06.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF07.png b/Telegram/SourceFiles/art/Emoji/D83CDF07.png new file mode 100644 index 000000000..235c6bb90 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF07.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF08.png b/Telegram/SourceFiles/art/Emoji/D83CDF08.png new file mode 100644 index 000000000..428c8428f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF08.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF09.png b/Telegram/SourceFiles/art/Emoji/D83CDF09.png new file mode 100644 index 000000000..ebe76dcc7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF09.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF0A.png b/Telegram/SourceFiles/art/Emoji/D83CDF0A.png new file mode 100644 index 000000000..f844fdeb4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF0A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF0B.png b/Telegram/SourceFiles/art/Emoji/D83CDF0B.png new file mode 100644 index 000000000..76fecab42 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF0B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF0C.png b/Telegram/SourceFiles/art/Emoji/D83CDF0C.png new file mode 100644 index 000000000..8f503806f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF0C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF0D.png b/Telegram/SourceFiles/art/Emoji/D83CDF0D.png new file mode 100644 index 000000000..ab306db61 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF0D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF0E.png b/Telegram/SourceFiles/art/Emoji/D83CDF0E.png new file mode 100644 index 000000000..3ccaf4f1d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF0E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF0F.png b/Telegram/SourceFiles/art/Emoji/D83CDF0F.png new file mode 100644 index 000000000..5d3be0886 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF0F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF10.png b/Telegram/SourceFiles/art/Emoji/D83CDF10.png new file mode 100644 index 000000000..b5f35fb97 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF10.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF11.png b/Telegram/SourceFiles/art/Emoji/D83CDF11.png new file mode 100644 index 000000000..078260d6d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF11.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF12.png b/Telegram/SourceFiles/art/Emoji/D83CDF12.png new file mode 100644 index 000000000..d0a0f7296 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF12.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF13.png b/Telegram/SourceFiles/art/Emoji/D83CDF13.png new file mode 100644 index 000000000..2c7289657 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF13.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF14.png b/Telegram/SourceFiles/art/Emoji/D83CDF14.png new file mode 100644 index 000000000..66696d896 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF14.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF15.png b/Telegram/SourceFiles/art/Emoji/D83CDF15.png new file mode 100644 index 000000000..ff5c8e0fb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF15.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF16.png b/Telegram/SourceFiles/art/Emoji/D83CDF16.png new file mode 100644 index 000000000..63734dda3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF16.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF17.png b/Telegram/SourceFiles/art/Emoji/D83CDF17.png new file mode 100644 index 000000000..97e3de6fd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF17.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF18.png b/Telegram/SourceFiles/art/Emoji/D83CDF18.png new file mode 100644 index 000000000..13f8d9cb7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF18.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF19.png b/Telegram/SourceFiles/art/Emoji/D83CDF19.png new file mode 100644 index 000000000..4443ab354 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF19.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF1A.png b/Telegram/SourceFiles/art/Emoji/D83CDF1A.png new file mode 100644 index 000000000..48cf54e89 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF1A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF1B.png b/Telegram/SourceFiles/art/Emoji/D83CDF1B.png new file mode 100644 index 000000000..3f93634cc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF1B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF1C.png b/Telegram/SourceFiles/art/Emoji/D83CDF1C.png new file mode 100644 index 000000000..a57bf54d9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF1C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF1D.png b/Telegram/SourceFiles/art/Emoji/D83CDF1D.png new file mode 100644 index 000000000..c9829492b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF1D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF1E.png b/Telegram/SourceFiles/art/Emoji/D83CDF1E.png new file mode 100644 index 000000000..a78f6b1ff Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF1E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF1F.png b/Telegram/SourceFiles/art/Emoji/D83CDF1F.png new file mode 100644 index 000000000..a5aa95959 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF1F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF20.png b/Telegram/SourceFiles/art/Emoji/D83CDF20.png new file mode 100644 index 000000000..502a01740 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF20.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF30.png b/Telegram/SourceFiles/art/Emoji/D83CDF30.png new file mode 100644 index 000000000..ca0e78a11 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF30.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF31.png b/Telegram/SourceFiles/art/Emoji/D83CDF31.png new file mode 100644 index 000000000..e2a1224c3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF31.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF32.png b/Telegram/SourceFiles/art/Emoji/D83CDF32.png new file mode 100644 index 000000000..ea51b2b03 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF32.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF33.png b/Telegram/SourceFiles/art/Emoji/D83CDF33.png new file mode 100644 index 000000000..25ad311a3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF33.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF34.png b/Telegram/SourceFiles/art/Emoji/D83CDF34.png new file mode 100644 index 000000000..5d1fc8763 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF34.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF35.png b/Telegram/SourceFiles/art/Emoji/D83CDF35.png new file mode 100644 index 000000000..d9f1ebe7e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF35.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF37.png b/Telegram/SourceFiles/art/Emoji/D83CDF37.png new file mode 100644 index 000000000..58f4f4c41 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF37.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF38.png b/Telegram/SourceFiles/art/Emoji/D83CDF38.png new file mode 100644 index 000000000..3e76c6296 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF38.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF39.png b/Telegram/SourceFiles/art/Emoji/D83CDF39.png new file mode 100644 index 000000000..aec58deb6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF39.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF3A.png b/Telegram/SourceFiles/art/Emoji/D83CDF3A.png new file mode 100644 index 000000000..1b83115df Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF3A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF3B.png b/Telegram/SourceFiles/art/Emoji/D83CDF3B.png new file mode 100644 index 000000000..97da79226 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF3B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF3C.png b/Telegram/SourceFiles/art/Emoji/D83CDF3C.png new file mode 100644 index 000000000..cc737e74b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF3C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF3D.png b/Telegram/SourceFiles/art/Emoji/D83CDF3D.png new file mode 100644 index 000000000..648a2830c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF3D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF3E.png b/Telegram/SourceFiles/art/Emoji/D83CDF3E.png new file mode 100644 index 000000000..ecbf4cd36 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF3E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF3F.png b/Telegram/SourceFiles/art/Emoji/D83CDF3F.png new file mode 100644 index 000000000..dd5399e3b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF3F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF40.png b/Telegram/SourceFiles/art/Emoji/D83CDF40.png new file mode 100644 index 000000000..86ac7ed2c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF40.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF41.png b/Telegram/SourceFiles/art/Emoji/D83CDF41.png new file mode 100644 index 000000000..e2a9cdd46 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF41.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF42.png b/Telegram/SourceFiles/art/Emoji/D83CDF42.png new file mode 100644 index 000000000..640daa083 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF42.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF43.png b/Telegram/SourceFiles/art/Emoji/D83CDF43.png new file mode 100644 index 000000000..94773f8e3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF43.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF44.png b/Telegram/SourceFiles/art/Emoji/D83CDF44.png new file mode 100644 index 000000000..f1114e758 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF44.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF45.png b/Telegram/SourceFiles/art/Emoji/D83CDF45.png new file mode 100644 index 000000000..d11e09635 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF45.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF46.png b/Telegram/SourceFiles/art/Emoji/D83CDF46.png new file mode 100644 index 000000000..a0ea6fce6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF46.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF47.png b/Telegram/SourceFiles/art/Emoji/D83CDF47.png new file mode 100644 index 000000000..ffe08febc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF47.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF48.png b/Telegram/SourceFiles/art/Emoji/D83CDF48.png new file mode 100644 index 000000000..dd86e85d2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF48.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF49.png b/Telegram/SourceFiles/art/Emoji/D83CDF49.png new file mode 100644 index 000000000..45f804c99 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF49.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF4A.png b/Telegram/SourceFiles/art/Emoji/D83CDF4A.png new file mode 100644 index 000000000..7b3689ade Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF4A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF4B.png b/Telegram/SourceFiles/art/Emoji/D83CDF4B.png new file mode 100644 index 000000000..3fa9c850c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF4B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF4C.png b/Telegram/SourceFiles/art/Emoji/D83CDF4C.png new file mode 100644 index 000000000..700ff44f0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF4C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF4D.png b/Telegram/SourceFiles/art/Emoji/D83CDF4D.png new file mode 100644 index 000000000..9f1070eec Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF4D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF4E.png b/Telegram/SourceFiles/art/Emoji/D83CDF4E.png new file mode 100644 index 000000000..e360df0b4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF4E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF4F.png b/Telegram/SourceFiles/art/Emoji/D83CDF4F.png new file mode 100644 index 000000000..4f4292701 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF4F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF50.png b/Telegram/SourceFiles/art/Emoji/D83CDF50.png new file mode 100644 index 000000000..436b5800c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF50.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF51.png b/Telegram/SourceFiles/art/Emoji/D83CDF51.png new file mode 100644 index 000000000..677749f19 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF51.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF52.png b/Telegram/SourceFiles/art/Emoji/D83CDF52.png new file mode 100644 index 000000000..3069b8314 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF52.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF53.png b/Telegram/SourceFiles/art/Emoji/D83CDF53.png new file mode 100644 index 000000000..eeb27c83d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF53.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF54.png b/Telegram/SourceFiles/art/Emoji/D83CDF54.png new file mode 100644 index 000000000..8065a3e96 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF54.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF55.png b/Telegram/SourceFiles/art/Emoji/D83CDF55.png new file mode 100644 index 000000000..5cb956681 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF55.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF56.png b/Telegram/SourceFiles/art/Emoji/D83CDF56.png new file mode 100644 index 000000000..2c9d393b8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF56.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF57.png b/Telegram/SourceFiles/art/Emoji/D83CDF57.png new file mode 100644 index 000000000..d21ea0d97 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF57.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF58.png b/Telegram/SourceFiles/art/Emoji/D83CDF58.png new file mode 100644 index 000000000..948a08dc3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF58.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF59.png b/Telegram/SourceFiles/art/Emoji/D83CDF59.png new file mode 100644 index 000000000..61ab47ace Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF59.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF5A.png b/Telegram/SourceFiles/art/Emoji/D83CDF5A.png new file mode 100644 index 000000000..6cb325396 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF5A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF5B.png b/Telegram/SourceFiles/art/Emoji/D83CDF5B.png new file mode 100644 index 000000000..0a79679a7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF5B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF5C.png b/Telegram/SourceFiles/art/Emoji/D83CDF5C.png new file mode 100644 index 000000000..12fa5e970 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF5C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF5D.png b/Telegram/SourceFiles/art/Emoji/D83CDF5D.png new file mode 100644 index 000000000..f76f82acd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF5D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF5E.png b/Telegram/SourceFiles/art/Emoji/D83CDF5E.png new file mode 100644 index 000000000..281ddda19 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF5E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF5F.png b/Telegram/SourceFiles/art/Emoji/D83CDF5F.png new file mode 100644 index 000000000..0b4ca0418 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF5F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF60.png b/Telegram/SourceFiles/art/Emoji/D83CDF60.png new file mode 100644 index 000000000..d25bedc83 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF60.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF61.png b/Telegram/SourceFiles/art/Emoji/D83CDF61.png new file mode 100644 index 000000000..f8a228023 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF61.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF62.png b/Telegram/SourceFiles/art/Emoji/D83CDF62.png new file mode 100644 index 000000000..62a24bcd9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF62.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF63.png b/Telegram/SourceFiles/art/Emoji/D83CDF63.png new file mode 100644 index 000000000..361eb8125 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF63.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF64.png b/Telegram/SourceFiles/art/Emoji/D83CDF64.png new file mode 100644 index 000000000..5bd6768ae Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF64.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF65.png b/Telegram/SourceFiles/art/Emoji/D83CDF65.png new file mode 100644 index 000000000..a4809260e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF65.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF66.png b/Telegram/SourceFiles/art/Emoji/D83CDF66.png new file mode 100644 index 000000000..7d67e8e41 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF66.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF67.png b/Telegram/SourceFiles/art/Emoji/D83CDF67.png new file mode 100644 index 000000000..b88025d3d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF67.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF68.png b/Telegram/SourceFiles/art/Emoji/D83CDF68.png new file mode 100644 index 000000000..429f44e62 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF68.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF69.png b/Telegram/SourceFiles/art/Emoji/D83CDF69.png new file mode 100644 index 000000000..54efe4f0d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF69.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF6A.png b/Telegram/SourceFiles/art/Emoji/D83CDF6A.png new file mode 100644 index 000000000..a73950843 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF6A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF6B.png b/Telegram/SourceFiles/art/Emoji/D83CDF6B.png new file mode 100644 index 000000000..b16a6e04e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF6B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF6C.png b/Telegram/SourceFiles/art/Emoji/D83CDF6C.png new file mode 100644 index 000000000..b796b6ac2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF6C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF6D.png b/Telegram/SourceFiles/art/Emoji/D83CDF6D.png new file mode 100644 index 000000000..622f29617 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF6D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF6E.png b/Telegram/SourceFiles/art/Emoji/D83CDF6E.png new file mode 100644 index 000000000..c534a4b42 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF6E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF6F.png b/Telegram/SourceFiles/art/Emoji/D83CDF6F.png new file mode 100644 index 000000000..3f03181e7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF6F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF70.png b/Telegram/SourceFiles/art/Emoji/D83CDF70.png new file mode 100644 index 000000000..f930ce7a6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF70.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF71.png b/Telegram/SourceFiles/art/Emoji/D83CDF71.png new file mode 100644 index 000000000..0db1d7110 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF71.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF72.png b/Telegram/SourceFiles/art/Emoji/D83CDF72.png new file mode 100644 index 000000000..0ae27b185 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF72.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF73.png b/Telegram/SourceFiles/art/Emoji/D83CDF73.png new file mode 100644 index 000000000..5b7dcfa5e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF73.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF74.png b/Telegram/SourceFiles/art/Emoji/D83CDF74.png new file mode 100644 index 000000000..a15bf5984 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF74.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF75.png b/Telegram/SourceFiles/art/Emoji/D83CDF75.png new file mode 100644 index 000000000..cc30ad599 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF75.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF76.png b/Telegram/SourceFiles/art/Emoji/D83CDF76.png new file mode 100644 index 000000000..449d352c6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF76.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF77.png b/Telegram/SourceFiles/art/Emoji/D83CDF77.png new file mode 100644 index 000000000..12098c503 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF77.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF78.png b/Telegram/SourceFiles/art/Emoji/D83CDF78.png new file mode 100644 index 000000000..f4ed4ea28 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF78.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF79.png b/Telegram/SourceFiles/art/Emoji/D83CDF79.png new file mode 100644 index 000000000..ce34a5ff0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF79.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF7A.png b/Telegram/SourceFiles/art/Emoji/D83CDF7A.png new file mode 100644 index 000000000..e5efdaefe Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF7A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF7B.png b/Telegram/SourceFiles/art/Emoji/D83CDF7B.png new file mode 100644 index 000000000..f690c8003 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF7B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF7C.png b/Telegram/SourceFiles/art/Emoji/D83CDF7C.png new file mode 100644 index 000000000..81e6102ba Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF7C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF80.png b/Telegram/SourceFiles/art/Emoji/D83CDF80.png new file mode 100644 index 000000000..18bfbb4f7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF80.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF81.png b/Telegram/SourceFiles/art/Emoji/D83CDF81.png new file mode 100644 index 000000000..aa28c366a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF81.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF82.png b/Telegram/SourceFiles/art/Emoji/D83CDF82.png new file mode 100644 index 000000000..a9c0f5b8b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF82.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF83.png b/Telegram/SourceFiles/art/Emoji/D83CDF83.png new file mode 100644 index 000000000..d446cf6e9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF83.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF84.png b/Telegram/SourceFiles/art/Emoji/D83CDF84.png new file mode 100644 index 000000000..c86aa0ffd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF84.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF85.png b/Telegram/SourceFiles/art/Emoji/D83CDF85.png new file mode 100644 index 000000000..d9a4273e8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF85.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF86.png b/Telegram/SourceFiles/art/Emoji/D83CDF86.png new file mode 100644 index 000000000..3c07fafb1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF86.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF87.png b/Telegram/SourceFiles/art/Emoji/D83CDF87.png new file mode 100644 index 000000000..6fb75ec6d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF87.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF88.png b/Telegram/SourceFiles/art/Emoji/D83CDF88.png new file mode 100644 index 000000000..ad5167712 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF88.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF89.png b/Telegram/SourceFiles/art/Emoji/D83CDF89.png new file mode 100644 index 000000000..5c4d5597d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF89.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF8A.png b/Telegram/SourceFiles/art/Emoji/D83CDF8A.png new file mode 100644 index 000000000..7d5afa99a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF8A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF8B.png b/Telegram/SourceFiles/art/Emoji/D83CDF8B.png new file mode 100644 index 000000000..51c96fe3e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF8B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF8C.png b/Telegram/SourceFiles/art/Emoji/D83CDF8C.png new file mode 100644 index 000000000..f2f460b03 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF8C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF8D.png b/Telegram/SourceFiles/art/Emoji/D83CDF8D.png new file mode 100644 index 000000000..b83bebb4e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF8D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF8E.png b/Telegram/SourceFiles/art/Emoji/D83CDF8E.png new file mode 100644 index 000000000..734e849fe Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF8E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF8F.png b/Telegram/SourceFiles/art/Emoji/D83CDF8F.png new file mode 100644 index 000000000..a23ab7e77 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF8F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF90.png b/Telegram/SourceFiles/art/Emoji/D83CDF90.png new file mode 100644 index 000000000..7a282a3e0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF90.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF91.png b/Telegram/SourceFiles/art/Emoji/D83CDF91.png new file mode 100644 index 000000000..2c748d046 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF91.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF92.png b/Telegram/SourceFiles/art/Emoji/D83CDF92.png new file mode 100644 index 000000000..485bd1817 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF92.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDF93.png b/Telegram/SourceFiles/art/Emoji/D83CDF93.png new file mode 100644 index 000000000..5a601fe20 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDF93.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFA0.png b/Telegram/SourceFiles/art/Emoji/D83CDFA0.png new file mode 100644 index 000000000..0ba4267a8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFA0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFA1.png b/Telegram/SourceFiles/art/Emoji/D83CDFA1.png new file mode 100644 index 000000000..d59c5e566 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFA1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFA2.png b/Telegram/SourceFiles/art/Emoji/D83CDFA2.png new file mode 100644 index 000000000..3e8437b4b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFA2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFA3.png b/Telegram/SourceFiles/art/Emoji/D83CDFA3.png new file mode 100644 index 000000000..493f9f4df Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFA3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFA4.png b/Telegram/SourceFiles/art/Emoji/D83CDFA4.png new file mode 100644 index 000000000..8ad098873 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFA4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFA5.png b/Telegram/SourceFiles/art/Emoji/D83CDFA5.png new file mode 100644 index 000000000..d21fd0e41 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFA5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFA6.png b/Telegram/SourceFiles/art/Emoji/D83CDFA6.png new file mode 100644 index 000000000..e3a45c144 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFA6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFA7.png b/Telegram/SourceFiles/art/Emoji/D83CDFA7.png new file mode 100644 index 000000000..e351eff98 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFA7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFA8.png b/Telegram/SourceFiles/art/Emoji/D83CDFA8.png new file mode 100644 index 000000000..ef35ada5c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFA8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFA9.png b/Telegram/SourceFiles/art/Emoji/D83CDFA9.png new file mode 100644 index 000000000..27f6c29af Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFA9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFAA.png b/Telegram/SourceFiles/art/Emoji/D83CDFAA.png new file mode 100644 index 000000000..ccb34e0d9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFAA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFAB.png b/Telegram/SourceFiles/art/Emoji/D83CDFAB.png new file mode 100644 index 000000000..38e00dd65 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFAB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFAC.png b/Telegram/SourceFiles/art/Emoji/D83CDFAC.png new file mode 100644 index 000000000..6ddf1db3a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFAC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFAD.png b/Telegram/SourceFiles/art/Emoji/D83CDFAD.png new file mode 100644 index 000000000..ec9984263 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFAD.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFAE.png b/Telegram/SourceFiles/art/Emoji/D83CDFAE.png new file mode 100644 index 000000000..a94e3a663 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFAE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFAF.png b/Telegram/SourceFiles/art/Emoji/D83CDFAF.png new file mode 100644 index 000000000..b8aa1e16e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFAF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFB0.png b/Telegram/SourceFiles/art/Emoji/D83CDFB0.png new file mode 100644 index 000000000..a3c36cf36 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFB0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFB1.png b/Telegram/SourceFiles/art/Emoji/D83CDFB1.png new file mode 100644 index 000000000..efb17ad5c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFB1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFB2.png b/Telegram/SourceFiles/art/Emoji/D83CDFB2.png new file mode 100644 index 000000000..8fc6c037a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFB2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFB3.png b/Telegram/SourceFiles/art/Emoji/D83CDFB3.png new file mode 100644 index 000000000..c7459face Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFB3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFB4.png b/Telegram/SourceFiles/art/Emoji/D83CDFB4.png new file mode 100644 index 000000000..2090a8d33 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFB4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFB5.png b/Telegram/SourceFiles/art/Emoji/D83CDFB5.png new file mode 100644 index 000000000..e9c06839d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFB5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFB6.png b/Telegram/SourceFiles/art/Emoji/D83CDFB6.png new file mode 100644 index 000000000..956bc4daa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFB6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFB7.png b/Telegram/SourceFiles/art/Emoji/D83CDFB7.png new file mode 100644 index 000000000..4fde00598 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFB7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFB8.png b/Telegram/SourceFiles/art/Emoji/D83CDFB8.png new file mode 100644 index 000000000..584ba696e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFB8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFB9.png b/Telegram/SourceFiles/art/Emoji/D83CDFB9.png new file mode 100644 index 000000000..748a58743 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFB9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFBA.png b/Telegram/SourceFiles/art/Emoji/D83CDFBA.png new file mode 100644 index 000000000..77ca90e4f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFBA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFBB.png b/Telegram/SourceFiles/art/Emoji/D83CDFBB.png new file mode 100644 index 000000000..0f1b9a7ec Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFBB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFBC.png b/Telegram/SourceFiles/art/Emoji/D83CDFBC.png new file mode 100644 index 000000000..0441b7260 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFBC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFBD.png b/Telegram/SourceFiles/art/Emoji/D83CDFBD.png new file mode 100644 index 000000000..5d2beac39 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFBD.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFBE.png b/Telegram/SourceFiles/art/Emoji/D83CDFBE.png new file mode 100644 index 000000000..96e86051c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFBE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFBF.png b/Telegram/SourceFiles/art/Emoji/D83CDFBF.png new file mode 100644 index 000000000..79f2da345 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFBF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFC0.png b/Telegram/SourceFiles/art/Emoji/D83CDFC0.png new file mode 100644 index 000000000..8bf69e297 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFC0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFC1.png b/Telegram/SourceFiles/art/Emoji/D83CDFC1.png new file mode 100644 index 000000000..be1a59b60 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFC1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFC2.png b/Telegram/SourceFiles/art/Emoji/D83CDFC2.png new file mode 100644 index 000000000..9bdd6b444 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFC2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFC3.png b/Telegram/SourceFiles/art/Emoji/D83CDFC3.png new file mode 100644 index 000000000..d8c9cf3fa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFC3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFC4.png b/Telegram/SourceFiles/art/Emoji/D83CDFC4.png new file mode 100644 index 000000000..dbe988e83 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFC4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFC6.png b/Telegram/SourceFiles/art/Emoji/D83CDFC6.png new file mode 100644 index 000000000..ea7948793 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFC6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFC7.png b/Telegram/SourceFiles/art/Emoji/D83CDFC7.png new file mode 100644 index 000000000..130932220 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFC7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFC8.png b/Telegram/SourceFiles/art/Emoji/D83CDFC8.png new file mode 100644 index 000000000..4540605b8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFC8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFC9.png b/Telegram/SourceFiles/art/Emoji/D83CDFC9.png new file mode 100644 index 000000000..f4048b83b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFC9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFCA.png b/Telegram/SourceFiles/art/Emoji/D83CDFCA.png new file mode 100644 index 000000000..45aa9fb71 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFCA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFE0.png b/Telegram/SourceFiles/art/Emoji/D83CDFE0.png new file mode 100644 index 000000000..2fcd7b381 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFE0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFE1.png b/Telegram/SourceFiles/art/Emoji/D83CDFE1.png new file mode 100644 index 000000000..18ae9e645 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFE1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFE2.png b/Telegram/SourceFiles/art/Emoji/D83CDFE2.png new file mode 100644 index 000000000..4c73dcbb8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFE2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFE3.png b/Telegram/SourceFiles/art/Emoji/D83CDFE3.png new file mode 100644 index 000000000..dafcbb0da Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFE3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFE4.png b/Telegram/SourceFiles/art/Emoji/D83CDFE4.png new file mode 100644 index 000000000..32ec6cc50 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFE4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFE5.png b/Telegram/SourceFiles/art/Emoji/D83CDFE5.png new file mode 100644 index 000000000..05da811c2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFE5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFE6.png b/Telegram/SourceFiles/art/Emoji/D83CDFE6.png new file mode 100644 index 000000000..9d909979b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFE6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFE7.png b/Telegram/SourceFiles/art/Emoji/D83CDFE7.png new file mode 100644 index 000000000..452778238 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFE7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFE8.png b/Telegram/SourceFiles/art/Emoji/D83CDFE8.png new file mode 100644 index 000000000..a8586eef8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFE8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFE9.png b/Telegram/SourceFiles/art/Emoji/D83CDFE9.png new file mode 100644 index 000000000..54bc6d108 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFE9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFEA.png b/Telegram/SourceFiles/art/Emoji/D83CDFEA.png new file mode 100644 index 000000000..4060f516f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFEA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFEB.png b/Telegram/SourceFiles/art/Emoji/D83CDFEB.png new file mode 100644 index 000000000..0b2ec517c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFEB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFEC.png b/Telegram/SourceFiles/art/Emoji/D83CDFEC.png new file mode 100644 index 000000000..7b0d510ce Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFEC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFED.png b/Telegram/SourceFiles/art/Emoji/D83CDFED.png new file mode 100644 index 000000000..0ae5367f6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFED.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFEE.png b/Telegram/SourceFiles/art/Emoji/D83CDFEE.png new file mode 100644 index 000000000..55982b6e6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFEE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFEF.png b/Telegram/SourceFiles/art/Emoji/D83CDFEF.png new file mode 100644 index 000000000..1e446c807 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFEF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83CDFF0.png b/Telegram/SourceFiles/art/Emoji/D83CDFF0.png new file mode 100644 index 000000000..0db16f2ce Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83CDFF0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC00.png b/Telegram/SourceFiles/art/Emoji/D83DDC00.png new file mode 100644 index 000000000..f7982a4c6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC00.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC01.png b/Telegram/SourceFiles/art/Emoji/D83DDC01.png new file mode 100644 index 000000000..6d16b88de Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC01.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC02.png b/Telegram/SourceFiles/art/Emoji/D83DDC02.png new file mode 100644 index 000000000..4ec1cced1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC02.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC03.png b/Telegram/SourceFiles/art/Emoji/D83DDC03.png new file mode 100644 index 000000000..df9e28447 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC03.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC04.png b/Telegram/SourceFiles/art/Emoji/D83DDC04.png new file mode 100644 index 000000000..2d50aa00f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC04.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC05.png b/Telegram/SourceFiles/art/Emoji/D83DDC05.png new file mode 100644 index 000000000..94cb5f049 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC05.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC06.png b/Telegram/SourceFiles/art/Emoji/D83DDC06.png new file mode 100644 index 000000000..bb771a6b1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC06.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC07.png b/Telegram/SourceFiles/art/Emoji/D83DDC07.png new file mode 100644 index 000000000..53b553043 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC07.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC08.png b/Telegram/SourceFiles/art/Emoji/D83DDC08.png new file mode 100644 index 000000000..17991b36c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC08.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC09.png b/Telegram/SourceFiles/art/Emoji/D83DDC09.png new file mode 100644 index 000000000..6ce569d56 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC09.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC0A.png b/Telegram/SourceFiles/art/Emoji/D83DDC0A.png new file mode 100644 index 000000000..a8e76cbac Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC0A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC0B.png b/Telegram/SourceFiles/art/Emoji/D83DDC0B.png new file mode 100644 index 000000000..9cc51718a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC0B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC0C.png b/Telegram/SourceFiles/art/Emoji/D83DDC0C.png new file mode 100644 index 000000000..0d36155a5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC0C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC0D.png b/Telegram/SourceFiles/art/Emoji/D83DDC0D.png new file mode 100644 index 000000000..6b3817043 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC0D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC0E.png b/Telegram/SourceFiles/art/Emoji/D83DDC0E.png new file mode 100644 index 000000000..9080dd0e2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC0E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC0F.png b/Telegram/SourceFiles/art/Emoji/D83DDC0F.png new file mode 100644 index 000000000..e74447a80 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC0F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC10.png b/Telegram/SourceFiles/art/Emoji/D83DDC10.png new file mode 100644 index 000000000..070c46041 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC10.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC11.png b/Telegram/SourceFiles/art/Emoji/D83DDC11.png new file mode 100644 index 000000000..6f143a678 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC11.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC12.png b/Telegram/SourceFiles/art/Emoji/D83DDC12.png new file mode 100644 index 000000000..a584b4a70 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC12.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC13.png b/Telegram/SourceFiles/art/Emoji/D83DDC13.png new file mode 100644 index 000000000..ed3c077a1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC13.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC14.png b/Telegram/SourceFiles/art/Emoji/D83DDC14.png new file mode 100644 index 000000000..2e92ba265 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC14.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC15.png b/Telegram/SourceFiles/art/Emoji/D83DDC15.png new file mode 100644 index 000000000..d9fc6220d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC15.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC16.png b/Telegram/SourceFiles/art/Emoji/D83DDC16.png new file mode 100644 index 000000000..c3212776c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC16.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC17.png b/Telegram/SourceFiles/art/Emoji/D83DDC17.png new file mode 100644 index 000000000..0043f3cd1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC17.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC18.png b/Telegram/SourceFiles/art/Emoji/D83DDC18.png new file mode 100644 index 000000000..8a93ce9b3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC18.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC19.png b/Telegram/SourceFiles/art/Emoji/D83DDC19.png new file mode 100644 index 000000000..ac19c2dab Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC19.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC1A.png b/Telegram/SourceFiles/art/Emoji/D83DDC1A.png new file mode 100644 index 000000000..635ccfac6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC1A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC1B.png b/Telegram/SourceFiles/art/Emoji/D83DDC1B.png new file mode 100644 index 000000000..dccb76eae Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC1B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC1C.png b/Telegram/SourceFiles/art/Emoji/D83DDC1C.png new file mode 100644 index 000000000..73d740e30 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC1C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC1D.png b/Telegram/SourceFiles/art/Emoji/D83DDC1D.png new file mode 100644 index 000000000..1b49267cc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC1D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC1E.png b/Telegram/SourceFiles/art/Emoji/D83DDC1E.png new file mode 100644 index 000000000..d66de864e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC1E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC1F.png b/Telegram/SourceFiles/art/Emoji/D83DDC1F.png new file mode 100644 index 000000000..52f30a811 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC1F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC20.png b/Telegram/SourceFiles/art/Emoji/D83DDC20.png new file mode 100644 index 000000000..2b1e6446f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC20.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC21.png b/Telegram/SourceFiles/art/Emoji/D83DDC21.png new file mode 100644 index 000000000..279dc2e15 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC21.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC22.png b/Telegram/SourceFiles/art/Emoji/D83DDC22.png new file mode 100644 index 000000000..2314d9f99 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC22.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC23.png b/Telegram/SourceFiles/art/Emoji/D83DDC23.png new file mode 100644 index 000000000..7a6f8d5b5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC23.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC24.png b/Telegram/SourceFiles/art/Emoji/D83DDC24.png new file mode 100644 index 000000000..480fcf1fc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC24.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC25.png b/Telegram/SourceFiles/art/Emoji/D83DDC25.png new file mode 100644 index 000000000..6e05fed66 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC25.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC26.png b/Telegram/SourceFiles/art/Emoji/D83DDC26.png new file mode 100644 index 000000000..e53f64335 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC26.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC27.png b/Telegram/SourceFiles/art/Emoji/D83DDC27.png new file mode 100644 index 000000000..779766ce8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC27.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC28.png b/Telegram/SourceFiles/art/Emoji/D83DDC28.png new file mode 100644 index 000000000..cb6821ce0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC28.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC29.png b/Telegram/SourceFiles/art/Emoji/D83DDC29.png new file mode 100644 index 000000000..21a918263 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC29.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC2A.png b/Telegram/SourceFiles/art/Emoji/D83DDC2A.png new file mode 100644 index 000000000..a44d2e12a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC2A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC2B.png b/Telegram/SourceFiles/art/Emoji/D83DDC2B.png new file mode 100644 index 000000000..f09e1a33a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC2B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC2C.png b/Telegram/SourceFiles/art/Emoji/D83DDC2C.png new file mode 100644 index 000000000..2c855eb24 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC2C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC2D.png b/Telegram/SourceFiles/art/Emoji/D83DDC2D.png new file mode 100644 index 000000000..ff2e49a3a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC2D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC2E.png b/Telegram/SourceFiles/art/Emoji/D83DDC2E.png new file mode 100644 index 000000000..f95c3b91f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC2E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC2F.png b/Telegram/SourceFiles/art/Emoji/D83DDC2F.png new file mode 100644 index 000000000..359832955 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC2F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC30.png b/Telegram/SourceFiles/art/Emoji/D83DDC30.png new file mode 100644 index 000000000..3249366c3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC30.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC31.png b/Telegram/SourceFiles/art/Emoji/D83DDC31.png new file mode 100644 index 000000000..5a410e326 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC31.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC32.png b/Telegram/SourceFiles/art/Emoji/D83DDC32.png new file mode 100644 index 000000000..085713703 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC32.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC33.png b/Telegram/SourceFiles/art/Emoji/D83DDC33.png new file mode 100644 index 000000000..6f025da42 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC33.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC34.png b/Telegram/SourceFiles/art/Emoji/D83DDC34.png new file mode 100644 index 000000000..0be777d7b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC34.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC35.png b/Telegram/SourceFiles/art/Emoji/D83DDC35.png new file mode 100644 index 000000000..5ccdc028d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC35.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC36.png b/Telegram/SourceFiles/art/Emoji/D83DDC36.png new file mode 100644 index 000000000..50ff6c0aa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC36.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC37.png b/Telegram/SourceFiles/art/Emoji/D83DDC37.png new file mode 100644 index 000000000..78afd2c55 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC37.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC38.png b/Telegram/SourceFiles/art/Emoji/D83DDC38.png new file mode 100644 index 000000000..2141d1b62 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC38.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC39.png b/Telegram/SourceFiles/art/Emoji/D83DDC39.png new file mode 100644 index 000000000..775d8571c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC39.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC3A.png b/Telegram/SourceFiles/art/Emoji/D83DDC3A.png new file mode 100644 index 000000000..a2bbc5b63 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC3A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC3B.png b/Telegram/SourceFiles/art/Emoji/D83DDC3B.png new file mode 100644 index 000000000..6a91df894 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC3B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC3C.png b/Telegram/SourceFiles/art/Emoji/D83DDC3C.png new file mode 100644 index 000000000..58ecebc7c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC3C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC3D.png b/Telegram/SourceFiles/art/Emoji/D83DDC3D.png new file mode 100644 index 000000000..3863e975e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC3D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC3E.png b/Telegram/SourceFiles/art/Emoji/D83DDC3E.png new file mode 100644 index 000000000..288939d22 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC3E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC40.png b/Telegram/SourceFiles/art/Emoji/D83DDC40.png new file mode 100644 index 000000000..3a434193c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC40.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC42.png b/Telegram/SourceFiles/art/Emoji/D83DDC42.png new file mode 100644 index 000000000..baeb7b170 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC42.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC43.png b/Telegram/SourceFiles/art/Emoji/D83DDC43.png new file mode 100644 index 000000000..71af1e29f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC43.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC44.png b/Telegram/SourceFiles/art/Emoji/D83DDC44.png new file mode 100644 index 000000000..fd7a6e25c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC44.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC45.png b/Telegram/SourceFiles/art/Emoji/D83DDC45.png new file mode 100644 index 000000000..75aec779d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC45.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC46.png b/Telegram/SourceFiles/art/Emoji/D83DDC46.png new file mode 100644 index 000000000..d881fdb09 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC46.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC47.png b/Telegram/SourceFiles/art/Emoji/D83DDC47.png new file mode 100644 index 000000000..029274eec Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC47.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC48.png b/Telegram/SourceFiles/art/Emoji/D83DDC48.png new file mode 100644 index 000000000..7a68d8c87 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC48.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC49.png b/Telegram/SourceFiles/art/Emoji/D83DDC49.png new file mode 100644 index 000000000..db52a0d87 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC49.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC4A.png b/Telegram/SourceFiles/art/Emoji/D83DDC4A.png new file mode 100644 index 000000000..0026ab128 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC4A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC4B.png b/Telegram/SourceFiles/art/Emoji/D83DDC4B.png new file mode 100644 index 000000000..87d5bfe45 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC4B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC4C.png b/Telegram/SourceFiles/art/Emoji/D83DDC4C.png new file mode 100644 index 000000000..60b7abcee Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC4C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC4D.png b/Telegram/SourceFiles/art/Emoji/D83DDC4D.png new file mode 100644 index 000000000..2f816aa5d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC4D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC4E.png b/Telegram/SourceFiles/art/Emoji/D83DDC4E.png new file mode 100644 index 000000000..77732826c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC4E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC4F.png b/Telegram/SourceFiles/art/Emoji/D83DDC4F.png new file mode 100644 index 000000000..45a633a8e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC4F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC50.png b/Telegram/SourceFiles/art/Emoji/D83DDC50.png new file mode 100644 index 000000000..da6439150 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC50.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC51.png b/Telegram/SourceFiles/art/Emoji/D83DDC51.png new file mode 100644 index 000000000..0eeaeec65 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC51.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC52.png b/Telegram/SourceFiles/art/Emoji/D83DDC52.png new file mode 100644 index 000000000..897a33099 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC52.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC53.png b/Telegram/SourceFiles/art/Emoji/D83DDC53.png new file mode 100644 index 000000000..5b9b40171 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC53.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC54.png b/Telegram/SourceFiles/art/Emoji/D83DDC54.png new file mode 100644 index 000000000..fa76d908e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC54.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC55.png b/Telegram/SourceFiles/art/Emoji/D83DDC55.png new file mode 100644 index 000000000..23d1ebce7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC55.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC56.png b/Telegram/SourceFiles/art/Emoji/D83DDC56.png new file mode 100644 index 000000000..3d3656b8a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC56.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC57.png b/Telegram/SourceFiles/art/Emoji/D83DDC57.png new file mode 100644 index 000000000..14a977455 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC57.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC58.png b/Telegram/SourceFiles/art/Emoji/D83DDC58.png new file mode 100644 index 000000000..553cc6eab Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC58.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC59.png b/Telegram/SourceFiles/art/Emoji/D83DDC59.png new file mode 100644 index 000000000..4d2cfdeca Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC59.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC5A.png b/Telegram/SourceFiles/art/Emoji/D83DDC5A.png new file mode 100644 index 000000000..f72b865b1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC5A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC5B.png b/Telegram/SourceFiles/art/Emoji/D83DDC5B.png new file mode 100644 index 000000000..c5ea2ddfe Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC5B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC5C.png b/Telegram/SourceFiles/art/Emoji/D83DDC5C.png new file mode 100644 index 000000000..4fad011ba Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC5C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC5D.png b/Telegram/SourceFiles/art/Emoji/D83DDC5D.png new file mode 100644 index 000000000..ab72e0074 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC5D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC5E.png b/Telegram/SourceFiles/art/Emoji/D83DDC5E.png new file mode 100644 index 000000000..a3cf22a3e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC5E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC5F.png b/Telegram/SourceFiles/art/Emoji/D83DDC5F.png new file mode 100644 index 000000000..36f592bc6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC5F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC60.png b/Telegram/SourceFiles/art/Emoji/D83DDC60.png new file mode 100644 index 000000000..03325c82e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC60.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC61.png b/Telegram/SourceFiles/art/Emoji/D83DDC61.png new file mode 100644 index 000000000..e565a4226 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC61.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC62.png b/Telegram/SourceFiles/art/Emoji/D83DDC62.png new file mode 100644 index 000000000..445320ff1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC62.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC63.png b/Telegram/SourceFiles/art/Emoji/D83DDC63.png new file mode 100644 index 000000000..171c4c6f4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC63.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC64.png b/Telegram/SourceFiles/art/Emoji/D83DDC64.png new file mode 100644 index 000000000..ebd2d98d7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC64.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC65.png b/Telegram/SourceFiles/art/Emoji/D83DDC65.png new file mode 100644 index 000000000..67d500e7c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC65.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC66.png b/Telegram/SourceFiles/art/Emoji/D83DDC66.png new file mode 100644 index 000000000..00b77bc29 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC66.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC67.png b/Telegram/SourceFiles/art/Emoji/D83DDC67.png new file mode 100644 index 000000000..162941f5c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC67.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC68.png b/Telegram/SourceFiles/art/Emoji/D83DDC68.png new file mode 100644 index 000000000..37dfd2ade Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC68.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC69.png b/Telegram/SourceFiles/art/Emoji/D83DDC69.png new file mode 100644 index 000000000..176ad8fcf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC69.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC6A.png b/Telegram/SourceFiles/art/Emoji/D83DDC6A.png new file mode 100644 index 000000000..1009ac89b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC6A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC6B.png b/Telegram/SourceFiles/art/Emoji/D83DDC6B.png new file mode 100644 index 000000000..be243b4c7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC6B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC6C.png b/Telegram/SourceFiles/art/Emoji/D83DDC6C.png new file mode 100644 index 000000000..9a262f1d9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC6C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC6D.png b/Telegram/SourceFiles/art/Emoji/D83DDC6D.png new file mode 100644 index 000000000..217da2327 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC6D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC6E.png b/Telegram/SourceFiles/art/Emoji/D83DDC6E.png new file mode 100644 index 000000000..f389f634c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC6E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC6F.png b/Telegram/SourceFiles/art/Emoji/D83DDC6F.png new file mode 100644 index 000000000..6d1645b49 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC6F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC70.png b/Telegram/SourceFiles/art/Emoji/D83DDC70.png new file mode 100644 index 000000000..131117046 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC70.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC71.png b/Telegram/SourceFiles/art/Emoji/D83DDC71.png new file mode 100644 index 000000000..ca207b05a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC71.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC72.png b/Telegram/SourceFiles/art/Emoji/D83DDC72.png new file mode 100644 index 000000000..86dc32566 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC72.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC73.png b/Telegram/SourceFiles/art/Emoji/D83DDC73.png new file mode 100644 index 000000000..c5aada506 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC73.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC74.png b/Telegram/SourceFiles/art/Emoji/D83DDC74.png new file mode 100644 index 000000000..e007082f0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC74.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC75.png b/Telegram/SourceFiles/art/Emoji/D83DDC75.png new file mode 100644 index 000000000..1c70b19ea Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC75.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC76.png b/Telegram/SourceFiles/art/Emoji/D83DDC76.png new file mode 100644 index 000000000..3b23af431 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC76.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC77.png b/Telegram/SourceFiles/art/Emoji/D83DDC77.png new file mode 100644 index 000000000..65e396692 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC77.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC78.png b/Telegram/SourceFiles/art/Emoji/D83DDC78.png new file mode 100644 index 000000000..ccd0a43a6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC78.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC79.png b/Telegram/SourceFiles/art/Emoji/D83DDC79.png new file mode 100644 index 000000000..5b3e00967 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC79.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC7A.png b/Telegram/SourceFiles/art/Emoji/D83DDC7A.png new file mode 100644 index 000000000..e64950111 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC7A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC7B.png b/Telegram/SourceFiles/art/Emoji/D83DDC7B.png new file mode 100644 index 000000000..abc5fe22c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC7B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC7C.png b/Telegram/SourceFiles/art/Emoji/D83DDC7C.png new file mode 100644 index 000000000..4dec37dd0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC7C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC7D.png b/Telegram/SourceFiles/art/Emoji/D83DDC7D.png new file mode 100644 index 000000000..57db9bbd6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC7D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC7E.png b/Telegram/SourceFiles/art/Emoji/D83DDC7E.png new file mode 100644 index 000000000..854cae372 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC7E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC7F.png b/Telegram/SourceFiles/art/Emoji/D83DDC7F.png new file mode 100644 index 000000000..6283942ae Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC7F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC80.png b/Telegram/SourceFiles/art/Emoji/D83DDC80.png new file mode 100644 index 000000000..73f61d98f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC80.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC81.png b/Telegram/SourceFiles/art/Emoji/D83DDC81.png new file mode 100644 index 000000000..ec18497cc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC81.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC82.png b/Telegram/SourceFiles/art/Emoji/D83DDC82.png new file mode 100644 index 000000000..459186261 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC82.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC83.png b/Telegram/SourceFiles/art/Emoji/D83DDC83.png new file mode 100644 index 000000000..cae7c04bf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC83.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC84.png b/Telegram/SourceFiles/art/Emoji/D83DDC84.png new file mode 100644 index 000000000..514f9b08e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC84.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC85.png b/Telegram/SourceFiles/art/Emoji/D83DDC85.png new file mode 100644 index 000000000..9d85f43cc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC85.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC86.png b/Telegram/SourceFiles/art/Emoji/D83DDC86.png new file mode 100644 index 000000000..45b22d157 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC86.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC87.png b/Telegram/SourceFiles/art/Emoji/D83DDC87.png new file mode 100644 index 000000000..aa8ac455c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC87.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC88.png b/Telegram/SourceFiles/art/Emoji/D83DDC88.png new file mode 100644 index 000000000..04915436a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC88.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC89.png b/Telegram/SourceFiles/art/Emoji/D83DDC89.png new file mode 100644 index 000000000..c2151a219 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC89.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC8A.png b/Telegram/SourceFiles/art/Emoji/D83DDC8A.png new file mode 100644 index 000000000..1ee73302e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC8A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC8B.png b/Telegram/SourceFiles/art/Emoji/D83DDC8B.png new file mode 100644 index 000000000..c2ae15ec2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC8B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC8C.png b/Telegram/SourceFiles/art/Emoji/D83DDC8C.png new file mode 100644 index 000000000..9a0a3eb00 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC8C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC8D.png b/Telegram/SourceFiles/art/Emoji/D83DDC8D.png new file mode 100644 index 000000000..cde47d9fb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC8D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC8E.png b/Telegram/SourceFiles/art/Emoji/D83DDC8E.png new file mode 100644 index 000000000..d17d19cd9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC8E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC8F.png b/Telegram/SourceFiles/art/Emoji/D83DDC8F.png new file mode 100644 index 000000000..af81a7fbb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC8F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC90.png b/Telegram/SourceFiles/art/Emoji/D83DDC90.png new file mode 100644 index 000000000..41d16a32f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC90.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC91.png b/Telegram/SourceFiles/art/Emoji/D83DDC91.png new file mode 100644 index 000000000..2654b929a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC91.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC92.png b/Telegram/SourceFiles/art/Emoji/D83DDC92.png new file mode 100644 index 000000000..9146473e9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC92.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC93.png b/Telegram/SourceFiles/art/Emoji/D83DDC93.png new file mode 100644 index 000000000..d7f83e739 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC93.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC94.png b/Telegram/SourceFiles/art/Emoji/D83DDC94.png new file mode 100644 index 000000000..e02f1174d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC94.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC95.png b/Telegram/SourceFiles/art/Emoji/D83DDC95.png new file mode 100644 index 000000000..8757fb1df Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC95.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC96.png b/Telegram/SourceFiles/art/Emoji/D83DDC96.png new file mode 100644 index 000000000..c5b3bdcc5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC96.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC97.png b/Telegram/SourceFiles/art/Emoji/D83DDC97.png new file mode 100644 index 000000000..ab4de12dd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC97.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC98.png b/Telegram/SourceFiles/art/Emoji/D83DDC98.png new file mode 100644 index 000000000..2cee5aa57 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC98.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC99.png b/Telegram/SourceFiles/art/Emoji/D83DDC99.png new file mode 100644 index 000000000..a21bc71a5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC99.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC9A.png b/Telegram/SourceFiles/art/Emoji/D83DDC9A.png new file mode 100644 index 000000000..41bb4e67b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC9A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC9B.png b/Telegram/SourceFiles/art/Emoji/D83DDC9B.png new file mode 100644 index 000000000..8c538bee0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC9B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC9C.png b/Telegram/SourceFiles/art/Emoji/D83DDC9C.png new file mode 100644 index 000000000..1fdce8ec4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC9C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC9D.png b/Telegram/SourceFiles/art/Emoji/D83DDC9D.png new file mode 100644 index 000000000..df97fe9d0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC9D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC9E.png b/Telegram/SourceFiles/art/Emoji/D83DDC9E.png new file mode 100644 index 000000000..a4f9a41ef Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC9E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDC9F.png b/Telegram/SourceFiles/art/Emoji/D83DDC9F.png new file mode 100644 index 000000000..c4d1c4e2b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDC9F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCA0.png b/Telegram/SourceFiles/art/Emoji/D83DDCA0.png new file mode 100644 index 000000000..fc2c29f95 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCA0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCA1.png b/Telegram/SourceFiles/art/Emoji/D83DDCA1.png new file mode 100644 index 000000000..57a5d7f56 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCA1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCA2.png b/Telegram/SourceFiles/art/Emoji/D83DDCA2.png new file mode 100644 index 000000000..cff291f92 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCA2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCA3.png b/Telegram/SourceFiles/art/Emoji/D83DDCA3.png new file mode 100644 index 000000000..2b943e952 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCA3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCA4.png b/Telegram/SourceFiles/art/Emoji/D83DDCA4.png new file mode 100644 index 000000000..d25ffffc9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCA4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCA5.png b/Telegram/SourceFiles/art/Emoji/D83DDCA5.png new file mode 100644 index 000000000..4db5a0eab Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCA5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCA6.png b/Telegram/SourceFiles/art/Emoji/D83DDCA6.png new file mode 100644 index 000000000..758ce6d25 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCA6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCA7.png b/Telegram/SourceFiles/art/Emoji/D83DDCA7.png new file mode 100644 index 000000000..74c1d2b20 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCA7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCA8.png b/Telegram/SourceFiles/art/Emoji/D83DDCA8.png new file mode 100644 index 000000000..f8039e1a1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCA8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCA9.png b/Telegram/SourceFiles/art/Emoji/D83DDCA9.png new file mode 100644 index 000000000..a86877f45 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCA9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCAA.png b/Telegram/SourceFiles/art/Emoji/D83DDCAA.png new file mode 100644 index 000000000..5a1e68d29 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCAA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCAB.png b/Telegram/SourceFiles/art/Emoji/D83DDCAB.png new file mode 100644 index 000000000..999a66701 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCAB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCAC.png b/Telegram/SourceFiles/art/Emoji/D83DDCAC.png new file mode 100644 index 000000000..effcbbe78 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCAC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCAD.png b/Telegram/SourceFiles/art/Emoji/D83DDCAD.png new file mode 100644 index 000000000..f23fd2b12 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCAD.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCAE.png b/Telegram/SourceFiles/art/Emoji/D83DDCAE.png new file mode 100644 index 000000000..b9af846b2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCAE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCAF.png b/Telegram/SourceFiles/art/Emoji/D83DDCAF.png new file mode 100644 index 000000000..5fb88244d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCAF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCB0.png b/Telegram/SourceFiles/art/Emoji/D83DDCB0.png new file mode 100644 index 000000000..4b7d9ad23 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCB0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCB1.png b/Telegram/SourceFiles/art/Emoji/D83DDCB1.png new file mode 100644 index 000000000..fea93466a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCB1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCB2.png b/Telegram/SourceFiles/art/Emoji/D83DDCB2.png new file mode 100644 index 000000000..4e83e7707 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCB2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCB3.png b/Telegram/SourceFiles/art/Emoji/D83DDCB3.png new file mode 100644 index 000000000..6141cec48 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCB3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCB4.png b/Telegram/SourceFiles/art/Emoji/D83DDCB4.png new file mode 100644 index 000000000..9f6bda273 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCB4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCB5.png b/Telegram/SourceFiles/art/Emoji/D83DDCB5.png new file mode 100644 index 000000000..d27fb53f6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCB5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCB6.png b/Telegram/SourceFiles/art/Emoji/D83DDCB6.png new file mode 100644 index 000000000..b4d6405a3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCB6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCB7.png b/Telegram/SourceFiles/art/Emoji/D83DDCB7.png new file mode 100644 index 000000000..e1f552602 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCB7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCB8.png b/Telegram/SourceFiles/art/Emoji/D83DDCB8.png new file mode 100644 index 000000000..20240f82e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCB8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCB9.png b/Telegram/SourceFiles/art/Emoji/D83DDCB9.png new file mode 100644 index 000000000..ba319c937 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCB9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCBA.png b/Telegram/SourceFiles/art/Emoji/D83DDCBA.png new file mode 100644 index 000000000..4a9e28013 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCBA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCBB.png b/Telegram/SourceFiles/art/Emoji/D83DDCBB.png new file mode 100644 index 000000000..d4f6546f7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCBB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCBC.png b/Telegram/SourceFiles/art/Emoji/D83DDCBC.png new file mode 100644 index 000000000..4f7011c0c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCBC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCBD.png b/Telegram/SourceFiles/art/Emoji/D83DDCBD.png new file mode 100644 index 000000000..d2e416e21 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCBD.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCBE.png b/Telegram/SourceFiles/art/Emoji/D83DDCBE.png new file mode 100644 index 000000000..de1a1c045 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCBE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCBF.png b/Telegram/SourceFiles/art/Emoji/D83DDCBF.png new file mode 100644 index 000000000..38c906b95 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCBF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCC0.png b/Telegram/SourceFiles/art/Emoji/D83DDCC0.png new file mode 100644 index 000000000..da3cd5d7c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCC0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCC1.png b/Telegram/SourceFiles/art/Emoji/D83DDCC1.png new file mode 100644 index 000000000..f37868d90 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCC1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCC2.png b/Telegram/SourceFiles/art/Emoji/D83DDCC2.png new file mode 100644 index 000000000..4b727ddaf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCC2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCC3.png b/Telegram/SourceFiles/art/Emoji/D83DDCC3.png new file mode 100644 index 000000000..08f5dc18e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCC3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCC4.png b/Telegram/SourceFiles/art/Emoji/D83DDCC4.png new file mode 100644 index 000000000..33665a175 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCC4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCC5.png b/Telegram/SourceFiles/art/Emoji/D83DDCC5.png new file mode 100644 index 000000000..b4c0e8ca3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCC5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCC6.png b/Telegram/SourceFiles/art/Emoji/D83DDCC6.png new file mode 100644 index 000000000..698aabb9f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCC6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCC7.png b/Telegram/SourceFiles/art/Emoji/D83DDCC7.png new file mode 100644 index 000000000..e1b35a1d8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCC7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCC8.png b/Telegram/SourceFiles/art/Emoji/D83DDCC8.png new file mode 100644 index 000000000..ddaa706fd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCC8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCC9.png b/Telegram/SourceFiles/art/Emoji/D83DDCC9.png new file mode 100644 index 000000000..7b956c69f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCC9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCCA.png b/Telegram/SourceFiles/art/Emoji/D83DDCCA.png new file mode 100644 index 000000000..4778f38b4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCCA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCCB.png b/Telegram/SourceFiles/art/Emoji/D83DDCCB.png new file mode 100644 index 000000000..2d0720dd9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCCB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCCC.png b/Telegram/SourceFiles/art/Emoji/D83DDCCC.png new file mode 100644 index 000000000..9735ecaaa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCCC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCCD.png b/Telegram/SourceFiles/art/Emoji/D83DDCCD.png new file mode 100644 index 000000000..f50854a6f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCCD.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCCE.png b/Telegram/SourceFiles/art/Emoji/D83DDCCE.png new file mode 100644 index 000000000..ce86e8b26 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCCE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCCF.png b/Telegram/SourceFiles/art/Emoji/D83DDCCF.png new file mode 100644 index 000000000..8aa5e8f5e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCCF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCD0.png b/Telegram/SourceFiles/art/Emoji/D83DDCD0.png new file mode 100644 index 000000000..f6379989a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCD0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCD1.png b/Telegram/SourceFiles/art/Emoji/D83DDCD1.png new file mode 100644 index 000000000..c0a4b779b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCD1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCD2.png b/Telegram/SourceFiles/art/Emoji/D83DDCD2.png new file mode 100644 index 000000000..400cf7b6b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCD2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCD3.png b/Telegram/SourceFiles/art/Emoji/D83DDCD3.png new file mode 100644 index 000000000..930e01fea Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCD3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCD4.png b/Telegram/SourceFiles/art/Emoji/D83DDCD4.png new file mode 100644 index 000000000..b26265e4b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCD4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCD5.png b/Telegram/SourceFiles/art/Emoji/D83DDCD5.png new file mode 100644 index 000000000..06d336472 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCD5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCD6.png b/Telegram/SourceFiles/art/Emoji/D83DDCD6.png new file mode 100644 index 000000000..be0ef9ca1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCD6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCD7.png b/Telegram/SourceFiles/art/Emoji/D83DDCD7.png new file mode 100644 index 000000000..1b3f7b7f4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCD7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCD8.png b/Telegram/SourceFiles/art/Emoji/D83DDCD8.png new file mode 100644 index 000000000..7cb1ac919 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCD8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCD9.png b/Telegram/SourceFiles/art/Emoji/D83DDCD9.png new file mode 100644 index 000000000..ecf7d465f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCD9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCDA.png b/Telegram/SourceFiles/art/Emoji/D83DDCDA.png new file mode 100644 index 000000000..2ebfaf0aa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCDA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCDB.png b/Telegram/SourceFiles/art/Emoji/D83DDCDB.png new file mode 100644 index 000000000..36a9b0ffc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCDB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCDC.png b/Telegram/SourceFiles/art/Emoji/D83DDCDC.png new file mode 100644 index 000000000..056647b69 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCDC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCDD.png b/Telegram/SourceFiles/art/Emoji/D83DDCDD.png new file mode 100644 index 000000000..35e9942d6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCDD.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCDE.png b/Telegram/SourceFiles/art/Emoji/D83DDCDE.png new file mode 100644 index 000000000..20ba9ba64 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCDE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCDF.png b/Telegram/SourceFiles/art/Emoji/D83DDCDF.png new file mode 100644 index 000000000..8d932d2c1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCDF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCE0.png b/Telegram/SourceFiles/art/Emoji/D83DDCE0.png new file mode 100644 index 000000000..781669ead Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCE0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCE1.png b/Telegram/SourceFiles/art/Emoji/D83DDCE1.png new file mode 100644 index 000000000..c2a3bc9a8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCE1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCE2.png b/Telegram/SourceFiles/art/Emoji/D83DDCE2.png new file mode 100644 index 000000000..4c3be3e30 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCE2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCE3.png b/Telegram/SourceFiles/art/Emoji/D83DDCE3.png new file mode 100644 index 000000000..584786765 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCE3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCE4.png b/Telegram/SourceFiles/art/Emoji/D83DDCE4.png new file mode 100644 index 000000000..0e6254dff Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCE4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCE5.png b/Telegram/SourceFiles/art/Emoji/D83DDCE5.png new file mode 100644 index 000000000..6a731d10b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCE5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCE6.png b/Telegram/SourceFiles/art/Emoji/D83DDCE6.png new file mode 100644 index 000000000..4d3f70114 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCE6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCE7.png b/Telegram/SourceFiles/art/Emoji/D83DDCE7.png new file mode 100644 index 000000000..5bd245493 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCE7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCE8.png b/Telegram/SourceFiles/art/Emoji/D83DDCE8.png new file mode 100644 index 000000000..446ff9796 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCE8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCE9.png b/Telegram/SourceFiles/art/Emoji/D83DDCE9.png new file mode 100644 index 000000000..b7b83f539 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCE9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCEA.png b/Telegram/SourceFiles/art/Emoji/D83DDCEA.png new file mode 100644 index 000000000..ec474bed8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCEA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCEB.png b/Telegram/SourceFiles/art/Emoji/D83DDCEB.png new file mode 100644 index 000000000..4239a5a16 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCEB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCEC.png b/Telegram/SourceFiles/art/Emoji/D83DDCEC.png new file mode 100644 index 000000000..4289c26a7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCEC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCED.png b/Telegram/SourceFiles/art/Emoji/D83DDCED.png new file mode 100644 index 000000000..20847402f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCED.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCEE.png b/Telegram/SourceFiles/art/Emoji/D83DDCEE.png new file mode 100644 index 000000000..e50f686e3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCEE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCEF.png b/Telegram/SourceFiles/art/Emoji/D83DDCEF.png new file mode 100644 index 000000000..2e33772f0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCEF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCF0.png b/Telegram/SourceFiles/art/Emoji/D83DDCF0.png new file mode 100644 index 000000000..016fa96bc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCF0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCF1.png b/Telegram/SourceFiles/art/Emoji/D83DDCF1.png new file mode 100644 index 000000000..cc722ad2b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCF1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCF2.png b/Telegram/SourceFiles/art/Emoji/D83DDCF2.png new file mode 100644 index 000000000..c95466188 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCF2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCF3.png b/Telegram/SourceFiles/art/Emoji/D83DDCF3.png new file mode 100644 index 000000000..687897b8c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCF3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCF4.png b/Telegram/SourceFiles/art/Emoji/D83DDCF4.png new file mode 100644 index 000000000..0547aba37 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCF4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCF5.png b/Telegram/SourceFiles/art/Emoji/D83DDCF5.png new file mode 100644 index 000000000..136b78a94 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCF5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCF6.png b/Telegram/SourceFiles/art/Emoji/D83DDCF6.png new file mode 100644 index 000000000..68a63e0fd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCF6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCF7.png b/Telegram/SourceFiles/art/Emoji/D83DDCF7.png new file mode 100644 index 000000000..d38227ef0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCF7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCF9.png b/Telegram/SourceFiles/art/Emoji/D83DDCF9.png new file mode 100644 index 000000000..6cb3b3608 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCF9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCFA.png b/Telegram/SourceFiles/art/Emoji/D83DDCFA.png new file mode 100644 index 000000000..c282230a2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCFA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCFB.png b/Telegram/SourceFiles/art/Emoji/D83DDCFB.png new file mode 100644 index 000000000..173b13ced Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCFB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDCFC.png b/Telegram/SourceFiles/art/Emoji/D83DDCFC.png new file mode 100644 index 000000000..7c71a8143 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDCFC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD00.png b/Telegram/SourceFiles/art/Emoji/D83DDD00.png new file mode 100644 index 000000000..03465b513 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD00.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD01.png b/Telegram/SourceFiles/art/Emoji/D83DDD01.png new file mode 100644 index 000000000..bc521ef6a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD01.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD02.png b/Telegram/SourceFiles/art/Emoji/D83DDD02.png new file mode 100644 index 000000000..41ac49297 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD02.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD03.png b/Telegram/SourceFiles/art/Emoji/D83DDD03.png new file mode 100644 index 000000000..6f24b204f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD03.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD04.png b/Telegram/SourceFiles/art/Emoji/D83DDD04.png new file mode 100644 index 000000000..6255482cd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD04.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD05.png b/Telegram/SourceFiles/art/Emoji/D83DDD05.png new file mode 100644 index 000000000..0fd3e11c5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD05.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD06.png b/Telegram/SourceFiles/art/Emoji/D83DDD06.png new file mode 100644 index 000000000..7df3172b9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD06.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD07.png b/Telegram/SourceFiles/art/Emoji/D83DDD07.png new file mode 100644 index 000000000..ff3769cab Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD07.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD08.png b/Telegram/SourceFiles/art/Emoji/D83DDD08.png new file mode 100644 index 000000000..b5c7b283e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD08.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD09.png b/Telegram/SourceFiles/art/Emoji/D83DDD09.png new file mode 100644 index 000000000..a51efc8f8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD09.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD0A.png b/Telegram/SourceFiles/art/Emoji/D83DDD0A.png new file mode 100644 index 000000000..c1fcf4d36 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD0A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD0B.png b/Telegram/SourceFiles/art/Emoji/D83DDD0B.png new file mode 100644 index 000000000..fd3e3d2ac Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD0B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD0C.png b/Telegram/SourceFiles/art/Emoji/D83DDD0C.png new file mode 100644 index 000000000..0317018ee Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD0C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD0D.png b/Telegram/SourceFiles/art/Emoji/D83DDD0D.png new file mode 100644 index 000000000..2bdf40b33 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD0D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD0E.png b/Telegram/SourceFiles/art/Emoji/D83DDD0E.png new file mode 100644 index 000000000..d9a8b8ac5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD0E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD0F.png b/Telegram/SourceFiles/art/Emoji/D83DDD0F.png new file mode 100644 index 000000000..3dc1ea093 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD0F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD10.png b/Telegram/SourceFiles/art/Emoji/D83DDD10.png new file mode 100644 index 000000000..42104282a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD10.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD11.png b/Telegram/SourceFiles/art/Emoji/D83DDD11.png new file mode 100644 index 000000000..c60bcad4d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD11.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD12.png b/Telegram/SourceFiles/art/Emoji/D83DDD12.png new file mode 100644 index 000000000..8a680cfbc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD12.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD13.png b/Telegram/SourceFiles/art/Emoji/D83DDD13.png new file mode 100644 index 000000000..bfc3b9b4a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD13.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD14.png b/Telegram/SourceFiles/art/Emoji/D83DDD14.png new file mode 100644 index 000000000..937d445a8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD14.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD15.png b/Telegram/SourceFiles/art/Emoji/D83DDD15.png new file mode 100644 index 000000000..135191fcd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD15.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD16.png b/Telegram/SourceFiles/art/Emoji/D83DDD16.png new file mode 100644 index 000000000..8081be264 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD16.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD17.png b/Telegram/SourceFiles/art/Emoji/D83DDD17.png new file mode 100644 index 000000000..fbab54d69 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD17.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD18.png b/Telegram/SourceFiles/art/Emoji/D83DDD18.png new file mode 100644 index 000000000..978796588 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD18.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD19.png b/Telegram/SourceFiles/art/Emoji/D83DDD19.png new file mode 100644 index 000000000..ed66b43c0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD19.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD1A.png b/Telegram/SourceFiles/art/Emoji/D83DDD1A.png new file mode 100644 index 000000000..adcdb79ff Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD1A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD1B.png b/Telegram/SourceFiles/art/Emoji/D83DDD1B.png new file mode 100644 index 000000000..956d7d798 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD1B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD1C.png b/Telegram/SourceFiles/art/Emoji/D83DDD1C.png new file mode 100644 index 000000000..72d88f59d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD1C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD1D.png b/Telegram/SourceFiles/art/Emoji/D83DDD1D.png new file mode 100644 index 000000000..940a84d56 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD1D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD1E.png b/Telegram/SourceFiles/art/Emoji/D83DDD1E.png new file mode 100644 index 000000000..4577ba883 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD1E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD1F.png b/Telegram/SourceFiles/art/Emoji/D83DDD1F.png new file mode 100644 index 000000000..9533fa00c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD1F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD20.png b/Telegram/SourceFiles/art/Emoji/D83DDD20.png new file mode 100644 index 000000000..74e29fab0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD20.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD21.png b/Telegram/SourceFiles/art/Emoji/D83DDD21.png new file mode 100644 index 000000000..c77b49a46 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD21.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD22.png b/Telegram/SourceFiles/art/Emoji/D83DDD22.png new file mode 100644 index 000000000..841012e2d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD22.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD23.png b/Telegram/SourceFiles/art/Emoji/D83DDD23.png new file mode 100644 index 000000000..8320fa329 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD23.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD24.png b/Telegram/SourceFiles/art/Emoji/D83DDD24.png new file mode 100644 index 000000000..eeb066655 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD24.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD25.png b/Telegram/SourceFiles/art/Emoji/D83DDD25.png new file mode 100644 index 000000000..f4db0d90b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD25.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD26.png b/Telegram/SourceFiles/art/Emoji/D83DDD26.png new file mode 100644 index 000000000..78acca90a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD26.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD27.png b/Telegram/SourceFiles/art/Emoji/D83DDD27.png new file mode 100644 index 000000000..9a424b438 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD27.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD28.png b/Telegram/SourceFiles/art/Emoji/D83DDD28.png new file mode 100644 index 000000000..0193fc1d8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD28.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD29.png b/Telegram/SourceFiles/art/Emoji/D83DDD29.png new file mode 100644 index 000000000..7eaa1d62a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD29.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD2A.png b/Telegram/SourceFiles/art/Emoji/D83DDD2A.png new file mode 100644 index 000000000..02c024a51 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD2A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD2B.png b/Telegram/SourceFiles/art/Emoji/D83DDD2B.png new file mode 100644 index 000000000..40cd7f9d4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD2B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD2C.png b/Telegram/SourceFiles/art/Emoji/D83DDD2C.png new file mode 100644 index 000000000..014727134 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD2C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD2D.png b/Telegram/SourceFiles/art/Emoji/D83DDD2D.png new file mode 100644 index 000000000..450c039fd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD2D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD2E.png b/Telegram/SourceFiles/art/Emoji/D83DDD2E.png new file mode 100644 index 000000000..2c056bfc2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD2E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD2F.png b/Telegram/SourceFiles/art/Emoji/D83DDD2F.png new file mode 100644 index 000000000..f6fb36231 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD2F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD30.png b/Telegram/SourceFiles/art/Emoji/D83DDD30.png new file mode 100644 index 000000000..aff5d8a6b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD30.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD31.png b/Telegram/SourceFiles/art/Emoji/D83DDD31.png new file mode 100644 index 000000000..d115de5bd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD31.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD32.png b/Telegram/SourceFiles/art/Emoji/D83DDD32.png new file mode 100644 index 000000000..f0c6e28bd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD32.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD33.png b/Telegram/SourceFiles/art/Emoji/D83DDD33.png new file mode 100644 index 000000000..9b0a44d4d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD33.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD34.png b/Telegram/SourceFiles/art/Emoji/D83DDD34.png new file mode 100644 index 000000000..a1b4491ec Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD34.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD35.png b/Telegram/SourceFiles/art/Emoji/D83DDD35.png new file mode 100644 index 000000000..e7460124d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD35.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD36.png b/Telegram/SourceFiles/art/Emoji/D83DDD36.png new file mode 100644 index 000000000..2d3c57d19 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD36.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD37.png b/Telegram/SourceFiles/art/Emoji/D83DDD37.png new file mode 100644 index 000000000..7fea98d2b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD37.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD38.png b/Telegram/SourceFiles/art/Emoji/D83DDD38.png new file mode 100644 index 000000000..136df5169 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD38.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD39.png b/Telegram/SourceFiles/art/Emoji/D83DDD39.png new file mode 100644 index 000000000..00a0c43de Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD39.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD3A.png b/Telegram/SourceFiles/art/Emoji/D83DDD3A.png new file mode 100644 index 000000000..8f7b1d390 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD3A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD3B.png b/Telegram/SourceFiles/art/Emoji/D83DDD3B.png new file mode 100644 index 000000000..e980342d8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD3B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD3C.png b/Telegram/SourceFiles/art/Emoji/D83DDD3C.png new file mode 100644 index 000000000..c5f37cb71 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD3C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD3D.png b/Telegram/SourceFiles/art/Emoji/D83DDD3D.png new file mode 100644 index 000000000..d887596dd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD3D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD50.png b/Telegram/SourceFiles/art/Emoji/D83DDD50.png new file mode 100644 index 000000000..f916852fb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD50.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD51.png b/Telegram/SourceFiles/art/Emoji/D83DDD51.png new file mode 100644 index 000000000..3b080e668 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD51.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD52.png b/Telegram/SourceFiles/art/Emoji/D83DDD52.png new file mode 100644 index 000000000..a6d62d1f2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD52.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD53.png b/Telegram/SourceFiles/art/Emoji/D83DDD53.png new file mode 100644 index 000000000..d151c69bd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD53.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD54.png b/Telegram/SourceFiles/art/Emoji/D83DDD54.png new file mode 100644 index 000000000..89034d2ec Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD54.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD55.png b/Telegram/SourceFiles/art/Emoji/D83DDD55.png new file mode 100644 index 000000000..256b44146 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD55.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD56.png b/Telegram/SourceFiles/art/Emoji/D83DDD56.png new file mode 100644 index 000000000..b748e6a73 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD56.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD57.png b/Telegram/SourceFiles/art/Emoji/D83DDD57.png new file mode 100644 index 000000000..03d61d03b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD57.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD58.png b/Telegram/SourceFiles/art/Emoji/D83DDD58.png new file mode 100644 index 000000000..f3af8b163 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD58.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD59.png b/Telegram/SourceFiles/art/Emoji/D83DDD59.png new file mode 100644 index 000000000..7eaa84c6f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD59.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD5A.png b/Telegram/SourceFiles/art/Emoji/D83DDD5A.png new file mode 100644 index 000000000..ca4a1b703 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD5A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD5B.png b/Telegram/SourceFiles/art/Emoji/D83DDD5B.png new file mode 100644 index 000000000..cb1a87d63 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD5B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD5C.png b/Telegram/SourceFiles/art/Emoji/D83DDD5C.png new file mode 100644 index 000000000..1dba0c0d3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD5C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD5D.png b/Telegram/SourceFiles/art/Emoji/D83DDD5D.png new file mode 100644 index 000000000..28d50d044 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD5D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD5E.png b/Telegram/SourceFiles/art/Emoji/D83DDD5E.png new file mode 100644 index 000000000..09194e1cc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD5E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD5F.png b/Telegram/SourceFiles/art/Emoji/D83DDD5F.png new file mode 100644 index 000000000..32d1ddc71 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD5F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD60.png b/Telegram/SourceFiles/art/Emoji/D83DDD60.png new file mode 100644 index 000000000..8fad34eb6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD60.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD61.png b/Telegram/SourceFiles/art/Emoji/D83DDD61.png new file mode 100644 index 000000000..1403edc4c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD61.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD62.png b/Telegram/SourceFiles/art/Emoji/D83DDD62.png new file mode 100644 index 000000000..666436d28 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD62.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD63.png b/Telegram/SourceFiles/art/Emoji/D83DDD63.png new file mode 100644 index 000000000..d4c7fecfe Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD63.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD64.png b/Telegram/SourceFiles/art/Emoji/D83DDD64.png new file mode 100644 index 000000000..2b7105239 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD64.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD65.png b/Telegram/SourceFiles/art/Emoji/D83DDD65.png new file mode 100644 index 000000000..416e00426 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD65.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD66.png b/Telegram/SourceFiles/art/Emoji/D83DDD66.png new file mode 100644 index 000000000..ef3e23f93 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD66.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDD67.png b/Telegram/SourceFiles/art/Emoji/D83DDD67.png new file mode 100644 index 000000000..5910b2e35 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDD67.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDDFB.png b/Telegram/SourceFiles/art/Emoji/D83DDDFB.png new file mode 100644 index 000000000..cdecd76a6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDDFB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDDFC.png b/Telegram/SourceFiles/art/Emoji/D83DDDFC.png new file mode 100644 index 000000000..ea72808c4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDDFC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDDFD.png b/Telegram/SourceFiles/art/Emoji/D83DDDFD.png new file mode 100644 index 000000000..899fe6ec5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDDFD.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDDFE.png b/Telegram/SourceFiles/art/Emoji/D83DDDFE.png new file mode 100644 index 000000000..bd3ca85e1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDDFE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDDFF.png b/Telegram/SourceFiles/art/Emoji/D83DDDFF.png new file mode 100644 index 000000000..bb6cad653 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDDFF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE00.png b/Telegram/SourceFiles/art/Emoji/D83DDE00.png new file mode 100644 index 000000000..e7cbe1d4e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE00.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE01.png b/Telegram/SourceFiles/art/Emoji/D83DDE01.png new file mode 100644 index 000000000..deee5ea51 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE01.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE02.png b/Telegram/SourceFiles/art/Emoji/D83DDE02.png new file mode 100644 index 000000000..89190faa2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE02.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE03.png b/Telegram/SourceFiles/art/Emoji/D83DDE03.png new file mode 100644 index 000000000..be04f6cfe Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE03.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE04.png b/Telegram/SourceFiles/art/Emoji/D83DDE04.png new file mode 100644 index 000000000..435b0ca2a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE04.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE05.png b/Telegram/SourceFiles/art/Emoji/D83DDE05.png new file mode 100644 index 000000000..2aaf1b772 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE05.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE06.png b/Telegram/SourceFiles/art/Emoji/D83DDE06.png new file mode 100644 index 000000000..f3f1c7e67 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE06.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE07.png b/Telegram/SourceFiles/art/Emoji/D83DDE07.png new file mode 100644 index 000000000..00ddb6e1e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE07.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE08.png b/Telegram/SourceFiles/art/Emoji/D83DDE08.png new file mode 100644 index 000000000..b775c5151 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE08.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE09.png b/Telegram/SourceFiles/art/Emoji/D83DDE09.png new file mode 100644 index 000000000..5eccad2d1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE09.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE0A.png b/Telegram/SourceFiles/art/Emoji/D83DDE0A.png new file mode 100644 index 000000000..288549441 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE0A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE0B.png b/Telegram/SourceFiles/art/Emoji/D83DDE0B.png new file mode 100644 index 000000000..83c0e8301 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE0B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE0C.png b/Telegram/SourceFiles/art/Emoji/D83DDE0C.png new file mode 100644 index 000000000..b8a367a56 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE0C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE0D.png b/Telegram/SourceFiles/art/Emoji/D83DDE0D.png new file mode 100644 index 000000000..6fdf5c6e0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE0D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE0E.png b/Telegram/SourceFiles/art/Emoji/D83DDE0E.png new file mode 100644 index 000000000..8c1b63f01 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE0E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE0F.png b/Telegram/SourceFiles/art/Emoji/D83DDE0F.png new file mode 100644 index 000000000..cd36ee7d9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE0F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE10.png b/Telegram/SourceFiles/art/Emoji/D83DDE10.png new file mode 100644 index 000000000..f5b9b1251 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE10.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE11.png b/Telegram/SourceFiles/art/Emoji/D83DDE11.png new file mode 100644 index 000000000..47648dff9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE11.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE12.png b/Telegram/SourceFiles/art/Emoji/D83DDE12.png new file mode 100644 index 000000000..bfd07f9f9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE12.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE13.png b/Telegram/SourceFiles/art/Emoji/D83DDE13.png new file mode 100644 index 000000000..9812eea77 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE13.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE14.png b/Telegram/SourceFiles/art/Emoji/D83DDE14.png new file mode 100644 index 000000000..e2ff195ac Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE14.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE15.png b/Telegram/SourceFiles/art/Emoji/D83DDE15.png new file mode 100644 index 000000000..c1dcf8670 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE15.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE16.png b/Telegram/SourceFiles/art/Emoji/D83DDE16.png new file mode 100644 index 000000000..e61bc8922 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE16.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE17.png b/Telegram/SourceFiles/art/Emoji/D83DDE17.png new file mode 100644 index 000000000..b583473d4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE17.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE18.png b/Telegram/SourceFiles/art/Emoji/D83DDE18.png new file mode 100644 index 000000000..b4b985e6e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE18.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE19.png b/Telegram/SourceFiles/art/Emoji/D83DDE19.png new file mode 100644 index 000000000..6981b2bc4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE19.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE1A.png b/Telegram/SourceFiles/art/Emoji/D83DDE1A.png new file mode 100644 index 000000000..5d72bc989 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE1A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE1B.png b/Telegram/SourceFiles/art/Emoji/D83DDE1B.png new file mode 100644 index 000000000..5466a03f3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE1B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE1C.png b/Telegram/SourceFiles/art/Emoji/D83DDE1C.png new file mode 100644 index 000000000..6796924ae Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE1C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE1D.png b/Telegram/SourceFiles/art/Emoji/D83DDE1D.png new file mode 100644 index 000000000..aa3d784f4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE1D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE1E.png b/Telegram/SourceFiles/art/Emoji/D83DDE1E.png new file mode 100644 index 000000000..f2845ef68 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE1E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE1F.png b/Telegram/SourceFiles/art/Emoji/D83DDE1F.png new file mode 100644 index 000000000..b21d08f6a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE1F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE20.png b/Telegram/SourceFiles/art/Emoji/D83DDE20.png new file mode 100644 index 000000000..5b4a0cda6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE20.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE21.png b/Telegram/SourceFiles/art/Emoji/D83DDE21.png new file mode 100644 index 000000000..4d891fab0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE21.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE22.png b/Telegram/SourceFiles/art/Emoji/D83DDE22.png new file mode 100644 index 000000000..2cc2c82fa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE22.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE23.png b/Telegram/SourceFiles/art/Emoji/D83DDE23.png new file mode 100644 index 000000000..3cd5062af Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE23.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE24.png b/Telegram/SourceFiles/art/Emoji/D83DDE24.png new file mode 100644 index 000000000..7a98d95fc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE24.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE25.png b/Telegram/SourceFiles/art/Emoji/D83DDE25.png new file mode 100644 index 000000000..e244fe793 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE25.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE26.png b/Telegram/SourceFiles/art/Emoji/D83DDE26.png new file mode 100644 index 000000000..48641e6b3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE26.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE27.png b/Telegram/SourceFiles/art/Emoji/D83DDE27.png new file mode 100644 index 000000000..a2e655adf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE27.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE28.png b/Telegram/SourceFiles/art/Emoji/D83DDE28.png new file mode 100644 index 000000000..76ccea9a5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE28.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE29.png b/Telegram/SourceFiles/art/Emoji/D83DDE29.png new file mode 100644 index 000000000..443088297 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE29.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE2A.png b/Telegram/SourceFiles/art/Emoji/D83DDE2A.png new file mode 100644 index 000000000..0bb276b0a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE2A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE2B.png b/Telegram/SourceFiles/art/Emoji/D83DDE2B.png new file mode 100644 index 000000000..0b459a272 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE2B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE2C.png b/Telegram/SourceFiles/art/Emoji/D83DDE2C.png new file mode 100644 index 000000000..b945eff8e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE2C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE2D.png b/Telegram/SourceFiles/art/Emoji/D83DDE2D.png new file mode 100644 index 000000000..aac29ca70 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE2D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE2E.png b/Telegram/SourceFiles/art/Emoji/D83DDE2E.png new file mode 100644 index 000000000..f6df656ef Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE2E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE2F.png b/Telegram/SourceFiles/art/Emoji/D83DDE2F.png new file mode 100644 index 000000000..98c430848 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE2F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE30.png b/Telegram/SourceFiles/art/Emoji/D83DDE30.png new file mode 100644 index 000000000..8f50d8dfa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE30.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE31.png b/Telegram/SourceFiles/art/Emoji/D83DDE31.png new file mode 100644 index 000000000..a54a8a002 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE31.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE32.png b/Telegram/SourceFiles/art/Emoji/D83DDE32.png new file mode 100644 index 000000000..48c87eab5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE32.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE33.png b/Telegram/SourceFiles/art/Emoji/D83DDE33.png new file mode 100644 index 000000000..cf5089212 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE33.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE34.png b/Telegram/SourceFiles/art/Emoji/D83DDE34.png new file mode 100644 index 000000000..3f4f1d6f9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE34.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE35.png b/Telegram/SourceFiles/art/Emoji/D83DDE35.png new file mode 100644 index 000000000..24391dbc1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE35.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE36.png b/Telegram/SourceFiles/art/Emoji/D83DDE36.png new file mode 100644 index 000000000..46b30afa0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE36.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE37.png b/Telegram/SourceFiles/art/Emoji/D83DDE37.png new file mode 100644 index 000000000..1dea4b588 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE37.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE38.png b/Telegram/SourceFiles/art/Emoji/D83DDE38.png new file mode 100644 index 000000000..882d0aca3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE38.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE39.png b/Telegram/SourceFiles/art/Emoji/D83DDE39.png new file mode 100644 index 000000000..c31174452 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE39.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE3A.png b/Telegram/SourceFiles/art/Emoji/D83DDE3A.png new file mode 100644 index 000000000..a18fa7d81 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE3A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE3B.png b/Telegram/SourceFiles/art/Emoji/D83DDE3B.png new file mode 100644 index 000000000..ed35e283b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE3B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE3C.png b/Telegram/SourceFiles/art/Emoji/D83DDE3C.png new file mode 100644 index 000000000..f924c45f2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE3C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE3D.png b/Telegram/SourceFiles/art/Emoji/D83DDE3D.png new file mode 100644 index 000000000..bf8c96266 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE3D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE3E.png b/Telegram/SourceFiles/art/Emoji/D83DDE3E.png new file mode 100644 index 000000000..e02931ced Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE3E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE3F.png b/Telegram/SourceFiles/art/Emoji/D83DDE3F.png new file mode 100644 index 000000000..a7cd4e156 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE3F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE40.png b/Telegram/SourceFiles/art/Emoji/D83DDE40.png new file mode 100644 index 000000000..9a72002d2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE40.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE45.png b/Telegram/SourceFiles/art/Emoji/D83DDE45.png new file mode 100644 index 000000000..503fd3225 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE45.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE46.png b/Telegram/SourceFiles/art/Emoji/D83DDE46.png new file mode 100644 index 000000000..f965125e0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE46.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE47.png b/Telegram/SourceFiles/art/Emoji/D83DDE47.png new file mode 100644 index 000000000..355c9d286 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE47.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE48.png b/Telegram/SourceFiles/art/Emoji/D83DDE48.png new file mode 100644 index 000000000..098c7f5b8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE48.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE49.png b/Telegram/SourceFiles/art/Emoji/D83DDE49.png new file mode 100644 index 000000000..320c7fa07 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE49.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE4A.png b/Telegram/SourceFiles/art/Emoji/D83DDE4A.png new file mode 100644 index 000000000..2a36454ea Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE4A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE4B.png b/Telegram/SourceFiles/art/Emoji/D83DDE4B.png new file mode 100644 index 000000000..e9f865578 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE4B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE4C.png b/Telegram/SourceFiles/art/Emoji/D83DDE4C.png new file mode 100644 index 000000000..ccb621a3c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE4C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE4D.png b/Telegram/SourceFiles/art/Emoji/D83DDE4D.png new file mode 100644 index 000000000..fc9fb7ec1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE4D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE4E.png b/Telegram/SourceFiles/art/Emoji/D83DDE4E.png new file mode 100644 index 000000000..2fd7c71ea Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE4E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE4F.png b/Telegram/SourceFiles/art/Emoji/D83DDE4F.png new file mode 100644 index 000000000..204545d59 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE4F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE80.png b/Telegram/SourceFiles/art/Emoji/D83DDE80.png new file mode 100644 index 000000000..7e9241d33 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE80.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE81.png b/Telegram/SourceFiles/art/Emoji/D83DDE81.png new file mode 100644 index 000000000..ade03aebf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE81.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE82.png b/Telegram/SourceFiles/art/Emoji/D83DDE82.png new file mode 100644 index 000000000..ad242a2a5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE82.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE83.png b/Telegram/SourceFiles/art/Emoji/D83DDE83.png new file mode 100644 index 000000000..0c6dc1817 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE83.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE84.png b/Telegram/SourceFiles/art/Emoji/D83DDE84.png new file mode 100644 index 000000000..829cb73bd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE84.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE85.png b/Telegram/SourceFiles/art/Emoji/D83DDE85.png new file mode 100644 index 000000000..07eb96af4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE85.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE86.png b/Telegram/SourceFiles/art/Emoji/D83DDE86.png new file mode 100644 index 000000000..d757d24ee Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE86.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE87.png b/Telegram/SourceFiles/art/Emoji/D83DDE87.png new file mode 100644 index 000000000..c50d0df55 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE87.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE88.png b/Telegram/SourceFiles/art/Emoji/D83DDE88.png new file mode 100644 index 000000000..2be47b27b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE88.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE89.png b/Telegram/SourceFiles/art/Emoji/D83DDE89.png new file mode 100644 index 000000000..0de6bd45b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE89.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE8A.png b/Telegram/SourceFiles/art/Emoji/D83DDE8A.png new file mode 100644 index 000000000..46637f4d7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE8A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE8B.png b/Telegram/SourceFiles/art/Emoji/D83DDE8B.png new file mode 100644 index 000000000..c25512bb2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE8B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE8C.png b/Telegram/SourceFiles/art/Emoji/D83DDE8C.png new file mode 100644 index 000000000..95e047a2e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE8C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE8D.png b/Telegram/SourceFiles/art/Emoji/D83DDE8D.png new file mode 100644 index 000000000..eeffc287b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE8D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE8E.png b/Telegram/SourceFiles/art/Emoji/D83DDE8E.png new file mode 100644 index 000000000..cce5a5b68 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE8E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE8F.png b/Telegram/SourceFiles/art/Emoji/D83DDE8F.png new file mode 100644 index 000000000..be13deb52 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE8F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE90.png b/Telegram/SourceFiles/art/Emoji/D83DDE90.png new file mode 100644 index 000000000..8407d415e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE90.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE91.png b/Telegram/SourceFiles/art/Emoji/D83DDE91.png new file mode 100644 index 000000000..d9b1421f5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE91.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE92.png b/Telegram/SourceFiles/art/Emoji/D83DDE92.png new file mode 100644 index 000000000..57981c784 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE92.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE93.png b/Telegram/SourceFiles/art/Emoji/D83DDE93.png new file mode 100644 index 000000000..b2c68471d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE93.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE94.png b/Telegram/SourceFiles/art/Emoji/D83DDE94.png new file mode 100644 index 000000000..3cacb88d6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE94.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE95.png b/Telegram/SourceFiles/art/Emoji/D83DDE95.png new file mode 100644 index 000000000..7facea0af Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE95.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE96.png b/Telegram/SourceFiles/art/Emoji/D83DDE96.png new file mode 100644 index 000000000..8fe25d5bc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE96.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE97.png b/Telegram/SourceFiles/art/Emoji/D83DDE97.png new file mode 100644 index 000000000..26e2b6100 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE97.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE98.png b/Telegram/SourceFiles/art/Emoji/D83DDE98.png new file mode 100644 index 000000000..1324bd250 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE98.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE99.png b/Telegram/SourceFiles/art/Emoji/D83DDE99.png new file mode 100644 index 000000000..9b0d95cb1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE99.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE9A.png b/Telegram/SourceFiles/art/Emoji/D83DDE9A.png new file mode 100644 index 000000000..ef64e61b1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE9A.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE9B.png b/Telegram/SourceFiles/art/Emoji/D83DDE9B.png new file mode 100644 index 000000000..59af9fe4b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE9B.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE9C.png b/Telegram/SourceFiles/art/Emoji/D83DDE9C.png new file mode 100644 index 000000000..3fa333033 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE9C.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE9D.png b/Telegram/SourceFiles/art/Emoji/D83DDE9D.png new file mode 100644 index 000000000..7c4a41298 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE9D.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE9E.png b/Telegram/SourceFiles/art/Emoji/D83DDE9E.png new file mode 100644 index 000000000..19b0411a5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE9E.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDE9F.png b/Telegram/SourceFiles/art/Emoji/D83DDE9F.png new file mode 100644 index 000000000..f391cdf33 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDE9F.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEA0.png b/Telegram/SourceFiles/art/Emoji/D83DDEA0.png new file mode 100644 index 000000000..6987fd55f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEA0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEA1.png b/Telegram/SourceFiles/art/Emoji/D83DDEA1.png new file mode 100644 index 000000000..e6abeb1f4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEA1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEA2.png b/Telegram/SourceFiles/art/Emoji/D83DDEA2.png new file mode 100644 index 000000000..ec8cd9ede Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEA2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEA3.png b/Telegram/SourceFiles/art/Emoji/D83DDEA3.png new file mode 100644 index 000000000..4f29601c3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEA3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEA4.png b/Telegram/SourceFiles/art/Emoji/D83DDEA4.png new file mode 100644 index 000000000..e4ab4aa26 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEA4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEA5.png b/Telegram/SourceFiles/art/Emoji/D83DDEA5.png new file mode 100644 index 000000000..d3d6899b8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEA5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEA6.png b/Telegram/SourceFiles/art/Emoji/D83DDEA6.png new file mode 100644 index 000000000..4f32bd12d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEA6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEA7.png b/Telegram/SourceFiles/art/Emoji/D83DDEA7.png new file mode 100644 index 000000000..041e7ba47 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEA7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEA8.png b/Telegram/SourceFiles/art/Emoji/D83DDEA8.png new file mode 100644 index 000000000..b67f8109d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEA8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEA9.png b/Telegram/SourceFiles/art/Emoji/D83DDEA9.png new file mode 100644 index 000000000..a0127dbaa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEA9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEAA.png b/Telegram/SourceFiles/art/Emoji/D83DDEAA.png new file mode 100644 index 000000000..808f73cf7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEAA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEAB.png b/Telegram/SourceFiles/art/Emoji/D83DDEAB.png new file mode 100644 index 000000000..092f7f7de Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEAB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEAC.png b/Telegram/SourceFiles/art/Emoji/D83DDEAC.png new file mode 100644 index 000000000..2295dd1c8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEAC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEAD.png b/Telegram/SourceFiles/art/Emoji/D83DDEAD.png new file mode 100644 index 000000000..947ecea48 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEAD.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEAE.png b/Telegram/SourceFiles/art/Emoji/D83DDEAE.png new file mode 100644 index 000000000..7c37d2e19 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEAE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEAF.png b/Telegram/SourceFiles/art/Emoji/D83DDEAF.png new file mode 100644 index 000000000..cc94e6898 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEAF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEB0.png b/Telegram/SourceFiles/art/Emoji/D83DDEB0.png new file mode 100644 index 000000000..3790c67f8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEB0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEB1.png b/Telegram/SourceFiles/art/Emoji/D83DDEB1.png new file mode 100644 index 000000000..6b0182437 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEB1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEB2.png b/Telegram/SourceFiles/art/Emoji/D83DDEB2.png new file mode 100644 index 000000000..ff2242583 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEB2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEB3.png b/Telegram/SourceFiles/art/Emoji/D83DDEB3.png new file mode 100644 index 000000000..3aa33aed3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEB3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEB4.png b/Telegram/SourceFiles/art/Emoji/D83DDEB4.png new file mode 100644 index 000000000..5b8e42404 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEB4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEB5.png b/Telegram/SourceFiles/art/Emoji/D83DDEB5.png new file mode 100644 index 000000000..a53016c5e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEB5.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEB6.png b/Telegram/SourceFiles/art/Emoji/D83DDEB6.png new file mode 100644 index 000000000..3cae4052a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEB6.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEB7.png b/Telegram/SourceFiles/art/Emoji/D83DDEB7.png new file mode 100644 index 000000000..464b92574 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEB7.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEB8.png b/Telegram/SourceFiles/art/Emoji/D83DDEB8.png new file mode 100644 index 000000000..ff2620417 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEB8.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEB9.png b/Telegram/SourceFiles/art/Emoji/D83DDEB9.png new file mode 100644 index 000000000..34f6afe5f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEB9.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEBA.png b/Telegram/SourceFiles/art/Emoji/D83DDEBA.png new file mode 100644 index 000000000..42f346a3c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEBA.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEBB.png b/Telegram/SourceFiles/art/Emoji/D83DDEBB.png new file mode 100644 index 000000000..730020ed7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEBB.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEBC.png b/Telegram/SourceFiles/art/Emoji/D83DDEBC.png new file mode 100644 index 000000000..2e16d9036 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEBC.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEBD.png b/Telegram/SourceFiles/art/Emoji/D83DDEBD.png new file mode 100644 index 000000000..4bae58224 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEBD.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEBE.png b/Telegram/SourceFiles/art/Emoji/D83DDEBE.png new file mode 100644 index 000000000..0ad1c760f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEBE.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEBF.png b/Telegram/SourceFiles/art/Emoji/D83DDEBF.png new file mode 100644 index 000000000..90e601a5f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEBF.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEC0.png b/Telegram/SourceFiles/art/Emoji/D83DDEC0.png new file mode 100644 index 000000000..048ec2c63 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEC0.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEC1.png b/Telegram/SourceFiles/art/Emoji/D83DDEC1.png new file mode 100644 index 000000000..84976f7b2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEC1.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEC2.png b/Telegram/SourceFiles/art/Emoji/D83DDEC2.png new file mode 100644 index 000000000..9149a022e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEC2.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEC3.png b/Telegram/SourceFiles/art/Emoji/D83DDEC3.png new file mode 100644 index 000000000..affea8ec1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEC3.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEC4.png b/Telegram/SourceFiles/art/Emoji/D83DDEC4.png new file mode 100644 index 000000000..1ba419121 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEC4.png differ diff --git a/Telegram/SourceFiles/art/Emoji/D83DDEC5.png b/Telegram/SourceFiles/art/Emoji/D83DDEC5.png new file mode 100644 index 000000000..cd438cb8e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji/D83DDEC5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/002320E3.png b/Telegram/SourceFiles/art/Emoji_200x/002320E3.png new file mode 100644 index 000000000..c14a4460a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/002320E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/003020E3.png b/Telegram/SourceFiles/art/Emoji_200x/003020E3.png new file mode 100644 index 000000000..0a2bde821 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/003020E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/003120E3.png b/Telegram/SourceFiles/art/Emoji_200x/003120E3.png new file mode 100644 index 000000000..da83ccd20 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/003120E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/003220E3.png b/Telegram/SourceFiles/art/Emoji_200x/003220E3.png new file mode 100644 index 000000000..54bab62b9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/003220E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/003320E3.png b/Telegram/SourceFiles/art/Emoji_200x/003320E3.png new file mode 100644 index 000000000..e6a36c363 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/003320E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/003420E3.png b/Telegram/SourceFiles/art/Emoji_200x/003420E3.png new file mode 100644 index 000000000..6db17bdff Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/003420E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/003520E3.png b/Telegram/SourceFiles/art/Emoji_200x/003520E3.png new file mode 100644 index 000000000..1b6b700c8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/003520E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/003620E3.png b/Telegram/SourceFiles/art/Emoji_200x/003620E3.png new file mode 100644 index 000000000..b2fadafb7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/003620E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/003720E3.png b/Telegram/SourceFiles/art/Emoji_200x/003720E3.png new file mode 100644 index 000000000..5407503e1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/003720E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/003820E3.png b/Telegram/SourceFiles/art/Emoji_200x/003820E3.png new file mode 100644 index 000000000..de2b4841e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/003820E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/003920E3.png b/Telegram/SourceFiles/art/Emoji_200x/003920E3.png new file mode 100644 index 000000000..6ef6f18f9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/003920E3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/00A9.png b/Telegram/SourceFiles/art/Emoji_200x/00A9.png new file mode 100644 index 000000000..28533e75d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/00A9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/00AE.png b/Telegram/SourceFiles/art/Emoji_200x/00AE.png new file mode 100644 index 000000000..5f2761e21 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/00AE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/203C.png b/Telegram/SourceFiles/art/Emoji_200x/203C.png new file mode 100644 index 000000000..e88ee38a2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/203C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2049.png b/Telegram/SourceFiles/art/Emoji_200x/2049.png new file mode 100644 index 000000000..7f718b2d4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2049.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2122.png b/Telegram/SourceFiles/art/Emoji_200x/2122.png new file mode 100644 index 000000000..6b6fc3e46 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2122.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2139.png b/Telegram/SourceFiles/art/Emoji_200x/2139.png new file mode 100644 index 000000000..f79cf5d11 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2139.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2194.png b/Telegram/SourceFiles/art/Emoji_200x/2194.png new file mode 100644 index 000000000..882998f2a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2194.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2195.png b/Telegram/SourceFiles/art/Emoji_200x/2195.png new file mode 100644 index 000000000..f13c0a67d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2195.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2196.png b/Telegram/SourceFiles/art/Emoji_200x/2196.png new file mode 100644 index 000000000..2e52811a7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2196.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2197.png b/Telegram/SourceFiles/art/Emoji_200x/2197.png new file mode 100644 index 000000000..cf317ef03 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2197.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2198.png b/Telegram/SourceFiles/art/Emoji_200x/2198.png new file mode 100644 index 000000000..3e1ba579c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2198.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2199.png b/Telegram/SourceFiles/art/Emoji_200x/2199.png new file mode 100644 index 000000000..becb903f6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2199.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/21A9.png b/Telegram/SourceFiles/art/Emoji_200x/21A9.png new file mode 100644 index 000000000..6fd2be728 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/21A9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/21AA.png b/Telegram/SourceFiles/art/Emoji_200x/21AA.png new file mode 100644 index 000000000..222c5bd9f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/21AA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/231A.png b/Telegram/SourceFiles/art/Emoji_200x/231A.png new file mode 100644 index 000000000..7012df246 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/231A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/231B.png b/Telegram/SourceFiles/art/Emoji_200x/231B.png new file mode 100644 index 000000000..960000dd2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/231B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/23E9.png b/Telegram/SourceFiles/art/Emoji_200x/23E9.png new file mode 100644 index 000000000..671e93025 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/23E9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/23EA.png b/Telegram/SourceFiles/art/Emoji_200x/23EA.png new file mode 100644 index 000000000..6dc6838c2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/23EA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/23EB.png b/Telegram/SourceFiles/art/Emoji_200x/23EB.png new file mode 100644 index 000000000..beb3dea23 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/23EB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/23EC.png b/Telegram/SourceFiles/art/Emoji_200x/23EC.png new file mode 100644 index 000000000..49900815b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/23EC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/23F0.png b/Telegram/SourceFiles/art/Emoji_200x/23F0.png new file mode 100644 index 000000000..aa557e8aa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/23F0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/23F3.png b/Telegram/SourceFiles/art/Emoji_200x/23F3.png new file mode 100644 index 000000000..349870e87 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/23F3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/24C2.png b/Telegram/SourceFiles/art/Emoji_200x/24C2.png new file mode 100644 index 000000000..b4ba40ca1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/24C2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/25AA.png b/Telegram/SourceFiles/art/Emoji_200x/25AA.png new file mode 100644 index 000000000..1f10f8e08 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/25AA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/25AB.png b/Telegram/SourceFiles/art/Emoji_200x/25AB.png new file mode 100644 index 000000000..f74572b0e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/25AB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/25B6.png b/Telegram/SourceFiles/art/Emoji_200x/25B6.png new file mode 100644 index 000000000..5d6c46bcd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/25B6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/25C0.png b/Telegram/SourceFiles/art/Emoji_200x/25C0.png new file mode 100644 index 000000000..45a05ab42 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/25C0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/25FB.png b/Telegram/SourceFiles/art/Emoji_200x/25FB.png new file mode 100644 index 000000000..3cf4c8e0e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/25FB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/25FC.png b/Telegram/SourceFiles/art/Emoji_200x/25FC.png new file mode 100644 index 000000000..4328b0cb8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/25FC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/25FD.png b/Telegram/SourceFiles/art/Emoji_200x/25FD.png new file mode 100644 index 000000000..a721d35f3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/25FD.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/25FE.png b/Telegram/SourceFiles/art/Emoji_200x/25FE.png new file mode 100644 index 000000000..69a4c30c9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/25FE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2600.png b/Telegram/SourceFiles/art/Emoji_200x/2600.png new file mode 100644 index 000000000..46866e591 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2600.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2601.png b/Telegram/SourceFiles/art/Emoji_200x/2601.png new file mode 100644 index 000000000..b015d7eb9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2601.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/260E.png b/Telegram/SourceFiles/art/Emoji_200x/260E.png new file mode 100644 index 000000000..a3945c21b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/260E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2611.png b/Telegram/SourceFiles/art/Emoji_200x/2611.png new file mode 100644 index 000000000..0ca26e5dc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2611.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2614.png b/Telegram/SourceFiles/art/Emoji_200x/2614.png new file mode 100644 index 000000000..ba1d0cc6c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2614.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2615.png b/Telegram/SourceFiles/art/Emoji_200x/2615.png new file mode 100644 index 000000000..bd0774a80 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2615.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/261D.png b/Telegram/SourceFiles/art/Emoji_200x/261D.png new file mode 100644 index 000000000..d2839d918 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/261D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/263A.png b/Telegram/SourceFiles/art/Emoji_200x/263A.png new file mode 100644 index 000000000..e7ca3ef0c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/263A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2648.png b/Telegram/SourceFiles/art/Emoji_200x/2648.png new file mode 100644 index 000000000..607f647dc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2648.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2649.png b/Telegram/SourceFiles/art/Emoji_200x/2649.png new file mode 100644 index 000000000..7f47a50b5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2649.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/264A.png b/Telegram/SourceFiles/art/Emoji_200x/264A.png new file mode 100644 index 000000000..6bb2cb1b0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/264A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/264B.png b/Telegram/SourceFiles/art/Emoji_200x/264B.png new file mode 100644 index 000000000..0d515c715 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/264B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/264C.png b/Telegram/SourceFiles/art/Emoji_200x/264C.png new file mode 100644 index 000000000..b4a6cdd07 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/264C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/264D.png b/Telegram/SourceFiles/art/Emoji_200x/264D.png new file mode 100644 index 000000000..71bb86952 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/264D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/264E.png b/Telegram/SourceFiles/art/Emoji_200x/264E.png new file mode 100644 index 000000000..f70bcfe44 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/264E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/264F.png b/Telegram/SourceFiles/art/Emoji_200x/264F.png new file mode 100644 index 000000000..82cb4ca09 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/264F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2650.png b/Telegram/SourceFiles/art/Emoji_200x/2650.png new file mode 100644 index 000000000..957ee3931 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2650.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2651.png b/Telegram/SourceFiles/art/Emoji_200x/2651.png new file mode 100644 index 000000000..a7885092d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2651.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2652.png b/Telegram/SourceFiles/art/Emoji_200x/2652.png new file mode 100644 index 000000000..0c595cca9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2652.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2653.png b/Telegram/SourceFiles/art/Emoji_200x/2653.png new file mode 100644 index 000000000..4d8dad9e8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2653.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2660.png b/Telegram/SourceFiles/art/Emoji_200x/2660.png new file mode 100644 index 000000000..185da237d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2660.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2663.png b/Telegram/SourceFiles/art/Emoji_200x/2663.png new file mode 100644 index 000000000..cd5902b28 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2663.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2665.png b/Telegram/SourceFiles/art/Emoji_200x/2665.png new file mode 100644 index 000000000..4c2a6c014 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2665.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2666.png b/Telegram/SourceFiles/art/Emoji_200x/2666.png new file mode 100644 index 000000000..6c6744131 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2666.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2668.png b/Telegram/SourceFiles/art/Emoji_200x/2668.png new file mode 100644 index 000000000..3e625f99e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2668.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/267B.png b/Telegram/SourceFiles/art/Emoji_200x/267B.png new file mode 100644 index 000000000..8aa2cceed Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/267B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/267F.png b/Telegram/SourceFiles/art/Emoji_200x/267F.png new file mode 100644 index 000000000..1a3d9118b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/267F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2693.png b/Telegram/SourceFiles/art/Emoji_200x/2693.png new file mode 100644 index 000000000..088cc8811 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2693.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26A0.png b/Telegram/SourceFiles/art/Emoji_200x/26A0.png new file mode 100644 index 000000000..6cfe3fd7d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26A0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26A1.png b/Telegram/SourceFiles/art/Emoji_200x/26A1.png new file mode 100644 index 000000000..d28c4d2f5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26A1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26AA.png b/Telegram/SourceFiles/art/Emoji_200x/26AA.png new file mode 100644 index 000000000..2d7697a93 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26AA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26AB.png b/Telegram/SourceFiles/art/Emoji_200x/26AB.png new file mode 100644 index 000000000..b3689bebf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26AB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26BD.png b/Telegram/SourceFiles/art/Emoji_200x/26BD.png new file mode 100644 index 000000000..7b0d02c03 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26BD.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26BE.png b/Telegram/SourceFiles/art/Emoji_200x/26BE.png new file mode 100644 index 000000000..3cdeb7f1c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26BE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26C4.png b/Telegram/SourceFiles/art/Emoji_200x/26C4.png new file mode 100644 index 000000000..a9d6b93b5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26C4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26C5.png b/Telegram/SourceFiles/art/Emoji_200x/26C5.png new file mode 100644 index 000000000..dd47bcee4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26C5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26CE.png b/Telegram/SourceFiles/art/Emoji_200x/26CE.png new file mode 100644 index 000000000..44e106e13 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26CE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26D4.png b/Telegram/SourceFiles/art/Emoji_200x/26D4.png new file mode 100644 index 000000000..fdbdb6eab Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26D4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26EA.png b/Telegram/SourceFiles/art/Emoji_200x/26EA.png new file mode 100644 index 000000000..48123dc93 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26EA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26F2.png b/Telegram/SourceFiles/art/Emoji_200x/26F2.png new file mode 100644 index 000000000..8417696cf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26F2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26F3.png b/Telegram/SourceFiles/art/Emoji_200x/26F3.png new file mode 100644 index 000000000..b633fba8f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26F3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26F5.png b/Telegram/SourceFiles/art/Emoji_200x/26F5.png new file mode 100644 index 000000000..dfb228ff0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26F5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26FA.png b/Telegram/SourceFiles/art/Emoji_200x/26FA.png new file mode 100644 index 000000000..51ff648d4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26FA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/26FD.png b/Telegram/SourceFiles/art/Emoji_200x/26FD.png new file mode 100644 index 000000000..0170cbfe6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/26FD.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2702.png b/Telegram/SourceFiles/art/Emoji_200x/2702.png new file mode 100644 index 000000000..f69e6d703 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2702.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2705.png b/Telegram/SourceFiles/art/Emoji_200x/2705.png new file mode 100644 index 000000000..8bb339b61 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2705.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2708.png b/Telegram/SourceFiles/art/Emoji_200x/2708.png new file mode 100644 index 000000000..2f39cfdab Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2708.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2709.png b/Telegram/SourceFiles/art/Emoji_200x/2709.png new file mode 100644 index 000000000..4b5170372 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2709.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/270A.png b/Telegram/SourceFiles/art/Emoji_200x/270A.png new file mode 100644 index 000000000..3e1b192c0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/270A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/270B.png b/Telegram/SourceFiles/art/Emoji_200x/270B.png new file mode 100644 index 000000000..b7f129047 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/270B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/270C.png b/Telegram/SourceFiles/art/Emoji_200x/270C.png new file mode 100644 index 000000000..d00ef611c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/270C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/270F.png b/Telegram/SourceFiles/art/Emoji_200x/270F.png new file mode 100644 index 000000000..356cfdf53 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/270F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2712.png b/Telegram/SourceFiles/art/Emoji_200x/2712.png new file mode 100644 index 000000000..d67c37798 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2712.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2714.png b/Telegram/SourceFiles/art/Emoji_200x/2714.png new file mode 100644 index 000000000..3687194df Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2714.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2716.png b/Telegram/SourceFiles/art/Emoji_200x/2716.png new file mode 100644 index 000000000..cc463f7e9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2716.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2728.png b/Telegram/SourceFiles/art/Emoji_200x/2728.png new file mode 100644 index 000000000..95fed5428 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2728.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2733.png b/Telegram/SourceFiles/art/Emoji_200x/2733.png new file mode 100644 index 000000000..353d48fa1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2733.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2734.png b/Telegram/SourceFiles/art/Emoji_200x/2734.png new file mode 100644 index 000000000..83b017bdb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2734.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2744.png b/Telegram/SourceFiles/art/Emoji_200x/2744.png new file mode 100644 index 000000000..744a5a985 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2744.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2747.png b/Telegram/SourceFiles/art/Emoji_200x/2747.png new file mode 100644 index 000000000..5724bfb12 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2747.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/274C.png b/Telegram/SourceFiles/art/Emoji_200x/274C.png new file mode 100644 index 000000000..a44fa1351 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/274C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/274E.png b/Telegram/SourceFiles/art/Emoji_200x/274E.png new file mode 100644 index 000000000..463aa6555 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/274E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2753.png b/Telegram/SourceFiles/art/Emoji_200x/2753.png new file mode 100644 index 000000000..e35e377b2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2753.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2754.png b/Telegram/SourceFiles/art/Emoji_200x/2754.png new file mode 100644 index 000000000..dd051d976 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2754.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2755.png b/Telegram/SourceFiles/art/Emoji_200x/2755.png new file mode 100644 index 000000000..b5d9f0c6a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2755.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2757.png b/Telegram/SourceFiles/art/Emoji_200x/2757.png new file mode 100644 index 000000000..df962008f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2757.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2764.png b/Telegram/SourceFiles/art/Emoji_200x/2764.png new file mode 100644 index 000000000..d673061b4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2764.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2795.png b/Telegram/SourceFiles/art/Emoji_200x/2795.png new file mode 100644 index 000000000..176e933d7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2795.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2796.png b/Telegram/SourceFiles/art/Emoji_200x/2796.png new file mode 100644 index 000000000..c386691e5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2796.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2797.png b/Telegram/SourceFiles/art/Emoji_200x/2797.png new file mode 100644 index 000000000..e6e5328e7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2797.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/27A1.png b/Telegram/SourceFiles/art/Emoji_200x/27A1.png new file mode 100644 index 000000000..4d206ad9d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/27A1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/27B0.png b/Telegram/SourceFiles/art/Emoji_200x/27B0.png new file mode 100644 index 000000000..e4113491d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/27B0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/27BF.png b/Telegram/SourceFiles/art/Emoji_200x/27BF.png new file mode 100644 index 000000000..7185a89c9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/27BF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2934.png b/Telegram/SourceFiles/art/Emoji_200x/2934.png new file mode 100644 index 000000000..ef1f0c65a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2934.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2935.png b/Telegram/SourceFiles/art/Emoji_200x/2935.png new file mode 100644 index 000000000..2a66fa707 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2935.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2B05.png b/Telegram/SourceFiles/art/Emoji_200x/2B05.png new file mode 100644 index 000000000..dc8838afc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2B05.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2B06.png b/Telegram/SourceFiles/art/Emoji_200x/2B06.png new file mode 100644 index 000000000..979116c7d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2B06.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2B07.png b/Telegram/SourceFiles/art/Emoji_200x/2B07.png new file mode 100644 index 000000000..6eee8d53a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2B07.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2B1B.png b/Telegram/SourceFiles/art/Emoji_200x/2B1B.png new file mode 100644 index 000000000..bfa079170 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2B1B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2B1C.png b/Telegram/SourceFiles/art/Emoji_200x/2B1C.png new file mode 100644 index 000000000..df98dc042 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2B1C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2B50.png b/Telegram/SourceFiles/art/Emoji_200x/2B50.png new file mode 100644 index 000000000..e504b3b38 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2B50.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/2B55.png b/Telegram/SourceFiles/art/Emoji_200x/2B55.png new file mode 100644 index 000000000..05bd8242a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/2B55.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/3030.png b/Telegram/SourceFiles/art/Emoji_200x/3030.png new file mode 100644 index 000000000..a59595797 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/3030.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/303D.png b/Telegram/SourceFiles/art/Emoji_200x/303D.png new file mode 100644 index 000000000..4ddba5875 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/303D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/3297.png b/Telegram/SourceFiles/art/Emoji_200x/3297.png new file mode 100644 index 000000000..c0e448cdd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/3297.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/3299.png b/Telegram/SourceFiles/art/Emoji_200x/3299.png new file mode 100644 index 000000000..f26db5755 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/3299.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDC04.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDC04.png new file mode 100644 index 000000000..5eed66e77 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDC04.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDCCF.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDCCF.png new file mode 100644 index 000000000..6787516ef Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDCCF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD70.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD70.png new file mode 100644 index 000000000..e3b588279 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD70.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD71.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD71.png new file mode 100644 index 000000000..7e2386bf3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD71.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD7E.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD7E.png new file mode 100644 index 000000000..bab881ff9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD7E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD7F.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD7F.png new file mode 100644 index 000000000..a4e501e66 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD7F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD8E.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD8E.png new file mode 100644 index 000000000..abfea7fe3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD8E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD91.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD91.png new file mode 100644 index 000000000..eda6ce600 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD91.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD92.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD92.png new file mode 100644 index 000000000..ccba152dd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD92.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD93.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD93.png new file mode 100644 index 000000000..8f3ad527c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD93.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD94.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD94.png new file mode 100644 index 000000000..535af9a1c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD94.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD95.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD95.png new file mode 100644 index 000000000..bab9fedf7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD95.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD96.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD96.png new file mode 100644 index 000000000..adfb570da Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD96.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD97.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD97.png new file mode 100644 index 000000000..745c540f9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD97.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD98.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD98.png new file mode 100644 index 000000000..de8304f83 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD98.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD99.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD99.png new file mode 100644 index 000000000..74bd04756 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD99.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDD9A.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDD9A.png new file mode 100644 index 000000000..0149780b3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDD9A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDDE8D83CDDF3.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDDE8D83CDDF3.png new file mode 100644 index 000000000..59057372a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDDE8D83CDDF3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDDE9D83CDDEA.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDDE9D83CDDEA.png new file mode 100644 index 000000000..1bffd79e7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDDE9D83CDDEA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDDEAD83CDDF8.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDDEAD83CDDF8.png new file mode 100644 index 000000000..2de9d39d5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDDEAD83CDDF8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDDEBD83CDDF7.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDDEBD83CDDF7.png new file mode 100644 index 000000000..2b6315f6f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDDEBD83CDDF7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDDECD83CDDE7.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDDECD83CDDE7.png new file mode 100644 index 000000000..3cee7d4b7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDDECD83CDDE7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDDEED83CDDF9.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDDEED83CDDF9.png new file mode 100644 index 000000000..c62452f77 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDDEED83CDDF9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDDEFD83CDDF5.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDDEFD83CDDF5.png new file mode 100644 index 000000000..dba144bab Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDDEFD83CDDF5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDDF0D83CDDF7.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDDF0D83CDDF7.png new file mode 100644 index 000000000..8752e1e9b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDDF0D83CDDF7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDDF7D83CDDFA.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDDF7D83CDDFA.png new file mode 100644 index 000000000..e2a6107f2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDDF7D83CDDFA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDDFAD83CDDF8.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDDFAD83CDDF8.png new file mode 100644 index 000000000..a3d4fcac7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDDFAD83CDDF8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE01.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE01.png new file mode 100644 index 000000000..e8f05065e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE01.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE02.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE02.png new file mode 100644 index 000000000..1413988ee Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE02.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE1A.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE1A.png new file mode 100644 index 000000000..097c1cada Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE1A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE2F.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE2F.png new file mode 100644 index 000000000..d6e240304 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE2F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE32.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE32.png new file mode 100644 index 000000000..2f9986d46 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE32.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE33.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE33.png new file mode 100644 index 000000000..a83577983 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE33.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE34.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE34.png new file mode 100644 index 000000000..d09d146b7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE34.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE35.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE35.png new file mode 100644 index 000000000..6ed721521 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE35.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE36.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE36.png new file mode 100644 index 000000000..21f121363 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE36.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE37.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE37.png new file mode 100644 index 000000000..7d81b97dc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE37.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE38.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE38.png new file mode 100644 index 000000000..6e6fc0375 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE38.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE39.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE39.png new file mode 100644 index 000000000..b21a3db89 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE39.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE3A.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE3A.png new file mode 100644 index 000000000..7d65fed9a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE3A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE50.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE50.png new file mode 100644 index 000000000..eacc90ce6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE50.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDE51.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDE51.png new file mode 100644 index 000000000..712750d91 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDE51.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF00.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF00.png new file mode 100644 index 000000000..10398c097 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF00.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF01.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF01.png new file mode 100644 index 000000000..01c7723dc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF01.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF02.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF02.png new file mode 100644 index 000000000..42dc32dea Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF02.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF03.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF03.png new file mode 100644 index 000000000..13be8d6a0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF03.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF04.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF04.png new file mode 100644 index 000000000..2b4288f4c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF04.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF05.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF05.png new file mode 100644 index 000000000..0bf59eccf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF05.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF06.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF06.png new file mode 100644 index 000000000..717d62147 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF06.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF07.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF07.png new file mode 100644 index 000000000..858418265 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF07.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF08.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF08.png new file mode 100644 index 000000000..131ef72fb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF08.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF09.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF09.png new file mode 100644 index 000000000..7ea010492 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF09.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF0A.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF0A.png new file mode 100644 index 000000000..ca9321004 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF0A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF0B.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF0B.png new file mode 100644 index 000000000..4c03da5af Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF0B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF0C.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF0C.png new file mode 100644 index 000000000..49901b7eb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF0C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF0D.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF0D.png new file mode 100644 index 000000000..4d9de7eab Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF0D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF0E.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF0E.png new file mode 100644 index 000000000..08f1f036f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF0E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF0F.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF0F.png new file mode 100644 index 000000000..670569a32 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF0F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF10.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF10.png new file mode 100644 index 000000000..7ab854d25 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF10.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF11.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF11.png new file mode 100644 index 000000000..11c2b4b2a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF11.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF12.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF12.png new file mode 100644 index 000000000..cb7e5d3e2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF12.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF13.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF13.png new file mode 100644 index 000000000..50cb26c1d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF13.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF14.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF14.png new file mode 100644 index 000000000..7058cb771 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF14.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF15.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF15.png new file mode 100644 index 000000000..2d1fb28ab Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF15.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF16.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF16.png new file mode 100644 index 000000000..97c618420 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF16.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF17.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF17.png new file mode 100644 index 000000000..fd0e6ecc3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF17.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF18.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF18.png new file mode 100644 index 000000000..a09048593 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF18.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF19.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF19.png new file mode 100644 index 000000000..52c38f4ce Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF19.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF1A.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF1A.png new file mode 100644 index 000000000..70967efaa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF1A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF1B.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF1B.png new file mode 100644 index 000000000..1a8013c0b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF1B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF1C.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF1C.png new file mode 100644 index 000000000..e85fb8a94 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF1C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF1D.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF1D.png new file mode 100644 index 000000000..590f11ab6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF1D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF1E.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF1E.png new file mode 100644 index 000000000..8ec3b5d7d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF1E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF1F.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF1F.png new file mode 100644 index 000000000..e5a9062bd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF1F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF20.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF20.png new file mode 100644 index 000000000..7f22fec75 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF20.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF30.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF30.png new file mode 100644 index 000000000..3b3a45304 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF30.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF31.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF31.png new file mode 100644 index 000000000..7a08bc199 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF31.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF32.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF32.png new file mode 100644 index 000000000..819cbea56 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF32.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF33.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF33.png new file mode 100644 index 000000000..da4526e48 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF33.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF34.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF34.png new file mode 100644 index 000000000..8308c0bbd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF34.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF35.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF35.png new file mode 100644 index 000000000..5c7aeffe2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF35.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF37.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF37.png new file mode 100644 index 000000000..77e6d0e21 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF37.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF38.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF38.png new file mode 100644 index 000000000..08c58d608 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF38.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF39.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF39.png new file mode 100644 index 000000000..148448b92 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF39.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF3A.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF3A.png new file mode 100644 index 000000000..ea9066813 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF3A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF3B.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF3B.png new file mode 100644 index 000000000..65ed1d1fe Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF3B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF3C.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF3C.png new file mode 100644 index 000000000..fe3b343cb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF3C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF3D.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF3D.png new file mode 100644 index 000000000..3f9124893 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF3D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF3E.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF3E.png new file mode 100644 index 000000000..874716a5f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF3E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF3F.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF3F.png new file mode 100644 index 000000000..468e5cae0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF3F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF40.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF40.png new file mode 100644 index 000000000..c005320e3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF40.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF41.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF41.png new file mode 100644 index 000000000..0fa3044d6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF41.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF42.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF42.png new file mode 100644 index 000000000..fb7426661 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF42.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF43.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF43.png new file mode 100644 index 000000000..4f92d9753 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF43.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF44.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF44.png new file mode 100644 index 000000000..00eb64597 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF44.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF45.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF45.png new file mode 100644 index 000000000..91f6e60a6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF45.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF46.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF46.png new file mode 100644 index 000000000..2ab119bc5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF46.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF47.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF47.png new file mode 100644 index 000000000..ebfdcaa28 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF47.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF48.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF48.png new file mode 100644 index 000000000..39530dd80 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF48.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF49.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF49.png new file mode 100644 index 000000000..1de97a870 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF49.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF4A.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF4A.png new file mode 100644 index 000000000..cec925771 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF4A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF4B.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF4B.png new file mode 100644 index 000000000..c4a0b149a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF4B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF4C.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF4C.png new file mode 100644 index 000000000..b80d8d557 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF4C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF4D.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF4D.png new file mode 100644 index 000000000..210422a5d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF4D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF4E.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF4E.png new file mode 100644 index 000000000..fb46e0be0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF4E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF4F.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF4F.png new file mode 100644 index 000000000..648d9d11d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF4F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF50.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF50.png new file mode 100644 index 000000000..818c5010d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF50.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF51.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF51.png new file mode 100644 index 000000000..5b948c665 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF51.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF52.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF52.png new file mode 100644 index 000000000..68389986c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF52.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF53.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF53.png new file mode 100644 index 000000000..0e1074dbd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF53.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF54.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF54.png new file mode 100644 index 000000000..381aa0788 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF54.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF55.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF55.png new file mode 100644 index 000000000..04dcbec1c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF55.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF56.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF56.png new file mode 100644 index 000000000..7772485d6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF56.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF57.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF57.png new file mode 100644 index 000000000..2ca6fa575 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF57.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF58.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF58.png new file mode 100644 index 000000000..253506eac Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF58.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF59.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF59.png new file mode 100644 index 000000000..03347b29f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF59.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF5A.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF5A.png new file mode 100644 index 000000000..be235653b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF5A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF5B.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF5B.png new file mode 100644 index 000000000..97db1bab0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF5B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF5C.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF5C.png new file mode 100644 index 000000000..35c9d15b3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF5C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF5D.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF5D.png new file mode 100644 index 000000000..dfd5315a0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF5D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF5E.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF5E.png new file mode 100644 index 000000000..c51775be4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF5E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF5F.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF5F.png new file mode 100644 index 000000000..b4909dab0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF5F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF60.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF60.png new file mode 100644 index 000000000..6fd67d6d7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF60.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF61.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF61.png new file mode 100644 index 000000000..2df0faaa2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF61.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF62.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF62.png new file mode 100644 index 000000000..2e182eb08 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF62.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF63.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF63.png new file mode 100644 index 000000000..7996b557d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF63.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF64.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF64.png new file mode 100644 index 000000000..e60351b88 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF64.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF65.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF65.png new file mode 100644 index 000000000..5303c92b4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF65.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF66.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF66.png new file mode 100644 index 000000000..5d39a73c3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF66.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF67.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF67.png new file mode 100644 index 000000000..7b8f1160f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF67.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF68.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF68.png new file mode 100644 index 000000000..1e487db53 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF68.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF69.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF69.png new file mode 100644 index 000000000..214c82b44 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF69.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF6A.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF6A.png new file mode 100644 index 000000000..da64d049a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF6A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF6B.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF6B.png new file mode 100644 index 000000000..c64375657 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF6B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF6C.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF6C.png new file mode 100644 index 000000000..1663bc4e1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF6C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF6D.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF6D.png new file mode 100644 index 000000000..f7e6cfb13 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF6D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF6E.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF6E.png new file mode 100644 index 000000000..09dde56cd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF6E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF6F.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF6F.png new file mode 100644 index 000000000..ccedd3e4e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF6F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF70.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF70.png new file mode 100644 index 000000000..0664a8adc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF70.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF71.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF71.png new file mode 100644 index 000000000..94d6d8d19 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF71.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF72.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF72.png new file mode 100644 index 000000000..d0099d736 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF72.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF73.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF73.png new file mode 100644 index 000000000..ed8bef948 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF73.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF74.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF74.png new file mode 100644 index 000000000..33a27feae Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF74.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF75.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF75.png new file mode 100644 index 000000000..839309a71 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF75.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF76.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF76.png new file mode 100644 index 000000000..1ac501569 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF76.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF77.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF77.png new file mode 100644 index 000000000..f7aaa5ec6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF77.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF78.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF78.png new file mode 100644 index 000000000..9c169bbb8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF78.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF79.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF79.png new file mode 100644 index 000000000..0c707341f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF79.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF7A.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF7A.png new file mode 100644 index 000000000..0ba7099e0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF7A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF7B.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF7B.png new file mode 100644 index 000000000..a659723e4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF7B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF7C.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF7C.png new file mode 100644 index 000000000..395f6c388 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF7C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF80.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF80.png new file mode 100644 index 000000000..16ff8fae6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF80.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF81.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF81.png new file mode 100644 index 000000000..f6334740b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF81.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF82.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF82.png new file mode 100644 index 000000000..6671441cf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF82.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF83.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF83.png new file mode 100644 index 000000000..d47c713e9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF83.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF84.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF84.png new file mode 100644 index 000000000..6311de99b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF84.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF85.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF85.png new file mode 100644 index 000000000..7e51ae105 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF85.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF86.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF86.png new file mode 100644 index 000000000..090c5397c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF86.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF87.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF87.png new file mode 100644 index 000000000..13ee90246 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF87.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF88.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF88.png new file mode 100644 index 000000000..e844d34d1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF88.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF89.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF89.png new file mode 100644 index 000000000..651b90619 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF89.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF8A.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF8A.png new file mode 100644 index 000000000..61fbc226f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF8A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF8B.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF8B.png new file mode 100644 index 000000000..5e9b50133 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF8B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF8C.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF8C.png new file mode 100644 index 000000000..b5e83adf3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF8C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF8D.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF8D.png new file mode 100644 index 000000000..1a5d47093 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF8D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF8E.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF8E.png new file mode 100644 index 000000000..43e35c209 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF8E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF8F.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF8F.png new file mode 100644 index 000000000..e06d71767 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF8F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF90.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF90.png new file mode 100644 index 000000000..fa61da43c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF90.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF91.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF91.png new file mode 100644 index 000000000..b9c78223d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF91.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF92.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF92.png new file mode 100644 index 000000000..e2e7f94d3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF92.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDF93.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDF93.png new file mode 100644 index 000000000..7c4acb6e3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDF93.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFA0.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA0.png new file mode 100644 index 000000000..4cbc26e14 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFA1.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA1.png new file mode 100644 index 000000000..28fcf13ac Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFA2.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA2.png new file mode 100644 index 000000000..622d65dc5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFA3.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA3.png new file mode 100644 index 000000000..15ff55f40 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFA4.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA4.png new file mode 100644 index 000000000..cf506a7a1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFA5.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA5.png new file mode 100644 index 000000000..368520e86 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFA6.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA6.png new file mode 100644 index 000000000..8db7c36e3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFA7.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA7.png new file mode 100644 index 000000000..369bb613c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFA8.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA8.png new file mode 100644 index 000000000..4f262e9d5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFA9.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA9.png new file mode 100644 index 000000000..ded5fb199 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFA9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFAA.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFAA.png new file mode 100644 index 000000000..d3fa2e7b2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFAA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFAB.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFAB.png new file mode 100644 index 000000000..2326b826e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFAB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFAC.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFAC.png new file mode 100644 index 000000000..c4fceb90d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFAC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFAD.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFAD.png new file mode 100644 index 000000000..9ee703b7b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFAD.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFAE.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFAE.png new file mode 100644 index 000000000..24e5e4342 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFAE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFAF.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFAF.png new file mode 100644 index 000000000..a26789adc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFAF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFB0.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB0.png new file mode 100644 index 000000000..9a41f2b94 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFB1.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB1.png new file mode 100644 index 000000000..8b20818eb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFB2.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB2.png new file mode 100644 index 000000000..9b7222fed Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFB3.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB3.png new file mode 100644 index 000000000..fb86d9a10 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFB4.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB4.png new file mode 100644 index 000000000..a6b87f903 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFB5.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB5.png new file mode 100644 index 000000000..e1a645778 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFB6.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB6.png new file mode 100644 index 000000000..81f7b3f5f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFB7.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB7.png new file mode 100644 index 000000000..faeb0417f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFB8.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB8.png new file mode 100644 index 000000000..c37357ab9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFB9.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB9.png new file mode 100644 index 000000000..58690df21 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFB9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFBA.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFBA.png new file mode 100644 index 000000000..3692a3a08 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFBA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFBB.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFBB.png new file mode 100644 index 000000000..3762cabb4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFBB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFBC.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFBC.png new file mode 100644 index 000000000..94407dfd9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFBC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFBD.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFBD.png new file mode 100644 index 000000000..695bc2e91 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFBD.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFBE.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFBE.png new file mode 100644 index 000000000..9ea63d650 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFBE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFBF.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFBF.png new file mode 100644 index 000000000..d9e1c437d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFBF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFC0.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC0.png new file mode 100644 index 000000000..d028df5e2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFC1.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC1.png new file mode 100644 index 000000000..4c8098f00 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFC2.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC2.png new file mode 100644 index 000000000..e94e5a450 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFC3.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC3.png new file mode 100644 index 000000000..0b6eef1bc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFC4.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC4.png new file mode 100644 index 000000000..dd9afd6b0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFC6.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC6.png new file mode 100644 index 000000000..78093ebbc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFC7.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC7.png new file mode 100644 index 000000000..5f3ce95a1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFC8.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC8.png new file mode 100644 index 000000000..ec1895484 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFC9.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC9.png new file mode 100644 index 000000000..ce3ff95f2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFC9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFCA.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFCA.png new file mode 100644 index 000000000..843f65a70 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFCA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFE0.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE0.png new file mode 100644 index 000000000..c548555ca Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFE1.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE1.png new file mode 100644 index 000000000..1820e813d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFE2.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE2.png new file mode 100644 index 000000000..bdbb46684 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFE3.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE3.png new file mode 100644 index 000000000..68e30c185 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFE4.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE4.png new file mode 100644 index 000000000..20084ba9e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFE5.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE5.png new file mode 100644 index 000000000..80f7702bd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFE6.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE6.png new file mode 100644 index 000000000..82014379d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFE7.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE7.png new file mode 100644 index 000000000..7a989c031 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFE8.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE8.png new file mode 100644 index 000000000..c98450a8a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFE9.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE9.png new file mode 100644 index 000000000..aca3a327f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFE9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFEA.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFEA.png new file mode 100644 index 000000000..ad419013f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFEA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFEB.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFEB.png new file mode 100644 index 000000000..10cf3fd25 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFEB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFEC.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFEC.png new file mode 100644 index 000000000..0e230abf4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFEC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFED.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFED.png new file mode 100644 index 000000000..b90c17723 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFED.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFEE.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFEE.png new file mode 100644 index 000000000..3c848169d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFEE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFEF.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFEF.png new file mode 100644 index 000000000..6d6face3a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFEF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83CDFF0.png b/Telegram/SourceFiles/art/Emoji_200x/D83CDFF0.png new file mode 100644 index 000000000..fbcbcac65 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83CDFF0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC00.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC00.png new file mode 100644 index 000000000..05d567d31 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC00.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC01.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC01.png new file mode 100644 index 000000000..174af216b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC01.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC02.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC02.png new file mode 100644 index 000000000..a667a0c5d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC02.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC03.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC03.png new file mode 100644 index 000000000..9f7247172 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC03.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC04.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC04.png new file mode 100644 index 000000000..e1cee8753 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC04.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC05.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC05.png new file mode 100644 index 000000000..4257f4ebf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC05.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC06.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC06.png new file mode 100644 index 000000000..e58daa802 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC06.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC07.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC07.png new file mode 100644 index 000000000..51589d74e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC07.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC08.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC08.png new file mode 100644 index 000000000..852453ed6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC08.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC09.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC09.png new file mode 100644 index 000000000..de24e35a8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC09.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC0A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC0A.png new file mode 100644 index 000000000..27cfb7ff4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC0A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC0B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC0B.png new file mode 100644 index 000000000..931351443 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC0B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC0C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC0C.png new file mode 100644 index 000000000..f9c72d689 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC0C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC0D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC0D.png new file mode 100644 index 000000000..bf7c47893 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC0D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC0E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC0E.png new file mode 100644 index 000000000..79ee818d4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC0E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC0F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC0F.png new file mode 100644 index 000000000..e5581d30f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC0F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC10.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC10.png new file mode 100644 index 000000000..8b2641cfb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC10.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC11.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC11.png new file mode 100644 index 000000000..ae53d7e71 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC11.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC12.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC12.png new file mode 100644 index 000000000..7ae9a574c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC12.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC13.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC13.png new file mode 100644 index 000000000..faab03023 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC13.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC14.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC14.png new file mode 100644 index 000000000..8b0c676ff Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC14.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC15.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC15.png new file mode 100644 index 000000000..f17993ba6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC15.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC16.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC16.png new file mode 100644 index 000000000..e2868afd1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC16.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC17.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC17.png new file mode 100644 index 000000000..fb8be6a0c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC17.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC18.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC18.png new file mode 100644 index 000000000..c4b5bbe53 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC18.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC19.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC19.png new file mode 100644 index 000000000..bfcf92926 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC19.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC1A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC1A.png new file mode 100644 index 000000000..64917172b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC1A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC1B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC1B.png new file mode 100644 index 000000000..cbe373e0f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC1B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC1C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC1C.png new file mode 100644 index 000000000..6c30e029c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC1C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC1D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC1D.png new file mode 100644 index 000000000..635d46fa6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC1D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC1E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC1E.png new file mode 100644 index 000000000..f6e8e4dd0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC1E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC1F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC1F.png new file mode 100644 index 000000000..355dfb7ee Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC1F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC20.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC20.png new file mode 100644 index 000000000..55c541e71 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC20.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC21.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC21.png new file mode 100644 index 000000000..129aa41ce Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC21.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC22.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC22.png new file mode 100644 index 000000000..6c528da0c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC22.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC23.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC23.png new file mode 100644 index 000000000..33038dabc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC23.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC24.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC24.png new file mode 100644 index 000000000..ade6a3741 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC24.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC25.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC25.png new file mode 100644 index 000000000..02a700dce Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC25.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC26.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC26.png new file mode 100644 index 000000000..7c2e92517 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC26.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC27.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC27.png new file mode 100644 index 000000000..22db286fd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC27.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC28.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC28.png new file mode 100644 index 000000000..35aed0f6a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC28.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC29.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC29.png new file mode 100644 index 000000000..2db3f3138 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC29.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC2A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC2A.png new file mode 100644 index 000000000..c0d0d642d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC2A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC2B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC2B.png new file mode 100644 index 000000000..6f8795cb0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC2B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC2C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC2C.png new file mode 100644 index 000000000..7645e5857 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC2C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC2D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC2D.png new file mode 100644 index 000000000..5e384ead9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC2D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC2E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC2E.png new file mode 100644 index 000000000..f4d34421d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC2E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC2F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC2F.png new file mode 100644 index 000000000..9217819b7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC2F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC30.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC30.png new file mode 100644 index 000000000..34946f038 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC30.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC31.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC31.png new file mode 100644 index 000000000..eeefb5f7c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC31.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC32.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC32.png new file mode 100644 index 000000000..03c388f01 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC32.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC33.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC33.png new file mode 100644 index 000000000..d179e8975 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC33.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC34.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC34.png new file mode 100644 index 000000000..b67e7e306 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC34.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC35.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC35.png new file mode 100644 index 000000000..425b9024f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC35.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC36.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC36.png new file mode 100644 index 000000000..72116e0fb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC36.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC37.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC37.png new file mode 100644 index 000000000..1de688c89 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC37.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC38.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC38.png new file mode 100644 index 000000000..2492dd47b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC38.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC39.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC39.png new file mode 100644 index 000000000..e015e6292 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC39.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC3A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC3A.png new file mode 100644 index 000000000..b9150ee6a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC3A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC3B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC3B.png new file mode 100644 index 000000000..ac5bb7d03 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC3B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC3C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC3C.png new file mode 100644 index 000000000..2f69dfa68 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC3C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC3D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC3D.png new file mode 100644 index 000000000..ef709b441 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC3D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC3E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC3E.png new file mode 100644 index 000000000..db349627b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC3E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC40.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC40.png new file mode 100644 index 000000000..9c5f8ab30 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC40.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC42.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC42.png new file mode 100644 index 000000000..42f4090db Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC42.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC43.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC43.png new file mode 100644 index 000000000..6638eeb18 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC43.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC44.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC44.png new file mode 100644 index 000000000..8a1f88bdc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC44.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC45.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC45.png new file mode 100644 index 000000000..cc0f77f6e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC45.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC46.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC46.png new file mode 100644 index 000000000..c6f4500cf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC46.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC47.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC47.png new file mode 100644 index 000000000..c9f526ce5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC47.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC48.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC48.png new file mode 100644 index 000000000..47885c7ba Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC48.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC49.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC49.png new file mode 100644 index 000000000..aeab471dd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC49.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC4A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC4A.png new file mode 100644 index 000000000..1508d819a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC4A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC4B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC4B.png new file mode 100644 index 000000000..055797b08 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC4B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC4C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC4C.png new file mode 100644 index 000000000..7c8d6d2f4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC4C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC4D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC4D.png new file mode 100644 index 000000000..6ca3a943c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC4D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC4E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC4E.png new file mode 100644 index 000000000..5a5b9dcb9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC4E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC4F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC4F.png new file mode 100644 index 000000000..a5aa99dad Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC4F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC50.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC50.png new file mode 100644 index 000000000..66bad4069 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC50.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC51.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC51.png new file mode 100644 index 000000000..0cb5bb5ff Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC51.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC52.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC52.png new file mode 100644 index 000000000..b19b897af Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC52.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC53.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC53.png new file mode 100644 index 000000000..d22e8bed7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC53.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC54.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC54.png new file mode 100644 index 000000000..ec450a7df Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC54.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC55.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC55.png new file mode 100644 index 000000000..8048916f3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC55.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC56.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC56.png new file mode 100644 index 000000000..1410336e1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC56.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC57.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC57.png new file mode 100644 index 000000000..980f9504a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC57.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC58.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC58.png new file mode 100644 index 000000000..bbbabb04c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC58.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC59.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC59.png new file mode 100644 index 000000000..08792f97e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC59.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC5A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC5A.png new file mode 100644 index 000000000..5c3b27a4e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC5A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC5B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC5B.png new file mode 100644 index 000000000..829b2281c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC5B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC5C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC5C.png new file mode 100644 index 000000000..ea50404bf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC5C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC5D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC5D.png new file mode 100644 index 000000000..1cd7c8082 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC5D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC5E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC5E.png new file mode 100644 index 000000000..81813f2bf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC5E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC5F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC5F.png new file mode 100644 index 000000000..db839fb5b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC5F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC60.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC60.png new file mode 100644 index 000000000..7e44d0fd2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC60.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC61.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC61.png new file mode 100644 index 000000000..6e8ae4486 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC61.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC62.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC62.png new file mode 100644 index 000000000..bb3223507 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC62.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC63.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC63.png new file mode 100644 index 000000000..f460a156d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC63.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC64.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC64.png new file mode 100644 index 000000000..9ffe3c8ad Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC64.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC65.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC65.png new file mode 100644 index 000000000..a7e876be8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC65.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC66.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC66.png new file mode 100644 index 000000000..c8ccb2e3c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC66.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC67.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC67.png new file mode 100644 index 000000000..7f5595815 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC67.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC68.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC68.png new file mode 100644 index 000000000..f3d5f82c1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC68.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC69.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC69.png new file mode 100644 index 000000000..9ca0cb68a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC69.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC6A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC6A.png new file mode 100644 index 000000000..49ba1f3b2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC6A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC6B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC6B.png new file mode 100644 index 000000000..c4e15dbff Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC6B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC6C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC6C.png new file mode 100644 index 000000000..f1d662033 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC6C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC6D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC6D.png new file mode 100644 index 000000000..57c492d2c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC6D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC6E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC6E.png new file mode 100644 index 000000000..743935142 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC6E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC6F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC6F.png new file mode 100644 index 000000000..45af61040 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC6F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC70.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC70.png new file mode 100644 index 000000000..ac03bb99c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC70.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC71.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC71.png new file mode 100644 index 000000000..b557ec477 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC71.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC72.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC72.png new file mode 100644 index 000000000..2c3091269 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC72.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC73.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC73.png new file mode 100644 index 000000000..a22edb20d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC73.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC74.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC74.png new file mode 100644 index 000000000..0213ef7b0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC74.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC75.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC75.png new file mode 100644 index 000000000..b5cb604e0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC75.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC76.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC76.png new file mode 100644 index 000000000..652648adc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC76.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC77.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC77.png new file mode 100644 index 000000000..c5151c577 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC77.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC78.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC78.png new file mode 100644 index 000000000..372472465 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC78.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC79.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC79.png new file mode 100644 index 000000000..ee5d900ca Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC79.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC7A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC7A.png new file mode 100644 index 000000000..58bb1b988 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC7A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC7B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC7B.png new file mode 100644 index 000000000..3ebaa49f5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC7B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC7C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC7C.png new file mode 100644 index 000000000..eff1d2f48 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC7C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC7D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC7D.png new file mode 100644 index 000000000..9a6d71f52 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC7D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC7E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC7E.png new file mode 100644 index 000000000..f79bc4add Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC7E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC7F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC7F.png new file mode 100644 index 000000000..341e858bd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC7F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC80.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC80.png new file mode 100644 index 000000000..449ea4242 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC80.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC81.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC81.png new file mode 100644 index 000000000..60709436f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC81.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC82.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC82.png new file mode 100644 index 000000000..88b7242d6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC82.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC83.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC83.png new file mode 100644 index 000000000..0fa57acad Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC83.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC84.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC84.png new file mode 100644 index 000000000..232b12357 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC84.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC85.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC85.png new file mode 100644 index 000000000..d3ad72cd9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC85.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC86.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC86.png new file mode 100644 index 000000000..cb4b4ac79 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC86.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC87.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC87.png new file mode 100644 index 000000000..6c5e3c2b0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC87.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC88.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC88.png new file mode 100644 index 000000000..4c9ea154b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC88.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC89.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC89.png new file mode 100644 index 000000000..9365fa790 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC89.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC8A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC8A.png new file mode 100644 index 000000000..3fd09e307 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC8A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC8B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC8B.png new file mode 100644 index 000000000..f6276e6f5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC8B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC8C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC8C.png new file mode 100644 index 000000000..7112dc7cf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC8C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC8D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC8D.png new file mode 100644 index 000000000..c59b16b08 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC8D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC8E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC8E.png new file mode 100644 index 000000000..2a9abf1af Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC8E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC8F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC8F.png new file mode 100644 index 000000000..e408de16f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC8F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC90.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC90.png new file mode 100644 index 000000000..b4cdde8bc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC90.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC91.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC91.png new file mode 100644 index 000000000..cfcc41e6c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC91.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC92.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC92.png new file mode 100644 index 000000000..3b705a58e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC92.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC93.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC93.png new file mode 100644 index 000000000..56630ddea Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC93.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC94.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC94.png new file mode 100644 index 000000000..3aa00be9e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC94.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC95.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC95.png new file mode 100644 index 000000000..7a908689a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC95.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC96.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC96.png new file mode 100644 index 000000000..fc68b66f7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC96.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC97.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC97.png new file mode 100644 index 000000000..5d12bc18b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC97.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC98.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC98.png new file mode 100644 index 000000000..2876699c3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC98.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC99.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC99.png new file mode 100644 index 000000000..1646bb54f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC99.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC9A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC9A.png new file mode 100644 index 000000000..e0d53e0ed Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC9A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC9B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC9B.png new file mode 100644 index 000000000..3b9617153 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC9B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC9C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC9C.png new file mode 100644 index 000000000..909230678 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC9C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC9D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC9D.png new file mode 100644 index 000000000..f7f7b0ba0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC9D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC9E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC9E.png new file mode 100644 index 000000000..ec7d15ded Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC9E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDC9F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDC9F.png new file mode 100644 index 000000000..169bd8619 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDC9F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCA0.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA0.png new file mode 100644 index 000000000..a4710a554 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCA1.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA1.png new file mode 100644 index 000000000..09cab71d3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCA2.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA2.png new file mode 100644 index 000000000..faece3a8f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCA3.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA3.png new file mode 100644 index 000000000..22cff38d1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCA4.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA4.png new file mode 100644 index 000000000..e331541f3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCA5.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA5.png new file mode 100644 index 000000000..9502db92d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCA6.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA6.png new file mode 100644 index 000000000..7d5c45afd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCA7.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA7.png new file mode 100644 index 000000000..708c31145 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCA8.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA8.png new file mode 100644 index 000000000..6b6e5dd12 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCA9.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA9.png new file mode 100644 index 000000000..f58e74b03 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCA9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCAA.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCAA.png new file mode 100644 index 000000000..9d66acec3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCAA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCAB.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCAB.png new file mode 100644 index 000000000..83b8515df Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCAB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCAC.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCAC.png new file mode 100644 index 000000000..358c93316 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCAC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCAD.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCAD.png new file mode 100644 index 000000000..2dc8fef96 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCAD.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCAE.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCAE.png new file mode 100644 index 000000000..d2b083db3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCAE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCAF.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCAF.png new file mode 100644 index 000000000..f2ece046b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCAF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCB0.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB0.png new file mode 100644 index 000000000..93b74a4d3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCB1.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB1.png new file mode 100644 index 000000000..3da65e5d8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCB2.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB2.png new file mode 100644 index 000000000..0f88aea52 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCB3.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB3.png new file mode 100644 index 000000000..bfa945fad Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCB4.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB4.png new file mode 100644 index 000000000..682870866 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCB5.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB5.png new file mode 100644 index 000000000..215785e6a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCB6.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB6.png new file mode 100644 index 000000000..d096caf53 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCB7.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB7.png new file mode 100644 index 000000000..baa8c938b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCB8.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB8.png new file mode 100644 index 000000000..c13f1398e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCB9.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB9.png new file mode 100644 index 000000000..a26922dff Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCB9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCBA.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCBA.png new file mode 100644 index 000000000..726bb639b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCBA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCBB.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCBB.png new file mode 100644 index 000000000..64b1b3ce9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCBB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCBC.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCBC.png new file mode 100644 index 000000000..0dfced070 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCBC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCBD.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCBD.png new file mode 100644 index 000000000..eefee3811 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCBD.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCBE.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCBE.png new file mode 100644 index 000000000..a78d368b6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCBE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCBF.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCBF.png new file mode 100644 index 000000000..ac6555a5e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCBF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCC0.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC0.png new file mode 100644 index 000000000..508479b47 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCC1.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC1.png new file mode 100644 index 000000000..fede38853 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCC2.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC2.png new file mode 100644 index 000000000..3d78ba3e1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCC3.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC3.png new file mode 100644 index 000000000..ab4c984d5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCC4.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC4.png new file mode 100644 index 000000000..e45bf0ebd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCC5.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC5.png new file mode 100644 index 000000000..ead39039a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCC6.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC6.png new file mode 100644 index 000000000..df7e55e3b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCC7.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC7.png new file mode 100644 index 000000000..454e21e9f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCC8.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC8.png new file mode 100644 index 000000000..5d2177970 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCC9.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC9.png new file mode 100644 index 000000000..d9a7d9ae6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCC9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCCA.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCCA.png new file mode 100644 index 000000000..952a2935f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCCA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCCB.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCCB.png new file mode 100644 index 000000000..4ad220b97 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCCB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCCC.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCCC.png new file mode 100644 index 000000000..8dffd7e62 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCCC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCCD.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCCD.png new file mode 100644 index 000000000..b312b8071 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCCD.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCCE.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCCE.png new file mode 100644 index 000000000..d5f79d022 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCCE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCCF.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCCF.png new file mode 100644 index 000000000..5a42e3d2a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCCF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCD0.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD0.png new file mode 100644 index 000000000..b4f5d7cbf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCD1.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD1.png new file mode 100644 index 000000000..49e0dd3f9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCD2.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD2.png new file mode 100644 index 000000000..5549c62b1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCD3.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD3.png new file mode 100644 index 000000000..b4c4fee23 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCD4.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD4.png new file mode 100644 index 000000000..ab963a7c0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCD5.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD5.png new file mode 100644 index 000000000..1a45000af Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCD6.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD6.png new file mode 100644 index 000000000..eb0163436 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCD7.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD7.png new file mode 100644 index 000000000..c34c7f36a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCD8.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD8.png new file mode 100644 index 000000000..1ee39138b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCD9.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD9.png new file mode 100644 index 000000000..1309b8bcf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCD9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCDA.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCDA.png new file mode 100644 index 000000000..24dbf0e24 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCDA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCDB.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCDB.png new file mode 100644 index 000000000..b459b4cec Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCDB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCDC.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCDC.png new file mode 100644 index 000000000..a74bbffa6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCDC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCDD.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCDD.png new file mode 100644 index 000000000..24446a5fe Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCDD.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCDE.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCDE.png new file mode 100644 index 000000000..2888c5daa Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCDE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCDF.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCDF.png new file mode 100644 index 000000000..be57d831a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCDF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCE0.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE0.png new file mode 100644 index 000000000..d699782e9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCE1.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE1.png new file mode 100644 index 000000000..be125e3d7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCE2.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE2.png new file mode 100644 index 000000000..a9bd2a0cc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCE3.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE3.png new file mode 100644 index 000000000..5dd94cf5f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCE4.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE4.png new file mode 100644 index 000000000..894e8b088 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCE5.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE5.png new file mode 100644 index 000000000..79e4699d5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCE6.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE6.png new file mode 100644 index 000000000..9411c1744 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCE7.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE7.png new file mode 100644 index 000000000..d91bd9b50 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCE8.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE8.png new file mode 100644 index 000000000..72ccebc74 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCE9.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE9.png new file mode 100644 index 000000000..ee379898f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCE9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCEA.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCEA.png new file mode 100644 index 000000000..f85dffdf1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCEA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCEB.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCEB.png new file mode 100644 index 000000000..9b33e58f1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCEB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCEC.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCEC.png new file mode 100644 index 000000000..48d689673 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCEC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCED.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCED.png new file mode 100644 index 000000000..806c74f9e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCED.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCEE.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCEE.png new file mode 100644 index 000000000..8dc267f01 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCEE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCEF.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCEF.png new file mode 100644 index 000000000..004844dd8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCEF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCF0.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF0.png new file mode 100644 index 000000000..38b9efb10 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCF1.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF1.png new file mode 100644 index 000000000..62b978d01 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCF2.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF2.png new file mode 100644 index 000000000..88c052408 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCF3.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF3.png new file mode 100644 index 000000000..759298aa0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCF4.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF4.png new file mode 100644 index 000000000..330bd8f78 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCF5.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF5.png new file mode 100644 index 000000000..25e2b4292 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCF6.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF6.png new file mode 100644 index 000000000..cd89d66ef Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCF7.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF7.png new file mode 100644 index 000000000..95ba6e68b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCF9.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF9.png new file mode 100644 index 000000000..0b5dbe0b1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCF9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCFA.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCFA.png new file mode 100644 index 000000000..5a49e5cf9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCFA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCFB.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCFB.png new file mode 100644 index 000000000..b061488a8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCFB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDCFC.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDCFC.png new file mode 100644 index 000000000..3ad233dd2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDCFC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD00.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD00.png new file mode 100644 index 000000000..5d9a82267 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD00.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD01.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD01.png new file mode 100644 index 000000000..af63735c5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD01.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD02.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD02.png new file mode 100644 index 000000000..a1adae3ab Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD02.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD03.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD03.png new file mode 100644 index 000000000..901572ec2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD03.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD04.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD04.png new file mode 100644 index 000000000..b851be324 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD04.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD05.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD05.png new file mode 100644 index 000000000..0db16405a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD05.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD06.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD06.png new file mode 100644 index 000000000..2cc7f16f0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD06.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD07.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD07.png new file mode 100644 index 000000000..59da65ae0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD07.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD08.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD08.png new file mode 100644 index 000000000..2b9a77ff1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD08.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD09.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD09.png new file mode 100644 index 000000000..766294402 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD09.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD0A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD0A.png new file mode 100644 index 000000000..d4113851f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD0A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD0B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD0B.png new file mode 100644 index 000000000..c94655f39 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD0B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD0C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD0C.png new file mode 100644 index 000000000..a20bc3f0a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD0C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD0D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD0D.png new file mode 100644 index 000000000..bc89453e0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD0D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD0E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD0E.png new file mode 100644 index 000000000..95ceeeb64 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD0E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD0F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD0F.png new file mode 100644 index 000000000..03dfb30c9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD0F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD10.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD10.png new file mode 100644 index 000000000..ce24ea08e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD10.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD11.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD11.png new file mode 100644 index 000000000..18b1238dc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD11.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD12.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD12.png new file mode 100644 index 000000000..0687ee6e3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD12.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD13.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD13.png new file mode 100644 index 000000000..35f44c9e6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD13.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD14.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD14.png new file mode 100644 index 000000000..92e82ba18 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD14.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD15.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD15.png new file mode 100644 index 000000000..85f58eb08 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD15.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD16.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD16.png new file mode 100644 index 000000000..0e4346fbf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD16.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD17.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD17.png new file mode 100644 index 000000000..fca8de1f3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD17.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD18.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD18.png new file mode 100644 index 000000000..1c4a9de16 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD18.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD19.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD19.png new file mode 100644 index 000000000..378a07cae Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD19.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD1A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD1A.png new file mode 100644 index 000000000..7d0ed9985 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD1A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD1B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD1B.png new file mode 100644 index 000000000..4edbd61d4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD1B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD1C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD1C.png new file mode 100644 index 000000000..4154b8692 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD1C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD1D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD1D.png new file mode 100644 index 000000000..c4b9ef164 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD1D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD1E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD1E.png new file mode 100644 index 000000000..8353724dd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD1E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD1F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD1F.png new file mode 100644 index 000000000..acee5a011 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD1F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD20.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD20.png new file mode 100644 index 000000000..eb1627073 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD20.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD21.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD21.png new file mode 100644 index 000000000..94a078a45 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD21.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD22.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD22.png new file mode 100644 index 000000000..4fd28f941 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD22.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD23.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD23.png new file mode 100644 index 000000000..08a19dee8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD23.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD24.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD24.png new file mode 100644 index 000000000..58fe8347d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD24.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD25.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD25.png new file mode 100644 index 000000000..8b9757da8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD25.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD26.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD26.png new file mode 100644 index 000000000..4e586fb42 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD26.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD27.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD27.png new file mode 100644 index 000000000..b82006ff3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD27.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD28.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD28.png new file mode 100644 index 000000000..0ba8f6337 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD28.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD29.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD29.png new file mode 100644 index 000000000..dd9ca9350 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD29.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD2A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD2A.png new file mode 100644 index 000000000..bffa1af11 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD2A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD2B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD2B.png new file mode 100644 index 000000000..3b19914b8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD2B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD2C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD2C.png new file mode 100644 index 000000000..c2fd38b47 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD2C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD2D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD2D.png new file mode 100644 index 000000000..fd98f02c3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD2D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD2E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD2E.png new file mode 100644 index 000000000..d4e5edbc8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD2E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD2F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD2F.png new file mode 100644 index 000000000..035b37ab5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD2F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD30.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD30.png new file mode 100644 index 000000000..3a9f66301 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD30.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD31.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD31.png new file mode 100644 index 000000000..5855c5a98 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD31.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD32.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD32.png new file mode 100644 index 000000000..df757d5d7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD32.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD33.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD33.png new file mode 100644 index 000000000..a0328de92 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD33.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD34.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD34.png new file mode 100644 index 000000000..25f577781 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD34.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD35.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD35.png new file mode 100644 index 000000000..53193bced Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD35.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD36.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD36.png new file mode 100644 index 000000000..fd5950728 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD36.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD37.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD37.png new file mode 100644 index 000000000..1889961b0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD37.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD38.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD38.png new file mode 100644 index 000000000..8fcd15d60 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD38.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD39.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD39.png new file mode 100644 index 000000000..719c0f688 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD39.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD3A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD3A.png new file mode 100644 index 000000000..4ec327a3c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD3A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD3B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD3B.png new file mode 100644 index 000000000..193261f1c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD3B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD3C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD3C.png new file mode 100644 index 000000000..227afffe5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD3C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD3D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD3D.png new file mode 100644 index 000000000..fcccf2fc2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD3D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD50.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD50.png new file mode 100644 index 000000000..0047d00ce Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD50.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD51.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD51.png new file mode 100644 index 000000000..d62bd65b4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD51.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD52.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD52.png new file mode 100644 index 000000000..7f6bdf989 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD52.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD53.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD53.png new file mode 100644 index 000000000..9a465efa2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD53.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD54.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD54.png new file mode 100644 index 000000000..2bf4d53db Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD54.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD55.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD55.png new file mode 100644 index 000000000..6025f4b93 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD55.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD56.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD56.png new file mode 100644 index 000000000..b9193acd7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD56.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD57.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD57.png new file mode 100644 index 000000000..119e8e5c9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD57.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD58.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD58.png new file mode 100644 index 000000000..f605e1e71 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD58.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD59.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD59.png new file mode 100644 index 000000000..d4c5468eb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD59.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD5A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD5A.png new file mode 100644 index 000000000..f3443de5d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD5A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD5B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD5B.png new file mode 100644 index 000000000..e980fae98 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD5B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD5C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD5C.png new file mode 100644 index 000000000..4263adb50 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD5C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD5D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD5D.png new file mode 100644 index 000000000..613c6fcb0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD5D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD5E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD5E.png new file mode 100644 index 000000000..6a6536e45 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD5E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD5F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD5F.png new file mode 100644 index 000000000..407ab48bf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD5F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD60.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD60.png new file mode 100644 index 000000000..bb8fc787c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD60.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD61.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD61.png new file mode 100644 index 000000000..85abfc19d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD61.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD62.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD62.png new file mode 100644 index 000000000..29658cfa2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD62.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD63.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD63.png new file mode 100644 index 000000000..f894aef37 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD63.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD64.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD64.png new file mode 100644 index 000000000..9cb385612 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD64.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD65.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD65.png new file mode 100644 index 000000000..5bf8741bf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD65.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD66.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD66.png new file mode 100644 index 000000000..2267c382b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD66.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDD67.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDD67.png new file mode 100644 index 000000000..3e4b4904e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDD67.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDDFB.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDDFB.png new file mode 100644 index 000000000..1efaf8967 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDDFB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDDFC.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDDFC.png new file mode 100644 index 000000000..68a99ecd8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDDFC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDDFD.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDDFD.png new file mode 100644 index 000000000..159612368 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDDFD.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDDFE.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDDFE.png new file mode 100644 index 000000000..31a70da2d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDDFE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDDFF.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDDFF.png new file mode 100644 index 000000000..62ff06257 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDDFF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE00.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE00.png new file mode 100644 index 000000000..b8d72e9af Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE00.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE01.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE01.png new file mode 100644 index 000000000..ba9c093fd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE01.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE02.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE02.png new file mode 100644 index 000000000..96b6e233e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE02.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE03.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE03.png new file mode 100644 index 000000000..55d41eec0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE03.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE04.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE04.png new file mode 100644 index 000000000..cf577613a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE04.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE05.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE05.png new file mode 100644 index 000000000..47f206c24 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE05.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE06.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE06.png new file mode 100644 index 000000000..4768eb7e9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE06.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE07.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE07.png new file mode 100644 index 000000000..53a738ad7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE07.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE08.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE08.png new file mode 100644 index 000000000..a30704e16 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE08.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE09.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE09.png new file mode 100644 index 000000000..15f01c9d7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE09.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE0A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE0A.png new file mode 100644 index 000000000..5ec63cc72 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE0A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE0B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE0B.png new file mode 100644 index 000000000..b0072e5cc Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE0B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE0C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE0C.png new file mode 100644 index 000000000..bdf4bc61c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE0C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE0D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE0D.png new file mode 100644 index 000000000..d6ca1b5c7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE0D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE0E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE0E.png new file mode 100644 index 000000000..31418a7b2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE0E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE0F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE0F.png new file mode 100644 index 000000000..caa85b30c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE0F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE10.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE10.png new file mode 100644 index 000000000..13ed22eac Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE10.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE11.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE11.png new file mode 100644 index 000000000..f3bef3f8b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE11.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE12.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE12.png new file mode 100644 index 000000000..0efd3c4cd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE12.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE13.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE13.png new file mode 100644 index 000000000..f877a2f3f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE13.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE14.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE14.png new file mode 100644 index 000000000..46afc2be0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE14.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE15.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE15.png new file mode 100644 index 000000000..e7d7ec7cd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE15.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE16.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE16.png new file mode 100644 index 000000000..3d5030092 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE16.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE17.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE17.png new file mode 100644 index 000000000..dce5b9207 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE17.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE18.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE18.png new file mode 100644 index 000000000..b8beb9939 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE18.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE19.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE19.png new file mode 100644 index 000000000..a0f703f9f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE19.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE1A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE1A.png new file mode 100644 index 000000000..15b8934ee Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE1A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE1B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE1B.png new file mode 100644 index 000000000..3021b7c9f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE1B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE1C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE1C.png new file mode 100644 index 000000000..2058d5970 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE1C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE1D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE1D.png new file mode 100644 index 000000000..b55044d96 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE1D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE1E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE1E.png new file mode 100644 index 000000000..cbf24e004 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE1E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE1F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE1F.png new file mode 100644 index 000000000..639329fb1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE1F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE20.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE20.png new file mode 100644 index 000000000..a3ae6862f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE20.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE21.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE21.png new file mode 100644 index 000000000..24955a6e5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE21.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE22.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE22.png new file mode 100644 index 000000000..cbf9f082a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE22.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE23.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE23.png new file mode 100644 index 000000000..0c72e0b7e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE23.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE24.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE24.png new file mode 100644 index 000000000..8bfdcf58a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE24.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE25.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE25.png new file mode 100644 index 000000000..b361fc24f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE25.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE26.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE26.png new file mode 100644 index 000000000..7f05ca411 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE26.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE27.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE27.png new file mode 100644 index 000000000..07e6cd63b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE27.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE28.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE28.png new file mode 100644 index 000000000..26284ea1d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE28.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE29.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE29.png new file mode 100644 index 000000000..22e597389 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE29.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE2A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE2A.png new file mode 100644 index 000000000..3c48683b2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE2A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE2B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE2B.png new file mode 100644 index 000000000..ba234a8ba Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE2B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE2C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE2C.png new file mode 100644 index 000000000..57fd6145d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE2C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE2D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE2D.png new file mode 100644 index 000000000..0ca4ff178 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE2D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE2E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE2E.png new file mode 100644 index 000000000..bbd705122 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE2E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE2F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE2F.png new file mode 100644 index 000000000..e1c6a5015 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE2F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE30.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE30.png new file mode 100644 index 000000000..e89cc19b8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE30.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE31.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE31.png new file mode 100644 index 000000000..e9759b6f4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE31.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE32.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE32.png new file mode 100644 index 000000000..c8d7543b7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE32.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE33.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE33.png new file mode 100644 index 000000000..ce13a1108 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE33.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE34.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE34.png new file mode 100644 index 000000000..9d9405cc6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE34.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE35.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE35.png new file mode 100644 index 000000000..75fe52bee Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE35.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE36.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE36.png new file mode 100644 index 000000000..ac79dfcd8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE36.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE37.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE37.png new file mode 100644 index 000000000..2d7361c32 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE37.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE38.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE38.png new file mode 100644 index 000000000..4f6194ad1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE38.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE39.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE39.png new file mode 100644 index 000000000..1212644e8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE39.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE3A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE3A.png new file mode 100644 index 000000000..85ffa5946 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE3A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE3B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE3B.png new file mode 100644 index 000000000..3789c2ddd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE3B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE3C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE3C.png new file mode 100644 index 000000000..eef2547a3 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE3C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE3D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE3D.png new file mode 100644 index 000000000..602ea99fe Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE3D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE3E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE3E.png new file mode 100644 index 000000000..086f8cf09 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE3E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE3F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE3F.png new file mode 100644 index 000000000..ea5ea5b34 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE3F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE40.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE40.png new file mode 100644 index 000000000..e9a78c36a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE40.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE45.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE45.png new file mode 100644 index 000000000..25c90ec60 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE45.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE46.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE46.png new file mode 100644 index 000000000..7bf3f5f89 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE46.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE47.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE47.png new file mode 100644 index 000000000..27d93e080 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE47.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE48.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE48.png new file mode 100644 index 000000000..2f9334ab9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE48.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE49.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE49.png new file mode 100644 index 000000000..84c3c2749 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE49.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE4A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE4A.png new file mode 100644 index 000000000..2ca2f98b5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE4A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE4B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE4B.png new file mode 100644 index 000000000..f3ef2e951 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE4B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE4C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE4C.png new file mode 100644 index 000000000..af638a128 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE4C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE4D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE4D.png new file mode 100644 index 000000000..a580062cb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE4D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE4E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE4E.png new file mode 100644 index 000000000..775bb2d56 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE4E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE4F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE4F.png new file mode 100644 index 000000000..7c1df639e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE4F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE80.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE80.png new file mode 100644 index 000000000..224e102c5 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE80.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE81.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE81.png new file mode 100644 index 000000000..2ee806bcb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE81.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE82.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE82.png new file mode 100644 index 000000000..cac179e76 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE82.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE83.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE83.png new file mode 100644 index 000000000..6ca12967c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE83.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE84.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE84.png new file mode 100644 index 000000000..278108b36 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE84.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE85.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE85.png new file mode 100644 index 000000000..5280c4897 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE85.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE86.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE86.png new file mode 100644 index 000000000..c27590560 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE86.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE87.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE87.png new file mode 100644 index 000000000..e98033ab0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE87.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE88.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE88.png new file mode 100644 index 000000000..f248aa309 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE88.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE89.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE89.png new file mode 100644 index 000000000..c21f54a64 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE89.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE8A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE8A.png new file mode 100644 index 000000000..91efb9a29 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE8A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE8B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE8B.png new file mode 100644 index 000000000..fd6501b14 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE8B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE8C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE8C.png new file mode 100644 index 000000000..bce0c8e6f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE8C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE8D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE8D.png new file mode 100644 index 000000000..b7834d9ef Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE8D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE8E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE8E.png new file mode 100644 index 000000000..84f65e529 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE8E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE8F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE8F.png new file mode 100644 index 000000000..a78da5416 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE8F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE90.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE90.png new file mode 100644 index 000000000..907d67b5b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE90.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE91.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE91.png new file mode 100644 index 000000000..6312ecddb Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE91.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE92.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE92.png new file mode 100644 index 000000000..b5975da28 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE92.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE93.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE93.png new file mode 100644 index 000000000..8a0667b9c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE93.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE94.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE94.png new file mode 100644 index 000000000..5020711d0 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE94.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE95.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE95.png new file mode 100644 index 000000000..532babcbd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE95.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE96.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE96.png new file mode 100644 index 000000000..ace90541f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE96.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE97.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE97.png new file mode 100644 index 000000000..cfd2471f7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE97.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE98.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE98.png new file mode 100644 index 000000000..95f71f6ae Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE98.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE99.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE99.png new file mode 100644 index 000000000..5d6b7dc19 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE99.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE9A.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE9A.png new file mode 100644 index 000000000..3d2b22195 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE9A.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE9B.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE9B.png new file mode 100644 index 000000000..7eac37e74 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE9B.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE9C.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE9C.png new file mode 100644 index 000000000..cf008ad2a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE9C.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE9D.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE9D.png new file mode 100644 index 000000000..609419d82 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE9D.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE9E.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE9E.png new file mode 100644 index 000000000..31c2888a8 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE9E.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDE9F.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDE9F.png new file mode 100644 index 000000000..f5f3e9cc1 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDE9F.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEA0.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA0.png new file mode 100644 index 000000000..6bb475789 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEA1.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA1.png new file mode 100644 index 000000000..7a7a0809e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEA2.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA2.png new file mode 100644 index 000000000..8ddba2c0a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEA3.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA3.png new file mode 100644 index 000000000..5eb71516e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEA4.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA4.png new file mode 100644 index 000000000..d15d5adb2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEA5.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA5.png new file mode 100644 index 000000000..e4f26bd44 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEA6.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA6.png new file mode 100644 index 000000000..6dccf0c6f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEA7.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA7.png new file mode 100644 index 000000000..c9a9e916e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEA8.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA8.png new file mode 100644 index 000000000..b17f9297d Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEA9.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA9.png new file mode 100644 index 000000000..9a00eff64 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEA9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEAA.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEAA.png new file mode 100644 index 000000000..1496590d2 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEAA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEAB.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEAB.png new file mode 100644 index 000000000..d268825a7 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEAB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEAC.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEAC.png new file mode 100644 index 000000000..d067f9a0f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEAC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEAD.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEAD.png new file mode 100644 index 000000000..2d3e590e6 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEAD.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEAE.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEAE.png new file mode 100644 index 000000000..32ab88dea Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEAE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEAF.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEAF.png new file mode 100644 index 000000000..70732d27e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEAF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEB0.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB0.png new file mode 100644 index 000000000..22134b75e Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEB1.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB1.png new file mode 100644 index 000000000..41bb6daf4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEB2.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB2.png new file mode 100644 index 000000000..c6ff95ee9 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEB3.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB3.png new file mode 100644 index 000000000..2c602a360 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEB4.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB4.png new file mode 100644 index 000000000..2d07f2073 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEB5.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB5.png new file mode 100644 index 000000000..c08d0022a Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB5.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEB6.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB6.png new file mode 100644 index 000000000..4015033fe Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB6.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEB7.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB7.png new file mode 100644 index 000000000..2cdad11fd Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB7.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEB8.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB8.png new file mode 100644 index 000000000..017fe3a2c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB8.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEB9.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB9.png new file mode 100644 index 000000000..8f5ac8759 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEB9.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEBA.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEBA.png new file mode 100644 index 000000000..7288f7857 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEBA.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEBB.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEBB.png new file mode 100644 index 000000000..b108f3937 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEBB.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEBC.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEBC.png new file mode 100644 index 000000000..0e932718b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEBC.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEBD.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEBD.png new file mode 100644 index 000000000..18c41beaf Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEBD.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEBE.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEBE.png new file mode 100644 index 000000000..8e5fed276 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEBE.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEBF.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEBF.png new file mode 100644 index 000000000..1f4047975 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEBF.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEC0.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEC0.png new file mode 100644 index 000000000..a1462bcc4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEC0.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEC1.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEC1.png new file mode 100644 index 000000000..70074c842 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEC1.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEC2.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEC2.png new file mode 100644 index 000000000..e3fa4043f Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEC2.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEC3.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEC3.png new file mode 100644 index 000000000..2aade255c Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEC3.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEC4.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEC4.png new file mode 100644 index 000000000..8598c82c4 Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEC4.png differ diff --git a/Telegram/SourceFiles/art/Emoji_200x/D83DDEC5.png b/Telegram/SourceFiles/art/Emoji_200x/D83DDEC5.png new file mode 100644 index 000000000..2dd6d6f6b Binary files /dev/null and b/Telegram/SourceFiles/art/Emoji_200x/D83DDEC5.png differ diff --git a/Telegram/SourceFiles/art/ThoolikaTrditionalUnicode.ttf b/Telegram/SourceFiles/art/ThoolikaTrditionalUnicode.ttf new file mode 100644 index 000000000..00394ae16 Binary files /dev/null and b/Telegram/SourceFiles/art/ThoolikaTrditionalUnicode.ttf differ diff --git a/Telegram/SourceFiles/art/bg.png b/Telegram/SourceFiles/art/bg.png new file mode 100644 index 000000000..8c5073a61 Binary files /dev/null and b/Telegram/SourceFiles/art/bg.png differ diff --git a/Telegram/SourceFiles/art/bg_125x.png b/Telegram/SourceFiles/art/bg_125x.png new file mode 100644 index 000000000..697e360c3 Binary files /dev/null and b/Telegram/SourceFiles/art/bg_125x.png differ diff --git a/Telegram/SourceFiles/art/bg_150x.png b/Telegram/SourceFiles/art/bg_150x.png new file mode 100644 index 000000000..56d1fdcd4 Binary files /dev/null and b/Telegram/SourceFiles/art/bg_150x.png differ diff --git a/Telegram/SourceFiles/art/bg_200x.png b/Telegram/SourceFiles/art/bg_200x.png new file mode 100644 index 000000000..bb77a20c3 Binary files /dev/null and b/Telegram/SourceFiles/art/bg_200x.png differ diff --git a/Telegram/SourceFiles/art/blank.gif b/Telegram/SourceFiles/art/blank.gif new file mode 100644 index 000000000..75b945d25 Binary files /dev/null and b/Telegram/SourceFiles/art/blank.gif differ diff --git a/Telegram/SourceFiles/art/chatcolor1.png b/Telegram/SourceFiles/art/chatcolor1.png new file mode 100644 index 000000000..77d012f8a Binary files /dev/null and b/Telegram/SourceFiles/art/chatcolor1.png differ diff --git a/Telegram/SourceFiles/art/chatcolor2.png b/Telegram/SourceFiles/art/chatcolor2.png new file mode 100644 index 000000000..b637934d9 Binary files /dev/null and b/Telegram/SourceFiles/art/chatcolor2.png differ diff --git a/Telegram/SourceFiles/art/chatcolor3.png b/Telegram/SourceFiles/art/chatcolor3.png new file mode 100644 index 000000000..ad3cc7ed6 Binary files /dev/null and b/Telegram/SourceFiles/art/chatcolor3.png differ diff --git a/Telegram/SourceFiles/art/chatcolor4.png b/Telegram/SourceFiles/art/chatcolor4.png new file mode 100644 index 000000000..5d54ea480 Binary files /dev/null and b/Telegram/SourceFiles/art/chatcolor4.png differ diff --git a/Telegram/SourceFiles/art/emoji.png b/Telegram/SourceFiles/art/emoji.png new file mode 100644 index 000000000..6496e59d7 Binary files /dev/null and b/Telegram/SourceFiles/art/emoji.png differ diff --git a/Telegram/SourceFiles/art/emoji_125x.png b/Telegram/SourceFiles/art/emoji_125x.png new file mode 100644 index 000000000..fff1fe01b Binary files /dev/null and b/Telegram/SourceFiles/art/emoji_125x.png differ diff --git a/Telegram/SourceFiles/art/emoji_150x.png b/Telegram/SourceFiles/art/emoji_150x.png new file mode 100644 index 000000000..9e100664c Binary files /dev/null and b/Telegram/SourceFiles/art/emoji_150x.png differ diff --git a/Telegram/SourceFiles/art/emoji_200x.png b/Telegram/SourceFiles/art/emoji_200x.png new file mode 100644 index 000000000..e30686ef8 Binary files /dev/null and b/Telegram/SourceFiles/art/emoji_200x.png differ diff --git a/Telegram/SourceFiles/art/favicon.ico b/Telegram/SourceFiles/art/favicon.ico new file mode 100644 index 000000000..5f62ac8a6 Binary files /dev/null and b/Telegram/SourceFiles/art/favicon.ico differ diff --git a/Telegram/SourceFiles/art/grid.png b/Telegram/SourceFiles/art/grid.png new file mode 100644 index 000000000..b886b374d Binary files /dev/null and b/Telegram/SourceFiles/art/grid.png differ diff --git a/Telegram/SourceFiles/art/grid_125x.png b/Telegram/SourceFiles/art/grid_125x.png new file mode 100644 index 000000000..40409c8b8 Binary files /dev/null and b/Telegram/SourceFiles/art/grid_125x.png differ diff --git a/Telegram/SourceFiles/art/grid_150x.png b/Telegram/SourceFiles/art/grid_150x.png new file mode 100644 index 000000000..ceaa29ce4 Binary files /dev/null and b/Telegram/SourceFiles/art/grid_150x.png differ diff --git a/Telegram/SourceFiles/art/grid_200x.png b/Telegram/SourceFiles/art/grid_200x.png new file mode 100644 index 000000000..2316f49f3 Binary files /dev/null and b/Telegram/SourceFiles/art/grid_200x.png differ diff --git a/Telegram/SourceFiles/art/icon.ico b/Telegram/SourceFiles/art/icon.ico new file mode 100644 index 000000000..e6e430ee1 Binary files /dev/null and b/Telegram/SourceFiles/art/icon.ico differ diff --git a/Telegram/SourceFiles/art/icon.png b/Telegram/SourceFiles/art/icon.png new file mode 100644 index 000000000..4e53389ae Binary files /dev/null and b/Telegram/SourceFiles/art/icon.png differ diff --git a/Telegram/SourceFiles/art/iconbig.png b/Telegram/SourceFiles/art/iconbig.png new file mode 100644 index 000000000..fb3d3c175 Binary files /dev/null and b/Telegram/SourceFiles/art/iconbig.png differ diff --git a/Telegram/SourceFiles/art/iconf.png b/Telegram/SourceFiles/art/iconf.png new file mode 100644 index 000000000..fa9c541a6 Binary files /dev/null and b/Telegram/SourceFiles/art/iconf.png differ diff --git a/Telegram/SourceFiles/art/iconround128.png b/Telegram/SourceFiles/art/iconround128.png new file mode 100644 index 000000000..79c3efba3 Binary files /dev/null and b/Telegram/SourceFiles/art/iconround128.png differ diff --git a/Telegram/SourceFiles/art/iconround16.png b/Telegram/SourceFiles/art/iconround16.png new file mode 100644 index 000000000..94617bb4c Binary files /dev/null and b/Telegram/SourceFiles/art/iconround16.png differ diff --git a/Telegram/SourceFiles/art/iconround256.ico b/Telegram/SourceFiles/art/iconround256.ico new file mode 100644 index 000000000..718f5a706 Binary files /dev/null and b/Telegram/SourceFiles/art/iconround256.ico differ diff --git a/Telegram/SourceFiles/art/iconround256.png b/Telegram/SourceFiles/art/iconround256.png new file mode 100644 index 000000000..92566ae16 Binary files /dev/null and b/Telegram/SourceFiles/art/iconround256.png differ diff --git a/Telegram/SourceFiles/art/iconroundbig.ico b/Telegram/SourceFiles/art/iconroundbig.ico new file mode 100644 index 000000000..0d81d1081 Binary files /dev/null and b/Telegram/SourceFiles/art/iconroundbig.ico differ diff --git a/Telegram/SourceFiles/art/iconroundbig.png b/Telegram/SourceFiles/art/iconroundbig.png new file mode 100644 index 000000000..9b249bac3 Binary files /dev/null and b/Telegram/SourceFiles/art/iconroundbig.png differ diff --git a/Telegram/SourceFiles/art/iconrounddark.bmp b/Telegram/SourceFiles/art/iconrounddark.bmp new file mode 100644 index 000000000..e09bb6a0e Binary files /dev/null and b/Telegram/SourceFiles/art/iconrounddark.bmp differ diff --git a/Telegram/SourceFiles/art/iconroundfull.png b/Telegram/SourceFiles/art/iconroundfull.png new file mode 100644 index 000000000..7576358c3 Binary files /dev/null and b/Telegram/SourceFiles/art/iconroundfull.png differ diff --git a/Telegram/SourceFiles/art/icons.png b/Telegram/SourceFiles/art/icons.png new file mode 100644 index 000000000..6729c2a2f Binary files /dev/null and b/Telegram/SourceFiles/art/icons.png differ diff --git a/Telegram/SourceFiles/art/newmsg.wav b/Telegram/SourceFiles/art/newmsg.wav new file mode 100644 index 000000000..262941fa2 Binary files /dev/null and b/Telegram/SourceFiles/art/newmsg.wav differ diff --git a/Telegram/SourceFiles/art/segoe_ui.ttf b/Telegram/SourceFiles/art/segoe_ui.ttf new file mode 100644 index 000000000..ed52fc683 Binary files /dev/null and b/Telegram/SourceFiles/art/segoe_ui.ttf differ diff --git a/Telegram/SourceFiles/art/segoe_ui_semibold.ttf b/Telegram/SourceFiles/art/segoe_ui_semibold.ttf new file mode 100644 index 000000000..82cafee64 Binary files /dev/null and b/Telegram/SourceFiles/art/segoe_ui_semibold.ttf differ diff --git a/Telegram/SourceFiles/art/segoe_wp_semibold.ttf b/Telegram/SourceFiles/art/segoe_wp_semibold.ttf new file mode 100644 index 000000000..2d067e4a8 Binary files /dev/null and b/Telegram/SourceFiles/art/segoe_wp_semibold.ttf differ diff --git a/Telegram/SourceFiles/art/sprite.png b/Telegram/SourceFiles/art/sprite.png new file mode 100644 index 000000000..b1713b073 Binary files /dev/null and b/Telegram/SourceFiles/art/sprite.png differ diff --git a/Telegram/SourceFiles/art/sprite_125x.png b/Telegram/SourceFiles/art/sprite_125x.png new file mode 100644 index 000000000..ddac976c6 Binary files /dev/null and b/Telegram/SourceFiles/art/sprite_125x.png differ diff --git a/Telegram/SourceFiles/art/sprite_150x.png b/Telegram/SourceFiles/art/sprite_150x.png new file mode 100644 index 000000000..5e9e4ab3a Binary files /dev/null and b/Telegram/SourceFiles/art/sprite_150x.png differ diff --git a/Telegram/SourceFiles/art/sprite_200x.png b/Telegram/SourceFiles/art/sprite_200x.png new file mode 100644 index 000000000..5da23c725 Binary files /dev/null and b/Telegram/SourceFiles/art/sprite_200x.png differ diff --git a/Telegram/SourceFiles/art/usercolor1.png b/Telegram/SourceFiles/art/usercolor1.png new file mode 100644 index 000000000..726cc9bf4 Binary files /dev/null and b/Telegram/SourceFiles/art/usercolor1.png differ diff --git a/Telegram/SourceFiles/art/usercolor2.png b/Telegram/SourceFiles/art/usercolor2.png new file mode 100644 index 000000000..ddeb1f163 Binary files /dev/null and b/Telegram/SourceFiles/art/usercolor2.png differ diff --git a/Telegram/SourceFiles/art/usercolor3.png b/Telegram/SourceFiles/art/usercolor3.png new file mode 100644 index 000000000..165e74f50 Binary files /dev/null and b/Telegram/SourceFiles/art/usercolor3.png differ diff --git a/Telegram/SourceFiles/art/usercolor4.png b/Telegram/SourceFiles/art/usercolor4.png new file mode 100644 index 000000000..e40428440 Binary files /dev/null and b/Telegram/SourceFiles/art/usercolor4.png differ diff --git a/Telegram/SourceFiles/art/usercolor5.png b/Telegram/SourceFiles/art/usercolor5.png new file mode 100644 index 000000000..1909c77fe Binary files /dev/null and b/Telegram/SourceFiles/art/usercolor5.png differ diff --git a/Telegram/SourceFiles/art/usercolor6.png b/Telegram/SourceFiles/art/usercolor6.png new file mode 100644 index 000000000..97c9e8085 Binary files /dev/null and b/Telegram/SourceFiles/art/usercolor6.png differ diff --git a/Telegram/SourceFiles/art/usercolor7.png b/Telegram/SourceFiles/art/usercolor7.png new file mode 100644 index 000000000..d769bd553 Binary files /dev/null and b/Telegram/SourceFiles/art/usercolor7.png differ diff --git a/Telegram/SourceFiles/art/usercolor8.png b/Telegram/SourceFiles/art/usercolor8.png new file mode 100644 index 000000000..1fbbe1808 Binary files /dev/null and b/Telegram/SourceFiles/art/usercolor8.png differ diff --git a/Telegram/SourceFiles/boxes/aboutbox.cpp b/Telegram/SourceFiles/boxes/aboutbox.cpp new file mode 100644 index 000000000..d254f9b65 --- /dev/null +++ b/Telegram/SourceFiles/boxes/aboutbox.cpp @@ -0,0 +1,130 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" + +#include "aboutbox.h" +#include "mainwidget.h" +#include "window.h" + +AboutBox::AboutBox() : _hiding(false), +_text(this, lang(lng_about_text), st::aboutLabel, st::aboutTextStyle), +_done(this, lang(lng_about_done), st::aboutCloseButton), +a_opacity(0, 1) { + + _width = st::aboutWidth; + _height = st::aboutHeight; + + _text.move(0, st::aboutTextTop); + + _headerWidth = st::aboutHeaderFont->m.width(qsl("Telegram ")); + _subheaderWidth = st::aboutSubheaderFont->m.width(qsl("Desktop")); + + _versionText = lang(lng_about_version).replace(qsl("{version}"), QString::fromWCharArray(AppVersionStr)); + _versionWidth = st::aboutVersionFont->m.width(_versionText); + + _done.move(0, _height - _done.height()); + + connect(&_done, SIGNAL(clicked()), this, SLOT(onClose())); + + resize(_width, _height); + + showAll(); + _cache = grab(rect()); + hideAll(); +} + +void AboutBox::hideAll() { + _done.hide(); + _text.hide(); +} + +void AboutBox::showAll() { + _done.show(); + _text.show(); +} + +void AboutBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + onClose(); + } else if (e->key() == Qt::Key_Escape) { + onClose(); + } +} + +void AboutBox::parentResized() { + QSize s = parentWidget()->size(); + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + update(); +} + +void AboutBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (_cache.isNull()) { + if (!_hiding || a_opacity.current() > 0.01) { + // fill bg + p.fillRect(0, 0, _width, _height, st::boxBG->b); + + p.drawPixmap(QPoint((_width - st::aboutIcon.width()) / 2, st::aboutIconTop), App::sprite(), st::aboutIcon); + + p.setPen(st::black->p); + p.setFont(st::aboutHeaderFont->f); + p.drawText((_width - (_headerWidth + _subheaderWidth)) / 2, st::aboutHeaderTop + st::aboutHeaderFont->ascent, qsl("Telegram")); + + p.setFont(st::aboutSubheaderFont->f); + p.drawText((_width - (_headerWidth + _subheaderWidth)) / 2 + _headerWidth, st::aboutHeaderTop + st::aboutSubheaderFont->ascent, qsl("Desktop")); + + p.setFont(st::aboutVersionFont->f); + p.setPen(st::aboutVersionColor->p); + p.drawText((_width - _versionWidth) / 2, st::aboutVersionTop + st::aboutVersionFont->ascent, _versionText); + } + } else { + p.setOpacity(a_opacity.current()); + p.drawPixmap(0, 0, _cache); + } +} + +void AboutBox::animStep(float64 ms) { + if (ms >= 1) { + a_opacity.finish(); + _cache = QPixmap(); + if (!_hiding) { + showAll(); + setFocus(); + } + } else { + a_opacity.update(ms, anim::linear); + } + update(); +} + +void AboutBox::onClose() { + emit closed(); +} + +void AboutBox::startHide() { + _hiding = true; + if (_cache.isNull()) { + _cache = grab(rect()); + hideAll(); + } + a_opacity.start(0); +} + +AboutBox::~AboutBox() { +} diff --git a/Telegram/SourceFiles/boxes/aboutbox.h b/Telegram/SourceFiles/boxes/aboutbox.h new file mode 100644 index 000000000..8e7c32523 --- /dev/null +++ b/Telegram/SourceFiles/boxes/aboutbox.h @@ -0,0 +1,56 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "layerwidget.h" + +class AboutBox : public LayeredWidget { + Q_OBJECT + +public: + + AboutBox(); + void parentResized(); + void animStep(float64 ms); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void startHide(); + ~AboutBox(); + +public slots: + + void onClose(); + +private: + + void hideAll(); + void showAll(); + + int32 _width, _height; + BottomButton _done; + FlatLabel _text; + int32 _headerWidth, _subheaderWidth; + + QString _versionText; + int32 _versionWidth; + + bool _hiding; + QPixmap _cache; + + anim::fvalue a_opacity; +}; diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp new file mode 100644 index 000000000..0e32e0a69 --- /dev/null +++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp @@ -0,0 +1,375 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" + +#include "application.h" +#include "addcontactbox.h" +#include "mainwidget.h" +#include "window.h" + +AddContactBox::AddContactBox(QString fname, QString lname, QString phone) : + _hiding(false), _peer(0), _addRequest(0), _contactId(0), + _firstInput(this, st::inpAddContact, lang(lng_signup_firstname), fname), + _lastInput(this, st::inpAddContact, lang(lng_signup_lastname), lname), + _phoneInput(this, st::inpAddContact, lang(lng_contact_phone), phone.isEmpty() ? phone : App::formatPhone(phone)), + _addButton(this, lang(lng_add_contact), st::btnSelectDone), + _retryButton(this, lang(lng_try_other_contact), st::btnSelectDone), + _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), + a_opacity(0, 1) { + + if (!phone.isEmpty()) { + _phoneInput.setDisabled(true); + } + + initBox(); +} + +AddContactBox::AddContactBox(PeerData *peer) : + _hiding(false), _peer(peer), _addRequest(0), _contactId(0), + _firstInput(this, st::inpAddContact, lang(peer->chat ? lng_dlg_new_group_name : lng_signup_firstname), peer->chat ? peer->name : peer->asUser()->firstName), + _lastInput(this, st::inpAddContact, lang(lng_signup_lastname), peer->chat ? QString() : peer->asUser()->lastName), + _phoneInput(this, st::inpAddContact, lang(lng_contact_phone)), + _addButton(this, lang(lng_settings_save), st::btnSelectDone), + _retryButton(this, lang(lng_try_other_contact), st::btnSelectDone), + _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), + a_opacity(0, 1) { + + initBox(); +} + +void AddContactBox::initBox() { + _width = st::addContactWidth; + if (_peer) { + if (_peer->chat) { + _boxTitle = lang(lng_edit_group_title); + _height = st::addContactTitleHeight + st::addContactPadding.top() + 1 * _firstInput.height() + st::addContactPadding.bottom() + _addButton.height(); + } else { + _boxTitle = lang(_peer == App::self() ? lng_edit_self_title : lng_edit_contact_title); + _height = st::addContactTitleHeight + st::addContactPadding.top() + 2 * _firstInput.height() + 1 * st::addContactDelta + st::addContactPadding.bottom() + _addButton.height(); + } + } else { + bool readyToAdd = !_phoneInput.text().isEmpty() && (!_firstInput.text().isEmpty() || !_lastInput.text().isEmpty()); + _boxTitle = lang(readyToAdd ? lng_confirm_contact_data : lng_enter_contact_data); + _height = st::addContactTitleHeight + st::addContactPadding.top() + 3 * _firstInput.height() + 2 * st::addContactDelta + st::addContactPadding.bottom() + _addButton.height(); + } + _firstInput.setGeometry(st::addContactPadding.left(), st::addContactTitleHeight + st::addContactPadding.top(), _width - st::addContactPadding.left() - st::addContactPadding.right(), _firstInput.height()); + _lastInput.setGeometry(st::addContactPadding.left(), _firstInput.y() + _firstInput.height() + st::addContactDelta, _firstInput.width(), _firstInput.height()); + _phoneInput.setGeometry(st::addContactPadding.left(), _lastInput.y() + _lastInput.height() + st::addContactDelta, _lastInput.width(), _lastInput.height()); + + int32 buttonTop = (_peer ? (_peer->chat ? _firstInput : _lastInput) : _phoneInput).y() + _phoneInput.height() + st::addContactPadding.bottom(); + _cancelButton.move(0, buttonTop); + _addButton.move(_width - _addButton.width(), buttonTop); + _retryButton.move(_width - _retryButton.width(), buttonTop); + _retryButton.hide(); + + connect(&_addButton, SIGNAL(clicked()), this, SLOT(onSend())); + connect(&_retryButton, SIGNAL(clicked()), this, SLOT(onRetry())); + connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCancel())); + + resize(_width, _height); + + showAll(); + _cache = grab(rect()); + hideAll(); +} + +void AddContactBox::hideAll() { + _firstInput.hide(); + _lastInput.hide(); + _phoneInput.hide(); + _addButton.hide(); + _retryButton.hide(); + _cancelButton.hide(); +} + +void AddContactBox::showAll() { + _firstInput.show(); + if (_peer && _peer->chat) { + _lastInput.hide(); + } else { + _lastInput.show(); + } + if (_peer) { + _phoneInput.hide(); + } else { + _phoneInput.show(); + } + _addButton.show(); + _cancelButton.show(); +} + +void AddContactBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + if (_firstInput.hasFocus()) { + if (_peer && _peer->chat) { + if (_firstInput.text().trimmed().isEmpty()) { + _firstInput.setFocus(); + _firstInput.notaBene(); + } else { + onSend(); + } + } else { + _lastInput.setFocus(); + } + } else if (_lastInput.hasFocus()) { + if (_peer) { + if (_firstInput.text().trimmed().isEmpty()) { + _firstInput.setFocus(); + _firstInput.notaBene(); + } else if (_lastInput.text().trimmed().isEmpty()) { + _lastInput.setFocus(); + _lastInput.notaBene(); + } else { + onSend(); + } + } else if (_phoneInput.isEnabled()) { + _phoneInput.setFocus(); + } else { + onSend(); + } + } else if (_phoneInput.hasFocus()) { + if (_firstInput.text().trimmed().isEmpty()) { + _firstInput.setFocus(); + _firstInput.notaBene(); + } else if (_lastInput.text().trimmed().isEmpty()) { + _lastInput.setFocus(); + _lastInput.notaBene(); + } else { + onSend(); + } + } + } else if (e->key() == Qt::Key_Escape) { + onCancel(); + } +} + +void AddContactBox::parentResized() { + QSize s = parentWidget()->size(); + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + update(); +} + +void AddContactBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (_cache.isNull()) { + if (!_hiding || a_opacity.current() > 0.01) { + // fill bg + p.fillRect(QRect(QPoint(0, 0), size()), st::boxBG->b); + + // paint shadows + if (_retryButton.isHidden()) { + p.fillRect(0, st::addContactTitleHeight, _width, st::scrollDef.topsh, st::scrollDef.shColor->b); + } + p.fillRect(0, size().height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b); + + // paint button sep + p.setPen(st::btnSelectSep->p); + p.drawLine(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::btnSelectCancel.width, size().height() - 1); + + // draw box title / text + p.setPen(st::black->p); + p.setFont(st::addContactTitleFont->f); + if (_retryButton.isHidden()) { + p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, _boxTitle); + } else { + int32 h = size().height() - st::boxPadding.top() * 2 - _retryButton.height() - st::boxPadding.bottom(); + p.drawText(QRect(st::boxPadding.left(), st::boxPadding.top(), _width - st::boxPadding.left() - st::boxPadding.right(), h), lang(lng_contact_not_joined).replace(qsl("{name}"), _sentName), style::al_topleft); + } + } + } else { + p.setOpacity(a_opacity.current()); + p.drawPixmap(0, 0, _cache); + } +} + +void AddContactBox::animStep(float64 dt) { + if (dt >= 1) { + a_opacity.finish(); + _cache = QPixmap(); + if (!_hiding) { + showAll(); + if (_firstInput.text().isEmpty() && _lastInput.text().isEmpty() || _phoneInput.isHidden() || !_phoneInput.isEnabled()) { + _firstInput.setFocus(); + } else { + _phoneInput.setFocus(); + } + } + } else { + a_opacity.update(dt, anim::linear); + } + update(); +} + +void AddContactBox::onSend() { + if (_addRequest) return; + + QString firstName = _firstInput.text().trimmed(), lastName = _lastInput.text().trimmed(), phone = _phoneInput.text().trimmed(); + if (firstName.isEmpty() && lastName.isEmpty()) { + _firstInput.setFocus(); + _firstInput.notaBene(); + return; + } else if (!_peer && !App::isValidPhone(phone)) { + _phoneInput.setFocus(); + _phoneInput.notaBene(); + return; + } + if (firstName.isEmpty()) { + firstName = lastName; + lastName = QString(); + } + _sentName = firstName; + if (_peer == App::self()) { + _addRequest = MTP::send(MTPaccount_UpdateProfile(MTP_string(firstName), MTP_string(lastName)), rpcDone(&AddContactBox::onSaveSelfDone), rpcFail(&AddContactBox::onSaveSelfFail)); + } else if (_peer) { + if (_peer->chat) { + _addRequest = MTP::send(MTPmessages_EditChatTitle(MTP_int(int32(_peer->id & 0xFFFFFFFF)), MTP_string(firstName)), rpcDone(&AddContactBox::onSaveChatDone), rpcFail(&AddContactBox::onSaveFail)); + } else { + _contactId = MTP::nonce(); + QVector v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(_peer->asUser()->phone), MTP_string(firstName), MTP_string(lastName))); + _addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector(v), MTP_bool(false)), rpcDone(&AddContactBox::onSaveUserDone), rpcFail(&AddContactBox::onSaveFail)); + } + } else { + _contactId = MTP::nonce(); + QVector v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(phone), MTP_string(firstName), MTP_string(lastName))); + _addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector(v), MTP_bool(false)), rpcDone(&AddContactBox::onImportDone)); + } +} + +void AddContactBox::onSaveSelfDone(const MTPUser &user) { + App::feedUsers(MTP_vector(QVector(1, user))); + emit closed(); +} + +bool AddContactBox::onSaveSelfFail(const RPCError &error) { + QString err(error.type()); + QString firstName = textOneLine(_firstInput.text()), lastName = textOneLine(_lastInput.text()); + if (err == "NAME_NOT_MODIFIED") { + App::self()->setName(firstName, lastName, firstName + ' ' + lastName); + emit closed(); + return true; + } else if (err == "FIRSTNAME_INVALID") { + _firstInput.setFocus(); + _firstInput.notaBene(); + return true; + } else if (err == "LASTNAME_INVALID") { + _lastInput.setFocus(); + _lastInput.notaBene(); + return true; + } + _firstInput.setFocus(); + return true; +} + +bool AddContactBox::onSaveFail(const RPCError &error) { + QString err(error.type()); + QString firstName = _firstInput.text().trimmed(), lastName = _lastInput.text().trimmed(); + if (err == "CHAT_TITLE_NOT_MODIFIED") { + _peer->updateName(firstName, QString()); + emit closed(); + return true; + } else if (err == "NO_CHAT_TITLE") { + _firstInput.setFocus(); + _firstInput.notaBene(); + return true; + } + _firstInput.setFocus(); + return true; +} + +void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) { + if (_hiding || !App::main()) return; + + const MTPDcontacts_importedContacts &d(res.c_contacts_importedContacts()); + App::feedUsers(d.vusers); + + const QVector &v(d.vimported.c_vector().v); + int32 uid = 0; + if (!v.isEmpty()) { + const MTPDimportedContact &c(v.front().c_importedContact()); + if (c.vclient_id.v != _contactId) return; + + uid = c.vuser_id.v; + if (uid && !App::userLoaded(uid)) { + uid = 0; + } + } + if (uid) { + App::main()->addNewContact(uid); + App::main()->showPeer(App::peerFromUser(uid)); + App::wnd()->hideLayer(); + } else { + _addButton.hide(); + _firstInput.hide(); + _lastInput.hide(); + _phoneInput.hide(); + _retryButton.show(); + int32 theight = st::addContactTitleFont->m.boundingRect(0, 0, _width - st::boxPadding.left() - st::boxPadding.right(), 1, Qt::TextWordWrap, lang(lng_contact_not_joined).replace(qsl("{name}"), _sentName)).height(); + int32 h = st::boxPadding.top() * 2 + theight + _retryButton.height() + st::boxPadding.bottom(); + resize(_width, h); + _retryButton.move(_retryButton.x(), h - _retryButton.height()); + _cancelButton.move(_cancelButton.x(), h - _retryButton.height()); + update(); + } +} + +void AddContactBox::onSaveChatDone(const MTPmessages_StatedMessage &result) { + App::main()->sentFullDataReceived(0, result); + emit closed(); +} + +void AddContactBox::onSaveUserDone(const MTPcontacts_ImportedContacts &res) { + const MTPDcontacts_importedContacts &d(res.c_contacts_importedContacts()); + App::feedUsers(d.vusers); + emit closed(); +} + +void AddContactBox::onCancel() { + emit closed(); +} + +void AddContactBox::onRetry() { + _addRequest = 0; + _contactId = 0; + _addButton.show(); + _cancelButton.move(_cancelButton.x(), _addButton.y()); + showAll(); + _firstInput.setText(QString()); + _firstInput.updatePlaceholder(); + _lastInput.setText(QString()); + _lastInput.updatePlaceholder(); + _phoneInput.setText(QString()); + _phoneInput.updatePlaceholder(); + _phoneInput.setDisabled(false); + _retryButton.hide(); + _firstInput.setFocus(); + resize(_width, _height); + update(); +} + +void AddContactBox::startHide() { + _hiding = true; + if (_cache.isNull()) { + _cache = grab(rect()); + hideAll(); + } + a_opacity.start(0); +} + +AddContactBox::~AddContactBox() { +} diff --git a/Telegram/SourceFiles/boxes/addcontactbox.h b/Telegram/SourceFiles/boxes/addcontactbox.h new file mode 100644 index 000000000..f3ba5f417 --- /dev/null +++ b/Telegram/SourceFiles/boxes/addcontactbox.h @@ -0,0 +1,74 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "layerwidget.h" + +class AddContactBox : public LayeredWidget, public RPCSender { + Q_OBJECT + +public: + + AddContactBox(QString fname = QString(), QString lname = QString(), QString phone = QString()); + AddContactBox(PeerData *peer); + void parentResized(); + void animStep(float64 dt); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void startHide(); + ~AddContactBox(); + +public slots: + + void onSend(); + void onRetry(); + void onCancel(); + +private: + + void hideAll(); + void showAll(); + + void onImportDone(const MTPcontacts_ImportedContacts &res); + + void onSaveSelfDone(const MTPUser &user); + bool onSaveSelfFail(const RPCError &error); + + void onSaveChatDone(const MTPmessages_StatedMessage &result); + void onSaveUserDone(const MTPcontacts_ImportedContacts &res); + bool onSaveFail(const RPCError &e); + + void initBox(); + + PeerData *_peer; + QString _boxTitle; + + int32 _width, _height, _thumbw, _thumbh; + FlatButton _addButton, _retryButton, _cancelButton; + FlatInput _firstInput, _lastInput, _phoneInput; + + uint64 _contactId; + + QPixmap _cache; + + mtpRequestId _addRequest; + QString _sentName; + + anim::fvalue a_opacity; + bool _hiding; +}; diff --git a/Telegram/SourceFiles/boxes/addparticipantbox.cpp b/Telegram/SourceFiles/boxes/addparticipantbox.cpp new file mode 100644 index 000000000..c755907fc --- /dev/null +++ b/Telegram/SourceFiles/boxes/addparticipantbox.cpp @@ -0,0 +1,662 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" + +#include "addparticipantbox.h" +#include "mainwidget.h" +#include "window.h" + +AddParticipantInner::AddParticipantInner(ChatData *chat) : _chat(chat), _selCount(0), + _contacts(&App::main()->contactsList()), _sel(0), _filteredSel(-1), _mouseSel(false) { + + _filter = qsl("a"); + updateFilter(); + + for (DialogRow *r = _contacts->list.begin; r != _contacts->list.end; r = r->next) { + r->attached = 0; + } + + connect(App::main(), SIGNAL(dialogRowReplaced(DialogRow *, DialogRow *)), this, SLOT(onDialogRowReplaced(DialogRow *, DialogRow *))); + connect(App::main(), SIGNAL(peerUpdated(PeerData*)), this, SLOT(peerUpdated(PeerData *))); + connect(App::main(), SIGNAL(peerNameChanged(PeerData *, const PeerData::Names &, const PeerData::NameFirstChars &)), this, SLOT(peerUpdated(PeerData *))); + connect(App::main(), SIGNAL(peerPhotoChanged(PeerData *)), this, SLOT(peerUpdated(PeerData *))); +} + +void AddParticipantInner::peerUpdated(PeerData *peer) { + if (!peer || peer == _chat) { + if (_chat->forbidden) { + App::wnd()->hideLayer(); + } else if (!_chat->participants.isEmpty() || _chat->count <= 0) { + for (ContactsData::iterator i = _contactsData.begin(), e = _contactsData.end(); i != e; ++i ) { + delete i.value(); + } + _contactsData.clear(); + for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) { + row->attached = 0; + } + if (!_filter.isEmpty()) { + for (int32 j = 0, s = _filtered.size(); j < s; ++j) { + _filtered[j]->attached = 0; + } + } + } + } else if (!peer->chat) { + ContactsData::iterator i = _contactsData.find(peer->asUser()); + if (i != _contactsData.cend()) { + for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) { + if (row->attached == i.value()) row->attached = 0; + } + if (!_filter.isEmpty()) { + for (int32 j = 0, s = _filtered.size(); j < s; ++j) { + if (_filtered[j]->attached == i.value()) _filtered[j]->attached = 0; + } + } + delete i.value(); + _contactsData.erase(i); + } + } + + parentWidget()->update(); +} + +void AddParticipantInner::loadProfilePhotos(int32 yFrom) { + int32 yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5; + MTP::clearLoaderPriorities(); + + if (yTo < 0) return; + if (yFrom < 0) yFrom = 0; + + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; + if (_filter.isEmpty()) { + if (_contacts->list.count) { + _contacts->list.adjustCurrent(yFrom, rh); + for ( + DialogRow *preloadFrom = _contacts->list.current; + preloadFrom != _contacts->list.end && preloadFrom->pos * rh < yTo; + preloadFrom = preloadFrom->next + ) { + preloadFrom->history->peer->photo->load(); + } + } + } else if (!_filtered.isEmpty()) { + int32 from = yFrom / rh; + if (from < 0) from = 0; + if (from < _filtered.size()) { + int32 to = (yTo / rh) + 1; + if (to > _filtered.size()) to = _filtered.size(); + + for (; from < to; ++from) { + _filtered[from]->history->peer->photo->load(); + } + } + } +} + +AddParticipantInner::ContactData *AddParticipantInner::contactData(DialogRow *row) { + ContactData *data = (ContactData*)row->attached; + if (!data) { + UserData *user = row->history->peer->asUser(); + ContactsData::const_iterator i = _contactsData.constFind(user); + if (i == _contactsData.cend()) { + _contactsData.insert(user, data = new ContactData()); + data->inchat = _chat->participants.constFind(user) != _chat->participants.cend(); + data->check = false; + data->name.setText(st::profileListNameFont, user->name, _textNameOptions); + data->online = App::onlineText(user->onlineTill, _time); + } else { + data = i.value(); + } + row->attached = data; + } + return data; +} + +void AddParticipantInner::paintDialog(QPainter &p, DialogRow *row, bool sel) { + int32 left = st::profileListPadding.width(); + + UserData *user = row->history->peer->asUser(); + ContactData *data = contactData(row); + + if (data->inchat || data->check || _selCount + _chat->count >= cMaxGroupCount()) { + sel = false; + } + + if (sel || data->inchat || data->check) { + p.fillRect(0, 0, width(), 2 * st::profileListPadding.height() + st::profileListPhotoSize, ((data->inchat || data->check) ? st::profileActiveBG : st::profileHoverBG)->b); + } + + p.drawPixmap(left, st::profileListPadding.height(), user->photo->pix(st::profileListPhotoSize)); + + if (data->inchat || data->check) { + p.setPen(st::white->p); + } else { + p.setPen(st::profileListNameColor->p); + } + data->name.drawElided(p, left + st::profileListPhotoSize + st::profileListPadding.width(), st::profileListNameTop, width() - st::participantDelta - st::profileListPadding.width() * 2 - st::profileListPhotoSize - st::profileListPadding.width() * 2); + + if (sel || data->check) { + p.drawPixmap(QPoint(width() - st::profileCheckRect.width() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::profileCheckRect.height()) / 2 - st::profileCheckDeltaY), App::sprite(), (data->check ? st::profileCheckActiveRect : st::profileCheckRect)); + } + + p.setFont(st::profileSubFont->f); + if (data->inchat || data->check) { + p.setPen(st::white->p); + } else { + p.setPen((user->onlineTill >= _time ? st::profileOnlineColor : st::profileOfflineColor)->p); + } + p.drawText(left + st::profileListPhotoSize + st::profileListPadding.width(), st::profileListPadding.height() + st::profileListPhotoSize - st::profileListStatusBottom, data->online); +} + +void AddParticipantInner::paintEvent(QPaintEvent *e) { + QRect r(e->rect()); + QPainter p(this); + + _time = unixtime(); + p.fillRect(r, st::white->b); + + int32 yFrom = r.top(); + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; + if (_filter.isEmpty()) { + if (_contacts->list.count) { + _contacts->list.adjustCurrent(yFrom, rh); + + DialogRow *drawFrom = _contacts->list.current; + p.translate(0, drawFrom->pos * rh); + while (drawFrom != _contacts->list.end && drawFrom->pos * rh < r.bottom()) { + paintDialog(p, drawFrom, (drawFrom == _sel)); + p.translate(0, rh); + drawFrom = drawFrom->next; + } + } else { + // .. + } + } else { + if (_filtered.isEmpty()) { + // .. + } else { + int32 from = yFrom / rh; + if (from < 0) from = 0; + if (from < _filtered.size()) { + int32 to = (r.bottom() / rh) + 1; + if (to > _filtered.size()) to = _filtered.size(); + + p.translate(0, from * rh); + for (; from < to; ++from) { + paintDialog(p, _filtered[from], (_filteredSel == from)); + p.translate(0, rh); + } + } + } + } +} + +void AddParticipantInner::enterEvent(QEvent *e) { + setMouseTracking(true); +} + +void AddParticipantInner::leaveEvent(QEvent *e) { + setMouseTracking(false); + updateSel(); +} + +void AddParticipantInner::mouseMoveEvent(QMouseEvent *e) { + _mouseSel = true; + _lastMousePos = e->globalPos(); + updateSel(); +} + +void AddParticipantInner::mousePressEvent(QMouseEvent *e) { + _mouseSel = true; + _lastMousePos = e->globalPos(); + updateSel(); + if (e->button() == Qt::LeftButton) { + chooseParticipant(); + } +} + +void AddParticipantInner::chooseParticipant() { + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from; + if (_filter.isEmpty()) { + if (!_sel || contactData(_sel)->inchat) return; + changeCheckState(_sel); + } else { + if (_filteredSel < 0 || _filteredSel >= _filtered.size() || contactData(_filtered[_filteredSel])->inchat) return; + + DialogRow *row = _filtered[_filteredSel]; + changeCheckState(row); + + PeerData *peer = row->history->peer; + updateFilter(); + + for (_sel = _contacts->list.begin; _sel != _contacts->list.end; _sel = _sel->next) { + if (_sel->history->peer == peer) { + break; + } + } + if (_sel == _contacts->list.end) { + _sel = 0; + } else { + emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh); + } + } + parentWidget()->update(); +} + +void AddParticipantInner::changeCheckState(DialogRow *row) { + if (contactData(row)->check) { + contactData(row)->check = false; + --_selCount; + } else if (_selCount + _chat->count < cMaxGroupCount()) { + contactData(row)->check = true; + ++_selCount; + } +} + +ChatData *AddParticipantInner::chat() { + return _chat; +} + +QVector AddParticipantInner::selected() { + QVector result; + result.reserve(_contactsData.size()); + for (ContactsData::const_iterator i = _contactsData.cbegin(), e = _contactsData.cend(); i != e; ++i) { + if (i.value()->check) { + result.push_back(i.key()); + } + } + return result; +} + +void AddParticipantInner::updateSel() { + if (!_mouseSel) return; + + QPoint p(mapFromGlobal(_lastMousePos)); + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; + if (_filter.isEmpty()) { + DialogRow *newSel = rect().contains(p) ? _contacts->list.rowAtY(p.y(), rh) : 0; + if (newSel != _sel) { + _sel = newSel; + parentWidget()->update(); + } + } else { + int32 newFilteredSel = (p.y() >= 0 && rect().contains(p)) ? (p.y() / rh) : -1; + if (newFilteredSel != _filteredSel) { + _filteredSel = newFilteredSel; + parentWidget()->update(); + } + } +} + +void AddParticipantInner::updateFilter(QString filter) { + QStringList f; + if (!filter.isEmpty()) { + QStringList filterList = filter.split(cWordSplit(), QString::SkipEmptyParts); + int l = filterList.size(); + + f.reserve(l); + for (int i = 0; i < l; ++i) { + QString filterName = filterList[i].trimmed(); + if (filterName.isEmpty()) continue; + f.push_back(filterName); + } + filter = f.join(' '); + } + if (_filter != filter) { + int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2); + _filter = filter; + if (_filter.isEmpty()) { + resize(width(), _contacts->list.count * rh); + if (_contacts->list.count) { + _sel = _contacts->list.begin; + while (_sel->next->next &&& contactData(_sel)->inchat) { + _sel = _sel->next; + } + } + } else { + QStringList::const_iterator fb = f.cbegin(), fe = f.cend(), fi; + + _filtered.clear(); + if (!f.isEmpty()) { + DialogsList *dialogsToFilter = 0; + if (_contacts->list.count) { + for (fi = fb; fi != fe; ++fi) { + DialogsIndexed::DialogsIndex::iterator i = _contacts->index.find(fi->at(0)); + if (i == _contacts->index.cend()) { + dialogsToFilter = 0; + break; + } + if (!dialogsToFilter || dialogsToFilter->count > i.value()->count) { + dialogsToFilter = i.value(); + } + } + } + if (dialogsToFilter && dialogsToFilter->count) { + _filtered.reserve(dialogsToFilter->count); + for (DialogRow *i = dialogsToFilter->begin, *e = dialogsToFilter->end; i != e; i = i->next) { + const PeerData::Names &names(i->history->peer->names); + PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni; + for (fi = fb; fi != fe; ++fi) { + QString filterName(*fi); + for (ni = nb; ni != ne; ++ni) { + if ((*ni).indexOf(*fi) == 0) { + break; + } + } + if (ni == ne) { + break; + } + } + if (fi == fe) { + i->attached = 0; + _filtered.push_back(i); + } + } + } + } + _filteredSel = _filtered.isEmpty() ? -1 : 0; + while (_filteredSel < _filtered.size() - 1 && contactData(_filtered[_filteredSel])->inchat) { + ++_filteredSel; + } + + resize(width(), _filtered.size() * rh); + } + if (parentWidget()) parentWidget()->update(); + loadProfilePhotos(0); + } +} + +void AddParticipantInner::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) { + if (!_filter.isEmpty()) { + for (FilteredDialogs::iterator i = _filtered.begin(), e = _filtered.end(); i != e;) { + if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts! + if (newRow) { + *i = newRow; + ++i; + } else { + i = _filtered.erase(i); + } + } else { + ++i; + } + } + if (_filteredSel >= _filtered.size()) { + _filteredSel = -1; + } + } else { + if (_sel == oldRow) { + _sel = newRow; + } + } + _mouseSel = false; + int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2); + int32 newh = (_filter.isEmpty() ? _contacts->list.count : _filtered.size()) * rh; + resize(width(), newh); +} + +AddParticipantInner::~AddParticipantInner() { + for (ContactsData::iterator i = _contactsData.begin(), e = _contactsData.end(); i != e; ++i) { + delete *i; + } +} + +void AddParticipantInner::selectSkip(int32 dir) { + _mouseSel = false; + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, origDir = dir; + if (_filter.isEmpty()) { + if (_sel) { + if (dir > 0) { + while (dir && _sel->next->next) { + _sel = _sel->next; + --dir; + } + while (contactData(_sel)->inchat && _sel->next->next) { + _sel = _sel->next; + } + if (contactData(_sel)->inchat) { + while (contactData(_sel)->inchat && _sel->prev) { + _sel = _sel->prev; + } + } + } else { + while (dir && _sel->prev) { + _sel = _sel->prev; + ++dir; + } + while (contactData(_sel)->inchat && _sel->prev) { + _sel = _sel->prev; + } + if (contactData(_sel)->inchat) { + while (contactData(_sel)->inchat && _sel->next->next) { + _sel = _sel->next; + } + } + } + } else if (dir > 0 && _contacts->list.count) { + _sel = _contacts->list.begin; + while (contactData(_sel)->inchat && _sel->next->next) { + _sel = _sel->next; + } + } + if (_sel) { + if (contactData(_sel)->inchat) { + _sel = 0; + } else { + emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh); + } + } + } else { + if (dir > 0) { + if (_filteredSel < 0 && dir > 1) { + _filteredSel = 0; + } + _filteredSel += dir; + while (_filteredSel < _filtered.size() - 1 && contactData(_filtered[_filteredSel])->inchat) { + ++_filteredSel; + } + if (_filteredSel >= _filtered.size()) { + _filteredSel = _filtered.size() - 1; + } + while (_filteredSel > 0 && contactData(_filtered[_filteredSel])->inchat) { + --_filteredSel; + } + } else if (_filteredSel > 0) { + _filteredSel += dir; + if (_filteredSel < 0) { + _filteredSel = 0; + } + if (_filteredSel < _filtered.size() - 1) { + while (_filteredSel > 0 && contactData(_filtered[_filteredSel])->inchat) { + --_filteredSel; + } + } + while (_filteredSel < _filtered.size() - 1 && contactData(_filtered[_filteredSel])->inchat) { + ++_filteredSel; + } + } + if (_filteredSel >= 0) { + if (contactData(_filtered[_filteredSel])->inchat) { + _filteredSel = -1; + } else { + emit mustScrollTo(_filteredSel * rh, (_filteredSel + 1) * rh); + } + } + } + parentWidget()->update(); +} + +void AddParticipantInner::selectSkipPage(int32 h, int32 dir) { + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; + int32 points = h / rh; + if (!points) return; + selectSkip(points * dir); +} + +AddParticipantBox::AddParticipantBox(ChatData *chat) : _inner(chat), _hiding(false), + _scroll(this, st::newGroupScroll), + _filter(this, st::contactsFilter, lang(lng_participant_filter)), + _invite(this, lang(lng_participant_invite), st::btnSelectDone), + _cancel(this, lang(lng_cancel), st::btnSelectCancel), + a_opacity(0, 1), af_opacity(anim::linear) { + + _width = st::participantWidth; + _height = App::wnd()->height() - st::boxPadding.top() - st::boxPadding.bottom(); + if (_height > st::participantMaxHeight) _height = st::participantMaxHeight; + + resize(_width, _height); + + _scroll.setWidget(&_inner); + _scroll.setFocusPolicy(Qt::NoFocus); + + connect(&_invite, SIGNAL(clicked()), this, SLOT(onInvite())); + connect(&_cancel, SIGNAL(clicked()), this, SIGNAL(closed())); + connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel())); + connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); + connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate())); + connect(&_filter, SIGNAL(cancelled()), this, SIGNAL(onClose())); + connect(&_inner, SIGNAL(mustScrollTo(int,int)), &_scroll, SLOT(scrollToY(int,int))); + + showAll(); + _cache = grab(rect()); + hideAll(); +} + +void AddParticipantBox::hideAll() { + _filter.hide(); + _scroll.hide(); + _cancel.hide(); + _invite.hide(); +} + +void AddParticipantBox::showAll() { + _filter.show(); + _scroll.show(); + _cancel.show(); + _invite.show(); +} + +void AddParticipantBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + onClose(); + } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { + _inner.chooseParticipant(); + } else if (e->key() == Qt::Key_Down) { + _inner.selectSkip(1); + } else if (e->key() == Qt::Key_Up) { + _inner.selectSkip(-1); + } else if (e->key() == Qt::Key_PageDown) { + _inner.selectSkipPage(_scroll.height(), 1); + } else if (e->key() == Qt::Key_PageUp) { + _inner.selectSkipPage(_scroll.height(), -1); + } else { + e->ignore(); + } +} + +void AddParticipantBox::parentResized() { + QSize s = parentWidget()->size(); + _height = App::wnd()->height() - st::boxPadding.top() - st::boxPadding.bottom(); + if (_height > st::participantMaxHeight) _height = st::participantMaxHeight; + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + update(); +} + +void AddParticipantBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (_cache.isNull()) { + if (!_hiding || a_opacity.current() > 0.01) { + // fill bg + p.fillRect(QRect(QPoint(0, 0), size()), st::boxBG->b); + + // paint shadows + p.fillRect(0, st::participantFilter.height, _width, st::scrollDef.topsh, st::scrollDef.shColor->b); + + // paint button sep + p.setPen(st::btnSelectSep->p); + p.drawLine(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::btnSelectCancel.width, size().height() - 1); + + // draw box title / text + p.setPen(st::black->p); + p.setFont(st::addContactTitleFont->f); + p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_profile_add_participant)); + } + } else { + p.setOpacity(a_opacity.current()); + p.drawPixmap(0, 0, _cache); + } +} + +void AddParticipantBox::resizeEvent(QResizeEvent *e) { + LayeredWidget::resizeEvent(e); + _filter.move(st::newGroupNamePadding.left(), st::contactsAdd.height + st::newGroupNamePadding.top()); + _inner.resize(_width, _inner.height()); + _scroll.resize(_width, _height - st::contactsAdd.height - st::newGroupNamePadding.top() - _filter.height() - st::newGroupNamePadding.bottom() - _cancel.height()); + _scroll.move(0, _filter.y() + _filter.height() + st::newGroupNamePadding.bottom()); + _invite.move(width() - _invite.width(), _height - _invite.height()); + _cancel.move(0, _height - _cancel.height()); +} + +void AddParticipantBox::animStep(float64 dt) { + if (dt >= 1) { + a_opacity.finish(); + _cache = QPixmap(); + if (!_hiding) { + showAll(); + _filter.setFocus(); + } + } else { + a_opacity.update(dt, af_opacity); + } + update(); +} + +void AddParticipantBox::startHide() { + _hiding = true; + if (_cache.isNull()) { + _cache = grab(rect()); + hideAll(); + } + a_opacity.start(0); +} + +void AddParticipantBox::onFilterUpdate() { + _scroll.scrollToY(0); + _inner.updateFilter(_filter.text()); +} + +void AddParticipantBox::onClose() { + emit closed(); +} + +void AddParticipantBox::onInvite() { + QVector users(_inner.selected()); + if (users.isEmpty()) { + _filter.setFocus(); + return; + } + + App::main()->addParticipants(_inner.chat(), users); +} + +void AddParticipantBox::onScroll() { + _inner.loadProfilePhotos(_scroll.scrollTop()); +} + +AddParticipantBox::~AddParticipantBox() { + +} diff --git a/Telegram/SourceFiles/boxes/addparticipantbox.h b/Telegram/SourceFiles/boxes/addparticipantbox.h new file mode 100644 index 000000000..966ab1778 --- /dev/null +++ b/Telegram/SourceFiles/boxes/addparticipantbox.h @@ -0,0 +1,130 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "layerwidget.h" + +class AddParticipantInner : public QWidget, public RPCSender { + Q_OBJECT + +public: + + AddParticipantInner(ChatData *chat); + + void paintEvent(QPaintEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + + void paintDialog(QPainter &p, DialogRow *row, bool sel); + void updateFilter(QString filter = QString()); + + void selectSkip(int32 dir); + void selectSkipPage(int32 h, int32 dir); + + void loadProfilePhotos(int32 yFrom); + void chooseParticipant(); + void changeCheckState(DialogRow *row); + + ChatData *chat(); + QVector selected(); + + ~AddParticipantInner(); + +signals: + + void mustScrollTo(int ymin, int ymax); + +public slots: + + void onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow); + + void updateSel(); + void peerUpdated(PeerData *peer); + +private: + + ChatData *_chat; + + int32 _time; + + DialogsIndexed *_contacts; + DialogRow *_sel; + QString _filter; + typedef QVector FilteredDialogs; + FilteredDialogs _filtered; + int32 _filteredSel; + bool _mouseSel; + + int32 _selCount; + + typedef struct { + Text name; + QString online; + bool inchat; + bool check; + } ContactData; + typedef QMap ContactsData; + ContactsData _contactsData; + + ContactData *contactData(DialogRow *row); + + QPoint _lastMousePos; + +}; + +class AddParticipantBox : public LayeredWidget { + Q_OBJECT + +public: + + AddParticipantBox(ChatData *chat); + void parentResized(); + void animStep(float64 dt); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void startHide(); + ~AddParticipantBox(); + +public slots: + + void onFilterUpdate(); + void onClose(); + void onScroll(); + void onInvite(); + +private: + + void hideAll(); + void showAll(); + + ScrollArea _scroll; + AddParticipantInner _inner; + int32 _width, _height; + FlatInput _filter; + FlatButton _invite, _cancel; + + bool _hiding; + + QPixmap _cache; + + anim::fvalue a_opacity; + anim::transition af_opacity; +}; diff --git a/Telegram/SourceFiles/boxes/confirmbox.cpp b/Telegram/SourceFiles/boxes/confirmbox.cpp new file mode 100644 index 000000000..49db880a7 --- /dev/null +++ b/Telegram/SourceFiles/boxes/confirmbox.cpp @@ -0,0 +1,128 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" + +#include "confirmbox.h" +#include "mainwidget.h" +#include "window.h" + +ConfirmBox::ConfirmBox(QString text, QString doneText, QString cancelText) : _hiding(false), _text(100), + _confirm(this, doneText.isEmpty() ? lang(lng_continue) : doneText, st::btnSelectDone), + _cancel(this, cancelText.isEmpty() ? lang(lng_cancel) : cancelText, st::btnSelectCancel), + a_opacity(0, 1), af_opacity(anim::linear) { + + _text.setText(st::boxFont, text, _textPlainOptions); + + _width = st::confirmWidth; + _textWidth = _width - st::boxPadding.left() - st::boxPadding.right(); + _textHeight = _text.countHeight(_textWidth); + _height = st::boxPadding.top() + _textHeight + st::boxPadding.bottom() + _confirm.height(); + + _confirm.move(_width - _confirm.width(), st::boxPadding.top() + _textHeight + st::boxPadding.bottom()); + _cancel.move(0, st::boxPadding.top() + _textHeight + st::boxPadding.bottom()); + + connect(&_confirm, SIGNAL(clicked()), this, SIGNAL(confirmed())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onCancel())); + + resize(_width, _height); + + showAll(); + _cache = grab(rect()); + hideAll(); +} + +void ConfirmBox::hideAll() { + _confirm.hide(); + _cancel.hide(); +} + +void ConfirmBox::showAll() { + _confirm.show(); + _cancel.show(); +} + +void ConfirmBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + emit confirmed(); + } else if (e->key() == Qt::Key_Escape) { + onCancel(); + } +} + +void ConfirmBox::parentResized() { + QSize s = parentWidget()->size(); + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + update(); +} + +void ConfirmBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (_cache.isNull()) { + if (!_hiding || a_opacity.current() > 0.01) { + // fill bg + p.fillRect(0, 0, _width, _height, st::boxBG->b); + + // paint shadows + p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b); + + // paint button sep + p.setPen(st::btnSelectSep->p); + p.drawLine(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::btnSelectCancel.width, _height - 1); + + // draw box title / text + p.setFont(st::boxFont->f); + p.setPen(st::black->p); + _text.draw(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, (_text.maxWidth() < _width) ? style::al_center : style::al_left); + } + } else { + p.setOpacity(a_opacity.current()); + p.drawPixmap(0, 0, _cache); + } +} + +void ConfirmBox::animStep(float64 ms) { + if (ms >= 1) { + a_opacity.finish(); + _cache = QPixmap(); + if (!_hiding) { + showAll(); + setFocus(); + } + } else { + a_opacity.update(ms, af_opacity); + } + update(); +} + +void ConfirmBox::onCancel() { + emit cancelled(); + emit closed(); +} + +void ConfirmBox::startHide() { + _hiding = true; + if (_cache.isNull()) { + _cache = grab(rect()); + hideAll(); + } + a_opacity.start(0); +} + +ConfirmBox::~ConfirmBox() { +} diff --git a/Telegram/SourceFiles/boxes/confirmbox.h b/Telegram/SourceFiles/boxes/confirmbox.h new file mode 100644 index 000000000..78f71b539 --- /dev/null +++ b/Telegram/SourceFiles/boxes/confirmbox.h @@ -0,0 +1,59 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "layerwidget.h" + +class ConfirmBox : public LayeredWidget, public RPCSender { + Q_OBJECT + +public: + + ConfirmBox(QString text, QString doneText = QString(), QString cancelText = QString()); + void parentResized(); + void animStep(float64 ms); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void startHide(); + ~ConfirmBox(); + +signals: + + void confirmed(); + void cancelled(); + +public slots: + + void onCancel(); + +private: + + void hideAll(); + void showAll(); + + int32 _width, _height; + FlatButton _confirm, _cancel; + Text _text; + int32 _textWidth, _textHeight; + + bool _hiding; + QPixmap _cache; + + anim::fvalue a_opacity; + anim::transition af_opacity; +}; diff --git a/Telegram/SourceFiles/boxes/connectionbox.cpp b/Telegram/SourceFiles/boxes/connectionbox.cpp new file mode 100644 index 000000000..2b7f9bdf2 --- /dev/null +++ b/Telegram/SourceFiles/boxes/connectionbox.cpp @@ -0,0 +1,226 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" + +#include "connectionbox.h" +#include "mainwidget.h" +#include "window.h" + +ConnectionBox::ConnectionBox() : _hiding(false), + _hostInput(this, st::inpConnectionHost, lang(lng_connection_host_ph), cConnectionProxy().host), + _portInput(this, st::inpConnectionPort, lang(lng_connection_port_ph), QString::number(cConnectionProxy().port)), + _userInput(this, st::inpConnectionUser, lang(lng_connection_user_ph), cConnectionProxy().user), + _passwordInput(this, st::inpConnectionPassword, lang(lng_connection_password_ph), cConnectionProxy().password), + _saveButton(this, lang(lng_connection_save), st::btnSelectDone), + _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), + _autoRadio(this, qsl("conn_type"), dbictAuto, lang(lng_connection_auto_rb), (cConnectionType() == dbictAuto)), + _httpProxyRadio(this, qsl("conn_type"), dbictHttpProxy, lang(lng_connection_http_proxy_rb), (cConnectionType() == dbictHttpProxy)), + _tcpProxyRadio(this, qsl("conn_type"), dbictTcpProxy, lang(lng_connection_tcp_proxy_rb), (cConnectionType() == dbictTcpProxy)), + a_opacity(0, 1) { + + _width = st::addContactWidth; + + connect(&_saveButton, SIGNAL(clicked()), this, SLOT(onSave())); + connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCancel())); + + connect(&_autoRadio, SIGNAL(changed()), this, SLOT(onChange())); + connect(&_httpProxyRadio, SIGNAL(changed()), this, SLOT(onChange())); + connect(&_tcpProxyRadio, SIGNAL(changed()), this, SLOT(onChange())); + + _passwordInput.setEchoMode(QLineEdit::Password); + + showAll(); + _cache = grab(rect()); + hideAll(); +} + +void ConnectionBox::hideAll() { + _autoRadio.hide(); + _httpProxyRadio.hide(); + _tcpProxyRadio.hide(); + + _hostInput.hide(); + _portInput.hide(); + _userInput.hide(); + _passwordInput.hide(); + + _saveButton.hide(); + _cancelButton.hide(); +} + +void ConnectionBox::showAll() { + _autoRadio.show(); + _httpProxyRadio.show(); + _tcpProxyRadio.show(); + + _autoRadio.move(st::boxPadding.left(), st::addContactTitleHeight + st::connectionSkip); + _httpProxyRadio.move(st::boxPadding.left(), _autoRadio.y() + _autoRadio.height() + st::connectionSkip); + + int32 inputy = 0; + if (_httpProxyRadio.checked()) { + inputy = _httpProxyRadio.y() + _httpProxyRadio.height() + st::boxPadding.top(); + _tcpProxyRadio.move(st::boxPadding.left(), inputy + st::boxPadding.top() + 2 * _hostInput.height() + st::connectionSkip); + } else { + _tcpProxyRadio.move(st::boxPadding.left(), _httpProxyRadio.y() + _httpProxyRadio.height() + st::connectionSkip); + if (_tcpProxyRadio.checked()) { + inputy = _tcpProxyRadio.y() + _tcpProxyRadio.height() + st::boxPadding.top(); + } + } + + if (inputy) { + _hostInput.show(); + _portInput.show(); + _userInput.show(); + _passwordInput.show(); + _hostInput.move(st::boxPadding.left() + st::rbDefFlat.textLeft, inputy); + _portInput.move(_width - st::boxPadding.right() - _portInput.width(), inputy); + _userInput.move(st::boxPadding.left() + st::rbDefFlat.textLeft, _hostInput.y() + _hostInput.height() + st::boxPadding.top()); + _passwordInput.move(_width - st::boxPadding.right() - _passwordInput.width(), _userInput.y()); + } else { + _hostInput.hide(); + _portInput.hide(); + _userInput.hide(); + _passwordInput.hide(); + } + + _saveButton.show(); + _cancelButton.show(); + + int32 buttony = (_tcpProxyRadio.checked() ? (_userInput.y() + _userInput.height()) : (_tcpProxyRadio.y() + _tcpProxyRadio.height())) + st::connectionSkip; + + _saveButton.move(_width - _saveButton.width(), buttony); + _cancelButton.move(0, buttony); + + _height = _saveButton.y() + _saveButton.height(); + resize(_width, _height); +} + +void ConnectionBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + } else if (e->key() == Qt::Key_Escape) { + onCancel(); + } +} + +void ConnectionBox::parentResized() { + QSize s = parentWidget()->size(); + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + update(); +} + +void ConnectionBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (_cache.isNull()) { + if (!_hiding || a_opacity.current() > 0.01) { + // fill bg + p.fillRect(0, 0, _width, _height, st::boxBG->b); + + // paint shadows + p.fillRect(0, st::addContactTitleHeight, _width, st::scrollDef.topsh, st::scrollDef.shColor->b); + p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b); + + // paint button sep + p.setPen(st::btnSelectSep->p); + p.drawLine(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::btnSelectCancel.width, _height - 1); + + // draw box title / text + p.setFont(st::addContactTitleFont->f); + p.setPen(st::black->p); + p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_connection_header)); + } + } else { + p.setOpacity(a_opacity.current()); + p.drawPixmap(0, 0, _cache); + } +} + +void ConnectionBox::animStep(float64 dt) { + if (dt >= 1) { + a_opacity.finish(); + _cache = QPixmap(); + if (!_hiding) { + showAll(); + if (!_hostInput.isHidden()) { + _hostInput.setFocus(); + } + } + } else { + a_opacity.update(dt, anim::linear); + } + update(); +} + +void ConnectionBox::onChange() { + showAll(); + if (_httpProxyRadio.checked() || _tcpProxyRadio.checked()) { + _hostInput.setFocus(); + if (_httpProxyRadio.checked() && !_portInput.text().toInt()) { + _portInput.setText(qsl("80")); + _portInput.updatePlaceholder(); + } + } + update(); +} + +void ConnectionBox::onSave() { + if (_httpProxyRadio.checked() || _tcpProxyRadio.checked()) { + ConnectionProxy p; + p.host = _hostInput.text().trimmed(); + p.user = _userInput.text().trimmed(); + p.password = _passwordInput.text().trimmed(); + p.port = _portInput.text().toInt(); + if (p.host.isEmpty()) { + _hostInput.setFocus(); + return; + } else if (!p.port) { + _portInput.setFocus(); + return; + } + if (_httpProxyRadio.checked()) { + cSetConnectionType(dbictHttpProxy); + } else { + cSetConnectionType(dbictTcpProxy); + } + cSetConnectionProxy(p); + } else { + cSetConnectionType(dbictAuto); + cSetConnectionProxy(ConnectionProxy()); + QNetworkProxyFactory::setUseSystemConfiguration(false); + QNetworkProxyFactory::setUseSystemConfiguration(true); + } + App::writeConfig(); + MTP::restart(); + emit closed(); +} + +void ConnectionBox::onCancel() { + emit closed(); +} + +void ConnectionBox::startHide() { + _hiding = true; + if (_cache.isNull()) { + _cache = grab(rect()); + hideAll(); + } + a_opacity.start(0); +} + +ConnectionBox::~ConnectionBox() { +} diff --git a/Telegram/SourceFiles/boxes/connectionbox.h b/Telegram/SourceFiles/boxes/connectionbox.h new file mode 100644 index 000000000..d0dabf26f --- /dev/null +++ b/Telegram/SourceFiles/boxes/connectionbox.h @@ -0,0 +1,58 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "layerwidget.h" +#include "gui/phoneinput.h" + +class ConnectionBox : public LayeredWidget { + Q_OBJECT + +public: + + ConnectionBox(); + void parentResized(); + void animStep(float64 dt); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void startHide(); + ~ConnectionBox(); + +public slots: + + void onChange(); + void onSave(); + void onCancel(); + +private: + + void hideAll(); + void showAll(); + + FlatButton _saveButton, _cancelButton; + FlatInput _hostInput; + PortInput _portInput; + FlatInput _userInput, _passwordInput; + FlatRadiobutton _autoRadio, _httpProxyRadio, _tcpProxyRadio; + + int32 _width, _height; + QPixmap _cache; + + anim::fvalue a_opacity; + bool _hiding; +}; diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp new file mode 100644 index 000000000..ec76e77af --- /dev/null +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -0,0 +1,549 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" + +#include "addcontactbox.h" +#include "contactsbox.h" +#include "mainwidget.h" +#include "window.h" + +ContactsInner::ContactsInner() : _contacts(&App::main()->contactsList()), _sel(0), _filteredSel(-1), _mouseSel(false) { + + _filter = qsl("a"); + updateFilter(); + + for (DialogRow *r = _contacts->list.begin; r != _contacts->list.end; r = r->next) { + r->attached = 0; + } + + connect(App::main(), SIGNAL(dialogRowReplaced(DialogRow *, DialogRow *)), this, SLOT(onDialogRowReplaced(DialogRow *, DialogRow *))); + connect(App::main(), SIGNAL(peerUpdated(PeerData*)), this, SLOT(peerUpdated(PeerData *))); + connect(App::main(), SIGNAL(peerNameChanged(PeerData *, const PeerData::Names &, const PeerData::NameFirstChars &)), this, SLOT(peerUpdated(PeerData *))); + connect(App::main(), SIGNAL(peerPhotoChanged(PeerData *)), this, SLOT(peerUpdated(PeerData *))); +} + +void ContactsInner::peerUpdated(PeerData *peer) { + if (!peer->chat) { + ContactsData::iterator i = _contactsData.find(peer->asUser()); + if (i != _contactsData.cend()) { + for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) { + if (row->attached == i.value()) row->attached = 0; + } + if (!_filter.isEmpty()) { + for (int32 j = 0, s = _filtered.size(); j < s; ++j) { + if (_filtered[j]->attached == i.value()) _filtered[j]->attached = 0; + } + } + delete i.value(); + _contactsData.erase(i); + } + } + + parentWidget()->update(); +} + +void ContactsInner::loadProfilePhotos(int32 yFrom) { + int32 yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5; + MTP::clearLoaderPriorities(); + + if (yTo < 0) return; + if (yFrom < 0) yFrom = 0; + + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; + if (_filter.isEmpty()) { + if (_contacts->list.count) { + _contacts->list.adjustCurrent(yFrom, rh); + for ( + DialogRow *preloadFrom = _contacts->list.current; + preloadFrom != _contacts->list.end && preloadFrom->pos * rh < yTo; + preloadFrom = preloadFrom->next + ) { + preloadFrom->history->peer->photo->load(); + } + } + } else if (!_filtered.isEmpty()) { + int32 from = yFrom / rh; + if (from < 0) from = 0; + if (from < _filtered.size()) { + int32 to = (yTo / rh) + 1; + if (to > _filtered.size()) to = _filtered.size(); + + for (; from < to; ++from) { + _filtered[from]->history->peer->photo->load(); + } + } + } +} + +ContactsInner::ContactData *ContactsInner::contactData(DialogRow *row) { + ContactData *data = (ContactData*)row->attached; + if (!data) { + UserData *user = row->history->peer->asUser(); + ContactsData::const_iterator i = _contactsData.constFind(user); + if (i == _contactsData.cend()) { + _contactsData.insert(user, data = new ContactData()); + data->name.setText(st::profileListNameFont, user->name, _textNameOptions); + data->online = App::onlineText(user->onlineTill, _time); + } else { + data = i.value(); + } + row->attached = data; + } + return data; +} + +void ContactsInner::paintDialog(QPainter &p, DialogRow *row, bool sel) { + int32 left = st::profileListPadding.width(); + + UserData *user = row->history->peer->asUser(); + ContactData *data = contactData(row); + + if (sel) { + p.fillRect(0, 0, width(), 2 * st::profileListPadding.height() + st::profileListPhotoSize, st::profileHoverBG->b); + } + + p.drawPixmap(left, st::profileListPadding.height(), user->photo->pix(st::profileListPhotoSize)); + + p.setPen(st::profileListNameColor->p); + data->name.drawElided(p, left + st::profileListPhotoSize + st::participantDelta, st::profileListNameTop, width() - st::profileListPadding.width() - st::profileListPhotoSize - st::profileListPadding.width() - st::participantDelta - st::scrollDef.width - st::contactsImg.width()); + + if (sel) { + p.drawPixmap(QPoint(width() - st::contactsImg.width() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::contactsImg.height()) / 2 - st::profileCheckDeltaY), App::sprite(), st::contactsImg); + } + + p.setFont(st::profileSubFont->f); + p.setPen((user->onlineTill >= _time ? st::profileOnlineColor : st::profileOfflineColor)->p); + + p.drawText(left + st::profileListPhotoSize + st::participantDelta, st::profileListPadding.height() + st::profileListPhotoSize - st::profileListStatusBottom, data->online); +} + +void ContactsInner::paintEvent(QPaintEvent *e) { + QRect r(e->rect()); + QPainter p(this); + + _time = unixtime(); + p.fillRect(r, st::white->b); + + int32 yFrom = r.top(); + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; + if (_filter.isEmpty()) { + if (_contacts->list.count) { + _contacts->list.adjustCurrent(yFrom, rh); + + DialogRow *drawFrom = _contacts->list.current; + p.translate(0, drawFrom->pos * rh); + while (drawFrom != _contacts->list.end && drawFrom->pos * rh < r.bottom()) { + paintDialog(p, drawFrom, (drawFrom == _sel)); + p.translate(0, rh); + drawFrom = drawFrom->next; + } + } else { + // .. + } + } else { + if (_filtered.isEmpty()) { + // .. + } else { + int32 from = yFrom / rh; + if (from < 0) from = 0; + if (from < _filtered.size()) { + int32 to = (r.bottom() / rh) + 1; + if (to > _filtered.size()) to = _filtered.size(); + + p.translate(0, from * rh); + for (; from < to; ++from) { + paintDialog(p, _filtered[from], (_filteredSel == from)); + p.translate(0, rh); + } + } + } + } +} + +void ContactsInner::enterEvent(QEvent *e) { + setMouseTracking(true); +} + +void ContactsInner::leaveEvent(QEvent *e) { + setMouseTracking(false); + updateSel(); +} + +void ContactsInner::mouseMoveEvent(QMouseEvent *e) { + _mouseSel = true; + _lastMousePos = e->globalPos(); + updateSel(); +} + +void ContactsInner::mousePressEvent(QMouseEvent *e) { + _mouseSel = true; + _lastMousePos = e->globalPos(); + updateSel(); + if (e->button() == Qt::LeftButton) { + chooseParticipant(); + } +} + +void ContactsInner::chooseParticipant() { + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from; + DialogRow *r = 0; + if (_filter.isEmpty()) { + r = _sel; + } else { + if (_filteredSel < 0 || _filteredSel >= _filtered.size()) return; + r = _filtered[_filteredSel]; + } + if (r) { + App::wnd()->hideSettings(true); + App::main()->showPeer(r->history->peer->id, false, true); + App::wnd()->hideLayer(); + } + + parentWidget()->update(); +} + +void ContactsInner::updateSel() { + if (!_mouseSel) return; + + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; + QPoint p(mapFromGlobal(_lastMousePos)); + if (_filter.isEmpty()) { + DialogRow *newSel = rect().contains(p) ? _contacts->list.rowAtY(p.y(), rh) : 0; + if (newSel != _sel) { + _sel = newSel; + parentWidget()->update(); + } + } else { + int32 newFilteredSel = (p.y() >= 0 && rect().contains(p)) ? (p.y() / rh) : -1; + if (newFilteredSel != _filteredSel) { + _filteredSel = newFilteredSel; + parentWidget()->update(); + } + } +} + +void ContactsInner::updateFilter(QString filter) { + QStringList f; + if (!filter.isEmpty()) { + QStringList filterList = filter.split(cWordSplit(), QString::SkipEmptyParts); + int l = filterList.size(); + + f.reserve(l); + for (int i = 0; i < l; ++i) { + QString filterName = filterList[i].trimmed(); + if (filterName.isEmpty()) continue; + f.push_back(filterName); + } + filter = f.join(' '); + } + if (_filter != filter) { + int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2); + _filter = filter; + if (_filter.isEmpty()) { + resize(width(), _contacts->list.count * rh + st::contactsClose.height); + if (_contacts->list.count) { + _sel = _contacts->list.begin; + } + } else { + QStringList::const_iterator fb = f.cbegin(), fe = f.cend(), fi; + + _filtered.clear(); + if (!f.isEmpty()) { + DialogsList *dialogsToFilter = 0; + if (_contacts->list.count) { + for (fi = fb; fi != fe; ++fi) { + DialogsIndexed::DialogsIndex::iterator i = _contacts->index.find(fi->at(0)); + if (i == _contacts->index.cend()) { + dialogsToFilter = 0; + break; + } + if (!dialogsToFilter || dialogsToFilter->count > i.value()->count) { + dialogsToFilter = i.value(); + } + } + } + if (dialogsToFilter && dialogsToFilter->count) { + _filtered.reserve(dialogsToFilter->count); + for (DialogRow *i = dialogsToFilter->begin, *e = dialogsToFilter->end; i != e; i = i->next) { + const PeerData::Names &names(i->history->peer->names); + PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni; + for (fi = fb; fi != fe; ++fi) { + QString filterName(*fi); + for (ni = nb; ni != ne; ++ni) { + if ((*ni).indexOf(*fi) == 0) { + break; + } + } + if (ni == ne) { + break; + } + } + if (fi == fe) { + i->attached = 0; + _filtered.push_back(i); + } + } + } + } + _filteredSel = _filtered.isEmpty() ? -1 : 0; + + resize(width(), _filtered.size() * rh + st::contactsClose.height); + } + if (parentWidget()) parentWidget()->update(); + loadProfilePhotos(0); + } +} + +void ContactsInner::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) { + if (!_filter.isEmpty()) { + for (FilteredDialogs::iterator i = _filtered.begin(), e = _filtered.end(); i != e;) { + if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts! + if (newRow) { + *i = newRow; + ++i; + } else { + i = _filtered.erase(i); + } + } else { + ++i; + } + } + if (_filteredSel >= _filtered.size()) { + _filteredSel = -1; + } + } else { + if (_sel == oldRow) { + _sel = newRow; + } + } + _mouseSel = false; + int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2); + int32 newh = (_filter.isEmpty() ? _contacts->list.count : _filtered.size()) * rh; + resize(width(), newh); +} + +ContactsInner::~ContactsInner() { + for (ContactsData::iterator i = _contactsData.begin(), e = _contactsData.end(); i != e; ++i) { + delete *i; + } +} + +void ContactsInner::selectSkip(int32 dir) { + _mouseSel = false; + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, origDir = dir; + if (_filter.isEmpty()) { + if (_sel) { + if (dir > 0) { + while (dir && _sel->next->next) { + _sel = _sel->next; + --dir; + } + } else { + while (dir && _sel->prev) { + _sel = _sel->prev; + ++dir; + } + } + } else if (dir > 0 && _contacts->list.count) { + _sel = _contacts->list.begin; + } + if (_sel) { + emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh + st::contactsClose.height); + } + } else { + if (dir > 0) { + if (_filteredSel < 0 && dir > 1) { + _filteredSel = 0; + } + _filteredSel += dir; + if (_filteredSel >= _filtered.size()) { + _filteredSel = _filtered.size() - 1; + } + } else if (_filteredSel > 0) { + _filteredSel += dir; + if (_filteredSel < 0) { + _filteredSel = 0; + } + } + if (_filteredSel >= 0) { + emit mustScrollTo(_filteredSel * rh, (_filteredSel + 1) * rh + st::contactsClose.height); + } + } + parentWidget()->update(); +} + +void ContactsInner::selectSkipPage(int32 h, int32 dir) { + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; + int32 points = h / rh; + if (!points) return; + selectSkip(points * dir); +} + +ContactsBox::ContactsBox() : _inner(), _hiding(false), _scroll(this, st::newGroupScroll), + _addContact(this, lang(lng_add_contact_button), st::contactsAdd), + _filter(this, st::contactsFilter, lang(lng_participant_filter)), + _close(this, lang(lng_contacts_done), st::contactsClose), + a_opacity(0, 1) { + + _width = st::participantWidth; + _height = App::wnd()->height() - st::boxPadding.top() - st::boxPadding.bottom(); + if (_height > st::participantMaxHeight) _height = st::participantMaxHeight; + + resize(_width, _height); + + _scroll.setWidget(&_inner); + _scroll.setFocusPolicy(Qt::NoFocus); + + connect(&_addContact, SIGNAL(clicked()), this, SLOT(onAdd())); + connect(&_close, SIGNAL(clicked()), this, SLOT(onClose())); + connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel())); + connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); + connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate())); + connect(&_filter, SIGNAL(cancelled()), this, SIGNAL(onClose())); + connect(&_inner, SIGNAL(mustScrollTo(int,int)), &_scroll, SLOT(scrollToY(int,int))); + + showAll(); + _cache = grab(rect()); + hideAll(); +} + +void ContactsBox::hideAll() { + _addContact.hide(); + _filter.hide(); + _scroll.hide(); + _close.hide(); +} + +void ContactsBox::showAll() { + _addContact.show(); + _filter.show(); + _scroll.show(); + _close.show(); +} + +void ContactsBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + onClose(); + } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { + if (_filter.hasFocus()) { + _inner.chooseParticipant(); + } + } else if (_filter.hasFocus()) { + if (e->key() == Qt::Key_Down) { + _inner.selectSkip(1); + } else if (e->key() == Qt::Key_Up) { + _inner.selectSkip(-1); + } else if (e->key() == Qt::Key_PageDown) { + _inner.selectSkipPage(_scroll.height(), 1); + } else if (e->key() == Qt::Key_PageUp) { + _inner.selectSkipPage(_scroll.height(), -1); + } else { + e->ignore(); + } + } else { + e->ignore(); + } +} + +void ContactsBox::parentResized() { + QSize s = parentWidget()->size(); + _height = App::wnd()->height() - st::boxPadding.top() - st::boxPadding.bottom(); + if (_height > st::participantMaxHeight) _height = st::participantMaxHeight; + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + update(); +} + +void ContactsBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (_cache.isNull()) { + if (!_hiding || a_opacity.current() > 0.01) { + // fill bg + p.fillRect(QRect(QPoint(0, 0), size()), st::boxBG->b); + + // paint shadows + p.fillRect(0, _addContact.height(), _width, st::scrollDef.topsh, st::scrollDef.shColor->b); + + // paint button sep + p.setPen(st::btnSelectSep->p); + p.drawLine(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::btnSelectCancel.width, size().height() - 1); + + // draw box title / text + p.setPen(st::black->p); + p.setFont(st::addContactTitleFont->f); + p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_contacts_header)); + } + } else { + p.setOpacity(a_opacity.current()); + p.drawPixmap(0, 0, _cache); + } +} + +void ContactsBox::resizeEvent(QResizeEvent *e) { + LayeredWidget::resizeEvent(e); + _addContact.move(_width - _addContact.width(), 0); + _filter.move(st::newGroupNamePadding.left(), _addContact.height() + st::newGroupNamePadding.top()); + _inner.resize(_width, _inner.height()); + _scroll.resize(_width, _height - _addContact.height() - st::newGroupNamePadding.top() - _filter.height() - st::newGroupNamePadding.bottom()); + _scroll.move(0, _filter.y() + _filter.height() + st::newGroupNamePadding.bottom()); + _close.move(0, _height - _close.height()); +} + +void ContactsBox::animStep(float64 dt) { + if (dt >= 1) { + a_opacity.finish(); + _cache = QPixmap(); + if (!_hiding) { + showAll(); + _filter.setFocus(); + } + } else { + a_opacity.update(dt, anim::linear); + } + update(); +} + +void ContactsBox::startHide() { + _hiding = true; + if (_cache.isNull()) { + _cache = grab(rect()); + hideAll(); + } + a_opacity.start(0); +} + +void ContactsBox::onFilterUpdate() { + _scroll.scrollToY(0); + _inner.updateFilter(_filter.text()); +} + +void ContactsBox::onAdd() { + App::wnd()->replaceLayer(new AddContactBox()); +} + +void ContactsBox::onClose() { + emit closed(); +} + +void ContactsBox::onScroll() { + _inner.loadProfilePhotos(_scroll.scrollTop()); +} + +ContactsBox::~ContactsBox() { + +} diff --git a/Telegram/SourceFiles/boxes/contactsbox.h b/Telegram/SourceFiles/boxes/contactsbox.h new file mode 100644 index 000000000..5fb4b01ac --- /dev/null +++ b/Telegram/SourceFiles/boxes/contactsbox.h @@ -0,0 +1,123 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "layerwidget.h" + +class ContactsInner : public QWidget, public RPCSender { + Q_OBJECT + +public: + + ContactsInner(); + + void paintEvent(QPaintEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + + void paintDialog(QPainter &p, DialogRow *row, bool sel); + void updateFilter(QString filter = QString()); + + void selectSkip(int32 dir); + void selectSkipPage(int32 h, int32 dir); + + void loadProfilePhotos(int32 yFrom); + + ~ContactsInner(); + +signals: + + void mustScrollTo(int ymin, int ymax); + +public slots: + + void onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow); + + void updateSel(); + void peerUpdated(PeerData *peer); + + void chooseParticipant(); + +private: + + int32 _time; + + DialogsIndexed *_contacts; + DialogRow *_sel; + QString _filter; + typedef QVector FilteredDialogs; + FilteredDialogs _filtered; + int32 _filteredSel; + bool _mouseSel; + + typedef struct { + Text name; + QString online; + } ContactData; + typedef QMap ContactsData; + ContactsData _contactsData; + + ContactData *contactData(DialogRow *row); + + QPoint _lastMousePos; + +}; + +class ContactsBox : public LayeredWidget, public RPCSender { + Q_OBJECT + +public: + + ContactsBox(); + void parentResized(); + void animStep(float64 dt); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void startHide(); + ~ContactsBox(); + +public slots: + + void onFilterUpdate(); + void onClose(); + void onScroll(); + void onAdd(); + +private: + + void hideAll(); + void showAll(); + + void created(const MTPmessages_StatedMessage &result); + bool failed(const RPCError &e); + + ScrollArea _scroll; + ContactsInner _inner; + FlatButton _addContact; + int32 _width, _height; + FlatInput _filter; + BottomButton _close; + bool _hiding; + + QPixmap _cache; + + anim::fvalue a_opacity; +}; diff --git a/Telegram/SourceFiles/boxes/downloadpathbox.cpp b/Telegram/SourceFiles/boxes/downloadpathbox.cpp new file mode 100644 index 000000000..4833a1193 --- /dev/null +++ b/Telegram/SourceFiles/boxes/downloadpathbox.cpp @@ -0,0 +1,192 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" + +#include "downloadpathbox.h" +#include "gui/filedialog.h" + +DownloadPathBox::DownloadPathBox() : _hiding(false), + _path(cDownloadPath()), + _tempRadio(this, qsl("dir_type"), 0, lang(lng_download_path_temp_radio), _path.isEmpty()), + _dirRadio(this, qsl("dir_type"), 1, lang(lng_download_path_dir_radio), !_path.isEmpty()), + _dirInput(this, st::inpDownloadDir, QString(), QDir::toNativeSeparators(_path)), + _saveButton(this, lang(lng_connection_save), st::btnSelectDone), + _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), + a_opacity(0, 1) { + + _width = st::addContactWidth; + + connect(&_saveButton, SIGNAL(clicked()), this, SLOT(onSave())); + connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCancel())); + + connect(&_tempRadio, SIGNAL(changed()), this, SLOT(onChange())); + connect(&_dirRadio, SIGNAL(changed()), this, SLOT(onChange())); + + connect(&_dirInput, SIGNAL(focused()), this, SLOT(onEditPath())); + _dirInput.setCursorPosition(0); + + showAll(); + _cache = grab(rect()); + hideAll(); +} + +void DownloadPathBox::hideAll() { + _tempRadio.hide(); + _dirRadio.hide(); + + _dirInput.hide(); + + _saveButton.hide(); + _cancelButton.hide(); +} + +void DownloadPathBox::showAll() { + _tempRadio.show(); + _dirRadio.show(); + + if (_dirRadio.checked()) { + _dirInput.show(); + } else { + _dirInput.hide(); + } + + _saveButton.show(); + _cancelButton.show(); + + _tempRadio.move(st::boxPadding.left(), st::addContactTitleHeight + st::downloadSkip); + _dirRadio.move(st::boxPadding.left(), _tempRadio.y() + _tempRadio.height() + st::downloadSkip); + int32 inputy = _dirRadio.y() + _dirRadio.height() + st::boxPadding.top(); + + _dirInput.move(st::boxPadding.left() + st::rbDefFlat.textLeft, inputy); + + int32 buttony = (_dirRadio.checked() ? (_dirInput.y() + _dirInput.height()) : (_dirRadio.y() + _dirRadio.height())) + st::downloadSkip; + + _saveButton.move(_width - _saveButton.width(), buttony); + _cancelButton.move(0, buttony); + + _height = _saveButton.y() + _saveButton.height(); + resize(_width, _height); +} + +void DownloadPathBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + } else if (e->key() == Qt::Key_Escape) { + onCancel(); + } +} + +void DownloadPathBox::parentResized() { + QSize s = parentWidget()->size(); + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + update(); +} + +void DownloadPathBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (_cache.isNull()) { + if (!_hiding || a_opacity.current() > 0.01) { + // fill bg + p.fillRect(0, 0, _width, _height, st::boxBG->b); + + // paint shadows + p.fillRect(0, st::addContactTitleHeight, _width, st::scrollDef.topsh, st::scrollDef.shColor->b); + p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b); + + // paint button sep + p.setPen(st::btnSelectSep->p); + p.drawLine(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::btnSelectCancel.width, _height - 1); + + // draw box title / text + p.setFont(st::addContactTitleFont->f); + p.setPen(st::black->p); + p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_download_path_header)); + } + } else { + p.setOpacity(a_opacity.current()); + p.drawPixmap(0, 0, _cache); + } +} + +void DownloadPathBox::animStep(float64 dt) { + if (dt >= 1) { + a_opacity.finish(); + _cache = QPixmap(); + if (!_hiding) { + showAll(); + } + } else { + a_opacity.update(dt, anim::linear); + } + update(); +} + +void DownloadPathBox::onChange() { + if (_dirRadio.checked()) { + if (_path.isEmpty()) { + _tempRadio.setChecked(true); + onEditPath(); + if (!_path.isEmpty()) { + _dirRadio.setChecked(true); + } + } else { + _dirInput.setText(QDir::toNativeSeparators(_path)); + _dirInput.setCursorPosition(0); + } + } + showAll(); + update(); +} + +void DownloadPathBox::onEditPath() { + _dirInput.clearFocus(); + + filedialogInit(); + QString path, lastPath = cDialogLastPath(); + if (!cDownloadPath().isEmpty()) cSetDialogLastPath(cDownloadPath()); + if (filedialogGetDir(path, lang(lng_download_path_choose))) { + if (!path.isEmpty()) { + _path = path + '/'; + _dirInput.setText(QDir::toNativeSeparators(_path)); + _dirInput.setCursorPosition(0); + } + } + cSetDialogLastPath(lastPath); +} + +void DownloadPathBox::onSave() { + cSetDownloadPath(_tempRadio.checked() ? QString() : _path); + App::writeUserConfig(); + emit closed(); +} + +void DownloadPathBox::onCancel() { + emit closed(); +} + +void DownloadPathBox::startHide() { + _hiding = true; + if (_cache.isNull()) { + _cache = grab(rect()); + hideAll(); + } + a_opacity.start(0); +} + +DownloadPathBox::~DownloadPathBox() { +} diff --git a/Telegram/SourceFiles/boxes/downloadpathbox.h b/Telegram/SourceFiles/boxes/downloadpathbox.h new file mode 100644 index 000000000..e704542ae --- /dev/null +++ b/Telegram/SourceFiles/boxes/downloadpathbox.h @@ -0,0 +1,59 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "layerwidget.h" +#include "gui/phoneinput.h" + +class DownloadPathBox : public LayeredWidget { + Q_OBJECT + +public: + + DownloadPathBox(); + void parentResized(); + void animStep(float64 dt); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void startHide(); + ~DownloadPathBox(); + +public slots: + + void onChange(); + void onEditPath(); + void onSave(); + void onCancel(); + +private: + + void hideAll(); + void showAll(); + + QString _path; + + FlatRadiobutton _tempRadio, _dirRadio; + FlatInput _dirInput; + FlatButton _saveButton, _cancelButton; + + int32 _width, _height; + QPixmap _cache; + + anim::fvalue a_opacity; + bool _hiding; +}; diff --git a/Telegram/SourceFiles/boxes/emojibox.cpp b/Telegram/SourceFiles/boxes/emojibox.cpp new file mode 100644 index 000000000..f435711b8 --- /dev/null +++ b/Telegram/SourceFiles/boxes/emojibox.cpp @@ -0,0 +1,196 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" + +#include "emojibox.h" +#include "mainwidget.h" +#include "window.h" + +namespace { + // copied from genemoji.cpp + struct EmojiReplace { + uint32 code; + const char *replace; + }; + EmojiReplace replaces[] = { + {0xD83DDE0A, ":-)"}, + {0xD83DDE03, ":-D"}, + {0xD83DDE09, ";-)"}, + {0xD83DDE06, "xD"}, + {0xD83DDE1C, ";-P"}, + {0xD83DDE0B, ":-p"}, + {0xD83DDE0D, "8-)"}, + {0xD83DDE0E, "B-)"}, + {0xD83DDE12, ":-("}, + {0xD83DDE0F, ":]"}, + {0xD83DDE14, "3("}, + {0xD83DDE22, ":'("}, + {0xD83DDE2D, ":_("}, + {0xD83DDE29, ":(("}, + {0xD83DDE28, ":o"}, + {0xD83DDE10, ":|"}, + {0xD83DDE0C, "3-)"}, + {0xD83DDE20, ">("}, + {0xD83DDE21, ">(("}, + {0xD83DDE07, "O:)"}, + {0xD83DDE30, ";o"}, + {0xD83DDE33, "8|"}, + {0xD83DDE32, "8o"}, + {0xD83DDE37, ":X"}, + {0xD83DDE1A, ":-*"}, + {0xD83DDE08, "}:)"}, + {0x2764, "<3"}, + {0xD83DDC4D, ":like:"}, + {0xD83DDC4E, ":dislike:"}, + {0x261D, ":up:"}, + {0x270C, ":v:"}, + {0xD83DDC4C, ":ok:"} + }; + const uint32 replacesCount = sizeof(replaces) / sizeof(EmojiReplace), replacesInRow = 8; +} + +EmojiBox::EmojiBox() : _hiding(false), + _done(this, lang(lng_about_done), st::aboutCloseButton), + a_opacity(0, 1) { + + fillBlocks(); + + _blockHeight = st::emojiReplaceInnerHeight; + + _width = _blocks[0].size() * st::emojiReplaceWidth + (st::emojiReplaceWidth - st::emojiSize); + + _height = st::boxPadding.top() + st::boxFont->height; + _height += _blocks.size() * st::emojiReplaceHeight + (st::emojiReplaceHeight - _blockHeight); + _height += _done.height(); + + _done.setWidth(_width); + _header.setText(st::boxFont, lang(lng_settings_emoji_list)); + + _done.move(0, _height - _done.height()); + + connect(&_done, SIGNAL(clicked()), this, SLOT(onClose())); + + resize(_width, _height); + + showAll(); + _cache = grab(rect()); + hideAll(); +} + +void EmojiBox::fillBlocks() { + BlockRow currentRow; + currentRow.reserve(replacesInRow); + for (int32 i = 0; i < replacesCount; ++i) { + Block block(getEmoji(replaces[i].code), QString::fromUtf8(replaces[i].replace)); + currentRow.push_back(block); + if (currentRow.size() == replacesInRow) { + _blocks.push_back(currentRow); + currentRow.resize(0); + } + } + if (currentRow.size()) { + _blocks.push_back(currentRow); + } +} + +void EmojiBox::hideAll() { + _done.hide(); +} + +void EmojiBox::showAll() { + _done.show(); +} + +void EmojiBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + onClose(); + } else if (e->key() == Qt::Key_Escape) { + onClose(); + } +} + +void EmojiBox::parentResized() { + QSize s = parentWidget()->size(); + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + update(); +} + +void EmojiBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (_cache.isNull()) { + if (!_hiding || a_opacity.current() > 0.01) { + // fill bg + p.fillRect(0, 0, _width, _height, st::boxBG->b); + + p.setFont(st::boxFont->f); + p.setPen(st::boxGrayTitle->p); + _header.draw(p, 0, st::boxPadding.top(), _width, Qt::AlignCenter); + + p.setFont(st::emojiTextFont->f); + p.setPen(st::black->p); + int32 top = st::boxPadding.top() + st::boxFont->height + (st::emojiReplaceHeight - _blockHeight) / 2; + for (Blocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) { + int32 rowSize = i->size(), left = (_width - rowSize * st::emojiReplaceWidth) / 2; + for (BlockRow::const_iterator j = i->cbegin(), en = i->cend(); j != en; ++j) { + if (j->emoji) { + QPoint pos(left + (st::emojiReplaceWidth - st::emojiSize) / 2, top + (st::emojiReplaceHeight - _blockHeight) / 2); + p.drawPixmap(pos, App::emojis(), QRect(j->emoji->x, j->emoji->y, st::emojiSize, st::emojiSize)); + } + QRect trect(left, top + (st::emojiReplaceHeight + _blockHeight) / 2 - st::emojiTextFont->height, st::emojiReplaceWidth, st::emojiTextFont->height); + p.drawText(trect, j->text, QTextOption(Qt::AlignHCenter | Qt::AlignTop)); + left += st::emojiReplaceWidth; + } + top += st::emojiReplaceHeight; + } + } + } else { + p.setOpacity(a_opacity.current()); + p.drawPixmap(0, 0, _cache); + } +} + +void EmojiBox::animStep(float64 ms) { + if (ms >= 1) { + a_opacity.finish(); + _cache = QPixmap(); + if (!_hiding) { + showAll(); + setFocus(); + } + } else { + a_opacity.update(ms, anim::linear); + } + update(); +} + +void EmojiBox::onClose() { + emit closed(); +} + +void EmojiBox::startHide() { + _hiding = true; + if (_cache.isNull()) { + _cache = grab(rect()); + hideAll(); + } + a_opacity.start(0); +} + +EmojiBox::~EmojiBox() { +} diff --git a/Telegram/SourceFiles/boxes/emojibox.h b/Telegram/SourceFiles/boxes/emojibox.h new file mode 100644 index 000000000..c250c60f6 --- /dev/null +++ b/Telegram/SourceFiles/boxes/emojibox.h @@ -0,0 +1,66 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "layerwidget.h" + +class EmojiBox : public LayeredWidget { + Q_OBJECT + +public: + + EmojiBox(); + void parentResized(); + void animStep(float64 ms); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void startHide(); + ~EmojiBox(); + +public slots: + + void onClose(); + +private: + + void hideAll(); + void showAll(); + + void fillBlocks(); + + int32 _width, _height; + BottomButton _done; + + Text _header; + + int32 _blockHeight; + struct Block { + Block(const EmojiData *emoji = 0, const QString &text = QString()) : emoji(emoji), text(text) { + } + const EmojiData *emoji; + QString text; + }; + typedef QVector BlockRow; + typedef QVector Blocks; + Blocks _blocks; + + bool _hiding; + QPixmap _cache; + + anim::fvalue a_opacity; +}; diff --git a/Telegram/SourceFiles/boxes/newgroupbox.cpp b/Telegram/SourceFiles/boxes/newgroupbox.cpp new file mode 100644 index 000000000..b4b66feb2 --- /dev/null +++ b/Telegram/SourceFiles/boxes/newgroupbox.cpp @@ -0,0 +1,764 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" + +#include "newgroupbox.h" +#include "mainwidget.h" +#include "window.h" + +NewGroupInner::NewGroupInner() : _contacts(&App::main()->contactsList()), _sel(0), _filteredSel(-1), _mouseSel(false), _selCount(0) { + + _filter = qsl("a"); + updateFilter(); + + for (DialogRow *r = _contacts->list.begin; r != _contacts->list.end; r = r->next) { + r->attached = 0; + } + + connect(App::main(), SIGNAL(dialogRowReplaced(DialogRow *, DialogRow *)), this, SLOT(onDialogRowReplaced(DialogRow *, DialogRow *))); + connect(App::main(), SIGNAL(peerUpdated(PeerData*)), this, SLOT(peerUpdated(PeerData *))); + connect(App::main(), SIGNAL(peerNameChanged(PeerData *, const PeerData::Names &, const PeerData::NameFirstChars &)), this, SLOT(peerUpdated(PeerData *))); + connect(App::main(), SIGNAL(peerPhotoChanged(PeerData *)), this, SLOT(peerUpdated(PeerData *))); +} + +void NewGroupInner::peerUpdated(PeerData *peer) { + if (!peer->chat) { + ContactsData::iterator i = _contactsData.find(peer->asUser()); + if (i != _contactsData.cend()) { + for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) { + if (row->attached == i.value()) row->attached = 0; + } + if (!_filter.isEmpty()) { + for (int32 j = 0, s = _filtered.size(); j < s; ++j) { + if (_filtered[j]->attached == i.value()) _filtered[j]->attached = 0; + } + } + delete i.value(); + _contactsData.erase(i); + } + } + + parentWidget()->update(); +} + +void NewGroupInner::loadProfilePhotos(int32 yFrom) { + int32 yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5; + MTP::clearLoaderPriorities(); + + if (yTo < 0) return; + if (yFrom < 0) yFrom = 0; + + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; + if (_filter.isEmpty()) { + if (_contacts->list.count) { + _contacts->list.adjustCurrent(yFrom, rh); + for ( + DialogRow *preloadFrom = _contacts->list.current; + preloadFrom != _contacts->list.end && preloadFrom->pos * rh < yTo; + preloadFrom = preloadFrom->next + ) { + preloadFrom->history->peer->photo->load(); + } + } + } else if (!_filtered.isEmpty()) { + int32 from = yFrom / rh; + if (from < 0) from = 0; + if (from < _filtered.size()) { + int32 to = (yTo / rh) + 1; + if (to > _filtered.size()) to = _filtered.size(); + + for (; from < to; ++from) { + _filtered[from]->history->peer->photo->load(); + } + } + } +} + +NewGroupInner::ContactData *NewGroupInner::contactData(DialogRow *row) { + ContactData *data = (ContactData*)row->attached; + if (!data) { + UserData *user = row->history->peer->asUser(); + ContactsData::const_iterator i = _contactsData.constFind(user); + if (i == _contactsData.cend()) { + _contactsData.insert(user, data = new ContactData()); + data->check = false; + data->name.setText(st::profileListNameFont, user->name, _textNameOptions); + data->online = App::onlineText(user->onlineTill, _time); + } else { + data = i.value(); + } + row->attached = data; + } + return data; +} + +void NewGroupInner::paintDialog(QPainter &p, DialogRow *row, bool sel) { + int32 left = st::profileListPadding.width(); + + UserData *user = row->history->peer->asUser(); + ContactData *data = contactData(row); + + if (_selCount >= cMaxGroupCount() && !data->check) { + sel = false; + } + + if (sel || data->check) { + p.fillRect(0, 0, width(), 2 * st::profileListPadding.height() + st::profileListPhotoSize, (data->check ? st::profileActiveBG : st::profileHoverBG)->b); + } + + p.drawPixmap(left, st::profileListPadding.height(), user->photo->pix(st::profileListPhotoSize)); + + if (data->check) { + p.setPen(st::white->p); + } else { + p.setPen(st::profileListNameColor->p); + } + data->name.drawElided(p, left + st::profileListPhotoSize + st::participantDelta, st::profileListNameTop, width() - st::profileListPadding.width() - st::profileListPhotoSize - st::profileListPadding.width() - st::participantDelta - st::scrollDef.width - st::profileCheckRect.width()); + + if (sel || data->check) { + p.drawPixmap(QPoint(width() - st::profileCheckRect.width() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::profileCheckRect.height()) / 2 - st::profileCheckDeltaY), App::sprite(), (data->check ? st::profileCheckActiveRect : st::profileCheckRect)); + } + + p.setFont(st::profileSubFont->f); + if (data->check) { + p.setPen(st::white->p); + } else { + p.setPen((user->onlineTill >= _time ? st::profileOnlineColor : st::profileOfflineColor)->p); + } + p.drawText(left + st::profileListPhotoSize + st::participantDelta, st::profileListPadding.height() + st::profileListPhotoSize - 6, data->online); +} + +void NewGroupInner::paintEvent(QPaintEvent *e) { + QRect r(e->rect()); + QPainter p(this); + + _time = unixtime(); + p.fillRect(r, st::white->b); + + int32 yFrom = r.top(); + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; + if (_filter.isEmpty()) { + if (_contacts->list.count) { + _contacts->list.adjustCurrent(yFrom, rh); + + DialogRow *drawFrom = _contacts->list.current; + p.translate(0, drawFrom->pos * rh); + while (drawFrom != _contacts->list.end && drawFrom->pos * rh < r.bottom()) { + paintDialog(p, drawFrom, (drawFrom == _sel)); + p.translate(0, rh); + drawFrom = drawFrom->next; + } + } else { + // .. + } + } else { + if (_filtered.isEmpty()) { + // .. + } else { + int32 from = yFrom / rh; + if (from < 0) from = 0; + if (from < _filtered.size()) { + int32 to = (r.bottom() / rh) + 1; + if (to > _filtered.size()) to = _filtered.size(); + + p.translate(0, from * rh); + for (; from < to; ++from) { + paintDialog(p, _filtered[from], (_filteredSel == from)); + p.translate(0, rh); + } + } + } + } +} + +void NewGroupInner::enterEvent(QEvent *e) { + setMouseTracking(true); +} + +void NewGroupInner::leaveEvent(QEvent *e) { + setMouseTracking(false); + updateSel(); +} + +void NewGroupInner::mouseMoveEvent(QMouseEvent *e) { + _mouseSel = true; + _lastMousePos = e->globalPos(); + updateSel(); +} + +void NewGroupInner::mousePressEvent(QMouseEvent *e) { + _mouseSel = true; + _lastMousePos = e->globalPos(); + updateSel(); + if (e->button() == Qt::LeftButton) { + chooseParticipant(); + } +} + +void NewGroupInner::changeCheckState(DialogRow *row) { + if (contactData(row)->check) { + contactData(row)->check = false; + --_selCount; + } else if (_selCount < cMaxGroupCount()) { + contactData(row)->check = true; + ++_selCount; + } +} + +void NewGroupInner::chooseParticipant() { + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from; + if (_filter.isEmpty()) { + if (!_sel) return; + changeCheckState(_sel); + } else { + if (_filteredSel < 0 || _filteredSel >= _filtered.size()) return; + + DialogRow *row = _filtered[_filteredSel]; + changeCheckState(row); + + PeerData *peer = row->history->peer; + updateFilter(); + + for (_sel = _contacts->list.begin; _sel != _contacts->list.end; _sel = _sel->next) { + if (_sel->history->peer == peer) { + break; + } + } + if (_sel == _contacts->list.end) { + _sel = 0; + } else { + emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh); + } + } + + parentWidget()->update(); +} + +void NewGroupInner::updateSel() { + if (!_mouseSel) return; + + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; + QPoint p(mapFromGlobal(_lastMousePos)); + if (_filter.isEmpty()) { + DialogRow *newSel = rect().contains(p) ? _contacts->list.rowAtY(p.y(), rh) : 0; + if (newSel != _sel) { + _sel = newSel; + parentWidget()->update(); + } + } else { + int32 newFilteredSel = (p.y() >= 0 && rect().contains(p)) ? (p.y() / rh) : -1; + if (newFilteredSel != _filteredSel) { + _filteredSel = newFilteredSel; + parentWidget()->update(); + } + } +} + +void NewGroupInner::updateFilter(QString filter) { + QStringList f; + if (!filter.isEmpty()) { + QStringList filterList = filter.split(cWordSplit(), QString::SkipEmptyParts); + int l = filterList.size(); + + f.reserve(l); + for (int i = 0; i < l; ++i) { + QString filterName = filterList[i].trimmed(); + if (filterName.isEmpty()) continue; + f.push_back(filterName); + } + filter = f.join(' '); + } + if (_filter != filter) { + int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2); + _filter = filter; + if (_filter.isEmpty()) { + resize(width(), _contacts->list.count * rh); + if (_contacts->list.count) { + _sel = _contacts->list.begin; + } + } else { + QStringList::const_iterator fb = f.cbegin(), fe = f.cend(), fi; + + _filtered.clear(); + if (!f.isEmpty()) { + DialogsList *dialogsToFilter = 0; + if (_contacts->list.count) { + for (fi = fb; fi != fe; ++fi) { + DialogsIndexed::DialogsIndex::iterator i = _contacts->index.find(fi->at(0)); + if (i == _contacts->index.cend()) { + dialogsToFilter = 0; + break; + } + if (!dialogsToFilter || dialogsToFilter->count > i.value()->count) { + dialogsToFilter = i.value(); + } + } + } + if (dialogsToFilter && dialogsToFilter->count) { + _filtered.reserve(dialogsToFilter->count); + for (DialogRow *i = dialogsToFilter->begin, *e = dialogsToFilter->end; i != e; i = i->next) { + const PeerData::Names &names(i->history->peer->names); + PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni; + for (fi = fb; fi != fe; ++fi) { + QString filterName(*fi); + for (ni = nb; ni != ne; ++ni) { + if ((*ni).indexOf(*fi) == 0) { + break; + } + } + if (ni == ne) { + break; + } + } + if (fi == fe) { + i->attached = 0; + _filtered.push_back(i); + } + } + } + } + _filteredSel = _filtered.isEmpty() ? -1 : 0; + + resize(width(), _filtered.size() * rh); + } + if (parentWidget()) parentWidget()->update(); + loadProfilePhotos(0); + } +} + +void NewGroupInner::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) { + if (!_filter.isEmpty()) { + for (FilteredDialogs::iterator i = _filtered.begin(), e = _filtered.end(); i != e;) { + if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts! + if (newRow) { + *i = newRow; + ++i; + } else { + i = _filtered.erase(i); + } + } else { + ++i; + } + } + if (_filteredSel >= _filtered.size()) { + _filteredSel = -1; + } + } else { + if (_sel == oldRow) { + _sel = newRow; + } + } + _mouseSel = false; + int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2); + int32 newh = (_filter.isEmpty() ? _contacts->list.count : _filtered.size()) * rh; + resize(width(), newh); +} + +NewGroupInner::~NewGroupInner() { + for (ContactsData::iterator i = _contactsData.begin(), e = _contactsData.end(); i != e; ++i) { + delete *i; + } +} + +void NewGroupInner::selectSkip(int32 dir) { + _mouseSel = false; + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, origDir = dir; + if (_filter.isEmpty()) { + if (_sel) { + if (dir > 0) { + while (dir && _sel->next->next) { + _sel = _sel->next; + --dir; + } + } else { + while (dir && _sel->prev) { + _sel = _sel->prev; + ++dir; + } + } + } else if (dir > 0 && _contacts->list.count) { + _sel = _contacts->list.begin; + } + if (_sel) { + emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh); + } + } else { + if (dir > 0) { + if (_filteredSel < 0 && dir > 1) { + _filteredSel = 0; + } + _filteredSel += dir; + if (_filteredSel >= _filtered.size()) { + _filteredSel = _filtered.size() - 1; + } + } else if (_filteredSel > 0) { + _filteredSel += dir; + if (_filteredSel < 0) { + _filteredSel = 0; + } + } + if (_filteredSel >= 0) { + emit mustScrollTo(_filteredSel * rh, (_filteredSel + 1) * rh); + } + } + parentWidget()->update(); +} + +void NewGroupInner::selectSkipPage(int32 h, int32 dir) { + int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; + int32 points = h / rh; + if (!points) return; + selectSkip(points * dir); +} + +QVector NewGroupInner::selectedInputs() { + QVector result; + result.reserve(_contactsData.size()); + for (ContactsData::const_iterator i = _contactsData.cbegin(), e = _contactsData.cend(); i != e; ++i) { + if (i.value()->check) { + result.push_back(i.key()->inputUser); + } + } + return result; +} + +NewGroupBox::NewGroupBox() : _inner(), _hiding(false), _scroll(this, st::newGroupScroll), + _filter(this, st::contactsFilter, lang(lng_participant_filter)), + _next(this, lang(lng_create_group_next), st::btnSelectDone), + _cancel(this, lang(lng_cancel), st::btnSelectCancel), + a_opacity(0, 1) { + + _width = st::participantWidth; + _height = App::wnd()->height() - st::boxPadding.top() - st::boxPadding.bottom(); + if (_height > st::participantMaxHeight) _height = st::participantMaxHeight; + + resize(_width, _height); + + _scroll.setWidget(&_inner); + _scroll.setFocusPolicy(Qt::NoFocus); + + connect(&_next, SIGNAL(clicked()), this, SLOT(onNext())); + connect(&_cancel, SIGNAL(clicked()), this, SIGNAL(closed())); + connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel())); + connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); + connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate())); + connect(&_filter, SIGNAL(cancelled()), this, SIGNAL(onClose())); + connect(&_inner, SIGNAL(mustScrollTo(int,int)), &_scroll, SLOT(scrollToY(int,int))); + + showAll(); + _cache = grab(rect()); + hideAll(); +} + +void NewGroupBox::hideAll() { + _filter.hide(); + _scroll.hide(); + _next.hide(); + _cancel.hide(); +} + +void NewGroupBox::showAll() { + _filter.show(); + _scroll.show(); + _next.show(); + _cancel.show(); +} + +void NewGroupBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + onClose(); + } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { + _inner.chooseParticipant(); + } else if (_filter.hasFocus()) { + if (e->key() == Qt::Key_Down) { + _inner.selectSkip(1); + } else if (e->key() == Qt::Key_Up) { + _inner.selectSkip(-1); + } else if (e->key() == Qt::Key_PageDown) { + _inner.selectSkipPage(_scroll.height(), 1); + } else if (e->key() == Qt::Key_PageUp) { + _inner.selectSkipPage(_scroll.height(), -1); + } else { + e->ignore(); + } + } else { + e->ignore(); + } +} + +void NewGroupBox::parentResized() { + QSize s = parentWidget()->size(); + _height = App::wnd()->height() - st::boxPadding.top() - st::boxPadding.bottom(); + if (_height > st::participantMaxHeight) _height = st::participantMaxHeight; + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + update(); +} + +void NewGroupBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (_cache.isNull()) { + if (!_hiding || a_opacity.current() > 0.01) { + // fill bg + p.fillRect(QRect(QPoint(0, 0), size()), st::boxBG->b); + + // paint shadows + p.fillRect(0, st::participantFilter.height, _width, st::scrollDef.topsh, st::scrollDef.shColor->b); + + // paint button sep + p.setPen(st::btnSelectSep->p); + p.drawLine(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::btnSelectCancel.width, size().height() - 1); + + // draw box title / text + p.setPen(st::black->p); + p.setFont(st::addContactTitleFont->f); + p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_create_new_group)); + } + } else { + p.setOpacity(a_opacity.current()); + p.drawPixmap(0, 0, _cache); + } +} + +void NewGroupBox::resizeEvent(QResizeEvent *e) { + LayeredWidget::resizeEvent(e); + _filter.move(st::newGroupNamePadding.left(), st::contactsAdd.height + st::newGroupNamePadding.top()); + _inner.resize(_width, _inner.height()); + _scroll.resize(_width, _height - st::contactsAdd.height - st::newGroupNamePadding.top() - _filter.height() - st::newGroupNamePadding.bottom() - _cancel.height()); + _scroll.move(0, _filter.y() + _filter.height() + st::newGroupNamePadding.bottom()); + _next.move(width() - _next.width(), _height - _next.height()); + _cancel.move(0, _height - _cancel.height()); +} + +void NewGroupBox::animStep(float64 dt) { + if (dt >= 1) { + a_opacity.finish(); + _cache = QPixmap(); + if (!_hiding) { + showAll(); + _filter.setFocus(); + } + } else { + a_opacity.update(dt, anim::linear); + } + update(); +} + +void NewGroupBox::startHide() { + _hiding = true; + if (_cache.isNull()) { + _cache = grab(rect()); + hideAll(); + } + a_opacity.start(0); +} + +void NewGroupBox::onFilterUpdate() { + _scroll.scrollToY(0); + _inner.updateFilter(_filter.text()); +} + +void NewGroupBox::onClose() { + emit closed(); +} + +void NewGroupBox::onNext() { + MTPVector users(MTP_vector(_inner.selectedInputs())); + if (users.c_vector().v.isEmpty()) { + _filter.setFocus(); + _filter.notaBene(); + return; + } + + App::wnd()->replaceLayer(new CreateGroupBox(users)); +} + +void NewGroupBox::onScroll() { + _inner.loadProfilePhotos(_scroll.scrollTop()); +} + +NewGroupBox::~NewGroupBox() { +} + +CreateGroupBox::CreateGroupBox(const MTPVector &users) : _users(users), + _hiding(false), _createRequestId(0), + _name(this, st::newGroupName, lang(lng_dlg_new_group_name)), + _create(this, lang(lng_dlg_create_group), st::btnSelectDone), + _cancel(this, lang(lng_cancel), st::btnSelectCancel), + a_opacity(0, 1) { + _width = st::addContactWidth; + + _height = st::addContactTitleHeight + st::addContactPadding.top() + _name.height() + st::addContactPadding.bottom() + _create.height(); + + _name.setGeometry(st::addContactPadding.left(), st::addContactTitleHeight + st::addContactPadding.top(), _width - st::addContactPadding.left() - st::addContactPadding.right(), _name.height()); + + int32 buttonTop = _name.y() + _name.height() + st::addContactPadding.bottom(); + _cancel.move(0, buttonTop); + _create.move(_width - _create.width(), buttonTop); + + connect(&_create, SIGNAL(clicked()), this, SLOT(onCreate())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onCancel())); + + resize(_width, _height); + + showAll(); + _cache = grab(rect()); + hideAll(); +} + +void CreateGroupBox::hideAll() { + _name.hide(); + _cancel.hide(); + _create.hide(); +} + +void CreateGroupBox::showAll() { + _name.show(); + _cancel.show(); + _create.show(); +} + +void CreateGroupBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + if (_name.hasFocus()) { + if (_name.text().trimmed().isEmpty()) { + _name.setFocus(); + _name.notaBene(); + } else { + onCreate(); + } + } + } else if (e->key() == Qt::Key_Escape) { + onCancel(); + } +} + +void CreateGroupBox::parentResized() { + QSize s = parentWidget()->size(); + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + update(); +} + +void CreateGroupBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (_cache.isNull()) { + if (!_hiding || a_opacity.current() > 0.01) { + // fill bg + p.fillRect(QRect(QPoint(0, 0), size()), st::boxBG->b); + + // paint shadows + p.fillRect(0, st::addContactTitleHeight, _width, st::scrollDef.topsh, st::scrollDef.shColor->b); + p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b); + + // paint button sep + p.setPen(st::btnSelectSep->p); + p.drawLine(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::btnSelectCancel.width, size().height() - 1); + + // draw box title / text + p.setPen(st::black->p); + p.setFont(st::addContactTitleFont->f); + p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_create_group_title)); + } + } else { + p.setOpacity(a_opacity.current()); + p.drawPixmap(0, 0, _cache); + } +} + +void CreateGroupBox::animStep(float64 dt) { + if (dt >= 1) { + a_opacity.finish(); + _cache = QPixmap(); + if (!_hiding) { + showAll(); + _name.setFocus(); + } + } else { + a_opacity.update(dt, anim::linear); + } + update(); +} + +void CreateGroupBox::onCreate() { + if (_createRequestId) return; + + QString name = _name.text(); + if (name.isEmpty()) { + _name.setFocus(); + _name.notaBene(); + return; + } + + _create.setDisabled(true); + _name.setDisabled(true); + _createRequestId = MTP::send(MTPmessages_CreateChat(_users, MTP_string(_name.text())), rpcDone(&CreateGroupBox::created), rpcFail(&CreateGroupBox::failed)); +} + +void CreateGroupBox::created(const MTPmessages_StatedMessage &result) { + App::main()->sentFullDataReceived(0, result); + const QVector *d = 0; + switch (result.type()) { + case mtpc_messages_statedMessage: { + d = &result.c_messages_statedMessage().vchats.c_vector().v; + } break; + + case mtpc_messages_statedMessageLink: { + d = &result.c_messages_statedMessageLink().vchats.c_vector().v; + } break; + } + App::wnd()->hideLayer(); + PeerId peerId = 0; + if (d && !d->isEmpty()) { + switch (d->first().type()) { + case mtpc_chat: peerId = App::peerFromChat(d->first().c_chat().vid); break; + case mtpc_chatForbidden: peerId = App::peerFromChat(d->first().c_chatForbidden().vid); break; + case mtpc_chatEmpty: peerId = App::peerFromChat(d->first().c_chatEmpty().vid); break; + } + } + if (peerId) { + App::main()->showPeer(peerId); + } +} + +bool CreateGroupBox::failed(const RPCError &e) { + _createRequestId = 0; + if (e.type() == "NO_CHAT_TITLE") { + _name.setFocus(); + return true; + } else if (e.type() == "USERS_TOO_FEW") { + emit closed(); + return true; + } + return false; +} + +void CreateGroupBox::onCancel() { + emit closed(); +} + +void CreateGroupBox::startHide() { + _hiding = true; + if (_cache.isNull()) { + _cache = grab(rect()); + hideAll(); + } + a_opacity.start(0); +} + +CreateGroupBox::~CreateGroupBox() { +} diff --git a/Telegram/SourceFiles/boxes/newgroupbox.h b/Telegram/SourceFiles/boxes/newgroupbox.h new file mode 100644 index 000000000..5ae9e96b6 --- /dev/null +++ b/Telegram/SourceFiles/boxes/newgroupbox.h @@ -0,0 +1,166 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "layerwidget.h" + +class NewGroupInner : public QWidget { + Q_OBJECT + +public: + + NewGroupInner(); + + void paintEvent(QPaintEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + + void paintDialog(QPainter &p, DialogRow *row, bool sel); + void updateFilter(QString filter = QString()); + + void selectSkip(int32 dir); + void selectSkipPage(int32 h, int32 dir); + + QVector selectedInputs(); + + void loadProfilePhotos(int32 yFrom); + + void changeCheckState(DialogRow *row); + + ~NewGroupInner(); + +signals: + + void mustScrollTo(int ymin, int ymax); + +public slots: + + void onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow); + + void updateSel(); + void peerUpdated(PeerData *peer); + + void chooseParticipant(); + +private: + + int32 _time; + + DialogsIndexed *_contacts; + DialogRow *_sel; + QString _filter; + typedef QVector FilteredDialogs; + FilteredDialogs _filtered; + int32 _filteredSel; + bool _mouseSel; + + typedef struct { + Text name; + QString online; + bool check; + } ContactData; + typedef QMap ContactsData; + ContactsData _contactsData; + int32 _selCount; + + ContactData *contactData(DialogRow *row); + + QPoint _lastMousePos; + +}; + +class NewGroupBox : public LayeredWidget, public RPCSender { + Q_OBJECT + +public: + + NewGroupBox(); + void parentResized(); + void animStep(float64 dt); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void startHide(); + ~NewGroupBox(); + +public slots: + + void onFilterUpdate(); + void onClose(); + void onNext(); + void onScroll(); + +private: + + void hideAll(); + void showAll(); + + ScrollArea _scroll; + NewGroupInner _inner; + int32 _width, _height; + FlatInput _filter; + FlatButton _next, _cancel; + bool _hiding; + + QPixmap _cache; + + anim::fvalue a_opacity; +}; + +class CreateGroupBox : public LayeredWidget, public RPCSender { + Q_OBJECT + +public: + + CreateGroupBox(const MTPVector &users); + void parentResized(); + void animStep(float64 dt); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void startHide(); + ~CreateGroupBox(); + +public slots: + + void onCreate(); + void onCancel(); + +private: + + void hideAll(); + void showAll(); + + void created(const MTPmessages_StatedMessage &result); + bool failed(const RPCError &e); + + MTPVector _users; + + int32 _createRequestId; + + int32 _width, _height; + FlatInput _name; + FlatButton _create, _cancel; + + bool _hiding; + + QPixmap _cache; + + anim::fvalue a_opacity; +}; diff --git a/Telegram/SourceFiles/boxes/photocropbox.cpp b/Telegram/SourceFiles/boxes/photocropbox.cpp new file mode 100644 index 000000000..2f0b173e2 --- /dev/null +++ b/Telegram/SourceFiles/boxes/photocropbox.cpp @@ -0,0 +1,309 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" +#include "lang.h" + +#include "app.h" +#include "application.h" +#include "mainwidget.h" +#include "photocropbox.h" +#include "fileuploader.h" + +PhotoCropBox::PhotoCropBox(const QImage &img, const PeerId &peer) : _img(img), _downState(0), _peerId(peer), + _sendButton(this, lang(lng_settings_save), st::btnSelectDone), + _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), + a_opacity(0, 1) { + + connect(&_sendButton, SIGNAL(clicked()), this, SLOT(onSend())); + connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCancel())); + if (_peerId) { + connect(this, SIGNAL(ready(const QImage &)), this, SLOT(onReady(const QImage &))); + } + + int32 s = st::cropBoxWidth - st::boxPadding.left() - st::boxPadding.right(); + _thumb = QPixmap::fromImage(img.scaled(s, s, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + _thumbw = _thumb.width(); + _thumbh = _thumb.height(); + if (_thumbw > _thumbh) { + _cropw = _thumbh - 20; + } else { + _cropw = _thumbw - 20; + } + _cropx = (_thumbw - _cropw) / 2; + _cropy = (_thumbh - _cropw) / 2; + _width = st::cropBoxWidth; + _height = _thumbh + st::boxPadding.top() + st::boxFont->height + st::boxPadding.top() + st::boxPadding.bottom() + _sendButton.height(); + _thumbx = (_width - _thumbw) / 2; + _thumby = st::boxPadding.top() * 2 + st::boxFont->height; + setMouseTracking(true); + + resize(_width, _height); +} + +void PhotoCropBox::mousePressEvent(QMouseEvent *e) { + if (e->button() != Qt::LeftButton) return; + + _downState = mouseState(e->pos()); + _fromposx = e->pos().x(); + _fromposy = e->pos().y(); + _fromcropx = _cropx; + _fromcropy = _cropy; + _fromcropw = _cropw; +} + +int32 PhotoCropBox::mouseState(QPoint p) { + p -= QPoint(_thumbx, _thumby); + int32 delta = st::cropPointSize, mdelta(-delta / 2); + if (QRect(_cropx + mdelta, _cropy + mdelta, delta, delta).contains(p)) { + return 1; + } else if (QRect(_cropx + _cropw + mdelta, _cropy + mdelta, delta, delta).contains(p)) { + return 2; + } else if (QRect(_cropx + _cropw + mdelta, _cropy + _cropw + mdelta, delta, delta).contains(p)) { + return 3; + } else if (QRect(_cropx + mdelta, _cropy + _cropw + mdelta, delta, delta).contains(p)) { + return 4; + } else if (QRect(_cropx, _cropy, _cropw, _cropw).contains(p)) { + return 5; + } + return 0; +} + +void PhotoCropBox::mouseReleaseEvent(QMouseEvent *e) { + if (_downState) { + _downState = 0; + mouseMoveEvent(e); + } +} + +void PhotoCropBox::mouseMoveEvent(QMouseEvent *e) { + if (_downState && !(e->buttons() & Qt::LeftButton)) { + mouseReleaseEvent(e); + } + if (_downState) { + if (_downState == 1) { + int32 dx = e->pos().x() - _fromposx, dy = e->pos().y() - _fromposy, d = (dx < dy) ? dx : dy; + if (_fromcropx + d < 0) { + d = -_fromcropx; + } + if (_fromcropy + d < 0) { + d = -_fromcropy; + } + if (_fromcropw - d < st::cropMinSize) { + d = _fromcropw - st::cropMinSize; + } + if (_cropx != _fromcropx + d || _cropy != _fromcropy + d || _cropw != _fromcropw - d) { + _cropx = _fromcropx + d; + _cropy = _fromcropy + d; + _cropw = _fromcropw - d; + update(); + } + } else if (_downState == 2) { + int32 dx = _fromposx - e->pos().x(), dy = e->pos().y() - _fromposy, d = (dx < dy) ? dx : dy; + if (_fromcropx + _fromcropw - d > _thumbw) { + d = _fromcropx + _fromcropw - _thumbw; + } + if (_fromcropy + d < 0) { + d = -_fromcropy; + } + if (_fromcropw - d < st::cropMinSize) { + d = _fromcropw - st::cropMinSize; + } + if (_cropy != _fromcropy + d || _cropw != _fromcropw - d) { + _cropy = _fromcropy + d; + _cropw = _fromcropw - d; + update(); + } + } else if (_downState == 3) { + int32 dx = _fromposx - e->pos().x(), dy = _fromposy - e->pos().y(), d = (dx < dy) ? dx : dy; + if (_fromcropx + _fromcropw - d > _thumbw) { + d = _fromcropx + _fromcropw - _thumbw; + } + if (_fromcropy + _fromcropw - d > _thumbh) { + d = _fromcropy + _fromcropw - _thumbh; + } + if (_fromcropw - d < st::cropMinSize) { + d = _fromcropw - st::cropMinSize; + } + if (_cropw != _fromcropw - d) { + _cropw = _fromcropw - d; + update(); + } + } else if (_downState == 4) { + int32 dx = e->pos().x() - _fromposx, dy = _fromposy - e->pos().y(), d = (dx < dy) ? dx : dy; + if (_fromcropx + d < 0) { + d = -_fromcropx; + } + if (_fromcropy + _fromcropw - d > _thumbh) { + d = _fromcropy + _fromcropw - _thumbh; + } + if (_fromcropw - d < st::cropMinSize) { + d = _fromcropw - st::cropMinSize; + } + if (_cropx != _fromcropx + d || _cropw != _fromcropw - d) { + _cropx = _fromcropx + d; + _cropw = _fromcropw - d; + update(); + } + } else if (_downState == 5) { + int32 dx = e->pos().x() - _fromposx, dy = e->pos().y() - _fromposy; + if (_fromcropx + dx < 0) { + dx = -_fromcropx; + } else if (_fromcropx + _fromcropw + dx > _thumbw) { + dx = _thumbw - _fromcropx - _fromcropw; + } + if (_fromcropy + dy < 0) { + dy = -_fromcropy; + } else if (_fromcropy + _fromcropw + dy > _thumbh) { + dy = _thumbh - _fromcropy - _fromcropw; + } + if (_cropx != _fromcropx + dx || _cropy != _fromcropy + dy) { + _cropx = _fromcropx + dx; + _cropy = _fromcropy + dy; + update(); + } + } + } + int32 cursorState = _downState ? _downState : mouseState(e->pos()); + QCursor cur(style::cur_default); + if (cursorState == 1 || cursorState == 3) { + cur = style::cur_sizefdiag; + } else if (cursorState == 2 || cursorState == 4) { + cur = style::cur_sizebdiag; + } else if (cursorState == 5) { + cur = style::cur_sizeall; + } + setCursor(cur); +} + +void PhotoCropBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + onSend(); + } else if (e->key() == Qt::Key_Escape) { + onCancel(); + } +} + +void PhotoCropBox::parentResized() { + QSize s = parentWidget()->size(); + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + _sendButton.move(_width - _sendButton.width(), _height - _sendButton.height()); + _cancelButton.move(0, _height - _cancelButton.height()); + update(); +} + +void PhotoCropBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + p.setOpacity(a_opacity.current()); + + // fill bg + p.fillRect(QRect(QPoint(0, 0), size()), st::boxBG->b); + + // paint shadows + p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b); + + // paint button sep + p.setPen(st::btnSelectSep->p); + p.drawLine(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::btnSelectCancel.width, _height - 1); + + p.setFont(st::boxFont->f); + p.setPen(st::boxGrayTitle->p); + p.drawText(QRect(st::boxPadding.left(), st::boxPadding.top(), _width - st::boxPadding.left() - st::boxPadding.right(), st::boxFont->height), lang(lng_settings_crop_profile), style::al_center); + + p.translate(_thumbx, _thumby); + p.drawPixmap(0, 0, _thumb); + p.setOpacity(a_opacity.current() * 0.5); + if (_cropy > 0) { + p.fillRect(QRect(0, 0, _cropx + _cropw, _cropy), st::black->b); + } + if (_cropx + _cropw < _thumbw) { + p.fillRect(QRect(_cropx + _cropw, 0, _thumbw - _cropx - _cropw, _cropy + _cropw), st::black->b); + } + if (_cropy + _cropw < _thumbh) { + p.fillRect(QRect(_cropx, _cropy + _cropw, _thumbw - _cropx, _thumbh - _cropy - _cropw), st::black->b); + } + if (_cropx > 0) { + p.fillRect(QRect(0, _cropy, _cropx, _thumbh - _cropy), st::black->b); + } + + int32 delta = st::cropPointSize, mdelta(-delta / 2); + p.fillRect(QRect(_cropx + mdelta, _cropy + mdelta, delta, delta), st::white->b); + p.fillRect(QRect(_cropx + _cropw + mdelta, _cropy + mdelta, delta, delta), st::white->b); + p.fillRect(QRect(_cropx + _cropw + mdelta, _cropy + _cropw + mdelta, delta, delta), st::white->b); + p.fillRect(QRect(_cropx + mdelta, _cropy + _cropw + mdelta, delta, delta), st::white->b); +} + +void PhotoCropBox::animStep(float64 ms) { + if (ms >= 1) { + a_opacity.finish(); + } else { + a_opacity.update(ms, anim::linear); + } + _sendButton.setOpacity(a_opacity.current()); + _cancelButton.setOpacity(a_opacity.current()); + update(); +} + +void PhotoCropBox::onSend() { + QImage from(_img); + if (_img.width() < _thumb.width()) { + from = _thumb.toImage(); + } + float64 x = float64(_cropx) / _thumbw, y = float64(_cropy) / _thumbh, w = float64(_cropw) / _thumbw; + int32 ix = int32(x * from.width()), iy = int32(y * from.height()), iw = int32(w * from.width()); + if (ix < 0) { + ix = 0; + } + if (ix + iw > from.width()) { + iw = from.width() - ix; + } + if (iy < 0) { + iy = 0; + } + if (iy + iw > from.height()) { + iw = from.height() - iy; + } + int32 offset = ix * from.depth() / 8 + iy * from.bytesPerLine(); + QImage cropped(from.bits() + offset, iw, iw, from.bytesPerLine(), from.format()), tosend; + if (cropped.width() > 1280) { + tosend = cropped.scaled(1280, 1280, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } else if (cropped.width() < 320) { + tosend = cropped.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } else { + tosend = cropped.copy(); + } + + emit ready(tosend); +} + +void PhotoCropBox::onReady(const QImage &tosend) { + App::app()->uploadProfilePhoto(tosend, _peerId); + emit closed(); +} + +void PhotoCropBox::onCancel() { + emit closed(); +} + +void PhotoCropBox::startHide() { + _hiding = true; + a_opacity.start(0); +} + +PhotoCropBox::~PhotoCropBox() { +} diff --git a/Telegram/SourceFiles/boxes/photocropbox.h b/Telegram/SourceFiles/boxes/photocropbox.h new file mode 100644 index 000000000..164a9a7cb --- /dev/null +++ b/Telegram/SourceFiles/boxes/photocropbox.h @@ -0,0 +1,64 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "layerwidget.h" + +class PhotoCropBox : public LayeredWidget { + Q_OBJECT + +public: + + PhotoCropBox(const QImage &img, const PeerId &peer); + void parentResized(); + void animStep(float64 ms); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void startHide(); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + int32 mouseState(QPoint p); + ~PhotoCropBox(); + +public slots: + + void onSend(); + void onCancel(); + void onReady(const QImage &tosend); + +signals: + + void ready(const QImage &tosend); + +private: + + int32 _downState; + int32 _width, _height, _thumbx, _thumby, _thumbw, _thumbh; + int32 _cropx, _cropy, _cropw; + int32 _fromposx, _fromposy, _fromcropx, _fromcropy, _fromcropw; + FlatButton _sendButton, _cancelButton; + QImage _img; + QPixmap _thumb; + PeerId _peerId; + + anim::fvalue a_opacity; + + bool _hiding; + +}; diff --git a/Telegram/SourceFiles/boxes/photosendbox.cpp b/Telegram/SourceFiles/boxes/photosendbox.cpp new file mode 100644 index 000000000..c31670d89 --- /dev/null +++ b/Telegram/SourceFiles/boxes/photosendbox.cpp @@ -0,0 +1,131 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" +#include "lang.h" + +#include "app.h" +#include "mainwidget.h" +#include "photosendbox.h" + +PhotoSendBox::PhotoSendBox(const ReadyLocalMedia &img) : _img(img), + _sendButton(this, lang(lng_send_button), st::btnSelectDone), + _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), + a_opacity(0, 1) { + + connect(&_sendButton, SIGNAL(clicked()), this, SLOT(onSend())); + connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCancel())); + + int32 maxW = 0, maxH = 0; + for (PreparedPhotoThumbs::const_iterator i = img.photoThumbs.cbegin(), e = img.photoThumbs.cend(); i != e; ++i) { + if (i->width() >= maxW && i->height() >= maxH) { + _thumb = *i; + maxW = _thumb.width(); + maxH = _thumb.height(); + } + } + int32 tw = _thumb.width(), th = _thumb.height(); + if (!tw || !th) { + tw = th = 1; + } + _width = st::confirmWidth; + _thumbw = _width - st::boxPadding.left() - st::boxPadding.right(); + if (_thumb.width() < _thumbw) { + _thumbw = (_thumb.width() > 20) ? _thumb.width() : 20; + } + int32 maxthumbh = qRound(1.5 * _thumbw); + _thumbh = qRound(th * float64(_thumbw) / tw); + if (_thumbh > maxthumbh) { + _thumbw = qRound(_thumbw * float64(maxthumbh) / _thumbh); + _thumbh = maxthumbh; + if (_thumbw < 10) { + _thumbw = 10; + } + } + _height = _thumbh + st::boxPadding.top() + st::boxFont->height + st::boxPadding.bottom() + st::boxPadding.bottom() + _sendButton.height(); + + _thumb = QPixmap::fromImage(_thumb.toImage().scaled(_thumbw, _thumbh, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + + resize(_width, _height); +} + +void PhotoSendBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + onSend(); + } else if (e->key() == Qt::Key_Escape) { + onCancel(); + } +} + +void PhotoSendBox::parentResized() { + QSize s = parentWidget()->size(); + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + _sendButton.move(_width - _sendButton.width(), _height - _sendButton.height()); + _cancelButton.move(0, _height - _cancelButton.height()); + update(); +} + +void PhotoSendBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + p.setOpacity(a_opacity.current()); + + // fill bg + p.fillRect(QRect(QPoint(0, 0), size()), st::boxBG->b); + + // paint shadows + p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b); + + // paint button sep + p.setPen(st::btnSelectSep->p); + p.drawLine(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::btnSelectCancel.width, _height - 1); + + p.setFont(st::boxFont->f); + p.setPen(st::boxGrayTitle->p); + p.drawText(QRect(st::boxPadding.left(), st::boxPadding.top(), _width - st::boxPadding.left() - st::boxPadding.right(), st::boxFont->height), lang(lng_really_send_image), style::al_center); + p.drawPixmap((_width - _thumbw) / 2, st::boxPadding.top() * 2 + st::boxFont->height, _thumb); +} + +void PhotoSendBox::animStep(float64 ms) { + if (ms >= 1) { + a_opacity.finish(); + } else { + a_opacity.update(ms, anim::linear); + } + _sendButton.setOpacity(a_opacity.current()); + _cancelButton.setOpacity(a_opacity.current()); + update(); +} + +void PhotoSendBox::onSend() { + if (App::main()) App::main()->confirmSendImage(_img); + emit closed(); +} + +void PhotoSendBox::onCancel() { + if (App::main()) App::main()->cancelSendImage(); + emit closed(); +} + +void PhotoSendBox::startHide() { + _hiding = true; + a_opacity.start(0); +} + +PhotoSendBox::~PhotoSendBox() { + if (App::main()) App::main()->cancelSendImage(); +} diff --git a/Telegram/SourceFiles/boxes/photosendbox.h b/Telegram/SourceFiles/boxes/photosendbox.h new file mode 100644 index 000000000..a3caadea5 --- /dev/null +++ b/Telegram/SourceFiles/boxes/photosendbox.h @@ -0,0 +1,52 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "layerwidget.h" +#include "localimageloader.h" + +class PhotoSendBox : public LayeredWidget { + Q_OBJECT + +public: + + PhotoSendBox(const ReadyLocalMedia &img); + void parentResized(); + void animStep(float64 ms); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void startHide(); + ~PhotoSendBox(); + +public slots: + + void onSend(); + void onCancel(); + +private: + + ReadyLocalMedia _img; + int32 _width, _height, _thumbw, _thumbh; + FlatButton _sendButton, _cancelButton; + QPixmap _thumb; + + anim::fvalue a_opacity; + + bool _hiding; + +}; diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h new file mode 100644 index 000000000..514d2a60f --- /dev/null +++ b/Telegram/SourceFiles/config.h @@ -0,0 +1,203 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +static const int32 AppVersion = 4018; +static const wchar_t *AppVersionStr = L"0.4.18"; +static const wchar_t *AppName = L"Telegram Win (Unofficial)"; +static const wchar_t *AppId = L"{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"; + +#include "settings.h" + +enum { + MTPShortBufferSize = 65535, // of ints, 256 kb + MTPPacketSizeMax = 67108864, // 64 mb + MTPIdsBufferSize = 400, // received msgIds and wereAcked msgIds count stored + MTPCheckResendTimeout = 5000, // how much time passed from send till we resend request or check it's state, in ms + MTPCheckResendWaiting = 1000, // how much time to wait for some more requests, when resending request or checking it's state, in ms + MTPResendThreshold = 1, // how much ints should message contain for us not to resend, but to check it's state + MTPContainerLives = 600, // container lives 10 minutes in haveSent map + MTPMaxReceiveDelay = 64000, // 64 seconds + MTPConnectionOldTimeout = 192000, // 192 seconds + MTPTcpConnectionWaitTimeout = 3000, // 3 seconds waiting for tcp, until we accept http + MTPMillerRabinIterCount = 30, // 30 Miller-Rabin iterations for dh_prime primality check + + MinReceiveDelay = 1000, // 1 seconds + MaxSelectedItems = 100, + + MaxPhoneTailLength = 18, // rest of the phone number, without country code (seen 12 at least) + + MaxScrollSpeed = 37, // 37px per 15ms while select-by-drag + FingerAccuracyThreshold = 3, // touch flick ignore 3px + MaxScrollAccelerated = 4000, // 4000px per second + MaxScrollFlick = 2500, // 2500px per second + + LocalEncryptIterCount = 4000, // key derivation iteration count + LocalEncryptNoPwdIterCount = 4, // key derivation iteration count without pwd (not secure anyway) + LocalEncryptSaltSize = 32, // 256 bit + LocalEncryptKeySize = 256, // 2048 bit + + SaveRecentEmojisTimeout = 3000, // 3 secs +}; + +#ifdef Q_OS_WIN +inline const GUID &cGUID() { + static const GUID gGuid = { 0x87a94ab0, 0xe370, 0x4cde, { 0x98, 0xd3, 0xac, 0xc1, 0x10, 0xc5, 0x96, 0x7d } }; + + return gGuid; +} +#endif + +inline const char *cGUIDStr() { + static const char *gGuidStr = "{87A94AB0-E370-4cde-98D3-ACC110C5967D}"; + + return gGuidStr; +} + +inline const char **cPublicRSAKeys(uint32 &cnt) { + static const char *(keys[]) = {"\ +-----BEGIN RSA PUBLIC KEY-----\n\ +MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6\n\ +lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS\n\ +an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw\n\ +Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+\n\ +8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\n\ +Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n\ +-----END RSA PUBLIC KEY-----"}; + cnt = sizeof(keys) / sizeof(const char*); + return keys; +} + +inline const char *cFirstDCIp() { + return cTestMode() ? "173.240.5.253" : "173.240.5.1"; +} + +inline int32 cFirstDCPort() { + return 443; +} + +static const char *UpdatesPublicKey = "\ +-----BEGIN RSA PUBLIC KEY-----\n\ +MIGJAoGBAMA4ViQrjkPZ9xj0lrer3r23JvxOnrtE8nI69XLGSr+sRERz9YnUptnU\n\ +BZpkIfKaRcl6XzNJiN28cVwO1Ui5JSa814UAiDHzWUqCaXUiUEQ6NmNTneiGx2sQ\n\ ++9PKKlb8mmr3BB9A45ZNwLT6G9AK3+qkZLHojeSA+m84/a6GP4svAgMBAAE=\n\ +-----END RSA PUBLIC KEY-----\ +"; + +#ifdef CUSTOM_API_ID +#include "../../../TelegramPrivate/custom_api_id.h" // Custom API id and API hash +#else +static const int32 ApiId = 17349; +static const char *ApiHash = "344583e45741c457fe1862106095a5eb"; +#endif + +inline const char *cApiDeviceModel() { + return "x86 desktop"; +} +inline const char *cApiSystemVersion() { + return "windows"; +} +inline QString cApiAppVersion() { + return QString::number(AppVersion); +} +static const char *ApiLang = "en"; + +extern QString gKeyFile; +inline const QString &cDataFile() { + if (!gKeyFile.isEmpty()) return gKeyFile; + static const QString res(cTestMode() ? qsl("data_test") : qsl("data")); + return res; +} + +inline const QString &cTempDir() { + static const QString res = cWorkingDir() + qsl("tdata/tdld/"); + return res; +} + +static const char *DefaultCountry = "US"; +static const char *DefaultLanguage = "en"; + +enum { + DialogsFirstLoad = 20, // first dialogs part size requested + DialogsPerPage = 40, // next dialogs part size + + MessagesFirstLoad = 30, // first history part size requested + MessagesPerPage = 50, // next history part size + + LinkCropLimit = 360, // 360px link length max + + DownloadPartSize = 32 * 1024, // 32kb for photo + DocumentDownloadPartSize = 128 * 1024, // 128kb for document + MaxUploadPhotoSize = 10 * 1024 * 1024, // 10mb photos max + MaxUploadDocumentSize = 1500 * 1024 * 1024, // 1500mb documents max + UseBigFilesFrom = 10 * 1024 * 1024, // mtp big files methods used for files greater than 10mb + MaxFileQueries = 32, // max 32 file parts downloaded at the same time + + UploadPartSize = 32 * 1024, // 32kb for photo + DocumentMaxPartsCount = 3000, // no more than 3000 parts + DocumentUploadPartSize0 = 32 * 1024, // 32kb for tiny document ( < 1mb ) + DocumentUploadPartSize1 = 64 * 1024, // 64kb for little document ( <= 32mb ) + DocumentUploadPartSize2 = 128 * 1024, // 128kb for small document ( <= 375mb ) + DocumentUploadPartSize3 = 256 * 1024, // 256kb for medium document ( <= 750mb ) + DocumentUploadPartSize4 = 512 * 1024, // 512kb for large document ( <= 1500mb ) + MaxUploadFileParallelSize = 512 * 1024, // max 512kb uploaded at the same time + UploadRequestInterval = 500, // one part each half second, if not uploaded faster + + MaxPhotosInMemory = 50, // try to clear some memory after 50 photos are created + NoUpdatesTimeout = 180 * 1000, // if nothing is received in 3 min we reconnect + + MemoryForImageCache = 64 * 1024 * 1024, // after 64mb of unpacked images we try to clear some memory + NotifyWindows = 3, // 3 desktop notifies at the same time + NotifyWaitTimeout = 1200, // 1.2 seconds timeout before notification + NotifySettingSaveTimeout = 1000, // wait 1 second before saving notify setting to server + UpdateChunk = 100 * 1024, // 100kb parts when downloading the update + IdleMsecs = 60 * 1000, // after 60secs without user input we think we are idle + + ForwardOnAdd = 120, // how many messages from chat history server should forward to user, that was added to this chat +}; + +inline const QRegularExpression &cWordSplit() { + static QRegularExpression regexp(qsl("[\\s\\-\\+\\)\\(\\,\\.\\:\\!\\_\\;\\\"\\'\\x0]")); + return regexp; +} + +inline const QRegularExpression &cRussianLetters() { + static QRegularExpression regexp(QString::fromUtf8("[а-ÑÐ-ЯёÐ]")); + return regexp; +} + +inline QStringList cImgExtensions() { + static QStringList imgExtensions; + if (imgExtensions.isEmpty()) { + imgExtensions.reserve(4); + imgExtensions.push_back(qsl(".jpg")); + imgExtensions.push_back(qsl(".jpeg")); + imgExtensions.push_back(qsl(".png")); + imgExtensions.push_back(qsl(".gif")); + } + return imgExtensions; +} + +inline QStringList cPhotoExtensions() { + static QStringList photoExtensions; + if (photoExtensions.isEmpty()) { + photoExtensions.push_back(qsl(".jpg")); + photoExtensions.push_back(qsl(".jpeg")); + } + return photoExtensions; +} diff --git a/Telegram/SourceFiles/countries.h b/Telegram/SourceFiles/countries.h new file mode 100644 index 000000000..0a9b10a6d --- /dev/null +++ b/Telegram/SourceFiles/countries.h @@ -0,0 +1,250 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +static const CountryInfo countries[] = { + CountryInfo("Afghanistan", "AF", "93"), + CountryInfo("Albania", "AL", "355"), + CountryInfo("Algeria", "DZ", "213"), + CountryInfo("American Samoa", "AS", "1684"), + CountryInfo("Andorra", "AD", "376"), + CountryInfo("Angola", "AO", "244"), + CountryInfo("Anguilla", "AI", "1264"), + CountryInfo("Antigua & Barbuda", "AG", "1268"), + CountryInfo("Argentina", "AR", "54"), + CountryInfo("Armenia", "AM", "374"), + CountryInfo("Aruba", "AW", "297"), + CountryInfo("Australia", "AU", "61"), + CountryInfo("Austria", "AT", "43"), + CountryInfo("Azerbaijan", "AZ", "994"), + CountryInfo("Bahamas", "BS", "1242"), + CountryInfo("Bahrain", "BH", "973"), + CountryInfo("Bangladesh", "BD", "880"), + CountryInfo("Barbados", "BB", "1246"), + CountryInfo("Belarus", "BY", "375"), + CountryInfo("Belgium", "BE", "32"), + CountryInfo("Belize", "BZ", "501"), + CountryInfo("Benin", "BJ", "229"), + CountryInfo("Bermuda", "BM", "1441"), + CountryInfo("Bhutan", "BT", "975"), + CountryInfo("Bolivia", "BO", "591"), + CountryInfo("Bonaire, Sint Eustatius & Saba", "BQ", "599"), + CountryInfo("Bosnia & Herzegovina", "BA", "387"), + CountryInfo("Botswana", "BW", "267"), + CountryInfo("Brazil", "BR", "55"), + CountryInfo("British Virgin Islands", "VG", "1284"), + CountryInfo("Brunei Darussalam", "BN", "673"), + CountryInfo("Bulgaria", "BG", "359"), + CountryInfo("Burkina Faso", "BF", "226"), + CountryInfo("Burundi", "BI", "257"), + CountryInfo("Cambodia", "KH", "855"), + CountryInfo("Cameroon", "CM", "237"), + CountryInfo("Canada", "CA", "1"), + CountryInfo("Cape Verde", "CV", "238"), + CountryInfo("Cayman Islands", "KY", "1345"), + CountryInfo("Central African Republic", "CF", "236"), + CountryInfo("Chad", "TD", "235"), + CountryInfo("Chile", "CL", "56"), + CountryInfo("China", "CN", "86"), + CountryInfo("Colombia", "CO", "57"), + CountryInfo("Comoros", "KM", "269"), + CountryInfo("Congo", "CG", "242"), + CountryInfo("Congo, Democratic Republic", "CD", "243"), + CountryInfo("Cook Islands", "CK", "682"), + CountryInfo("Costa Rica", "CR", "506"), + CountryInfo("Croatia", "HR", "385"), + CountryInfo("Cuba", "CU", "53"), + CountryInfo("Curaçao", "CW", "599"), + CountryInfo("Cyprus", "CY", "357"), + CountryInfo("Czech Republic", "CZ", "420"), + CountryInfo("Côte d`Ivoire", "CI", "225"), + CountryInfo("Denmark", "DK", "45"), + CountryInfo("Diego Garcia", "IO", "246"), + CountryInfo("Djibouti", "DJ", "253"), + CountryInfo("Dominica", "DM", "1767"), + CountryInfo("Dominican Republic", "DO", "1"), + CountryInfo("Ecuador", "EC", "593"), + CountryInfo("Egypt", "EG", "20"), + CountryInfo("El Salvador", "SV", "503"), + CountryInfo("Equatorial Guinea", "GQ", "240"), + CountryInfo("Eritrea", "ER", "291"), + CountryInfo("Estonia", "EE", "372"), + CountryInfo("Ethiopia", "ET", "251"), + CountryInfo("Falkland Islands", "FK", "500"), + CountryInfo("Faroe Islands", "FO", "298"), + CountryInfo("Fiji", "FJ", "679"), + CountryInfo("Finland", "FI", "358"), + CountryInfo("France", "FR", "33"), + CountryInfo("French Guiana", "GF", "594"), + CountryInfo("French Polynesia", "PF", "689"), + CountryInfo("Gabon", "GA", "241"), + CountryInfo("Gambia", "GM", "220"), + CountryInfo("Georgia", "GE", "995"), + CountryInfo("Germany", "DE", "49"), + CountryInfo("Ghana", "GH", "233"), + CountryInfo("Gibraltar", "GI", "350"), + CountryInfo("Greece", "GR", "30"), + CountryInfo("Greenland", "GL", "299"), + CountryInfo("Grenada", "GD", "1473"), + CountryInfo("Guadeloupe", "GP", "590"), + CountryInfo("Guam", "GU", "1671"), + CountryInfo("Guatemala", "GT", "502"), + CountryInfo("Guinea", "GN", "224"), + CountryInfo("Guinea-Bissau", "GW", "245"), + CountryInfo("Guyana", "GY", "592"), + CountryInfo("Haiti", "HT", "509"), + CountryInfo("Honduras", "HN", "504"), + CountryInfo("Hong Kong", "HK", "852"), + CountryInfo("Hungary", "HU", "36"), + CountryInfo("Iceland", "IS", "354"), + CountryInfo("India", "IN", "91"), + CountryInfo("Indonesia", "ID", "62"), + CountryInfo("Iran", "IR", "98"), + CountryInfo("Iraq", "IQ", "964"), + CountryInfo("Ireland", "IE", "353"), + CountryInfo("Israel", "IL", "972"), + CountryInfo("Italy", "IT", "39"), + CountryInfo("Jamaica", "JM", "1876"), + CountryInfo("Japan", "JP", "81"), + CountryInfo("Jordan", "JO", "962"), + CountryInfo("Kazakhstan", "KZ", "7"), + CountryInfo("Kenya", "KE", "254"), + CountryInfo("Kiribati", "KI", "686"), + CountryInfo("Kuwait", "KW", "965"), + CountryInfo("Kyrgyzstan", "KG", "996"), + CountryInfo("Laos", "LA", "856"), + CountryInfo("Latvia", "LV", "371"), + CountryInfo("Lebanon", "LB", "961"), + CountryInfo("Lesotho", "LS", "266"), + CountryInfo("Liberia", "LR", "231"), + CountryInfo("Libya", "LY", "218"), + CountryInfo("Liechtenstein", "LI", "423"), + CountryInfo("Lithuania", "LT", "370"), + CountryInfo("Luxembourg", "LU", "352"), + CountryInfo("Macau", "MO", "853"), + CountryInfo("Macedonia", "MK", "389"), + CountryInfo("Madagascar", "MG", "261"), + CountryInfo("Malawi", "MW", "265"), + CountryInfo("Malaysia", "MY", "60"), + CountryInfo("Maldives", "MV", "960"), + CountryInfo("Mali", "ML", "223"), + CountryInfo("Malta", "MT", "356"), + CountryInfo("Marshall Islands", "MH", "692"), + CountryInfo("Martinique", "MQ", "596"), + CountryInfo("Mauritania", "MR", "222"), + CountryInfo("Mauritius", "MU", "230"), + CountryInfo("Mexico", "MX", "52"), + CountryInfo("Micronesia", "FM", "691"), + CountryInfo("Moldova", "MD", "373"), + CountryInfo("Monaco", "MC", "377"), + CountryInfo("Mongolia", "MN", "976"), + CountryInfo("Montenegro", "ME", "382"), + CountryInfo("Montserrat", "MS", "1664"), + CountryInfo("Morocco", "MA", "212"), + CountryInfo("Mozambique", "MZ", "258"), + CountryInfo("Myanmar", "MM", "95"), + CountryInfo("Namibia", "NA", "264"), + CountryInfo("Nauru", "NR", "674"), + CountryInfo("Nepal", "NP", "977"), + CountryInfo("Netherlands", "NL", "31"), + CountryInfo("New Caledonia", "NC", "687"), + CountryInfo("New Zealand", "NZ", "64"), + CountryInfo("Nicaragua", "NI", "505"), + CountryInfo("Niger", "NE", "227"), + CountryInfo("Nigeria", "NG", "234"), + CountryInfo("Niue", "NU", "683"), + CountryInfo("Norfolk Island", "NF", "672"), + CountryInfo("North Korea", "KP", "850"), + CountryInfo("Northern Mariana Islands", "MP", "1670"), + CountryInfo("Norway", "NO", "47"), + CountryInfo("Oman", "OM", "968"), + CountryInfo("Pakistan", "PK", "92"), + CountryInfo("Palau", "PW", "680"), + CountryInfo("Palestine", "PS", "970"), + CountryInfo("Panama", "PA", "507"), + CountryInfo("Papua New Guinea", "PG", "675"), + CountryInfo("Paraguay", "PY", "595"), + CountryInfo("Peru", "PE", "51"), + CountryInfo("Philippines", "PH", "63"), + CountryInfo("Poland", "PL", "48"), + CountryInfo("Portugal", "PT", "351"), + CountryInfo("Puerto Rico", "PR", "1"), + CountryInfo("Qatar", "QA", "974"), + CountryInfo("Romania", "RO", "40"), + CountryInfo("Russian Federation", "RU", "7"), + CountryInfo("Rwanda", "RW", "250"), + CountryInfo("Réunion", "RE", "262"), + CountryInfo("Saint Helena", "SH", "247"), + CountryInfo("Saint Helena", "SH2", "290"), + CountryInfo("Saint Kitts & Nevis", "KN", "1869"), + CountryInfo("Saint Lucia", "LC", "1758"), + CountryInfo("Saint Pierre & Miquelon", "PM", "508"), + CountryInfo("Saint Vincent & the Grenadines", "VC", "1784"), + CountryInfo("Samoa", "WS", "685"), + CountryInfo("San Marino", "SM", "378"), + CountryInfo("Saudi Arabia", "SA", "966"), + CountryInfo("Senegal", "SN", "221"), + CountryInfo("Serbia", "RS", "381"), + CountryInfo("Seychelles", "SC", "248"), + CountryInfo("Sierra Leone", "SL", "232"), + CountryInfo("Singapore", "SG", "65"), + CountryInfo("Sint Maarten", "SX", "1721"), + CountryInfo("Slovakia", "SK", "421"), + CountryInfo("Slovenia", "SI", "386"), + CountryInfo("Solomon Islands", "SB", "677"), + CountryInfo("Somalia", "SO", "252"), + CountryInfo("South Africa", "ZA", "27"), + CountryInfo("South Korea", "KR", "82"), + CountryInfo("South Sudan", "SS", "211"), + CountryInfo("Spain", "ES", "34"), + CountryInfo("Sri Lanka", "LK", "94"), + CountryInfo("Sudan", "SD", "249"), + CountryInfo("Suriname", "SR", "597"), + CountryInfo("Swaziland", "SZ", "268"), + CountryInfo("Sweden", "SE", "46"), + CountryInfo("Switzerland", "CH", "41"), + CountryInfo("Syrian Arab Republic", "SY", "963"), + CountryInfo("São Tomé & Príncipe", "ST", "239"), + CountryInfo("Taiwan", "TW", "886"), + CountryInfo("Tajikistan", "TJ", "992"), + CountryInfo("Tanzania", "TZ", "255"), + CountryInfo("Thailand", "TH", "66"), + CountryInfo("Timor-Leste", "TL", "670"), + CountryInfo("Togo", "TG", "228"), + CountryInfo("Tokelau", "TK", "690"), + CountryInfo("Tonga", "TO", "676"), + CountryInfo("Trinidad & Tobago", "TT", "1868"), + CountryInfo("Tunisia", "TN", "216"), + CountryInfo("Turkey", "TR", "90"), + CountryInfo("Turkmenistan", "TM", "993"), + CountryInfo("Turks & Caicos Islands", "TC", "1649"), + CountryInfo("Tuvalu", "TV", "688"), + CountryInfo("US Virgin Islands", "VI", "1340"), + CountryInfo("USA", "US", "1"), + CountryInfo("Uganda", "UG", "256"), + CountryInfo("Ukraine", "UA", "380"), + CountryInfo("United Arab Emirates", "AE", "971"), + CountryInfo("United Kingdom", "GB", "44"), + CountryInfo("Uruguay", "UY", "598"), + CountryInfo("Uzbekistan", "UZ", "998"), + CountryInfo("Vanuatu", "VU", "678"), + CountryInfo("Venezuela", "VE", "58"), + CountryInfo("Vietnam", "VN", "84"), + CountryInfo("Wallis & Futuna", "WF", "681"), + CountryInfo("Yemen", "YE", "967"), + CountryInfo("Zambia", "ZM", "260"), + CountryInfo("Zimbabwe", "ZW", "263"), +}; diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp new file mode 100644 index 000000000..7652f1850 --- /dev/null +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -0,0 +1,1008 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" +#include "lang.h" + +#include "window.h" +#include "dialogswidget.h" +#include "mainwidget.h" +#include "boxes/addcontactbox.h" +#include "boxes/newgroupbox.h" + +DialogsListWidget::DialogsListWidget(QWidget *parent, MainWidget *main) : QWidget(parent), dialogs(false), contactsNoDialogs(true), contacts(true), contactSel(false), sel(0), filteredSel(-1), selByMouse(false) { + connect(main, SIGNAL(dialogToTop(const History::DialogLinks &)), this, SLOT(onDialogToTop(const History::DialogLinks &))); + connect(main, SIGNAL(peerNameChanged(PeerData *, const PeerData::Names &, const PeerData::NameFirstChars &)), this, SLOT(onPeerNameChanged(PeerData *, const PeerData::Names &, const PeerData::NameFirstChars &))); + connect(main, SIGNAL(peerPhotoChanged(PeerData *)), this, SLOT(onPeerPhotoChanged(PeerData *))); + connect(main, SIGNAL(dialogRowReplaced(DialogRow *, DialogRow *)), this, SLOT(onDialogRowReplaced(DialogRow *, DialogRow *))); +} + +void DialogsListWidget::paintEvent(QPaintEvent *e) { + QRect r(e->rect()); + bool trivial = (rect() == r); + + QPainter p(this); + if (!trivial) { + p.setClipRect(r); + } + + if (filter.isEmpty()) { + int32 otherStart = dialogs.list.count * st::dlgHeight; + PeerData *active = App::main()->activePeer(), *selected = sel ? sel->history->peer : 0; + if (otherStart) { + dialogs.list.paint(p, width(), r.top(), r.bottom(), active, selected); + } + if (contactsNoDialogs.list.count) { + contactsNoDialogs.list.paint(p, width(), r.top() - otherStart, r.bottom() - otherStart, active, selected); + } else if (!otherStart) { + // .. paint no dialogs found + } + } else { + if (filtered.isEmpty()) { + // .. paint no dialogs + } else { + int32 from = r.top() / int32(st::dlgHeight); + if (from < 0) from = 0; + if (from < filtered.size()) { + int32 to = (r.bottom() / int32(st::dlgHeight)) + 1, w = width(); + if (to > filtered.size()) to = filtered.size(); + + p.translate(0, from * st::dlgHeight); + for (; from < to; ++from) { + bool active = (filtered[from]->history->peer == App::main()->activePeer()); + bool selected = (from == filteredSel); + filtered[from]->paint(p, w, active, selected); + p.translate(0, st::dlgHeight); + } + } + } + } +} + +void DialogsListWidget::activate() { + if (filter.isEmpty() && !sel || !filter.isEmpty() && (filteredSel < 0 || filteredSel >= filtered.size())) { + selectSkip(1); + } +} + +void DialogsListWidget::mouseMoveEvent(QMouseEvent *e) { + lastMousePos = mapToGlobal(e->pos()); + selByMouse = true; + onUpdateSelected(true); +} + +void DialogsListWidget::onUpdateSelected(bool force) { + QPoint mouse(mapFromGlobal(lastMousePos)); + if (!force && !rect().contains(mouse) || !selByMouse) return; + + int w = width(), mouseY = mouse.y(); + if (filter.isEmpty()) { + DialogRow *newSel = dialogs.list.rowAtY(mouseY, st::dlgHeight); + int32 otherStart = dialogs.list.count * st::dlgHeight; + if (newSel) { + contactSel = false; + } else { + newSel = contactsNoDialogs.list.rowAtY(mouseY - otherStart, st::dlgHeight); + contactSel = true; + } + if (contactSel) { + mouse.setY(mouse.y() - otherStart); + } + if (newSel) { + mouse.setY(mouse.y() - newSel->pos * st::dlgHeight); + } + if (newSel != sel) { + sel = newSel; + setCursor(sel ? style::cur_pointer : style::cur_default); + parentWidget()->update(); + } + } else { + if (!filtered.isEmpty()) { + int32 newFilteredSel = mouseY / int32(st::dlgHeight); + if (newFilteredSel < 0 || newFilteredSel >= filtered.size()) { + newFilteredSel = -1; + } + if (newFilteredSel >= 0) { + mouse.setY(mouse.y() - newFilteredSel * st::dlgHeight); + } + if (newFilteredSel != filteredSel) { + filteredSel = newFilteredSel; + setCursor((filteredSel >= 0) ? style::cur_pointer : style::cur_default); + parentWidget()->update(); + } + } + } +} + +void DialogsListWidget::mousePressEvent(QMouseEvent *e) { + lastMousePos = mapToGlobal(e->pos()); + selByMouse = true; + onUpdateSelected(true); + if (e->button() == Qt::LeftButton) { + choosePeer(); + } +} + +void DialogsListWidget::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) { + if (!filter.isEmpty()) { + for (FilteredDialogs::iterator i = filtered.begin(), e = filtered.end(); i != e;) { + if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts! + if (newRow) { + *i = newRow; + ++i; + } else { + i = filtered.erase(i); + } + } else { + ++i; + } + } + } + if (sel == oldRow) { + sel = newRow; + } +} + +void DialogsListWidget::createDialogAtTop(History *history, int32 unreadCount) { + history->updateNameText(); + + History::DialogLinks links = dialogs.addToEnd(history); + int32 movedFrom = links[0]->pos * st::dlgHeight; + dialogs.bringToTop(links); + history->dialogs = links; + + contactsNoDialogs.del(history->peer, links[0]); + + emit dialogToTopFrom(movedFrom); + emit App::main()->dialogsUpdated(); + + refresh(); +} + +void DialogsListWidget::removePeer(PeerData *peer) { + if (sel && sel->history->peer == peer) { + sel = 0; + } + History *history = App::history(peer->id); + dialogs.del(peer); + history->dialogs = History::DialogLinks(); + if (contacts.list.rowByPeer.constFind(peer->id) != contacts.list.rowByPeer.cend()) { + if (contactsNoDialogs.list.rowByPeer.constFind(peer->id) == contactsNoDialogs.list.rowByPeer.cend()) { + contactsNoDialogs.addByName(App::history(peer->id)); + } + } +// contactsNoDialogs.del(peer); +// contacts.del(peer); +// App::deleteHistory(peer->id); + + emit App::main()->dialogsUpdated(); + + refresh(); +} + +void DialogsListWidget::removeContact(UserData *user) { + if (sel && sel->history->peer == user) { + sel = 0; + } + contactsNoDialogs.del(user); + contacts.del(user); + + emit App::main()->dialogsUpdated(); + + refresh(); +} + +void DialogsListWidget::dlgUpdated(DialogRow *row) { + if (filter.isEmpty()) { + update(0, row->pos * st::dlgHeight, width(), st::dlgHeight); + } else { + int32 cnt = 0; + for (FilteredDialogs::const_iterator i = filtered.cbegin(), e = filtered.cend(); i != e; ++i) { + if ((*i)->history == row->history) { + update(0, cnt * st::dlgHeight, width(), st::dlgHeight); + break; + } + ++cnt; + } + } +} + +void DialogsListWidget::dlgUpdated(History *history) { + if (filter.isEmpty()) { + DialogRow *row = 0; + DialogsList::RowByPeer::iterator i = dialogs.list.rowByPeer.find(history->peer->id); + if (i != dialogs.list.rowByPeer.cend()) { + update(0, i.value()->pos * st::dlgHeight, width(), st::dlgHeight); + } else { + i = contactsNoDialogs.list.rowByPeer.find(history->peer->id); + if (i != contactsNoDialogs.list.rowByPeer.cend()) { + update(0, (dialogs.list.count + i.value()->pos) * st::dlgHeight, width(), st::dlgHeight); + } + } + } else { + int32 cnt = 0; + for (FilteredDialogs::const_iterator i = filtered.cbegin(), e = filtered.cend(); i != e; ++i) { + if ((*i)->history == history) { + update(0, cnt * st::dlgHeight, width(), st::dlgHeight); + break; + } + ++cnt; + } + } +} + +void DialogsListWidget::enterEvent(QEvent *e) { + setMouseTracking(true); + lastMousePos = QCursor::pos(); + onUpdateSelected(true); +} + +void DialogsListWidget::leaveEvent(QEvent *e) { + setMouseTracking(false); + if (sel || filteredSel >= 0) { + sel = 0; + filteredSel = -1; + parentWidget()->update(); + } +} + +void DialogsListWidget::onParentGeometryChanged() { + lastMousePos = QCursor::pos(); + if (rect().contains(mapFromGlobal(lastMousePos))) { + setMouseTracking(true); + onUpdateSelected(true); + } +} + +void DialogsListWidget::onDialogToTop(const History::DialogLinks &links) { + int32 movedFrom = links[0]->pos * st::dlgHeight; + dialogs.bringToTop(links); + emit dialogToTopFrom(movedFrom); + emit App::main()->dialogsUpdated(); + parentWidget()->update(); +} + +void DialogsListWidget::onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) { + dialogs.peerNameChanged(peer, oldNames, oldChars); + contactsNoDialogs.peerNameChanged(peer, oldNames, oldChars); + contacts.peerNameChanged(peer, oldNames, oldChars); + parentWidget()->update(); +} + +void DialogsListWidget::onPeerPhotoChanged(PeerData *peer) { + parentWidget()->update(); +} + +void DialogsListWidget::onFilterUpdate(QString newFilter) { + newFilter = textAccentFold(newFilter.trimmed().toLower()); + if (newFilter != filter) { + QStringList f; + if (!newFilter.isEmpty()) { + QStringList filterList = newFilter.split(cWordSplit(), QString::SkipEmptyParts); + int l = filterList.size(); + + f.reserve(l); + for (int i = 0; i < l; ++i) { + QString filterName = filterList[i].trimmed(); + if (filterName.isEmpty()) continue; + f.push_back(filterName); + } + newFilter = f.join(' '); + } + if (newFilter != filter) { + filter = newFilter; + if (!filter.isEmpty()) { + QStringList::const_iterator fb = f.cbegin(), fe = f.cend(), fi; + + filtered.clear(); + if (!f.isEmpty()) { + DialogsList *dialogsToFilter = 0, *contactsNoDialogsToFilter = 0; + if (dialogs.list.count) { + for (fi = fb; fi != fe; ++fi) { + DialogsIndexed::DialogsIndex::iterator i = dialogs.index.find(fi->at(0)); + if (i == dialogs.index.cend()) { + dialogsToFilter = 0; + break; + } + if (!dialogsToFilter || dialogsToFilter->count > i.value()->count) { + dialogsToFilter = i.value(); + } + } + } + if (contactsNoDialogs.list.count) { + for (fi = fb; fi != fe; ++fi) { + DialogsIndexed::DialogsIndex::iterator i = contactsNoDialogs.index.find(fi->at(0)); + if (i == contactsNoDialogs.index.cend()) { + contactsNoDialogsToFilter = 0; + break; + } + if (!contactsNoDialogsToFilter || contactsNoDialogsToFilter->count > i.value()->count) { + contactsNoDialogsToFilter = i.value(); + } + } + } + filtered.reserve((dialogsToFilter ? dialogsToFilter->count : 0) + (contactsNoDialogsToFilter ? contactsNoDialogsToFilter->count : 0)); + if (dialogsToFilter && dialogsToFilter->count) { + for (DialogRow *i = dialogsToFilter->begin, *e = dialogsToFilter->end; i != e; i = i->next) { + const PeerData::Names &names(i->history->peer->names); + PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni; + for (fi = fb; fi != fe; ++fi) { + QString filterName(*fi); + for (ni = nb; ni != ne; ++ni) { + if ((*ni).indexOf(*fi) == 0) { + break; + } + } + if (ni == ne) { + break; + } + } + if (fi == fe) { + filtered.push_back(i); + } + } + } + if (contactsNoDialogsToFilter && contactsNoDialogsToFilter->count) { + for (DialogRow *i = contactsNoDialogsToFilter->begin, *e = contactsNoDialogsToFilter->end; i != e; i = i->next) { + const PeerData::Names &names(i->history->peer->names); + PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni; + for (fi = fb; fi != fe; ++fi) { + QString filterName(*fi); + for (ni = nb; ni != ne; ++ni) { + if ((*ni).indexOf(*fi) == 0) { + break; + } + } + if (ni == ne) { + break; + } + } + if (fi == fe) { + filtered.push_back(i); + } + } + } + } + } + } + refresh(true); + setMouseSel(false, true); + } +} + +void DialogsListWidget::dialogsReceived(const QVector &added) { + for (QVector::const_iterator i = added.cbegin(), e = added.cend(); i != e; ++i) { + if (i->type() == mtpc_dialog) { + addDialog(i->c_dialog()); + } + } + if (App::wnd()) App::wnd()->psUpdateCounter(); + if (!sel && dialogs.list.count) { + sel = dialogs.list.begin; + contactSel = false; + } + refresh(); +} + +void DialogsListWidget::contactsReceived(const QVector &contacts) { + for (QVector::const_iterator i = contacts.cbegin(), e = contacts.cend(); i != e; ++i) { + addNewContact(i->c_contact().vuser_id.v); + } + if (!sel && contactsNoDialogs.list.count) { + sel = contactsNoDialogs.list.begin; + contactSel = true; + } + refresh(); +} + +int32 DialogsListWidget::addNewContact(int32 uid, bool select) { + PeerId peer = App::peerFromUser(uid); + if (!App::peerLoaded(peer)) return -1; + + History *history = App::history(peer); + contacts.addByName(history); + DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(peer); + if (i == dialogs.list.rowByPeer.cend()) { + DialogRow *added = contactsNoDialogs.addByName(history); + if (!added) return -1; + if (select) { + sel = added; + contactSel = true; + } + return added ? ((dialogs.list.count + added->pos) * st::dlgHeight) : -1; + } + if (select) { + sel = i.value(); + contactSel = false; + } + return i.value()->pos * st::dlgHeight; +} + +void DialogsListWidget::refresh(bool toTop) { + resize(width(), (filter.isEmpty() ? (dialogs.list.count + contactsNoDialogs.list.count) : filtered.count()) * st::dlgHeight); + if (toTop) { + emit mustScrollTo(0, 0); + loadPeerPhotos(0); + } + parentWidget()->update(); +} + +void DialogsListWidget::setMouseSel(bool msel, bool toTop) { + selByMouse = msel; + if (!selByMouse && toTop) { + if (filter.isEmpty()) { + sel = (dialogs.list.count ? dialogs.list.begin : (contactsNoDialogs.list.count ? contactsNoDialogs.list.begin : 0)); + contactSel = !dialogs.list.count && contactsNoDialogs.list.count; + } else { + filteredSel = 0; + } + } +} + +void DialogsListWidget::clearFilter() { + if (!filter.isEmpty()) { + filter = QString(); + refresh(true); + } +} + +void DialogsListWidget::addDialog(const MTPDdialog &dialog) { + History *history = App::history(App::peerFromMTP(dialog.vpeer), dialog.vunread_count.v); + History::DialogLinks links = dialogs.addToEnd(history); + history->dialogs = links; + contactsNoDialogs.del(history->peer); + + App::main()->applyNotifySetting(MTP_notifyPeer(dialog.vpeer), dialog.vnotify_settings, history); +} + +void DialogsListWidget::selectSkip(int32 direction) { + if (filter.isEmpty()) { + if (!sel) { + if (dialogs.list.count && direction > 0) { + sel = dialogs.list.begin; + } else if (contactsNoDialogs.list.count && direction > 0) { + sel = contactsNoDialogs.list.begin; + } else { + return; + } + } else if (direction > 0) { + if (sel->next->next) { + sel = sel->next; + } else if (sel->next == dialogs.list.end && contactsNoDialogs.list.count) { + sel = contactsNoDialogs.list.begin; + contactSel = true; + } + } else { + if (sel->prev) { + sel = sel->prev; + } else if (sel == contactsNoDialogs.list.begin && dialogs.list.count) { + sel = dialogs.list.end->prev; + contactSel = false; + } + } + int32 fromY = (sel->pos + (contactSel ? dialogs.list.count : 0)) * st::dlgHeight; + emit mustScrollTo(fromY, fromY + st::dlgHeight); + } else { + if (filtered.isEmpty()) return; + int32 newSel = snap(filteredSel + direction, 0, filtered.size() - 1); + if (newSel != filteredSel) { + filteredSel = newSel; + } + emit mustScrollTo(filteredSel * st::dlgHeight, (filteredSel + 1) * st::dlgHeight); + } + parentWidget()->update(); +} + +void DialogsListWidget::scrollToPeer(const PeerId &peer) { + int32 fromY = -1; + if (filter.isEmpty()) { + DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(peer); + if (i != dialogs.list.rowByPeer.cend()) { + fromY = i.value()->pos * st::dlgHeight; + } else { + i = contactsNoDialogs.list.rowByPeer.constFind(peer); + if (i != contactsNoDialogs.list.rowByPeer.cend()) { + fromY = (i.value()->pos + dialogs.list.count) * st::dlgHeight; + } + } + } else { + for (int32 i = 0, c = filtered.size(); i < c; ++i) { + if (filtered[i]->history->peer->id == peer) { + fromY = i * st::dlgHeight; + break; + } + } + } + if (fromY >= 0) { + emit mustScrollTo(fromY, fromY + st::dlgHeight); + } +} + +void DialogsListWidget::selectSkipPage(int32 pixels, int32 direction) { + int32 toSkip = pixels / int32(st::dlgHeight); + if (filter.isEmpty()) { + if (!sel) { + if (direction > 0 && dialogs.list.count) { + sel = dialogs.list.begin; + } else if (direction > 0 && contactsNoDialogs.list.count) { + sel = contactsNoDialogs.list.begin; + } else { + return; + } + } + if (direction > 0) { + while (toSkip-- && sel->next->next) { + sel = sel->next; + } + if (toSkip >= 0 && sel->next == dialogs.list.end && contactsNoDialogs.list.count) { + sel = contactsNoDialogs.list.begin; + while (toSkip-- && sel->next->next) { + sel = sel->next; + } + contactSel = true; + } + } else { + while (toSkip-- && sel->prev) { + sel = sel->prev; + } + if (toSkip >= 0 && sel == contactsNoDialogs.list.begin && dialogs.list.count) { + sel = dialogs.list.end->prev; + while (toSkip-- && sel->prev) { + sel = sel->prev; + } + contactSel = false; + } + } + int32 fromY = (sel->pos + (contactSel ? dialogs.list.count : 0)) * st::dlgHeight; + emit mustScrollTo(fromY, fromY + st::dlgHeight); + } else { + return selectSkip(direction * toSkip); + } + parentWidget()->update(); +} + +void DialogsListWidget::loadPeerPhotos(int32 yFrom) { + int32 yTo = yFrom + parentWidget()->height() * 5; + MTP::clearLoaderPriorities(); + if (filter.isEmpty()) { + int32 otherStart = dialogs.list.count * st::dlgHeight; + if (yFrom < otherStart) { + dialogs.list.adjustCurrent(yFrom, st::dlgHeight); + for (DialogRow *row = dialogs.list.current; row != dialogs.list.end && (row->pos * st::dlgHeight) < yTo; row = row->next) { + row->history->peer->photo->load(); + } + yFrom = 0; + } else { + yFrom -= otherStart; + } + yTo -= otherStart; + if (yTo > 0) { + contactsNoDialogs.list.adjustCurrent(yFrom, st::dlgHeight); + for (DialogRow *row = contactsNoDialogs.list.current; row != contactsNoDialogs.list.end && (row->pos * st::dlgHeight) < yTo; row = row->next) { + row->history->peer->photo->load(); + } + } + } else { + int32 from = yFrom / st::dlgHeight; + if (from < 0) from = 0; + if (from < filtered.size()) { + int32 to = (yTo / int32(st::dlgHeight)) + 1, w = width(); + if (to > filtered.size()) to = filtered.size(); + + for (; from < to; ++from) { + filtered[from]->history->peer->photo->load(); + } + } + } +} + +void DialogsListWidget::choosePeer() { + History *history = filter.isEmpty() ? (sel ? sel->history : 0) : ((filteredSel >= 0 && filteredSel < filtered.size()) ? filtered[filteredSel]->history : 0); + if (history) { + emit peerChosen(history->peer->id); + sel = 0; + filteredSel = -1; + parentWidget()->update(); + } +} + +void DialogsListWidget::destroyData() { + sel = 0; + contactSel = false; + filteredSel = 0; + filtered.clear(); + filter.clear(); + contacts.clear(); + contactsNoDialogs.clear(); + dialogs.clear(); +} + +PeerData *DialogsListWidget::peerBefore(const PeerData *peer) const { + if (!filter.isEmpty()) { + if (filtered.isEmpty() || filtered.at(0)->history->peer == peer) return 0; + + for (FilteredDialogs::const_iterator b = filtered.cbegin(), i = b + 1, e = filtered.cend(); i != e; ++i) { + if ((*i)->history->peer == peer) { + FilteredDialogs::const_iterator j = i - 1; + return (*j)->history->peer; + } + } + return 0; + } + + DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(peer->id); + if (i == dialogs.list.rowByPeer.constEnd()) { + i = contactsNoDialogs.list.rowByPeer.constFind(peer->id); + if (i == contactsNoDialogs.list.rowByPeer.cend()) { + return 0; + } + if (i.value()->prev) { + return i.value()->prev->history->peer; + } else if (dialogs.list.count) { + return dialogs.list.end->prev->history->peer; + } + return 0; + } + if (i.value()->prev) { + return i.value()->prev->history->peer; + } + return 0; +} + +PeerData *DialogsListWidget::peerAfter(const PeerData *peer) const { + if (!filter.isEmpty()) { + for (FilteredDialogs::const_iterator i = filtered.cbegin(), e = filtered.cend(); i != e; ++i) { + if ((*i)->history->peer == peer) { + ++i; + return (i == e) ? 0 : (*i)->history->peer; + } + } + return 0; + } + DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(peer->id); + if (i == dialogs.list.rowByPeer.constEnd()) { + i = contactsNoDialogs.list.rowByPeer.constFind(peer->id); + if (i == contactsNoDialogs.list.rowByPeer.cend()) { + return 0; + } + if (i.value()->next != contactsNoDialogs.list.end) { + return i.value()->next->history->peer; + } + return 0; + } + + if (i.value()->next != dialogs.list.end) { + return i.value()->next->history->peer; + } else if (contactsNoDialogs.list.count) { + return contactsNoDialogs.list.begin->history->peer; + } + return 0; +} + +DialogsIndexed &DialogsListWidget::contactsList() { + return contacts; +} + +DialogsIndexed &DialogsListWidget::dialogsList() { + return dialogs; +} + +DialogsWidget::DialogsWidget(MainWidget *parent) : QWidget(parent), _configLoaded(false), _drawShadow(true), +scroll(this, st::dlgScroll), list(&scroll, parent), _filter(this, st::dlgFilter, lang(lng_dlg_filter)), dlgOffset(0), dlgCount(-1), dlgPreloading(0), contactsRequest(0), +_newGroup(this, st::btnNewGroup), _addContact(this, st::btnAddContact) { + scroll.setWidget(&list); + scroll.setFocusPolicy(Qt::NoFocus); + connect(&list, SIGNAL(mustScrollTo(int, int)), &scroll, SLOT(scrollToY(int, int))); + connect(&list, SIGNAL(dialogToTopFrom(int)), this, SLOT(onDialogToTopFrom(int))); +// connect(&list, SIGNAL(peerChosen(const PeerId &)), this, SLOT(onCancel())); + connect(&list, SIGNAL(peerChosen(const PeerId &)), this, SIGNAL(peerChosen(const PeerId &))); + connect(&scroll, SIGNAL(geometryChanged()), &list, SLOT(onParentGeometryChanged())); + connect(&scroll, SIGNAL(scrolled()), &list, SLOT(onUpdateSelected())); + connect(&scroll, SIGNAL(scrolled()), this, SLOT(onListScroll())); + connect(&_filter, SIGNAL(cancelled()), this, SLOT(onCancel())); + connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate())); + connect(parent, SIGNAL(dialogsUpdated()), this, SLOT(onListScroll())); + connect(&_addContact, SIGNAL(clicked()), this, SLOT(onAddContact())); + connect(&_newGroup, SIGNAL(clicked()), this, SLOT(onNewGroup())); + + scroll.show(); + _filter.show(); + _filter.move(st::dlgPaddingHor, st::dlgFilterPadding); + _filter.setFocusPolicy(Qt::StrongFocus); + _addContact.hide(); + _newGroup.show(); + _newGroup.move(width() - _newGroup.width() - st::dlgPaddingHor, 0); + _addContact.move(width() - _addContact.width() - st::dlgPaddingHor, 0); + scroll.move(0, _filter.height() + 2 * st::dlgFilterPadding); +} + +void DialogsWidget::activate() { + _filter.setFocus(); + list.activate(); +} + +void DialogsWidget::createDialogAtTop(History *history, int32 unreadCount) { + list.createDialogAtTop(history, unreadCount); +} + +void DialogsWidget::dlgUpdated(DialogRow *row) { + list.dlgUpdated(row); +} + +void DialogsWidget::dlgUpdated(History *row) { + list.dlgUpdated(row); +} + +void DialogsWidget::dialogsToUp() { + if (_filter.text().trimmed().isEmpty()) { + scroll.scrollToY(0); + } +} + +void DialogsWidget::setInnerFocus() { + _filter.setFocus(); +} + +void DialogsWidget::regTyping(History *history, UserData *user) { + uint64 ms = getms(); + history->typing[user] = ms + 6000; + + Histories::TypingHistories::const_iterator i = App::histories().typing.find(history); + if (i == App::histories().typing.cend()) { + App::histories().typing.insert(history, ms); + history->typingFrame = 0; + } + + history->updateTyping(ms, history->typingFrame, true); + anim::start(this); +} + +bool DialogsWidget::animStep(float64) { + uint64 ms = getms(); + Histories::TypingHistories &typing(App::histories().typing); + for (Histories::TypingHistories::iterator i = typing.begin(), e = typing.end(); i != e;) { + uint32 typingFrame = (ms - i.value()) / 150; + if (i.key()->updateTyping(ms, typingFrame)) { + list.dlgUpdated(i.key()); + App::main()->topBar()->update(); + } + if (i.key()->typing.isEmpty()) { + i = typing.erase(i); + } else { + ++i; + } + } + return !typing.isEmpty(); +} + +void DialogsWidget::onCancel() { + list.clearFilter(); + _filter.clear(); + _filter.updatePlaceholder(); + emit cancelled(); +} + +void DialogsWidget::unreadCountsReceived(const QVector &dialogs) { + for (QVector::const_iterator i = dialogs.cbegin(), e = dialogs.cend(); i != e; ++i) { + const MTPDdialog &d(i->c_dialog()); + Histories::iterator j = App::histories().find(App::peerFromMTP(d.vpeer)); + if (j != App::histories().end()) { + App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, j.value()); + j.value()->setUnreadCount(d.vunread_count.v, false); + } + } + if (App::wnd()) App::wnd()->psUpdateCounter(); +} + +void DialogsWidget::dialogsReceived(const MTPmessages_Dialogs &dialogs) { + const QVector *dlgList = 0; + switch (dialogs.type()) { + case mtpc_messages_dialogs: { + const MTPDmessages_dialogs &data(dialogs.c_messages_dialogs()); + App::feedUsers(data.vusers); + App::feedChats(data.vchats); + App::feedMsgs(data.vmessages); + dlgList = &data.vdialogs.c_vector().v; + dlgCount = dlgList->size(); + } break; + case mtpc_messages_dialogsSlice: { + const MTPDmessages_dialogsSlice &data(dialogs.c_messages_dialogsSlice()); + App::feedUsers(data.vusers); + App::feedChats(data.vchats); + App::feedMsgs(data.vmessages); + dlgList = &data.vdialogs.c_vector().v; + dlgCount = data.vcount.v; + } break; + } + + unreadCountsReceived(*dlgList); + + if (!contactsRequest) { + contactsRequest = MTP::send(MTPcontacts_GetContacts(MTP_string("")), rpcDone(&DialogsWidget::contactsReceived), rpcFail(&DialogsWidget::contactsFailed)); + } + + if (dlgList) { + list.dialogsReceived(*dlgList); + onListScroll(); + + if (dlgList->size()) { + dlgOffset += dlgList->size(); + } else { + dlgCount = dlgOffset; + } + } else { + dlgCount = dlgOffset; + loadConfig(); + } + + dlgPreloading = 0; + if (dlgList) { + loadDialogs(); + } +} + +bool DialogsWidget::dialogsFailed(const RPCError &e) { + LOG(("RPC Error: %1 %2: %3").arg(e.code()).arg(e.type()).arg(e.description())); + dlgPreloading = 0; + return true; +} + +void DialogsWidget::loadConfig() { + if (!_configLoaded) { + mtpConfigLoader()->load(); + _configLoaded = true; + } +} + +void DialogsWidget::loadDialogs() { + if (dlgPreloading) return; + if (dlgCount >= 0 && dlgOffset >= dlgCount) { + loadConfig(); + return; + } + + int32 loadCount = dlgOffset ? DialogsPerPage : DialogsFirstLoad; + dlgPreloading = MTP::send(MTPmessages_GetDialogs(MTP_int(dlgOffset), MTP_int(0), MTP_int(loadCount)), rpcDone(&DialogsWidget::dialogsReceived), rpcFail(&DialogsWidget::dialogsFailed)); +} + +void DialogsWidget::contactsReceived(const MTPcontacts_Contacts &contacts) { + if (contacts.type() == mtpc_contacts_contacts) { + const MTPDcontacts_contacts &d(contacts.c_contacts_contacts()); + App::feedUsers(d.vusers); + list.contactsReceived(d.vcontacts.c_vector().v); + } +} + +bool DialogsWidget::contactsFailed() { + return true; +} + +bool DialogsWidget::addNewContact(int32 uid, bool show) { + _filter.setText(QString()); + onFilterUpdate(); + int32 to = list.addNewContact(uid, true); + if (to < 0 || !show) return false; + list.refresh(); + scroll.scrollToY(to); + return true; +} + +void DialogsWidget::onListScroll() { + list.loadPeerPhotos(scroll.scrollTop()); + if (scroll.scrollTop() > list.dialogsList().list.count * st::dlgHeight - scroll.height()) { + loadDialogs(); + } +} + +void DialogsWidget::onFilterUpdate() { + list.onFilterUpdate(_filter.text()); +} + +void DialogsWidget::resizeEvent(QResizeEvent *e) { + int32 w = width() - st::dlgShadow; + _filter.setGeometry(st::dlgPaddingHor, st::dlgFilterPadding, w - 2 * st::dlgPaddingHor, _filter.height()); + _newGroup.move(w - _newGroup.width() - st::dlgPaddingHor, _filter.y()); + _addContact.move(w - _addContact.width() - st::dlgPaddingHor, _filter.y()); + scroll.resize(w, height() - _filter.y() - _filter.height() - st::dlgFilterPadding - st::dlgPaddingVer); + list.resize(w, list.height()); + onListScroll(); +} + +void DialogsWidget::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + e->ignore(); + } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { + list.choosePeer(); + } else if (e->key() == Qt::Key_Down) { + list.setMouseSel(false); + list.selectSkip(1); + } else if (e->key() == Qt::Key_Up) { + list.setMouseSel(false); + list.selectSkip(-1); + } else if (e->key() == Qt::Key_PageDown) { + list.setMouseSel(false); + list.selectSkipPage(scroll.height(), 1); + } else if (e->key() == Qt::Key_PageUp) { + list.setMouseSel(false); + list.selectSkipPage(scroll.height(), -1); + } else { + e->ignore(); + } +} + +void DialogsWidget::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (_drawShadow) { + p.setPen(st::dlgShadowColor->p); + for (int i = 0, w = width() - st::dlgShadow; i < st::dlgShadow; ++i) { + p.drawLine(w + i, 0, w + i, height()); + } + } +} + +void DialogsWidget::destroyData() { + list.destroyData(); +} + +PeerData *DialogsWidget::peerBefore(const PeerData *peer) const { + return list.peerBefore(peer); +} + +PeerData *DialogsWidget::peerAfter(const PeerData *peer) const { + return list.peerAfter(peer); +} + +void DialogsWidget::scrollToPeer(const PeerId &peer) { + list.scrollToPeer(peer); +} + +void DialogsWidget::removePeer(PeerData *peer) { + _filter.setText(QString()); + onFilterUpdate(); + list.removePeer(peer); +} + +void DialogsWidget::removeContact(UserData *user) { + _filter.setText(QString()); + onFilterUpdate(); + list.removeContact(user); +} + +DialogsIndexed &DialogsWidget::contactsList() { + return list.contactsList(); +} + +void DialogsWidget::onAddContact() { + App::wnd()->showLayer(new AddContactBox()); +} + +void DialogsWidget::onNewGroup() { + App::wnd()->showLayer(new NewGroupBox()); +} + +void DialogsWidget::onDialogToTopFrom(int movedFrom) { + if (scroll.scrollTop() > 0) { + if (movedFrom > scroll.scrollTop()) { + scroll.scrollToY(scroll.scrollTop() + st::dlgHeight); + } + } +} + +void DialogsWidget::enableShadow(bool enable) { + _drawShadow = enable; +} diff --git a/Telegram/SourceFiles/dialogswidget.h b/Telegram/SourceFiles/dialogswidget.h new file mode 100644 index 000000000..653bec574 --- /dev/null +++ b/Telegram/SourceFiles/dialogswidget.h @@ -0,0 +1,183 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +class MainWidget; + +class DialogsListWidget : public QWidget { + Q_OBJECT + +public: + + DialogsListWidget(QWidget *parent, MainWidget *main); + + void dialogsReceived(const QVector &dialogs); + void showMore(int32 pixels); + + void activate(); + + void contactsReceived(const QVector &contacts); + int32 addNewContact(int32 uid, bool sel = false); // return y of row or -1 if failed + + void paintEvent(QPaintEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + + void selectSkip(int32 direction); + void selectSkipPage(int32 pixels, int32 direction); + + void createDialogAtTop(History *history, int32 unreadCount); + void dlgUpdated(DialogRow *row); + void dlgUpdated(History *row); + void removePeer(PeerData *peer); + void removeContact(UserData *user); + + void loadPeerPhotos(int32 yFrom); + void clearFilter(); + void refresh(bool toTop = false); + + void choosePeer(); + + void destroyData(); + + PeerData *peerBefore(const PeerData *peer) const; + PeerData *peerAfter(const PeerData *peer) const; + void scrollToPeer(const PeerId &peer); + + DialogsIndexed &contactsList(); + DialogsIndexed &dialogsList(); + + void setMouseSel(bool msel, bool toTop = false); + +public slots: + + void onUpdateSelected(bool force = false); + void onParentGeometryChanged(); + void onDialogToTop(const History::DialogLinks &links); + void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars); + void onPeerPhotoChanged(PeerData *peer); + void onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow); + void onFilterUpdate(QString newFilter); + +signals: + + void peerChosen(const PeerId &); + void mustScrollTo(int scrollToTop, int scrollToBottom); + void dialogToTopFrom(int movedFrom); + +private: + + void addDialog(const MTPDdialog &dialog); + + DialogsIndexed dialogs; + DialogsIndexed contactsNoDialogs; + DialogsIndexed contacts; + DialogRow *sel; + bool contactSel; + bool selByMouse; + + QString filter; + typedef QVector FilteredDialogs; + FilteredDialogs filtered; + int32 filteredSel; + + QPoint lastMousePos; + + void paintDialog(QPainter &p, DialogRow *dialog); + +}; + +class DialogsWidget : public QWidget, public Animated, public RPCSender { + Q_OBJECT + +public: + DialogsWidget(MainWidget *parent); + + void dialogsReceived(const MTPmessages_Dialogs &dialogs); + void contactsReceived(const MTPcontacts_Contacts &contacts); + bool addNewContact(int32 uid, bool show = true); + + void resizeEvent(QResizeEvent *e); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + + void loadDialogs(); + void createDialogAtTop(History *history, int32 unreadCount); + void dlgUpdated(DialogRow *row); + void dlgUpdated(History *row); + + void dialogsToUp(); + + void regTyping(History *history, UserData *user); + + bool animStep(float64 ms); + + void setInnerFocus(); + + void destroyData(); + + PeerData *peerBefore(const PeerData *peer) const; + PeerData *peerAfter(const PeerData *peer) const; + void scrollToPeer(const PeerId &peer); + + void removePeer(PeerData *peer); + void removeContact(UserData *user); + + DialogsIndexed &contactsList(); + + void enableShadow(bool enable = true); + +signals: + + void peerChosen(const PeerId &); + void cancelled(); + +public slots: + + void onCancel(); + void onListScroll(); + void activate(); + void onFilterUpdate(); + void onAddContact(); + void onNewGroup(); + + void onDialogToTopFrom(int movedFrom); + +private: + + void loadConfig(); + bool _configLoaded; + + bool _drawShadow; + + void unreadCountsReceived(const QVector &dialogs); + bool dialogsFailed(const RPCError &e); + + bool contactsFailed(); + + int32 dlgOffset, dlgCount; + mtpRequestId dlgPreloading; + mtpRequestId contactsRequest; + + FlatInput _filter; + IconedButton _newGroup, _addContact; + ScrollArea scroll; + DialogsListWidget list; +}; diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp new file mode 100644 index 000000000..691fb7204 --- /dev/null +++ b/Telegram/SourceFiles/dropdown.cpp @@ -0,0 +1,682 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" + +#include "dropdown.h" +#include "historywidget.h" + +#include "lang.h" + +Dropdown::Dropdown(QWidget *parent) : TWidget(parent), + _shadow(st::dropdownShadow), a_opacity(0), _hiding(false) { + _width = st::dropdownPadding.left() + st::dropdownPadding.right(); + _height = st::dropdownPadding.top() + st::dropdownPadding.bottom(); + resize(_width, _height); + + _hideTimer.setSingleShot(true); + connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart())); +} + +IconedButton *Dropdown::addButton(IconedButton *button) { + button->setParent(this); + + _width = qMax(_width, st::dropdownPadding.left() + st::dropdownPadding.right() + button->width()); + if (!_buttons.isEmpty()) { + _height += st::dropdownBorder; + } + _height += button->height(); + + _buttons.push_back(button); + + resize(_width, _height); + + return button; +} + +void Dropdown::resizeEvent(QResizeEvent *e) { + int32 top = st::dropdownPadding.top(); + for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) { + (*i)->move(st::dropdownPadding.left(), top); + top += st::dropdownBorder + (*i)->height(); + } +} + +void Dropdown::paintEvent(QPaintEvent *e) { + QPainter p(this); + + if (animating()) { + p.setOpacity(a_opacity.current()); + } + + QRect r(st::dropdownPadding.left(), st::dropdownPadding.top(), _width - st::dropdownPadding.left() - st::dropdownPadding.right(), _height - st::dropdownPadding.top() - st::dropdownPadding.bottom()); + // draw shadow + _shadow.paint(p, r); + + if (!_buttons.isEmpty()) { // paint separators + int32 top = st::dropdownPadding.top() + _buttons.front()->height(); + p.setPen(st::dropdownBorderColor->p); + for (int32 i = 1, s = _buttons.size(); i < s; ++i) { + for (int32 e = top + st::dropdownBorder; top < e; ++top) { + p.drawLine(st::dropdownPadding.left(), top, _width - st::dropdownPadding.right() - 1, top); + } + top += _buttons[i]->height(); + } + } +} + +void Dropdown::enterEvent(QEvent *e) { + _hideTimer.stop(); + if (_hiding) showStart(); +} + +void Dropdown::leaveEvent(QEvent *e) { + if (animating()) { + hideStart(); + } else { + _hideTimer.start(300); + } +} + +void Dropdown::otherEnter() { + _hideTimer.stop(); + showStart(); +} + +void Dropdown::otherLeave() { + if (animating()) { + hideStart(); + } else { + _hideTimer.start(0); + } +} + +void Dropdown::fastHide() { + if (animating()) { + anim::stop(this); + } + a_opacity = anim::fvalue(0, 0); + _hideTimer.stop(); + hide(); +} + +void Dropdown::adjustButtons() { + for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) { + (*i)->setOpacity(a_opacity.current()); + } +} + +void Dropdown::hideStart() { + _hiding = true; + a_opacity.start(0); + anim::start(this); +} + +void Dropdown::hideFinish() { + hide(); +} + +void Dropdown::showStart() { + if (!isHidden() && a_opacity.current() == 1) { + return; + } + _hiding = false; + show(); + a_opacity.start(1); + anim::start(this); +} + +bool Dropdown::animStep(float64 ms) { + float64 dt = ms / 150; + bool res = true; + if (dt >= 1) { + a_opacity.finish(); + if (_hiding) { + hideFinish(); + } + res = false; + } else { + a_opacity.update(dt, anim::linear); + } + adjustButtons(); + update(); + return res; +} + +bool Dropdown::eventFilter(QObject *obj, QEvent *e) { + if (e->type() == QEvent::Enter) { + otherEnter(); + } else if (e->type() == QEvent::Leave) { + otherLeave(); + } else if (e->type() == QEvent::MouseButtonPress && static_cast(e)->button() == Qt::LeftButton) { + if (isHidden() || _hiding) { + otherEnter(); + } else { + otherLeave(); + } + } + return false; +} + +DragArea::DragArea(QWidget *parent) : TWidget(parent), + _shadow(st::boxShadow), a_opacity(0), a_color(st::dragColor->c), _hiding(false), _in(false) { + setMouseTracking(true); + setAcceptDrops(true); +} + +void DragArea::mouseMoveEvent(QMouseEvent *e) { + if (_hiding) return; + + bool newIn = QRect(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom()).contains(e->pos()); + if (newIn != _in) { + _in = newIn; + a_opacity.start(1); + a_color.start((_in ? st::dragDropColor : st::dragColor)->c); + anim::start(this); + } +} + +void DragArea::dragMoveEvent(QDragMoveEvent *e) { + QRect r(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom()); + bool newIn = r.contains(e->pos()); + if (newIn != _in) { + _in = newIn; + a_opacity.start(1); + a_color.start((_in ? st::dragDropColor : st::dragColor)->c); + anim::start(this); + } + e->setDropAction(_in ? Qt::CopyAction : Qt::IgnoreAction); + e->accept(); +} + +void DragArea::setText(const QString &text, const QString &subtext) { + _text = text; + _subtext = subtext; + update(); +} + +void DragArea::paintEvent(QPaintEvent *e) { + QPainter p(this); + + if (animating()) { + p.setOpacity(a_opacity.current()); + } + + QRect r(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom()); + + // draw shadow + _shadow.paint(p, r); + + p.fillRect(r, st::white->b); + + p.setPen(a_color.current()); + + p.setFont(st::dragFont->f); + p.drawText(QRect(0, (height() - st::dragHeight) / 2, width(), st::dragFont->height), _text, QTextOption(style::al_top)); + + p.setFont(st::dragSubfont->f); + p.drawText(QRect(0, (height() + st::dragHeight) / 2 - st::dragSubfont->height, width(), st::dragSubfont->height * 2), _subtext, QTextOption(style::al_top)); +} + +void DragArea::dragEnterEvent(QDragEnterEvent *e) { + static_cast(parentWidget())->dragEnterEvent(e); + e->setDropAction(Qt::IgnoreAction); + e->accept(); +} + +void DragArea::dragLeaveEvent(QDragLeaveEvent *e) { + static_cast(parentWidget())->dragLeaveEvent(e); + _in = false; + a_opacity.start(_hiding ? 0 : 1); + a_color.start((_in ? st::dragDropColor : st::dragColor)->c); + anim::start(this); +} + +void DragArea::dropEvent(QDropEvent *e) { + static_cast(parentWidget())->dropEvent(e); + if (e->isAccepted()) { + emit dropped(e); + } +} + +void DragArea::otherEnter() { + showStart(); +} + +void DragArea::otherLeave() { + hideStart(); +} + +void DragArea::fastHide() { + if (animating()) { + anim::stop(this); + } + a_opacity = anim::fvalue(0, 0); + hide(); +} + +void DragArea::hideStart() { + _hiding = true; + _in = false; + a_opacity.start(0); + a_color.start((_in ? st::dragDropColor : st::dragColor)->c); + anim::start(this); +} + +void DragArea::hideFinish() { + hide(); + _in = false; + a_color = anim::cvalue(st::dragColor->c); +} + +void DragArea::showStart() { + _hiding = false; + show(); + a_opacity.start(1); + a_color.start((_in ? st::dragDropColor : st::dragColor)->c); + anim::start(this); +} + +bool DragArea::animStep(float64 ms) { + float64 dt = ms / 150; + bool res = true; + if (dt >= 1) { + a_opacity.finish(); + a_color.finish(); + if (_hiding) { + hideFinish(); + } + res = false; + } else { + a_opacity.update(dt, anim::linear); + a_color.update(dt, anim::linear); + } + update(); + return res; +} + +static const int emojiPerRow = 7, emojiRowsPerPage = 6; + +EmojiPanInner::EmojiPanInner(QWidget *parent) : QWidget(parent), _selected(-1), _pressedSel(-1), _tab(cEmojiTab()) { + resize(emojiPerRow * st::emojiPanSize.width(), emojiRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub); + setMouseTracking(true); + setFocusPolicy(Qt::NoFocus); + _saveConfigTimer.setSingleShot(true); + connect(&_saveConfigTimer, SIGNAL(timeout()), this, SLOT(onSaveConfig())); +} + +void EmojiPanInner::paintEvent(QPaintEvent *e) { + QPainter p(this); + int32 size = _emojis.size(); + if (!size) { + p.setFont(st::emojiPanFont->f); + p.setPen(st::emojiPanText->p); + p.drawText(QRect(0, 0, width(), height() * 0.75), lang(lng_emoji_no_recent), QTextOption(style::al_center)); + return; + } + + QRect r = e ? e->rect() : rect(); + + int32 rows = (size / emojiPerRow) + ((size % emojiPerRow) ? 1 : 0); + int32 fromrow = qMax(qFloor(r.top() / st::emojiPanSize.height()), 0), torow = qMin(qCeil(r.bottom() / st::emojiPanSize.height()) + 1, rows); + for (int32 i = fromrow; i < torow; ++i) { + for (int32 j = 0; j < emojiPerRow; ++j) { + int32 index = i * emojiPerRow + j; + if (index >= size) break; + + float64 hover = _hovers[index]; + + QPoint w(j * st::emojiPanSize.width(), i * st::emojiPanSize.height()); + if (hover > 0) { + p.setOpacity(hover); + p.setBrush(st::emojiPanHover->b); + p.setPen(Qt::NoPen); + p.drawRoundedRect(QRect(w, st::emojiPanSize), st::emojiPanRound, st::emojiPanRound); + p.setOpacity(1); + } + QRect r(_emojis[index]->x, _emojis[index]->y, st::emojiSize, st::emojiSize); + p.drawPixmap(w + QPoint((st::emojiPanSize.width() - st::emojiSize) / 2, (st::emojiPanSize.height() - st::emojiSize) / 2), App::emojis(), r); + } + } +} + +void EmojiPanInner::mousePressEvent(QMouseEvent *e) { + _lastMousePos = e->globalPos(); + updateSelected(); + _pressedSel = _selected; +} + +void EmojiPanInner::mouseReleaseEvent(QMouseEvent *e) { + _lastMousePos = e->globalPos(); + updateSelected(); + if (_selected == _pressedSel && _selected >= 0 && _selected < _emojis.size()) { + EmojiPtr emoji(_emojis[_selected]); + RecentEmojiPack recent(cGetRecentEmojis()); + RecentEmojiPack::iterator i = recent.begin(), e = recent.end(); + for (; i != e; ++i) { + if (i->first == emoji) { + ++i->second; + if (i->second > 0x8000) { + for (RecentEmojiPack::iterator j = recent.begin(); j != e; ++j) { + if (j->second > 1) { + j->second /= 2; + } else { + j->second = 1; + } + } + } + for (; i != recent.begin(); --i) { + if ((i - 1)->second > i->second) { + break; + } + qSwap(*i, *(i - 1)); + } + break; + } + } + if (i == e) { + while (recent.size() >= emojiPerRow * emojiRowsPerPage) recent.pop_back(); + recent.push_back(qMakePair(emoji, 1)); + for (i = recent.end() - 1; i != recent.begin(); --i) { + if ((i - 1)->second > i->second) { + break; + } + qSwap(*i, *(i - 1)); + } + } + cSetRecentEmojis(recent); + _saveConfigTimer.start(SaveRecentEmojisTimeout); + + emit emojiSelected(emoji); + } +} + +void EmojiPanInner::onSaveConfig() { + App::writeUserConfig(); +} + +void EmojiPanInner::mouseMoveEvent(QMouseEvent *e) { + _lastMousePos = e->globalPos(); + updateSelected(); +} + +void EmojiPanInner::leaveEvent(QEvent *e) { + _lastMousePos = QCursor::pos(); + updateSelected(); +} + +void EmojiPanInner::updateSelected() { + int32 selIndex = -1; + QPoint p(mapFromGlobal(_lastMousePos)); + if (p.x() >= 0 && p.y() >= 0 && p.x() < emojiPerRow * st::emojiPanSize.width()) { + selIndex = qFloor(p.y() / st::emojiPanSize.height()) * emojiPerRow + qFloor(p.x() / st::emojiPanSize.width()); + if (selIndex >= _emojis.size()) { + selIndex = -1; + } + } + if (selIndex != _selected) { + bool startanim = false; + if (_selected >= 0) { + _emojiAnimations.remove(_selected + 1); + if (_emojiAnimations.find(-_selected - 1) == _emojiAnimations.end()) { + if (_emojiAnimations.isEmpty()) startanim = true; + _emojiAnimations.insert(-_selected - 1, getms()); + } + } + _selected = selIndex; + if (_selected >= 0) { + _emojiAnimations.remove(-_selected - 1); + if (_emojiAnimations.find(_selected + 1) == _emojiAnimations.end()) { + if (_emojiAnimations.isEmpty()) startanim = true; + _emojiAnimations.insert(_selected + 1, getms()); + } + } + if (startanim) anim::start(this); + setCursor((_selected >= 0) ? style::cur_pointer : style::cur_default); + } +} + +bool EmojiPanInner::animStep(float64 ms) { + uint64 now = getms(); + for (EmojiAnimations::iterator i = _emojiAnimations.begin(); i != _emojiAnimations.end();) { + float64 dt = float64(now - i.value()) / st::emojiPanDuration; + if (dt >= 1) { + _hovers[qAbs(i.key()) - 1] = (i.key() > 0) ? 1 : 0; + i = _emojiAnimations.erase(i); + } else { + _hovers[qAbs(i.key()) - 1] = (i.key() > 0) ? dt : (1 - dt); + ++i; + } + } + update(); + return !_emojiAnimations.isEmpty(); +} + +void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) { + _tab = packIndex; + _emojis = emojiPack(packIndex); + _hovers = QVector(_emojis.size(), 0); + _emojiAnimations.clear(); + _selected = _pressedSel = -1; + int32 size = _emojis.size(); + int32 h = qMax(((size / emojiPerRow) + ((size % emojiPerRow) ? 1 : 0)) * st::emojiPanSize.height(), emojiRowsPerPage * st::emojiPanSize.height() - int(st::emojiPanSub)); + resize(width(), h); + _lastMousePos = QCursor::pos(); + updateSelected(); + update(); +} + +EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent), +_recent (this, qsl("emoji_group"), dbietRecent , QString(), cEmojiTab() == dbietRecent , st::rbEmojiRecent), +_people (this, qsl("emoji_group"), dbietPeople , QString(), cEmojiTab() == dbietPeople , st::rbEmojiPeople), +_nature (this, qsl("emoji_group"), dbietNature , QString(), cEmojiTab() == dbietNature , st::rbEmojiNature), +_objects(this, qsl("emoji_group"), dbietObjects, QString(), cEmojiTab() == dbietObjects, st::rbEmojiObjects), +_places (this, qsl("emoji_group"), dbietPlaces , QString(), cEmojiTab() == dbietPlaces , st::rbEmojiPlaces), +_symbols(this, qsl("emoji_group"), dbietSymbols, QString(), cEmojiTab() == dbietSymbols, st::rbEmojiSymbols), +_shadow(st::dropdownShadow), a_opacity(0), _hiding(false), _scroll(this, st::emojiScroll), _inner() { + setFocusPolicy(Qt::NoFocus); + _scroll.setFocusPolicy(Qt::NoFocus); + _scroll.viewport()->setFocusPolicy(Qt::NoFocus); + + _inner.showEmojiPack(cEmojiTab()); + + _scroll.setGeometry(st::dropdownPadding.left() + st::emojiPanPadding.left(), st::dropdownPadding.top() + _recent.height() + st::emojiPanPadding.top(), st::emojiPanPadding.left() + _inner.width() + st::emojiPanPadding.right(), emojiRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub); + _scroll.setWidget(&_inner); + + _width = st::dropdownPadding.left() + st::emojiPanPadding.left() + _scroll.width() + st::emojiPanPadding.right() + st::dropdownPadding.right(); + _height = st::dropdownPadding.top() + _recent.height() + st::emojiPanPadding.top() + _scroll.height() + st::emojiPanPadding.bottom() + st::dropdownPadding.bottom(); + resize(_width, _height); + + int32 left = st::dropdownPadding.left() + (_width - st::dropdownPadding.left() - st::dropdownPadding.right() - 6 * _recent.width()) / 2; + int32 top = st::dropdownPadding.top(); + _recent.move(left, top); left += _recent.width(); + _people.move(left, top); left += _people.width(); + _nature.move(left, top); left += _nature.width(); + _objects.move(left, top); left += _objects.width(); + _places.move(left, top); left += _places.width(); + _symbols.move(left, top); left += _symbols.width(); + + _hideTimer.setSingleShot(true); + connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart())); + + connect(&_recent , SIGNAL(changed()), this, SLOT(onTabChange())); + connect(&_people , SIGNAL(changed()), this, SLOT(onTabChange())); + connect(&_nature , SIGNAL(changed()), this, SLOT(onTabChange())); + connect(&_objects, SIGNAL(changed()), this, SLOT(onTabChange())); + connect(&_places , SIGNAL(changed()), this, SLOT(onTabChange())); + connect(&_symbols, SIGNAL(changed()), this, SLOT(onTabChange())); + + connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSelected())); + + connect(&_inner, SIGNAL(emojiSelected(EmojiPtr)), this, SIGNAL(emojiSelected(EmojiPtr))); +} + +void EmojiPan::paintEvent(QPaintEvent *e) { + QPainter p(this); + + if (!_cache.isNull()) { + p.setOpacity(a_opacity.current()); + } + + QRect r(st::dropdownPadding.left(), st::dropdownPadding.top(), _width - st::dropdownPadding.left() - st::dropdownPadding.right(), _height - st::dropdownPadding.top() - st::dropdownPadding.bottom()); + + // draw shadow + _shadow.paint(p, r); + + if (_cache.isNull()) { + p.fillRect(r, st::white->b); + } else { + p.drawPixmap(r.left(), r.top(), _cache); + } +} + +void EmojiPan::enterEvent(QEvent *e) { + _hideTimer.stop(); + if (_hiding) showStart(); +} + +void EmojiPan::leaveEvent(QEvent *e) { + if (animating()) { + hideStart(); + } else { + _hideTimer.start(300); + } +} + +void EmojiPan::otherEnter() { + _hideTimer.stop(); + showStart(); +} + +void EmojiPan::otherLeave() { + if (animating()) { + hideStart(); + } else { + _hideTimer.start(0); + } +} + +void EmojiPan::fastHide() { + if (animating()) { + anim::stop(this); + } + a_opacity = anim::fvalue(0, 0); + _hideTimer.stop(); + hide(); + _cache = QPixmap(); +} + +bool EmojiPan::animStep(float64 ms) { + float64 dt = ms / 150; + bool res = true; + if (dt >= 1) { + a_opacity.finish(); + if (_hiding) { + hideFinish(); + } else { + showAll(); + _cache = QPixmap(); + } + res = false; + } else { + a_opacity.update(dt, anim::linear); + } + update(); + return res; +} + +void EmojiPan::hideStart() { + if (_cache.isNull()) { + showAll(); + _cache = grab(rect().marginsRemoved(st::dropdownPadding)); + } + hideAll(); + _hiding = true; + a_opacity.start(0); + anim::start(this); +} + +void EmojiPan::hideFinish() { + hide(); + _cache = QPixmap(); +} + +void EmojiPan::showStart() { + if (!isHidden() && a_opacity.current() == 1) { + return; + } + if (_cache.isNull()) { + showAll(); + _cache = grab(rect().marginsRemoved(st::dropdownPadding)); + } + hideAll(); + _hiding = false; + show(); + a_opacity.start(1); + anim::start(this); +} + +bool EmojiPan::eventFilter(QObject *obj, QEvent *e) { + if (e->type() == QEvent::Enter) { + otherEnter(); + } else if (e->type() == QEvent::Leave) { + otherLeave(); + } else if (e->type() == QEvent::MouseButtonPress && static_cast(e)->button() == Qt::LeftButton) { + if (isHidden() || _hiding) { + otherEnter(); + } else { + otherLeave(); + } + } + return false; +} + +void EmojiPan::showAll() { + _recent.show(); + _people.show(); + _nature.show(); + _objects.show(); + _places.show(); + _symbols.show(); + _scroll.show(); +} + +void EmojiPan::hideAll() { + _recent.hide(); + _people.hide(); + _nature.hide(); + _objects.hide(); + _places.hide(); + _symbols.hide(); + _scroll.hide(); +} + +void EmojiPan::onTabChange() { + DBIEmojiTab newTab; + if (_recent.checked()) newTab = dbietRecent; + else if (_people.checked()) newTab = dbietPeople; + else if (_nature.checked()) newTab = dbietNature; + else if (_objects.checked()) newTab = dbietObjects; + else if (_places.checked()) newTab = dbietPlaces; + else if (_symbols.checked()) newTab = dbietSymbols; + if (newTab != cEmojiTab()) { + cSetEmojiTab(newTab); + App::writeUserConfig(); + _scroll.scrollToY(0); + _inner.showEmojiPack(newTab); + } +} diff --git a/Telegram/SourceFiles/dropdown.h b/Telegram/SourceFiles/dropdown.h new file mode 100644 index 000000000..92b46d9f1 --- /dev/null +++ b/Telegram/SourceFiles/dropdown.h @@ -0,0 +1,215 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "gui/twidget.h" +#include "gui/boxshadow.h" + +class Dropdown : public TWidget, public Animated { + Q_OBJECT + +public: + + Dropdown(QWidget *parent); + + IconedButton *addButton(IconedButton *button); + + void resizeEvent(QResizeEvent *e); + void paintEvent(QPaintEvent *e); + + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void otherEnter(); + void otherLeave(); + + void fastHide(); + + bool animStep(float64 ms); + + bool eventFilter(QObject *obj, QEvent *e); + +public slots: + + void hideStart(); + void hideFinish(); + + void showStart(); + +private: + + void adjustButtons(); + + typedef QVector Buttons; + Buttons _buttons; + + int32 _width, _height; + bool _hiding; + + anim::fvalue a_opacity; + + QTimer _hideTimer; + + BoxShadow _shadow; + +}; + +class DragArea : public TWidget, public Animated { + Q_OBJECT + +public: + + DragArea(QWidget *parent); + + void paintEvent(QPaintEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void dragEnterEvent(QDragEnterEvent *e); + void dragLeaveEvent(QDragLeaveEvent *e); + void dropEvent(QDropEvent *e); + void dragMoveEvent(QDragMoveEvent *e); + + void setText(const QString &text, const QString &subtext); + + void otherEnter(); + void otherLeave(); + + void fastHide(); + + bool animStep(float64 ms); + +signals: + + void dropped(QDropEvent *e); + +public slots: + + void hideStart(); + void hideFinish(); + + void showStart(); + +private: + + bool _hiding, _in; + + anim::fvalue a_opacity; + anim::cvalue a_color; + + BoxShadow _shadow; + + QString _text, _subtext; + +}; + +class EmojiPanInner : public QWidget, public Animated { + Q_OBJECT + +public: + + EmojiPanInner(QWidget *parent = 0); + + void paintEvent(QPaintEvent *e); + + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void leaveEvent(QEvent *e); + + bool animStep(float64 ms); + + void showEmojiPack(DBIEmojiTab packIndex); + +public slots: + + void updateSelected(); + void onSaveConfig(); + +signals: + + void emojiSelected(EmojiPtr emoji); + +private: + + typedef QMap EmojiAnimations; // index - showing, -index - hiding + EmojiAnimations _emojiAnimations; + + QVector _emojis; + QVector _hovers; + + DBIEmojiTab _tab; + int32 _selected, _pressedSel; + QPoint _lastMousePos; + + QTimer _saveConfigTimer; + +}; + +class EmojiPan : public TWidget, public Animated { + Q_OBJECT + +public: + + EmojiPan(QWidget *parent); + + void paintEvent(QPaintEvent *e); + + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void otherEnter(); + void otherLeave(); + + void fastHide(); + + bool animStep(float64 ms); + + bool eventFilter(QObject *obj, QEvent *e); + +public slots: + + void hideStart(); + void hideFinish(); + + void showStart(); + + void onTabChange(); + +signals: + + void emojiSelected(EmojiPtr emoji); + +private: + + void showAll(); + void hideAll(); + + int32 _width, _height; + bool _hiding; + QPixmap _cache; + + anim::fvalue a_opacity; + + QTimer _hideTimer; + + BoxShadow _shadow; + + FlatRadiobutton _recent, _people, _nature, _objects, _places, _symbols; + + int32 _emojiPack; + ScrollArea _scroll; + EmojiPanInner _inner; + +}; diff --git a/Telegram/SourceFiles/fileuploader.cpp b/Telegram/SourceFiles/fileuploader.cpp new file mode 100644 index 000000000..0293863c8 --- /dev/null +++ b/Telegram/SourceFiles/fileuploader.cpp @@ -0,0 +1,214 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "fileuploader.h" + +FileUploader::FileUploader() : uploading(0), sentSize(0) { + nextTimer.setSingleShot(true); + connect(&nextTimer, SIGNAL(timeout()), this, SLOT(sendNext())); +} + +void FileUploader::uploadMedia(MsgId msgId, const ReadyLocalMedia &media) { + if (media.type == ToPreparePhoto) { + App::feedPhoto(media.photo, media.photoThumbs); + } else if (media.type == ToPrepareDocument) { + DocumentData *document; + if (media.photoThumbs.isEmpty()) { + document = App::feedDocument(media.document); + } else { + document = App::feedDocument(media.document, media.photoThumbs.begin().value()); + } + document->status = FileUploading; + if (!media.file.isEmpty()) { + document->fileName = media.file; + document->modDate = QFileInfo(media.file).lastModified(); + } + } + queue.insert(msgId, File(media)); + sendNext(); +} + +void FileUploader::currentFailed() { + Queue::iterator j = queue.find(uploading); + if (j != queue.end()) { + if (j->media.type == ToPreparePhoto) { + emit photoFailed(j.key()); + } else if (j->media.type == ToPrepareDocument) { + DocumentData *doc = App::document(j->media.id); + if (doc->status == FileUploading) { + doc->status = FileFailed; + } + emit documentFailed(j.key()); + } + queue.erase(j); + } + + requestsSent.clear(); + docRequestsSent.clear(); + queue.remove(uploading); + uploading = 0; + sentSize = 0; + + sendNext(); +} + +void FileUploader::sendNext() { + if (sentSize >= MaxUploadFileParallelSize || queue.isEmpty()) return; + + Queue::iterator i = uploading ? queue.find(uploading) : queue.begin(); + if (!uploading) { + uploading = i.key(); + } else if (i == queue.end()) { + i = queue.begin(); + uploading = i.key(); + } + if (i->media.parts.isEmpty()) { + if (i->docSentParts >= i->docPartsCount) { + if (requestsSent.isEmpty() && docRequestsSent.isEmpty()) { + if (i->media.type == ToPreparePhoto) { + emit photoReady(uploading, MTP_inputFile(MTP_long(i->media.id), MTP_int(i->partsCount), MTP_string(i->media.filename), MTP_string(i->media.jpeg_md5))); + } else if (i->media.type == ToPrepareDocument) { + QByteArray docMd5(32, Qt::Uninitialized); + hashMd5Hex(i->docHash.result(), docMd5.data()); + + MTPInputFile doc = (i->docSize > UseBigFilesFrom) ? MTP_inputFileBig(MTP_long(i->media.id), MTP_int(i->docPartsCount), MTP_string(i->media.filename)) : MTP_inputFile(MTP_long(i->media.id), MTP_int(i->docPartsCount), MTP_string(i->media.filename), MTP_string(docMd5)); + if (i->partsCount) { + emit thumbDocumentReady(uploading, doc, MTP_inputFile(MTP_long(i->media.jpeg_id), MTP_int(i->partsCount), MTP_string(i->media.filename), MTP_string(i->media.jpeg_md5))); + } else { + emit documentReady(uploading, doc); + } + } + queue.remove(uploading); + uploading = 0; + sendNext(); + } + return; + } + + QByteArray toSend; + if (i->media.data.isEmpty()) { + if (!i->docFile) { + i->docFile.reset(new QFile(i->media.file)); + if (!i->docFile->open(QIODevice::ReadOnly)) { + currentFailed(); + return; + } + } + toSend = i->docFile->read(i->docPartSize); + if (i->docSize <= UseBigFilesFrom) { + i->docHash.feed(toSend.constData(), toSend.size()); + } + } else { + toSend = i->media.data.mid(i->docSentParts * i->docPartSize, i->docPartSize); + } + if (toSend.size() > i->docPartSize || toSend.size() < i->docPartSize && i->docSentParts + 1 != i->docPartsCount) { + currentFailed(); + return; + } + mtpRequestId requestId; + if (i->docSize > UseBigFilesFrom) { + requestId = MTP::send(MTPupload_SaveBigFilePart(MTP_long(i->media.id), MTP_int(i->docSentParts), MTP_int(i->docPartsCount), MTP_string(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl); + } else { + requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->media.id), MTP_int(i->docSentParts), MTP_string(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl); + } + docRequestsSent.insert(requestId, i->docSentParts); + sentSize += i->docPartSize; + + i->docSentParts++; + } else { + LocalFileParts::iterator part = i->media.parts.begin(); + + mtpRequestId requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->media.jpeg_id), MTP_int(part.key()), MTP_string(part.value())), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl); + requestsSent.insert(requestId, part.value()); + sentSize += part.value().size(); + + i->media.parts.erase(part); + } + nextTimer.start(UploadRequestInterval); +} + +void FileUploader::cancel(MsgId msgId) { + uploaded.remove(msgId); + if (uploading == msgId) { + currentFailed(); + } else { + queue.remove(msgId); + } +} + +void FileUploader::confirm(MsgId msgId) { +} + +void FileUploader::clear() { + uploaded.clear(); + queue.clear(); + for (QMap::const_iterator i = requestsSent.cbegin(), e = requestsSent.cend(); i != e; ++i) { + MTP::cancel(i.key()); + } + requestsSent.clear(); + for (QMap::const_iterator i = docRequestsSent.cbegin(), e = docRequestsSent.cend(); i != e; ++i) { + MTP::cancel(i.key()); + } + docRequestsSent.clear(); + sentSize = 0; +} + +void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) { + QMap::iterator j = docRequestsSent.end(); + QMap::iterator i = requestsSent.find(requestId); + if (i == requestsSent.cend()) { + j = docRequestsSent.find(requestId); + } + if (i != requestsSent.cend() || j != docRequestsSent.cend()) { + if (!result.v) { // failed to upload current file + currentFailed(); + return; + } else { + Queue::const_iterator k = queue.constFind(uploading); + if (i != requestsSent.cend()) { + sentSize -= i.value().size(); + requestsSent.erase(i); + } else { + sentSize -= k->docPartSize; + docRequestsSent.erase(j); + } + if (k->media.type == ToPreparePhoto) { + emit photoProgress(k.key()); + } else if (k->media.type == ToPrepareDocument) { + DocumentData *doc = App::document(k->media.id); + if (doc->status == FileUploading) { + doc->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize; + if (doc->uploadOffset > doc->size) { + doc->uploadOffset = doc->size; + } + } + emit documentProgress(k.key()); + } + } + } + + sendNext(); +} + +bool FileUploader::partFailed(const RPCError &err, mtpRequestId requestId) { + if (requestsSent.constFind(requestId) != requestsSent.cend() || docRequestsSent.constFind(requestId) != docRequestsSent.cend()) { // failed to upload current file + currentFailed(); + } + sendNext(); + return true; +} diff --git a/Telegram/SourceFiles/fileuploader.h b/Telegram/SourceFiles/fileuploader.h new file mode 100644 index 000000000..07a48be96 --- /dev/null +++ b/Telegram/SourceFiles/fileuploader.h @@ -0,0 +1,108 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "localimageloader.h" + +class FileUploader : public QObject, public RPCSender { + Q_OBJECT + +public: + + FileUploader(); + void uploadMedia(MsgId msgId, const ReadyLocalMedia &image); + + int32 currentOffset(MsgId msgId) const; // -1 means file not found + int32 fullSize(MsgId msgId) const; + + void cancel(MsgId msgId); + void confirm(MsgId msgId); + + void clear(); + +public slots: + + void sendNext(); + +signals: + + void photoReady(MsgId msgId, const MTPInputFile &file); + void documentReady(MsgId msgId, const MTPInputFile &file); + void thumbDocumentReady(MsgId msgId, const MTPInputFile &file, const MTPInputFile &thumb); + + void photoProgress(MsgId msgId); + void documentProgress(MsgId msgId); + + void photoFailed(MsgId msgId); + void documentFailed(MsgId msgId); + +private: + + struct File { + File(const ReadyLocalMedia &media) : media(media), docSentParts(0) { + partsCount = media.parts.size(); + if (media.type == ToPrepareDocument) { + docSize = media.file.isEmpty() ? media.data.size() : media.filesize; + if (docSize >= 1024 * 1024 || !setPartSize(DocumentUploadPartSize0)) { + if (docSize > 32 * 1024 * 1024 || !setPartSize(DocumentUploadPartSize1)) { + if (!setPartSize(DocumentUploadPartSize2)) { + if (!setPartSize(DocumentUploadPartSize3)) { + if (!setPartSize(DocumentUploadPartSize4)) { + LOG(("Upload Error: bad doc size: %1").arg(docSize)); + } + } + } + } + } + } else { + docSize = docPartSize = docPartsCount = 0; + } + } + bool setPartSize(uint32 partSize) { + docPartSize = partSize; + docPartsCount = (docSize / docPartSize) + ((docSize % docPartSize) ? 1 : 0); + return (docPartsCount <= DocumentMaxPartsCount); + } + + ReadyLocalMedia media; + int32 partsCount; + + QSharedPointer docFile; + int32 docSentParts; + int32 docSize; + int32 docPartSize; + int32 docPartsCount; + HashMd5 docHash; + }; + typedef QMap Queue; + + void partLoaded(const MTPBool &result, mtpRequestId requestId); + bool partFailed(const RPCError &err, mtpRequestId requestId); + + void currentFailed(); + + QMap requestsSent; + QMap docRequestsSent; + uint32 sentSize; + + MsgId uploading; + Queue queue; + Queue uploaded; + QTimer nextTimer; + +}; diff --git a/Telegram/SourceFiles/gui/animation.cpp b/Telegram/SourceFiles/gui/animation.cpp new file mode 100644 index 000000000..0ea3f3ee3 --- /dev/null +++ b/Telegram/SourceFiles/gui/animation.cpp @@ -0,0 +1,96 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" + +#include "animation.h" +#include + +namespace { + AnimationManager *manager = 0; +}; + +namespace anim { + + float64 linear(const float64 &delta, const float64 &dt) { + return delta * dt; + } + + float64 sineInOut(const float64 &delta, const float64 &dt) { + return -(delta / 2) * (cos(M_PI * dt) - 1); + } + + float64 halfSine(const float64 &delta, const float64 &dt) { + return delta * sin(M_PI * dt / 2); + } + + float64 easeOutBack(const float64 &delta, const float64 &dt) { + static const float64 s = 1.70158; + + const float64 t = dt - 1; + return delta * (t * t * ((s + 1) * t + s) + 1); + } + + float64 easeInCirc(const float64 &delta, const float64 &dt) { + return -delta * (sqrt(1 - dt * dt) - 1); + } + + float64 easeOutCirc(const float64 &delta, const float64 &dt) { + const float64 t = dt - 1; + return delta * sqrt(1 - t * t); + } + + float64 easeInCubic(const float64 &delta, const float64 &dt) { + return delta * dt * dt * dt; + } + + float64 easeOutCubic(const float64 &delta, const float64 &dt) { + const float64 t = dt - 1; + return delta * (t * t * t + 1); + } + + float64 easeInQuint(const float64 &delta, const float64 &dt) { + const float64 t2 = dt * dt; + return delta * t2 * t2 * dt; + } + + float64 easeOutQuint(const float64 &delta, const float64 &dt) { + const float64 t = dt - 1, t2 = t * t; + return delta * (t2 * t2 * t + 1); + } + + void start(Animated *obj) { + if (!manager) return; + manager->start(obj); + } + + void stop(Animated *obj) { + if (!manager) return; + manager->stop(obj); + } + + void startManager() { + delete manager; + manager = new AnimationManager(); + } + + void stopManager() { + delete manager; + manager = 0; + } + +} diff --git a/Telegram/SourceFiles/gui/animation.h b/Telegram/SourceFiles/gui/animation.h new file mode 100644 index 000000000..7cd59b704 --- /dev/null +++ b/Telegram/SourceFiles/gui/animation.h @@ -0,0 +1,292 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "types.h" +#include +#include + +class Animated; + +namespace anim { + + typedef float64 (*transition)(const float64 &delta, const float64 &dt); + + float64 linear(const float64 &delta, const float64 &dt); + float64 sineInOut(const float64 &delta, const float64 &dt); + float64 halfSine(const float64 &delta, const float64 &dt); + float64 easeOutBack(const float64 &delta, const float64 &dt); + float64 easeInCirc(const float64 &delta, const float64 &dt); + float64 easeOutCirc(const float64 &delta, const float64 &dt); + float64 easeInCubic(const float64 &delta, const float64 &dt); + float64 easeOutCubic(const float64 &delta, const float64 &dt); + float64 easeInQuint(const float64 &delta, const float64 &dt); + float64 easeOutQuint(const float64 &delta, const float64 &dt); + + class fvalue { // float animated value + public: + + fvalue() { + } + fvalue(const float64 &from) : _cur(from), _from(from), _delta(0) { + } + fvalue(const float64 &from, const float64 &to) : _cur(from), _from(from), _delta(to - from) { + } + void start(const float64 &to) { + _from = _cur; + _delta = to - _from; + } + void restart() { + _delta = _from + _delta - _cur; + _from = _cur; + } + const float64 ¤t() const { + return _cur; + } + void update(const float64 &dt, transition func) { + _cur = _from + (*func)(_delta, dt); + } + void finish() { + _cur = _from + _delta; + _from = _cur; + _delta = 0; + } + + private: + + float64 _cur, _from, _delta; + }; + + class ivalue { // int animated value + public: + + ivalue() { + } + ivalue(int32 from) : _cur(from), _from(float64(from)), _delta(0) { + } + ivalue(int32 from, int32 to) : _cur(from), _from(float64(from)), _delta(float64(to - from)) { + } + void start(int32 to) { + _from = float64(_cur); + _delta = float64(to) - _from; + } + void restart() { + _delta = _from + _delta - float64(_cur); + _from = float64(_cur); + } + int32 current() const { + return _cur; + } + void update(const float64 &dt, transition func) { + _cur = qRound(_from + (*func)(_delta, dt)); + } + void finish() { + _cur = qRound(_from + _delta); + _from = _cur; + _delta = 0; + } + + private: + + int32 _cur; + float64 _from, _delta; + }; + + class cvalue { // QColor animated value + public: + + cvalue() { + } + cvalue(const QColor &from) : _cur(from), _from_r(from.redF()), _from_g(from.greenF()), _from_b(from.blueF()), _from_a(from.alphaF()), _delta_r(0), _delta_g(0), _delta_b(0), _delta_a(0) { + } + cvalue(const QColor &from, const QColor &to) + : _cur(from) + , _from_r(from.redF()), _from_g(from.greenF()), _from_b(from.blueF()), _from_a(from.alphaF()) + , _delta_r(to.redF() - from.redF()), _delta_g(to.greenF() - from.greenF()), _delta_b(to.blueF() - from.blueF()), _delta_a(to.alphaF() - from.alphaF()) + { + } + void start(const QColor &to) { + _from_r = _cur.redF(); + _from_g = _cur.greenF(); + _from_b = _cur.blueF(); + _from_a = _cur.alphaF(); + _delta_r = to.redF() - _from_r; + _delta_g = to.greenF() - _from_g; + _delta_b = to.blueF() - _from_b; + _delta_a = to.alphaF() - _from_a; + } + void restart() { + _delta_r = _from_r + _delta_r - _cur.redF(); + _delta_g = _from_g + _delta_g - _cur.greenF(); + _delta_b = _from_b + _delta_b - _cur.blueF(); + _delta_a = _from_a + _delta_a - _cur.alphaF(); + _from_r = _cur.redF(); + _from_g = _cur.greenF(); + _from_b = _cur.blueF(); + _from_a = _cur.alphaF(); + } + const QColor ¤t() const { + return _cur; + } + void update(const float64 &dt, transition func) { + _cur.setRedF(_from_r + (*func)(_delta_r, dt)); + _cur.setGreenF(_from_g + (*func)(_delta_g, dt)); + _cur.setBlueF(_from_b + (*func)(_delta_b, dt)); + _cur.setAlphaF(_from_a + (*func)(_delta_a, dt)); + } + void finish() { + _cur.setRedF(_from_r + _delta_r); + _cur.setGreenF(_from_g + _delta_g); + _cur.setBlueF(_from_b + _delta_b); + _cur.setAlphaF(_from_a + _delta_a); + _from_r = _cur.redF(); + _from_g = _cur.greenF(); + _from_b = _cur.blueF(); + _from_a = _cur.alphaF(); + _delta_r = _delta_g = _delta_b = _delta_a = 0; + } + + private: + + QColor _cur; + float64 _from_r, _from_g, _from_b, _from_a, _delta_r, _delta_g, _delta_b, _delta_a; + }; + + void start(Animated *obj); + void stop(Animated *obj); + + void startManager(); + void stopManager(); + +}; + +class Animated { +public: + + Animated() : animInProcess(false), animStarted(0) { + } + + virtual bool animStep(float64 ms) = 0; + + void animReset() { + animStarted = float64(getms()); + } + + virtual ~Animated() { + if (animating()) { + anim::stop(this); + } + } + + bool animating() const { + return animInProcess; + } + +private: + + float64 animStarted; + bool animInProcess; + friend class AnimationManager; + +}; + +class AnimationManager : public QObject { +Q_OBJECT + +public: + + AnimationManager() : timer(this), iterating(false) { + timer.setSingleShot(false); + connect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); + } + + void start(Animated *obj) { + obj->animReset(); + if (iterating) { + toStart.insert(obj); + if (!toStop.isEmpty()) { + toStop.remove(obj); + } + } else { + if (!objs.size()) { + timer.start(7); + } + objs.insert(obj); + } + obj->animInProcess = true; + } + + void stop(Animated *obj) { + if (iterating) { + toStop.insert(obj); + if (!toStart.isEmpty()) { + toStart.insert(obj); + } + } else { + AnimObjs::iterator i = objs.find(obj); + if (i != objs.cend()) { + objs.erase(i); + if (!objs.size()) { + timer.stop(); + } + } + } + obj->animInProcess = false; + } + +public slots: + void timeout() { + iterating = true; + float64 ms = float64(getms()); + for (AnimObjs::iterator i = objs.begin(), e = objs.end(); i != e; ) { + Animated *obj = *i; + if (!obj->animStep(ms - obj->animStarted)) { + i = objs.erase(i); + obj->animInProcess = false; + } else { + ++i; + } + } + iterating = false; + if (!toStart.isEmpty()) { + for (AnimObjs::iterator i = toStart.begin(), e = toStart.end(); i != e; ++i) { + objs.insert(*i); + } + toStart.clear(); + } + if (!toStop.isEmpty()) { + for (AnimObjs::iterator i = toStop.begin(), e = toStop.end(); i != e; ++i) { + objs.remove(*i); + } + toStop.clear(); + } + if (!objs.size()) { + timer.stop(); + } + } + +private: + + typedef QSet AnimObjs; + AnimObjs objs; + AnimObjs toStart; + AnimObjs toStop; + QTimer timer; + bool iterating; + +}; diff --git a/Telegram/SourceFiles/gui/boxshadow.cpp b/Telegram/SourceFiles/gui/boxshadow.cpp new file mode 100644 index 000000000..c3751bb13 --- /dev/null +++ b/Telegram/SourceFiles/gui/boxshadow.cpp @@ -0,0 +1,74 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" + +#include "boxshadow.h" + +BoxShadow::BoxShadow(const style::rect &topLeft) : _size(topLeft.width()) { + QImage cornersImage(_size * 2, _size * 2, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&cornersImage); + p.drawPixmap(QPoint(0, 0), App::sprite(), topLeft); + } + uchar *bits = cornersImage.bits(); + if (bits) { + for ( + quint32 *p = (quint32*)bits, *end = (quint32*)(bits + cornersImage.byteCount()); + p < end; + ++p + ) { + *p = (*p ^ 0x00ffffff) << 24; + } + } + { + QPainter p(&cornersImage); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.drawImage(0, _size, cornersImage.mirrored(), 0, _size, _size, _size); + } + { + QPainter p(&cornersImage); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.drawImage(_size, 0, cornersImage.mirrored(true, false), _size, 0, _size, _size * 2); + } + _corners = QPixmap::fromImage(cornersImage); + _colors.reserve(_size); + uchar prev = 0; + for (int32 i = 0; i < _size; ++i) { + uchar a = (cornersImage.pixel(QPoint(i, _size - 1)) >> 24); + if (a < prev) break; + + _colors.push_back(style::color(0, 0, 0, a)); + prev = a; + } +} + +void BoxShadow::paint(QPainter &p, const QRect &box, const QPoint &shift, int32 flags) { + int32 count = _colors.size(), minus = _size - count + 1; + bool left = (flags & Left), top = (flags & Top), right = (flags & Right), bottom = (flags & Bottom); + if (left && top) p.drawPixmap(box.left() - _size + minus + shift.x(), box.top() - _size + minus + shift.y(), _corners, 0, 0, _size, _size); + if (right && top) p.drawPixmap(box.right() - minus + 1 + shift.x(), box.top() - _size + minus + shift.y(), _corners, _size, 0, _size, _size); + if (right && bottom) p.drawPixmap(box.right() - minus + 1 + shift.x(), box.bottom() - minus + 1 + shift.y(), _corners, _size, _size, _size, _size); + if (left && bottom) p.drawPixmap(box.left() - _size + minus + shift.x(), box.bottom() - minus + 1 + shift.y(), _corners, 0, _size, _size, _size); + for (int32 i = 1; i <= count; ++i) { + p.setPen(_colors[i - 1]->p); + if (top) p.drawLine(box.left() + (left ? minus : 0) + shift.x(), box.top() - count + i + shift.y(), box.right() - (right ? minus : 0) + shift.x(), box.top() - count + i + shift.y()); + if (right) p.drawLine(box.right() + count - i + shift.x(), box.top() + (top ? minus : 0) + shift.y(), box.right() + count - i + shift.x(), box.bottom() - (bottom ? minus : 0) + shift.y()); + if (bottom) p.drawLine(box.right() - (right ? minus : 0) + shift.x(), box.bottom() + count - i + shift.y(), box.left() + (left ? minus : 0) + shift.x(), box.bottom() + count - i + shift.y()); + if (left) p.drawLine(box.left() - count + i + shift.x(), box.bottom() - (bottom ? minus : 0) + shift.y(), box.left() - count + i + shift.x(), box.top() + (top ? minus : 0) + shift.y()); + } +} diff --git a/Telegram/SourceFiles/gui/boxshadow.h b/Telegram/SourceFiles/gui/boxshadow.h new file mode 100644 index 000000000..345b6a7f5 --- /dev/null +++ b/Telegram/SourceFiles/gui/boxshadow.h @@ -0,0 +1,40 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +class BoxShadow { +public: + + enum { + Left = 1, + Top = 2, + Right = 4, + Bottom = 8 + }; + + BoxShadow(const style::rect &topLeft); + + void paint(QPainter &p, const QRect &box, const QPoint &shift = QPoint(0, 1), int32 flags = Left | Top | Right | Bottom); + +private: + + int32 _size; + QPixmap _corners; + QVector _colors; + +}; diff --git a/Telegram/SourceFiles/gui/button.cpp b/Telegram/SourceFiles/gui/button.cpp new file mode 100644 index 000000000..5d87a716d --- /dev/null +++ b/Telegram/SourceFiles/gui/button.cpp @@ -0,0 +1,113 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "button.h" + +Button::Button(QWidget *parent) : TWidget(parent), _state(StateNone), _acceptBoth(false) { +} + +void Button::leaveEvent(QEvent *e) { + if (_state & StateDown) return; + + if (_state & StateOver) { + int oldState = _state; + _state &= ~StateOver; + emit stateChanged(oldState, ButtonByHover); + } + setMouseTracking(false); + return TWidget::leaveEvent(e); +} + +void Button::enterEvent(QEvent *e) { + if (!(_state & StateOver)) { + int oldState = _state; + _state |= StateOver; + emit stateChanged(oldState, ButtonByHover); + } + setMouseTracking(true); + return TWidget::enterEvent(e); +} + +void Button::setAcceptBoth(bool acceptBoth) { + _acceptBoth = acceptBoth; +} + +void Button::mousePressEvent(QMouseEvent *e) { + if (_acceptBoth || e->buttons() & Qt::LeftButton) { + if (!(_state & StateOver)) { + enterEvent(0); + } + if (!(_state & StateDown)) { + int oldState = _state; + _state |= StateDown; + emit stateChanged(oldState, ButtonByPress); + + e->accept(); + } + } +} + +void Button::mouseMoveEvent(QMouseEvent *e) { + if (rect().contains(e->pos())) { + if (!(_state & StateOver)) { + int oldState = _state; + _state |= StateOver; + emit stateChanged(oldState, ButtonByHover); + } + } else { + if (_state & StateOver) { + int oldState = _state; + _state &= ~StateOver; + emit stateChanged(oldState, ButtonByHover); + } + } +} + +void Button::mouseReleaseEvent(QMouseEvent *e) { + if (_state & StateDown) { + int oldState = _state; + _state &= ~StateDown; + emit stateChanged(oldState, ButtonByPress); + if (oldState & StateOver) { + emit clicked(); + } else { + leaveEvent(e); + } + } +} + +void Button::setDisabled(bool disabled) { + int oldState = _state; + if (disabled && !(_state & StateDisabled)) { + _state |= StateDisabled; + emit stateChanged(oldState, ButtonByUser); + } else if (!disabled && (_state & StateDisabled)) { + _state &= ~StateDisabled; + emit stateChanged(oldState, ButtonByUser); + } +} + +void Button::clearState() { + int oldState = _state; + _state = StateNone; + emit stateChanged(oldState, ButtonByUser); +} + +int Button::getState() const { + return _state; +} diff --git a/Telegram/SourceFiles/gui/button.h b/Telegram/SourceFiles/gui/button.h new file mode 100644 index 000000000..51843613e --- /dev/null +++ b/Telegram/SourceFiles/gui/button.h @@ -0,0 +1,68 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "gui/twidget.h" + +typedef enum { + ButtonByUser = 0x00, // by clearState() call + ButtonByPress = 0x01, + ButtonByHover = 0x02, +} ButtonStateChangeSource; + +class Button : public TWidget { + Q_OBJECT + +public: + Button(QWidget *parent); + + enum { + StateNone = 0x00, + StateOver = 0x01, + StateDown = 0x02, + StateDisabled = 0x04, + }; + + void mousePressEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + + void clearState(); + int getState() const; + + void setDisabled(bool disabled = true); + bool disabled() const { + return (_state & StateDisabled); + } + + void setAcceptBoth(bool acceptBoth = true); + +signals: + void clicked(); + void stateChanged(int oldState, ButtonStateChangeSource source); + +protected: + + int _state; + bool _acceptBoth; + +}; diff --git a/Telegram/SourceFiles/gui/countrycodeinput.cpp b/Telegram/SourceFiles/gui/countrycodeinput.cpp new file mode 100644 index 000000000..a42f0b4e2 --- /dev/null +++ b/Telegram/SourceFiles/gui/countrycodeinput.cpp @@ -0,0 +1,83 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" + +#include "gui/countrycodeinput.h" +#include "gui/countryinput.h" + +CountryCodeInput::CountryCodeInput(QWidget *parent, const style::flatInput &st) : FlatInput(parent, st), _nosignal(false) { + +} + +void CountryCodeInput::startErasing(QKeyEvent *e) { + setFocus(); + keyPressEvent(e); +} + +void CountryCodeInput::codeSelected(const QString &code) { + QString old(text()); + setText('+' + code); + _nosignal = true; + correctValue(0, old); + _nosignal = false; + emit changed(); +} + +void CountryCodeInput::correctValue(QKeyEvent *e, const QString &was) { + QString oldText(text()), newText, addToNumber; + int oldPos(cursorPosition()), newPos(-1), oldLen(oldText.length()), start = 0, digits = 5; + newText.reserve(oldLen + 1); + newText += '+'; + if (oldLen && oldText[0] == '+') { + ++start; + } + for (int i = start; i < oldLen; ++i) { + QChar ch(oldText[i]); + if (ch.isDigit()) { + if (!digits || !--digits) { + addToNumber += ch; + } else { + newText += ch; + } + } + if (i == oldPos) { + newPos = newText.length(); + } + } + if (!addToNumber.isEmpty()) { + QString validCode = findValidCode(newText.mid(1)); + addToNumber = newText.mid(1 + validCode.length()) + addToNumber; + newText = '+' + validCode; + } + if (newPos < 0 || newPos > newText.length()) { + newPos = newText.length(); + } + if (newText != oldText) { + setText(newText); + if (newPos != oldPos) { + setCursorPosition(newPos); + } + } + if (!_nosignal && was != newText) { + emit codeChanged(newText.mid(1)); + } + if (!addToNumber.isEmpty()) { + emit addedToNumber(addToNumber); + } +} diff --git a/Telegram/SourceFiles/gui/countrycodeinput.h b/Telegram/SourceFiles/gui/countrycodeinput.h new file mode 100644 index 000000000..869aba541 --- /dev/null +++ b/Telegram/SourceFiles/gui/countrycodeinput.h @@ -0,0 +1,47 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "gui/flatinput.h" + +class CountryCodeInput : public FlatInput { + Q_OBJECT + +public: + + CountryCodeInput(QWidget *parent, const style::flatInput &st); + +public slots: + + void startErasing(QKeyEvent *e); + void codeSelected(const QString &code); + +signals: + + void codeChanged(const QString &code); + void addedToNumber(const QString &added); + +protected: + + void correctValue(QKeyEvent *e, const QString &was); + +private: + + bool _nosignal; + +}; diff --git a/Telegram/SourceFiles/gui/countryinput.cpp b/Telegram/SourceFiles/gui/countryinput.cpp new file mode 100644 index 000000000..477c7ed85 --- /dev/null +++ b/Telegram/SourceFiles/gui/countryinput.cpp @@ -0,0 +1,608 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" +#include "lang.h" + +#include "application.h" +#include "gui/countryinput.h" +#include "gui/scrollarea.h" + +namespace { + + struct CountryInfo { + CountryInfo(const char *_name, const char *_iso2, const char *_code) : name(_name), iso2(_iso2), code(_code) { + } + const char *name, *iso2, *code; + }; + +#include "countries.h" + + typedef QHash CountriesByCode; + typedef QHash CountriesByISO2; + typedef QList CountriesFiltered; + typedef QVector CountriesIds; + typedef QHash CountriesByLetter; + typedef QVector CountryNames; + typedef QVector CountriesNames; + + CountriesByCode countriesByCode; + CountriesByISO2 countriesByISO2; + CountriesFiltered countriesFiltered, countriesAll, *countriesNow = &countriesAll; + CountriesByLetter countriesByLetter; + CountriesNames countriesNames; + + QString lastFilter, lastValidISO; + int countriesCount = sizeof(countries) / sizeof(countries[0]); + + void initCountries() { + if (countriesByCode.size()) return; + + countriesByCode.reserve(countriesCount); + countriesByISO2.reserve(countriesCount); + for (int i = 0; i < countriesCount; ++i) { + const CountryInfo *info(countries + i); + countriesByCode.insert(info->code, info); + CountriesByISO2::const_iterator already = countriesByISO2.constFind(info->iso2); + if (already != countriesByISO2.cend()) { + QString badISO = info->iso2; + badISO; + } + countriesByISO2.insert(info->iso2, info); + } + countriesAll.reserve(countriesCount); + countriesFiltered.reserve(countriesCount); + countriesNames.resize(countriesCount); + } +} + +QString findValidCode(QString fullCode) { + while (fullCode.length()) { + CountriesByCode::const_iterator i = countriesByCode.constFind(fullCode); + if (i != countriesByCode.cend()) { + return (*i)->code; + } + fullCode = fullCode.mid(0, fullCode.length() - 1); + } + return ""; +} + +CountryInput::CountryInput(QWidget *parent, const style::countryInput &st) : QWidget(parent), _st(st), _active(false), _select(0), _text(lang(lng_country_code)) { + initCountries(); + + resize(_st.width, _st.height + _st.ptrSize.height()); + QImage trImage(_st.ptrSize.width(), _st.ptrSize.height(), QImage::Format_ARGB32_Premultiplied); + { + static const QPoint trPoints[3] = { + QPoint(0, 0), + QPoint(_st.ptrSize.width(), 0), + QPoint(qCeil(trImage.width() / 2.), trImage.height()) + }; + QPainter p(&trImage); + p.setRenderHint(QPainter::Antialiasing); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(0, 0, trImage.width(), trImage.height(), st::transparent->b); + + p.setPen(Qt::NoPen); + p.setBrush(_st.bgColor->b); + p.drawPolygon(trPoints, 3); + } + _arrow = QPixmap::fromImage(trImage); + _inner = QRect(0, 0, _st.width, _st.height); + _arrowRect = QRect((st::inpIntroCountryCode.width - _arrow.width() - 1) / 2, _st.height, _arrow.width(), _arrow.height()); +} + +void CountryInput::paintEvent(QPaintEvent *e) { + QPainter p(this); + + p.fillRect(_inner, _st.bgColor->b); + p.drawPixmap(_arrowRect.x(), _arrowRect.top(), _arrow); + + p.setFont(_st.font->f); + + p.drawText(rect().marginsRemoved(_st.textMrg), _text, QTextOption(_st.align)); +} + +void CountryInput::mouseMoveEvent(QMouseEvent *e) { + bool newActive = _inner.contains(e->pos()) || _arrowRect.contains(e->pos()); + if (_active != newActive) { + _active = newActive; + setCursor(_active ? style::cur_pointer : style::cur_default); + } +} + +void CountryInput::mousePressEvent(QMouseEvent *e) { + mouseMoveEvent(e); + if (_active) { + Window *w = App::wnd(); + if (w->focusWidget()) w->focusWidget()->clearFocus(); + if (_select) { + _select->hide(); + _select->deleteLater(); + } + _select = new CountrySelect(); + connect(_select, SIGNAL(countryChosen(const QString &)), this, SLOT(onChooseCountry(const QString &))); + connect(_select, SIGNAL(countryFinished()), this, SLOT(onFinishCountry())); + } +} + +void CountryInput::enterEvent(QEvent *e) { + setMouseTracking(true); +} + +void CountryInput::leaveEvent(QEvent *e) { + setMouseTracking(false); + _active = false; + setCursor(style::cur_default); +} + +void CountryInput::onChooseCode(const QString &code) { + if (_select) { + _select->hide(); + _select->deleteLater(); + _select = 0; + emit selectClosed(); + } + if (code.length()) { + CountriesByCode::const_iterator i = countriesByCode.constFind(code); + if (i != countriesByCode.cend()) { + const CountryInfo *info = *i; + lastValidISO = info->iso2; + setText(QString::fromUtf8(info->name)); + } else { + setText(lang(lng_bad_country_code)); + } + } else { + setText(lang(lng_country_code)); + } + update(); +} + +bool CountryInput::onChooseCountry(const QString &iso) { + CountriesByISO2::const_iterator i = countriesByISO2.constFind(iso); + const CountryInfo *info = (i == countriesByISO2.cend()) ? 0 : (*i); + + if (info) { + lastValidISO = info->iso2; + setText(QString::fromUtf8(info->name)); + emit codeChanged(info->code); + update(); + return true; + } + return false; +} + +void CountryInput::onFinishCountry() { + if (_select) { + _select->hide(); + _select->deleteLater(); + _select = 0; + emit selectClosed(); + } +} + +void CountryInput::setText(const QString &newText) { + _text = _st.font->m.elidedText(newText, Qt::ElideRight, width() - _st.textMrg.left() - _st.textMrg.right()); +} + +CountryInput::~CountryInput() { + delete _select; +} + +CountryList::CountryList(QWidget *parent, const style::countryList &st) : QWidget(parent), _sel(0), _mouseSel(false), + _st(st) { + CountriesByISO2::const_iterator l = countriesByISO2.constFind(lastValidISO); + bool seenLastValid = false; + int already = countriesAll.size(); + + countriesByLetter.clear(); + const CountryInfo *lastValid = (l == countriesByISO2.cend()) ? 0 : (*l); + for (int i = 0; i < countriesCount; ++i) { + const CountryInfo *ins = lastValid ? (i ? (countries + i - (seenLastValid ? 0 : 1)) : lastValid) : (countries + i); + if (lastValid && i && ins == lastValid) { + seenLastValid = true; + ++ins; + } + if (already > i) { + countriesAll[i] = ins; + } else { + countriesAll.push_back(ins); + } + + QStringList namesList = QString::fromUtf8(ins->name).toLower().split(QRegularExpression("[\\s\\-]"), QString::SkipEmptyParts); + CountryNames &names(countriesNames[i]); + int l = namesList.size(); + names.resize(0); + names.reserve(l); + for (int j = 0, l = namesList.size(); j < l; ++j) { + QString name = namesList[j].trimmed(); + if (!name.length()) continue; + + QChar ch = name[0]; + CountriesIds &v(countriesByLetter[ch]); + if (v.isEmpty() || v.back() != i) { + v.push_back(i); + } + + names.push_back(name); + } + } + + lastFilter = ""; + resetList(); +} + +void CountryList::resetList() { + countriesNow = &countriesAll; + if (lastFilter.length()) { + QChar first = lastFilter[0].toLower(); + CountriesIds &ids(countriesByLetter[first]); + + QStringList filterList = lastFilter.split(QRegularExpression("[\\s\\-]"), QString::SkipEmptyParts); + int l = filterList.size(); + + CountryNames filter; + filter.reserve(l); + for (int i = 0; i < l; ++i) { + QString filterName = filterList[i].trimmed(); + if (!filterName.length()) continue; + filter.push_back(filterName); + } + CountryNames::const_iterator fb = filter.cbegin(), fe = filter.cend(), fi; + + countriesFiltered.clear(); + for (CountriesIds::const_iterator i = ids.cbegin(), e = ids.cend(); i != e; ++i) { + int index = *i; + CountryNames &names(countriesNames[index]); + CountryNames::const_iterator nb = names.cbegin(), ne = names.cend(), ni; + for (fi = fb; fi != fe; ++fi) { + QString filterName(*fi); + for (ni = nb; ni != ne; ++ni) { + if ((*ni).indexOf(*fi) == 0) { + break; + } + } + if (ni == ne) { + break; + } + } + if (fi == fe) { + countriesFiltered.push_back(countriesAll[index]); + } + } + countriesNow = &countriesFiltered; + } + resize(width(), countriesNow->length() ? (countriesNow->length() * _st.rowHeight + 2 * _st.verticalMargin) : parentWidget()->height()); + setSelected(0); +} + +void CountryList::paintEvent(QPaintEvent *e) { + QRect r(e->rect()); + bool trivial = (rect() == r); + + QPainter p(this); + if (!trivial) { + p.setClipRect(r); + } + + int l = countriesNow->size(); + if (l) { + int from = (r.top() > _st.verticalMargin) ? (r.top() - _st.verticalMargin) / _st.rowHeight : 0, to = from + r.height() / _st.rowHeight + 1; + if (to >= l) { + if (from >= l) return; + to = l; + } + p.setFont(_st.font->f); + QRectF textRect(_st.margin + _st.borderMargin, _st.verticalMargin + from * _st.rowHeight, width() - 2 * _st.margin - 2 * _st.borderMargin, _st.rowHeight - _st.borderWidth); + for (int i = from; i < to; ++i) { + bool sel = (i == _sel); + if (sel) { + p.fillRect(_st.borderMargin, _st.verticalMargin + i * _st.rowHeight, width() - 2 * _st.borderMargin, _st.rowHeight, _st.bgHovered->b); + } + p.setFont(_st.font->f); + p.setPen(_st.color->p); + p.drawText(textRect, _st.font->m.elidedText(QString::fromUtf8((*countriesNow)[i]->name), Qt::ElideRight, width() - 2 * _st.margin - _st.codeWidth), QTextOption(style::al_left)); + p.setFont(_st.codeFont->f); + p.setPen(_st.codeColor->p); + p.drawText(textRect, QString("+") + (*countriesNow)[i]->code, QTextOption(style::al_right)); + textRect.setBottom(textRect.bottom() + _st.rowHeight); + textRect.setTop(textRect.top() + _st.rowHeight); + } + } else { + p.setFont(_st.notFoundFont->f); + p.setPen(_st.notFoundColor->p); + p.drawText(r, lang(lng_country_none), QTextOption(style::al_center)); + } +} + +void CountryList::mouseMoveEvent(QMouseEvent *e) { + _mouseSel = true; + _mousePos = mapToGlobal(e->pos()); + onUpdateSelected(true); +} + +void CountryList::onUpdateSelected(bool force) { + QPoint p(mapFromGlobal(_mousePos)); + if (!force && !rect().contains(p) || !_mouseSel) return; + + int newSelected = p.y(); + newSelected = (newSelected > _st.verticalMargin) ? (newSelected - _st.verticalMargin) / _st.rowHeight : 0; + int l = countriesNow->size(); + + if (newSelected >= l) newSelected = l - 1; + if (newSelected < 0) newSelected = 0; + if (newSelected != _sel) { + _sel = newSelected; + update(); + } +} + +void CountryList::mousePressEvent(QMouseEvent *e) { + _mouseSel = true; + _mousePos = mapToGlobal(e->pos()); + onUpdateSelected(true); + + emit countrySelected(); +} + +void CountryList::enterEvent(QEvent *e) { + setMouseTracking(true); +} + +void CountryList::leaveEvent(QEvent *e) { + setMouseTracking(false); +} + +void CountryList::updateFiltered() { + resetList(); +} + +void CountryList::onParentGeometryChanged() { + _mousePos = QCursor::pos(); + if (rect().contains(mapFromGlobal(_mousePos))) { + setMouseTracking(true); + onUpdateSelected(true); + } +} + +void CountryList::selectSkip(int delta) { + setSelected(_sel + delta); +} + +void CountryList::selectSkipPage(int h, int delta) { + setSelected(_sel + delta * (h / int(_st.rowHeight) - 1)); +} + +void CountryList::setSelected(int newSelected) { + _mouseSel = false; + if (newSelected >= countriesNow->size()) { + newSelected = countriesNow->size() - 1; + } + if (newSelected < 0) { + newSelected = 0; + } + _sel = newSelected; + emit mustScrollTo(_sel * _st.rowHeight, (_sel + 1) * _st.rowHeight); + update(); +} + +QString CountryList::getSelectedCountry() const { + if (lastFilter.length()) { + if (_sel < countriesFiltered.size()) { + return countriesFiltered[_sel]->iso2; + } else { + return ""; + } + } + return countriesAll[_sel]->iso2; +} + +CountrySelect::CountrySelect() : QWidget(App::wnd()), + _scroll(this, st::scrollCountries), _list(&_scroll), + _filter(this, st::inpCountry, lang(lng_country_ph)), + _doneButton(this, lang(lng_country_done), st::btnSelectDone), + _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), + _innerLeft(0), _innerTop(0), _innerWidth(0), _innerHeight(0), _result("none"), + a_alpha(0), a_bgAlpha(0), a_coord(st::countriesSlideShift), _shadow(st::boxShadow) { + setGeometry(App::wnd()->rect()); + + App::wnd()->topWidget(this); + + connect(App::wnd(), SIGNAL(resized(const QSize &)), this, SLOT(onParentResize(const QSize &))); + connect(&_doneButton, SIGNAL(clicked()), this, SLOT(onCountryChoose())); + connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCountryCancel())); + connect(&_scroll, SIGNAL(scrollFinished()), this, SLOT(onScrollFinished())); + connect(&_scroll, SIGNAL(geometryChanged()), &_list, SLOT(onParentGeometryChanged())); + connect(&_scroll, SIGNAL(scrolled()), &_list, SLOT(onUpdateSelected())); + connect(&_list, SIGNAL(countrySelected()), this, SLOT(onCountryChoose())); + connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate())); + connect(&_list, SIGNAL(mustScrollTo(int, int)), &_scroll, SLOT(scrollToY(int, int))); + + show(); + setFocus(); + _scroll.setWidget(&_list); + _scroll.setFocusPolicy(Qt::NoFocus); + + prepareAnimation(0); +} + +void CountrySelect::prepareAnimation(int to) { + if (to) { + if (_result == "none") _result = ""; + a_alpha.start(0); + af_alpha = st::countriesAlphaHideFunc; + a_bgAlpha.start(0); + af_bgAlpha = st::countriesBackHideFunc; + a_coord.start(to * st::countriesSlideShift); + af_coord = st::countriesHideFunc; + } else { + _result = "none"; + a_alpha.start(1); + af_alpha = st::countriesAlphaShowFunc; + a_bgAlpha.start(1); + af_bgAlpha = st::countriesBackShowFunc; + a_coord.start(0); + af_coord = st::countriesShowFunc; + } + _cache = grab(QRect(_innerLeft, _innerTop, _innerWidth, _innerHeight)); + _scroll.hide(); + _doneButton.hide(); + _cancelButton.hide(); + _filter.hide(); + anim::start(this); +} + +void CountrySelect::paintEvent(QPaintEvent *e) { + bool trivial = (rect() == e->rect()); + + QPainter p(this); + if (!trivial) { + p.setClipRect(e->rect()); + } + p.setOpacity(st::layerAlpha * a_bgAlpha.current()); + p.fillRect(rect(), st::layerBG->b); + if (animating()) { + p.setOpacity(a_alpha.current()); + p.drawPixmap(a_coord.current() + _innerLeft, _innerTop, _cache); + } else { + p.setOpacity(1); + + QRect inner(_innerLeft, _innerTop, _innerWidth, _innerHeight); + _shadow.paint(p, inner); + if (trivial || e->rect().intersects(inner)) { + // fill bg + p.fillRect(inner, st::white->b); + + // paint shadows + p.fillRect(_innerLeft, _innerTop + st::participantFilter.height, _innerWidth, st::scrollDef.topsh, st::scrollDef.shColor->b); + + // paint button sep + p.setPen(st::btnSelectSep->p); + p.drawLine(_innerLeft + st::btnSelectCancel.width, _innerTop + _innerHeight - st::btnSelectCancel.height, _innerLeft + st::btnSelectCancel.width, _innerTop + _innerHeight - 1); + + // draw box title / text + p.setPen(st::black->p); + p.setFont(st::addContactTitleFont->f); + p.drawText(_innerLeft + st::addContactTitlePos.x(), _innerTop + st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_country_select)); + } + } +} + +void CountrySelect::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + onCountryCancel(); + } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { + onCountryChoose(); + } else if (e->key() == Qt::Key_Down) { + _list.selectSkip(1); + } else if (e->key() == Qt::Key_Up) { + _list.selectSkip(-1); + } else if (e->key() == Qt::Key_PageDown) { + _list.selectSkipPage(_scroll.height(), 1); + } else if (e->key() == Qt::Key_PageUp) { + _list.selectSkipPage(_scroll.height(), -1); + } +} + +void CountrySelect::onFilterUpdate() { + QString newFilter(_filter.text().trimmed().toLower()); + if (newFilter != lastFilter) { + lastFilter = newFilter; + _list.updateFiltered(); + } +} + +void CountrySelect::resizeEvent(QResizeEvent *e) { + if (width() != e->oldSize().width()) { + _innerWidth = st::newGroupNamePadding.left() + _filter.width() + st::newGroupNamePadding.right(); + _innerLeft = (width() - _innerWidth) / 2; + + _list.resize(_innerWidth, _list.height()); + } + if (height() != e->oldSize().height()) { + _innerTop = st::introSelectDelta; + _innerHeight = height() - _innerTop - st::introSelectDelta; + if (_innerHeight > st::introSelectMaxHeight) { + _innerHeight = st::introSelectMaxHeight; + _innerTop = (height() - _innerHeight) / 2; + } + } + + _filter.move(_innerLeft + st::newGroupNamePadding.left(), _innerTop + st::contactsAdd.height + st::newGroupNamePadding.top()); + int32 scrollTop = _filter.y() + _filter.height() + st::newGroupNamePadding.bottom(); + int32 scrollHeight = _innerHeight - st::contactsAdd.height - st::newGroupNamePadding.top() - _filter.height() - st::newGroupNamePadding.bottom() - _cancelButton.height(); + _scroll.setGeometry(_innerLeft, scrollTop, _innerWidth, scrollHeight); + + int btnTop = scrollTop + scrollHeight; + _cancelButton.move(_innerLeft, btnTop); + _doneButton.move(_innerLeft + _innerWidth - _doneButton.width(), btnTop); +} + +bool CountrySelect::animStep(float64 ms) { + float64 dt = ms / st::countriesSlideDuration; + bool res = true; + if (dt >= 1) { + a_alpha.finish(); + a_bgAlpha.finish(); + a_coord.finish(); + _cache = QPixmap(); + _scroll.show(); + _doneButton.show(); + _cancelButton.show(); + _filter.show(); + _filter.setFocus(); + if (_result != "none") { + QTimer::singleShot(0, this, SIGNAL(countryFinished())); + } + res = false; + } else { + a_alpha.update(dt, af_alpha); + a_bgAlpha.update(dt, af_bgAlpha); + a_coord.update(dt, af_coord); + } + update(); + return res; +} + +void CountrySelect::onParentResize(const QSize &newSize) { + resize(App::wnd()->size()); +} + +void CountrySelect::onCountryCancel() { + finish(""); +} + +void CountrySelect::onCountryChoose() { + finish(_list.getSelectedCountry()); +} + +void CountrySelect::finish(const QString &res) { + _result = res; + prepareAnimation(_result.length() ? -1 : 1); + emit countryChosen(_result); +} + +void CountrySelect::onScrollFinished() { + _filter.setFocus(); +} + +CountrySelect::~CountrySelect() { + if (App::wnd()) { + App::wnd()->noTopWidget(this); + } +} diff --git a/Telegram/SourceFiles/gui/countryinput.h b/Telegram/SourceFiles/gui/countryinput.h new file mode 100644 index 000000000..a2c51a095 --- /dev/null +++ b/Telegram/SourceFiles/gui/countryinput.h @@ -0,0 +1,162 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "style.h" + +#include "gui/flatinput.h" +#include "gui/scrollarea.h" +#include "gui/flatbutton.h" +#include "gui/boxshadow.h" + +QString findValidCode(QString fullCode); + +class CountrySelect; + +class CountryInput : public QWidget { + Q_OBJECT + +public: + + CountryInput(QWidget *parent, const style::countryInput &st); + + void paintEvent(QPaintEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + + ~CountryInput(); + +public slots: + + void onChooseCode(const QString &code); + bool onChooseCountry(const QString &country); + void onFinishCountry(); + +signals: + + void codeChanged(const QString &code); + void selectClosed(); + +private: + + void setText(const QString &newText); + + QPixmap _arrow; + QRect _inner, _arrowRect; + style::countryInput _st; + bool _active; + QString _text; + + CountrySelect *_select; + +}; + +class CountryList : public QWidget { + Q_OBJECT + +public: + + CountryList(QWidget *parent, const style::countryList &st = st::countryList); + + void paintEvent(QPaintEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + + void selectSkip(int delta); + void selectSkipPage(int h, int delta); + + void updateFiltered(); + + QString getSelectedCountry() const; + +public slots: + + void onUpdateSelected(bool force = false); + void onParentGeometryChanged(); + +signals: + + void countrySelected(); + void mustScrollTo(int scrollToTop, int scrollToBottom); + +private: + + void resetList(); + void setSelected(int newSelected); + + int _sel; + style::countryList _st; + QPoint _mousePos; + + bool _mouseSel; + +}; + +class CountrySelect : public QWidget, public Animated { + Q_OBJECT + +public: + + CountrySelect(); + + void paintEvent(QPaintEvent *e); + void keyPressEvent(QKeyEvent *e); + void resizeEvent(QResizeEvent *e); + + bool animStep(float64 ms); + + ~CountrySelect(); + +signals: + + void countryChosen(const QString &country = QString()); + void countryFinished(); + +public slots: + + void onParentResize(const QSize &newSize); + void onCountryChoose(); + void onCountryCancel(); + void onScrollFinished(); + void onFilterUpdate(); + +private: + + void finish(const QString &res); + void prepareAnimation(int to); + + QString _result; + FlatInput _filter; + ScrollArea _scroll; + CountryList _list; + FlatButton _doneButton, _cancelButton; + int32 _innerLeft, _innerTop, _innerWidth, _innerHeight; + + anim::fvalue a_alpha, a_bgAlpha; + anim::ivalue a_coord; + anim::transition af_alpha, af_bgAlpha, af_coord; + QPixmap _cache; + + BoxShadow _shadow; + +}; diff --git a/Telegram/SourceFiles/gui/emoji_config.cpp b/Telegram/SourceFiles/gui/emoji_config.cpp new file mode 100644 index 000000000..8d313f193 --- /dev/null +++ b/Telegram/SourceFiles/gui/emoji_config.cpp @@ -0,0 +1,5567 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "gui/emoji_config.h" + +namespace { + EmojiData *emojis = 0; + char emojisData[sizeof(EmojiData) * 845]; +} + +void initEmoji() { + EmojiData *toFill = emojis = (EmojiData*)emojisData; + + switch (cScale()) { + + case dbisOne: + new (toFill++) EmojiData(176, 0, 169, 0, 1); + new (toFill++) EmojiData(192, 0, 174, 0, 1); + new (toFill++) EmojiData(208, 0, 8252, 0, 1); + new (toFill++) EmojiData(224, 0, 8265, 0, 1); + new (toFill++) EmojiData(240, 0, 8482, 0, 1); + new (toFill++) EmojiData(256, 0, 8505, 0, 1); + new (toFill++) EmojiData(272, 0, 8596, 0, 1); + new (toFill++) EmojiData(288, 0, 8597, 0, 1); + new (toFill++) EmojiData(304, 0, 8598, 0, 1); + new (toFill++) EmojiData(320, 0, 8599, 0, 1); + new (toFill++) EmojiData(336, 0, 8600, 0, 1); + new (toFill++) EmojiData(352, 0, 8601, 0, 1); + new (toFill++) EmojiData(368, 0, 8617, 0, 1); + new (toFill++) EmojiData(384, 0, 8618, 0, 1); + new (toFill++) EmojiData(400, 0, 8986, 0, 1); + new (toFill++) EmojiData(416, 0, 8987, 0, 1); + new (toFill++) EmojiData(432, 0, 9193, 0, 1); + new (toFill++) EmojiData(448, 0, 9194, 0, 1); + new (toFill++) EmojiData(464, 0, 9195, 0, 1); + new (toFill++) EmojiData(480, 0, 9196, 0, 1); + new (toFill++) EmojiData(496, 0, 9200, 0, 1); + new (toFill++) EmojiData(512, 0, 9203, 0, 1); + new (toFill++) EmojiData(528, 0, 9410, 0, 1); + new (toFill++) EmojiData(544, 0, 9642, 0, 1); + new (toFill++) EmojiData(560, 0, 9643, 0, 1); + new (toFill++) EmojiData(576, 0, 9654, 0, 1); + new (toFill++) EmojiData(592, 0, 9664, 0, 1); + new (toFill++) EmojiData(608, 0, 9723, 0, 1); + new (toFill++) EmojiData(624, 0, 9724, 0, 1); + new (toFill++) EmojiData(0, 16, 9725, 0, 1); + new (toFill++) EmojiData(16, 16, 9726, 0, 1); + new (toFill++) EmojiData(32, 16, 9728, 0, 1); + new (toFill++) EmojiData(48, 16, 9729, 0, 1); + new (toFill++) EmojiData(64, 16, 9742, 0, 1); + new (toFill++) EmojiData(80, 16, 9745, 0, 1); + new (toFill++) EmojiData(96, 16, 9748, 0, 1); + new (toFill++) EmojiData(112, 16, 9749, 0, 1); + new (toFill++) EmojiData(128, 16, 9757, 0, 1); + new (toFill++) EmojiData(144, 16, 9786, 0, 1); + new (toFill++) EmojiData(160, 16, 9800, 0, 1); + new (toFill++) EmojiData(176, 16, 9801, 0, 1); + new (toFill++) EmojiData(192, 16, 9802, 0, 1); + new (toFill++) EmojiData(208, 16, 9803, 0, 1); + new (toFill++) EmojiData(224, 16, 9804, 0, 1); + new (toFill++) EmojiData(240, 16, 9805, 0, 1); + new (toFill++) EmojiData(256, 16, 9806, 0, 1); + new (toFill++) EmojiData(272, 16, 9807, 0, 1); + new (toFill++) EmojiData(288, 16, 9808, 0, 1); + new (toFill++) EmojiData(304, 16, 9809, 0, 1); + new (toFill++) EmojiData(320, 16, 9810, 0, 1); + new (toFill++) EmojiData(336, 16, 9811, 0, 1); + new (toFill++) EmojiData(352, 16, 9824, 0, 1); + new (toFill++) EmojiData(368, 16, 9827, 0, 1); + new (toFill++) EmojiData(384, 16, 9829, 0, 1); + new (toFill++) EmojiData(400, 16, 9830, 0, 1); + new (toFill++) EmojiData(416, 16, 9832, 0, 1); + new (toFill++) EmojiData(432, 16, 9851, 0, 1); + new (toFill++) EmojiData(448, 16, 9855, 0, 1); + new (toFill++) EmojiData(464, 16, 9875, 0, 1); + new (toFill++) EmojiData(480, 16, 9888, 0, 1); + new (toFill++) EmojiData(496, 16, 9889, 0, 1); + new (toFill++) EmojiData(512, 16, 9898, 0, 1); + new (toFill++) EmojiData(528, 16, 9899, 0, 1); + new (toFill++) EmojiData(544, 16, 9917, 0, 1); + new (toFill++) EmojiData(560, 16, 9918, 0, 1); + new (toFill++) EmojiData(576, 16, 9924, 0, 1); + new (toFill++) EmojiData(592, 16, 9925, 0, 1); + new (toFill++) EmojiData(608, 16, 9934, 0, 1); + new (toFill++) EmojiData(624, 16, 9940, 0, 1); + new (toFill++) EmojiData(0, 32, 9962, 0, 1); + new (toFill++) EmojiData(16, 32, 9970, 0, 1); + new (toFill++) EmojiData(32, 32, 9971, 0, 1); + new (toFill++) EmojiData(48, 32, 9973, 0, 1); + new (toFill++) EmojiData(64, 32, 9978, 0, 1); + new (toFill++) EmojiData(80, 32, 9981, 0, 1); + new (toFill++) EmojiData(96, 32, 9986, 0, 1); + new (toFill++) EmojiData(112, 32, 9989, 0, 1); + new (toFill++) EmojiData(128, 32, 9992, 0, 1); + new (toFill++) EmojiData(144, 32, 9993, 0, 1); + new (toFill++) EmojiData(160, 32, 9994, 0, 1); + new (toFill++) EmojiData(176, 32, 9995, 0, 1); + new (toFill++) EmojiData(192, 32, 9996, 0, 1); + new (toFill++) EmojiData(208, 32, 9999, 0, 1); + new (toFill++) EmojiData(224, 32, 10002, 0, 1); + new (toFill++) EmojiData(240, 32, 10004, 0, 1); + new (toFill++) EmojiData(256, 32, 10006, 0, 1); + new (toFill++) EmojiData(272, 32, 10024, 0, 1); + new (toFill++) EmojiData(288, 32, 10035, 0, 1); + new (toFill++) EmojiData(304, 32, 10036, 0, 1); + new (toFill++) EmojiData(320, 32, 10052, 0, 1); + new (toFill++) EmojiData(336, 32, 10055, 0, 1); + new (toFill++) EmojiData(352, 32, 10060, 0, 1); + new (toFill++) EmojiData(368, 32, 10062, 0, 1); + new (toFill++) EmojiData(384, 32, 10067, 0, 1); + new (toFill++) EmojiData(400, 32, 10068, 0, 1); + new (toFill++) EmojiData(416, 32, 10069, 0, 1); + new (toFill++) EmojiData(432, 32, 10071, 0, 1); + new (toFill++) EmojiData(448, 32, 10084, 0, 1); + new (toFill++) EmojiData(464, 32, 10133, 0, 1); + new (toFill++) EmojiData(480, 32, 10134, 0, 1); + new (toFill++) EmojiData(496, 32, 10135, 0, 1); + new (toFill++) EmojiData(512, 32, 10145, 0, 1); + new (toFill++) EmojiData(528, 32, 10160, 0, 1); + new (toFill++) EmojiData(544, 32, 10175, 0, 1); + new (toFill++) EmojiData(560, 32, 10548, 0, 1); + new (toFill++) EmojiData(576, 32, 10549, 0, 1); + new (toFill++) EmojiData(592, 32, 11013, 0, 1); + new (toFill++) EmojiData(608, 32, 11014, 0, 1); + new (toFill++) EmojiData(624, 32, 11015, 0, 1); + new (toFill++) EmojiData(0, 48, 11035, 0, 1); + new (toFill++) EmojiData(16, 48, 11036, 0, 1); + new (toFill++) EmojiData(32, 48, 11088, 0, 1); + new (toFill++) EmojiData(48, 48, 11093, 0, 1); + new (toFill++) EmojiData(64, 48, 12336, 0, 1); + new (toFill++) EmojiData(80, 48, 12349, 0, 1); + new (toFill++) EmojiData(96, 48, 12951, 0, 1); + new (toFill++) EmojiData(112, 48, 12953, 0, 1); + new (toFill++) EmojiData(0, 0, 2302179, 0, 2); + new (toFill++) EmojiData(16, 0, 3154147, 0, 2); + new (toFill++) EmojiData(32, 0, 3219683, 0, 2); + new (toFill++) EmojiData(48, 0, 3285219, 0, 2); + new (toFill++) EmojiData(64, 0, 3350755, 0, 2); + new (toFill++) EmojiData(80, 0, 3416291, 0, 2); + new (toFill++) EmojiData(96, 0, 3481827, 0, 2); + new (toFill++) EmojiData(112, 0, 3547363, 0, 2); + new (toFill++) EmojiData(128, 0, 3612899, 0, 2); + new (toFill++) EmojiData(144, 0, 3678435, 0, 2); + new (toFill++) EmojiData(160, 0, 3743971, 0, 2); + new (toFill++) EmojiData(128, 48, 3627867140, 0, 2); + new (toFill++) EmojiData(144, 48, 3627867343, 0, 2); + new (toFill++) EmojiData(160, 48, 3627867504, 0, 2); + new (toFill++) EmojiData(176, 48, 3627867505, 0, 2); + new (toFill++) EmojiData(192, 48, 3627867518, 0, 2); + new (toFill++) EmojiData(208, 48, 3627867519, 0, 2); + new (toFill++) EmojiData(224, 48, 3627867534, 0, 2); + new (toFill++) EmojiData(240, 48, 3627867537, 0, 2); + new (toFill++) EmojiData(256, 48, 3627867538, 0, 2); + new (toFill++) EmojiData(272, 48, 3627867539, 0, 2); + new (toFill++) EmojiData(288, 48, 3627867540, 0, 2); + new (toFill++) EmojiData(304, 48, 3627867541, 0, 2); + new (toFill++) EmojiData(320, 48, 3627867542, 0, 2); + new (toFill++) EmojiData(336, 48, 3627867543, 0, 2); + new (toFill++) EmojiData(352, 48, 3627867544, 0, 2); + new (toFill++) EmojiData(368, 48, 3627867545, 0, 2); + new (toFill++) EmojiData(384, 48, 3627867546, 0, 2); + new (toFill++) EmojiData(400, 48, 3627867624, 3627867635, 4); + new (toFill++) EmojiData(416, 48, 3627867625, 3627867626, 4); + new (toFill++) EmojiData(432, 48, 3627867626, 3627867640, 4); + new (toFill++) EmojiData(448, 48, 3627867627, 3627867639, 4); + new (toFill++) EmojiData(464, 48, 3627867628, 3627867623, 4); + new (toFill++) EmojiData(480, 48, 3627867630, 3627867641, 4); + new (toFill++) EmojiData(496, 48, 3627867631, 3627867637, 4); + new (toFill++) EmojiData(512, 48, 3627867632, 3627867639, 4); + new (toFill++) EmojiData(528, 48, 3627867639, 3627867642, 4); + new (toFill++) EmojiData(544, 48, 3627867642, 3627867640, 4); + new (toFill++) EmojiData(560, 48, 3627867649, 0, 2); + new (toFill++) EmojiData(576, 48, 3627867650, 0, 2); + new (toFill++) EmojiData(592, 48, 3627867674, 0, 2); + new (toFill++) EmojiData(608, 48, 3627867695, 0, 2); + new (toFill++) EmojiData(624, 48, 3627867698, 0, 2); + new (toFill++) EmojiData(0, 64, 3627867699, 0, 2); + new (toFill++) EmojiData(16, 64, 3627867700, 0, 2); + new (toFill++) EmojiData(32, 64, 3627867701, 0, 2); + new (toFill++) EmojiData(48, 64, 3627867702, 0, 2); + new (toFill++) EmojiData(64, 64, 3627867703, 0, 2); + new (toFill++) EmojiData(80, 64, 3627867704, 0, 2); + new (toFill++) EmojiData(96, 64, 3627867705, 0, 2); + new (toFill++) EmojiData(112, 64, 3627867706, 0, 2); + new (toFill++) EmojiData(128, 64, 3627867728, 0, 2); + new (toFill++) EmojiData(144, 64, 3627867729, 0, 2); + new (toFill++) EmojiData(160, 64, 3627867904, 0, 2); + new (toFill++) EmojiData(176, 64, 3627867905, 0, 2); + new (toFill++) EmojiData(192, 64, 3627867906, 0, 2); + new (toFill++) EmojiData(208, 64, 3627867907, 0, 2); + new (toFill++) EmojiData(224, 64, 3627867908, 0, 2); + new (toFill++) EmojiData(240, 64, 3627867909, 0, 2); + new (toFill++) EmojiData(256, 64, 3627867910, 0, 2); + new (toFill++) EmojiData(272, 64, 3627867911, 0, 2); + new (toFill++) EmojiData(288, 64, 3627867912, 0, 2); + new (toFill++) EmojiData(304, 64, 3627867913, 0, 2); + new (toFill++) EmojiData(320, 64, 3627867914, 0, 2); + new (toFill++) EmojiData(336, 64, 3627867915, 0, 2); + new (toFill++) EmojiData(352, 64, 3627867916, 0, 2); + new (toFill++) EmojiData(368, 64, 3627867917, 0, 2); + new (toFill++) EmojiData(384, 64, 3627867918, 0, 2); + new (toFill++) EmojiData(400, 64, 3627867919, 0, 2); + new (toFill++) EmojiData(416, 64, 3627867920, 0, 2); + new (toFill++) EmojiData(432, 64, 3627867921, 0, 2); + new (toFill++) EmojiData(448, 64, 3627867922, 0, 2); + new (toFill++) EmojiData(464, 64, 3627867923, 0, 2); + new (toFill++) EmojiData(480, 64, 3627867924, 0, 2); + new (toFill++) EmojiData(496, 64, 3627867925, 0, 2); + new (toFill++) EmojiData(512, 64, 3627867926, 0, 2); + new (toFill++) EmojiData(528, 64, 3627867927, 0, 2); + new (toFill++) EmojiData(544, 64, 3627867928, 0, 2); + new (toFill++) EmojiData(560, 64, 3627867929, 0, 2); + new (toFill++) EmojiData(576, 64, 3627867930, 0, 2); + new (toFill++) EmojiData(592, 64, 3627867931, 0, 2); + new (toFill++) EmojiData(608, 64, 3627867932, 0, 2); + new (toFill++) EmojiData(624, 64, 3627867933, 0, 2); + new (toFill++) EmojiData(0, 80, 3627867934, 0, 2); + new (toFill++) EmojiData(16, 80, 3627867935, 0, 2); + new (toFill++) EmojiData(32, 80, 3627867936, 0, 2); + new (toFill++) EmojiData(48, 80, 3627867952, 0, 2); + new (toFill++) EmojiData(64, 80, 3627867953, 0, 2); + new (toFill++) EmojiData(80, 80, 3627867954, 0, 2); + new (toFill++) EmojiData(96, 80, 3627867955, 0, 2); + new (toFill++) EmojiData(112, 80, 3627867956, 0, 2); + new (toFill++) EmojiData(128, 80, 3627867957, 0, 2); + new (toFill++) EmojiData(144, 80, 3627867959, 0, 2); + new (toFill++) EmojiData(160, 80, 3627867960, 0, 2); + new (toFill++) EmojiData(176, 80, 3627867961, 0, 2); + new (toFill++) EmojiData(192, 80, 3627867962, 0, 2); + new (toFill++) EmojiData(208, 80, 3627867963, 0, 2); + new (toFill++) EmojiData(224, 80, 3627867964, 0, 2); + new (toFill++) EmojiData(240, 80, 3627867965, 0, 2); + new (toFill++) EmojiData(256, 80, 3627867966, 0, 2); + new (toFill++) EmojiData(272, 80, 3627867967, 0, 2); + new (toFill++) EmojiData(288, 80, 3627867968, 0, 2); + new (toFill++) EmojiData(304, 80, 3627867969, 0, 2); + new (toFill++) EmojiData(320, 80, 3627867970, 0, 2); + new (toFill++) EmojiData(336, 80, 3627867971, 0, 2); + new (toFill++) EmojiData(352, 80, 3627867972, 0, 2); + new (toFill++) EmojiData(368, 80, 3627867973, 0, 2); + new (toFill++) EmojiData(384, 80, 3627867974, 0, 2); + new (toFill++) EmojiData(400, 80, 3627867975, 0, 2); + new (toFill++) EmojiData(416, 80, 3627867976, 0, 2); + new (toFill++) EmojiData(432, 80, 3627867977, 0, 2); + new (toFill++) EmojiData(448, 80, 3627867978, 0, 2); + new (toFill++) EmojiData(464, 80, 3627867979, 0, 2); + new (toFill++) EmojiData(480, 80, 3627867980, 0, 2); + new (toFill++) EmojiData(496, 80, 3627867981, 0, 2); + new (toFill++) EmojiData(512, 80, 3627867982, 0, 2); + new (toFill++) EmojiData(528, 80, 3627867983, 0, 2); + new (toFill++) EmojiData(544, 80, 3627867984, 0, 2); + new (toFill++) EmojiData(560, 80, 3627867985, 0, 2); + new (toFill++) EmojiData(576, 80, 3627867986, 0, 2); + new (toFill++) EmojiData(592, 80, 3627867987, 0, 2); + new (toFill++) EmojiData(608, 80, 3627867988, 0, 2); + new (toFill++) EmojiData(624, 80, 3627867989, 0, 2); + new (toFill++) EmojiData(0, 96, 3627867990, 0, 2); + new (toFill++) EmojiData(16, 96, 3627867991, 0, 2); + new (toFill++) EmojiData(32, 96, 3627867992, 0, 2); + new (toFill++) EmojiData(48, 96, 3627867993, 0, 2); + new (toFill++) EmojiData(64, 96, 3627867994, 0, 2); + new (toFill++) EmojiData(80, 96, 3627867995, 0, 2); + new (toFill++) EmojiData(96, 96, 3627867996, 0, 2); + new (toFill++) EmojiData(112, 96, 3627867997, 0, 2); + new (toFill++) EmojiData(128, 96, 3627867998, 0, 2); + new (toFill++) EmojiData(144, 96, 3627867999, 0, 2); + new (toFill++) EmojiData(160, 96, 3627868000, 0, 2); + new (toFill++) EmojiData(176, 96, 3627868001, 0, 2); + new (toFill++) EmojiData(192, 96, 3627868002, 0, 2); + new (toFill++) EmojiData(208, 96, 3627868003, 0, 2); + new (toFill++) EmojiData(224, 96, 3627868004, 0, 2); + new (toFill++) EmojiData(240, 96, 3627868005, 0, 2); + new (toFill++) EmojiData(256, 96, 3627868006, 0, 2); + new (toFill++) EmojiData(272, 96, 3627868007, 0, 2); + new (toFill++) EmojiData(288, 96, 3627868008, 0, 2); + new (toFill++) EmojiData(304, 96, 3627868009, 0, 2); + new (toFill++) EmojiData(320, 96, 3627868010, 0, 2); + new (toFill++) EmojiData(336, 96, 3627868011, 0, 2); + new (toFill++) EmojiData(352, 96, 3627868012, 0, 2); + new (toFill++) EmojiData(368, 96, 3627868013, 0, 2); + new (toFill++) EmojiData(384, 96, 3627868014, 0, 2); + new (toFill++) EmojiData(400, 96, 3627868015, 0, 2); + new (toFill++) EmojiData(416, 96, 3627868016, 0, 2); + new (toFill++) EmojiData(432, 96, 3627868017, 0, 2); + new (toFill++) EmojiData(448, 96, 3627868018, 0, 2); + new (toFill++) EmojiData(464, 96, 3627868019, 0, 2); + new (toFill++) EmojiData(480, 96, 3627868020, 0, 2); + new (toFill++) EmojiData(496, 96, 3627868021, 0, 2); + new (toFill++) EmojiData(512, 96, 3627868022, 0, 2); + new (toFill++) EmojiData(528, 96, 3627868023, 0, 2); + new (toFill++) EmojiData(544, 96, 3627868024, 0, 2); + new (toFill++) EmojiData(560, 96, 3627868025, 0, 2); + new (toFill++) EmojiData(576, 96, 3627868026, 0, 2); + new (toFill++) EmojiData(592, 96, 3627868027, 0, 2); + new (toFill++) EmojiData(608, 96, 3627868028, 0, 2); + new (toFill++) EmojiData(624, 96, 3627868032, 0, 2); + new (toFill++) EmojiData(0, 112, 3627868033, 0, 2); + new (toFill++) EmojiData(16, 112, 3627868034, 0, 2); + new (toFill++) EmojiData(32, 112, 3627868035, 0, 2); + new (toFill++) EmojiData(48, 112, 3627868036, 0, 2); + new (toFill++) EmojiData(64, 112, 3627868037, 0, 2); + new (toFill++) EmojiData(80, 112, 3627868038, 0, 2); + new (toFill++) EmojiData(96, 112, 3627868039, 0, 2); + new (toFill++) EmojiData(112, 112, 3627868040, 0, 2); + new (toFill++) EmojiData(128, 112, 3627868041, 0, 2); + new (toFill++) EmojiData(144, 112, 3627868042, 0, 2); + new (toFill++) EmojiData(160, 112, 3627868043, 0, 2); + new (toFill++) EmojiData(176, 112, 3627868044, 0, 2); + new (toFill++) EmojiData(192, 112, 3627868045, 0, 2); + new (toFill++) EmojiData(208, 112, 3627868046, 0, 2); + new (toFill++) EmojiData(224, 112, 3627868047, 0, 2); + new (toFill++) EmojiData(240, 112, 3627868048, 0, 2); + new (toFill++) EmojiData(256, 112, 3627868049, 0, 2); + new (toFill++) EmojiData(272, 112, 3627868050, 0, 2); + new (toFill++) EmojiData(288, 112, 3627868051, 0, 2); + new (toFill++) EmojiData(304, 112, 3627868064, 0, 2); + new (toFill++) EmojiData(320, 112, 3627868065, 0, 2); + new (toFill++) EmojiData(336, 112, 3627868066, 0, 2); + new (toFill++) EmojiData(352, 112, 3627868067, 0, 2); + new (toFill++) EmojiData(368, 112, 3627868068, 0, 2); + new (toFill++) EmojiData(384, 112, 3627868069, 0, 2); + new (toFill++) EmojiData(400, 112, 3627868070, 0, 2); + new (toFill++) EmojiData(416, 112, 3627868071, 0, 2); + new (toFill++) EmojiData(432, 112, 3627868072, 0, 2); + new (toFill++) EmojiData(448, 112, 3627868073, 0, 2); + new (toFill++) EmojiData(464, 112, 3627868074, 0, 2); + new (toFill++) EmojiData(480, 112, 3627868075, 0, 2); + new (toFill++) EmojiData(496, 112, 3627868076, 0, 2); + new (toFill++) EmojiData(512, 112, 3627868077, 0, 2); + new (toFill++) EmojiData(528, 112, 3627868078, 0, 2); + new (toFill++) EmojiData(544, 112, 3627868079, 0, 2); + new (toFill++) EmojiData(560, 112, 3627868080, 0, 2); + new (toFill++) EmojiData(576, 112, 3627868081, 0, 2); + new (toFill++) EmojiData(592, 112, 3627868082, 0, 2); + new (toFill++) EmojiData(608, 112, 3627868083, 0, 2); + new (toFill++) EmojiData(624, 112, 3627868084, 0, 2); + new (toFill++) EmojiData(0, 128, 3627868085, 0, 2); + new (toFill++) EmojiData(16, 128, 3627868086, 0, 2); + new (toFill++) EmojiData(32, 128, 3627868087, 0, 2); + new (toFill++) EmojiData(48, 128, 3627868088, 0, 2); + new (toFill++) EmojiData(64, 128, 3627868089, 0, 2); + new (toFill++) EmojiData(80, 128, 3627868090, 0, 2); + new (toFill++) EmojiData(96, 128, 3627868091, 0, 2); + new (toFill++) EmojiData(112, 128, 3627868092, 0, 2); + new (toFill++) EmojiData(128, 128, 3627868093, 0, 2); + new (toFill++) EmojiData(144, 128, 3627868094, 0, 2); + new (toFill++) EmojiData(160, 128, 3627868095, 0, 2); + new (toFill++) EmojiData(176, 128, 3627868096, 0, 2); + new (toFill++) EmojiData(192, 128, 3627868097, 0, 2); + new (toFill++) EmojiData(208, 128, 3627868098, 0, 2); + new (toFill++) EmojiData(224, 128, 3627868099, 0, 2); + new (toFill++) EmojiData(240, 128, 3627868100, 0, 2); + new (toFill++) EmojiData(256, 128, 3627868102, 0, 2); + new (toFill++) EmojiData(272, 128, 3627868103, 0, 2); + new (toFill++) EmojiData(288, 128, 3627868104, 0, 2); + new (toFill++) EmojiData(304, 128, 3627868105, 0, 2); + new (toFill++) EmojiData(320, 128, 3627868106, 0, 2); + new (toFill++) EmojiData(336, 128, 3627868128, 0, 2); + new (toFill++) EmojiData(352, 128, 3627868129, 0, 2); + new (toFill++) EmojiData(368, 128, 3627868130, 0, 2); + new (toFill++) EmojiData(384, 128, 3627868131, 0, 2); + new (toFill++) EmojiData(400, 128, 3627868132, 0, 2); + new (toFill++) EmojiData(416, 128, 3627868133, 0, 2); + new (toFill++) EmojiData(432, 128, 3627868134, 0, 2); + new (toFill++) EmojiData(448, 128, 3627868135, 0, 2); + new (toFill++) EmojiData(464, 128, 3627868136, 0, 2); + new (toFill++) EmojiData(480, 128, 3627868137, 0, 2); + new (toFill++) EmojiData(496, 128, 3627868138, 0, 2); + new (toFill++) EmojiData(512, 128, 3627868139, 0, 2); + new (toFill++) EmojiData(528, 128, 3627868140, 0, 2); + new (toFill++) EmojiData(544, 128, 3627868141, 0, 2); + new (toFill++) EmojiData(560, 128, 3627868142, 0, 2); + new (toFill++) EmojiData(576, 128, 3627868143, 0, 2); + new (toFill++) EmojiData(592, 128, 3627868144, 0, 2); + new (toFill++) EmojiData(608, 128, 3627932672, 0, 2); + new (toFill++) EmojiData(624, 128, 3627932673, 0, 2); + new (toFill++) EmojiData(0, 144, 3627932674, 0, 2); + new (toFill++) EmojiData(16, 144, 3627932675, 0, 2); + new (toFill++) EmojiData(32, 144, 3627932676, 0, 2); + new (toFill++) EmojiData(48, 144, 3627932677, 0, 2); + new (toFill++) EmojiData(64, 144, 3627932678, 0, 2); + new (toFill++) EmojiData(80, 144, 3627932679, 0, 2); + new (toFill++) EmojiData(96, 144, 3627932680, 0, 2); + new (toFill++) EmojiData(112, 144, 3627932681, 0, 2); + new (toFill++) EmojiData(128, 144, 3627932682, 0, 2); + new (toFill++) EmojiData(144, 144, 3627932683, 0, 2); + new (toFill++) EmojiData(160, 144, 3627932684, 0, 2); + new (toFill++) EmojiData(176, 144, 3627932685, 0, 2); + new (toFill++) EmojiData(192, 144, 3627932686, 0, 2); + new (toFill++) EmojiData(208, 144, 3627932687, 0, 2); + new (toFill++) EmojiData(224, 144, 3627932688, 0, 2); + new (toFill++) EmojiData(240, 144, 3627932689, 0, 2); + new (toFill++) EmojiData(256, 144, 3627932690, 0, 2); + new (toFill++) EmojiData(272, 144, 3627932691, 0, 2); + new (toFill++) EmojiData(288, 144, 3627932692, 0, 2); + new (toFill++) EmojiData(304, 144, 3627932693, 0, 2); + new (toFill++) EmojiData(320, 144, 3627932694, 0, 2); + new (toFill++) EmojiData(336, 144, 3627932695, 0, 2); + new (toFill++) EmojiData(352, 144, 3627932696, 0, 2); + new (toFill++) EmojiData(368, 144, 3627932697, 0, 2); + new (toFill++) EmojiData(384, 144, 3627932698, 0, 2); + new (toFill++) EmojiData(400, 144, 3627932699, 0, 2); + new (toFill++) EmojiData(416, 144, 3627932700, 0, 2); + new (toFill++) EmojiData(432, 144, 3627932701, 0, 2); + new (toFill++) EmojiData(448, 144, 3627932702, 0, 2); + new (toFill++) EmojiData(464, 144, 3627932703, 0, 2); + new (toFill++) EmojiData(480, 144, 3627932704, 0, 2); + new (toFill++) EmojiData(496, 144, 3627932705, 0, 2); + new (toFill++) EmojiData(512, 144, 3627932706, 0, 2); + new (toFill++) EmojiData(528, 144, 3627932707, 0, 2); + new (toFill++) EmojiData(544, 144, 3627932708, 0, 2); + new (toFill++) EmojiData(560, 144, 3627932709, 0, 2); + new (toFill++) EmojiData(576, 144, 3627932710, 0, 2); + new (toFill++) EmojiData(592, 144, 3627932711, 0, 2); + new (toFill++) EmojiData(608, 144, 3627932712, 0, 2); + new (toFill++) EmojiData(624, 144, 3627932713, 0, 2); + new (toFill++) EmojiData(0, 160, 3627932714, 0, 2); + new (toFill++) EmojiData(16, 160, 3627932715, 0, 2); + new (toFill++) EmojiData(32, 160, 3627932716, 0, 2); + new (toFill++) EmojiData(48, 160, 3627932717, 0, 2); + new (toFill++) EmojiData(64, 160, 3627932718, 0, 2); + new (toFill++) EmojiData(80, 160, 3627932719, 0, 2); + new (toFill++) EmojiData(96, 160, 3627932720, 0, 2); + new (toFill++) EmojiData(112, 160, 3627932721, 0, 2); + new (toFill++) EmojiData(128, 160, 3627932722, 0, 2); + new (toFill++) EmojiData(144, 160, 3627932723, 0, 2); + new (toFill++) EmojiData(160, 160, 3627932724, 0, 2); + new (toFill++) EmojiData(176, 160, 3627932725, 0, 2); + new (toFill++) EmojiData(192, 160, 3627932726, 0, 2); + new (toFill++) EmojiData(208, 160, 3627932727, 0, 2); + new (toFill++) EmojiData(224, 160, 3627932728, 0, 2); + new (toFill++) EmojiData(240, 160, 3627932729, 0, 2); + new (toFill++) EmojiData(256, 160, 3627932730, 0, 2); + new (toFill++) EmojiData(272, 160, 3627932731, 0, 2); + new (toFill++) EmojiData(288, 160, 3627932732, 0, 2); + new (toFill++) EmojiData(304, 160, 3627932733, 0, 2); + new (toFill++) EmojiData(320, 160, 3627932734, 0, 2); + new (toFill++) EmojiData(336, 160, 3627932736, 0, 2); + new (toFill++) EmojiData(352, 160, 3627932738, 0, 2); + new (toFill++) EmojiData(368, 160, 3627932739, 0, 2); + new (toFill++) EmojiData(384, 160, 3627932740, 0, 2); + new (toFill++) EmojiData(400, 160, 3627932741, 0, 2); + new (toFill++) EmojiData(416, 160, 3627932742, 0, 2); + new (toFill++) EmojiData(432, 160, 3627932743, 0, 2); + new (toFill++) EmojiData(448, 160, 3627932744, 0, 2); + new (toFill++) EmojiData(464, 160, 3627932745, 0, 2); + new (toFill++) EmojiData(480, 160, 3627932746, 0, 2); + new (toFill++) EmojiData(496, 160, 3627932747, 0, 2); + new (toFill++) EmojiData(512, 160, 3627932748, 0, 2); + new (toFill++) EmojiData(528, 160, 3627932749, 0, 2); + new (toFill++) EmojiData(544, 160, 3627932750, 0, 2); + new (toFill++) EmojiData(560, 160, 3627932751, 0, 2); + new (toFill++) EmojiData(576, 160, 3627932752, 0, 2); + new (toFill++) EmojiData(592, 160, 3627932753, 0, 2); + new (toFill++) EmojiData(608, 160, 3627932754, 0, 2); + new (toFill++) EmojiData(624, 160, 3627932755, 0, 2); + new (toFill++) EmojiData(0, 176, 3627932756, 0, 2); + new (toFill++) EmojiData(16, 176, 3627932757, 0, 2); + new (toFill++) EmojiData(32, 176, 3627932758, 0, 2); + new (toFill++) EmojiData(48, 176, 3627932759, 0, 2); + new (toFill++) EmojiData(64, 176, 3627932760, 0, 2); + new (toFill++) EmojiData(80, 176, 3627932761, 0, 2); + new (toFill++) EmojiData(96, 176, 3627932762, 0, 2); + new (toFill++) EmojiData(112, 176, 3627932763, 0, 2); + new (toFill++) EmojiData(128, 176, 3627932764, 0, 2); + new (toFill++) EmojiData(144, 176, 3627932765, 0, 2); + new (toFill++) EmojiData(160, 176, 3627932766, 0, 2); + new (toFill++) EmojiData(176, 176, 3627932767, 0, 2); + new (toFill++) EmojiData(192, 176, 3627932768, 0, 2); + new (toFill++) EmojiData(208, 176, 3627932769, 0, 2); + new (toFill++) EmojiData(224, 176, 3627932770, 0, 2); + new (toFill++) EmojiData(240, 176, 3627932771, 0, 2); + new (toFill++) EmojiData(256, 176, 3627932772, 0, 2); + new (toFill++) EmojiData(272, 176, 3627932773, 0, 2); + new (toFill++) EmojiData(288, 176, 3627932774, 0, 2); + new (toFill++) EmojiData(304, 176, 3627932775, 0, 2); + new (toFill++) EmojiData(320, 176, 3627932776, 0, 2); + new (toFill++) EmojiData(336, 176, 3627932777, 0, 2); + new (toFill++) EmojiData(352, 176, 3627932778, 0, 2); + new (toFill++) EmojiData(368, 176, 3627932779, 0, 2); + new (toFill++) EmojiData(384, 176, 3627932780, 0, 2); + new (toFill++) EmojiData(400, 176, 3627932781, 0, 2); + new (toFill++) EmojiData(416, 176, 3627932782, 0, 2); + new (toFill++) EmojiData(432, 176, 3627932783, 0, 2); + new (toFill++) EmojiData(448, 176, 3627932784, 0, 2); + new (toFill++) EmojiData(464, 176, 3627932785, 0, 2); + new (toFill++) EmojiData(480, 176, 3627932786, 0, 2); + new (toFill++) EmojiData(496, 176, 3627932787, 0, 2); + new (toFill++) EmojiData(512, 176, 3627932788, 0, 2); + new (toFill++) EmojiData(528, 176, 3627932789, 0, 2); + new (toFill++) EmojiData(544, 176, 3627932790, 0, 2); + new (toFill++) EmojiData(560, 176, 3627932791, 0, 2); + new (toFill++) EmojiData(576, 176, 3627932792, 0, 2); + new (toFill++) EmojiData(592, 176, 3627932793, 0, 2); + new (toFill++) EmojiData(608, 176, 3627932794, 0, 2); + new (toFill++) EmojiData(624, 176, 3627932795, 0, 2); + new (toFill++) EmojiData(0, 192, 3627932796, 0, 2); + new (toFill++) EmojiData(16, 192, 3627932797, 0, 2); + new (toFill++) EmojiData(32, 192, 3627932798, 0, 2); + new (toFill++) EmojiData(48, 192, 3627932799, 0, 2); + new (toFill++) EmojiData(64, 192, 3627932800, 0, 2); + new (toFill++) EmojiData(80, 192, 3627932801, 0, 2); + new (toFill++) EmojiData(96, 192, 3627932802, 0, 2); + new (toFill++) EmojiData(112, 192, 3627932803, 0, 2); + new (toFill++) EmojiData(128, 192, 3627932804, 0, 2); + new (toFill++) EmojiData(144, 192, 3627932805, 0, 2); + new (toFill++) EmojiData(160, 192, 3627932806, 0, 2); + new (toFill++) EmojiData(176, 192, 3627932807, 0, 2); + new (toFill++) EmojiData(192, 192, 3627932808, 0, 2); + new (toFill++) EmojiData(208, 192, 3627932809, 0, 2); + new (toFill++) EmojiData(224, 192, 3627932810, 0, 2); + new (toFill++) EmojiData(240, 192, 3627932811, 0, 2); + new (toFill++) EmojiData(256, 192, 3627932812, 0, 2); + new (toFill++) EmojiData(272, 192, 3627932813, 0, 2); + new (toFill++) EmojiData(288, 192, 3627932814, 0, 2); + new (toFill++) EmojiData(304, 192, 3627932815, 0, 2); + new (toFill++) EmojiData(320, 192, 3627932816, 0, 2); + new (toFill++) EmojiData(336, 192, 3627932817, 0, 2); + new (toFill++) EmojiData(352, 192, 3627932818, 0, 2); + new (toFill++) EmojiData(368, 192, 3627932819, 0, 2); + new (toFill++) EmojiData(384, 192, 3627932820, 0, 2); + new (toFill++) EmojiData(400, 192, 3627932821, 0, 2); + new (toFill++) EmojiData(416, 192, 3627932822, 0, 2); + new (toFill++) EmojiData(432, 192, 3627932823, 0, 2); + new (toFill++) EmojiData(448, 192, 3627932824, 0, 2); + new (toFill++) EmojiData(464, 192, 3627932825, 0, 2); + new (toFill++) EmojiData(480, 192, 3627932826, 0, 2); + new (toFill++) EmojiData(496, 192, 3627932827, 0, 2); + new (toFill++) EmojiData(512, 192, 3627932828, 0, 2); + new (toFill++) EmojiData(528, 192, 3627932829, 0, 2); + new (toFill++) EmojiData(544, 192, 3627932830, 0, 2); + new (toFill++) EmojiData(560, 192, 3627932831, 0, 2); + new (toFill++) EmojiData(576, 192, 3627932832, 0, 2); + new (toFill++) EmojiData(592, 192, 3627932833, 0, 2); + new (toFill++) EmojiData(608, 192, 3627932834, 0, 2); + new (toFill++) EmojiData(624, 192, 3627932835, 0, 2); + new (toFill++) EmojiData(0, 208, 3627932836, 0, 2); + new (toFill++) EmojiData(16, 208, 3627932837, 0, 2); + new (toFill++) EmojiData(32, 208, 3627932838, 0, 2); + new (toFill++) EmojiData(48, 208, 3627932839, 0, 2); + new (toFill++) EmojiData(64, 208, 3627932840, 0, 2); + new (toFill++) EmojiData(80, 208, 3627932841, 0, 2); + new (toFill++) EmojiData(96, 208, 3627932842, 0, 2); + new (toFill++) EmojiData(112, 208, 3627932843, 0, 2); + new (toFill++) EmojiData(128, 208, 3627932844, 0, 2); + new (toFill++) EmojiData(144, 208, 3627932845, 0, 2); + new (toFill++) EmojiData(160, 208, 3627932846, 0, 2); + new (toFill++) EmojiData(176, 208, 3627932847, 0, 2); + new (toFill++) EmojiData(192, 208, 3627932848, 0, 2); + new (toFill++) EmojiData(208, 208, 3627932849, 0, 2); + new (toFill++) EmojiData(224, 208, 3627932850, 0, 2); + new (toFill++) EmojiData(240, 208, 3627932851, 0, 2); + new (toFill++) EmojiData(256, 208, 3627932852, 0, 2); + new (toFill++) EmojiData(272, 208, 3627932853, 0, 2); + new (toFill++) EmojiData(288, 208, 3627932854, 0, 2); + new (toFill++) EmojiData(304, 208, 3627932855, 0, 2); + new (toFill++) EmojiData(320, 208, 3627932856, 0, 2); + new (toFill++) EmojiData(336, 208, 3627932857, 0, 2); + new (toFill++) EmojiData(352, 208, 3627932858, 0, 2); + new (toFill++) EmojiData(368, 208, 3627932859, 0, 2); + new (toFill++) EmojiData(384, 208, 3627932860, 0, 2); + new (toFill++) EmojiData(400, 208, 3627932861, 0, 2); + new (toFill++) EmojiData(416, 208, 3627932862, 0, 2); + new (toFill++) EmojiData(432, 208, 3627932863, 0, 2); + new (toFill++) EmojiData(448, 208, 3627932864, 0, 2); + new (toFill++) EmojiData(464, 208, 3627932865, 0, 2); + new (toFill++) EmojiData(480, 208, 3627932866, 0, 2); + new (toFill++) EmojiData(496, 208, 3627932867, 0, 2); + new (toFill++) EmojiData(512, 208, 3627932868, 0, 2); + new (toFill++) EmojiData(528, 208, 3627932869, 0, 2); + new (toFill++) EmojiData(544, 208, 3627932870, 0, 2); + new (toFill++) EmojiData(560, 208, 3627932871, 0, 2); + new (toFill++) EmojiData(576, 208, 3627932872, 0, 2); + new (toFill++) EmojiData(592, 208, 3627932873, 0, 2); + new (toFill++) EmojiData(608, 208, 3627932874, 0, 2); + new (toFill++) EmojiData(624, 208, 3627932875, 0, 2); + new (toFill++) EmojiData(0, 224, 3627932876, 0, 2); + new (toFill++) EmojiData(16, 224, 3627932877, 0, 2); + new (toFill++) EmojiData(32, 224, 3627932878, 0, 2); + new (toFill++) EmojiData(48, 224, 3627932879, 0, 2); + new (toFill++) EmojiData(64, 224, 3627932880, 0, 2); + new (toFill++) EmojiData(80, 224, 3627932881, 0, 2); + new (toFill++) EmojiData(96, 224, 3627932882, 0, 2); + new (toFill++) EmojiData(112, 224, 3627932883, 0, 2); + new (toFill++) EmojiData(128, 224, 3627932884, 0, 2); + new (toFill++) EmojiData(144, 224, 3627932885, 0, 2); + new (toFill++) EmojiData(160, 224, 3627932886, 0, 2); + new (toFill++) EmojiData(176, 224, 3627932887, 0, 2); + new (toFill++) EmojiData(192, 224, 3627932888, 0, 2); + new (toFill++) EmojiData(208, 224, 3627932889, 0, 2); + new (toFill++) EmojiData(224, 224, 3627932890, 0, 2); + new (toFill++) EmojiData(240, 224, 3627932891, 0, 2); + new (toFill++) EmojiData(256, 224, 3627932892, 0, 2); + new (toFill++) EmojiData(272, 224, 3627932893, 0, 2); + new (toFill++) EmojiData(288, 224, 3627932894, 0, 2); + new (toFill++) EmojiData(304, 224, 3627932895, 0, 2); + new (toFill++) EmojiData(320, 224, 3627932896, 0, 2); + new (toFill++) EmojiData(336, 224, 3627932897, 0, 2); + new (toFill++) EmojiData(352, 224, 3627932898, 0, 2); + new (toFill++) EmojiData(368, 224, 3627932899, 0, 2); + new (toFill++) EmojiData(384, 224, 3627932900, 0, 2); + new (toFill++) EmojiData(400, 224, 3627932901, 0, 2); + new (toFill++) EmojiData(416, 224, 3627932902, 0, 2); + new (toFill++) EmojiData(432, 224, 3627932903, 0, 2); + new (toFill++) EmojiData(448, 224, 3627932904, 0, 2); + new (toFill++) EmojiData(464, 224, 3627932905, 0, 2); + new (toFill++) EmojiData(480, 224, 3627932906, 0, 2); + new (toFill++) EmojiData(496, 224, 3627932907, 0, 2); + new (toFill++) EmojiData(512, 224, 3627932908, 0, 2); + new (toFill++) EmojiData(528, 224, 3627932909, 0, 2); + new (toFill++) EmojiData(544, 224, 3627932910, 0, 2); + new (toFill++) EmojiData(560, 224, 3627932911, 0, 2); + new (toFill++) EmojiData(576, 224, 3627932912, 0, 2); + new (toFill++) EmojiData(592, 224, 3627932913, 0, 2); + new (toFill++) EmojiData(608, 224, 3627932914, 0, 2); + new (toFill++) EmojiData(624, 224, 3627932915, 0, 2); + new (toFill++) EmojiData(0, 240, 3627932916, 0, 2); + new (toFill++) EmojiData(16, 240, 3627932917, 0, 2); + new (toFill++) EmojiData(32, 240, 3627932918, 0, 2); + new (toFill++) EmojiData(48, 240, 3627932919, 0, 2); + new (toFill++) EmojiData(64, 240, 3627932921, 0, 2); + new (toFill++) EmojiData(80, 240, 3627932922, 0, 2); + new (toFill++) EmojiData(96, 240, 3627932923, 0, 2); + new (toFill++) EmojiData(112, 240, 3627932924, 0, 2); + new (toFill++) EmojiData(128, 240, 3627932928, 0, 2); + new (toFill++) EmojiData(144, 240, 3627932929, 0, 2); + new (toFill++) EmojiData(160, 240, 3627932930, 0, 2); + new (toFill++) EmojiData(176, 240, 3627932931, 0, 2); + new (toFill++) EmojiData(192, 240, 3627932932, 0, 2); + new (toFill++) EmojiData(208, 240, 3627932933, 0, 2); + new (toFill++) EmojiData(224, 240, 3627932934, 0, 2); + new (toFill++) EmojiData(240, 240, 3627932935, 0, 2); + new (toFill++) EmojiData(256, 240, 3627932936, 0, 2); + new (toFill++) EmojiData(272, 240, 3627932937, 0, 2); + new (toFill++) EmojiData(288, 240, 3627932938, 0, 2); + new (toFill++) EmojiData(304, 240, 3627932939, 0, 2); + new (toFill++) EmojiData(320, 240, 3627932940, 0, 2); + new (toFill++) EmojiData(336, 240, 3627932941, 0, 2); + new (toFill++) EmojiData(352, 240, 3627932942, 0, 2); + new (toFill++) EmojiData(368, 240, 3627932943, 0, 2); + new (toFill++) EmojiData(384, 240, 3627932944, 0, 2); + new (toFill++) EmojiData(400, 240, 3627932945, 0, 2); + new (toFill++) EmojiData(416, 240, 3627932946, 0, 2); + new (toFill++) EmojiData(432, 240, 3627932947, 0, 2); + new (toFill++) EmojiData(448, 240, 3627932948, 0, 2); + new (toFill++) EmojiData(464, 240, 3627932949, 0, 2); + new (toFill++) EmojiData(480, 240, 3627932950, 0, 2); + new (toFill++) EmojiData(496, 240, 3627932951, 0, 2); + new (toFill++) EmojiData(512, 240, 3627932952, 0, 2); + new (toFill++) EmojiData(528, 240, 3627932953, 0, 2); + new (toFill++) EmojiData(544, 240, 3627932954, 0, 2); + new (toFill++) EmojiData(560, 240, 3627932955, 0, 2); + new (toFill++) EmojiData(576, 240, 3627932956, 0, 2); + new (toFill++) EmojiData(592, 240, 3627932957, 0, 2); + new (toFill++) EmojiData(608, 240, 3627932958, 0, 2); + new (toFill++) EmojiData(624, 240, 3627932959, 0, 2); + new (toFill++) EmojiData(0, 256, 3627932960, 0, 2); + new (toFill++) EmojiData(16, 256, 3627932961, 0, 2); + new (toFill++) EmojiData(32, 256, 3627932962, 0, 2); + new (toFill++) EmojiData(48, 256, 3627932963, 0, 2); + new (toFill++) EmojiData(64, 256, 3627932964, 0, 2); + new (toFill++) EmojiData(80, 256, 3627932965, 0, 2); + new (toFill++) EmojiData(96, 256, 3627932966, 0, 2); + new (toFill++) EmojiData(112, 256, 3627932967, 0, 2); + new (toFill++) EmojiData(128, 256, 3627932968, 0, 2); + new (toFill++) EmojiData(144, 256, 3627932969, 0, 2); + new (toFill++) EmojiData(160, 256, 3627932970, 0, 2); + new (toFill++) EmojiData(176, 256, 3627932971, 0, 2); + new (toFill++) EmojiData(192, 256, 3627932972, 0, 2); + new (toFill++) EmojiData(208, 256, 3627932973, 0, 2); + new (toFill++) EmojiData(224, 256, 3627932974, 0, 2); + new (toFill++) EmojiData(240, 256, 3627932975, 0, 2); + new (toFill++) EmojiData(256, 256, 3627932976, 0, 2); + new (toFill++) EmojiData(272, 256, 3627932977, 0, 2); + new (toFill++) EmojiData(288, 256, 3627932978, 0, 2); + new (toFill++) EmojiData(304, 256, 3627932979, 0, 2); + new (toFill++) EmojiData(320, 256, 3627932980, 0, 2); + new (toFill++) EmojiData(336, 256, 3627932981, 0, 2); + new (toFill++) EmojiData(352, 256, 3627932982, 0, 2); + new (toFill++) EmojiData(368, 256, 3627932983, 0, 2); + new (toFill++) EmojiData(384, 256, 3627932984, 0, 2); + new (toFill++) EmojiData(400, 256, 3627932985, 0, 2); + new (toFill++) EmojiData(416, 256, 3627932986, 0, 2); + new (toFill++) EmojiData(432, 256, 3627932987, 0, 2); + new (toFill++) EmojiData(448, 256, 3627932988, 0, 2); + new (toFill++) EmojiData(464, 256, 3627932989, 0, 2); + new (toFill++) EmojiData(480, 256, 3627933008, 0, 2); + new (toFill++) EmojiData(496, 256, 3627933009, 0, 2); + new (toFill++) EmojiData(512, 256, 3627933010, 0, 2); + new (toFill++) EmojiData(528, 256, 3627933011, 0, 2); + new (toFill++) EmojiData(544, 256, 3627933012, 0, 2); + new (toFill++) EmojiData(560, 256, 3627933013, 0, 2); + new (toFill++) EmojiData(576, 256, 3627933014, 0, 2); + new (toFill++) EmojiData(592, 256, 3627933015, 0, 2); + new (toFill++) EmojiData(608, 256, 3627933016, 0, 2); + new (toFill++) EmojiData(624, 256, 3627933017, 0, 2); + new (toFill++) EmojiData(0, 272, 3627933018, 0, 2); + new (toFill++) EmojiData(16, 272, 3627933019, 0, 2); + new (toFill++) EmojiData(32, 272, 3627933020, 0, 2); + new (toFill++) EmojiData(48, 272, 3627933021, 0, 2); + new (toFill++) EmojiData(64, 272, 3627933022, 0, 2); + new (toFill++) EmojiData(80, 272, 3627933023, 0, 2); + new (toFill++) EmojiData(96, 272, 3627933024, 0, 2); + new (toFill++) EmojiData(112, 272, 3627933025, 0, 2); + new (toFill++) EmojiData(128, 272, 3627933026, 0, 2); + new (toFill++) EmojiData(144, 272, 3627933027, 0, 2); + new (toFill++) EmojiData(160, 272, 3627933028, 0, 2); + new (toFill++) EmojiData(176, 272, 3627933029, 0, 2); + new (toFill++) EmojiData(192, 272, 3627933030, 0, 2); + new (toFill++) EmojiData(208, 272, 3627933031, 0, 2); + new (toFill++) EmojiData(224, 272, 3627933179, 0, 2); + new (toFill++) EmojiData(240, 272, 3627933180, 0, 2); + new (toFill++) EmojiData(256, 272, 3627933181, 0, 2); + new (toFill++) EmojiData(272, 272, 3627933182, 0, 2); + new (toFill++) EmojiData(288, 272, 3627933183, 0, 2); + new (toFill++) EmojiData(304, 272, 3627933184, 0, 2); + new (toFill++) EmojiData(320, 272, 3627933185, 0, 2); + new (toFill++) EmojiData(336, 272, 3627933186, 0, 2); + new (toFill++) EmojiData(352, 272, 3627933187, 0, 2); + new (toFill++) EmojiData(368, 272, 3627933188, 0, 2); + new (toFill++) EmojiData(384, 272, 3627933189, 0, 2); + new (toFill++) EmojiData(400, 272, 3627933190, 0, 2); + new (toFill++) EmojiData(416, 272, 3627933191, 0, 2); + new (toFill++) EmojiData(432, 272, 3627933192, 0, 2); + new (toFill++) EmojiData(448, 272, 3627933193, 0, 2); + new (toFill++) EmojiData(464, 272, 3627933194, 0, 2); + new (toFill++) EmojiData(480, 272, 3627933195, 0, 2); + new (toFill++) EmojiData(496, 272, 3627933196, 0, 2); + new (toFill++) EmojiData(512, 272, 3627933197, 0, 2); + new (toFill++) EmojiData(528, 272, 3627933198, 0, 2); + new (toFill++) EmojiData(544, 272, 3627933199, 0, 2); + new (toFill++) EmojiData(560, 272, 3627933200, 0, 2); + new (toFill++) EmojiData(576, 272, 3627933201, 0, 2); + new (toFill++) EmojiData(592, 272, 3627933202, 0, 2); + new (toFill++) EmojiData(608, 272, 3627933203, 0, 2); + new (toFill++) EmojiData(624, 272, 3627933204, 0, 2); + new (toFill++) EmojiData(0, 288, 3627933205, 0, 2); + new (toFill++) EmojiData(16, 288, 3627933206, 0, 2); + new (toFill++) EmojiData(32, 288, 3627933207, 0, 2); + new (toFill++) EmojiData(48, 288, 3627933208, 0, 2); + new (toFill++) EmojiData(64, 288, 3627933209, 0, 2); + new (toFill++) EmojiData(80, 288, 3627933210, 0, 2); + new (toFill++) EmojiData(96, 288, 3627933211, 0, 2); + new (toFill++) EmojiData(112, 288, 3627933212, 0, 2); + new (toFill++) EmojiData(128, 288, 3627933213, 0, 2); + new (toFill++) EmojiData(144, 288, 3627933214, 0, 2); + new (toFill++) EmojiData(160, 288, 3627933215, 0, 2); + new (toFill++) EmojiData(176, 288, 3627933216, 0, 2); + new (toFill++) EmojiData(192, 288, 3627933217, 0, 2); + new (toFill++) EmojiData(208, 288, 3627933218, 0, 2); + new (toFill++) EmojiData(224, 288, 3627933219, 0, 2); + new (toFill++) EmojiData(240, 288, 3627933220, 0, 2); + new (toFill++) EmojiData(256, 288, 3627933221, 0, 2); + new (toFill++) EmojiData(272, 288, 3627933222, 0, 2); + new (toFill++) EmojiData(288, 288, 3627933223, 0, 2); + new (toFill++) EmojiData(304, 288, 3627933224, 0, 2); + new (toFill++) EmojiData(320, 288, 3627933225, 0, 2); + new (toFill++) EmojiData(336, 288, 3627933226, 0, 2); + new (toFill++) EmojiData(352, 288, 3627933227, 0, 2); + new (toFill++) EmojiData(368, 288, 3627933228, 0, 2); + new (toFill++) EmojiData(384, 288, 3627933229, 0, 2); + new (toFill++) EmojiData(400, 288, 3627933230, 0, 2); + new (toFill++) EmojiData(416, 288, 3627933231, 0, 2); + new (toFill++) EmojiData(432, 288, 3627933232, 0, 2); + new (toFill++) EmojiData(448, 288, 3627933233, 0, 2); + new (toFill++) EmojiData(464, 288, 3627933234, 0, 2); + new (toFill++) EmojiData(480, 288, 3627933235, 0, 2); + new (toFill++) EmojiData(496, 288, 3627933236, 0, 2); + new (toFill++) EmojiData(512, 288, 3627933237, 0, 2); + new (toFill++) EmojiData(528, 288, 3627933238, 0, 2); + new (toFill++) EmojiData(544, 288, 3627933239, 0, 2); + new (toFill++) EmojiData(560, 288, 3627933240, 0, 2); + new (toFill++) EmojiData(576, 288, 3627933241, 0, 2); + new (toFill++) EmojiData(592, 288, 3627933242, 0, 2); + new (toFill++) EmojiData(608, 288, 3627933243, 0, 2); + new (toFill++) EmojiData(624, 288, 3627933244, 0, 2); + new (toFill++) EmojiData(0, 304, 3627933245, 0, 2); + new (toFill++) EmojiData(16, 304, 3627933246, 0, 2); + new (toFill++) EmojiData(32, 304, 3627933247, 0, 2); + new (toFill++) EmojiData(48, 304, 3627933248, 0, 2); + new (toFill++) EmojiData(64, 304, 3627933253, 0, 2); + new (toFill++) EmojiData(80, 304, 3627933254, 0, 2); + new (toFill++) EmojiData(96, 304, 3627933255, 0, 2); + new (toFill++) EmojiData(112, 304, 3627933256, 0, 2); + new (toFill++) EmojiData(128, 304, 3627933257, 0, 2); + new (toFill++) EmojiData(144, 304, 3627933258, 0, 2); + new (toFill++) EmojiData(160, 304, 3627933259, 0, 2); + new (toFill++) EmojiData(176, 304, 3627933260, 0, 2); + new (toFill++) EmojiData(192, 304, 3627933261, 0, 2); + new (toFill++) EmojiData(208, 304, 3627933262, 0, 2); + new (toFill++) EmojiData(224, 304, 3627933263, 0, 2); + new (toFill++) EmojiData(240, 304, 3627933312, 0, 2); + new (toFill++) EmojiData(256, 304, 3627933313, 0, 2); + new (toFill++) EmojiData(272, 304, 3627933314, 0, 2); + new (toFill++) EmojiData(288, 304, 3627933315, 0, 2); + new (toFill++) EmojiData(304, 304, 3627933316, 0, 2); + new (toFill++) EmojiData(320, 304, 3627933317, 0, 2); + new (toFill++) EmojiData(336, 304, 3627933318, 0, 2); + new (toFill++) EmojiData(352, 304, 3627933319, 0, 2); + new (toFill++) EmojiData(368, 304, 3627933320, 0, 2); + new (toFill++) EmojiData(384, 304, 3627933321, 0, 2); + new (toFill++) EmojiData(400, 304, 3627933322, 0, 2); + new (toFill++) EmojiData(416, 304, 3627933323, 0, 2); + new (toFill++) EmojiData(432, 304, 3627933324, 0, 2); + new (toFill++) EmojiData(448, 304, 3627933325, 0, 2); + new (toFill++) EmojiData(464, 304, 3627933326, 0, 2); + new (toFill++) EmojiData(480, 304, 3627933327, 0, 2); + new (toFill++) EmojiData(496, 304, 3627933328, 0, 2); + new (toFill++) EmojiData(512, 304, 3627933329, 0, 2); + new (toFill++) EmojiData(528, 304, 3627933330, 0, 2); + new (toFill++) EmojiData(544, 304, 3627933331, 0, 2); + new (toFill++) EmojiData(560, 304, 3627933332, 0, 2); + new (toFill++) EmojiData(576, 304, 3627933333, 0, 2); + new (toFill++) EmojiData(592, 304, 3627933334, 0, 2); + new (toFill++) EmojiData(608, 304, 3627933335, 0, 2); + new (toFill++) EmojiData(624, 304, 3627933336, 0, 2); + new (toFill++) EmojiData(0, 320, 3627933337, 0, 2); + new (toFill++) EmojiData(16, 320, 3627933338, 0, 2); + new (toFill++) EmojiData(32, 320, 3627933339, 0, 2); + new (toFill++) EmojiData(48, 320, 3627933340, 0, 2); + new (toFill++) EmojiData(64, 320, 3627933341, 0, 2); + new (toFill++) EmojiData(80, 320, 3627933342, 0, 2); + new (toFill++) EmojiData(96, 320, 3627933343, 0, 2); + new (toFill++) EmojiData(112, 320, 3627933344, 0, 2); + new (toFill++) EmojiData(128, 320, 3627933345, 0, 2); + new (toFill++) EmojiData(144, 320, 3627933346, 0, 2); + new (toFill++) EmojiData(160, 320, 3627933347, 0, 2); + new (toFill++) EmojiData(176, 320, 3627933348, 0, 2); + new (toFill++) EmojiData(192, 320, 3627933349, 0, 2); + new (toFill++) EmojiData(208, 320, 3627933350, 0, 2); + new (toFill++) EmojiData(224, 320, 3627933351, 0, 2); + new (toFill++) EmojiData(240, 320, 3627933352, 0, 2); + new (toFill++) EmojiData(256, 320, 3627933353, 0, 2); + new (toFill++) EmojiData(272, 320, 3627933354, 0, 2); + new (toFill++) EmojiData(288, 320, 3627933355, 0, 2); + new (toFill++) EmojiData(304, 320, 3627933356, 0, 2); + new (toFill++) EmojiData(320, 320, 3627933357, 0, 2); + new (toFill++) EmojiData(336, 320, 3627933358, 0, 2); + new (toFill++) EmojiData(352, 320, 3627933359, 0, 2); + new (toFill++) EmojiData(368, 320, 3627933360, 0, 2); + new (toFill++) EmojiData(384, 320, 3627933361, 0, 2); + new (toFill++) EmojiData(400, 320, 3627933362, 0, 2); + new (toFill++) EmojiData(416, 320, 3627933363, 0, 2); + new (toFill++) EmojiData(432, 320, 3627933364, 0, 2); + new (toFill++) EmojiData(448, 320, 3627933365, 0, 2); + new (toFill++) EmojiData(464, 320, 3627933366, 0, 2); + new (toFill++) EmojiData(480, 320, 3627933367, 0, 2); + new (toFill++) EmojiData(496, 320, 3627933368, 0, 2); + new (toFill++) EmojiData(512, 320, 3627933369, 0, 2); + new (toFill++) EmojiData(528, 320, 3627933370, 0, 2); + new (toFill++) EmojiData(544, 320, 3627933371, 0, 2); + new (toFill++) EmojiData(560, 320, 3627933372, 0, 2); + new (toFill++) EmojiData(576, 320, 3627933373, 0, 2); + new (toFill++) EmojiData(592, 320, 3627933374, 0, 2); + new (toFill++) EmojiData(608, 320, 3627933375, 0, 2); + new (toFill++) EmojiData(624, 320, 3627933376, 0, 2); + new (toFill++) EmojiData(0, 336, 3627933377, 0, 2); + new (toFill++) EmojiData(16, 336, 3627933378, 0, 2); + new (toFill++) EmojiData(32, 336, 3627933379, 0, 2); + new (toFill++) EmojiData(48, 336, 3627933380, 0, 2); + new (toFill++) EmojiData(64, 336, 3627933381, 0, 2); + break; + + case dbisOneAndQuarter: + new (toFill++) EmojiData(220, 0, 169, 0, 1); + new (toFill++) EmojiData(240, 0, 174, 0, 1); + new (toFill++) EmojiData(260, 0, 8252, 0, 1); + new (toFill++) EmojiData(280, 0, 8265, 0, 1); + new (toFill++) EmojiData(300, 0, 8482, 0, 1); + new (toFill++) EmojiData(320, 0, 8505, 0, 1); + new (toFill++) EmojiData(340, 0, 8596, 0, 1); + new (toFill++) EmojiData(360, 0, 8597, 0, 1); + new (toFill++) EmojiData(380, 0, 8598, 0, 1); + new (toFill++) EmojiData(400, 0, 8599, 0, 1); + new (toFill++) EmojiData(420, 0, 8600, 0, 1); + new (toFill++) EmojiData(440, 0, 8601, 0, 1); + new (toFill++) EmojiData(460, 0, 8617, 0, 1); + new (toFill++) EmojiData(480, 0, 8618, 0, 1); + new (toFill++) EmojiData(500, 0, 8986, 0, 1); + new (toFill++) EmojiData(520, 0, 8987, 0, 1); + new (toFill++) EmojiData(540, 0, 9193, 0, 1); + new (toFill++) EmojiData(560, 0, 9194, 0, 1); + new (toFill++) EmojiData(580, 0, 9195, 0, 1); + new (toFill++) EmojiData(600, 0, 9196, 0, 1); + new (toFill++) EmojiData(620, 0, 9200, 0, 1); + new (toFill++) EmojiData(640, 0, 9203, 0, 1); + new (toFill++) EmojiData(660, 0, 9410, 0, 1); + new (toFill++) EmojiData(680, 0, 9642, 0, 1); + new (toFill++) EmojiData(700, 0, 9643, 0, 1); + new (toFill++) EmojiData(720, 0, 9654, 0, 1); + new (toFill++) EmojiData(740, 0, 9664, 0, 1); + new (toFill++) EmojiData(760, 0, 9723, 0, 1); + new (toFill++) EmojiData(780, 0, 9724, 0, 1); + new (toFill++) EmojiData(0, 20, 9725, 0, 1); + new (toFill++) EmojiData(20, 20, 9726, 0, 1); + new (toFill++) EmojiData(40, 20, 9728, 0, 1); + new (toFill++) EmojiData(60, 20, 9729, 0, 1); + new (toFill++) EmojiData(80, 20, 9742, 0, 1); + new (toFill++) EmojiData(100, 20, 9745, 0, 1); + new (toFill++) EmojiData(120, 20, 9748, 0, 1); + new (toFill++) EmojiData(140, 20, 9749, 0, 1); + new (toFill++) EmojiData(160, 20, 9757, 0, 1); + new (toFill++) EmojiData(180, 20, 9786, 0, 1); + new (toFill++) EmojiData(200, 20, 9800, 0, 1); + new (toFill++) EmojiData(220, 20, 9801, 0, 1); + new (toFill++) EmojiData(240, 20, 9802, 0, 1); + new (toFill++) EmojiData(260, 20, 9803, 0, 1); + new (toFill++) EmojiData(280, 20, 9804, 0, 1); + new (toFill++) EmojiData(300, 20, 9805, 0, 1); + new (toFill++) EmojiData(320, 20, 9806, 0, 1); + new (toFill++) EmojiData(340, 20, 9807, 0, 1); + new (toFill++) EmojiData(360, 20, 9808, 0, 1); + new (toFill++) EmojiData(380, 20, 9809, 0, 1); + new (toFill++) EmojiData(400, 20, 9810, 0, 1); + new (toFill++) EmojiData(420, 20, 9811, 0, 1); + new (toFill++) EmojiData(440, 20, 9824, 0, 1); + new (toFill++) EmojiData(460, 20, 9827, 0, 1); + new (toFill++) EmojiData(480, 20, 9829, 0, 1); + new (toFill++) EmojiData(500, 20, 9830, 0, 1); + new (toFill++) EmojiData(520, 20, 9832, 0, 1); + new (toFill++) EmojiData(540, 20, 9851, 0, 1); + new (toFill++) EmojiData(560, 20, 9855, 0, 1); + new (toFill++) EmojiData(580, 20, 9875, 0, 1); + new (toFill++) EmojiData(600, 20, 9888, 0, 1); + new (toFill++) EmojiData(620, 20, 9889, 0, 1); + new (toFill++) EmojiData(640, 20, 9898, 0, 1); + new (toFill++) EmojiData(660, 20, 9899, 0, 1); + new (toFill++) EmojiData(680, 20, 9917, 0, 1); + new (toFill++) EmojiData(700, 20, 9918, 0, 1); + new (toFill++) EmojiData(720, 20, 9924, 0, 1); + new (toFill++) EmojiData(740, 20, 9925, 0, 1); + new (toFill++) EmojiData(760, 20, 9934, 0, 1); + new (toFill++) EmojiData(780, 20, 9940, 0, 1); + new (toFill++) EmojiData(0, 40, 9962, 0, 1); + new (toFill++) EmojiData(20, 40, 9970, 0, 1); + new (toFill++) EmojiData(40, 40, 9971, 0, 1); + new (toFill++) EmojiData(60, 40, 9973, 0, 1); + new (toFill++) EmojiData(80, 40, 9978, 0, 1); + new (toFill++) EmojiData(100, 40, 9981, 0, 1); + new (toFill++) EmojiData(120, 40, 9986, 0, 1); + new (toFill++) EmojiData(140, 40, 9989, 0, 1); + new (toFill++) EmojiData(160, 40, 9992, 0, 1); + new (toFill++) EmojiData(180, 40, 9993, 0, 1); + new (toFill++) EmojiData(200, 40, 9994, 0, 1); + new (toFill++) EmojiData(220, 40, 9995, 0, 1); + new (toFill++) EmojiData(240, 40, 9996, 0, 1); + new (toFill++) EmojiData(260, 40, 9999, 0, 1); + new (toFill++) EmojiData(280, 40, 10002, 0, 1); + new (toFill++) EmojiData(300, 40, 10004, 0, 1); + new (toFill++) EmojiData(320, 40, 10006, 0, 1); + new (toFill++) EmojiData(340, 40, 10024, 0, 1); + new (toFill++) EmojiData(360, 40, 10035, 0, 1); + new (toFill++) EmojiData(380, 40, 10036, 0, 1); + new (toFill++) EmojiData(400, 40, 10052, 0, 1); + new (toFill++) EmojiData(420, 40, 10055, 0, 1); + new (toFill++) EmojiData(440, 40, 10060, 0, 1); + new (toFill++) EmojiData(460, 40, 10062, 0, 1); + new (toFill++) EmojiData(480, 40, 10067, 0, 1); + new (toFill++) EmojiData(500, 40, 10068, 0, 1); + new (toFill++) EmojiData(520, 40, 10069, 0, 1); + new (toFill++) EmojiData(540, 40, 10071, 0, 1); + new (toFill++) EmojiData(560, 40, 10084, 0, 1); + new (toFill++) EmojiData(580, 40, 10133, 0, 1); + new (toFill++) EmojiData(600, 40, 10134, 0, 1); + new (toFill++) EmojiData(620, 40, 10135, 0, 1); + new (toFill++) EmojiData(640, 40, 10145, 0, 1); + new (toFill++) EmojiData(660, 40, 10160, 0, 1); + new (toFill++) EmojiData(680, 40, 10175, 0, 1); + new (toFill++) EmojiData(700, 40, 10548, 0, 1); + new (toFill++) EmojiData(720, 40, 10549, 0, 1); + new (toFill++) EmojiData(740, 40, 11013, 0, 1); + new (toFill++) EmojiData(760, 40, 11014, 0, 1); + new (toFill++) EmojiData(780, 40, 11015, 0, 1); + new (toFill++) EmojiData(0, 60, 11035, 0, 1); + new (toFill++) EmojiData(20, 60, 11036, 0, 1); + new (toFill++) EmojiData(40, 60, 11088, 0, 1); + new (toFill++) EmojiData(60, 60, 11093, 0, 1); + new (toFill++) EmojiData(80, 60, 12336, 0, 1); + new (toFill++) EmojiData(100, 60, 12349, 0, 1); + new (toFill++) EmojiData(120, 60, 12951, 0, 1); + new (toFill++) EmojiData(140, 60, 12953, 0, 1); + new (toFill++) EmojiData(0, 0, 2302179, 0, 2); + new (toFill++) EmojiData(20, 0, 3154147, 0, 2); + new (toFill++) EmojiData(40, 0, 3219683, 0, 2); + new (toFill++) EmojiData(60, 0, 3285219, 0, 2); + new (toFill++) EmojiData(80, 0, 3350755, 0, 2); + new (toFill++) EmojiData(100, 0, 3416291, 0, 2); + new (toFill++) EmojiData(120, 0, 3481827, 0, 2); + new (toFill++) EmojiData(140, 0, 3547363, 0, 2); + new (toFill++) EmojiData(160, 0, 3612899, 0, 2); + new (toFill++) EmojiData(180, 0, 3678435, 0, 2); + new (toFill++) EmojiData(200, 0, 3743971, 0, 2); + new (toFill++) EmojiData(160, 60, 3627867140, 0, 2); + new (toFill++) EmojiData(180, 60, 3627867343, 0, 2); + new (toFill++) EmojiData(200, 60, 3627867504, 0, 2); + new (toFill++) EmojiData(220, 60, 3627867505, 0, 2); + new (toFill++) EmojiData(240, 60, 3627867518, 0, 2); + new (toFill++) EmojiData(260, 60, 3627867519, 0, 2); + new (toFill++) EmojiData(280, 60, 3627867534, 0, 2); + new (toFill++) EmojiData(300, 60, 3627867537, 0, 2); + new (toFill++) EmojiData(320, 60, 3627867538, 0, 2); + new (toFill++) EmojiData(340, 60, 3627867539, 0, 2); + new (toFill++) EmojiData(360, 60, 3627867540, 0, 2); + new (toFill++) EmojiData(380, 60, 3627867541, 0, 2); + new (toFill++) EmojiData(400, 60, 3627867542, 0, 2); + new (toFill++) EmojiData(420, 60, 3627867543, 0, 2); + new (toFill++) EmojiData(440, 60, 3627867544, 0, 2); + new (toFill++) EmojiData(460, 60, 3627867545, 0, 2); + new (toFill++) EmojiData(480, 60, 3627867546, 0, 2); + new (toFill++) EmojiData(500, 60, 3627867624, 3627867635, 4); + new (toFill++) EmojiData(520, 60, 3627867625, 3627867626, 4); + new (toFill++) EmojiData(540, 60, 3627867626, 3627867640, 4); + new (toFill++) EmojiData(560, 60, 3627867627, 3627867639, 4); + new (toFill++) EmojiData(580, 60, 3627867628, 3627867623, 4); + new (toFill++) EmojiData(600, 60, 3627867630, 3627867641, 4); + new (toFill++) EmojiData(620, 60, 3627867631, 3627867637, 4); + new (toFill++) EmojiData(640, 60, 3627867632, 3627867639, 4); + new (toFill++) EmojiData(660, 60, 3627867639, 3627867642, 4); + new (toFill++) EmojiData(680, 60, 3627867642, 3627867640, 4); + new (toFill++) EmojiData(700, 60, 3627867649, 0, 2); + new (toFill++) EmojiData(720, 60, 3627867650, 0, 2); + new (toFill++) EmojiData(740, 60, 3627867674, 0, 2); + new (toFill++) EmojiData(760, 60, 3627867695, 0, 2); + new (toFill++) EmojiData(780, 60, 3627867698, 0, 2); + new (toFill++) EmojiData(0, 80, 3627867699, 0, 2); + new (toFill++) EmojiData(20, 80, 3627867700, 0, 2); + new (toFill++) EmojiData(40, 80, 3627867701, 0, 2); + new (toFill++) EmojiData(60, 80, 3627867702, 0, 2); + new (toFill++) EmojiData(80, 80, 3627867703, 0, 2); + new (toFill++) EmojiData(100, 80, 3627867704, 0, 2); + new (toFill++) EmojiData(120, 80, 3627867705, 0, 2); + new (toFill++) EmojiData(140, 80, 3627867706, 0, 2); + new (toFill++) EmojiData(160, 80, 3627867728, 0, 2); + new (toFill++) EmojiData(180, 80, 3627867729, 0, 2); + new (toFill++) EmojiData(200, 80, 3627867904, 0, 2); + new (toFill++) EmojiData(220, 80, 3627867905, 0, 2); + new (toFill++) EmojiData(240, 80, 3627867906, 0, 2); + new (toFill++) EmojiData(260, 80, 3627867907, 0, 2); + new (toFill++) EmojiData(280, 80, 3627867908, 0, 2); + new (toFill++) EmojiData(300, 80, 3627867909, 0, 2); + new (toFill++) EmojiData(320, 80, 3627867910, 0, 2); + new (toFill++) EmojiData(340, 80, 3627867911, 0, 2); + new (toFill++) EmojiData(360, 80, 3627867912, 0, 2); + new (toFill++) EmojiData(380, 80, 3627867913, 0, 2); + new (toFill++) EmojiData(400, 80, 3627867914, 0, 2); + new (toFill++) EmojiData(420, 80, 3627867915, 0, 2); + new (toFill++) EmojiData(440, 80, 3627867916, 0, 2); + new (toFill++) EmojiData(460, 80, 3627867917, 0, 2); + new (toFill++) EmojiData(480, 80, 3627867918, 0, 2); + new (toFill++) EmojiData(500, 80, 3627867919, 0, 2); + new (toFill++) EmojiData(520, 80, 3627867920, 0, 2); + new (toFill++) EmojiData(540, 80, 3627867921, 0, 2); + new (toFill++) EmojiData(560, 80, 3627867922, 0, 2); + new (toFill++) EmojiData(580, 80, 3627867923, 0, 2); + new (toFill++) EmojiData(600, 80, 3627867924, 0, 2); + new (toFill++) EmojiData(620, 80, 3627867925, 0, 2); + new (toFill++) EmojiData(640, 80, 3627867926, 0, 2); + new (toFill++) EmojiData(660, 80, 3627867927, 0, 2); + new (toFill++) EmojiData(680, 80, 3627867928, 0, 2); + new (toFill++) EmojiData(700, 80, 3627867929, 0, 2); + new (toFill++) EmojiData(720, 80, 3627867930, 0, 2); + new (toFill++) EmojiData(740, 80, 3627867931, 0, 2); + new (toFill++) EmojiData(760, 80, 3627867932, 0, 2); + new (toFill++) EmojiData(780, 80, 3627867933, 0, 2); + new (toFill++) EmojiData(0, 100, 3627867934, 0, 2); + new (toFill++) EmojiData(20, 100, 3627867935, 0, 2); + new (toFill++) EmojiData(40, 100, 3627867936, 0, 2); + new (toFill++) EmojiData(60, 100, 3627867952, 0, 2); + new (toFill++) EmojiData(80, 100, 3627867953, 0, 2); + new (toFill++) EmojiData(100, 100, 3627867954, 0, 2); + new (toFill++) EmojiData(120, 100, 3627867955, 0, 2); + new (toFill++) EmojiData(140, 100, 3627867956, 0, 2); + new (toFill++) EmojiData(160, 100, 3627867957, 0, 2); + new (toFill++) EmojiData(180, 100, 3627867959, 0, 2); + new (toFill++) EmojiData(200, 100, 3627867960, 0, 2); + new (toFill++) EmojiData(220, 100, 3627867961, 0, 2); + new (toFill++) EmojiData(240, 100, 3627867962, 0, 2); + new (toFill++) EmojiData(260, 100, 3627867963, 0, 2); + new (toFill++) EmojiData(280, 100, 3627867964, 0, 2); + new (toFill++) EmojiData(300, 100, 3627867965, 0, 2); + new (toFill++) EmojiData(320, 100, 3627867966, 0, 2); + new (toFill++) EmojiData(340, 100, 3627867967, 0, 2); + new (toFill++) EmojiData(360, 100, 3627867968, 0, 2); + new (toFill++) EmojiData(380, 100, 3627867969, 0, 2); + new (toFill++) EmojiData(400, 100, 3627867970, 0, 2); + new (toFill++) EmojiData(420, 100, 3627867971, 0, 2); + new (toFill++) EmojiData(440, 100, 3627867972, 0, 2); + new (toFill++) EmojiData(460, 100, 3627867973, 0, 2); + new (toFill++) EmojiData(480, 100, 3627867974, 0, 2); + new (toFill++) EmojiData(500, 100, 3627867975, 0, 2); + new (toFill++) EmojiData(520, 100, 3627867976, 0, 2); + new (toFill++) EmojiData(540, 100, 3627867977, 0, 2); + new (toFill++) EmojiData(560, 100, 3627867978, 0, 2); + new (toFill++) EmojiData(580, 100, 3627867979, 0, 2); + new (toFill++) EmojiData(600, 100, 3627867980, 0, 2); + new (toFill++) EmojiData(620, 100, 3627867981, 0, 2); + new (toFill++) EmojiData(640, 100, 3627867982, 0, 2); + new (toFill++) EmojiData(660, 100, 3627867983, 0, 2); + new (toFill++) EmojiData(680, 100, 3627867984, 0, 2); + new (toFill++) EmojiData(700, 100, 3627867985, 0, 2); + new (toFill++) EmojiData(720, 100, 3627867986, 0, 2); + new (toFill++) EmojiData(740, 100, 3627867987, 0, 2); + new (toFill++) EmojiData(760, 100, 3627867988, 0, 2); + new (toFill++) EmojiData(780, 100, 3627867989, 0, 2); + new (toFill++) EmojiData(0, 120, 3627867990, 0, 2); + new (toFill++) EmojiData(20, 120, 3627867991, 0, 2); + new (toFill++) EmojiData(40, 120, 3627867992, 0, 2); + new (toFill++) EmojiData(60, 120, 3627867993, 0, 2); + new (toFill++) EmojiData(80, 120, 3627867994, 0, 2); + new (toFill++) EmojiData(100, 120, 3627867995, 0, 2); + new (toFill++) EmojiData(120, 120, 3627867996, 0, 2); + new (toFill++) EmojiData(140, 120, 3627867997, 0, 2); + new (toFill++) EmojiData(160, 120, 3627867998, 0, 2); + new (toFill++) EmojiData(180, 120, 3627867999, 0, 2); + new (toFill++) EmojiData(200, 120, 3627868000, 0, 2); + new (toFill++) EmojiData(220, 120, 3627868001, 0, 2); + new (toFill++) EmojiData(240, 120, 3627868002, 0, 2); + new (toFill++) EmojiData(260, 120, 3627868003, 0, 2); + new (toFill++) EmojiData(280, 120, 3627868004, 0, 2); + new (toFill++) EmojiData(300, 120, 3627868005, 0, 2); + new (toFill++) EmojiData(320, 120, 3627868006, 0, 2); + new (toFill++) EmojiData(340, 120, 3627868007, 0, 2); + new (toFill++) EmojiData(360, 120, 3627868008, 0, 2); + new (toFill++) EmojiData(380, 120, 3627868009, 0, 2); + new (toFill++) EmojiData(400, 120, 3627868010, 0, 2); + new (toFill++) EmojiData(420, 120, 3627868011, 0, 2); + new (toFill++) EmojiData(440, 120, 3627868012, 0, 2); + new (toFill++) EmojiData(460, 120, 3627868013, 0, 2); + new (toFill++) EmojiData(480, 120, 3627868014, 0, 2); + new (toFill++) EmojiData(500, 120, 3627868015, 0, 2); + new (toFill++) EmojiData(520, 120, 3627868016, 0, 2); + new (toFill++) EmojiData(540, 120, 3627868017, 0, 2); + new (toFill++) EmojiData(560, 120, 3627868018, 0, 2); + new (toFill++) EmojiData(580, 120, 3627868019, 0, 2); + new (toFill++) EmojiData(600, 120, 3627868020, 0, 2); + new (toFill++) EmojiData(620, 120, 3627868021, 0, 2); + new (toFill++) EmojiData(640, 120, 3627868022, 0, 2); + new (toFill++) EmojiData(660, 120, 3627868023, 0, 2); + new (toFill++) EmojiData(680, 120, 3627868024, 0, 2); + new (toFill++) EmojiData(700, 120, 3627868025, 0, 2); + new (toFill++) EmojiData(720, 120, 3627868026, 0, 2); + new (toFill++) EmojiData(740, 120, 3627868027, 0, 2); + new (toFill++) EmojiData(760, 120, 3627868028, 0, 2); + new (toFill++) EmojiData(780, 120, 3627868032, 0, 2); + new (toFill++) EmojiData(0, 140, 3627868033, 0, 2); + new (toFill++) EmojiData(20, 140, 3627868034, 0, 2); + new (toFill++) EmojiData(40, 140, 3627868035, 0, 2); + new (toFill++) EmojiData(60, 140, 3627868036, 0, 2); + new (toFill++) EmojiData(80, 140, 3627868037, 0, 2); + new (toFill++) EmojiData(100, 140, 3627868038, 0, 2); + new (toFill++) EmojiData(120, 140, 3627868039, 0, 2); + new (toFill++) EmojiData(140, 140, 3627868040, 0, 2); + new (toFill++) EmojiData(160, 140, 3627868041, 0, 2); + new (toFill++) EmojiData(180, 140, 3627868042, 0, 2); + new (toFill++) EmojiData(200, 140, 3627868043, 0, 2); + new (toFill++) EmojiData(220, 140, 3627868044, 0, 2); + new (toFill++) EmojiData(240, 140, 3627868045, 0, 2); + new (toFill++) EmojiData(260, 140, 3627868046, 0, 2); + new (toFill++) EmojiData(280, 140, 3627868047, 0, 2); + new (toFill++) EmojiData(300, 140, 3627868048, 0, 2); + new (toFill++) EmojiData(320, 140, 3627868049, 0, 2); + new (toFill++) EmojiData(340, 140, 3627868050, 0, 2); + new (toFill++) EmojiData(360, 140, 3627868051, 0, 2); + new (toFill++) EmojiData(380, 140, 3627868064, 0, 2); + new (toFill++) EmojiData(400, 140, 3627868065, 0, 2); + new (toFill++) EmojiData(420, 140, 3627868066, 0, 2); + new (toFill++) EmojiData(440, 140, 3627868067, 0, 2); + new (toFill++) EmojiData(460, 140, 3627868068, 0, 2); + new (toFill++) EmojiData(480, 140, 3627868069, 0, 2); + new (toFill++) EmojiData(500, 140, 3627868070, 0, 2); + new (toFill++) EmojiData(520, 140, 3627868071, 0, 2); + new (toFill++) EmojiData(540, 140, 3627868072, 0, 2); + new (toFill++) EmojiData(560, 140, 3627868073, 0, 2); + new (toFill++) EmojiData(580, 140, 3627868074, 0, 2); + new (toFill++) EmojiData(600, 140, 3627868075, 0, 2); + new (toFill++) EmojiData(620, 140, 3627868076, 0, 2); + new (toFill++) EmojiData(640, 140, 3627868077, 0, 2); + new (toFill++) EmojiData(660, 140, 3627868078, 0, 2); + new (toFill++) EmojiData(680, 140, 3627868079, 0, 2); + new (toFill++) EmojiData(700, 140, 3627868080, 0, 2); + new (toFill++) EmojiData(720, 140, 3627868081, 0, 2); + new (toFill++) EmojiData(740, 140, 3627868082, 0, 2); + new (toFill++) EmojiData(760, 140, 3627868083, 0, 2); + new (toFill++) EmojiData(780, 140, 3627868084, 0, 2); + new (toFill++) EmojiData(0, 160, 3627868085, 0, 2); + new (toFill++) EmojiData(20, 160, 3627868086, 0, 2); + new (toFill++) EmojiData(40, 160, 3627868087, 0, 2); + new (toFill++) EmojiData(60, 160, 3627868088, 0, 2); + new (toFill++) EmojiData(80, 160, 3627868089, 0, 2); + new (toFill++) EmojiData(100, 160, 3627868090, 0, 2); + new (toFill++) EmojiData(120, 160, 3627868091, 0, 2); + new (toFill++) EmojiData(140, 160, 3627868092, 0, 2); + new (toFill++) EmojiData(160, 160, 3627868093, 0, 2); + new (toFill++) EmojiData(180, 160, 3627868094, 0, 2); + new (toFill++) EmojiData(200, 160, 3627868095, 0, 2); + new (toFill++) EmojiData(220, 160, 3627868096, 0, 2); + new (toFill++) EmojiData(240, 160, 3627868097, 0, 2); + new (toFill++) EmojiData(260, 160, 3627868098, 0, 2); + new (toFill++) EmojiData(280, 160, 3627868099, 0, 2); + new (toFill++) EmojiData(300, 160, 3627868100, 0, 2); + new (toFill++) EmojiData(320, 160, 3627868102, 0, 2); + new (toFill++) EmojiData(340, 160, 3627868103, 0, 2); + new (toFill++) EmojiData(360, 160, 3627868104, 0, 2); + new (toFill++) EmojiData(380, 160, 3627868105, 0, 2); + new (toFill++) EmojiData(400, 160, 3627868106, 0, 2); + new (toFill++) EmojiData(420, 160, 3627868128, 0, 2); + new (toFill++) EmojiData(440, 160, 3627868129, 0, 2); + new (toFill++) EmojiData(460, 160, 3627868130, 0, 2); + new (toFill++) EmojiData(480, 160, 3627868131, 0, 2); + new (toFill++) EmojiData(500, 160, 3627868132, 0, 2); + new (toFill++) EmojiData(520, 160, 3627868133, 0, 2); + new (toFill++) EmojiData(540, 160, 3627868134, 0, 2); + new (toFill++) EmojiData(560, 160, 3627868135, 0, 2); + new (toFill++) EmojiData(580, 160, 3627868136, 0, 2); + new (toFill++) EmojiData(600, 160, 3627868137, 0, 2); + new (toFill++) EmojiData(620, 160, 3627868138, 0, 2); + new (toFill++) EmojiData(640, 160, 3627868139, 0, 2); + new (toFill++) EmojiData(660, 160, 3627868140, 0, 2); + new (toFill++) EmojiData(680, 160, 3627868141, 0, 2); + new (toFill++) EmojiData(700, 160, 3627868142, 0, 2); + new (toFill++) EmojiData(720, 160, 3627868143, 0, 2); + new (toFill++) EmojiData(740, 160, 3627868144, 0, 2); + new (toFill++) EmojiData(760, 160, 3627932672, 0, 2); + new (toFill++) EmojiData(780, 160, 3627932673, 0, 2); + new (toFill++) EmojiData(0, 180, 3627932674, 0, 2); + new (toFill++) EmojiData(20, 180, 3627932675, 0, 2); + new (toFill++) EmojiData(40, 180, 3627932676, 0, 2); + new (toFill++) EmojiData(60, 180, 3627932677, 0, 2); + new (toFill++) EmojiData(80, 180, 3627932678, 0, 2); + new (toFill++) EmojiData(100, 180, 3627932679, 0, 2); + new (toFill++) EmojiData(120, 180, 3627932680, 0, 2); + new (toFill++) EmojiData(140, 180, 3627932681, 0, 2); + new (toFill++) EmojiData(160, 180, 3627932682, 0, 2); + new (toFill++) EmojiData(180, 180, 3627932683, 0, 2); + new (toFill++) EmojiData(200, 180, 3627932684, 0, 2); + new (toFill++) EmojiData(220, 180, 3627932685, 0, 2); + new (toFill++) EmojiData(240, 180, 3627932686, 0, 2); + new (toFill++) EmojiData(260, 180, 3627932687, 0, 2); + new (toFill++) EmojiData(280, 180, 3627932688, 0, 2); + new (toFill++) EmojiData(300, 180, 3627932689, 0, 2); + new (toFill++) EmojiData(320, 180, 3627932690, 0, 2); + new (toFill++) EmojiData(340, 180, 3627932691, 0, 2); + new (toFill++) EmojiData(360, 180, 3627932692, 0, 2); + new (toFill++) EmojiData(380, 180, 3627932693, 0, 2); + new (toFill++) EmojiData(400, 180, 3627932694, 0, 2); + new (toFill++) EmojiData(420, 180, 3627932695, 0, 2); + new (toFill++) EmojiData(440, 180, 3627932696, 0, 2); + new (toFill++) EmojiData(460, 180, 3627932697, 0, 2); + new (toFill++) EmojiData(480, 180, 3627932698, 0, 2); + new (toFill++) EmojiData(500, 180, 3627932699, 0, 2); + new (toFill++) EmojiData(520, 180, 3627932700, 0, 2); + new (toFill++) EmojiData(540, 180, 3627932701, 0, 2); + new (toFill++) EmojiData(560, 180, 3627932702, 0, 2); + new (toFill++) EmojiData(580, 180, 3627932703, 0, 2); + new (toFill++) EmojiData(600, 180, 3627932704, 0, 2); + new (toFill++) EmojiData(620, 180, 3627932705, 0, 2); + new (toFill++) EmojiData(640, 180, 3627932706, 0, 2); + new (toFill++) EmojiData(660, 180, 3627932707, 0, 2); + new (toFill++) EmojiData(680, 180, 3627932708, 0, 2); + new (toFill++) EmojiData(700, 180, 3627932709, 0, 2); + new (toFill++) EmojiData(720, 180, 3627932710, 0, 2); + new (toFill++) EmojiData(740, 180, 3627932711, 0, 2); + new (toFill++) EmojiData(760, 180, 3627932712, 0, 2); + new (toFill++) EmojiData(780, 180, 3627932713, 0, 2); + new (toFill++) EmojiData(0, 200, 3627932714, 0, 2); + new (toFill++) EmojiData(20, 200, 3627932715, 0, 2); + new (toFill++) EmojiData(40, 200, 3627932716, 0, 2); + new (toFill++) EmojiData(60, 200, 3627932717, 0, 2); + new (toFill++) EmojiData(80, 200, 3627932718, 0, 2); + new (toFill++) EmojiData(100, 200, 3627932719, 0, 2); + new (toFill++) EmojiData(120, 200, 3627932720, 0, 2); + new (toFill++) EmojiData(140, 200, 3627932721, 0, 2); + new (toFill++) EmojiData(160, 200, 3627932722, 0, 2); + new (toFill++) EmojiData(180, 200, 3627932723, 0, 2); + new (toFill++) EmojiData(200, 200, 3627932724, 0, 2); + new (toFill++) EmojiData(220, 200, 3627932725, 0, 2); + new (toFill++) EmojiData(240, 200, 3627932726, 0, 2); + new (toFill++) EmojiData(260, 200, 3627932727, 0, 2); + new (toFill++) EmojiData(280, 200, 3627932728, 0, 2); + new (toFill++) EmojiData(300, 200, 3627932729, 0, 2); + new (toFill++) EmojiData(320, 200, 3627932730, 0, 2); + new (toFill++) EmojiData(340, 200, 3627932731, 0, 2); + new (toFill++) EmojiData(360, 200, 3627932732, 0, 2); + new (toFill++) EmojiData(380, 200, 3627932733, 0, 2); + new (toFill++) EmojiData(400, 200, 3627932734, 0, 2); + new (toFill++) EmojiData(420, 200, 3627932736, 0, 2); + new (toFill++) EmojiData(440, 200, 3627932738, 0, 2); + new (toFill++) EmojiData(460, 200, 3627932739, 0, 2); + new (toFill++) EmojiData(480, 200, 3627932740, 0, 2); + new (toFill++) EmojiData(500, 200, 3627932741, 0, 2); + new (toFill++) EmojiData(520, 200, 3627932742, 0, 2); + new (toFill++) EmojiData(540, 200, 3627932743, 0, 2); + new (toFill++) EmojiData(560, 200, 3627932744, 0, 2); + new (toFill++) EmojiData(580, 200, 3627932745, 0, 2); + new (toFill++) EmojiData(600, 200, 3627932746, 0, 2); + new (toFill++) EmojiData(620, 200, 3627932747, 0, 2); + new (toFill++) EmojiData(640, 200, 3627932748, 0, 2); + new (toFill++) EmojiData(660, 200, 3627932749, 0, 2); + new (toFill++) EmojiData(680, 200, 3627932750, 0, 2); + new (toFill++) EmojiData(700, 200, 3627932751, 0, 2); + new (toFill++) EmojiData(720, 200, 3627932752, 0, 2); + new (toFill++) EmojiData(740, 200, 3627932753, 0, 2); + new (toFill++) EmojiData(760, 200, 3627932754, 0, 2); + new (toFill++) EmojiData(780, 200, 3627932755, 0, 2); + new (toFill++) EmojiData(0, 220, 3627932756, 0, 2); + new (toFill++) EmojiData(20, 220, 3627932757, 0, 2); + new (toFill++) EmojiData(40, 220, 3627932758, 0, 2); + new (toFill++) EmojiData(60, 220, 3627932759, 0, 2); + new (toFill++) EmojiData(80, 220, 3627932760, 0, 2); + new (toFill++) EmojiData(100, 220, 3627932761, 0, 2); + new (toFill++) EmojiData(120, 220, 3627932762, 0, 2); + new (toFill++) EmojiData(140, 220, 3627932763, 0, 2); + new (toFill++) EmojiData(160, 220, 3627932764, 0, 2); + new (toFill++) EmojiData(180, 220, 3627932765, 0, 2); + new (toFill++) EmojiData(200, 220, 3627932766, 0, 2); + new (toFill++) EmojiData(220, 220, 3627932767, 0, 2); + new (toFill++) EmojiData(240, 220, 3627932768, 0, 2); + new (toFill++) EmojiData(260, 220, 3627932769, 0, 2); + new (toFill++) EmojiData(280, 220, 3627932770, 0, 2); + new (toFill++) EmojiData(300, 220, 3627932771, 0, 2); + new (toFill++) EmojiData(320, 220, 3627932772, 0, 2); + new (toFill++) EmojiData(340, 220, 3627932773, 0, 2); + new (toFill++) EmojiData(360, 220, 3627932774, 0, 2); + new (toFill++) EmojiData(380, 220, 3627932775, 0, 2); + new (toFill++) EmojiData(400, 220, 3627932776, 0, 2); + new (toFill++) EmojiData(420, 220, 3627932777, 0, 2); + new (toFill++) EmojiData(440, 220, 3627932778, 0, 2); + new (toFill++) EmojiData(460, 220, 3627932779, 0, 2); + new (toFill++) EmojiData(480, 220, 3627932780, 0, 2); + new (toFill++) EmojiData(500, 220, 3627932781, 0, 2); + new (toFill++) EmojiData(520, 220, 3627932782, 0, 2); + new (toFill++) EmojiData(540, 220, 3627932783, 0, 2); + new (toFill++) EmojiData(560, 220, 3627932784, 0, 2); + new (toFill++) EmojiData(580, 220, 3627932785, 0, 2); + new (toFill++) EmojiData(600, 220, 3627932786, 0, 2); + new (toFill++) EmojiData(620, 220, 3627932787, 0, 2); + new (toFill++) EmojiData(640, 220, 3627932788, 0, 2); + new (toFill++) EmojiData(660, 220, 3627932789, 0, 2); + new (toFill++) EmojiData(680, 220, 3627932790, 0, 2); + new (toFill++) EmojiData(700, 220, 3627932791, 0, 2); + new (toFill++) EmojiData(720, 220, 3627932792, 0, 2); + new (toFill++) EmojiData(740, 220, 3627932793, 0, 2); + new (toFill++) EmojiData(760, 220, 3627932794, 0, 2); + new (toFill++) EmojiData(780, 220, 3627932795, 0, 2); + new (toFill++) EmojiData(0, 240, 3627932796, 0, 2); + new (toFill++) EmojiData(20, 240, 3627932797, 0, 2); + new (toFill++) EmojiData(40, 240, 3627932798, 0, 2); + new (toFill++) EmojiData(60, 240, 3627932799, 0, 2); + new (toFill++) EmojiData(80, 240, 3627932800, 0, 2); + new (toFill++) EmojiData(100, 240, 3627932801, 0, 2); + new (toFill++) EmojiData(120, 240, 3627932802, 0, 2); + new (toFill++) EmojiData(140, 240, 3627932803, 0, 2); + new (toFill++) EmojiData(160, 240, 3627932804, 0, 2); + new (toFill++) EmojiData(180, 240, 3627932805, 0, 2); + new (toFill++) EmojiData(200, 240, 3627932806, 0, 2); + new (toFill++) EmojiData(220, 240, 3627932807, 0, 2); + new (toFill++) EmojiData(240, 240, 3627932808, 0, 2); + new (toFill++) EmojiData(260, 240, 3627932809, 0, 2); + new (toFill++) EmojiData(280, 240, 3627932810, 0, 2); + new (toFill++) EmojiData(300, 240, 3627932811, 0, 2); + new (toFill++) EmojiData(320, 240, 3627932812, 0, 2); + new (toFill++) EmojiData(340, 240, 3627932813, 0, 2); + new (toFill++) EmojiData(360, 240, 3627932814, 0, 2); + new (toFill++) EmojiData(380, 240, 3627932815, 0, 2); + new (toFill++) EmojiData(400, 240, 3627932816, 0, 2); + new (toFill++) EmojiData(420, 240, 3627932817, 0, 2); + new (toFill++) EmojiData(440, 240, 3627932818, 0, 2); + new (toFill++) EmojiData(460, 240, 3627932819, 0, 2); + new (toFill++) EmojiData(480, 240, 3627932820, 0, 2); + new (toFill++) EmojiData(500, 240, 3627932821, 0, 2); + new (toFill++) EmojiData(520, 240, 3627932822, 0, 2); + new (toFill++) EmojiData(540, 240, 3627932823, 0, 2); + new (toFill++) EmojiData(560, 240, 3627932824, 0, 2); + new (toFill++) EmojiData(580, 240, 3627932825, 0, 2); + new (toFill++) EmojiData(600, 240, 3627932826, 0, 2); + new (toFill++) EmojiData(620, 240, 3627932827, 0, 2); + new (toFill++) EmojiData(640, 240, 3627932828, 0, 2); + new (toFill++) EmojiData(660, 240, 3627932829, 0, 2); + new (toFill++) EmojiData(680, 240, 3627932830, 0, 2); + new (toFill++) EmojiData(700, 240, 3627932831, 0, 2); + new (toFill++) EmojiData(720, 240, 3627932832, 0, 2); + new (toFill++) EmojiData(740, 240, 3627932833, 0, 2); + new (toFill++) EmojiData(760, 240, 3627932834, 0, 2); + new (toFill++) EmojiData(780, 240, 3627932835, 0, 2); + new (toFill++) EmojiData(0, 260, 3627932836, 0, 2); + new (toFill++) EmojiData(20, 260, 3627932837, 0, 2); + new (toFill++) EmojiData(40, 260, 3627932838, 0, 2); + new (toFill++) EmojiData(60, 260, 3627932839, 0, 2); + new (toFill++) EmojiData(80, 260, 3627932840, 0, 2); + new (toFill++) EmojiData(100, 260, 3627932841, 0, 2); + new (toFill++) EmojiData(120, 260, 3627932842, 0, 2); + new (toFill++) EmojiData(140, 260, 3627932843, 0, 2); + new (toFill++) EmojiData(160, 260, 3627932844, 0, 2); + new (toFill++) EmojiData(180, 260, 3627932845, 0, 2); + new (toFill++) EmojiData(200, 260, 3627932846, 0, 2); + new (toFill++) EmojiData(220, 260, 3627932847, 0, 2); + new (toFill++) EmojiData(240, 260, 3627932848, 0, 2); + new (toFill++) EmojiData(260, 260, 3627932849, 0, 2); + new (toFill++) EmojiData(280, 260, 3627932850, 0, 2); + new (toFill++) EmojiData(300, 260, 3627932851, 0, 2); + new (toFill++) EmojiData(320, 260, 3627932852, 0, 2); + new (toFill++) EmojiData(340, 260, 3627932853, 0, 2); + new (toFill++) EmojiData(360, 260, 3627932854, 0, 2); + new (toFill++) EmojiData(380, 260, 3627932855, 0, 2); + new (toFill++) EmojiData(400, 260, 3627932856, 0, 2); + new (toFill++) EmojiData(420, 260, 3627932857, 0, 2); + new (toFill++) EmojiData(440, 260, 3627932858, 0, 2); + new (toFill++) EmojiData(460, 260, 3627932859, 0, 2); + new (toFill++) EmojiData(480, 260, 3627932860, 0, 2); + new (toFill++) EmojiData(500, 260, 3627932861, 0, 2); + new (toFill++) EmojiData(520, 260, 3627932862, 0, 2); + new (toFill++) EmojiData(540, 260, 3627932863, 0, 2); + new (toFill++) EmojiData(560, 260, 3627932864, 0, 2); + new (toFill++) EmojiData(580, 260, 3627932865, 0, 2); + new (toFill++) EmojiData(600, 260, 3627932866, 0, 2); + new (toFill++) EmojiData(620, 260, 3627932867, 0, 2); + new (toFill++) EmojiData(640, 260, 3627932868, 0, 2); + new (toFill++) EmojiData(660, 260, 3627932869, 0, 2); + new (toFill++) EmojiData(680, 260, 3627932870, 0, 2); + new (toFill++) EmojiData(700, 260, 3627932871, 0, 2); + new (toFill++) EmojiData(720, 260, 3627932872, 0, 2); + new (toFill++) EmojiData(740, 260, 3627932873, 0, 2); + new (toFill++) EmojiData(760, 260, 3627932874, 0, 2); + new (toFill++) EmojiData(780, 260, 3627932875, 0, 2); + new (toFill++) EmojiData(0, 280, 3627932876, 0, 2); + new (toFill++) EmojiData(20, 280, 3627932877, 0, 2); + new (toFill++) EmojiData(40, 280, 3627932878, 0, 2); + new (toFill++) EmojiData(60, 280, 3627932879, 0, 2); + new (toFill++) EmojiData(80, 280, 3627932880, 0, 2); + new (toFill++) EmojiData(100, 280, 3627932881, 0, 2); + new (toFill++) EmojiData(120, 280, 3627932882, 0, 2); + new (toFill++) EmojiData(140, 280, 3627932883, 0, 2); + new (toFill++) EmojiData(160, 280, 3627932884, 0, 2); + new (toFill++) EmojiData(180, 280, 3627932885, 0, 2); + new (toFill++) EmojiData(200, 280, 3627932886, 0, 2); + new (toFill++) EmojiData(220, 280, 3627932887, 0, 2); + new (toFill++) EmojiData(240, 280, 3627932888, 0, 2); + new (toFill++) EmojiData(260, 280, 3627932889, 0, 2); + new (toFill++) EmojiData(280, 280, 3627932890, 0, 2); + new (toFill++) EmojiData(300, 280, 3627932891, 0, 2); + new (toFill++) EmojiData(320, 280, 3627932892, 0, 2); + new (toFill++) EmojiData(340, 280, 3627932893, 0, 2); + new (toFill++) EmojiData(360, 280, 3627932894, 0, 2); + new (toFill++) EmojiData(380, 280, 3627932895, 0, 2); + new (toFill++) EmojiData(400, 280, 3627932896, 0, 2); + new (toFill++) EmojiData(420, 280, 3627932897, 0, 2); + new (toFill++) EmojiData(440, 280, 3627932898, 0, 2); + new (toFill++) EmojiData(460, 280, 3627932899, 0, 2); + new (toFill++) EmojiData(480, 280, 3627932900, 0, 2); + new (toFill++) EmojiData(500, 280, 3627932901, 0, 2); + new (toFill++) EmojiData(520, 280, 3627932902, 0, 2); + new (toFill++) EmojiData(540, 280, 3627932903, 0, 2); + new (toFill++) EmojiData(560, 280, 3627932904, 0, 2); + new (toFill++) EmojiData(580, 280, 3627932905, 0, 2); + new (toFill++) EmojiData(600, 280, 3627932906, 0, 2); + new (toFill++) EmojiData(620, 280, 3627932907, 0, 2); + new (toFill++) EmojiData(640, 280, 3627932908, 0, 2); + new (toFill++) EmojiData(660, 280, 3627932909, 0, 2); + new (toFill++) EmojiData(680, 280, 3627932910, 0, 2); + new (toFill++) EmojiData(700, 280, 3627932911, 0, 2); + new (toFill++) EmojiData(720, 280, 3627932912, 0, 2); + new (toFill++) EmojiData(740, 280, 3627932913, 0, 2); + new (toFill++) EmojiData(760, 280, 3627932914, 0, 2); + new (toFill++) EmojiData(780, 280, 3627932915, 0, 2); + new (toFill++) EmojiData(0, 300, 3627932916, 0, 2); + new (toFill++) EmojiData(20, 300, 3627932917, 0, 2); + new (toFill++) EmojiData(40, 300, 3627932918, 0, 2); + new (toFill++) EmojiData(60, 300, 3627932919, 0, 2); + new (toFill++) EmojiData(80, 300, 3627932921, 0, 2); + new (toFill++) EmojiData(100, 300, 3627932922, 0, 2); + new (toFill++) EmojiData(120, 300, 3627932923, 0, 2); + new (toFill++) EmojiData(140, 300, 3627932924, 0, 2); + new (toFill++) EmojiData(160, 300, 3627932928, 0, 2); + new (toFill++) EmojiData(180, 300, 3627932929, 0, 2); + new (toFill++) EmojiData(200, 300, 3627932930, 0, 2); + new (toFill++) EmojiData(220, 300, 3627932931, 0, 2); + new (toFill++) EmojiData(240, 300, 3627932932, 0, 2); + new (toFill++) EmojiData(260, 300, 3627932933, 0, 2); + new (toFill++) EmojiData(280, 300, 3627932934, 0, 2); + new (toFill++) EmojiData(300, 300, 3627932935, 0, 2); + new (toFill++) EmojiData(320, 300, 3627932936, 0, 2); + new (toFill++) EmojiData(340, 300, 3627932937, 0, 2); + new (toFill++) EmojiData(360, 300, 3627932938, 0, 2); + new (toFill++) EmojiData(380, 300, 3627932939, 0, 2); + new (toFill++) EmojiData(400, 300, 3627932940, 0, 2); + new (toFill++) EmojiData(420, 300, 3627932941, 0, 2); + new (toFill++) EmojiData(440, 300, 3627932942, 0, 2); + new (toFill++) EmojiData(460, 300, 3627932943, 0, 2); + new (toFill++) EmojiData(480, 300, 3627932944, 0, 2); + new (toFill++) EmojiData(500, 300, 3627932945, 0, 2); + new (toFill++) EmojiData(520, 300, 3627932946, 0, 2); + new (toFill++) EmojiData(540, 300, 3627932947, 0, 2); + new (toFill++) EmojiData(560, 300, 3627932948, 0, 2); + new (toFill++) EmojiData(580, 300, 3627932949, 0, 2); + new (toFill++) EmojiData(600, 300, 3627932950, 0, 2); + new (toFill++) EmojiData(620, 300, 3627932951, 0, 2); + new (toFill++) EmojiData(640, 300, 3627932952, 0, 2); + new (toFill++) EmojiData(660, 300, 3627932953, 0, 2); + new (toFill++) EmojiData(680, 300, 3627932954, 0, 2); + new (toFill++) EmojiData(700, 300, 3627932955, 0, 2); + new (toFill++) EmojiData(720, 300, 3627932956, 0, 2); + new (toFill++) EmojiData(740, 300, 3627932957, 0, 2); + new (toFill++) EmojiData(760, 300, 3627932958, 0, 2); + new (toFill++) EmojiData(780, 300, 3627932959, 0, 2); + new (toFill++) EmojiData(0, 320, 3627932960, 0, 2); + new (toFill++) EmojiData(20, 320, 3627932961, 0, 2); + new (toFill++) EmojiData(40, 320, 3627932962, 0, 2); + new (toFill++) EmojiData(60, 320, 3627932963, 0, 2); + new (toFill++) EmojiData(80, 320, 3627932964, 0, 2); + new (toFill++) EmojiData(100, 320, 3627932965, 0, 2); + new (toFill++) EmojiData(120, 320, 3627932966, 0, 2); + new (toFill++) EmojiData(140, 320, 3627932967, 0, 2); + new (toFill++) EmojiData(160, 320, 3627932968, 0, 2); + new (toFill++) EmojiData(180, 320, 3627932969, 0, 2); + new (toFill++) EmojiData(200, 320, 3627932970, 0, 2); + new (toFill++) EmojiData(220, 320, 3627932971, 0, 2); + new (toFill++) EmojiData(240, 320, 3627932972, 0, 2); + new (toFill++) EmojiData(260, 320, 3627932973, 0, 2); + new (toFill++) EmojiData(280, 320, 3627932974, 0, 2); + new (toFill++) EmojiData(300, 320, 3627932975, 0, 2); + new (toFill++) EmojiData(320, 320, 3627932976, 0, 2); + new (toFill++) EmojiData(340, 320, 3627932977, 0, 2); + new (toFill++) EmojiData(360, 320, 3627932978, 0, 2); + new (toFill++) EmojiData(380, 320, 3627932979, 0, 2); + new (toFill++) EmojiData(400, 320, 3627932980, 0, 2); + new (toFill++) EmojiData(420, 320, 3627932981, 0, 2); + new (toFill++) EmojiData(440, 320, 3627932982, 0, 2); + new (toFill++) EmojiData(460, 320, 3627932983, 0, 2); + new (toFill++) EmojiData(480, 320, 3627932984, 0, 2); + new (toFill++) EmojiData(500, 320, 3627932985, 0, 2); + new (toFill++) EmojiData(520, 320, 3627932986, 0, 2); + new (toFill++) EmojiData(540, 320, 3627932987, 0, 2); + new (toFill++) EmojiData(560, 320, 3627932988, 0, 2); + new (toFill++) EmojiData(580, 320, 3627932989, 0, 2); + new (toFill++) EmojiData(600, 320, 3627933008, 0, 2); + new (toFill++) EmojiData(620, 320, 3627933009, 0, 2); + new (toFill++) EmojiData(640, 320, 3627933010, 0, 2); + new (toFill++) EmojiData(660, 320, 3627933011, 0, 2); + new (toFill++) EmojiData(680, 320, 3627933012, 0, 2); + new (toFill++) EmojiData(700, 320, 3627933013, 0, 2); + new (toFill++) EmojiData(720, 320, 3627933014, 0, 2); + new (toFill++) EmojiData(740, 320, 3627933015, 0, 2); + new (toFill++) EmojiData(760, 320, 3627933016, 0, 2); + new (toFill++) EmojiData(780, 320, 3627933017, 0, 2); + new (toFill++) EmojiData(0, 340, 3627933018, 0, 2); + new (toFill++) EmojiData(20, 340, 3627933019, 0, 2); + new (toFill++) EmojiData(40, 340, 3627933020, 0, 2); + new (toFill++) EmojiData(60, 340, 3627933021, 0, 2); + new (toFill++) EmojiData(80, 340, 3627933022, 0, 2); + new (toFill++) EmojiData(100, 340, 3627933023, 0, 2); + new (toFill++) EmojiData(120, 340, 3627933024, 0, 2); + new (toFill++) EmojiData(140, 340, 3627933025, 0, 2); + new (toFill++) EmojiData(160, 340, 3627933026, 0, 2); + new (toFill++) EmojiData(180, 340, 3627933027, 0, 2); + new (toFill++) EmojiData(200, 340, 3627933028, 0, 2); + new (toFill++) EmojiData(220, 340, 3627933029, 0, 2); + new (toFill++) EmojiData(240, 340, 3627933030, 0, 2); + new (toFill++) EmojiData(260, 340, 3627933031, 0, 2); + new (toFill++) EmojiData(280, 340, 3627933179, 0, 2); + new (toFill++) EmojiData(300, 340, 3627933180, 0, 2); + new (toFill++) EmojiData(320, 340, 3627933181, 0, 2); + new (toFill++) EmojiData(340, 340, 3627933182, 0, 2); + new (toFill++) EmojiData(360, 340, 3627933183, 0, 2); + new (toFill++) EmojiData(380, 340, 3627933184, 0, 2); + new (toFill++) EmojiData(400, 340, 3627933185, 0, 2); + new (toFill++) EmojiData(420, 340, 3627933186, 0, 2); + new (toFill++) EmojiData(440, 340, 3627933187, 0, 2); + new (toFill++) EmojiData(460, 340, 3627933188, 0, 2); + new (toFill++) EmojiData(480, 340, 3627933189, 0, 2); + new (toFill++) EmojiData(500, 340, 3627933190, 0, 2); + new (toFill++) EmojiData(520, 340, 3627933191, 0, 2); + new (toFill++) EmojiData(540, 340, 3627933192, 0, 2); + new (toFill++) EmojiData(560, 340, 3627933193, 0, 2); + new (toFill++) EmojiData(580, 340, 3627933194, 0, 2); + new (toFill++) EmojiData(600, 340, 3627933195, 0, 2); + new (toFill++) EmojiData(620, 340, 3627933196, 0, 2); + new (toFill++) EmojiData(640, 340, 3627933197, 0, 2); + new (toFill++) EmojiData(660, 340, 3627933198, 0, 2); + new (toFill++) EmojiData(680, 340, 3627933199, 0, 2); + new (toFill++) EmojiData(700, 340, 3627933200, 0, 2); + new (toFill++) EmojiData(720, 340, 3627933201, 0, 2); + new (toFill++) EmojiData(740, 340, 3627933202, 0, 2); + new (toFill++) EmojiData(760, 340, 3627933203, 0, 2); + new (toFill++) EmojiData(780, 340, 3627933204, 0, 2); + new (toFill++) EmojiData(0, 360, 3627933205, 0, 2); + new (toFill++) EmojiData(20, 360, 3627933206, 0, 2); + new (toFill++) EmojiData(40, 360, 3627933207, 0, 2); + new (toFill++) EmojiData(60, 360, 3627933208, 0, 2); + new (toFill++) EmojiData(80, 360, 3627933209, 0, 2); + new (toFill++) EmojiData(100, 360, 3627933210, 0, 2); + new (toFill++) EmojiData(120, 360, 3627933211, 0, 2); + new (toFill++) EmojiData(140, 360, 3627933212, 0, 2); + new (toFill++) EmojiData(160, 360, 3627933213, 0, 2); + new (toFill++) EmojiData(180, 360, 3627933214, 0, 2); + new (toFill++) EmojiData(200, 360, 3627933215, 0, 2); + new (toFill++) EmojiData(220, 360, 3627933216, 0, 2); + new (toFill++) EmojiData(240, 360, 3627933217, 0, 2); + new (toFill++) EmojiData(260, 360, 3627933218, 0, 2); + new (toFill++) EmojiData(280, 360, 3627933219, 0, 2); + new (toFill++) EmojiData(300, 360, 3627933220, 0, 2); + new (toFill++) EmojiData(320, 360, 3627933221, 0, 2); + new (toFill++) EmojiData(340, 360, 3627933222, 0, 2); + new (toFill++) EmojiData(360, 360, 3627933223, 0, 2); + new (toFill++) EmojiData(380, 360, 3627933224, 0, 2); + new (toFill++) EmojiData(400, 360, 3627933225, 0, 2); + new (toFill++) EmojiData(420, 360, 3627933226, 0, 2); + new (toFill++) EmojiData(440, 360, 3627933227, 0, 2); + new (toFill++) EmojiData(460, 360, 3627933228, 0, 2); + new (toFill++) EmojiData(480, 360, 3627933229, 0, 2); + new (toFill++) EmojiData(500, 360, 3627933230, 0, 2); + new (toFill++) EmojiData(520, 360, 3627933231, 0, 2); + new (toFill++) EmojiData(540, 360, 3627933232, 0, 2); + new (toFill++) EmojiData(560, 360, 3627933233, 0, 2); + new (toFill++) EmojiData(580, 360, 3627933234, 0, 2); + new (toFill++) EmojiData(600, 360, 3627933235, 0, 2); + new (toFill++) EmojiData(620, 360, 3627933236, 0, 2); + new (toFill++) EmojiData(640, 360, 3627933237, 0, 2); + new (toFill++) EmojiData(660, 360, 3627933238, 0, 2); + new (toFill++) EmojiData(680, 360, 3627933239, 0, 2); + new (toFill++) EmojiData(700, 360, 3627933240, 0, 2); + new (toFill++) EmojiData(720, 360, 3627933241, 0, 2); + new (toFill++) EmojiData(740, 360, 3627933242, 0, 2); + new (toFill++) EmojiData(760, 360, 3627933243, 0, 2); + new (toFill++) EmojiData(780, 360, 3627933244, 0, 2); + new (toFill++) EmojiData(0, 380, 3627933245, 0, 2); + new (toFill++) EmojiData(20, 380, 3627933246, 0, 2); + new (toFill++) EmojiData(40, 380, 3627933247, 0, 2); + new (toFill++) EmojiData(60, 380, 3627933248, 0, 2); + new (toFill++) EmojiData(80, 380, 3627933253, 0, 2); + new (toFill++) EmojiData(100, 380, 3627933254, 0, 2); + new (toFill++) EmojiData(120, 380, 3627933255, 0, 2); + new (toFill++) EmojiData(140, 380, 3627933256, 0, 2); + new (toFill++) EmojiData(160, 380, 3627933257, 0, 2); + new (toFill++) EmojiData(180, 380, 3627933258, 0, 2); + new (toFill++) EmojiData(200, 380, 3627933259, 0, 2); + new (toFill++) EmojiData(220, 380, 3627933260, 0, 2); + new (toFill++) EmojiData(240, 380, 3627933261, 0, 2); + new (toFill++) EmojiData(260, 380, 3627933262, 0, 2); + new (toFill++) EmojiData(280, 380, 3627933263, 0, 2); + new (toFill++) EmojiData(300, 380, 3627933312, 0, 2); + new (toFill++) EmojiData(320, 380, 3627933313, 0, 2); + new (toFill++) EmojiData(340, 380, 3627933314, 0, 2); + new (toFill++) EmojiData(360, 380, 3627933315, 0, 2); + new (toFill++) EmojiData(380, 380, 3627933316, 0, 2); + new (toFill++) EmojiData(400, 380, 3627933317, 0, 2); + new (toFill++) EmojiData(420, 380, 3627933318, 0, 2); + new (toFill++) EmojiData(440, 380, 3627933319, 0, 2); + new (toFill++) EmojiData(460, 380, 3627933320, 0, 2); + new (toFill++) EmojiData(480, 380, 3627933321, 0, 2); + new (toFill++) EmojiData(500, 380, 3627933322, 0, 2); + new (toFill++) EmojiData(520, 380, 3627933323, 0, 2); + new (toFill++) EmojiData(540, 380, 3627933324, 0, 2); + new (toFill++) EmojiData(560, 380, 3627933325, 0, 2); + new (toFill++) EmojiData(580, 380, 3627933326, 0, 2); + new (toFill++) EmojiData(600, 380, 3627933327, 0, 2); + new (toFill++) EmojiData(620, 380, 3627933328, 0, 2); + new (toFill++) EmojiData(640, 380, 3627933329, 0, 2); + new (toFill++) EmojiData(660, 380, 3627933330, 0, 2); + new (toFill++) EmojiData(680, 380, 3627933331, 0, 2); + new (toFill++) EmojiData(700, 380, 3627933332, 0, 2); + new (toFill++) EmojiData(720, 380, 3627933333, 0, 2); + new (toFill++) EmojiData(740, 380, 3627933334, 0, 2); + new (toFill++) EmojiData(760, 380, 3627933335, 0, 2); + new (toFill++) EmojiData(780, 380, 3627933336, 0, 2); + new (toFill++) EmojiData(0, 400, 3627933337, 0, 2); + new (toFill++) EmojiData(20, 400, 3627933338, 0, 2); + new (toFill++) EmojiData(40, 400, 3627933339, 0, 2); + new (toFill++) EmojiData(60, 400, 3627933340, 0, 2); + new (toFill++) EmojiData(80, 400, 3627933341, 0, 2); + new (toFill++) EmojiData(100, 400, 3627933342, 0, 2); + new (toFill++) EmojiData(120, 400, 3627933343, 0, 2); + new (toFill++) EmojiData(140, 400, 3627933344, 0, 2); + new (toFill++) EmojiData(160, 400, 3627933345, 0, 2); + new (toFill++) EmojiData(180, 400, 3627933346, 0, 2); + new (toFill++) EmojiData(200, 400, 3627933347, 0, 2); + new (toFill++) EmojiData(220, 400, 3627933348, 0, 2); + new (toFill++) EmojiData(240, 400, 3627933349, 0, 2); + new (toFill++) EmojiData(260, 400, 3627933350, 0, 2); + new (toFill++) EmojiData(280, 400, 3627933351, 0, 2); + new (toFill++) EmojiData(300, 400, 3627933352, 0, 2); + new (toFill++) EmojiData(320, 400, 3627933353, 0, 2); + new (toFill++) EmojiData(340, 400, 3627933354, 0, 2); + new (toFill++) EmojiData(360, 400, 3627933355, 0, 2); + new (toFill++) EmojiData(380, 400, 3627933356, 0, 2); + new (toFill++) EmojiData(400, 400, 3627933357, 0, 2); + new (toFill++) EmojiData(420, 400, 3627933358, 0, 2); + new (toFill++) EmojiData(440, 400, 3627933359, 0, 2); + new (toFill++) EmojiData(460, 400, 3627933360, 0, 2); + new (toFill++) EmojiData(480, 400, 3627933361, 0, 2); + new (toFill++) EmojiData(500, 400, 3627933362, 0, 2); + new (toFill++) EmojiData(520, 400, 3627933363, 0, 2); + new (toFill++) EmojiData(540, 400, 3627933364, 0, 2); + new (toFill++) EmojiData(560, 400, 3627933365, 0, 2); + new (toFill++) EmojiData(580, 400, 3627933366, 0, 2); + new (toFill++) EmojiData(600, 400, 3627933367, 0, 2); + new (toFill++) EmojiData(620, 400, 3627933368, 0, 2); + new (toFill++) EmojiData(640, 400, 3627933369, 0, 2); + new (toFill++) EmojiData(660, 400, 3627933370, 0, 2); + new (toFill++) EmojiData(680, 400, 3627933371, 0, 2); + new (toFill++) EmojiData(700, 400, 3627933372, 0, 2); + new (toFill++) EmojiData(720, 400, 3627933373, 0, 2); + new (toFill++) EmojiData(740, 400, 3627933374, 0, 2); + new (toFill++) EmojiData(760, 400, 3627933375, 0, 2); + new (toFill++) EmojiData(780, 400, 3627933376, 0, 2); + new (toFill++) EmojiData(0, 420, 3627933377, 0, 2); + new (toFill++) EmojiData(20, 420, 3627933378, 0, 2); + new (toFill++) EmojiData(40, 420, 3627933379, 0, 2); + new (toFill++) EmojiData(60, 420, 3627933380, 0, 2); + new (toFill++) EmojiData(80, 420, 3627933381, 0, 2); + break; + + case dbisOneAndHalf: + new (toFill++) EmojiData(264, 0, 169, 0, 1); + new (toFill++) EmojiData(288, 0, 174, 0, 1); + new (toFill++) EmojiData(312, 0, 8252, 0, 1); + new (toFill++) EmojiData(336, 0, 8265, 0, 1); + new (toFill++) EmojiData(360, 0, 8482, 0, 1); + new (toFill++) EmojiData(384, 0, 8505, 0, 1); + new (toFill++) EmojiData(408, 0, 8596, 0, 1); + new (toFill++) EmojiData(432, 0, 8597, 0, 1); + new (toFill++) EmojiData(456, 0, 8598, 0, 1); + new (toFill++) EmojiData(480, 0, 8599, 0, 1); + new (toFill++) EmojiData(504, 0, 8600, 0, 1); + new (toFill++) EmojiData(528, 0, 8601, 0, 1); + new (toFill++) EmojiData(552, 0, 8617, 0, 1); + new (toFill++) EmojiData(576, 0, 8618, 0, 1); + new (toFill++) EmojiData(600, 0, 8986, 0, 1); + new (toFill++) EmojiData(624, 0, 8987, 0, 1); + new (toFill++) EmojiData(648, 0, 9193, 0, 1); + new (toFill++) EmojiData(672, 0, 9194, 0, 1); + new (toFill++) EmojiData(696, 0, 9195, 0, 1); + new (toFill++) EmojiData(720, 0, 9196, 0, 1); + new (toFill++) EmojiData(744, 0, 9200, 0, 1); + new (toFill++) EmojiData(768, 0, 9203, 0, 1); + new (toFill++) EmojiData(792, 0, 9410, 0, 1); + new (toFill++) EmojiData(816, 0, 9642, 0, 1); + new (toFill++) EmojiData(840, 0, 9643, 0, 1); + new (toFill++) EmojiData(864, 0, 9654, 0, 1); + new (toFill++) EmojiData(888, 0, 9664, 0, 1); + new (toFill++) EmojiData(912, 0, 9723, 0, 1); + new (toFill++) EmojiData(936, 0, 9724, 0, 1); + new (toFill++) EmojiData(0, 24, 9725, 0, 1); + new (toFill++) EmojiData(24, 24, 9726, 0, 1); + new (toFill++) EmojiData(48, 24, 9728, 0, 1); + new (toFill++) EmojiData(72, 24, 9729, 0, 1); + new (toFill++) EmojiData(96, 24, 9742, 0, 1); + new (toFill++) EmojiData(120, 24, 9745, 0, 1); + new (toFill++) EmojiData(144, 24, 9748, 0, 1); + new (toFill++) EmojiData(168, 24, 9749, 0, 1); + new (toFill++) EmojiData(192, 24, 9757, 0, 1); + new (toFill++) EmojiData(216, 24, 9786, 0, 1); + new (toFill++) EmojiData(240, 24, 9800, 0, 1); + new (toFill++) EmojiData(264, 24, 9801, 0, 1); + new (toFill++) EmojiData(288, 24, 9802, 0, 1); + new (toFill++) EmojiData(312, 24, 9803, 0, 1); + new (toFill++) EmojiData(336, 24, 9804, 0, 1); + new (toFill++) EmojiData(360, 24, 9805, 0, 1); + new (toFill++) EmojiData(384, 24, 9806, 0, 1); + new (toFill++) EmojiData(408, 24, 9807, 0, 1); + new (toFill++) EmojiData(432, 24, 9808, 0, 1); + new (toFill++) EmojiData(456, 24, 9809, 0, 1); + new (toFill++) EmojiData(480, 24, 9810, 0, 1); + new (toFill++) EmojiData(504, 24, 9811, 0, 1); + new (toFill++) EmojiData(528, 24, 9824, 0, 1); + new (toFill++) EmojiData(552, 24, 9827, 0, 1); + new (toFill++) EmojiData(576, 24, 9829, 0, 1); + new (toFill++) EmojiData(600, 24, 9830, 0, 1); + new (toFill++) EmojiData(624, 24, 9832, 0, 1); + new (toFill++) EmojiData(648, 24, 9851, 0, 1); + new (toFill++) EmojiData(672, 24, 9855, 0, 1); + new (toFill++) EmojiData(696, 24, 9875, 0, 1); + new (toFill++) EmojiData(720, 24, 9888, 0, 1); + new (toFill++) EmojiData(744, 24, 9889, 0, 1); + new (toFill++) EmojiData(768, 24, 9898, 0, 1); + new (toFill++) EmojiData(792, 24, 9899, 0, 1); + new (toFill++) EmojiData(816, 24, 9917, 0, 1); + new (toFill++) EmojiData(840, 24, 9918, 0, 1); + new (toFill++) EmojiData(864, 24, 9924, 0, 1); + new (toFill++) EmojiData(888, 24, 9925, 0, 1); + new (toFill++) EmojiData(912, 24, 9934, 0, 1); + new (toFill++) EmojiData(936, 24, 9940, 0, 1); + new (toFill++) EmojiData(0, 48, 9962, 0, 1); + new (toFill++) EmojiData(24, 48, 9970, 0, 1); + new (toFill++) EmojiData(48, 48, 9971, 0, 1); + new (toFill++) EmojiData(72, 48, 9973, 0, 1); + new (toFill++) EmojiData(96, 48, 9978, 0, 1); + new (toFill++) EmojiData(120, 48, 9981, 0, 1); + new (toFill++) EmojiData(144, 48, 9986, 0, 1); + new (toFill++) EmojiData(168, 48, 9989, 0, 1); + new (toFill++) EmojiData(192, 48, 9992, 0, 1); + new (toFill++) EmojiData(216, 48, 9993, 0, 1); + new (toFill++) EmojiData(240, 48, 9994, 0, 1); + new (toFill++) EmojiData(264, 48, 9995, 0, 1); + new (toFill++) EmojiData(288, 48, 9996, 0, 1); + new (toFill++) EmojiData(312, 48, 9999, 0, 1); + new (toFill++) EmojiData(336, 48, 10002, 0, 1); + new (toFill++) EmojiData(360, 48, 10004, 0, 1); + new (toFill++) EmojiData(384, 48, 10006, 0, 1); + new (toFill++) EmojiData(408, 48, 10024, 0, 1); + new (toFill++) EmojiData(432, 48, 10035, 0, 1); + new (toFill++) EmojiData(456, 48, 10036, 0, 1); + new (toFill++) EmojiData(480, 48, 10052, 0, 1); + new (toFill++) EmojiData(504, 48, 10055, 0, 1); + new (toFill++) EmojiData(528, 48, 10060, 0, 1); + new (toFill++) EmojiData(552, 48, 10062, 0, 1); + new (toFill++) EmojiData(576, 48, 10067, 0, 1); + new (toFill++) EmojiData(600, 48, 10068, 0, 1); + new (toFill++) EmojiData(624, 48, 10069, 0, 1); + new (toFill++) EmojiData(648, 48, 10071, 0, 1); + new (toFill++) EmojiData(672, 48, 10084, 0, 1); + new (toFill++) EmojiData(696, 48, 10133, 0, 1); + new (toFill++) EmojiData(720, 48, 10134, 0, 1); + new (toFill++) EmojiData(744, 48, 10135, 0, 1); + new (toFill++) EmojiData(768, 48, 10145, 0, 1); + new (toFill++) EmojiData(792, 48, 10160, 0, 1); + new (toFill++) EmojiData(816, 48, 10175, 0, 1); + new (toFill++) EmojiData(840, 48, 10548, 0, 1); + new (toFill++) EmojiData(864, 48, 10549, 0, 1); + new (toFill++) EmojiData(888, 48, 11013, 0, 1); + new (toFill++) EmojiData(912, 48, 11014, 0, 1); + new (toFill++) EmojiData(936, 48, 11015, 0, 1); + new (toFill++) EmojiData(0, 72, 11035, 0, 1); + new (toFill++) EmojiData(24, 72, 11036, 0, 1); + new (toFill++) EmojiData(48, 72, 11088, 0, 1); + new (toFill++) EmojiData(72, 72, 11093, 0, 1); + new (toFill++) EmojiData(96, 72, 12336, 0, 1); + new (toFill++) EmojiData(120, 72, 12349, 0, 1); + new (toFill++) EmojiData(144, 72, 12951, 0, 1); + new (toFill++) EmojiData(168, 72, 12953, 0, 1); + new (toFill++) EmojiData(0, 0, 2302179, 0, 2); + new (toFill++) EmojiData(24, 0, 3154147, 0, 2); + new (toFill++) EmojiData(48, 0, 3219683, 0, 2); + new (toFill++) EmojiData(72, 0, 3285219, 0, 2); + new (toFill++) EmojiData(96, 0, 3350755, 0, 2); + new (toFill++) EmojiData(120, 0, 3416291, 0, 2); + new (toFill++) EmojiData(144, 0, 3481827, 0, 2); + new (toFill++) EmojiData(168, 0, 3547363, 0, 2); + new (toFill++) EmojiData(192, 0, 3612899, 0, 2); + new (toFill++) EmojiData(216, 0, 3678435, 0, 2); + new (toFill++) EmojiData(240, 0, 3743971, 0, 2); + new (toFill++) EmojiData(192, 72, 3627867140, 0, 2); + new (toFill++) EmojiData(216, 72, 3627867343, 0, 2); + new (toFill++) EmojiData(240, 72, 3627867504, 0, 2); + new (toFill++) EmojiData(264, 72, 3627867505, 0, 2); + new (toFill++) EmojiData(288, 72, 3627867518, 0, 2); + new (toFill++) EmojiData(312, 72, 3627867519, 0, 2); + new (toFill++) EmojiData(336, 72, 3627867534, 0, 2); + new (toFill++) EmojiData(360, 72, 3627867537, 0, 2); + new (toFill++) EmojiData(384, 72, 3627867538, 0, 2); + new (toFill++) EmojiData(408, 72, 3627867539, 0, 2); + new (toFill++) EmojiData(432, 72, 3627867540, 0, 2); + new (toFill++) EmojiData(456, 72, 3627867541, 0, 2); + new (toFill++) EmojiData(480, 72, 3627867542, 0, 2); + new (toFill++) EmojiData(504, 72, 3627867543, 0, 2); + new (toFill++) EmojiData(528, 72, 3627867544, 0, 2); + new (toFill++) EmojiData(552, 72, 3627867545, 0, 2); + new (toFill++) EmojiData(576, 72, 3627867546, 0, 2); + new (toFill++) EmojiData(600, 72, 3627867624, 3627867635, 4); + new (toFill++) EmojiData(624, 72, 3627867625, 3627867626, 4); + new (toFill++) EmojiData(648, 72, 3627867626, 3627867640, 4); + new (toFill++) EmojiData(672, 72, 3627867627, 3627867639, 4); + new (toFill++) EmojiData(696, 72, 3627867628, 3627867623, 4); + new (toFill++) EmojiData(720, 72, 3627867630, 3627867641, 4); + new (toFill++) EmojiData(744, 72, 3627867631, 3627867637, 4); + new (toFill++) EmojiData(768, 72, 3627867632, 3627867639, 4); + new (toFill++) EmojiData(792, 72, 3627867639, 3627867642, 4); + new (toFill++) EmojiData(816, 72, 3627867642, 3627867640, 4); + new (toFill++) EmojiData(840, 72, 3627867649, 0, 2); + new (toFill++) EmojiData(864, 72, 3627867650, 0, 2); + new (toFill++) EmojiData(888, 72, 3627867674, 0, 2); + new (toFill++) EmojiData(912, 72, 3627867695, 0, 2); + new (toFill++) EmojiData(936, 72, 3627867698, 0, 2); + new (toFill++) EmojiData(0, 96, 3627867699, 0, 2); + new (toFill++) EmojiData(24, 96, 3627867700, 0, 2); + new (toFill++) EmojiData(48, 96, 3627867701, 0, 2); + new (toFill++) EmojiData(72, 96, 3627867702, 0, 2); + new (toFill++) EmojiData(96, 96, 3627867703, 0, 2); + new (toFill++) EmojiData(120, 96, 3627867704, 0, 2); + new (toFill++) EmojiData(144, 96, 3627867705, 0, 2); + new (toFill++) EmojiData(168, 96, 3627867706, 0, 2); + new (toFill++) EmojiData(192, 96, 3627867728, 0, 2); + new (toFill++) EmojiData(216, 96, 3627867729, 0, 2); + new (toFill++) EmojiData(240, 96, 3627867904, 0, 2); + new (toFill++) EmojiData(264, 96, 3627867905, 0, 2); + new (toFill++) EmojiData(288, 96, 3627867906, 0, 2); + new (toFill++) EmojiData(312, 96, 3627867907, 0, 2); + new (toFill++) EmojiData(336, 96, 3627867908, 0, 2); + new (toFill++) EmojiData(360, 96, 3627867909, 0, 2); + new (toFill++) EmojiData(384, 96, 3627867910, 0, 2); + new (toFill++) EmojiData(408, 96, 3627867911, 0, 2); + new (toFill++) EmojiData(432, 96, 3627867912, 0, 2); + new (toFill++) EmojiData(456, 96, 3627867913, 0, 2); + new (toFill++) EmojiData(480, 96, 3627867914, 0, 2); + new (toFill++) EmojiData(504, 96, 3627867915, 0, 2); + new (toFill++) EmojiData(528, 96, 3627867916, 0, 2); + new (toFill++) EmojiData(552, 96, 3627867917, 0, 2); + new (toFill++) EmojiData(576, 96, 3627867918, 0, 2); + new (toFill++) EmojiData(600, 96, 3627867919, 0, 2); + new (toFill++) EmojiData(624, 96, 3627867920, 0, 2); + new (toFill++) EmojiData(648, 96, 3627867921, 0, 2); + new (toFill++) EmojiData(672, 96, 3627867922, 0, 2); + new (toFill++) EmojiData(696, 96, 3627867923, 0, 2); + new (toFill++) EmojiData(720, 96, 3627867924, 0, 2); + new (toFill++) EmojiData(744, 96, 3627867925, 0, 2); + new (toFill++) EmojiData(768, 96, 3627867926, 0, 2); + new (toFill++) EmojiData(792, 96, 3627867927, 0, 2); + new (toFill++) EmojiData(816, 96, 3627867928, 0, 2); + new (toFill++) EmojiData(840, 96, 3627867929, 0, 2); + new (toFill++) EmojiData(864, 96, 3627867930, 0, 2); + new (toFill++) EmojiData(888, 96, 3627867931, 0, 2); + new (toFill++) EmojiData(912, 96, 3627867932, 0, 2); + new (toFill++) EmojiData(936, 96, 3627867933, 0, 2); + new (toFill++) EmojiData(0, 120, 3627867934, 0, 2); + new (toFill++) EmojiData(24, 120, 3627867935, 0, 2); + new (toFill++) EmojiData(48, 120, 3627867936, 0, 2); + new (toFill++) EmojiData(72, 120, 3627867952, 0, 2); + new (toFill++) EmojiData(96, 120, 3627867953, 0, 2); + new (toFill++) EmojiData(120, 120, 3627867954, 0, 2); + new (toFill++) EmojiData(144, 120, 3627867955, 0, 2); + new (toFill++) EmojiData(168, 120, 3627867956, 0, 2); + new (toFill++) EmojiData(192, 120, 3627867957, 0, 2); + new (toFill++) EmojiData(216, 120, 3627867959, 0, 2); + new (toFill++) EmojiData(240, 120, 3627867960, 0, 2); + new (toFill++) EmojiData(264, 120, 3627867961, 0, 2); + new (toFill++) EmojiData(288, 120, 3627867962, 0, 2); + new (toFill++) EmojiData(312, 120, 3627867963, 0, 2); + new (toFill++) EmojiData(336, 120, 3627867964, 0, 2); + new (toFill++) EmojiData(360, 120, 3627867965, 0, 2); + new (toFill++) EmojiData(384, 120, 3627867966, 0, 2); + new (toFill++) EmojiData(408, 120, 3627867967, 0, 2); + new (toFill++) EmojiData(432, 120, 3627867968, 0, 2); + new (toFill++) EmojiData(456, 120, 3627867969, 0, 2); + new (toFill++) EmojiData(480, 120, 3627867970, 0, 2); + new (toFill++) EmojiData(504, 120, 3627867971, 0, 2); + new (toFill++) EmojiData(528, 120, 3627867972, 0, 2); + new (toFill++) EmojiData(552, 120, 3627867973, 0, 2); + new (toFill++) EmojiData(576, 120, 3627867974, 0, 2); + new (toFill++) EmojiData(600, 120, 3627867975, 0, 2); + new (toFill++) EmojiData(624, 120, 3627867976, 0, 2); + new (toFill++) EmojiData(648, 120, 3627867977, 0, 2); + new (toFill++) EmojiData(672, 120, 3627867978, 0, 2); + new (toFill++) EmojiData(696, 120, 3627867979, 0, 2); + new (toFill++) EmojiData(720, 120, 3627867980, 0, 2); + new (toFill++) EmojiData(744, 120, 3627867981, 0, 2); + new (toFill++) EmojiData(768, 120, 3627867982, 0, 2); + new (toFill++) EmojiData(792, 120, 3627867983, 0, 2); + new (toFill++) EmojiData(816, 120, 3627867984, 0, 2); + new (toFill++) EmojiData(840, 120, 3627867985, 0, 2); + new (toFill++) EmojiData(864, 120, 3627867986, 0, 2); + new (toFill++) EmojiData(888, 120, 3627867987, 0, 2); + new (toFill++) EmojiData(912, 120, 3627867988, 0, 2); + new (toFill++) EmojiData(936, 120, 3627867989, 0, 2); + new (toFill++) EmojiData(0, 144, 3627867990, 0, 2); + new (toFill++) EmojiData(24, 144, 3627867991, 0, 2); + new (toFill++) EmojiData(48, 144, 3627867992, 0, 2); + new (toFill++) EmojiData(72, 144, 3627867993, 0, 2); + new (toFill++) EmojiData(96, 144, 3627867994, 0, 2); + new (toFill++) EmojiData(120, 144, 3627867995, 0, 2); + new (toFill++) EmojiData(144, 144, 3627867996, 0, 2); + new (toFill++) EmojiData(168, 144, 3627867997, 0, 2); + new (toFill++) EmojiData(192, 144, 3627867998, 0, 2); + new (toFill++) EmojiData(216, 144, 3627867999, 0, 2); + new (toFill++) EmojiData(240, 144, 3627868000, 0, 2); + new (toFill++) EmojiData(264, 144, 3627868001, 0, 2); + new (toFill++) EmojiData(288, 144, 3627868002, 0, 2); + new (toFill++) EmojiData(312, 144, 3627868003, 0, 2); + new (toFill++) EmojiData(336, 144, 3627868004, 0, 2); + new (toFill++) EmojiData(360, 144, 3627868005, 0, 2); + new (toFill++) EmojiData(384, 144, 3627868006, 0, 2); + new (toFill++) EmojiData(408, 144, 3627868007, 0, 2); + new (toFill++) EmojiData(432, 144, 3627868008, 0, 2); + new (toFill++) EmojiData(456, 144, 3627868009, 0, 2); + new (toFill++) EmojiData(480, 144, 3627868010, 0, 2); + new (toFill++) EmojiData(504, 144, 3627868011, 0, 2); + new (toFill++) EmojiData(528, 144, 3627868012, 0, 2); + new (toFill++) EmojiData(552, 144, 3627868013, 0, 2); + new (toFill++) EmojiData(576, 144, 3627868014, 0, 2); + new (toFill++) EmojiData(600, 144, 3627868015, 0, 2); + new (toFill++) EmojiData(624, 144, 3627868016, 0, 2); + new (toFill++) EmojiData(648, 144, 3627868017, 0, 2); + new (toFill++) EmojiData(672, 144, 3627868018, 0, 2); + new (toFill++) EmojiData(696, 144, 3627868019, 0, 2); + new (toFill++) EmojiData(720, 144, 3627868020, 0, 2); + new (toFill++) EmojiData(744, 144, 3627868021, 0, 2); + new (toFill++) EmojiData(768, 144, 3627868022, 0, 2); + new (toFill++) EmojiData(792, 144, 3627868023, 0, 2); + new (toFill++) EmojiData(816, 144, 3627868024, 0, 2); + new (toFill++) EmojiData(840, 144, 3627868025, 0, 2); + new (toFill++) EmojiData(864, 144, 3627868026, 0, 2); + new (toFill++) EmojiData(888, 144, 3627868027, 0, 2); + new (toFill++) EmojiData(912, 144, 3627868028, 0, 2); + new (toFill++) EmojiData(936, 144, 3627868032, 0, 2); + new (toFill++) EmojiData(0, 168, 3627868033, 0, 2); + new (toFill++) EmojiData(24, 168, 3627868034, 0, 2); + new (toFill++) EmojiData(48, 168, 3627868035, 0, 2); + new (toFill++) EmojiData(72, 168, 3627868036, 0, 2); + new (toFill++) EmojiData(96, 168, 3627868037, 0, 2); + new (toFill++) EmojiData(120, 168, 3627868038, 0, 2); + new (toFill++) EmojiData(144, 168, 3627868039, 0, 2); + new (toFill++) EmojiData(168, 168, 3627868040, 0, 2); + new (toFill++) EmojiData(192, 168, 3627868041, 0, 2); + new (toFill++) EmojiData(216, 168, 3627868042, 0, 2); + new (toFill++) EmojiData(240, 168, 3627868043, 0, 2); + new (toFill++) EmojiData(264, 168, 3627868044, 0, 2); + new (toFill++) EmojiData(288, 168, 3627868045, 0, 2); + new (toFill++) EmojiData(312, 168, 3627868046, 0, 2); + new (toFill++) EmojiData(336, 168, 3627868047, 0, 2); + new (toFill++) EmojiData(360, 168, 3627868048, 0, 2); + new (toFill++) EmojiData(384, 168, 3627868049, 0, 2); + new (toFill++) EmojiData(408, 168, 3627868050, 0, 2); + new (toFill++) EmojiData(432, 168, 3627868051, 0, 2); + new (toFill++) EmojiData(456, 168, 3627868064, 0, 2); + new (toFill++) EmojiData(480, 168, 3627868065, 0, 2); + new (toFill++) EmojiData(504, 168, 3627868066, 0, 2); + new (toFill++) EmojiData(528, 168, 3627868067, 0, 2); + new (toFill++) EmojiData(552, 168, 3627868068, 0, 2); + new (toFill++) EmojiData(576, 168, 3627868069, 0, 2); + new (toFill++) EmojiData(600, 168, 3627868070, 0, 2); + new (toFill++) EmojiData(624, 168, 3627868071, 0, 2); + new (toFill++) EmojiData(648, 168, 3627868072, 0, 2); + new (toFill++) EmojiData(672, 168, 3627868073, 0, 2); + new (toFill++) EmojiData(696, 168, 3627868074, 0, 2); + new (toFill++) EmojiData(720, 168, 3627868075, 0, 2); + new (toFill++) EmojiData(744, 168, 3627868076, 0, 2); + new (toFill++) EmojiData(768, 168, 3627868077, 0, 2); + new (toFill++) EmojiData(792, 168, 3627868078, 0, 2); + new (toFill++) EmojiData(816, 168, 3627868079, 0, 2); + new (toFill++) EmojiData(840, 168, 3627868080, 0, 2); + new (toFill++) EmojiData(864, 168, 3627868081, 0, 2); + new (toFill++) EmojiData(888, 168, 3627868082, 0, 2); + new (toFill++) EmojiData(912, 168, 3627868083, 0, 2); + new (toFill++) EmojiData(936, 168, 3627868084, 0, 2); + new (toFill++) EmojiData(0, 192, 3627868085, 0, 2); + new (toFill++) EmojiData(24, 192, 3627868086, 0, 2); + new (toFill++) EmojiData(48, 192, 3627868087, 0, 2); + new (toFill++) EmojiData(72, 192, 3627868088, 0, 2); + new (toFill++) EmojiData(96, 192, 3627868089, 0, 2); + new (toFill++) EmojiData(120, 192, 3627868090, 0, 2); + new (toFill++) EmojiData(144, 192, 3627868091, 0, 2); + new (toFill++) EmojiData(168, 192, 3627868092, 0, 2); + new (toFill++) EmojiData(192, 192, 3627868093, 0, 2); + new (toFill++) EmojiData(216, 192, 3627868094, 0, 2); + new (toFill++) EmojiData(240, 192, 3627868095, 0, 2); + new (toFill++) EmojiData(264, 192, 3627868096, 0, 2); + new (toFill++) EmojiData(288, 192, 3627868097, 0, 2); + new (toFill++) EmojiData(312, 192, 3627868098, 0, 2); + new (toFill++) EmojiData(336, 192, 3627868099, 0, 2); + new (toFill++) EmojiData(360, 192, 3627868100, 0, 2); + new (toFill++) EmojiData(384, 192, 3627868102, 0, 2); + new (toFill++) EmojiData(408, 192, 3627868103, 0, 2); + new (toFill++) EmojiData(432, 192, 3627868104, 0, 2); + new (toFill++) EmojiData(456, 192, 3627868105, 0, 2); + new (toFill++) EmojiData(480, 192, 3627868106, 0, 2); + new (toFill++) EmojiData(504, 192, 3627868128, 0, 2); + new (toFill++) EmojiData(528, 192, 3627868129, 0, 2); + new (toFill++) EmojiData(552, 192, 3627868130, 0, 2); + new (toFill++) EmojiData(576, 192, 3627868131, 0, 2); + new (toFill++) EmojiData(600, 192, 3627868132, 0, 2); + new (toFill++) EmojiData(624, 192, 3627868133, 0, 2); + new (toFill++) EmojiData(648, 192, 3627868134, 0, 2); + new (toFill++) EmojiData(672, 192, 3627868135, 0, 2); + new (toFill++) EmojiData(696, 192, 3627868136, 0, 2); + new (toFill++) EmojiData(720, 192, 3627868137, 0, 2); + new (toFill++) EmojiData(744, 192, 3627868138, 0, 2); + new (toFill++) EmojiData(768, 192, 3627868139, 0, 2); + new (toFill++) EmojiData(792, 192, 3627868140, 0, 2); + new (toFill++) EmojiData(816, 192, 3627868141, 0, 2); + new (toFill++) EmojiData(840, 192, 3627868142, 0, 2); + new (toFill++) EmojiData(864, 192, 3627868143, 0, 2); + new (toFill++) EmojiData(888, 192, 3627868144, 0, 2); + new (toFill++) EmojiData(912, 192, 3627932672, 0, 2); + new (toFill++) EmojiData(936, 192, 3627932673, 0, 2); + new (toFill++) EmojiData(0, 216, 3627932674, 0, 2); + new (toFill++) EmojiData(24, 216, 3627932675, 0, 2); + new (toFill++) EmojiData(48, 216, 3627932676, 0, 2); + new (toFill++) EmojiData(72, 216, 3627932677, 0, 2); + new (toFill++) EmojiData(96, 216, 3627932678, 0, 2); + new (toFill++) EmojiData(120, 216, 3627932679, 0, 2); + new (toFill++) EmojiData(144, 216, 3627932680, 0, 2); + new (toFill++) EmojiData(168, 216, 3627932681, 0, 2); + new (toFill++) EmojiData(192, 216, 3627932682, 0, 2); + new (toFill++) EmojiData(216, 216, 3627932683, 0, 2); + new (toFill++) EmojiData(240, 216, 3627932684, 0, 2); + new (toFill++) EmojiData(264, 216, 3627932685, 0, 2); + new (toFill++) EmojiData(288, 216, 3627932686, 0, 2); + new (toFill++) EmojiData(312, 216, 3627932687, 0, 2); + new (toFill++) EmojiData(336, 216, 3627932688, 0, 2); + new (toFill++) EmojiData(360, 216, 3627932689, 0, 2); + new (toFill++) EmojiData(384, 216, 3627932690, 0, 2); + new (toFill++) EmojiData(408, 216, 3627932691, 0, 2); + new (toFill++) EmojiData(432, 216, 3627932692, 0, 2); + new (toFill++) EmojiData(456, 216, 3627932693, 0, 2); + new (toFill++) EmojiData(480, 216, 3627932694, 0, 2); + new (toFill++) EmojiData(504, 216, 3627932695, 0, 2); + new (toFill++) EmojiData(528, 216, 3627932696, 0, 2); + new (toFill++) EmojiData(552, 216, 3627932697, 0, 2); + new (toFill++) EmojiData(576, 216, 3627932698, 0, 2); + new (toFill++) EmojiData(600, 216, 3627932699, 0, 2); + new (toFill++) EmojiData(624, 216, 3627932700, 0, 2); + new (toFill++) EmojiData(648, 216, 3627932701, 0, 2); + new (toFill++) EmojiData(672, 216, 3627932702, 0, 2); + new (toFill++) EmojiData(696, 216, 3627932703, 0, 2); + new (toFill++) EmojiData(720, 216, 3627932704, 0, 2); + new (toFill++) EmojiData(744, 216, 3627932705, 0, 2); + new (toFill++) EmojiData(768, 216, 3627932706, 0, 2); + new (toFill++) EmojiData(792, 216, 3627932707, 0, 2); + new (toFill++) EmojiData(816, 216, 3627932708, 0, 2); + new (toFill++) EmojiData(840, 216, 3627932709, 0, 2); + new (toFill++) EmojiData(864, 216, 3627932710, 0, 2); + new (toFill++) EmojiData(888, 216, 3627932711, 0, 2); + new (toFill++) EmojiData(912, 216, 3627932712, 0, 2); + new (toFill++) EmojiData(936, 216, 3627932713, 0, 2); + new (toFill++) EmojiData(0, 240, 3627932714, 0, 2); + new (toFill++) EmojiData(24, 240, 3627932715, 0, 2); + new (toFill++) EmojiData(48, 240, 3627932716, 0, 2); + new (toFill++) EmojiData(72, 240, 3627932717, 0, 2); + new (toFill++) EmojiData(96, 240, 3627932718, 0, 2); + new (toFill++) EmojiData(120, 240, 3627932719, 0, 2); + new (toFill++) EmojiData(144, 240, 3627932720, 0, 2); + new (toFill++) EmojiData(168, 240, 3627932721, 0, 2); + new (toFill++) EmojiData(192, 240, 3627932722, 0, 2); + new (toFill++) EmojiData(216, 240, 3627932723, 0, 2); + new (toFill++) EmojiData(240, 240, 3627932724, 0, 2); + new (toFill++) EmojiData(264, 240, 3627932725, 0, 2); + new (toFill++) EmojiData(288, 240, 3627932726, 0, 2); + new (toFill++) EmojiData(312, 240, 3627932727, 0, 2); + new (toFill++) EmojiData(336, 240, 3627932728, 0, 2); + new (toFill++) EmojiData(360, 240, 3627932729, 0, 2); + new (toFill++) EmojiData(384, 240, 3627932730, 0, 2); + new (toFill++) EmojiData(408, 240, 3627932731, 0, 2); + new (toFill++) EmojiData(432, 240, 3627932732, 0, 2); + new (toFill++) EmojiData(456, 240, 3627932733, 0, 2); + new (toFill++) EmojiData(480, 240, 3627932734, 0, 2); + new (toFill++) EmojiData(504, 240, 3627932736, 0, 2); + new (toFill++) EmojiData(528, 240, 3627932738, 0, 2); + new (toFill++) EmojiData(552, 240, 3627932739, 0, 2); + new (toFill++) EmojiData(576, 240, 3627932740, 0, 2); + new (toFill++) EmojiData(600, 240, 3627932741, 0, 2); + new (toFill++) EmojiData(624, 240, 3627932742, 0, 2); + new (toFill++) EmojiData(648, 240, 3627932743, 0, 2); + new (toFill++) EmojiData(672, 240, 3627932744, 0, 2); + new (toFill++) EmojiData(696, 240, 3627932745, 0, 2); + new (toFill++) EmojiData(720, 240, 3627932746, 0, 2); + new (toFill++) EmojiData(744, 240, 3627932747, 0, 2); + new (toFill++) EmojiData(768, 240, 3627932748, 0, 2); + new (toFill++) EmojiData(792, 240, 3627932749, 0, 2); + new (toFill++) EmojiData(816, 240, 3627932750, 0, 2); + new (toFill++) EmojiData(840, 240, 3627932751, 0, 2); + new (toFill++) EmojiData(864, 240, 3627932752, 0, 2); + new (toFill++) EmojiData(888, 240, 3627932753, 0, 2); + new (toFill++) EmojiData(912, 240, 3627932754, 0, 2); + new (toFill++) EmojiData(936, 240, 3627932755, 0, 2); + new (toFill++) EmojiData(0, 264, 3627932756, 0, 2); + new (toFill++) EmojiData(24, 264, 3627932757, 0, 2); + new (toFill++) EmojiData(48, 264, 3627932758, 0, 2); + new (toFill++) EmojiData(72, 264, 3627932759, 0, 2); + new (toFill++) EmojiData(96, 264, 3627932760, 0, 2); + new (toFill++) EmojiData(120, 264, 3627932761, 0, 2); + new (toFill++) EmojiData(144, 264, 3627932762, 0, 2); + new (toFill++) EmojiData(168, 264, 3627932763, 0, 2); + new (toFill++) EmojiData(192, 264, 3627932764, 0, 2); + new (toFill++) EmojiData(216, 264, 3627932765, 0, 2); + new (toFill++) EmojiData(240, 264, 3627932766, 0, 2); + new (toFill++) EmojiData(264, 264, 3627932767, 0, 2); + new (toFill++) EmojiData(288, 264, 3627932768, 0, 2); + new (toFill++) EmojiData(312, 264, 3627932769, 0, 2); + new (toFill++) EmojiData(336, 264, 3627932770, 0, 2); + new (toFill++) EmojiData(360, 264, 3627932771, 0, 2); + new (toFill++) EmojiData(384, 264, 3627932772, 0, 2); + new (toFill++) EmojiData(408, 264, 3627932773, 0, 2); + new (toFill++) EmojiData(432, 264, 3627932774, 0, 2); + new (toFill++) EmojiData(456, 264, 3627932775, 0, 2); + new (toFill++) EmojiData(480, 264, 3627932776, 0, 2); + new (toFill++) EmojiData(504, 264, 3627932777, 0, 2); + new (toFill++) EmojiData(528, 264, 3627932778, 0, 2); + new (toFill++) EmojiData(552, 264, 3627932779, 0, 2); + new (toFill++) EmojiData(576, 264, 3627932780, 0, 2); + new (toFill++) EmojiData(600, 264, 3627932781, 0, 2); + new (toFill++) EmojiData(624, 264, 3627932782, 0, 2); + new (toFill++) EmojiData(648, 264, 3627932783, 0, 2); + new (toFill++) EmojiData(672, 264, 3627932784, 0, 2); + new (toFill++) EmojiData(696, 264, 3627932785, 0, 2); + new (toFill++) EmojiData(720, 264, 3627932786, 0, 2); + new (toFill++) EmojiData(744, 264, 3627932787, 0, 2); + new (toFill++) EmojiData(768, 264, 3627932788, 0, 2); + new (toFill++) EmojiData(792, 264, 3627932789, 0, 2); + new (toFill++) EmojiData(816, 264, 3627932790, 0, 2); + new (toFill++) EmojiData(840, 264, 3627932791, 0, 2); + new (toFill++) EmojiData(864, 264, 3627932792, 0, 2); + new (toFill++) EmojiData(888, 264, 3627932793, 0, 2); + new (toFill++) EmojiData(912, 264, 3627932794, 0, 2); + new (toFill++) EmojiData(936, 264, 3627932795, 0, 2); + new (toFill++) EmojiData(0, 288, 3627932796, 0, 2); + new (toFill++) EmojiData(24, 288, 3627932797, 0, 2); + new (toFill++) EmojiData(48, 288, 3627932798, 0, 2); + new (toFill++) EmojiData(72, 288, 3627932799, 0, 2); + new (toFill++) EmojiData(96, 288, 3627932800, 0, 2); + new (toFill++) EmojiData(120, 288, 3627932801, 0, 2); + new (toFill++) EmojiData(144, 288, 3627932802, 0, 2); + new (toFill++) EmojiData(168, 288, 3627932803, 0, 2); + new (toFill++) EmojiData(192, 288, 3627932804, 0, 2); + new (toFill++) EmojiData(216, 288, 3627932805, 0, 2); + new (toFill++) EmojiData(240, 288, 3627932806, 0, 2); + new (toFill++) EmojiData(264, 288, 3627932807, 0, 2); + new (toFill++) EmojiData(288, 288, 3627932808, 0, 2); + new (toFill++) EmojiData(312, 288, 3627932809, 0, 2); + new (toFill++) EmojiData(336, 288, 3627932810, 0, 2); + new (toFill++) EmojiData(360, 288, 3627932811, 0, 2); + new (toFill++) EmojiData(384, 288, 3627932812, 0, 2); + new (toFill++) EmojiData(408, 288, 3627932813, 0, 2); + new (toFill++) EmojiData(432, 288, 3627932814, 0, 2); + new (toFill++) EmojiData(456, 288, 3627932815, 0, 2); + new (toFill++) EmojiData(480, 288, 3627932816, 0, 2); + new (toFill++) EmojiData(504, 288, 3627932817, 0, 2); + new (toFill++) EmojiData(528, 288, 3627932818, 0, 2); + new (toFill++) EmojiData(552, 288, 3627932819, 0, 2); + new (toFill++) EmojiData(576, 288, 3627932820, 0, 2); + new (toFill++) EmojiData(600, 288, 3627932821, 0, 2); + new (toFill++) EmojiData(624, 288, 3627932822, 0, 2); + new (toFill++) EmojiData(648, 288, 3627932823, 0, 2); + new (toFill++) EmojiData(672, 288, 3627932824, 0, 2); + new (toFill++) EmojiData(696, 288, 3627932825, 0, 2); + new (toFill++) EmojiData(720, 288, 3627932826, 0, 2); + new (toFill++) EmojiData(744, 288, 3627932827, 0, 2); + new (toFill++) EmojiData(768, 288, 3627932828, 0, 2); + new (toFill++) EmojiData(792, 288, 3627932829, 0, 2); + new (toFill++) EmojiData(816, 288, 3627932830, 0, 2); + new (toFill++) EmojiData(840, 288, 3627932831, 0, 2); + new (toFill++) EmojiData(864, 288, 3627932832, 0, 2); + new (toFill++) EmojiData(888, 288, 3627932833, 0, 2); + new (toFill++) EmojiData(912, 288, 3627932834, 0, 2); + new (toFill++) EmojiData(936, 288, 3627932835, 0, 2); + new (toFill++) EmojiData(0, 312, 3627932836, 0, 2); + new (toFill++) EmojiData(24, 312, 3627932837, 0, 2); + new (toFill++) EmojiData(48, 312, 3627932838, 0, 2); + new (toFill++) EmojiData(72, 312, 3627932839, 0, 2); + new (toFill++) EmojiData(96, 312, 3627932840, 0, 2); + new (toFill++) EmojiData(120, 312, 3627932841, 0, 2); + new (toFill++) EmojiData(144, 312, 3627932842, 0, 2); + new (toFill++) EmojiData(168, 312, 3627932843, 0, 2); + new (toFill++) EmojiData(192, 312, 3627932844, 0, 2); + new (toFill++) EmojiData(216, 312, 3627932845, 0, 2); + new (toFill++) EmojiData(240, 312, 3627932846, 0, 2); + new (toFill++) EmojiData(264, 312, 3627932847, 0, 2); + new (toFill++) EmojiData(288, 312, 3627932848, 0, 2); + new (toFill++) EmojiData(312, 312, 3627932849, 0, 2); + new (toFill++) EmojiData(336, 312, 3627932850, 0, 2); + new (toFill++) EmojiData(360, 312, 3627932851, 0, 2); + new (toFill++) EmojiData(384, 312, 3627932852, 0, 2); + new (toFill++) EmojiData(408, 312, 3627932853, 0, 2); + new (toFill++) EmojiData(432, 312, 3627932854, 0, 2); + new (toFill++) EmojiData(456, 312, 3627932855, 0, 2); + new (toFill++) EmojiData(480, 312, 3627932856, 0, 2); + new (toFill++) EmojiData(504, 312, 3627932857, 0, 2); + new (toFill++) EmojiData(528, 312, 3627932858, 0, 2); + new (toFill++) EmojiData(552, 312, 3627932859, 0, 2); + new (toFill++) EmojiData(576, 312, 3627932860, 0, 2); + new (toFill++) EmojiData(600, 312, 3627932861, 0, 2); + new (toFill++) EmojiData(624, 312, 3627932862, 0, 2); + new (toFill++) EmojiData(648, 312, 3627932863, 0, 2); + new (toFill++) EmojiData(672, 312, 3627932864, 0, 2); + new (toFill++) EmojiData(696, 312, 3627932865, 0, 2); + new (toFill++) EmojiData(720, 312, 3627932866, 0, 2); + new (toFill++) EmojiData(744, 312, 3627932867, 0, 2); + new (toFill++) EmojiData(768, 312, 3627932868, 0, 2); + new (toFill++) EmojiData(792, 312, 3627932869, 0, 2); + new (toFill++) EmojiData(816, 312, 3627932870, 0, 2); + new (toFill++) EmojiData(840, 312, 3627932871, 0, 2); + new (toFill++) EmojiData(864, 312, 3627932872, 0, 2); + new (toFill++) EmojiData(888, 312, 3627932873, 0, 2); + new (toFill++) EmojiData(912, 312, 3627932874, 0, 2); + new (toFill++) EmojiData(936, 312, 3627932875, 0, 2); + new (toFill++) EmojiData(0, 336, 3627932876, 0, 2); + new (toFill++) EmojiData(24, 336, 3627932877, 0, 2); + new (toFill++) EmojiData(48, 336, 3627932878, 0, 2); + new (toFill++) EmojiData(72, 336, 3627932879, 0, 2); + new (toFill++) EmojiData(96, 336, 3627932880, 0, 2); + new (toFill++) EmojiData(120, 336, 3627932881, 0, 2); + new (toFill++) EmojiData(144, 336, 3627932882, 0, 2); + new (toFill++) EmojiData(168, 336, 3627932883, 0, 2); + new (toFill++) EmojiData(192, 336, 3627932884, 0, 2); + new (toFill++) EmojiData(216, 336, 3627932885, 0, 2); + new (toFill++) EmojiData(240, 336, 3627932886, 0, 2); + new (toFill++) EmojiData(264, 336, 3627932887, 0, 2); + new (toFill++) EmojiData(288, 336, 3627932888, 0, 2); + new (toFill++) EmojiData(312, 336, 3627932889, 0, 2); + new (toFill++) EmojiData(336, 336, 3627932890, 0, 2); + new (toFill++) EmojiData(360, 336, 3627932891, 0, 2); + new (toFill++) EmojiData(384, 336, 3627932892, 0, 2); + new (toFill++) EmojiData(408, 336, 3627932893, 0, 2); + new (toFill++) EmojiData(432, 336, 3627932894, 0, 2); + new (toFill++) EmojiData(456, 336, 3627932895, 0, 2); + new (toFill++) EmojiData(480, 336, 3627932896, 0, 2); + new (toFill++) EmojiData(504, 336, 3627932897, 0, 2); + new (toFill++) EmojiData(528, 336, 3627932898, 0, 2); + new (toFill++) EmojiData(552, 336, 3627932899, 0, 2); + new (toFill++) EmojiData(576, 336, 3627932900, 0, 2); + new (toFill++) EmojiData(600, 336, 3627932901, 0, 2); + new (toFill++) EmojiData(624, 336, 3627932902, 0, 2); + new (toFill++) EmojiData(648, 336, 3627932903, 0, 2); + new (toFill++) EmojiData(672, 336, 3627932904, 0, 2); + new (toFill++) EmojiData(696, 336, 3627932905, 0, 2); + new (toFill++) EmojiData(720, 336, 3627932906, 0, 2); + new (toFill++) EmojiData(744, 336, 3627932907, 0, 2); + new (toFill++) EmojiData(768, 336, 3627932908, 0, 2); + new (toFill++) EmojiData(792, 336, 3627932909, 0, 2); + new (toFill++) EmojiData(816, 336, 3627932910, 0, 2); + new (toFill++) EmojiData(840, 336, 3627932911, 0, 2); + new (toFill++) EmojiData(864, 336, 3627932912, 0, 2); + new (toFill++) EmojiData(888, 336, 3627932913, 0, 2); + new (toFill++) EmojiData(912, 336, 3627932914, 0, 2); + new (toFill++) EmojiData(936, 336, 3627932915, 0, 2); + new (toFill++) EmojiData(0, 360, 3627932916, 0, 2); + new (toFill++) EmojiData(24, 360, 3627932917, 0, 2); + new (toFill++) EmojiData(48, 360, 3627932918, 0, 2); + new (toFill++) EmojiData(72, 360, 3627932919, 0, 2); + new (toFill++) EmojiData(96, 360, 3627932921, 0, 2); + new (toFill++) EmojiData(120, 360, 3627932922, 0, 2); + new (toFill++) EmojiData(144, 360, 3627932923, 0, 2); + new (toFill++) EmojiData(168, 360, 3627932924, 0, 2); + new (toFill++) EmojiData(192, 360, 3627932928, 0, 2); + new (toFill++) EmojiData(216, 360, 3627932929, 0, 2); + new (toFill++) EmojiData(240, 360, 3627932930, 0, 2); + new (toFill++) EmojiData(264, 360, 3627932931, 0, 2); + new (toFill++) EmojiData(288, 360, 3627932932, 0, 2); + new (toFill++) EmojiData(312, 360, 3627932933, 0, 2); + new (toFill++) EmojiData(336, 360, 3627932934, 0, 2); + new (toFill++) EmojiData(360, 360, 3627932935, 0, 2); + new (toFill++) EmojiData(384, 360, 3627932936, 0, 2); + new (toFill++) EmojiData(408, 360, 3627932937, 0, 2); + new (toFill++) EmojiData(432, 360, 3627932938, 0, 2); + new (toFill++) EmojiData(456, 360, 3627932939, 0, 2); + new (toFill++) EmojiData(480, 360, 3627932940, 0, 2); + new (toFill++) EmojiData(504, 360, 3627932941, 0, 2); + new (toFill++) EmojiData(528, 360, 3627932942, 0, 2); + new (toFill++) EmojiData(552, 360, 3627932943, 0, 2); + new (toFill++) EmojiData(576, 360, 3627932944, 0, 2); + new (toFill++) EmojiData(600, 360, 3627932945, 0, 2); + new (toFill++) EmojiData(624, 360, 3627932946, 0, 2); + new (toFill++) EmojiData(648, 360, 3627932947, 0, 2); + new (toFill++) EmojiData(672, 360, 3627932948, 0, 2); + new (toFill++) EmojiData(696, 360, 3627932949, 0, 2); + new (toFill++) EmojiData(720, 360, 3627932950, 0, 2); + new (toFill++) EmojiData(744, 360, 3627932951, 0, 2); + new (toFill++) EmojiData(768, 360, 3627932952, 0, 2); + new (toFill++) EmojiData(792, 360, 3627932953, 0, 2); + new (toFill++) EmojiData(816, 360, 3627932954, 0, 2); + new (toFill++) EmojiData(840, 360, 3627932955, 0, 2); + new (toFill++) EmojiData(864, 360, 3627932956, 0, 2); + new (toFill++) EmojiData(888, 360, 3627932957, 0, 2); + new (toFill++) EmojiData(912, 360, 3627932958, 0, 2); + new (toFill++) EmojiData(936, 360, 3627932959, 0, 2); + new (toFill++) EmojiData(0, 384, 3627932960, 0, 2); + new (toFill++) EmojiData(24, 384, 3627932961, 0, 2); + new (toFill++) EmojiData(48, 384, 3627932962, 0, 2); + new (toFill++) EmojiData(72, 384, 3627932963, 0, 2); + new (toFill++) EmojiData(96, 384, 3627932964, 0, 2); + new (toFill++) EmojiData(120, 384, 3627932965, 0, 2); + new (toFill++) EmojiData(144, 384, 3627932966, 0, 2); + new (toFill++) EmojiData(168, 384, 3627932967, 0, 2); + new (toFill++) EmojiData(192, 384, 3627932968, 0, 2); + new (toFill++) EmojiData(216, 384, 3627932969, 0, 2); + new (toFill++) EmojiData(240, 384, 3627932970, 0, 2); + new (toFill++) EmojiData(264, 384, 3627932971, 0, 2); + new (toFill++) EmojiData(288, 384, 3627932972, 0, 2); + new (toFill++) EmojiData(312, 384, 3627932973, 0, 2); + new (toFill++) EmojiData(336, 384, 3627932974, 0, 2); + new (toFill++) EmojiData(360, 384, 3627932975, 0, 2); + new (toFill++) EmojiData(384, 384, 3627932976, 0, 2); + new (toFill++) EmojiData(408, 384, 3627932977, 0, 2); + new (toFill++) EmojiData(432, 384, 3627932978, 0, 2); + new (toFill++) EmojiData(456, 384, 3627932979, 0, 2); + new (toFill++) EmojiData(480, 384, 3627932980, 0, 2); + new (toFill++) EmojiData(504, 384, 3627932981, 0, 2); + new (toFill++) EmojiData(528, 384, 3627932982, 0, 2); + new (toFill++) EmojiData(552, 384, 3627932983, 0, 2); + new (toFill++) EmojiData(576, 384, 3627932984, 0, 2); + new (toFill++) EmojiData(600, 384, 3627932985, 0, 2); + new (toFill++) EmojiData(624, 384, 3627932986, 0, 2); + new (toFill++) EmojiData(648, 384, 3627932987, 0, 2); + new (toFill++) EmojiData(672, 384, 3627932988, 0, 2); + new (toFill++) EmojiData(696, 384, 3627932989, 0, 2); + new (toFill++) EmojiData(720, 384, 3627933008, 0, 2); + new (toFill++) EmojiData(744, 384, 3627933009, 0, 2); + new (toFill++) EmojiData(768, 384, 3627933010, 0, 2); + new (toFill++) EmojiData(792, 384, 3627933011, 0, 2); + new (toFill++) EmojiData(816, 384, 3627933012, 0, 2); + new (toFill++) EmojiData(840, 384, 3627933013, 0, 2); + new (toFill++) EmojiData(864, 384, 3627933014, 0, 2); + new (toFill++) EmojiData(888, 384, 3627933015, 0, 2); + new (toFill++) EmojiData(912, 384, 3627933016, 0, 2); + new (toFill++) EmojiData(936, 384, 3627933017, 0, 2); + new (toFill++) EmojiData(0, 408, 3627933018, 0, 2); + new (toFill++) EmojiData(24, 408, 3627933019, 0, 2); + new (toFill++) EmojiData(48, 408, 3627933020, 0, 2); + new (toFill++) EmojiData(72, 408, 3627933021, 0, 2); + new (toFill++) EmojiData(96, 408, 3627933022, 0, 2); + new (toFill++) EmojiData(120, 408, 3627933023, 0, 2); + new (toFill++) EmojiData(144, 408, 3627933024, 0, 2); + new (toFill++) EmojiData(168, 408, 3627933025, 0, 2); + new (toFill++) EmojiData(192, 408, 3627933026, 0, 2); + new (toFill++) EmojiData(216, 408, 3627933027, 0, 2); + new (toFill++) EmojiData(240, 408, 3627933028, 0, 2); + new (toFill++) EmojiData(264, 408, 3627933029, 0, 2); + new (toFill++) EmojiData(288, 408, 3627933030, 0, 2); + new (toFill++) EmojiData(312, 408, 3627933031, 0, 2); + new (toFill++) EmojiData(336, 408, 3627933179, 0, 2); + new (toFill++) EmojiData(360, 408, 3627933180, 0, 2); + new (toFill++) EmojiData(384, 408, 3627933181, 0, 2); + new (toFill++) EmojiData(408, 408, 3627933182, 0, 2); + new (toFill++) EmojiData(432, 408, 3627933183, 0, 2); + new (toFill++) EmojiData(456, 408, 3627933184, 0, 2); + new (toFill++) EmojiData(480, 408, 3627933185, 0, 2); + new (toFill++) EmojiData(504, 408, 3627933186, 0, 2); + new (toFill++) EmojiData(528, 408, 3627933187, 0, 2); + new (toFill++) EmojiData(552, 408, 3627933188, 0, 2); + new (toFill++) EmojiData(576, 408, 3627933189, 0, 2); + new (toFill++) EmojiData(600, 408, 3627933190, 0, 2); + new (toFill++) EmojiData(624, 408, 3627933191, 0, 2); + new (toFill++) EmojiData(648, 408, 3627933192, 0, 2); + new (toFill++) EmojiData(672, 408, 3627933193, 0, 2); + new (toFill++) EmojiData(696, 408, 3627933194, 0, 2); + new (toFill++) EmojiData(720, 408, 3627933195, 0, 2); + new (toFill++) EmojiData(744, 408, 3627933196, 0, 2); + new (toFill++) EmojiData(768, 408, 3627933197, 0, 2); + new (toFill++) EmojiData(792, 408, 3627933198, 0, 2); + new (toFill++) EmojiData(816, 408, 3627933199, 0, 2); + new (toFill++) EmojiData(840, 408, 3627933200, 0, 2); + new (toFill++) EmojiData(864, 408, 3627933201, 0, 2); + new (toFill++) EmojiData(888, 408, 3627933202, 0, 2); + new (toFill++) EmojiData(912, 408, 3627933203, 0, 2); + new (toFill++) EmojiData(936, 408, 3627933204, 0, 2); + new (toFill++) EmojiData(0, 432, 3627933205, 0, 2); + new (toFill++) EmojiData(24, 432, 3627933206, 0, 2); + new (toFill++) EmojiData(48, 432, 3627933207, 0, 2); + new (toFill++) EmojiData(72, 432, 3627933208, 0, 2); + new (toFill++) EmojiData(96, 432, 3627933209, 0, 2); + new (toFill++) EmojiData(120, 432, 3627933210, 0, 2); + new (toFill++) EmojiData(144, 432, 3627933211, 0, 2); + new (toFill++) EmojiData(168, 432, 3627933212, 0, 2); + new (toFill++) EmojiData(192, 432, 3627933213, 0, 2); + new (toFill++) EmojiData(216, 432, 3627933214, 0, 2); + new (toFill++) EmojiData(240, 432, 3627933215, 0, 2); + new (toFill++) EmojiData(264, 432, 3627933216, 0, 2); + new (toFill++) EmojiData(288, 432, 3627933217, 0, 2); + new (toFill++) EmojiData(312, 432, 3627933218, 0, 2); + new (toFill++) EmojiData(336, 432, 3627933219, 0, 2); + new (toFill++) EmojiData(360, 432, 3627933220, 0, 2); + new (toFill++) EmojiData(384, 432, 3627933221, 0, 2); + new (toFill++) EmojiData(408, 432, 3627933222, 0, 2); + new (toFill++) EmojiData(432, 432, 3627933223, 0, 2); + new (toFill++) EmojiData(456, 432, 3627933224, 0, 2); + new (toFill++) EmojiData(480, 432, 3627933225, 0, 2); + new (toFill++) EmojiData(504, 432, 3627933226, 0, 2); + new (toFill++) EmojiData(528, 432, 3627933227, 0, 2); + new (toFill++) EmojiData(552, 432, 3627933228, 0, 2); + new (toFill++) EmojiData(576, 432, 3627933229, 0, 2); + new (toFill++) EmojiData(600, 432, 3627933230, 0, 2); + new (toFill++) EmojiData(624, 432, 3627933231, 0, 2); + new (toFill++) EmojiData(648, 432, 3627933232, 0, 2); + new (toFill++) EmojiData(672, 432, 3627933233, 0, 2); + new (toFill++) EmojiData(696, 432, 3627933234, 0, 2); + new (toFill++) EmojiData(720, 432, 3627933235, 0, 2); + new (toFill++) EmojiData(744, 432, 3627933236, 0, 2); + new (toFill++) EmojiData(768, 432, 3627933237, 0, 2); + new (toFill++) EmojiData(792, 432, 3627933238, 0, 2); + new (toFill++) EmojiData(816, 432, 3627933239, 0, 2); + new (toFill++) EmojiData(840, 432, 3627933240, 0, 2); + new (toFill++) EmojiData(864, 432, 3627933241, 0, 2); + new (toFill++) EmojiData(888, 432, 3627933242, 0, 2); + new (toFill++) EmojiData(912, 432, 3627933243, 0, 2); + new (toFill++) EmojiData(936, 432, 3627933244, 0, 2); + new (toFill++) EmojiData(0, 456, 3627933245, 0, 2); + new (toFill++) EmojiData(24, 456, 3627933246, 0, 2); + new (toFill++) EmojiData(48, 456, 3627933247, 0, 2); + new (toFill++) EmojiData(72, 456, 3627933248, 0, 2); + new (toFill++) EmojiData(96, 456, 3627933253, 0, 2); + new (toFill++) EmojiData(120, 456, 3627933254, 0, 2); + new (toFill++) EmojiData(144, 456, 3627933255, 0, 2); + new (toFill++) EmojiData(168, 456, 3627933256, 0, 2); + new (toFill++) EmojiData(192, 456, 3627933257, 0, 2); + new (toFill++) EmojiData(216, 456, 3627933258, 0, 2); + new (toFill++) EmojiData(240, 456, 3627933259, 0, 2); + new (toFill++) EmojiData(264, 456, 3627933260, 0, 2); + new (toFill++) EmojiData(288, 456, 3627933261, 0, 2); + new (toFill++) EmojiData(312, 456, 3627933262, 0, 2); + new (toFill++) EmojiData(336, 456, 3627933263, 0, 2); + new (toFill++) EmojiData(360, 456, 3627933312, 0, 2); + new (toFill++) EmojiData(384, 456, 3627933313, 0, 2); + new (toFill++) EmojiData(408, 456, 3627933314, 0, 2); + new (toFill++) EmojiData(432, 456, 3627933315, 0, 2); + new (toFill++) EmojiData(456, 456, 3627933316, 0, 2); + new (toFill++) EmojiData(480, 456, 3627933317, 0, 2); + new (toFill++) EmojiData(504, 456, 3627933318, 0, 2); + new (toFill++) EmojiData(528, 456, 3627933319, 0, 2); + new (toFill++) EmojiData(552, 456, 3627933320, 0, 2); + new (toFill++) EmojiData(576, 456, 3627933321, 0, 2); + new (toFill++) EmojiData(600, 456, 3627933322, 0, 2); + new (toFill++) EmojiData(624, 456, 3627933323, 0, 2); + new (toFill++) EmojiData(648, 456, 3627933324, 0, 2); + new (toFill++) EmojiData(672, 456, 3627933325, 0, 2); + new (toFill++) EmojiData(696, 456, 3627933326, 0, 2); + new (toFill++) EmojiData(720, 456, 3627933327, 0, 2); + new (toFill++) EmojiData(744, 456, 3627933328, 0, 2); + new (toFill++) EmojiData(768, 456, 3627933329, 0, 2); + new (toFill++) EmojiData(792, 456, 3627933330, 0, 2); + new (toFill++) EmojiData(816, 456, 3627933331, 0, 2); + new (toFill++) EmojiData(840, 456, 3627933332, 0, 2); + new (toFill++) EmojiData(864, 456, 3627933333, 0, 2); + new (toFill++) EmojiData(888, 456, 3627933334, 0, 2); + new (toFill++) EmojiData(912, 456, 3627933335, 0, 2); + new (toFill++) EmojiData(936, 456, 3627933336, 0, 2); + new (toFill++) EmojiData(0, 480, 3627933337, 0, 2); + new (toFill++) EmojiData(24, 480, 3627933338, 0, 2); + new (toFill++) EmojiData(48, 480, 3627933339, 0, 2); + new (toFill++) EmojiData(72, 480, 3627933340, 0, 2); + new (toFill++) EmojiData(96, 480, 3627933341, 0, 2); + new (toFill++) EmojiData(120, 480, 3627933342, 0, 2); + new (toFill++) EmojiData(144, 480, 3627933343, 0, 2); + new (toFill++) EmojiData(168, 480, 3627933344, 0, 2); + new (toFill++) EmojiData(192, 480, 3627933345, 0, 2); + new (toFill++) EmojiData(216, 480, 3627933346, 0, 2); + new (toFill++) EmojiData(240, 480, 3627933347, 0, 2); + new (toFill++) EmojiData(264, 480, 3627933348, 0, 2); + new (toFill++) EmojiData(288, 480, 3627933349, 0, 2); + new (toFill++) EmojiData(312, 480, 3627933350, 0, 2); + new (toFill++) EmojiData(336, 480, 3627933351, 0, 2); + new (toFill++) EmojiData(360, 480, 3627933352, 0, 2); + new (toFill++) EmojiData(384, 480, 3627933353, 0, 2); + new (toFill++) EmojiData(408, 480, 3627933354, 0, 2); + new (toFill++) EmojiData(432, 480, 3627933355, 0, 2); + new (toFill++) EmojiData(456, 480, 3627933356, 0, 2); + new (toFill++) EmojiData(480, 480, 3627933357, 0, 2); + new (toFill++) EmojiData(504, 480, 3627933358, 0, 2); + new (toFill++) EmojiData(528, 480, 3627933359, 0, 2); + new (toFill++) EmojiData(552, 480, 3627933360, 0, 2); + new (toFill++) EmojiData(576, 480, 3627933361, 0, 2); + new (toFill++) EmojiData(600, 480, 3627933362, 0, 2); + new (toFill++) EmojiData(624, 480, 3627933363, 0, 2); + new (toFill++) EmojiData(648, 480, 3627933364, 0, 2); + new (toFill++) EmojiData(672, 480, 3627933365, 0, 2); + new (toFill++) EmojiData(696, 480, 3627933366, 0, 2); + new (toFill++) EmojiData(720, 480, 3627933367, 0, 2); + new (toFill++) EmojiData(744, 480, 3627933368, 0, 2); + new (toFill++) EmojiData(768, 480, 3627933369, 0, 2); + new (toFill++) EmojiData(792, 480, 3627933370, 0, 2); + new (toFill++) EmojiData(816, 480, 3627933371, 0, 2); + new (toFill++) EmojiData(840, 480, 3627933372, 0, 2); + new (toFill++) EmojiData(864, 480, 3627933373, 0, 2); + new (toFill++) EmojiData(888, 480, 3627933374, 0, 2); + new (toFill++) EmojiData(912, 480, 3627933375, 0, 2); + new (toFill++) EmojiData(936, 480, 3627933376, 0, 2); + new (toFill++) EmojiData(0, 504, 3627933377, 0, 2); + new (toFill++) EmojiData(24, 504, 3627933378, 0, 2); + new (toFill++) EmojiData(48, 504, 3627933379, 0, 2); + new (toFill++) EmojiData(72, 504, 3627933380, 0, 2); + new (toFill++) EmojiData(96, 504, 3627933381, 0, 2); + break; + + case dbisTwo: + new (toFill++) EmojiData(352, 0, 169, 0, 1); + new (toFill++) EmojiData(384, 0, 174, 0, 1); + new (toFill++) EmojiData(416, 0, 8252, 0, 1); + new (toFill++) EmojiData(448, 0, 8265, 0, 1); + new (toFill++) EmojiData(480, 0, 8482, 0, 1); + new (toFill++) EmojiData(512, 0, 8505, 0, 1); + new (toFill++) EmojiData(544, 0, 8596, 0, 1); + new (toFill++) EmojiData(576, 0, 8597, 0, 1); + new (toFill++) EmojiData(608, 0, 8598, 0, 1); + new (toFill++) EmojiData(640, 0, 8599, 0, 1); + new (toFill++) EmojiData(672, 0, 8600, 0, 1); + new (toFill++) EmojiData(704, 0, 8601, 0, 1); + new (toFill++) EmojiData(736, 0, 8617, 0, 1); + new (toFill++) EmojiData(768, 0, 8618, 0, 1); + new (toFill++) EmojiData(800, 0, 8986, 0, 1); + new (toFill++) EmojiData(832, 0, 8987, 0, 1); + new (toFill++) EmojiData(864, 0, 9193, 0, 1); + new (toFill++) EmojiData(896, 0, 9194, 0, 1); + new (toFill++) EmojiData(928, 0, 9195, 0, 1); + new (toFill++) EmojiData(960, 0, 9196, 0, 1); + new (toFill++) EmojiData(992, 0, 9200, 0, 1); + new (toFill++) EmojiData(1024, 0, 9203, 0, 1); + new (toFill++) EmojiData(1056, 0, 9410, 0, 1); + new (toFill++) EmojiData(1088, 0, 9642, 0, 1); + new (toFill++) EmojiData(1120, 0, 9643, 0, 1); + new (toFill++) EmojiData(1152, 0, 9654, 0, 1); + new (toFill++) EmojiData(1184, 0, 9664, 0, 1); + new (toFill++) EmojiData(1216, 0, 9723, 0, 1); + new (toFill++) EmojiData(1248, 0, 9724, 0, 1); + new (toFill++) EmojiData(0, 32, 9725, 0, 1); + new (toFill++) EmojiData(32, 32, 9726, 0, 1); + new (toFill++) EmojiData(64, 32, 9728, 0, 1); + new (toFill++) EmojiData(96, 32, 9729, 0, 1); + new (toFill++) EmojiData(128, 32, 9742, 0, 1); + new (toFill++) EmojiData(160, 32, 9745, 0, 1); + new (toFill++) EmojiData(192, 32, 9748, 0, 1); + new (toFill++) EmojiData(224, 32, 9749, 0, 1); + new (toFill++) EmojiData(256, 32, 9757, 0, 1); + new (toFill++) EmojiData(288, 32, 9786, 0, 1); + new (toFill++) EmojiData(320, 32, 9800, 0, 1); + new (toFill++) EmojiData(352, 32, 9801, 0, 1); + new (toFill++) EmojiData(384, 32, 9802, 0, 1); + new (toFill++) EmojiData(416, 32, 9803, 0, 1); + new (toFill++) EmojiData(448, 32, 9804, 0, 1); + new (toFill++) EmojiData(480, 32, 9805, 0, 1); + new (toFill++) EmojiData(512, 32, 9806, 0, 1); + new (toFill++) EmojiData(544, 32, 9807, 0, 1); + new (toFill++) EmojiData(576, 32, 9808, 0, 1); + new (toFill++) EmojiData(608, 32, 9809, 0, 1); + new (toFill++) EmojiData(640, 32, 9810, 0, 1); + new (toFill++) EmojiData(672, 32, 9811, 0, 1); + new (toFill++) EmojiData(704, 32, 9824, 0, 1); + new (toFill++) EmojiData(736, 32, 9827, 0, 1); + new (toFill++) EmojiData(768, 32, 9829, 0, 1); + new (toFill++) EmojiData(800, 32, 9830, 0, 1); + new (toFill++) EmojiData(832, 32, 9832, 0, 1); + new (toFill++) EmojiData(864, 32, 9851, 0, 1); + new (toFill++) EmojiData(896, 32, 9855, 0, 1); + new (toFill++) EmojiData(928, 32, 9875, 0, 1); + new (toFill++) EmojiData(960, 32, 9888, 0, 1); + new (toFill++) EmojiData(992, 32, 9889, 0, 1); + new (toFill++) EmojiData(1024, 32, 9898, 0, 1); + new (toFill++) EmojiData(1056, 32, 9899, 0, 1); + new (toFill++) EmojiData(1088, 32, 9917, 0, 1); + new (toFill++) EmojiData(1120, 32, 9918, 0, 1); + new (toFill++) EmojiData(1152, 32, 9924, 0, 1); + new (toFill++) EmojiData(1184, 32, 9925, 0, 1); + new (toFill++) EmojiData(1216, 32, 9934, 0, 1); + new (toFill++) EmojiData(1248, 32, 9940, 0, 1); + new (toFill++) EmojiData(0, 64, 9962, 0, 1); + new (toFill++) EmojiData(32, 64, 9970, 0, 1); + new (toFill++) EmojiData(64, 64, 9971, 0, 1); + new (toFill++) EmojiData(96, 64, 9973, 0, 1); + new (toFill++) EmojiData(128, 64, 9978, 0, 1); + new (toFill++) EmojiData(160, 64, 9981, 0, 1); + new (toFill++) EmojiData(192, 64, 9986, 0, 1); + new (toFill++) EmojiData(224, 64, 9989, 0, 1); + new (toFill++) EmojiData(256, 64, 9992, 0, 1); + new (toFill++) EmojiData(288, 64, 9993, 0, 1); + new (toFill++) EmojiData(320, 64, 9994, 0, 1); + new (toFill++) EmojiData(352, 64, 9995, 0, 1); + new (toFill++) EmojiData(384, 64, 9996, 0, 1); + new (toFill++) EmojiData(416, 64, 9999, 0, 1); + new (toFill++) EmojiData(448, 64, 10002, 0, 1); + new (toFill++) EmojiData(480, 64, 10004, 0, 1); + new (toFill++) EmojiData(512, 64, 10006, 0, 1); + new (toFill++) EmojiData(544, 64, 10024, 0, 1); + new (toFill++) EmojiData(576, 64, 10035, 0, 1); + new (toFill++) EmojiData(608, 64, 10036, 0, 1); + new (toFill++) EmojiData(640, 64, 10052, 0, 1); + new (toFill++) EmojiData(672, 64, 10055, 0, 1); + new (toFill++) EmojiData(704, 64, 10060, 0, 1); + new (toFill++) EmojiData(736, 64, 10062, 0, 1); + new (toFill++) EmojiData(768, 64, 10067, 0, 1); + new (toFill++) EmojiData(800, 64, 10068, 0, 1); + new (toFill++) EmojiData(832, 64, 10069, 0, 1); + new (toFill++) EmojiData(864, 64, 10071, 0, 1); + new (toFill++) EmojiData(896, 64, 10084, 0, 1); + new (toFill++) EmojiData(928, 64, 10133, 0, 1); + new (toFill++) EmojiData(960, 64, 10134, 0, 1); + new (toFill++) EmojiData(992, 64, 10135, 0, 1); + new (toFill++) EmojiData(1024, 64, 10145, 0, 1); + new (toFill++) EmojiData(1056, 64, 10160, 0, 1); + new (toFill++) EmojiData(1088, 64, 10175, 0, 1); + new (toFill++) EmojiData(1120, 64, 10548, 0, 1); + new (toFill++) EmojiData(1152, 64, 10549, 0, 1); + new (toFill++) EmojiData(1184, 64, 11013, 0, 1); + new (toFill++) EmojiData(1216, 64, 11014, 0, 1); + new (toFill++) EmojiData(1248, 64, 11015, 0, 1); + new (toFill++) EmojiData(0, 96, 11035, 0, 1); + new (toFill++) EmojiData(32, 96, 11036, 0, 1); + new (toFill++) EmojiData(64, 96, 11088, 0, 1); + new (toFill++) EmojiData(96, 96, 11093, 0, 1); + new (toFill++) EmojiData(128, 96, 12336, 0, 1); + new (toFill++) EmojiData(160, 96, 12349, 0, 1); + new (toFill++) EmojiData(192, 96, 12951, 0, 1); + new (toFill++) EmojiData(224, 96, 12953, 0, 1); + new (toFill++) EmojiData(0, 0, 2302179, 0, 2); + new (toFill++) EmojiData(32, 0, 3154147, 0, 2); + new (toFill++) EmojiData(64, 0, 3219683, 0, 2); + new (toFill++) EmojiData(96, 0, 3285219, 0, 2); + new (toFill++) EmojiData(128, 0, 3350755, 0, 2); + new (toFill++) EmojiData(160, 0, 3416291, 0, 2); + new (toFill++) EmojiData(192, 0, 3481827, 0, 2); + new (toFill++) EmojiData(224, 0, 3547363, 0, 2); + new (toFill++) EmojiData(256, 0, 3612899, 0, 2); + new (toFill++) EmojiData(288, 0, 3678435, 0, 2); + new (toFill++) EmojiData(320, 0, 3743971, 0, 2); + new (toFill++) EmojiData(256, 96, 3627867140, 0, 2); + new (toFill++) EmojiData(288, 96, 3627867343, 0, 2); + new (toFill++) EmojiData(320, 96, 3627867504, 0, 2); + new (toFill++) EmojiData(352, 96, 3627867505, 0, 2); + new (toFill++) EmojiData(384, 96, 3627867518, 0, 2); + new (toFill++) EmojiData(416, 96, 3627867519, 0, 2); + new (toFill++) EmojiData(448, 96, 3627867534, 0, 2); + new (toFill++) EmojiData(480, 96, 3627867537, 0, 2); + new (toFill++) EmojiData(512, 96, 3627867538, 0, 2); + new (toFill++) EmojiData(544, 96, 3627867539, 0, 2); + new (toFill++) EmojiData(576, 96, 3627867540, 0, 2); + new (toFill++) EmojiData(608, 96, 3627867541, 0, 2); + new (toFill++) EmojiData(640, 96, 3627867542, 0, 2); + new (toFill++) EmojiData(672, 96, 3627867543, 0, 2); + new (toFill++) EmojiData(704, 96, 3627867544, 0, 2); + new (toFill++) EmojiData(736, 96, 3627867545, 0, 2); + new (toFill++) EmojiData(768, 96, 3627867546, 0, 2); + new (toFill++) EmojiData(800, 96, 3627867624, 3627867635, 4); + new (toFill++) EmojiData(832, 96, 3627867625, 3627867626, 4); + new (toFill++) EmojiData(864, 96, 3627867626, 3627867640, 4); + new (toFill++) EmojiData(896, 96, 3627867627, 3627867639, 4); + new (toFill++) EmojiData(928, 96, 3627867628, 3627867623, 4); + new (toFill++) EmojiData(960, 96, 3627867630, 3627867641, 4); + new (toFill++) EmojiData(992, 96, 3627867631, 3627867637, 4); + new (toFill++) EmojiData(1024, 96, 3627867632, 3627867639, 4); + new (toFill++) EmojiData(1056, 96, 3627867639, 3627867642, 4); + new (toFill++) EmojiData(1088, 96, 3627867642, 3627867640, 4); + new (toFill++) EmojiData(1120, 96, 3627867649, 0, 2); + new (toFill++) EmojiData(1152, 96, 3627867650, 0, 2); + new (toFill++) EmojiData(1184, 96, 3627867674, 0, 2); + new (toFill++) EmojiData(1216, 96, 3627867695, 0, 2); + new (toFill++) EmojiData(1248, 96, 3627867698, 0, 2); + new (toFill++) EmojiData(0, 128, 3627867699, 0, 2); + new (toFill++) EmojiData(32, 128, 3627867700, 0, 2); + new (toFill++) EmojiData(64, 128, 3627867701, 0, 2); + new (toFill++) EmojiData(96, 128, 3627867702, 0, 2); + new (toFill++) EmojiData(128, 128, 3627867703, 0, 2); + new (toFill++) EmojiData(160, 128, 3627867704, 0, 2); + new (toFill++) EmojiData(192, 128, 3627867705, 0, 2); + new (toFill++) EmojiData(224, 128, 3627867706, 0, 2); + new (toFill++) EmojiData(256, 128, 3627867728, 0, 2); + new (toFill++) EmojiData(288, 128, 3627867729, 0, 2); + new (toFill++) EmojiData(320, 128, 3627867904, 0, 2); + new (toFill++) EmojiData(352, 128, 3627867905, 0, 2); + new (toFill++) EmojiData(384, 128, 3627867906, 0, 2); + new (toFill++) EmojiData(416, 128, 3627867907, 0, 2); + new (toFill++) EmojiData(448, 128, 3627867908, 0, 2); + new (toFill++) EmojiData(480, 128, 3627867909, 0, 2); + new (toFill++) EmojiData(512, 128, 3627867910, 0, 2); + new (toFill++) EmojiData(544, 128, 3627867911, 0, 2); + new (toFill++) EmojiData(576, 128, 3627867912, 0, 2); + new (toFill++) EmojiData(608, 128, 3627867913, 0, 2); + new (toFill++) EmojiData(640, 128, 3627867914, 0, 2); + new (toFill++) EmojiData(672, 128, 3627867915, 0, 2); + new (toFill++) EmojiData(704, 128, 3627867916, 0, 2); + new (toFill++) EmojiData(736, 128, 3627867917, 0, 2); + new (toFill++) EmojiData(768, 128, 3627867918, 0, 2); + new (toFill++) EmojiData(800, 128, 3627867919, 0, 2); + new (toFill++) EmojiData(832, 128, 3627867920, 0, 2); + new (toFill++) EmojiData(864, 128, 3627867921, 0, 2); + new (toFill++) EmojiData(896, 128, 3627867922, 0, 2); + new (toFill++) EmojiData(928, 128, 3627867923, 0, 2); + new (toFill++) EmojiData(960, 128, 3627867924, 0, 2); + new (toFill++) EmojiData(992, 128, 3627867925, 0, 2); + new (toFill++) EmojiData(1024, 128, 3627867926, 0, 2); + new (toFill++) EmojiData(1056, 128, 3627867927, 0, 2); + new (toFill++) EmojiData(1088, 128, 3627867928, 0, 2); + new (toFill++) EmojiData(1120, 128, 3627867929, 0, 2); + new (toFill++) EmojiData(1152, 128, 3627867930, 0, 2); + new (toFill++) EmojiData(1184, 128, 3627867931, 0, 2); + new (toFill++) EmojiData(1216, 128, 3627867932, 0, 2); + new (toFill++) EmojiData(1248, 128, 3627867933, 0, 2); + new (toFill++) EmojiData(0, 160, 3627867934, 0, 2); + new (toFill++) EmojiData(32, 160, 3627867935, 0, 2); + new (toFill++) EmojiData(64, 160, 3627867936, 0, 2); + new (toFill++) EmojiData(96, 160, 3627867952, 0, 2); + new (toFill++) EmojiData(128, 160, 3627867953, 0, 2); + new (toFill++) EmojiData(160, 160, 3627867954, 0, 2); + new (toFill++) EmojiData(192, 160, 3627867955, 0, 2); + new (toFill++) EmojiData(224, 160, 3627867956, 0, 2); + new (toFill++) EmojiData(256, 160, 3627867957, 0, 2); + new (toFill++) EmojiData(288, 160, 3627867959, 0, 2); + new (toFill++) EmojiData(320, 160, 3627867960, 0, 2); + new (toFill++) EmojiData(352, 160, 3627867961, 0, 2); + new (toFill++) EmojiData(384, 160, 3627867962, 0, 2); + new (toFill++) EmojiData(416, 160, 3627867963, 0, 2); + new (toFill++) EmojiData(448, 160, 3627867964, 0, 2); + new (toFill++) EmojiData(480, 160, 3627867965, 0, 2); + new (toFill++) EmojiData(512, 160, 3627867966, 0, 2); + new (toFill++) EmojiData(544, 160, 3627867967, 0, 2); + new (toFill++) EmojiData(576, 160, 3627867968, 0, 2); + new (toFill++) EmojiData(608, 160, 3627867969, 0, 2); + new (toFill++) EmojiData(640, 160, 3627867970, 0, 2); + new (toFill++) EmojiData(672, 160, 3627867971, 0, 2); + new (toFill++) EmojiData(704, 160, 3627867972, 0, 2); + new (toFill++) EmojiData(736, 160, 3627867973, 0, 2); + new (toFill++) EmojiData(768, 160, 3627867974, 0, 2); + new (toFill++) EmojiData(800, 160, 3627867975, 0, 2); + new (toFill++) EmojiData(832, 160, 3627867976, 0, 2); + new (toFill++) EmojiData(864, 160, 3627867977, 0, 2); + new (toFill++) EmojiData(896, 160, 3627867978, 0, 2); + new (toFill++) EmojiData(928, 160, 3627867979, 0, 2); + new (toFill++) EmojiData(960, 160, 3627867980, 0, 2); + new (toFill++) EmojiData(992, 160, 3627867981, 0, 2); + new (toFill++) EmojiData(1024, 160, 3627867982, 0, 2); + new (toFill++) EmojiData(1056, 160, 3627867983, 0, 2); + new (toFill++) EmojiData(1088, 160, 3627867984, 0, 2); + new (toFill++) EmojiData(1120, 160, 3627867985, 0, 2); + new (toFill++) EmojiData(1152, 160, 3627867986, 0, 2); + new (toFill++) EmojiData(1184, 160, 3627867987, 0, 2); + new (toFill++) EmojiData(1216, 160, 3627867988, 0, 2); + new (toFill++) EmojiData(1248, 160, 3627867989, 0, 2); + new (toFill++) EmojiData(0, 192, 3627867990, 0, 2); + new (toFill++) EmojiData(32, 192, 3627867991, 0, 2); + new (toFill++) EmojiData(64, 192, 3627867992, 0, 2); + new (toFill++) EmojiData(96, 192, 3627867993, 0, 2); + new (toFill++) EmojiData(128, 192, 3627867994, 0, 2); + new (toFill++) EmojiData(160, 192, 3627867995, 0, 2); + new (toFill++) EmojiData(192, 192, 3627867996, 0, 2); + new (toFill++) EmojiData(224, 192, 3627867997, 0, 2); + new (toFill++) EmojiData(256, 192, 3627867998, 0, 2); + new (toFill++) EmojiData(288, 192, 3627867999, 0, 2); + new (toFill++) EmojiData(320, 192, 3627868000, 0, 2); + new (toFill++) EmojiData(352, 192, 3627868001, 0, 2); + new (toFill++) EmojiData(384, 192, 3627868002, 0, 2); + new (toFill++) EmojiData(416, 192, 3627868003, 0, 2); + new (toFill++) EmojiData(448, 192, 3627868004, 0, 2); + new (toFill++) EmojiData(480, 192, 3627868005, 0, 2); + new (toFill++) EmojiData(512, 192, 3627868006, 0, 2); + new (toFill++) EmojiData(544, 192, 3627868007, 0, 2); + new (toFill++) EmojiData(576, 192, 3627868008, 0, 2); + new (toFill++) EmojiData(608, 192, 3627868009, 0, 2); + new (toFill++) EmojiData(640, 192, 3627868010, 0, 2); + new (toFill++) EmojiData(672, 192, 3627868011, 0, 2); + new (toFill++) EmojiData(704, 192, 3627868012, 0, 2); + new (toFill++) EmojiData(736, 192, 3627868013, 0, 2); + new (toFill++) EmojiData(768, 192, 3627868014, 0, 2); + new (toFill++) EmojiData(800, 192, 3627868015, 0, 2); + new (toFill++) EmojiData(832, 192, 3627868016, 0, 2); + new (toFill++) EmojiData(864, 192, 3627868017, 0, 2); + new (toFill++) EmojiData(896, 192, 3627868018, 0, 2); + new (toFill++) EmojiData(928, 192, 3627868019, 0, 2); + new (toFill++) EmojiData(960, 192, 3627868020, 0, 2); + new (toFill++) EmojiData(992, 192, 3627868021, 0, 2); + new (toFill++) EmojiData(1024, 192, 3627868022, 0, 2); + new (toFill++) EmojiData(1056, 192, 3627868023, 0, 2); + new (toFill++) EmojiData(1088, 192, 3627868024, 0, 2); + new (toFill++) EmojiData(1120, 192, 3627868025, 0, 2); + new (toFill++) EmojiData(1152, 192, 3627868026, 0, 2); + new (toFill++) EmojiData(1184, 192, 3627868027, 0, 2); + new (toFill++) EmojiData(1216, 192, 3627868028, 0, 2); + new (toFill++) EmojiData(1248, 192, 3627868032, 0, 2); + new (toFill++) EmojiData(0, 224, 3627868033, 0, 2); + new (toFill++) EmojiData(32, 224, 3627868034, 0, 2); + new (toFill++) EmojiData(64, 224, 3627868035, 0, 2); + new (toFill++) EmojiData(96, 224, 3627868036, 0, 2); + new (toFill++) EmojiData(128, 224, 3627868037, 0, 2); + new (toFill++) EmojiData(160, 224, 3627868038, 0, 2); + new (toFill++) EmojiData(192, 224, 3627868039, 0, 2); + new (toFill++) EmojiData(224, 224, 3627868040, 0, 2); + new (toFill++) EmojiData(256, 224, 3627868041, 0, 2); + new (toFill++) EmojiData(288, 224, 3627868042, 0, 2); + new (toFill++) EmojiData(320, 224, 3627868043, 0, 2); + new (toFill++) EmojiData(352, 224, 3627868044, 0, 2); + new (toFill++) EmojiData(384, 224, 3627868045, 0, 2); + new (toFill++) EmojiData(416, 224, 3627868046, 0, 2); + new (toFill++) EmojiData(448, 224, 3627868047, 0, 2); + new (toFill++) EmojiData(480, 224, 3627868048, 0, 2); + new (toFill++) EmojiData(512, 224, 3627868049, 0, 2); + new (toFill++) EmojiData(544, 224, 3627868050, 0, 2); + new (toFill++) EmojiData(576, 224, 3627868051, 0, 2); + new (toFill++) EmojiData(608, 224, 3627868064, 0, 2); + new (toFill++) EmojiData(640, 224, 3627868065, 0, 2); + new (toFill++) EmojiData(672, 224, 3627868066, 0, 2); + new (toFill++) EmojiData(704, 224, 3627868067, 0, 2); + new (toFill++) EmojiData(736, 224, 3627868068, 0, 2); + new (toFill++) EmojiData(768, 224, 3627868069, 0, 2); + new (toFill++) EmojiData(800, 224, 3627868070, 0, 2); + new (toFill++) EmojiData(832, 224, 3627868071, 0, 2); + new (toFill++) EmojiData(864, 224, 3627868072, 0, 2); + new (toFill++) EmojiData(896, 224, 3627868073, 0, 2); + new (toFill++) EmojiData(928, 224, 3627868074, 0, 2); + new (toFill++) EmojiData(960, 224, 3627868075, 0, 2); + new (toFill++) EmojiData(992, 224, 3627868076, 0, 2); + new (toFill++) EmojiData(1024, 224, 3627868077, 0, 2); + new (toFill++) EmojiData(1056, 224, 3627868078, 0, 2); + new (toFill++) EmojiData(1088, 224, 3627868079, 0, 2); + new (toFill++) EmojiData(1120, 224, 3627868080, 0, 2); + new (toFill++) EmojiData(1152, 224, 3627868081, 0, 2); + new (toFill++) EmojiData(1184, 224, 3627868082, 0, 2); + new (toFill++) EmojiData(1216, 224, 3627868083, 0, 2); + new (toFill++) EmojiData(1248, 224, 3627868084, 0, 2); + new (toFill++) EmojiData(0, 256, 3627868085, 0, 2); + new (toFill++) EmojiData(32, 256, 3627868086, 0, 2); + new (toFill++) EmojiData(64, 256, 3627868087, 0, 2); + new (toFill++) EmojiData(96, 256, 3627868088, 0, 2); + new (toFill++) EmojiData(128, 256, 3627868089, 0, 2); + new (toFill++) EmojiData(160, 256, 3627868090, 0, 2); + new (toFill++) EmojiData(192, 256, 3627868091, 0, 2); + new (toFill++) EmojiData(224, 256, 3627868092, 0, 2); + new (toFill++) EmojiData(256, 256, 3627868093, 0, 2); + new (toFill++) EmojiData(288, 256, 3627868094, 0, 2); + new (toFill++) EmojiData(320, 256, 3627868095, 0, 2); + new (toFill++) EmojiData(352, 256, 3627868096, 0, 2); + new (toFill++) EmojiData(384, 256, 3627868097, 0, 2); + new (toFill++) EmojiData(416, 256, 3627868098, 0, 2); + new (toFill++) EmojiData(448, 256, 3627868099, 0, 2); + new (toFill++) EmojiData(480, 256, 3627868100, 0, 2); + new (toFill++) EmojiData(512, 256, 3627868102, 0, 2); + new (toFill++) EmojiData(544, 256, 3627868103, 0, 2); + new (toFill++) EmojiData(576, 256, 3627868104, 0, 2); + new (toFill++) EmojiData(608, 256, 3627868105, 0, 2); + new (toFill++) EmojiData(640, 256, 3627868106, 0, 2); + new (toFill++) EmojiData(672, 256, 3627868128, 0, 2); + new (toFill++) EmojiData(704, 256, 3627868129, 0, 2); + new (toFill++) EmojiData(736, 256, 3627868130, 0, 2); + new (toFill++) EmojiData(768, 256, 3627868131, 0, 2); + new (toFill++) EmojiData(800, 256, 3627868132, 0, 2); + new (toFill++) EmojiData(832, 256, 3627868133, 0, 2); + new (toFill++) EmojiData(864, 256, 3627868134, 0, 2); + new (toFill++) EmojiData(896, 256, 3627868135, 0, 2); + new (toFill++) EmojiData(928, 256, 3627868136, 0, 2); + new (toFill++) EmojiData(960, 256, 3627868137, 0, 2); + new (toFill++) EmojiData(992, 256, 3627868138, 0, 2); + new (toFill++) EmojiData(1024, 256, 3627868139, 0, 2); + new (toFill++) EmojiData(1056, 256, 3627868140, 0, 2); + new (toFill++) EmojiData(1088, 256, 3627868141, 0, 2); + new (toFill++) EmojiData(1120, 256, 3627868142, 0, 2); + new (toFill++) EmojiData(1152, 256, 3627868143, 0, 2); + new (toFill++) EmojiData(1184, 256, 3627868144, 0, 2); + new (toFill++) EmojiData(1216, 256, 3627932672, 0, 2); + new (toFill++) EmojiData(1248, 256, 3627932673, 0, 2); + new (toFill++) EmojiData(0, 288, 3627932674, 0, 2); + new (toFill++) EmojiData(32, 288, 3627932675, 0, 2); + new (toFill++) EmojiData(64, 288, 3627932676, 0, 2); + new (toFill++) EmojiData(96, 288, 3627932677, 0, 2); + new (toFill++) EmojiData(128, 288, 3627932678, 0, 2); + new (toFill++) EmojiData(160, 288, 3627932679, 0, 2); + new (toFill++) EmojiData(192, 288, 3627932680, 0, 2); + new (toFill++) EmojiData(224, 288, 3627932681, 0, 2); + new (toFill++) EmojiData(256, 288, 3627932682, 0, 2); + new (toFill++) EmojiData(288, 288, 3627932683, 0, 2); + new (toFill++) EmojiData(320, 288, 3627932684, 0, 2); + new (toFill++) EmojiData(352, 288, 3627932685, 0, 2); + new (toFill++) EmojiData(384, 288, 3627932686, 0, 2); + new (toFill++) EmojiData(416, 288, 3627932687, 0, 2); + new (toFill++) EmojiData(448, 288, 3627932688, 0, 2); + new (toFill++) EmojiData(480, 288, 3627932689, 0, 2); + new (toFill++) EmojiData(512, 288, 3627932690, 0, 2); + new (toFill++) EmojiData(544, 288, 3627932691, 0, 2); + new (toFill++) EmojiData(576, 288, 3627932692, 0, 2); + new (toFill++) EmojiData(608, 288, 3627932693, 0, 2); + new (toFill++) EmojiData(640, 288, 3627932694, 0, 2); + new (toFill++) EmojiData(672, 288, 3627932695, 0, 2); + new (toFill++) EmojiData(704, 288, 3627932696, 0, 2); + new (toFill++) EmojiData(736, 288, 3627932697, 0, 2); + new (toFill++) EmojiData(768, 288, 3627932698, 0, 2); + new (toFill++) EmojiData(800, 288, 3627932699, 0, 2); + new (toFill++) EmojiData(832, 288, 3627932700, 0, 2); + new (toFill++) EmojiData(864, 288, 3627932701, 0, 2); + new (toFill++) EmojiData(896, 288, 3627932702, 0, 2); + new (toFill++) EmojiData(928, 288, 3627932703, 0, 2); + new (toFill++) EmojiData(960, 288, 3627932704, 0, 2); + new (toFill++) EmojiData(992, 288, 3627932705, 0, 2); + new (toFill++) EmojiData(1024, 288, 3627932706, 0, 2); + new (toFill++) EmojiData(1056, 288, 3627932707, 0, 2); + new (toFill++) EmojiData(1088, 288, 3627932708, 0, 2); + new (toFill++) EmojiData(1120, 288, 3627932709, 0, 2); + new (toFill++) EmojiData(1152, 288, 3627932710, 0, 2); + new (toFill++) EmojiData(1184, 288, 3627932711, 0, 2); + new (toFill++) EmojiData(1216, 288, 3627932712, 0, 2); + new (toFill++) EmojiData(1248, 288, 3627932713, 0, 2); + new (toFill++) EmojiData(0, 320, 3627932714, 0, 2); + new (toFill++) EmojiData(32, 320, 3627932715, 0, 2); + new (toFill++) EmojiData(64, 320, 3627932716, 0, 2); + new (toFill++) EmojiData(96, 320, 3627932717, 0, 2); + new (toFill++) EmojiData(128, 320, 3627932718, 0, 2); + new (toFill++) EmojiData(160, 320, 3627932719, 0, 2); + new (toFill++) EmojiData(192, 320, 3627932720, 0, 2); + new (toFill++) EmojiData(224, 320, 3627932721, 0, 2); + new (toFill++) EmojiData(256, 320, 3627932722, 0, 2); + new (toFill++) EmojiData(288, 320, 3627932723, 0, 2); + new (toFill++) EmojiData(320, 320, 3627932724, 0, 2); + new (toFill++) EmojiData(352, 320, 3627932725, 0, 2); + new (toFill++) EmojiData(384, 320, 3627932726, 0, 2); + new (toFill++) EmojiData(416, 320, 3627932727, 0, 2); + new (toFill++) EmojiData(448, 320, 3627932728, 0, 2); + new (toFill++) EmojiData(480, 320, 3627932729, 0, 2); + new (toFill++) EmojiData(512, 320, 3627932730, 0, 2); + new (toFill++) EmojiData(544, 320, 3627932731, 0, 2); + new (toFill++) EmojiData(576, 320, 3627932732, 0, 2); + new (toFill++) EmojiData(608, 320, 3627932733, 0, 2); + new (toFill++) EmojiData(640, 320, 3627932734, 0, 2); + new (toFill++) EmojiData(672, 320, 3627932736, 0, 2); + new (toFill++) EmojiData(704, 320, 3627932738, 0, 2); + new (toFill++) EmojiData(736, 320, 3627932739, 0, 2); + new (toFill++) EmojiData(768, 320, 3627932740, 0, 2); + new (toFill++) EmojiData(800, 320, 3627932741, 0, 2); + new (toFill++) EmojiData(832, 320, 3627932742, 0, 2); + new (toFill++) EmojiData(864, 320, 3627932743, 0, 2); + new (toFill++) EmojiData(896, 320, 3627932744, 0, 2); + new (toFill++) EmojiData(928, 320, 3627932745, 0, 2); + new (toFill++) EmojiData(960, 320, 3627932746, 0, 2); + new (toFill++) EmojiData(992, 320, 3627932747, 0, 2); + new (toFill++) EmojiData(1024, 320, 3627932748, 0, 2); + new (toFill++) EmojiData(1056, 320, 3627932749, 0, 2); + new (toFill++) EmojiData(1088, 320, 3627932750, 0, 2); + new (toFill++) EmojiData(1120, 320, 3627932751, 0, 2); + new (toFill++) EmojiData(1152, 320, 3627932752, 0, 2); + new (toFill++) EmojiData(1184, 320, 3627932753, 0, 2); + new (toFill++) EmojiData(1216, 320, 3627932754, 0, 2); + new (toFill++) EmojiData(1248, 320, 3627932755, 0, 2); + new (toFill++) EmojiData(0, 352, 3627932756, 0, 2); + new (toFill++) EmojiData(32, 352, 3627932757, 0, 2); + new (toFill++) EmojiData(64, 352, 3627932758, 0, 2); + new (toFill++) EmojiData(96, 352, 3627932759, 0, 2); + new (toFill++) EmojiData(128, 352, 3627932760, 0, 2); + new (toFill++) EmojiData(160, 352, 3627932761, 0, 2); + new (toFill++) EmojiData(192, 352, 3627932762, 0, 2); + new (toFill++) EmojiData(224, 352, 3627932763, 0, 2); + new (toFill++) EmojiData(256, 352, 3627932764, 0, 2); + new (toFill++) EmojiData(288, 352, 3627932765, 0, 2); + new (toFill++) EmojiData(320, 352, 3627932766, 0, 2); + new (toFill++) EmojiData(352, 352, 3627932767, 0, 2); + new (toFill++) EmojiData(384, 352, 3627932768, 0, 2); + new (toFill++) EmojiData(416, 352, 3627932769, 0, 2); + new (toFill++) EmojiData(448, 352, 3627932770, 0, 2); + new (toFill++) EmojiData(480, 352, 3627932771, 0, 2); + new (toFill++) EmojiData(512, 352, 3627932772, 0, 2); + new (toFill++) EmojiData(544, 352, 3627932773, 0, 2); + new (toFill++) EmojiData(576, 352, 3627932774, 0, 2); + new (toFill++) EmojiData(608, 352, 3627932775, 0, 2); + new (toFill++) EmojiData(640, 352, 3627932776, 0, 2); + new (toFill++) EmojiData(672, 352, 3627932777, 0, 2); + new (toFill++) EmojiData(704, 352, 3627932778, 0, 2); + new (toFill++) EmojiData(736, 352, 3627932779, 0, 2); + new (toFill++) EmojiData(768, 352, 3627932780, 0, 2); + new (toFill++) EmojiData(800, 352, 3627932781, 0, 2); + new (toFill++) EmojiData(832, 352, 3627932782, 0, 2); + new (toFill++) EmojiData(864, 352, 3627932783, 0, 2); + new (toFill++) EmojiData(896, 352, 3627932784, 0, 2); + new (toFill++) EmojiData(928, 352, 3627932785, 0, 2); + new (toFill++) EmojiData(960, 352, 3627932786, 0, 2); + new (toFill++) EmojiData(992, 352, 3627932787, 0, 2); + new (toFill++) EmojiData(1024, 352, 3627932788, 0, 2); + new (toFill++) EmojiData(1056, 352, 3627932789, 0, 2); + new (toFill++) EmojiData(1088, 352, 3627932790, 0, 2); + new (toFill++) EmojiData(1120, 352, 3627932791, 0, 2); + new (toFill++) EmojiData(1152, 352, 3627932792, 0, 2); + new (toFill++) EmojiData(1184, 352, 3627932793, 0, 2); + new (toFill++) EmojiData(1216, 352, 3627932794, 0, 2); + new (toFill++) EmojiData(1248, 352, 3627932795, 0, 2); + new (toFill++) EmojiData(0, 384, 3627932796, 0, 2); + new (toFill++) EmojiData(32, 384, 3627932797, 0, 2); + new (toFill++) EmojiData(64, 384, 3627932798, 0, 2); + new (toFill++) EmojiData(96, 384, 3627932799, 0, 2); + new (toFill++) EmojiData(128, 384, 3627932800, 0, 2); + new (toFill++) EmojiData(160, 384, 3627932801, 0, 2); + new (toFill++) EmojiData(192, 384, 3627932802, 0, 2); + new (toFill++) EmojiData(224, 384, 3627932803, 0, 2); + new (toFill++) EmojiData(256, 384, 3627932804, 0, 2); + new (toFill++) EmojiData(288, 384, 3627932805, 0, 2); + new (toFill++) EmojiData(320, 384, 3627932806, 0, 2); + new (toFill++) EmojiData(352, 384, 3627932807, 0, 2); + new (toFill++) EmojiData(384, 384, 3627932808, 0, 2); + new (toFill++) EmojiData(416, 384, 3627932809, 0, 2); + new (toFill++) EmojiData(448, 384, 3627932810, 0, 2); + new (toFill++) EmojiData(480, 384, 3627932811, 0, 2); + new (toFill++) EmojiData(512, 384, 3627932812, 0, 2); + new (toFill++) EmojiData(544, 384, 3627932813, 0, 2); + new (toFill++) EmojiData(576, 384, 3627932814, 0, 2); + new (toFill++) EmojiData(608, 384, 3627932815, 0, 2); + new (toFill++) EmojiData(640, 384, 3627932816, 0, 2); + new (toFill++) EmojiData(672, 384, 3627932817, 0, 2); + new (toFill++) EmojiData(704, 384, 3627932818, 0, 2); + new (toFill++) EmojiData(736, 384, 3627932819, 0, 2); + new (toFill++) EmojiData(768, 384, 3627932820, 0, 2); + new (toFill++) EmojiData(800, 384, 3627932821, 0, 2); + new (toFill++) EmojiData(832, 384, 3627932822, 0, 2); + new (toFill++) EmojiData(864, 384, 3627932823, 0, 2); + new (toFill++) EmojiData(896, 384, 3627932824, 0, 2); + new (toFill++) EmojiData(928, 384, 3627932825, 0, 2); + new (toFill++) EmojiData(960, 384, 3627932826, 0, 2); + new (toFill++) EmojiData(992, 384, 3627932827, 0, 2); + new (toFill++) EmojiData(1024, 384, 3627932828, 0, 2); + new (toFill++) EmojiData(1056, 384, 3627932829, 0, 2); + new (toFill++) EmojiData(1088, 384, 3627932830, 0, 2); + new (toFill++) EmojiData(1120, 384, 3627932831, 0, 2); + new (toFill++) EmojiData(1152, 384, 3627932832, 0, 2); + new (toFill++) EmojiData(1184, 384, 3627932833, 0, 2); + new (toFill++) EmojiData(1216, 384, 3627932834, 0, 2); + new (toFill++) EmojiData(1248, 384, 3627932835, 0, 2); + new (toFill++) EmojiData(0, 416, 3627932836, 0, 2); + new (toFill++) EmojiData(32, 416, 3627932837, 0, 2); + new (toFill++) EmojiData(64, 416, 3627932838, 0, 2); + new (toFill++) EmojiData(96, 416, 3627932839, 0, 2); + new (toFill++) EmojiData(128, 416, 3627932840, 0, 2); + new (toFill++) EmojiData(160, 416, 3627932841, 0, 2); + new (toFill++) EmojiData(192, 416, 3627932842, 0, 2); + new (toFill++) EmojiData(224, 416, 3627932843, 0, 2); + new (toFill++) EmojiData(256, 416, 3627932844, 0, 2); + new (toFill++) EmojiData(288, 416, 3627932845, 0, 2); + new (toFill++) EmojiData(320, 416, 3627932846, 0, 2); + new (toFill++) EmojiData(352, 416, 3627932847, 0, 2); + new (toFill++) EmojiData(384, 416, 3627932848, 0, 2); + new (toFill++) EmojiData(416, 416, 3627932849, 0, 2); + new (toFill++) EmojiData(448, 416, 3627932850, 0, 2); + new (toFill++) EmojiData(480, 416, 3627932851, 0, 2); + new (toFill++) EmojiData(512, 416, 3627932852, 0, 2); + new (toFill++) EmojiData(544, 416, 3627932853, 0, 2); + new (toFill++) EmojiData(576, 416, 3627932854, 0, 2); + new (toFill++) EmojiData(608, 416, 3627932855, 0, 2); + new (toFill++) EmojiData(640, 416, 3627932856, 0, 2); + new (toFill++) EmojiData(672, 416, 3627932857, 0, 2); + new (toFill++) EmojiData(704, 416, 3627932858, 0, 2); + new (toFill++) EmojiData(736, 416, 3627932859, 0, 2); + new (toFill++) EmojiData(768, 416, 3627932860, 0, 2); + new (toFill++) EmojiData(800, 416, 3627932861, 0, 2); + new (toFill++) EmojiData(832, 416, 3627932862, 0, 2); + new (toFill++) EmojiData(864, 416, 3627932863, 0, 2); + new (toFill++) EmojiData(896, 416, 3627932864, 0, 2); + new (toFill++) EmojiData(928, 416, 3627932865, 0, 2); + new (toFill++) EmojiData(960, 416, 3627932866, 0, 2); + new (toFill++) EmojiData(992, 416, 3627932867, 0, 2); + new (toFill++) EmojiData(1024, 416, 3627932868, 0, 2); + new (toFill++) EmojiData(1056, 416, 3627932869, 0, 2); + new (toFill++) EmojiData(1088, 416, 3627932870, 0, 2); + new (toFill++) EmojiData(1120, 416, 3627932871, 0, 2); + new (toFill++) EmojiData(1152, 416, 3627932872, 0, 2); + new (toFill++) EmojiData(1184, 416, 3627932873, 0, 2); + new (toFill++) EmojiData(1216, 416, 3627932874, 0, 2); + new (toFill++) EmojiData(1248, 416, 3627932875, 0, 2); + new (toFill++) EmojiData(0, 448, 3627932876, 0, 2); + new (toFill++) EmojiData(32, 448, 3627932877, 0, 2); + new (toFill++) EmojiData(64, 448, 3627932878, 0, 2); + new (toFill++) EmojiData(96, 448, 3627932879, 0, 2); + new (toFill++) EmojiData(128, 448, 3627932880, 0, 2); + new (toFill++) EmojiData(160, 448, 3627932881, 0, 2); + new (toFill++) EmojiData(192, 448, 3627932882, 0, 2); + new (toFill++) EmojiData(224, 448, 3627932883, 0, 2); + new (toFill++) EmojiData(256, 448, 3627932884, 0, 2); + new (toFill++) EmojiData(288, 448, 3627932885, 0, 2); + new (toFill++) EmojiData(320, 448, 3627932886, 0, 2); + new (toFill++) EmojiData(352, 448, 3627932887, 0, 2); + new (toFill++) EmojiData(384, 448, 3627932888, 0, 2); + new (toFill++) EmojiData(416, 448, 3627932889, 0, 2); + new (toFill++) EmojiData(448, 448, 3627932890, 0, 2); + new (toFill++) EmojiData(480, 448, 3627932891, 0, 2); + new (toFill++) EmojiData(512, 448, 3627932892, 0, 2); + new (toFill++) EmojiData(544, 448, 3627932893, 0, 2); + new (toFill++) EmojiData(576, 448, 3627932894, 0, 2); + new (toFill++) EmojiData(608, 448, 3627932895, 0, 2); + new (toFill++) EmojiData(640, 448, 3627932896, 0, 2); + new (toFill++) EmojiData(672, 448, 3627932897, 0, 2); + new (toFill++) EmojiData(704, 448, 3627932898, 0, 2); + new (toFill++) EmojiData(736, 448, 3627932899, 0, 2); + new (toFill++) EmojiData(768, 448, 3627932900, 0, 2); + new (toFill++) EmojiData(800, 448, 3627932901, 0, 2); + new (toFill++) EmojiData(832, 448, 3627932902, 0, 2); + new (toFill++) EmojiData(864, 448, 3627932903, 0, 2); + new (toFill++) EmojiData(896, 448, 3627932904, 0, 2); + new (toFill++) EmojiData(928, 448, 3627932905, 0, 2); + new (toFill++) EmojiData(960, 448, 3627932906, 0, 2); + new (toFill++) EmojiData(992, 448, 3627932907, 0, 2); + new (toFill++) EmojiData(1024, 448, 3627932908, 0, 2); + new (toFill++) EmojiData(1056, 448, 3627932909, 0, 2); + new (toFill++) EmojiData(1088, 448, 3627932910, 0, 2); + new (toFill++) EmojiData(1120, 448, 3627932911, 0, 2); + new (toFill++) EmojiData(1152, 448, 3627932912, 0, 2); + new (toFill++) EmojiData(1184, 448, 3627932913, 0, 2); + new (toFill++) EmojiData(1216, 448, 3627932914, 0, 2); + new (toFill++) EmojiData(1248, 448, 3627932915, 0, 2); + new (toFill++) EmojiData(0, 480, 3627932916, 0, 2); + new (toFill++) EmojiData(32, 480, 3627932917, 0, 2); + new (toFill++) EmojiData(64, 480, 3627932918, 0, 2); + new (toFill++) EmojiData(96, 480, 3627932919, 0, 2); + new (toFill++) EmojiData(128, 480, 3627932921, 0, 2); + new (toFill++) EmojiData(160, 480, 3627932922, 0, 2); + new (toFill++) EmojiData(192, 480, 3627932923, 0, 2); + new (toFill++) EmojiData(224, 480, 3627932924, 0, 2); + new (toFill++) EmojiData(256, 480, 3627932928, 0, 2); + new (toFill++) EmojiData(288, 480, 3627932929, 0, 2); + new (toFill++) EmojiData(320, 480, 3627932930, 0, 2); + new (toFill++) EmojiData(352, 480, 3627932931, 0, 2); + new (toFill++) EmojiData(384, 480, 3627932932, 0, 2); + new (toFill++) EmojiData(416, 480, 3627932933, 0, 2); + new (toFill++) EmojiData(448, 480, 3627932934, 0, 2); + new (toFill++) EmojiData(480, 480, 3627932935, 0, 2); + new (toFill++) EmojiData(512, 480, 3627932936, 0, 2); + new (toFill++) EmojiData(544, 480, 3627932937, 0, 2); + new (toFill++) EmojiData(576, 480, 3627932938, 0, 2); + new (toFill++) EmojiData(608, 480, 3627932939, 0, 2); + new (toFill++) EmojiData(640, 480, 3627932940, 0, 2); + new (toFill++) EmojiData(672, 480, 3627932941, 0, 2); + new (toFill++) EmojiData(704, 480, 3627932942, 0, 2); + new (toFill++) EmojiData(736, 480, 3627932943, 0, 2); + new (toFill++) EmojiData(768, 480, 3627932944, 0, 2); + new (toFill++) EmojiData(800, 480, 3627932945, 0, 2); + new (toFill++) EmojiData(832, 480, 3627932946, 0, 2); + new (toFill++) EmojiData(864, 480, 3627932947, 0, 2); + new (toFill++) EmojiData(896, 480, 3627932948, 0, 2); + new (toFill++) EmojiData(928, 480, 3627932949, 0, 2); + new (toFill++) EmojiData(960, 480, 3627932950, 0, 2); + new (toFill++) EmojiData(992, 480, 3627932951, 0, 2); + new (toFill++) EmojiData(1024, 480, 3627932952, 0, 2); + new (toFill++) EmojiData(1056, 480, 3627932953, 0, 2); + new (toFill++) EmojiData(1088, 480, 3627932954, 0, 2); + new (toFill++) EmojiData(1120, 480, 3627932955, 0, 2); + new (toFill++) EmojiData(1152, 480, 3627932956, 0, 2); + new (toFill++) EmojiData(1184, 480, 3627932957, 0, 2); + new (toFill++) EmojiData(1216, 480, 3627932958, 0, 2); + new (toFill++) EmojiData(1248, 480, 3627932959, 0, 2); + new (toFill++) EmojiData(0, 512, 3627932960, 0, 2); + new (toFill++) EmojiData(32, 512, 3627932961, 0, 2); + new (toFill++) EmojiData(64, 512, 3627932962, 0, 2); + new (toFill++) EmojiData(96, 512, 3627932963, 0, 2); + new (toFill++) EmojiData(128, 512, 3627932964, 0, 2); + new (toFill++) EmojiData(160, 512, 3627932965, 0, 2); + new (toFill++) EmojiData(192, 512, 3627932966, 0, 2); + new (toFill++) EmojiData(224, 512, 3627932967, 0, 2); + new (toFill++) EmojiData(256, 512, 3627932968, 0, 2); + new (toFill++) EmojiData(288, 512, 3627932969, 0, 2); + new (toFill++) EmojiData(320, 512, 3627932970, 0, 2); + new (toFill++) EmojiData(352, 512, 3627932971, 0, 2); + new (toFill++) EmojiData(384, 512, 3627932972, 0, 2); + new (toFill++) EmojiData(416, 512, 3627932973, 0, 2); + new (toFill++) EmojiData(448, 512, 3627932974, 0, 2); + new (toFill++) EmojiData(480, 512, 3627932975, 0, 2); + new (toFill++) EmojiData(512, 512, 3627932976, 0, 2); + new (toFill++) EmojiData(544, 512, 3627932977, 0, 2); + new (toFill++) EmojiData(576, 512, 3627932978, 0, 2); + new (toFill++) EmojiData(608, 512, 3627932979, 0, 2); + new (toFill++) EmojiData(640, 512, 3627932980, 0, 2); + new (toFill++) EmojiData(672, 512, 3627932981, 0, 2); + new (toFill++) EmojiData(704, 512, 3627932982, 0, 2); + new (toFill++) EmojiData(736, 512, 3627932983, 0, 2); + new (toFill++) EmojiData(768, 512, 3627932984, 0, 2); + new (toFill++) EmojiData(800, 512, 3627932985, 0, 2); + new (toFill++) EmojiData(832, 512, 3627932986, 0, 2); + new (toFill++) EmojiData(864, 512, 3627932987, 0, 2); + new (toFill++) EmojiData(896, 512, 3627932988, 0, 2); + new (toFill++) EmojiData(928, 512, 3627932989, 0, 2); + new (toFill++) EmojiData(960, 512, 3627933008, 0, 2); + new (toFill++) EmojiData(992, 512, 3627933009, 0, 2); + new (toFill++) EmojiData(1024, 512, 3627933010, 0, 2); + new (toFill++) EmojiData(1056, 512, 3627933011, 0, 2); + new (toFill++) EmojiData(1088, 512, 3627933012, 0, 2); + new (toFill++) EmojiData(1120, 512, 3627933013, 0, 2); + new (toFill++) EmojiData(1152, 512, 3627933014, 0, 2); + new (toFill++) EmojiData(1184, 512, 3627933015, 0, 2); + new (toFill++) EmojiData(1216, 512, 3627933016, 0, 2); + new (toFill++) EmojiData(1248, 512, 3627933017, 0, 2); + new (toFill++) EmojiData(0, 544, 3627933018, 0, 2); + new (toFill++) EmojiData(32, 544, 3627933019, 0, 2); + new (toFill++) EmojiData(64, 544, 3627933020, 0, 2); + new (toFill++) EmojiData(96, 544, 3627933021, 0, 2); + new (toFill++) EmojiData(128, 544, 3627933022, 0, 2); + new (toFill++) EmojiData(160, 544, 3627933023, 0, 2); + new (toFill++) EmojiData(192, 544, 3627933024, 0, 2); + new (toFill++) EmojiData(224, 544, 3627933025, 0, 2); + new (toFill++) EmojiData(256, 544, 3627933026, 0, 2); + new (toFill++) EmojiData(288, 544, 3627933027, 0, 2); + new (toFill++) EmojiData(320, 544, 3627933028, 0, 2); + new (toFill++) EmojiData(352, 544, 3627933029, 0, 2); + new (toFill++) EmojiData(384, 544, 3627933030, 0, 2); + new (toFill++) EmojiData(416, 544, 3627933031, 0, 2); + new (toFill++) EmojiData(448, 544, 3627933179, 0, 2); + new (toFill++) EmojiData(480, 544, 3627933180, 0, 2); + new (toFill++) EmojiData(512, 544, 3627933181, 0, 2); + new (toFill++) EmojiData(544, 544, 3627933182, 0, 2); + new (toFill++) EmojiData(576, 544, 3627933183, 0, 2); + new (toFill++) EmojiData(608, 544, 3627933184, 0, 2); + new (toFill++) EmojiData(640, 544, 3627933185, 0, 2); + new (toFill++) EmojiData(672, 544, 3627933186, 0, 2); + new (toFill++) EmojiData(704, 544, 3627933187, 0, 2); + new (toFill++) EmojiData(736, 544, 3627933188, 0, 2); + new (toFill++) EmojiData(768, 544, 3627933189, 0, 2); + new (toFill++) EmojiData(800, 544, 3627933190, 0, 2); + new (toFill++) EmojiData(832, 544, 3627933191, 0, 2); + new (toFill++) EmojiData(864, 544, 3627933192, 0, 2); + new (toFill++) EmojiData(896, 544, 3627933193, 0, 2); + new (toFill++) EmojiData(928, 544, 3627933194, 0, 2); + new (toFill++) EmojiData(960, 544, 3627933195, 0, 2); + new (toFill++) EmojiData(992, 544, 3627933196, 0, 2); + new (toFill++) EmojiData(1024, 544, 3627933197, 0, 2); + new (toFill++) EmojiData(1056, 544, 3627933198, 0, 2); + new (toFill++) EmojiData(1088, 544, 3627933199, 0, 2); + new (toFill++) EmojiData(1120, 544, 3627933200, 0, 2); + new (toFill++) EmojiData(1152, 544, 3627933201, 0, 2); + new (toFill++) EmojiData(1184, 544, 3627933202, 0, 2); + new (toFill++) EmojiData(1216, 544, 3627933203, 0, 2); + new (toFill++) EmojiData(1248, 544, 3627933204, 0, 2); + new (toFill++) EmojiData(0, 576, 3627933205, 0, 2); + new (toFill++) EmojiData(32, 576, 3627933206, 0, 2); + new (toFill++) EmojiData(64, 576, 3627933207, 0, 2); + new (toFill++) EmojiData(96, 576, 3627933208, 0, 2); + new (toFill++) EmojiData(128, 576, 3627933209, 0, 2); + new (toFill++) EmojiData(160, 576, 3627933210, 0, 2); + new (toFill++) EmojiData(192, 576, 3627933211, 0, 2); + new (toFill++) EmojiData(224, 576, 3627933212, 0, 2); + new (toFill++) EmojiData(256, 576, 3627933213, 0, 2); + new (toFill++) EmojiData(288, 576, 3627933214, 0, 2); + new (toFill++) EmojiData(320, 576, 3627933215, 0, 2); + new (toFill++) EmojiData(352, 576, 3627933216, 0, 2); + new (toFill++) EmojiData(384, 576, 3627933217, 0, 2); + new (toFill++) EmojiData(416, 576, 3627933218, 0, 2); + new (toFill++) EmojiData(448, 576, 3627933219, 0, 2); + new (toFill++) EmojiData(480, 576, 3627933220, 0, 2); + new (toFill++) EmojiData(512, 576, 3627933221, 0, 2); + new (toFill++) EmojiData(544, 576, 3627933222, 0, 2); + new (toFill++) EmojiData(576, 576, 3627933223, 0, 2); + new (toFill++) EmojiData(608, 576, 3627933224, 0, 2); + new (toFill++) EmojiData(640, 576, 3627933225, 0, 2); + new (toFill++) EmojiData(672, 576, 3627933226, 0, 2); + new (toFill++) EmojiData(704, 576, 3627933227, 0, 2); + new (toFill++) EmojiData(736, 576, 3627933228, 0, 2); + new (toFill++) EmojiData(768, 576, 3627933229, 0, 2); + new (toFill++) EmojiData(800, 576, 3627933230, 0, 2); + new (toFill++) EmojiData(832, 576, 3627933231, 0, 2); + new (toFill++) EmojiData(864, 576, 3627933232, 0, 2); + new (toFill++) EmojiData(896, 576, 3627933233, 0, 2); + new (toFill++) EmojiData(928, 576, 3627933234, 0, 2); + new (toFill++) EmojiData(960, 576, 3627933235, 0, 2); + new (toFill++) EmojiData(992, 576, 3627933236, 0, 2); + new (toFill++) EmojiData(1024, 576, 3627933237, 0, 2); + new (toFill++) EmojiData(1056, 576, 3627933238, 0, 2); + new (toFill++) EmojiData(1088, 576, 3627933239, 0, 2); + new (toFill++) EmojiData(1120, 576, 3627933240, 0, 2); + new (toFill++) EmojiData(1152, 576, 3627933241, 0, 2); + new (toFill++) EmojiData(1184, 576, 3627933242, 0, 2); + new (toFill++) EmojiData(1216, 576, 3627933243, 0, 2); + new (toFill++) EmojiData(1248, 576, 3627933244, 0, 2); + new (toFill++) EmojiData(0, 608, 3627933245, 0, 2); + new (toFill++) EmojiData(32, 608, 3627933246, 0, 2); + new (toFill++) EmojiData(64, 608, 3627933247, 0, 2); + new (toFill++) EmojiData(96, 608, 3627933248, 0, 2); + new (toFill++) EmojiData(128, 608, 3627933253, 0, 2); + new (toFill++) EmojiData(160, 608, 3627933254, 0, 2); + new (toFill++) EmojiData(192, 608, 3627933255, 0, 2); + new (toFill++) EmojiData(224, 608, 3627933256, 0, 2); + new (toFill++) EmojiData(256, 608, 3627933257, 0, 2); + new (toFill++) EmojiData(288, 608, 3627933258, 0, 2); + new (toFill++) EmojiData(320, 608, 3627933259, 0, 2); + new (toFill++) EmojiData(352, 608, 3627933260, 0, 2); + new (toFill++) EmojiData(384, 608, 3627933261, 0, 2); + new (toFill++) EmojiData(416, 608, 3627933262, 0, 2); + new (toFill++) EmojiData(448, 608, 3627933263, 0, 2); + new (toFill++) EmojiData(480, 608, 3627933312, 0, 2); + new (toFill++) EmojiData(512, 608, 3627933313, 0, 2); + new (toFill++) EmojiData(544, 608, 3627933314, 0, 2); + new (toFill++) EmojiData(576, 608, 3627933315, 0, 2); + new (toFill++) EmojiData(608, 608, 3627933316, 0, 2); + new (toFill++) EmojiData(640, 608, 3627933317, 0, 2); + new (toFill++) EmojiData(672, 608, 3627933318, 0, 2); + new (toFill++) EmojiData(704, 608, 3627933319, 0, 2); + new (toFill++) EmojiData(736, 608, 3627933320, 0, 2); + new (toFill++) EmojiData(768, 608, 3627933321, 0, 2); + new (toFill++) EmojiData(800, 608, 3627933322, 0, 2); + new (toFill++) EmojiData(832, 608, 3627933323, 0, 2); + new (toFill++) EmojiData(864, 608, 3627933324, 0, 2); + new (toFill++) EmojiData(896, 608, 3627933325, 0, 2); + new (toFill++) EmojiData(928, 608, 3627933326, 0, 2); + new (toFill++) EmojiData(960, 608, 3627933327, 0, 2); + new (toFill++) EmojiData(992, 608, 3627933328, 0, 2); + new (toFill++) EmojiData(1024, 608, 3627933329, 0, 2); + new (toFill++) EmojiData(1056, 608, 3627933330, 0, 2); + new (toFill++) EmojiData(1088, 608, 3627933331, 0, 2); + new (toFill++) EmojiData(1120, 608, 3627933332, 0, 2); + new (toFill++) EmojiData(1152, 608, 3627933333, 0, 2); + new (toFill++) EmojiData(1184, 608, 3627933334, 0, 2); + new (toFill++) EmojiData(1216, 608, 3627933335, 0, 2); + new (toFill++) EmojiData(1248, 608, 3627933336, 0, 2); + new (toFill++) EmojiData(0, 640, 3627933337, 0, 2); + new (toFill++) EmojiData(32, 640, 3627933338, 0, 2); + new (toFill++) EmojiData(64, 640, 3627933339, 0, 2); + new (toFill++) EmojiData(96, 640, 3627933340, 0, 2); + new (toFill++) EmojiData(128, 640, 3627933341, 0, 2); + new (toFill++) EmojiData(160, 640, 3627933342, 0, 2); + new (toFill++) EmojiData(192, 640, 3627933343, 0, 2); + new (toFill++) EmojiData(224, 640, 3627933344, 0, 2); + new (toFill++) EmojiData(256, 640, 3627933345, 0, 2); + new (toFill++) EmojiData(288, 640, 3627933346, 0, 2); + new (toFill++) EmojiData(320, 640, 3627933347, 0, 2); + new (toFill++) EmojiData(352, 640, 3627933348, 0, 2); + new (toFill++) EmojiData(384, 640, 3627933349, 0, 2); + new (toFill++) EmojiData(416, 640, 3627933350, 0, 2); + new (toFill++) EmojiData(448, 640, 3627933351, 0, 2); + new (toFill++) EmojiData(480, 640, 3627933352, 0, 2); + new (toFill++) EmojiData(512, 640, 3627933353, 0, 2); + new (toFill++) EmojiData(544, 640, 3627933354, 0, 2); + new (toFill++) EmojiData(576, 640, 3627933355, 0, 2); + new (toFill++) EmojiData(608, 640, 3627933356, 0, 2); + new (toFill++) EmojiData(640, 640, 3627933357, 0, 2); + new (toFill++) EmojiData(672, 640, 3627933358, 0, 2); + new (toFill++) EmojiData(704, 640, 3627933359, 0, 2); + new (toFill++) EmojiData(736, 640, 3627933360, 0, 2); + new (toFill++) EmojiData(768, 640, 3627933361, 0, 2); + new (toFill++) EmojiData(800, 640, 3627933362, 0, 2); + new (toFill++) EmojiData(832, 640, 3627933363, 0, 2); + new (toFill++) EmojiData(864, 640, 3627933364, 0, 2); + new (toFill++) EmojiData(896, 640, 3627933365, 0, 2); + new (toFill++) EmojiData(928, 640, 3627933366, 0, 2); + new (toFill++) EmojiData(960, 640, 3627933367, 0, 2); + new (toFill++) EmojiData(992, 640, 3627933368, 0, 2); + new (toFill++) EmojiData(1024, 640, 3627933369, 0, 2); + new (toFill++) EmojiData(1056, 640, 3627933370, 0, 2); + new (toFill++) EmojiData(1088, 640, 3627933371, 0, 2); + new (toFill++) EmojiData(1120, 640, 3627933372, 0, 2); + new (toFill++) EmojiData(1152, 640, 3627933373, 0, 2); + new (toFill++) EmojiData(1184, 640, 3627933374, 0, 2); + new (toFill++) EmojiData(1216, 640, 3627933375, 0, 2); + new (toFill++) EmojiData(1248, 640, 3627933376, 0, 2); + new (toFill++) EmojiData(0, 672, 3627933377, 0, 2); + new (toFill++) EmojiData(32, 672, 3627933378, 0, 2); + new (toFill++) EmojiData(64, 672, 3627933379, 0, 2); + new (toFill++) EmojiData(96, 672, 3627933380, 0, 2); + new (toFill++) EmojiData(128, 672, 3627933381, 0, 2); + break; + + }; +}; + +const EmojiData *getEmoji(uint32 code) { + if (!emojis) return 0; + + uint32 highCode = code >> 16; + if (!highCode) { + switch (code) { + case 169: return &emojis[0]; + case 174: return &emojis[1]; + } + + if (code < 8252 || code > 12953) return 0; + + switch (code) { + case 8252: return &emojis[2]; + case 8265: return &emojis[3]; + case 8482: return &emojis[4]; + case 8505: return &emojis[5]; + case 8596: return &emojis[6]; + case 8597: return &emojis[7]; + case 8598: return &emojis[8]; + case 8599: return &emojis[9]; + case 8600: return &emojis[10]; + case 8601: return &emojis[11]; + case 8617: return &emojis[12]; + case 8618: return &emojis[13]; + case 8986: return &emojis[14]; + case 8987: return &emojis[15]; + case 9193: return &emojis[16]; + case 9194: return &emojis[17]; + case 9195: return &emojis[18]; + case 9196: return &emojis[19]; + case 9200: return &emojis[20]; + case 9203: return &emojis[21]; + case 9410: return &emojis[22]; + case 9642: return &emojis[23]; + case 9643: return &emojis[24]; + case 9654: return &emojis[25]; + case 9664: return &emojis[26]; + case 9723: return &emojis[27]; + case 9724: return &emojis[28]; + case 9725: return &emojis[29]; + case 9726: return &emojis[30]; + case 9728: return &emojis[31]; + case 9729: return &emojis[32]; + case 9742: return &emojis[33]; + case 9745: return &emojis[34]; + case 9748: return &emojis[35]; + case 9749: return &emojis[36]; + case 9757: return &emojis[37]; + case 9786: return &emojis[38]; + case 9800: return &emojis[39]; + case 9801: return &emojis[40]; + case 9802: return &emojis[41]; + case 9803: return &emojis[42]; + case 9804: return &emojis[43]; + case 9805: return &emojis[44]; + case 9806: return &emojis[45]; + case 9807: return &emojis[46]; + case 9808: return &emojis[47]; + case 9809: return &emojis[48]; + case 9810: return &emojis[49]; + case 9811: return &emojis[50]; + case 9824: return &emojis[51]; + case 9827: return &emojis[52]; + case 9829: return &emojis[53]; + case 9830: return &emojis[54]; + case 9832: return &emojis[55]; + case 9851: return &emojis[56]; + case 9855: return &emojis[57]; + case 9875: return &emojis[58]; + case 9888: return &emojis[59]; + case 9889: return &emojis[60]; + case 9898: return &emojis[61]; + case 9899: return &emojis[62]; + case 9917: return &emojis[63]; + case 9918: return &emojis[64]; + case 9924: return &emojis[65]; + case 9925: return &emojis[66]; + case 9934: return &emojis[67]; + case 9940: return &emojis[68]; + case 9962: return &emojis[69]; + case 9970: return &emojis[70]; + case 9971: return &emojis[71]; + case 9973: return &emojis[72]; + case 9978: return &emojis[73]; + case 9981: return &emojis[74]; + case 9986: return &emojis[75]; + case 9989: return &emojis[76]; + case 9992: return &emojis[77]; + case 9993: return &emojis[78]; + case 9994: return &emojis[79]; + case 9995: return &emojis[80]; + case 9996: return &emojis[81]; + case 9999: return &emojis[82]; + case 10002: return &emojis[83]; + case 10004: return &emojis[84]; + case 10006: return &emojis[85]; + case 10024: return &emojis[86]; + case 10035: return &emojis[87]; + case 10036: return &emojis[88]; + case 10052: return &emojis[89]; + case 10055: return &emojis[90]; + case 10060: return &emojis[91]; + case 10062: return &emojis[92]; + case 10067: return &emojis[93]; + case 10068: return &emojis[94]; + case 10069: return &emojis[95]; + case 10071: return &emojis[96]; + case 10084: return &emojis[97]; + case 10133: return &emojis[98]; + case 10134: return &emojis[99]; + case 10135: return &emojis[100]; + case 10145: return &emojis[101]; + case 10160: return &emojis[102]; + case 10175: return &emojis[103]; + case 10548: return &emojis[104]; + case 10549: return &emojis[105]; + case 11013: return &emojis[106]; + case 11014: return &emojis[107]; + case 11015: return &emojis[108]; + case 11035: return &emojis[109]; + case 11036: return &emojis[110]; + case 11088: return &emojis[111]; + case 11093: return &emojis[112]; + case 12336: return &emojis[113]; + case 12349: return &emojis[114]; + case 12951: return &emojis[115]; + case 12953: return &emojis[116]; + } + + return 0; + } + + if (highCode == 35 || highCode >= 48 && highCode < 58) { + if ((code & 0xFFFF) != 0x20E3) return 0; + + switch (code) { + case 2302179: return &emojis[117]; + case 3154147: return &emojis[118]; + case 3219683: return &emojis[119]; + case 3285219: return &emojis[120]; + case 3350755: return &emojis[121]; + case 3416291: return &emojis[122]; + case 3481827: return &emojis[123]; + case 3547363: return &emojis[124]; + case 3612899: return &emojis[125]; + case 3678435: return &emojis[126]; + case 3743971: return &emojis[127]; + } + + return 0; + } + + if (code < 3627867140 || code > 3627933381) return 0; + + switch (code) { + case 3627867140: return &emojis[128]; + case 3627867343: return &emojis[129]; + case 3627867504: return &emojis[130]; + case 3627867505: return &emojis[131]; + case 3627867518: return &emojis[132]; + case 3627867519: return &emojis[133]; + case 3627867534: return &emojis[134]; + case 3627867537: return &emojis[135]; + case 3627867538: return &emojis[136]; + case 3627867539: return &emojis[137]; + case 3627867540: return &emojis[138]; + case 3627867541: return &emojis[139]; + case 3627867542: return &emojis[140]; + case 3627867543: return &emojis[141]; + case 3627867544: return &emojis[142]; + case 3627867545: return &emojis[143]; + case 3627867546: return &emojis[144]; + case 3627867624: return &emojis[145]; + case 3627867625: return &emojis[146]; + case 3627867626: return &emojis[147]; + case 3627867627: return &emojis[148]; + case 3627867628: return &emojis[149]; + case 3627867630: return &emojis[150]; + case 3627867631: return &emojis[151]; + case 3627867632: return &emojis[152]; + case 3627867639: return &emojis[153]; + case 3627867642: return &emojis[154]; + case 3627867649: return &emojis[155]; + case 3627867650: return &emojis[156]; + case 3627867674: return &emojis[157]; + case 3627867695: return &emojis[158]; + case 3627867698: return &emojis[159]; + case 3627867699: return &emojis[160]; + case 3627867700: return &emojis[161]; + case 3627867701: return &emojis[162]; + case 3627867702: return &emojis[163]; + case 3627867703: return &emojis[164]; + case 3627867704: return &emojis[165]; + case 3627867705: return &emojis[166]; + case 3627867706: return &emojis[167]; + case 3627867728: return &emojis[168]; + case 3627867729: return &emojis[169]; + case 3627867904: return &emojis[170]; + case 3627867905: return &emojis[171]; + case 3627867906: return &emojis[172]; + case 3627867907: return &emojis[173]; + case 3627867908: return &emojis[174]; + case 3627867909: return &emojis[175]; + case 3627867910: return &emojis[176]; + case 3627867911: return &emojis[177]; + case 3627867912: return &emojis[178]; + case 3627867913: return &emojis[179]; + case 3627867914: return &emojis[180]; + case 3627867915: return &emojis[181]; + case 3627867916: return &emojis[182]; + case 3627867917: return &emojis[183]; + case 3627867918: return &emojis[184]; + case 3627867919: return &emojis[185]; + case 3627867920: return &emojis[186]; + case 3627867921: return &emojis[187]; + case 3627867922: return &emojis[188]; + case 3627867923: return &emojis[189]; + case 3627867924: return &emojis[190]; + case 3627867925: return &emojis[191]; + case 3627867926: return &emojis[192]; + case 3627867927: return &emojis[193]; + case 3627867928: return &emojis[194]; + case 3627867929: return &emojis[195]; + case 3627867930: return &emojis[196]; + case 3627867931: return &emojis[197]; + case 3627867932: return &emojis[198]; + case 3627867933: return &emojis[199]; + case 3627867934: return &emojis[200]; + case 3627867935: return &emojis[201]; + case 3627867936: return &emojis[202]; + case 3627867952: return &emojis[203]; + case 3627867953: return &emojis[204]; + case 3627867954: return &emojis[205]; + case 3627867955: return &emojis[206]; + case 3627867956: return &emojis[207]; + case 3627867957: return &emojis[208]; + case 3627867959: return &emojis[209]; + case 3627867960: return &emojis[210]; + case 3627867961: return &emojis[211]; + case 3627867962: return &emojis[212]; + case 3627867963: return &emojis[213]; + case 3627867964: return &emojis[214]; + case 3627867965: return &emojis[215]; + case 3627867966: return &emojis[216]; + case 3627867967: return &emojis[217]; + case 3627867968: return &emojis[218]; + case 3627867969: return &emojis[219]; + case 3627867970: return &emojis[220]; + case 3627867971: return &emojis[221]; + case 3627867972: return &emojis[222]; + case 3627867973: return &emojis[223]; + case 3627867974: return &emojis[224]; + case 3627867975: return &emojis[225]; + case 3627867976: return &emojis[226]; + case 3627867977: return &emojis[227]; + case 3627867978: return &emojis[228]; + case 3627867979: return &emojis[229]; + case 3627867980: return &emojis[230]; + case 3627867981: return &emojis[231]; + case 3627867982: return &emojis[232]; + case 3627867983: return &emojis[233]; + case 3627867984: return &emojis[234]; + case 3627867985: return &emojis[235]; + case 3627867986: return &emojis[236]; + case 3627867987: return &emojis[237]; + case 3627867988: return &emojis[238]; + case 3627867989: return &emojis[239]; + case 3627867990: return &emojis[240]; + case 3627867991: return &emojis[241]; + case 3627867992: return &emojis[242]; + case 3627867993: return &emojis[243]; + case 3627867994: return &emojis[244]; + case 3627867995: return &emojis[245]; + case 3627867996: return &emojis[246]; + case 3627867997: return &emojis[247]; + case 3627867998: return &emojis[248]; + case 3627867999: return &emojis[249]; + case 3627868000: return &emojis[250]; + case 3627868001: return &emojis[251]; + case 3627868002: return &emojis[252]; + case 3627868003: return &emojis[253]; + case 3627868004: return &emojis[254]; + case 3627868005: return &emojis[255]; + case 3627868006: return &emojis[256]; + case 3627868007: return &emojis[257]; + case 3627868008: return &emojis[258]; + case 3627868009: return &emojis[259]; + case 3627868010: return &emojis[260]; + case 3627868011: return &emojis[261]; + case 3627868012: return &emojis[262]; + case 3627868013: return &emojis[263]; + case 3627868014: return &emojis[264]; + case 3627868015: return &emojis[265]; + case 3627868016: return &emojis[266]; + case 3627868017: return &emojis[267]; + case 3627868018: return &emojis[268]; + case 3627868019: return &emojis[269]; + case 3627868020: return &emojis[270]; + case 3627868021: return &emojis[271]; + case 3627868022: return &emojis[272]; + case 3627868023: return &emojis[273]; + case 3627868024: return &emojis[274]; + case 3627868025: return &emojis[275]; + case 3627868026: return &emojis[276]; + case 3627868027: return &emojis[277]; + case 3627868028: return &emojis[278]; + case 3627868032: return &emojis[279]; + case 3627868033: return &emojis[280]; + case 3627868034: return &emojis[281]; + case 3627868035: return &emojis[282]; + case 3627868036: return &emojis[283]; + case 3627868037: return &emojis[284]; + case 3627868038: return &emojis[285]; + case 3627868039: return &emojis[286]; + case 3627868040: return &emojis[287]; + case 3627868041: return &emojis[288]; + case 3627868042: return &emojis[289]; + case 3627868043: return &emojis[290]; + case 3627868044: return &emojis[291]; + case 3627868045: return &emojis[292]; + case 3627868046: return &emojis[293]; + case 3627868047: return &emojis[294]; + case 3627868048: return &emojis[295]; + case 3627868049: return &emojis[296]; + case 3627868050: return &emojis[297]; + case 3627868051: return &emojis[298]; + case 3627868064: return &emojis[299]; + case 3627868065: return &emojis[300]; + case 3627868066: return &emojis[301]; + case 3627868067: return &emojis[302]; + case 3627868068: return &emojis[303]; + case 3627868069: return &emojis[304]; + case 3627868070: return &emojis[305]; + case 3627868071: return &emojis[306]; + case 3627868072: return &emojis[307]; + case 3627868073: return &emojis[308]; + case 3627868074: return &emojis[309]; + case 3627868075: return &emojis[310]; + case 3627868076: return &emojis[311]; + case 3627868077: return &emojis[312]; + case 3627868078: return &emojis[313]; + case 3627868079: return &emojis[314]; + case 3627868080: return &emojis[315]; + case 3627868081: return &emojis[316]; + case 3627868082: return &emojis[317]; + case 3627868083: return &emojis[318]; + case 3627868084: return &emojis[319]; + case 3627868085: return &emojis[320]; + case 3627868086: return &emojis[321]; + case 3627868087: return &emojis[322]; + case 3627868088: return &emojis[323]; + case 3627868089: return &emojis[324]; + case 3627868090: return &emojis[325]; + case 3627868091: return &emojis[326]; + case 3627868092: return &emojis[327]; + case 3627868093: return &emojis[328]; + case 3627868094: return &emojis[329]; + case 3627868095: return &emojis[330]; + case 3627868096: return &emojis[331]; + case 3627868097: return &emojis[332]; + case 3627868098: return &emojis[333]; + case 3627868099: return &emojis[334]; + case 3627868100: return &emojis[335]; + case 3627868102: return &emojis[336]; + case 3627868103: return &emojis[337]; + case 3627868104: return &emojis[338]; + case 3627868105: return &emojis[339]; + case 3627868106: return &emojis[340]; + case 3627868128: return &emojis[341]; + case 3627868129: return &emojis[342]; + case 3627868130: return &emojis[343]; + case 3627868131: return &emojis[344]; + case 3627868132: return &emojis[345]; + case 3627868133: return &emojis[346]; + case 3627868134: return &emojis[347]; + case 3627868135: return &emojis[348]; + case 3627868136: return &emojis[349]; + case 3627868137: return &emojis[350]; + case 3627868138: return &emojis[351]; + case 3627868139: return &emojis[352]; + case 3627868140: return &emojis[353]; + case 3627868141: return &emojis[354]; + case 3627868142: return &emojis[355]; + case 3627868143: return &emojis[356]; + case 3627868144: return &emojis[357]; + case 3627932672: return &emojis[358]; + case 3627932673: return &emojis[359]; + case 3627932674: return &emojis[360]; + case 3627932675: return &emojis[361]; + case 3627932676: return &emojis[362]; + case 3627932677: return &emojis[363]; + case 3627932678: return &emojis[364]; + case 3627932679: return &emojis[365]; + case 3627932680: return &emojis[366]; + case 3627932681: return &emojis[367]; + case 3627932682: return &emojis[368]; + case 3627932683: return &emojis[369]; + case 3627932684: return &emojis[370]; + case 3627932685: return &emojis[371]; + case 3627932686: return &emojis[372]; + case 3627932687: return &emojis[373]; + case 3627932688: return &emojis[374]; + case 3627932689: return &emojis[375]; + case 3627932690: return &emojis[376]; + case 3627932691: return &emojis[377]; + case 3627932692: return &emojis[378]; + case 3627932693: return &emojis[379]; + case 3627932694: return &emojis[380]; + case 3627932695: return &emojis[381]; + case 3627932696: return &emojis[382]; + case 3627932697: return &emojis[383]; + case 3627932698: return &emojis[384]; + case 3627932699: return &emojis[385]; + case 3627932700: return &emojis[386]; + case 3627932701: return &emojis[387]; + case 3627932702: return &emojis[388]; + case 3627932703: return &emojis[389]; + case 3627932704: return &emojis[390]; + case 3627932705: return &emojis[391]; + case 3627932706: return &emojis[392]; + case 3627932707: return &emojis[393]; + case 3627932708: return &emojis[394]; + case 3627932709: return &emojis[395]; + case 3627932710: return &emojis[396]; + case 3627932711: return &emojis[397]; + case 3627932712: return &emojis[398]; + case 3627932713: return &emojis[399]; + case 3627932714: return &emojis[400]; + case 3627932715: return &emojis[401]; + case 3627932716: return &emojis[402]; + case 3627932717: return &emojis[403]; + case 3627932718: return &emojis[404]; + case 3627932719: return &emojis[405]; + case 3627932720: return &emojis[406]; + case 3627932721: return &emojis[407]; + case 3627932722: return &emojis[408]; + case 3627932723: return &emojis[409]; + case 3627932724: return &emojis[410]; + case 3627932725: return &emojis[411]; + case 3627932726: return &emojis[412]; + case 3627932727: return &emojis[413]; + case 3627932728: return &emojis[414]; + case 3627932729: return &emojis[415]; + case 3627932730: return &emojis[416]; + case 3627932731: return &emojis[417]; + case 3627932732: return &emojis[418]; + case 3627932733: return &emojis[419]; + case 3627932734: return &emojis[420]; + case 3627932736: return &emojis[421]; + case 3627932738: return &emojis[422]; + case 3627932739: return &emojis[423]; + case 3627932740: return &emojis[424]; + case 3627932741: return &emojis[425]; + case 3627932742: return &emojis[426]; + case 3627932743: return &emojis[427]; + case 3627932744: return &emojis[428]; + case 3627932745: return &emojis[429]; + case 3627932746: return &emojis[430]; + case 3627932747: return &emojis[431]; + case 3627932748: return &emojis[432]; + case 3627932749: return &emojis[433]; + case 3627932750: return &emojis[434]; + case 3627932751: return &emojis[435]; + case 3627932752: return &emojis[436]; + case 3627932753: return &emojis[437]; + case 3627932754: return &emojis[438]; + case 3627932755: return &emojis[439]; + case 3627932756: return &emojis[440]; + case 3627932757: return &emojis[441]; + case 3627932758: return &emojis[442]; + case 3627932759: return &emojis[443]; + case 3627932760: return &emojis[444]; + case 3627932761: return &emojis[445]; + case 3627932762: return &emojis[446]; + case 3627932763: return &emojis[447]; + case 3627932764: return &emojis[448]; + case 3627932765: return &emojis[449]; + case 3627932766: return &emojis[450]; + case 3627932767: return &emojis[451]; + case 3627932768: return &emojis[452]; + case 3627932769: return &emojis[453]; + case 3627932770: return &emojis[454]; + case 3627932771: return &emojis[455]; + case 3627932772: return &emojis[456]; + case 3627932773: return &emojis[457]; + case 3627932774: return &emojis[458]; + case 3627932775: return &emojis[459]; + case 3627932776: return &emojis[460]; + case 3627932777: return &emojis[461]; + case 3627932778: return &emojis[462]; + case 3627932779: return &emojis[463]; + case 3627932780: return &emojis[464]; + case 3627932781: return &emojis[465]; + case 3627932782: return &emojis[466]; + case 3627932783: return &emojis[467]; + case 3627932784: return &emojis[468]; + case 3627932785: return &emojis[469]; + case 3627932786: return &emojis[470]; + case 3627932787: return &emojis[471]; + case 3627932788: return &emojis[472]; + case 3627932789: return &emojis[473]; + case 3627932790: return &emojis[474]; + case 3627932791: return &emojis[475]; + case 3627932792: return &emojis[476]; + case 3627932793: return &emojis[477]; + case 3627932794: return &emojis[478]; + case 3627932795: return &emojis[479]; + case 3627932796: return &emojis[480]; + case 3627932797: return &emojis[481]; + case 3627932798: return &emojis[482]; + case 3627932799: return &emojis[483]; + case 3627932800: return &emojis[484]; + case 3627932801: return &emojis[485]; + case 3627932802: return &emojis[486]; + case 3627932803: return &emojis[487]; + case 3627932804: return &emojis[488]; + case 3627932805: return &emojis[489]; + case 3627932806: return &emojis[490]; + case 3627932807: return &emojis[491]; + case 3627932808: return &emojis[492]; + case 3627932809: return &emojis[493]; + case 3627932810: return &emojis[494]; + case 3627932811: return &emojis[495]; + case 3627932812: return &emojis[496]; + case 3627932813: return &emojis[497]; + case 3627932814: return &emojis[498]; + case 3627932815: return &emojis[499]; + case 3627932816: return &emojis[500]; + case 3627932817: return &emojis[501]; + case 3627932818: return &emojis[502]; + case 3627932819: return &emojis[503]; + case 3627932820: return &emojis[504]; + case 3627932821: return &emojis[505]; + case 3627932822: return &emojis[506]; + case 3627932823: return &emojis[507]; + case 3627932824: return &emojis[508]; + case 3627932825: return &emojis[509]; + case 3627932826: return &emojis[510]; + case 3627932827: return &emojis[511]; + case 3627932828: return &emojis[512]; + case 3627932829: return &emojis[513]; + case 3627932830: return &emojis[514]; + case 3627932831: return &emojis[515]; + case 3627932832: return &emojis[516]; + case 3627932833: return &emojis[517]; + case 3627932834: return &emojis[518]; + case 3627932835: return &emojis[519]; + case 3627932836: return &emojis[520]; + case 3627932837: return &emojis[521]; + case 3627932838: return &emojis[522]; + case 3627932839: return &emojis[523]; + case 3627932840: return &emojis[524]; + case 3627932841: return &emojis[525]; + case 3627932842: return &emojis[526]; + case 3627932843: return &emojis[527]; + case 3627932844: return &emojis[528]; + case 3627932845: return &emojis[529]; + case 3627932846: return &emojis[530]; + case 3627932847: return &emojis[531]; + case 3627932848: return &emojis[532]; + case 3627932849: return &emojis[533]; + case 3627932850: return &emojis[534]; + case 3627932851: return &emojis[535]; + case 3627932852: return &emojis[536]; + case 3627932853: return &emojis[537]; + case 3627932854: return &emojis[538]; + case 3627932855: return &emojis[539]; + case 3627932856: return &emojis[540]; + case 3627932857: return &emojis[541]; + case 3627932858: return &emojis[542]; + case 3627932859: return &emojis[543]; + case 3627932860: return &emojis[544]; + case 3627932861: return &emojis[545]; + case 3627932862: return &emojis[546]; + case 3627932863: return &emojis[547]; + case 3627932864: return &emojis[548]; + case 3627932865: return &emojis[549]; + case 3627932866: return &emojis[550]; + case 3627932867: return &emojis[551]; + case 3627932868: return &emojis[552]; + case 3627932869: return &emojis[553]; + case 3627932870: return &emojis[554]; + case 3627932871: return &emojis[555]; + case 3627932872: return &emojis[556]; + case 3627932873: return &emojis[557]; + case 3627932874: return &emojis[558]; + case 3627932875: return &emojis[559]; + case 3627932876: return &emojis[560]; + case 3627932877: return &emojis[561]; + case 3627932878: return &emojis[562]; + case 3627932879: return &emojis[563]; + case 3627932880: return &emojis[564]; + case 3627932881: return &emojis[565]; + case 3627932882: return &emojis[566]; + case 3627932883: return &emojis[567]; + case 3627932884: return &emojis[568]; + case 3627932885: return &emojis[569]; + case 3627932886: return &emojis[570]; + case 3627932887: return &emojis[571]; + case 3627932888: return &emojis[572]; + case 3627932889: return &emojis[573]; + case 3627932890: return &emojis[574]; + case 3627932891: return &emojis[575]; + case 3627932892: return &emojis[576]; + case 3627932893: return &emojis[577]; + case 3627932894: return &emojis[578]; + case 3627932895: return &emojis[579]; + case 3627932896: return &emojis[580]; + case 3627932897: return &emojis[581]; + case 3627932898: return &emojis[582]; + case 3627932899: return &emojis[583]; + case 3627932900: return &emojis[584]; + case 3627932901: return &emojis[585]; + case 3627932902: return &emojis[586]; + case 3627932903: return &emojis[587]; + case 3627932904: return &emojis[588]; + case 3627932905: return &emojis[589]; + case 3627932906: return &emojis[590]; + case 3627932907: return &emojis[591]; + case 3627932908: return &emojis[592]; + case 3627932909: return &emojis[593]; + case 3627932910: return &emojis[594]; + case 3627932911: return &emojis[595]; + case 3627932912: return &emojis[596]; + case 3627932913: return &emojis[597]; + case 3627932914: return &emojis[598]; + case 3627932915: return &emojis[599]; + case 3627932916: return &emojis[600]; + case 3627932917: return &emojis[601]; + case 3627932918: return &emojis[602]; + case 3627932919: return &emojis[603]; + case 3627932921: return &emojis[604]; + case 3627932922: return &emojis[605]; + case 3627932923: return &emojis[606]; + case 3627932924: return &emojis[607]; + case 3627932928: return &emojis[608]; + case 3627932929: return &emojis[609]; + case 3627932930: return &emojis[610]; + case 3627932931: return &emojis[611]; + case 3627932932: return &emojis[612]; + case 3627932933: return &emojis[613]; + case 3627932934: return &emojis[614]; + case 3627932935: return &emojis[615]; + case 3627932936: return &emojis[616]; + case 3627932937: return &emojis[617]; + case 3627932938: return &emojis[618]; + case 3627932939: return &emojis[619]; + case 3627932940: return &emojis[620]; + case 3627932941: return &emojis[621]; + case 3627932942: return &emojis[622]; + case 3627932943: return &emojis[623]; + case 3627932944: return &emojis[624]; + case 3627932945: return &emojis[625]; + case 3627932946: return &emojis[626]; + case 3627932947: return &emojis[627]; + case 3627932948: return &emojis[628]; + case 3627932949: return &emojis[629]; + case 3627932950: return &emojis[630]; + case 3627932951: return &emojis[631]; + case 3627932952: return &emojis[632]; + case 3627932953: return &emojis[633]; + case 3627932954: return &emojis[634]; + case 3627932955: return &emojis[635]; + case 3627932956: return &emojis[636]; + case 3627932957: return &emojis[637]; + case 3627932958: return &emojis[638]; + case 3627932959: return &emojis[639]; + case 3627932960: return &emojis[640]; + case 3627932961: return &emojis[641]; + case 3627932962: return &emojis[642]; + case 3627932963: return &emojis[643]; + case 3627932964: return &emojis[644]; + case 3627932965: return &emojis[645]; + case 3627932966: return &emojis[646]; + case 3627932967: return &emojis[647]; + case 3627932968: return &emojis[648]; + case 3627932969: return &emojis[649]; + case 3627932970: return &emojis[650]; + case 3627932971: return &emojis[651]; + case 3627932972: return &emojis[652]; + case 3627932973: return &emojis[653]; + case 3627932974: return &emojis[654]; + case 3627932975: return &emojis[655]; + case 3627932976: return &emojis[656]; + case 3627932977: return &emojis[657]; + case 3627932978: return &emojis[658]; + case 3627932979: return &emojis[659]; + case 3627932980: return &emojis[660]; + case 3627932981: return &emojis[661]; + case 3627932982: return &emojis[662]; + case 3627932983: return &emojis[663]; + case 3627932984: return &emojis[664]; + case 3627932985: return &emojis[665]; + case 3627932986: return &emojis[666]; + case 3627932987: return &emojis[667]; + case 3627932988: return &emojis[668]; + case 3627932989: return &emojis[669]; + case 3627933008: return &emojis[670]; + case 3627933009: return &emojis[671]; + case 3627933010: return &emojis[672]; + case 3627933011: return &emojis[673]; + case 3627933012: return &emojis[674]; + case 3627933013: return &emojis[675]; + case 3627933014: return &emojis[676]; + case 3627933015: return &emojis[677]; + case 3627933016: return &emojis[678]; + case 3627933017: return &emojis[679]; + case 3627933018: return &emojis[680]; + case 3627933019: return &emojis[681]; + case 3627933020: return &emojis[682]; + case 3627933021: return &emojis[683]; + case 3627933022: return &emojis[684]; + case 3627933023: return &emojis[685]; + case 3627933024: return &emojis[686]; + case 3627933025: return &emojis[687]; + case 3627933026: return &emojis[688]; + case 3627933027: return &emojis[689]; + case 3627933028: return &emojis[690]; + case 3627933029: return &emojis[691]; + case 3627933030: return &emojis[692]; + case 3627933031: return &emojis[693]; + case 3627933179: return &emojis[694]; + case 3627933180: return &emojis[695]; + case 3627933181: return &emojis[696]; + case 3627933182: return &emojis[697]; + case 3627933183: return &emojis[698]; + case 3627933184: return &emojis[699]; + case 3627933185: return &emojis[700]; + case 3627933186: return &emojis[701]; + case 3627933187: return &emojis[702]; + case 3627933188: return &emojis[703]; + case 3627933189: return &emojis[704]; + case 3627933190: return &emojis[705]; + case 3627933191: return &emojis[706]; + case 3627933192: return &emojis[707]; + case 3627933193: return &emojis[708]; + case 3627933194: return &emojis[709]; + case 3627933195: return &emojis[710]; + case 3627933196: return &emojis[711]; + case 3627933197: return &emojis[712]; + case 3627933198: return &emojis[713]; + case 3627933199: return &emojis[714]; + case 3627933200: return &emojis[715]; + case 3627933201: return &emojis[716]; + case 3627933202: return &emojis[717]; + case 3627933203: return &emojis[718]; + case 3627933204: return &emojis[719]; + case 3627933205: return &emojis[720]; + case 3627933206: return &emojis[721]; + case 3627933207: return &emojis[722]; + case 3627933208: return &emojis[723]; + case 3627933209: return &emojis[724]; + case 3627933210: return &emojis[725]; + case 3627933211: return &emojis[726]; + case 3627933212: return &emojis[727]; + case 3627933213: return &emojis[728]; + case 3627933214: return &emojis[729]; + case 3627933215: return &emojis[730]; + case 3627933216: return &emojis[731]; + case 3627933217: return &emojis[732]; + case 3627933218: return &emojis[733]; + case 3627933219: return &emojis[734]; + case 3627933220: return &emojis[735]; + case 3627933221: return &emojis[736]; + case 3627933222: return &emojis[737]; + case 3627933223: return &emojis[738]; + case 3627933224: return &emojis[739]; + case 3627933225: return &emojis[740]; + case 3627933226: return &emojis[741]; + case 3627933227: return &emojis[742]; + case 3627933228: return &emojis[743]; + case 3627933229: return &emojis[744]; + case 3627933230: return &emojis[745]; + case 3627933231: return &emojis[746]; + case 3627933232: return &emojis[747]; + case 3627933233: return &emojis[748]; + case 3627933234: return &emojis[749]; + case 3627933235: return &emojis[750]; + case 3627933236: return &emojis[751]; + case 3627933237: return &emojis[752]; + case 3627933238: return &emojis[753]; + case 3627933239: return &emojis[754]; + case 3627933240: return &emojis[755]; + case 3627933241: return &emojis[756]; + case 3627933242: return &emojis[757]; + case 3627933243: return &emojis[758]; + case 3627933244: return &emojis[759]; + case 3627933245: return &emojis[760]; + case 3627933246: return &emojis[761]; + case 3627933247: return &emojis[762]; + case 3627933248: return &emojis[763]; + case 3627933253: return &emojis[764]; + case 3627933254: return &emojis[765]; + case 3627933255: return &emojis[766]; + case 3627933256: return &emojis[767]; + case 3627933257: return &emojis[768]; + case 3627933258: return &emojis[769]; + case 3627933259: return &emojis[770]; + case 3627933260: return &emojis[771]; + case 3627933261: return &emojis[772]; + case 3627933262: return &emojis[773]; + case 3627933263: return &emojis[774]; + case 3627933312: return &emojis[775]; + case 3627933313: return &emojis[776]; + case 3627933314: return &emojis[777]; + case 3627933315: return &emojis[778]; + case 3627933316: return &emojis[779]; + case 3627933317: return &emojis[780]; + case 3627933318: return &emojis[781]; + case 3627933319: return &emojis[782]; + case 3627933320: return &emojis[783]; + case 3627933321: return &emojis[784]; + case 3627933322: return &emojis[785]; + case 3627933323: return &emojis[786]; + case 3627933324: return &emojis[787]; + case 3627933325: return &emojis[788]; + case 3627933326: return &emojis[789]; + case 3627933327: return &emojis[790]; + case 3627933328: return &emojis[791]; + case 3627933329: return &emojis[792]; + case 3627933330: return &emojis[793]; + case 3627933331: return &emojis[794]; + case 3627933332: return &emojis[795]; + case 3627933333: return &emojis[796]; + case 3627933334: return &emojis[797]; + case 3627933335: return &emojis[798]; + case 3627933336: return &emojis[799]; + case 3627933337: return &emojis[800]; + case 3627933338: return &emojis[801]; + case 3627933339: return &emojis[802]; + case 3627933340: return &emojis[803]; + case 3627933341: return &emojis[804]; + case 3627933342: return &emojis[805]; + case 3627933343: return &emojis[806]; + case 3627933344: return &emojis[807]; + case 3627933345: return &emojis[808]; + case 3627933346: return &emojis[809]; + case 3627933347: return &emojis[810]; + case 3627933348: return &emojis[811]; + case 3627933349: return &emojis[812]; + case 3627933350: return &emojis[813]; + case 3627933351: return &emojis[814]; + case 3627933352: return &emojis[815]; + case 3627933353: return &emojis[816]; + case 3627933354: return &emojis[817]; + case 3627933355: return &emojis[818]; + case 3627933356: return &emojis[819]; + case 3627933357: return &emojis[820]; + case 3627933358: return &emojis[821]; + case 3627933359: return &emojis[822]; + case 3627933360: return &emojis[823]; + case 3627933361: return &emojis[824]; + case 3627933362: return &emojis[825]; + case 3627933363: return &emojis[826]; + case 3627933364: return &emojis[827]; + case 3627933365: return &emojis[828]; + case 3627933366: return &emojis[829]; + case 3627933367: return &emojis[830]; + case 3627933368: return &emojis[831]; + case 3627933369: return &emojis[832]; + case 3627933370: return &emojis[833]; + case 3627933371: return &emojis[834]; + case 3627933372: return &emojis[835]; + case 3627933373: return &emojis[836]; + case 3627933374: return &emojis[837]; + case 3627933375: return &emojis[838]; + case 3627933376: return &emojis[839]; + case 3627933377: return &emojis[840]; + case 3627933378: return &emojis[841]; + case 3627933379: return &emojis[842]; + case 3627933380: return &emojis[843]; + case 3627933381: return &emojis[844]; + } + + return 0; +} + +void findEmoji(const QChar *ch, const QChar *e, const QChar *&newEmojiEnd, uint32 &emojiCode) { + switch (ch->unicode()) { + case '}': + if (ch + 1 != e) switch ((ch + 1)->unicode()) { + case ':': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case ')': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933192; + return; + } + break; + } + break; + } + break; + case 'x': + if (ch + 1 != e) switch ((ch + 1)->unicode()) { + case 'D': + newEmojiEnd = ch + 2; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933190; + return; + } + break; + } + break; + case 'O': + if (ch + 1 != e) switch ((ch + 1)->unicode()) { + case ':': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case ')': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933191; + return; + } + break; + } + break; + } + break; + case 'B': + if (ch + 1 != e) switch ((ch + 1)->unicode()) { + case '-': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case ')': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933198; + return; + } + break; + } + break; + } + break; + case '>': + if (ch + 1 != e) switch ((ch + 1)->unicode()) { + case '(': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case '(': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933217; + return; + } + break; + } + newEmojiEnd = ch + 2; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933216; + return; + } + break; + } + break; + case '<': + if (ch + 1 != e) switch ((ch + 1)->unicode()) { + case '3': + newEmojiEnd = ch + 2; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 10084; + return; + } + break; + } + break; + case ';': + if (ch + 1 != e) switch ((ch + 1)->unicode()) { + case 'o': + newEmojiEnd = ch + 2; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933232; + return; + } + break; + case '-': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case 'P': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933212; + return; + } + break; + case ')': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933193; + return; + } + break; + } + break; + } + break; + case ':': + if (ch + 1 != e) switch ((ch + 1)->unicode()) { + case '|': + newEmojiEnd = ch + 2; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933200; + return; + } + break; + case 'v': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case ':': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 9996; + return; + } + break; + } + break; + case 'u': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case 'p': + if (ch + 3 != e) switch ((ch + 3)->unicode()) { + case ':': + newEmojiEnd = ch + 4; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 9757; + return; + } + break; + } + break; + } + break; + case 'o': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case 'k': + if (ch + 3 != e) switch ((ch + 3)->unicode()) { + case ':': + newEmojiEnd = ch + 4; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627932748; + return; + } + break; + } + break; + } + newEmojiEnd = ch + 2; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933224; + return; + } + break; + case 'l': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case 'i': + if (ch + 3 != e) switch ((ch + 3)->unicode()) { + case 'k': + if (ch + 4 != e) switch ((ch + 4)->unicode()) { + case 'e': + if (ch + 5 != e) switch ((ch + 5)->unicode()) { + case ':': + newEmojiEnd = ch + 6; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627932749; + return; + } + break; + } + break; + } + break; + } + break; + } + break; + case 'd': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case 'i': + if (ch + 3 != e) switch ((ch + 3)->unicode()) { + case 's': + if (ch + 4 != e) switch ((ch + 4)->unicode()) { + case 'l': + if (ch + 5 != e) switch ((ch + 5)->unicode()) { + case 'i': + if (ch + 6 != e) switch ((ch + 6)->unicode()) { + case 'k': + if (ch + 7 != e) switch ((ch + 7)->unicode()) { + case 'e': + if (ch + 8 != e) switch ((ch + 8)->unicode()) { + case ':': + newEmojiEnd = ch + 9; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627932750; + return; + } + break; + } + break; + } + break; + } + break; + } + break; + } + break; + } + break; + } + break; + case '_': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case '(': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933229; + return; + } + break; + } + break; + case ']': + newEmojiEnd = ch + 2; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933199; + return; + } + break; + case 'X': + newEmojiEnd = ch + 2; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933239; + return; + } + break; + case '-': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case 'p': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933195; + return; + } + break; + case 'D': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933187; + return; + } + break; + case '*': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933210; + return; + } + break; + case ')': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933194; + return; + } + break; + case '(': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933202; + return; + } + break; + } + break; + case '(': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case '(': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933225; + return; + } + break; + } + break; + case '\'': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case '(': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933218; + return; + } + break; + } + break; + } + break; + case '8': + if (ch + 1 != e) switch ((ch + 1)->unicode()) { + case '|': + newEmojiEnd = ch + 2; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933235; + return; + } + break; + case 'o': + newEmojiEnd = ch + 2; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933234; + return; + } + break; + case '-': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case ')': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933197; + return; + } + break; + } + break; + } + break; + case '3': + if (ch + 1 != e) switch ((ch + 1)->unicode()) { + case '-': + if (ch + 2 != e) switch ((ch + 2)->unicode()) { + case ')': + newEmojiEnd = ch + 3; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933196; + return; + } + break; + } + break; + case '(': + newEmojiEnd = ch + 2; + if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { + emojiCode = 3627933204; + return; + } + break; + } + break; + } +} + +EmojiPack emojiPack(DBIEmojiTab tab) { + switch (tab) { + + case dbietPeople: { + static QVector vPeople; + if (vPeople.isEmpty()) { + vPeople.resize(189); + vPeople[0] = &emojis[703]; + vPeople[1] = &emojis[702]; + vPeople[2] = &emojis[699]; + vPeople[3] = &emojis[709]; + vPeople[4] = &emojis[38]; + vPeople[5] = &emojis[708]; + vPeople[6] = &emojis[712]; + vPeople[7] = &emojis[723]; + vPeople[8] = &emojis[725]; + vPeople[9] = &emojis[722]; + vPeople[10] = &emojis[724]; + vPeople[11] = &emojis[727]; + vPeople[12] = &emojis[728]; + vPeople[13] = &emojis[726]; + vPeople[14] = &emojis[750]; + vPeople[15] = &emojis[700]; + vPeople[16] = &emojis[719]; + vPeople[17] = &emojis[711]; + vPeople[18] = &emojis[717]; + vPeople[19] = &emojis[729]; + vPeople[20] = &emojis[734]; + vPeople[21] = &emojis[733]; + vPeople[22] = &emojis[701]; + vPeople[23] = &emojis[744]; + vPeople[24] = &emojis[741]; + vPeople[25] = &emojis[736]; + vPeople[26] = &emojis[747]; + vPeople[27] = &emojis[704]; + vPeople[28] = &emojis[718]; + vPeople[29] = &emojis[740]; + vPeople[30] = &emojis[742]; + vPeople[31] = &emojis[739]; + vPeople[32] = &emojis[748]; + vPeople[33] = &emojis[731]; + vPeople[34] = &emojis[732]; + vPeople[35] = &emojis[735]; + vPeople[36] = &emojis[721]; + vPeople[37] = &emojis[705]; + vPeople[38] = &emojis[710]; + vPeople[39] = &emojis[754]; + vPeople[40] = &emojis[713]; + vPeople[41] = &emojis[751]; + vPeople[42] = &emojis[752]; + vPeople[43] = &emojis[749]; + vPeople[44] = &emojis[730]; + vPeople[45] = &emojis[737]; + vPeople[46] = &emojis[738]; + vPeople[47] = &emojis[707]; + vPeople[48] = &emojis[483]; + vPeople[49] = &emojis[745]; + vPeople[50] = &emojis[743]; + vPeople[51] = &emojis[715]; + vPeople[52] = &emojis[720]; + vPeople[53] = &emojis[746]; + vPeople[54] = &emojis[753]; + vPeople[55] = &emojis[706]; + vPeople[56] = &emojis[714]; + vPeople[57] = &emojis[716]; + vPeople[58] = &emojis[470]; + vPeople[59] = &emojis[471]; + vPeople[60] = &emojis[466]; + vPeople[61] = &emojis[475]; + vPeople[62] = &emojis[486]; + vPeople[63] = &emojis[474]; + vPeople[64] = &emojis[458]; + vPeople[65] = &emojis[459]; + vPeople[66] = &emojis[460]; + vPeople[67] = &emojis[461]; + vPeople[68] = &emojis[472]; + vPeople[69] = &emojis[473]; + vPeople[70] = &emojis[469]; + vPeople[71] = &emojis[480]; + vPeople[72] = &emojis[476]; + vPeople[73] = &emojis[757]; + vPeople[74] = &emojis[755]; + vPeople[75] = &emojis[758]; + vPeople[76] = &emojis[760]; + vPeople[77] = &emojis[759]; + vPeople[78] = &emojis[763]; + vPeople[79] = &emojis[762]; + vPeople[80] = &emojis[756]; + vPeople[81] = &emojis[761]; + vPeople[82] = &emojis[477]; + vPeople[83] = &emojis[478]; + vPeople[84] = &emojis[767]; + vPeople[85] = &emojis[768]; + vPeople[86] = &emojis[769]; + vPeople[87] = &emojis[484]; + vPeople[88] = &emojis[481]; + vPeople[89] = &emojis[525]; + vPeople[90] = &emojis[645]; + vPeople[91] = &emojis[86]; + vPeople[92] = &emojis[201]; + vPeople[93] = &emojis[527]; + vPeople[94] = &emojis[521]; + vPeople[95] = &emojis[518]; + vPeople[96] = &emojis[522]; + vPeople[97] = &emojis[523]; + vPeople[98] = &emojis[520]; + vPeople[99] = &emojis[524]; + vPeople[100] = &emojis[422]; + vPeople[101] = &emojis[421]; + vPeople[102] = &emojis[423]; + vPeople[103] = &emojis[425]; + vPeople[104] = &emojis[424]; + vPeople[105] = &emojis[433]; + vPeople[106] = &emojis[434]; + vPeople[107] = &emojis[432]; + vPeople[108] = &emojis[430]; + vPeople[109] = &emojis[79]; + vPeople[110] = &emojis[81]; + vPeople[111] = &emojis[431]; + vPeople[112] = &emojis[80]; + vPeople[113] = &emojis[436]; + vPeople[114] = &emojis[426]; + vPeople[115] = &emojis[427]; + vPeople[116] = &emojis[429]; + vPeople[117] = &emojis[428]; + vPeople[118] = &emojis[771]; + vPeople[119] = &emojis[774]; + vPeople[120] = &emojis[37]; + vPeople[121] = &emojis[435]; + vPeople[122] = &emojis[526]; + vPeople[123] = &emojis[829]; + vPeople[124] = &emojis[334]; + vPeople[125] = &emojis[487]; + vPeople[126] = &emojis[463]; + vPeople[127] = &emojis[462]; + vPeople[128] = &emojis[464]; + vPeople[129] = &emojis[465]; + vPeople[130] = &emojis[499]; + vPeople[131] = &emojis[501]; + vPeople[132] = &emojis[467]; + vPeople[133] = &emojis[765]; + vPeople[134] = &emojis[764]; + vPeople[135] = &emojis[485]; + vPeople[136] = &emojis[770]; + vPeople[137] = &emojis[490]; + vPeople[138] = &emojis[491]; + vPeople[139] = &emojis[489]; + vPeople[140] = &emojis[468]; + vPeople[141] = &emojis[773]; + vPeople[142] = &emojis[772]; + vPeople[143] = &emojis[766]; + vPeople[144] = &emojis[308]; + vPeople[145] = &emojis[437]; + vPeople[146] = &emojis[438]; + vPeople[147] = &emojis[451]; + vPeople[148] = &emojis[450]; + vPeople[149] = &emojis[453]; + vPeople[150] = &emojis[452]; + vPeople[151] = &emojis[454]; + vPeople[152] = &emojis[441]; + vPeople[153] = &emojis[440]; + vPeople[154] = &emojis[446]; + vPeople[155] = &emojis[443]; + vPeople[156] = &emojis[328]; + vPeople[157] = &emojis[442]; + vPeople[158] = &emojis[444]; + vPeople[159] = &emojis[445]; + vPeople[160] = &emojis[544]; + vPeople[161] = &emojis[448]; + vPeople[162] = &emojis[449]; + vPeople[163] = &emojis[447]; + vPeople[164] = &emojis[439]; + vPeople[165] = &emojis[279]; + vPeople[166] = &emojis[172]; + vPeople[167] = &emojis[488]; + vPeople[168] = &emojis[511]; + vPeople[169] = &emojis[509]; + vPeople[170] = &emojis[512]; + vPeople[171] = &emojis[510]; + vPeople[172] = &emojis[97]; + vPeople[173] = &emojis[504]; + vPeople[174] = &emojis[507]; + vPeople[175] = &emojis[503]; + vPeople[176] = &emojis[505]; + vPeople[177] = &emojis[506]; + vPeople[178] = &emojis[514]; + vPeople[179] = &emojis[508]; + vPeople[180] = &emojis[496]; + vPeople[181] = &emojis[495]; + vPeople[182] = &emojis[497]; + vPeople[183] = &emojis[498]; + vPeople[184] = &emojis[456]; + vPeople[185] = &emojis[457]; + vPeople[186] = &emojis[528]; + vPeople[187] = &emojis[455]; + vPeople[188] = &emojis[529]; + } + return vPeople; + } break; + + case dbietNature: { + static QVector vNature; + if (vNature.isEmpty()) { + vNature.resize(116); + vNature[0] = &emojis[412]; + vNature[1] = &emojis[416]; + vNature[2] = &emojis[407]; + vNature[3] = &emojis[403]; + vNature[4] = &emojis[415]; + vNature[5] = &emojis[406]; + vNature[6] = &emojis[414]; + vNature[7] = &emojis[405]; + vNature[8] = &emojis[398]; + vNature[9] = &emojis[417]; + vNature[10] = &emojis[413]; + vNature[11] = &emojis[419]; + vNature[12] = &emojis[404]; + vNature[13] = &emojis[381]; + vNature[14] = &emojis[411]; + vNature[15] = &emojis[376]; + vNature[16] = &emojis[410]; + vNature[17] = &emojis[375]; + vNature[18] = &emojis[382]; + vNature[19] = &emojis[418]; + vNature[20] = &emojis[397]; + vNature[21] = &emojis[396]; + vNature[22] = &emojis[394]; + vNature[23] = &emojis[395]; + vNature[24] = &emojis[393]; + vNature[25] = &emojis[378]; + vNature[26] = &emojis[371]; + vNature[27] = &emojis[392]; + vNature[28] = &emojis[385]; + vNature[29] = &emojis[387]; + vNature[30] = &emojis[386]; + vNature[31] = &emojis[388]; + vNature[32] = &emojis[370]; + vNature[33] = &emojis[383]; + vNature[34] = &emojis[384]; + vNature[35] = &emojis[390]; + vNature[36] = &emojis[389]; + vNature[37] = &emojis[402]; + vNature[38] = &emojis[409]; + vNature[39] = &emojis[369]; + vNature[40] = &emojis[362]; + vNature[41] = &emojis[373]; + vNature[42] = &emojis[358]; + vNature[43] = &emojis[361]; + vNature[44] = &emojis[363]; + vNature[45] = &emojis[365]; + vNature[46] = &emojis[367]; + vNature[47] = &emojis[372]; + vNature[48] = &emojis[374]; + vNature[49] = &emojis[377]; + vNature[50] = &emojis[379]; + vNature[51] = &emojis[380]; + vNature[52] = &emojis[359]; + vNature[53] = &emojis[360]; + vNature[54] = &emojis[408]; + vNature[55] = &emojis[391]; + vNature[56] = &emojis[368]; + vNature[57] = &emojis[401]; + vNature[58] = &emojis[400]; + vNature[59] = &emojis[364]; + vNature[60] = &emojis[366]; + vNature[61] = &emojis[399]; + vNature[62] = &emojis[420]; + vNature[63] = &emojis[500]; + vNature[64] = &emojis[210]; + vNature[65] = &emojis[209]; + vNature[66] = &emojis[218]; + vNature[67] = &emojis[211]; + vNature[68] = &emojis[213]; + vNature[69] = &emojis[212]; + vNature[70] = &emojis[219]; + vNature[71] = &emojis[221]; + vNature[72] = &emojis[220]; + vNature[73] = &emojis[217]; + vNature[74] = &emojis[216]; + vNature[75] = &emojis[222]; + vNature[76] = &emojis[208]; + vNature[77] = &emojis[207]; + vNature[78] = &emojis[205]; + vNature[79] = &emojis[206]; + vNature[80] = &emojis[203]; + vNature[81] = &emojis[204]; + vNature[82] = &emojis[214]; + vNature[83] = &emojis[186]; + vNature[84] = &emojis[200]; + vNature[85] = &emojis[199]; + vNature[86] = &emojis[196]; + vNature[87] = &emojis[187]; + vNature[88] = &emojis[188]; + vNature[89] = &emojis[189]; + vNature[90] = &emojis[190]; + vNature[91] = &emojis[191]; + vNature[92] = &emojis[192]; + vNature[93] = &emojis[193]; + vNature[94] = &emojis[194]; + vNature[95] = &emojis[198]; + vNature[96] = &emojis[197]; + vNature[97] = &emojis[195]; + vNature[98] = &emojis[183]; + vNature[99] = &emojis[184]; + vNature[100] = &emojis[185]; + vNature[101] = &emojis[181]; + vNature[102] = &emojis[182]; + vNature[103] = &emojis[183]; + vNature[104] = &emojis[111]; + vNature[105] = &emojis[31]; + vNature[106] = &emojis[66]; + vNature[107] = &emojis[32]; + vNature[108] = &emojis[60]; + vNature[109] = &emojis[35]; + vNature[110] = &emojis[89]; + vNature[111] = &emojis[65]; + vNature[112] = &emojis[170]; + vNature[113] = &emojis[171]; + vNature[114] = &emojis[178]; + vNature[115] = &emojis[180]; + } + return vNature; + } break; + + case dbietObjects: { + static QVector vObjects; + if (vObjects.isEmpty()) { + vObjects.resize(229); + vObjects[0] = &emojis[292]; + vObjects[1] = &emojis[513]; + vObjects[2] = &emojis[293]; + vObjects[3] = &emojis[297]; + vObjects[4] = &emojis[298]; + vObjects[5] = &emojis[294]; + vObjects[6] = &emojis[285]; + vObjects[7] = &emojis[286]; + vObjects[8] = &emojis[295]; + vObjects[9] = &emojis[296]; + vObjects[10] = &emojis[282]; + vObjects[11] = &emojis[479]; + vObjects[12] = &emojis[284]; + vObjects[13] = &emojis[283]; + vObjects[14] = &emojis[280]; + vObjects[15] = &emojis[290]; + vObjects[16] = &emojis[288]; + vObjects[17] = &emojis[289]; + vObjects[18] = &emojis[287]; + vObjects[19] = &emojis[291]; + vObjects[20] = &emojis[654]; + vObjects[21] = &emojis[304]; + vObjects[22] = &emojis[603]; + vObjects[23] = &emojis[604]; + vObjects[24] = &emojis[607]; + vObjects[25] = &emojis[547]; + vObjects[26] = &emojis[548]; + vObjects[27] = &emojis[545]; + vObjects[28] = &emojis[546]; + vObjects[29] = &emojis[543]; + vObjects[30] = &emojis[597]; + vObjects[31] = &emojis[33]; + vObjects[32] = &emojis[578]; + vObjects[33] = &emojis[579]; + vObjects[34] = &emojis[580]; + vObjects[35] = &emojis[581]; + vObjects[36] = &emojis[605]; + vObjects[37] = &emojis[606]; + vObjects[38] = &emojis[618]; + vObjects[39] = &emojis[617]; + vObjects[40] = &emojis[617]; + vObjects[41] = &emojis[615]; + vObjects[42] = &emojis[628]; + vObjects[43] = &emojis[628]; + vObjects[44] = &emojis[582]; + vObjects[45] = &emojis[583]; + vObjects[46] = &emojis[21]; + vObjects[47] = &emojis[15]; + vObjects[48] = &emojis[20]; + vObjects[49] = &emojis[14]; + vObjects[50] = &emojis[627]; + vObjects[51] = &emojis[626]; + vObjects[52] = &emojis[623]; + vObjects[53] = &emojis[624]; + vObjects[54] = &emojis[625]; + vObjects[55] = &emojis[622]; + vObjects[56] = &emojis[517]; + vObjects[57] = &emojis[646]; + vObjects[58] = &emojis[614]; + vObjects[59] = &emojis[613]; + vObjects[60] = &emojis[620]; + vObjects[61] = &emojis[619]; + vObjects[62] = &emojis[621]; + vObjects[63] = &emojis[839]; + vObjects[64] = &emojis[838]; + vObjects[65] = &emojis[836]; + vObjects[66] = &emojis[647]; + vObjects[67] = &emojis[649]; + vObjects[68] = &emojis[648]; + vObjects[69] = &emojis[817]; + vObjects[70] = &emojis[819]; + vObjects[71] = &emojis[519]; + vObjects[72] = &emojis[651]; + vObjects[73] = &emojis[650]; + vObjects[74] = &emojis[494]; + vObjects[75] = &emojis[493]; + vObjects[76] = &emojis[532]; + vObjects[77] = &emojis[536]; + vObjects[78] = &emojis[537]; + vObjects[79] = &emojis[539]; + vObjects[80] = &emojis[538]; + vObjects[81] = &emojis[535]; + vObjects[82] = &emojis[540]; + vObjects[83] = &emojis[598]; + vObjects[84] = &emojis[587]; + vObjects[85] = &emojis[585]; + vObjects[86] = &emojis[584]; + vObjects[87] = &emojis[78]; + vObjects[88] = &emojis[589]; + vObjects[89] = &emojis[588]; + vObjects[90] = &emojis[595]; + vObjects[91] = &emojis[591]; + vObjects[92] = &emojis[590]; + vObjects[93] = &emojis[592]; + vObjects[94] = &emojis[593]; + vObjects[95] = &emojis[594]; + vObjects[96] = &emojis[586]; + vObjects[97] = &emojis[577]; + vObjects[98] = &emojis[552]; + vObjects[99] = &emojis[551]; + vObjects[100] = &emojis[565]; + vObjects[101] = &emojis[558]; + vObjects[102] = &emojis[556]; + vObjects[103] = &emojis[557]; + vObjects[104] = &emojis[576]; + vObjects[105] = &emojis[559]; + vObjects[106] = &emojis[553]; + vObjects[107] = &emojis[554]; + vObjects[108] = &emojis[555]; + vObjects[109] = &emojis[549]; + vObjects[110] = &emojis[550]; + vObjects[111] = &emojis[75]; + vObjects[112] = &emojis[560]; + vObjects[113] = &emojis[562]; + vObjects[114] = &emojis[83]; + vObjects[115] = &emojis[82]; + vObjects[116] = &emojis[563]; + vObjects[117] = &emojis[564]; + vObjects[118] = &emojis[569]; + vObjects[119] = &emojis[571]; + vObjects[120] = &emojis[572]; + vObjects[121] = &emojis[573]; + vObjects[122] = &emojis[567]; + vObjects[123] = &emojis[568]; + vObjects[124] = &emojis[566]; + vObjects[125] = &emojis[574]; + vObjects[126] = &emojis[570]; + vObjects[127] = &emojis[630]; + vObjects[128] = &emojis[575]; + vObjects[129] = &emojis[652]; + vObjects[130] = &emojis[653]; + vObjects[131] = &emojis[596]; + vObjects[132] = &emojis[307]; + vObjects[133] = &emojis[311]; + vObjects[134] = &emojis[303]; + vObjects[135] = &emojis[306]; + vObjects[136] = &emojis[327]; + vObjects[137] = &emojis[320]; + vObjects[138] = &emojis[321]; + vObjects[139] = &emojis[324]; + vObjects[140] = &emojis[326]; + vObjects[141] = &emojis[325]; + vObjects[142] = &emojis[322]; + vObjects[143] = &emojis[323]; + vObjects[144] = &emojis[482]; + vObjects[145] = &emojis[313]; + vObjects[146] = &emojis[129]; + vObjects[147] = &emojis[319]; + vObjects[148] = &emojis[128]; + vObjects[149] = &emojis[317]; + vObjects[150] = &emojis[314]; + vObjects[151] = &emojis[338]; + vObjects[152] = &emojis[331]; + vObjects[153] = &emojis[63]; + vObjects[154] = &emojis[64]; + vObjects[155] = &emojis[329]; + vObjects[156] = &emojis[316]; + vObjects[157] = &emojis[339]; + vObjects[158] = &emojis[318]; + vObjects[159] = &emojis[71]; + vObjects[160] = &emojis[828]; + vObjects[161] = &emojis[827]; + vObjects[162] = &emojis[332]; + vObjects[163] = &emojis[337]; + vObjects[164] = &emojis[336]; + vObjects[165] = &emojis[330]; + vObjects[166] = &emojis[333]; + vObjects[167] = &emojis[340]; + vObjects[168] = &emojis[335]; + vObjects[169] = &emojis[302]; + vObjects[170] = &emojis[36]; + vObjects[171] = &emojis[271]; + vObjects[172] = &emojis[272]; + vObjects[173] = &emojis[278]; + vObjects[174] = &emojis[276]; + vObjects[175] = &emojis[277]; + vObjects[176] = &emojis[274]; + vObjects[177] = &emojis[275]; + vObjects[178] = &emojis[273]; + vObjects[179] = &emojis[270]; + vObjects[180] = &emojis[239]; + vObjects[181] = &emojis[238]; + vObjects[182] = &emojis[249]; + vObjects[183] = &emojis[241]; + vObjects[184] = &emojis[240]; + vObjects[185] = &emojis[247]; + vObjects[186] = &emojis[245]; + vObjects[187] = &emojis[254]; + vObjects[188] = &emojis[267]; + vObjects[189] = &emojis[253]; + vObjects[190] = &emojis[255]; + vObjects[191] = &emojis[243]; + vObjects[192] = &emojis[242]; + vObjects[193] = &emojis[244]; + vObjects[194] = &emojis[246]; + vObjects[195] = &emojis[268]; + vObjects[196] = &emojis[252]; + vObjects[197] = &emojis[251]; + vObjects[198] = &emojis[269]; + vObjects[199] = &emojis[248]; + vObjects[200] = &emojis[259]; + vObjects[201] = &emojis[264]; + vObjects[202] = &emojis[256]; + vObjects[203] = &emojis[258]; + vObjects[204] = &emojis[257]; + vObjects[205] = &emojis[281]; + vObjects[206] = &emojis[266]; + vObjects[207] = &emojis[260]; + vObjects[208] = &emojis[261]; + vObjects[209] = &emojis[262]; + vObjects[210] = &emojis[263]; + vObjects[211] = &emojis[265]; + vObjects[212] = &emojis[232]; + vObjects[213] = &emojis[233]; + vObjects[214] = &emojis[228]; + vObjects[215] = &emojis[229]; + vObjects[216] = &emojis[236]; + vObjects[217] = &emojis[225]; + vObjects[218] = &emojis[227]; + vObjects[219] = &emojis[237]; + vObjects[220] = &emojis[235]; + vObjects[221] = &emojis[226]; + vObjects[222] = &emojis[230]; + vObjects[223] = &emojis[234]; + vObjects[224] = &emojis[231]; + vObjects[225] = &emojis[250]; + vObjects[226] = &emojis[224]; + vObjects[227] = &emojis[223]; + vObjects[228] = &emojis[215]; + } + return vObjects; + } break; + + case dbietPlaces: { + static QVector vPlaces; + if (vPlaces.isEmpty()) { + vPlaces.resize(101); + vPlaces[0] = &emojis[341]; + vPlaces[1] = &emojis[342]; + vPlaces[2] = &emojis[352]; + vPlaces[3] = &emojis[343]; + vPlaces[4] = &emojis[344]; + vPlaces[5] = &emojis[346]; + vPlaces[6] = &emojis[347]; + vPlaces[7] = &emojis[351]; + vPlaces[8] = &emojis[350]; + vPlaces[9] = &emojis[349]; + vPlaces[10] = &emojis[502]; + vPlaces[11] = &emojis[69]; + vPlaces[12] = &emojis[353]; + vPlaces[13] = &emojis[345]; + vPlaces[14] = &emojis[177]; + vPlaces[15] = &emojis[176]; + vPlaces[16] = &emojis[356]; + vPlaces[17] = &emojis[357]; + vPlaces[18] = &emojis[73]; + vPlaces[19] = &emojis[354]; + vPlaces[20] = &emojis[695]; + vPlaces[21] = &emojis[697]; + vPlaces[22] = &emojis[694]; + vPlaces[23] = &emojis[174]; + vPlaces[24] = &emojis[175]; + vPlaces[25] = &emojis[173]; + vPlaces[26] = &emojis[696]; + vPlaces[27] = &emojis[179]; + vPlaces[28] = &emojis[299]; + vPlaces[29] = &emojis[300]; + vPlaces[30] = &emojis[70]; + vPlaces[31] = &emojis[301]; + vPlaces[32] = &emojis[809]; + vPlaces[33] = &emojis[72]; + vPlaces[34] = &emojis[811]; + vPlaces[35] = &emojis[810]; + vPlaces[36] = &emojis[58]; + vPlaces[37] = &emojis[775]; + vPlaces[38] = &emojis[77]; + vPlaces[39] = &emojis[542]; + vPlaces[40] = &emojis[776]; + vPlaces[41] = &emojis[777]; + vPlaces[42] = &emojis[785]; + vPlaces[43] = &emojis[784]; + vPlaces[44] = &emojis[805]; + vPlaces[45] = &emojis[781]; + vPlaces[46] = &emojis[779]; + vPlaces[47] = &emojis[780]; + vPlaces[48] = &emojis[783]; + vPlaces[49] = &emojis[782]; + vPlaces[50] = &emojis[804]; + vPlaces[51] = &emojis[804]; + vPlaces[52] = &emojis[778]; + vPlaces[53] = &emojis[789]; + vPlaces[54] = &emojis[787]; + vPlaces[55] = &emojis[788]; + vPlaces[56] = &emojis[800]; + vPlaces[57] = &emojis[799]; + vPlaces[58] = &emojis[798]; + vPlaces[59] = &emojis[796]; + vPlaces[60] = &emojis[797]; + vPlaces[61] = &emojis[802]; + vPlaces[62] = &emojis[801]; + vPlaces[63] = &emojis[815]; + vPlaces[64] = &emojis[794]; + vPlaces[65] = &emojis[795]; + vPlaces[66] = &emojis[793]; + vPlaces[67] = &emojis[792]; + vPlaces[68] = &emojis[791]; + vPlaces[69] = &emojis[825]; + vPlaces[70] = &emojis[808]; + vPlaces[71] = &emojis[806]; + vPlaces[72] = &emojis[807]; + vPlaces[73] = &emojis[803]; + vPlaces[74] = &emojis[492]; + vPlaces[75] = &emojis[790]; + vPlaces[76] = &emojis[310]; + vPlaces[77] = &emojis[813]; + vPlaces[78] = &emojis[812]; + vPlaces[79] = &emojis[59]; + vPlaces[80] = &emojis[814]; + vPlaces[81] = &emojis[656]; + vPlaces[82] = &emojis[74]; + vPlaces[83] = &emojis[355]; + vPlaces[84] = &emojis[315]; + vPlaces[85] = &emojis[55]; + vPlaces[86] = &emojis[698]; + vPlaces[87] = &emojis[309]; + vPlaces[88] = &emojis[312]; + vPlaces[89] = &emojis[561]; + vPlaces[90] = &emojis[816]; + vPlaces[91] = &emojis[151]; + vPlaces[92] = &emojis[152]; + vPlaces[93] = &emojis[146]; + vPlaces[94] = &emojis[145]; + vPlaces[95] = &emojis[154]; + vPlaces[96] = &emojis[148]; + vPlaces[97] = &emojis[147]; + vPlaces[98] = &emojis[150]; + vPlaces[99] = &emojis[153]; + vPlaces[100] = &emojis[149]; + } + return vPlaces; + } break; + + case dbietSymbols: { + static QVector vSymbols; + if (vSymbols.isEmpty()) { + vSymbols.resize(204); + vSymbols[0] = &emojis[119]; + vSymbols[1] = &emojis[120]; + vSymbols[2] = &emojis[121]; + vSymbols[3] = &emojis[122]; + vSymbols[4] = &emojis[123]; + vSymbols[5] = &emojis[124]; + vSymbols[6] = &emojis[125]; + vSymbols[7] = &emojis[126]; + vSymbols[8] = &emojis[127]; + vSymbols[9] = &emojis[118]; + vSymbols[10] = &emojis[639]; + vSymbols[11] = &emojis[642]; + vSymbols[12] = &emojis[117]; + vSymbols[13] = &emojis[643]; + vSymbols[14] = &emojis[107]; + vSymbols[15] = &emojis[108]; + vSymbols[16] = &emojis[106]; + vSymbols[17] = &emojis[101]; + vSymbols[18] = &emojis[640]; + vSymbols[19] = &emojis[641]; + vSymbols[20] = &emojis[644]; + vSymbols[21] = &emojis[9]; + vSymbols[22] = &emojis[8]; + vSymbols[23] = &emojis[10]; + vSymbols[24] = &emojis[11]; + vSymbols[25] = &emojis[6]; + vSymbols[26] = &emojis[7]; + vSymbols[27] = &emojis[612]; + vSymbols[28] = &emojis[26]; + vSymbols[29] = &emojis[25]; + vSymbols[30] = &emojis[668]; + vSymbols[31] = &emojis[669]; + vSymbols[32] = &emojis[12]; + vSymbols[33] = &emojis[13]; + vSymbols[34] = &emojis[5]; + vSymbols[35] = &emojis[17]; + vSymbols[36] = &emojis[16]; + vSymbols[37] = &emojis[18]; + vSymbols[38] = &emojis[19]; + vSymbols[39] = &emojis[105]; + vSymbols[40] = &emojis[104]; + vSymbols[41] = &emojis[141]; + vSymbols[42] = &emojis[608]; + vSymbols[43] = &emojis[609]; + vSymbols[44] = &emojis[610]; + vSymbols[45] = &emojis[139]; + vSymbols[46] = &emojis[143]; + vSymbols[47] = &emojis[136]; + vSymbols[48] = &emojis[137]; + vSymbols[49] = &emojis[140]; + vSymbols[50] = &emojis[602]; + vSymbols[51] = &emojis[305]; + vSymbols[52] = &emojis[155]; + vSymbols[53] = &emojis[158]; + vSymbols[54] = &emojis[160]; + vSymbols[55] = &emojis[162]; + vSymbols[56] = &emojis[159]; + vSymbols[57] = &emojis[161]; + vSymbols[58] = &emojis[159]; + vSymbols[59] = &emojis[168]; + vSymbols[60] = &emojis[166]; + vSymbols[61] = &emojis[167]; + vSymbols[62] = &emojis[163]; + vSymbols[63] = &emojis[157]; + vSymbols[64] = &emojis[834]; + vSymbols[65] = &emojis[832]; + vSymbols[66] = &emojis[833]; + vSymbols[67] = &emojis[835]; + vSymbols[68] = &emojis[837]; + vSymbols[69] = &emojis[823]; + vSymbols[70] = &emojis[821]; + vSymbols[71] = &emojis[133]; + vSymbols[72] = &emojis[57]; + vSymbols[73] = &emojis[820]; + vSymbols[74] = &emojis[164]; + vSymbols[75] = &emojis[165]; + vSymbols[76] = &emojis[156]; + vSymbols[77] = &emojis[22]; + vSymbols[78] = &emojis[169]; + vSymbols[79] = &emojis[116]; + vSymbols[80] = &emojis[115]; + vSymbols[81] = &emojis[135]; + vSymbols[82] = &emojis[142]; + vSymbols[83] = &emojis[138]; + vSymbols[84] = &emojis[818]; + vSymbols[85] = &emojis[638]; + vSymbols[86] = &emojis[601]; + vSymbols[87] = &emojis[822]; + vSymbols[88] = &emojis[824]; + vSymbols[89] = &emojis[826]; + vSymbols[90] = &emojis[830]; + vSymbols[91] = &emojis[831]; + vSymbols[92] = &emojis[68]; + vSymbols[93] = &emojis[87]; + vSymbols[94] = &emojis[90]; + vSymbols[95] = &emojis[92]; + vSymbols[96] = &emojis[76]; + vSymbols[97] = &emojis[88]; + vSymbols[98] = &emojis[515]; + vSymbols[99] = &emojis[144]; + vSymbols[100] = &emojis[599]; + vSymbols[101] = &emojis[600]; + vSymbols[102] = &emojis[130]; + vSymbols[103] = &emojis[131]; + vSymbols[104] = &emojis[134]; + vSymbols[105] = &emojis[132]; + vSymbols[106] = &emojis[516]; + vSymbols[107] = &emojis[103]; + vSymbols[108] = &emojis[56]; + vSymbols[109] = &emojis[39]; + vSymbols[110] = &emojis[40]; + vSymbols[111] = &emojis[41]; + vSymbols[112] = &emojis[42]; + vSymbols[113] = &emojis[43]; + vSymbols[114] = &emojis[44]; + vSymbols[115] = &emojis[45]; + vSymbols[116] = &emojis[46]; + vSymbols[117] = &emojis[47]; + vSymbols[118] = &emojis[48]; + vSymbols[119] = &emojis[49]; + vSymbols[120] = &emojis[50]; + vSymbols[121] = &emojis[67]; + vSymbols[122] = &emojis[655]; + vSymbols[123] = &emojis[348]; + vSymbols[124] = &emojis[541]; + vSymbols[125] = &emojis[534]; + vSymbols[126] = &emojis[533]; + vSymbols[127] = &emojis[0]; + vSymbols[128] = &emojis[1]; + vSymbols[129] = &emojis[4]; + vSymbols[130] = &emojis[114]; + vSymbols[131] = &emojis[113]; + vSymbols[132] = &emojis[637]; + vSymbols[133] = &emojis[634]; + vSymbols[134] = &emojis[633]; + vSymbols[135] = &emojis[635]; + vSymbols[136] = &emojis[636]; + vSymbols[137] = &emojis[91]; + vSymbols[138] = &emojis[112]; + vSymbols[139] = &emojis[96]; + vSymbols[140] = &emojis[93]; + vSymbols[141] = &emojis[95]; + vSymbols[142] = &emojis[94]; + vSymbols[143] = &emojis[611]; + vSymbols[144] = &emojis[681]; + vSymbols[145] = &emojis[693]; + vSymbols[146] = &emojis[670]; + vSymbols[147] = &emojis[682]; + vSymbols[148] = &emojis[671]; + vSymbols[149] = &emojis[683]; + vSymbols[150] = &emojis[672]; + vSymbols[151] = &emojis[684]; + vSymbols[152] = &emojis[673]; + vSymbols[153] = &emojis[685]; + vSymbols[154] = &emojis[674]; + vSymbols[155] = &emojis[686]; + vSymbols[156] = &emojis[675]; + vSymbols[157] = &emojis[676]; + vSymbols[158] = &emojis[677]; + vSymbols[159] = &emojis[678]; + vSymbols[160] = &emojis[679]; + vSymbols[161] = &emojis[680]; + vSymbols[162] = &emojis[687]; + vSymbols[163] = &emojis[688]; + vSymbols[164] = &emojis[689]; + vSymbols[165] = &emojis[690]; + vSymbols[166] = &emojis[691]; + vSymbols[167] = &emojis[692]; + vSymbols[168] = &emojis[85]; + vSymbols[169] = &emojis[98]; + vSymbols[170] = &emojis[99]; + vSymbols[171] = &emojis[100]; + vSymbols[172] = &emojis[51]; + vSymbols[173] = &emojis[53]; + vSymbols[174] = &emojis[52]; + vSymbols[175] = &emojis[54]; + vSymbols[176] = &emojis[530]; + vSymbols[177] = &emojis[531]; + vSymbols[178] = &emojis[84]; + vSymbols[179] = &emojis[34]; + vSymbols[180] = &emojis[632]; + vSymbols[181] = &emojis[631]; + vSymbols[182] = &emojis[102]; + vSymbols[183] = &emojis[657]; + vSymbols[184] = &emojis[658]; + vSymbols[185] = &emojis[659]; + vSymbols[186] = &emojis[28]; + vSymbols[187] = &emojis[27]; + vSymbols[188] = &emojis[30]; + vSymbols[189] = &emojis[29]; + vSymbols[190] = &emojis[23]; + vSymbols[191] = &emojis[24]; + vSymbols[192] = &emojis[666]; + vSymbols[193] = &emojis[110]; + vSymbols[194] = &emojis[109]; + vSymbols[195] = &emojis[62]; + vSymbols[196] = &emojis[61]; + vSymbols[197] = &emojis[660]; + vSymbols[198] = &emojis[661]; + vSymbols[199] = &emojis[667]; + vSymbols[200] = &emojis[662]; + vSymbols[201] = &emojis[663]; + vSymbols[202] = &emojis[664]; + vSymbols[203] = &emojis[665]; + } + return vSymbols; + } break; + + }; + + EmojiPack result; + result.reserve(cGetRecentEmojis().size()); + for (RecentEmojiPack::const_iterator i = cGetRecentEmojis().cbegin(), e = cGetRecentEmojis().cend(); i != e; ++i) { + result.push_back(i->first); + } + return result;} + diff --git a/Telegram/SourceFiles/gui/emoji_config.h b/Telegram/SourceFiles/gui/emoji_config.h new file mode 100644 index 000000000..f8f1839c7 --- /dev/null +++ b/Telegram/SourceFiles/gui/emoji_config.h @@ -0,0 +1,82 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +void initEmoji(); +EmojiPtr getEmoji(uint32 code); + +void findEmoji(const QChar *ch, const QChar *e, const QChar *&newEmojiEnd, uint32 &emojiCode); + +inline bool emojiEdge(const QChar *ch) { + return true; + + switch (ch->unicode()) { + case '.': case ',': case ':': case ';': case '!': case '?': case '#': case '@': + case '(': case ')': case '[': case ']': case '{': case '}': case '<': case '>': + case '+': case '=': case '-': case '_': case '*': case '/': case '\\': case '^': case '$': + case '"': case '\'': + case 8212: case 171: case 187: // --, <<, >> + return true; + } + return false; +} + +inline QString replaceEmojis(const QString &text) { + QString result; + const QChar *emojiEnd = text.unicode(), *e = text.cend(); + bool canFindEmoji = true, consumePrevious = false; + for (const QChar *ch = emojiEnd; ch != e;) { + uint32 emojiCode = 0; + const QChar *newEmojiEnd = 0; + if (canFindEmoji) { + findEmoji(ch, e, newEmojiEnd, emojiCode); + } + if (emojiCode) { +// if (newEmojiEnd < e && newEmojiEnd->unicode() == ' ') ++newEmojiEnd; + if (result.isEmpty()) result.reserve(text.size()); + if (ch > emojiEnd + (consumePrevious ? 1 : 0)) { + result.append(emojiEnd, ch - emojiEnd - (consumePrevious ? 1 : 0)); + } + if (emojiCode > 65535) { + result.append(QChar((emojiCode >> 16) & 0xFFFF)); + } + result.append(QChar(emojiCode & 0xFFFF)); + + ch = emojiEnd = newEmojiEnd; + canFindEmoji = true; + consumePrevious = false; + } else { + if (false && (ch->unicode() == QChar::Space || ch->unicode() == QChar::Nbsp)) { + canFindEmoji = true; + consumePrevious = true; + } else if (emojiEdge(ch)) { + canFindEmoji = true; + consumePrevious = false; + } else { + canFindEmoji = false; + } + ++ch; + } + } + if (result.isEmpty()) return text; + + if (emojiEnd < e) result.append(emojiEnd, e - emojiEnd); + return result; +} + +EmojiPack emojiPack(DBIEmojiTab tab); diff --git a/Telegram/SourceFiles/gui/filedialog.cpp b/Telegram/SourceFiles/gui/filedialog.cpp new file mode 100644 index 000000000..e51b41db1 --- /dev/null +++ b/Telegram/SourceFiles/gui/filedialog.cpp @@ -0,0 +1,168 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "gui/filedialog.h" + +#include "app.h" +#include "application.h" + +void filedialogInit() { + // hack to restore previous dir without hurting performance + if (cDialogLastPath().isEmpty()) { + QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); + settings.beginGroup(QLatin1String("Qt")); + QByteArray sd = settings.value(QLatin1String("filedialog")).toByteArray(); + QDataStream stream(&sd, QIODevice::ReadOnly); + if (!stream.atEnd()) { + int version = 3, _QFileDialogMagic = 190; + QByteArray splitterState; + QByteArray headerData; + QList bookmarks; + QStringList history; + QString currentDirectory; + qint32 marker; + qint32 v; + qint32 viewMode; + stream >> marker; + stream >> v; + if (marker == _QFileDialogMagic && v == version) { + stream >> splitterState + >> bookmarks + >> history + >> currentDirectory + >> headerData + >> viewMode; + cSetDialogLastPath(currentDirectory); + } + } + if (cDialogHelperPath().isEmpty()) { + QDir temppath(cWorkingDir() + "tdata/tdummy/"); + if (!temppath.exists()) { + temppath.mkpath(temppath.absolutePath()); + } + if (temppath.exists()) { + cSetDialogHelperPath(temppath.absolutePath()); + } + } + } +} + +// multipleFiles: 1 - multi open, 0 - single open, -1 - single save +bool _filedialogGetFiles(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, int multipleFiles, const QString &startFile = QString()) { + filedialogInit(); + + // hack for fast non-native dialog create + QFileDialog dialog(App::wnd(), caption, cDialogHelperPathFinal(), filter); + + dialog.setModal(true); + if (multipleFiles >= 0) { // open file or files + dialog.setFileMode(multipleFiles ? QFileDialog::ExistingFiles : QFileDialog::ExistingFile); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + } else if (multipleFiles < -1) { // save dir + dialog.setAcceptMode(QFileDialog::AcceptOpen); + dialog.setFileMode(QFileDialog::Directory); + dialog.setOption(QFileDialog::ShowDirsOnly); + } else { // save file + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setAcceptMode(QFileDialog::AcceptSave); + } + dialog.show(); + + if (!cDialogLastPath().isEmpty()) dialog.setDirectory(cDialogLastPath()); + if (multipleFiles == -1) { + QString toSelect(startFile); +#ifdef Q_OS_WIN + int32 lastSlash = toSelect.lastIndexOf('/'); + if (lastSlash >= 0) { + toSelect = toSelect.mid(lastSlash + 1); + } + int32 lastBackSlash = toSelect.lastIndexOf('\\'); + if (lastBackSlash >= 0) { + toSelect = toSelect.mid(lastBackSlash + 1); + } +#endif + dialog.selectFile(toSelect); + } + + int res = dialog.exec(); + + cSetDialogLastPath(dialog.directory().absolutePath()); + + if (res == QDialog::Accepted) { + if (multipleFiles > 0) { + files = dialog.selectedFiles(); + } else { + files = dialog.selectedFiles().mid(0, 1); + } + if (multipleFiles >= 0) { +#ifdef Q_OS_WIN + remoteContent = dialog.selectedRemoteContent(); +#endif + } + return true; + } + + files = QStringList(); + remoteContent = QByteArray(); + return false; +} + +bool filedialogGetOpenFiles(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter) { + return _filedialogGetFiles(files, remoteContent, caption, filter, 1); +} + +bool filedialogGetOpenFile(QString &file, QByteArray &remoteContent, const QString &caption, const QString &filter) { + QStringList files; + bool result = _filedialogGetFiles(files, remoteContent, caption, filter, 0); + file = files.isEmpty() ? QString() : files.at(0); + return result; +} + +bool filedialogGetSaveFile(QString &file, const QString &caption, const QString &filter, const QString &startName) { + QStringList files; + QByteArray remoteContent; + bool result = _filedialogGetFiles(files, remoteContent, caption, filter, -1, startName); + file = files.isEmpty() ? QString() : files.at(0); + return result; +} + +bool filedialogGetDir(QString &dir, const QString &caption) { + QStringList files; + QByteArray remoteContent; + bool result = _filedialogGetFiles(files, remoteContent, caption, QString(), -2); + dir = files.isEmpty() ? QString() : files.at(0); + return result; +} + +QString filedialogDefaultName(const QString &prefix, const QString &extension, const QString &path) { + filedialogInit(); + + time_t t = time(NULL); + struct tm tm; + mylocaltime(&tm, &t); + + QChar zero('0'); + + QDir dir(path.isEmpty() ? cDialogLastPath() : path); + QString base = prefix + QString("_%1-%2-%3_%4-%5-%6").arg(tm.tm_year + 1900).arg(tm.tm_mon + 1, 2, 10, zero).arg(tm.tm_mday, 2, 10, zero).arg(tm.tm_hour, 2, 10, zero).arg(tm.tm_min, 2, 10, zero).arg(tm.tm_sec, 2, 10, zero); + QString nameBase = dir.absolutePath() + '/' + base, name = nameBase + extension; + for (int i = 0; QFileInfo(name).exists(); ++i) { + name = nameBase + QString(" (%1)").arg(i + 2) + extension; + } + return name; +} diff --git a/Telegram/SourceFiles/gui/filedialog.h b/Telegram/SourceFiles/gui/filedialog.h new file mode 100644 index 000000000..669826d62 --- /dev/null +++ b/Telegram/SourceFiles/gui/filedialog.h @@ -0,0 +1,26 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +void filedialogInit(); +bool filedialogGetOpenFiles(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter); +bool filedialogGetOpenFile(QString &file, QByteArray &remoteContent, const QString &caption, const QString &filter); +bool filedialogGetSaveFile(QString &file, const QString &caption, const QString &filter, const QString &startName); +bool filedialogGetDir(QString &dir, const QString &caption); + +QString filedialogDefaultName(const QString &prefix, const QString &extension, const QString &path = QString()); diff --git a/Telegram/SourceFiles/gui/flatbutton.cpp b/Telegram/SourceFiles/gui/flatbutton.cpp new file mode 100644 index 000000000..500570d25 --- /dev/null +++ b/Telegram/SourceFiles/gui/flatbutton.cpp @@ -0,0 +1,204 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "gui/flatbutton.h" + +FlatButton::FlatButton(QWidget *parent, const QString &text, const style::flatButton &st) : Button(parent), + _text(text), _opacity(1), + _st(st), + a_bg(st.bgColor->c), a_text(st.color->c) { + if (_st.width < 0) { + _st.width = _st.font->m.width(text) - _st.width; + } else if (!_st.width) { + _st.width = _st.font->m.width(text) + _st.height - _st.font->height; + } + connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource))); + resize(_st.width, _st.height); + setCursor(_st.cursor); +} + +void FlatButton::setOpacity(float64 o) { + _opacity = o; + update(); +} + +void FlatButton::setText(const QString &text) { + _text = text; + update(); +} + +void FlatButton::setWidth(int32 w) { + _st.width = w; + resize(_st.width, height()); +} + +bool FlatButton::animStep(float64 ms) { + float64 dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + a_bg.finish(); + a_text.finish(); + res = false; + } else { + a_bg.update(dt, anim::linear); + a_text.update(dt, anim::linear); + } + update(); + return res; +} + +void FlatButton::onStateChange(int oldState, ButtonStateChangeSource source) { + style::color bgColorTo = (_state & StateOver) ? ((_state & StateDown) ? _st.downBgColor : _st.overBgColor) : _st.bgColor; + style::color colorTo = (_state & StateOver) ? ((_state & StateDown) ? _st.downColor : _st.overColor) : _st.color; + + a_bg.start(bgColorTo->c); + a_text.start(colorTo->c); + if (source == ButtonByUser || source == ButtonByPress) { + anim::stop(this); + a_bg.finish(); + a_text.finish(); + update(); + } else { + anim::start(this); + } +} + +void FlatButton::paintEvent(QPaintEvent *e) { + QPainter p(this); + + QRect r(0, height() - _st.height, width(), _st.height); + + p.setOpacity(_opacity); + p.fillRect(r, a_bg.current()); + + p.setFont(((_state & StateOver) ? _st.overFont : _st.font)->f); + p.setRenderHint(QPainter::TextAntialiasing); + p.setPen(a_text.current()); + + r.setTop((_state & StateOver) ? ((_state & StateDown) ? _st.downTextTop : _st.overTextTop) : _st.textTop); + p.drawText(r, _text, QTextOption(Qt::AlignHCenter)); +} + +BottomButton::BottomButton(QWidget *w, const QString &t, const style::flatButton &s) : FlatButton(w, t, s) { + resize(width(), height() + 1); +} + +void BottomButton::paintEvent(QPaintEvent *e) { + QPainter p(this); + + p.setPen(st::scrollDef.shColor->p); + p.drawLine(0, 0, width(), 0); + + FlatButton::paintEvent(e); +} + +LinkButton::LinkButton(QWidget *parent, const QString &text, const style::linkButton &st) : Button(parent), _text(text), _st(st) { + connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource))); + resize(_st.font->m.width(_text), _st.font->height); + setCursor(style::cur_pointer); +} + +void LinkButton::paintEvent(QPaintEvent *e) { + QPainter p(this); + p.setFont(((_state & StateOver) ? _st.overFont : _st.font)->f); + p.setPen(((_state & StateDown) ? _st.downColor : ((_state & StateOver) ? _st.overColor : _st.color))->p); + p.drawText(0, ((_state & StateOver) ? _st.overFont : _st.font)->ascent, _text); +} + +void LinkButton::setText(const QString &text) { + _text = text; + resize(_st.font->m.width(_text), _st.font->height); + update(); +} + +void LinkButton::onStateChange(int oldState, ButtonStateChangeSource source) { + update(); +} + +LinkButton::~LinkButton() { +} + +IconedButton::IconedButton(QWidget *parent, const style::iconedButton &st, const QString &text) : Button(parent), _opacity(1), + _text(text), _st(st), a_opacity(_st.opacity), a_bg(_st.bgColor->c) { + + if (_st.width < 0) { + _st.width = _st.font->m.width(text) - _st.width; + } else if (!_st.width) { + _st.width = _st.font->m.width(text) + _st.height - _st.font->height; + } + connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource))); + resize(_st.width, _st.height); + setCursor(_st.cursor); +} + +void IconedButton::setOpacity(float64 opacity) { + _opacity = opacity; + update(); +} + +bool IconedButton::animStep(float64 ms) { + float64 dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + a_opacity.finish(); + a_bg.finish(); + res = false; + } else { + a_opacity.update(dt, anim::linear); + a_bg.update(dt, anim::linear); + } + update(); + return res; +} + +void IconedButton::onStateChange(int oldState, ButtonStateChangeSource source) { + a_opacity.start((_state & (StateOver | StateDown)) ? _st.overOpacity : _st.opacity); + a_bg.start(((_state & (StateOver | StateDown)) ? _st.overBgColor : _st.bgColor)->c); + + if (source == ButtonByUser || source == ButtonByPress) { + anim::stop(this); + a_opacity.finish(); + a_bg.finish(); + update(); + } else { + anim::start(this); + } +} + +void IconedButton::paintEvent(QPaintEvent *e) { + QPainter p(this); + + p.setOpacity(_opacity); + + p.fillRect(e->rect(), a_bg.current()); + + p.setOpacity(a_opacity.current() * _opacity); + + if (!_text.isEmpty()) { + p.setFont(_st.font->f); + p.setRenderHint(QPainter::TextAntialiasing); + p.setPen(_st.color->p); + const QPoint &t((_state & StateDown) ? _st.downTextPos : _st.textPos); + p.drawText(t.x(), t.y() + _st.font->ascent, _text); + } + const QRect &i((_state & StateDown) ? _st.downIcon : _st.icon); + if (i.width()) { + const QPoint &t((_state & StateDown) ? _st.downIconPos : _st.iconPos); + p.drawPixmap(t, App::sprite(), i); + } +} diff --git a/Telegram/SourceFiles/gui/flatbutton.h b/Telegram/SourceFiles/gui/flatbutton.h new file mode 100644 index 000000000..0adffe355 --- /dev/null +++ b/Telegram/SourceFiles/gui/flatbutton.h @@ -0,0 +1,114 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "gui/button.h" +#include "gui/flatcheckbox.h" +#include "gui/animation.h" +#include "style.h" + +class FlatButton : public Button, public Animated { + Q_OBJECT + +public: + + FlatButton(QWidget *parent, const QString &text, const style::flatButton &st); + + bool animStep(float64 ms); + void paintEvent(QPaintEvent *e); + void setOpacity(float64 o); + + void setText(const QString &text); + void setWidth(int32 w); + + ~FlatButton() { + } + +public slots: + + void onStateChange(int oldState, ButtonStateChangeSource source); + +private: + + QString _text; + int32 _textWidth; + + style::flatButton _st; + anim::cvalue a_bg, a_text; + + float64 _opacity; +}; + +class BottomButton : public FlatButton { +public: + + BottomButton(QWidget *parent, const QString &text, const style::flatButton &st); + void paintEvent(QPaintEvent *e); + +}; + +class LinkButton : public Button { + Q_OBJECT + +public: + + LinkButton(QWidget *parent, const QString &text, const style::linkButton &st = st::btnDefLink); + + void paintEvent(QPaintEvent *e); + + void setText(const QString &text); + + ~LinkButton(); + +public slots: + + void onStateChange(int oldState, ButtonStateChangeSource source); + +private: + + QString _text; + style::linkButton _st; +}; + +class IconedButton : public Button, public Animated { + Q_OBJECT + +public: + + IconedButton(QWidget *parent, const style::iconedButton &st, const QString &text = QString()); + + bool animStep(float64 ms); + void paintEvent(QPaintEvent *e); + + void setOpacity(float64 o); + +public slots: + + void onStateChange(int oldState, ButtonStateChangeSource source); + +private: + + QString _text; + int32 _textWidth; + + style::iconedButton _st; + anim::fvalue a_opacity; + anim::cvalue a_bg; + + float64 _opacity; +}; diff --git a/Telegram/SourceFiles/gui/flatcheckbox.cpp b/Telegram/SourceFiles/gui/flatcheckbox.cpp new file mode 100644 index 000000000..e55077a14 --- /dev/null +++ b/Telegram/SourceFiles/gui/flatcheckbox.cpp @@ -0,0 +1,211 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" +#include "lang.h" + +#include "flatcheckbox.h" + +FlatCheckbox::FlatCheckbox(QWidget *parent, const QString &text, bool checked, const style::flatCheckbox &st) : Button(parent), + _text(text), _checked(checked), _st(st), _opacity(1), a_over(0, 0) { + connect(this, SIGNAL(clicked()), this, SLOT(onClicked())); + connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource))); + setCursor(_st.cursor); + int32 w = _st.width, h = _st.height; + if (w <= 0) w = _st.textLeft + _st.font->m.width(_text); + if (h <= 0) h = qMax(_st.font->height, _st.imageRect.height()); + resize(QSize(w, h)); +} + +bool FlatCheckbox::checked() const { + return _checked; +} + +void FlatCheckbox::setChecked(bool checked) { + if (_checked != checked) { + _checked = checked; + emit changed(); + update(); + } +} + +void FlatCheckbox::setOpacity(float64 o) { + _opacity = o; + update(); +} + +void FlatCheckbox::onClicked() { + if (_state & StateDisabled) return; + setChecked(!checked()); +} + +void FlatCheckbox::onStateChange(int oldState, ButtonStateChangeSource source) { + if ((_state & StateOver) && !(oldState & StateOver)) { + a_over.start(1); + anim::start(this); + } else if (!(_state & StateOver) && (oldState & StateOver)) { + a_over.start(0); + anim::start(this); + } + if ((_state & StateDisabled) && !(oldState & StateDisabled)) { + setCursor(_st.disabledCursor); + anim::start(this); + } else if (!(_state & StateDisabled) && (oldState & StateDisabled)) { + setCursor(_st.cursor); + anim::start(this); + } +} + +void FlatCheckbox::paintEvent(QPaintEvent *e) { + QPainter p(this); + + p.setOpacity(_opacity); + if (_st.bgColor != st::transparent) { + p.fillRect(rect(), _st.bgColor->b); + } + + p.setFont(_st.font->f); + p.setRenderHint(QPainter::TextAntialiasing); + p.setPen((_state & StateDisabled ? _st.disColor : _st.textColor)->p); + + QRect tRect(rect()); + tRect.setTop(_st.textTop); + tRect.setLeft(_st.textLeft); + p.drawText(tRect, _text, QTextOption(style::al_topleft)); + + if (_state & StateDisabled) { + QRect sRect(_checked ? _st.chkDisImageRect : _st.disImageRect); + p.drawPixmap(_st.imagePos, App::sprite(), sRect); + } else if (_checked && _st.chkImageRect == _st.chkOverImageRect || !_checked && _st.imageRect == _st.overImageRect) { + p.setOpacity(_opacity); + QRect sRect(_checked ? _st.chkImageRect : _st.imageRect); + p.drawPixmap(_st.imagePos, App::sprite(), sRect); + } else { + if (a_over.current() < 1) { + QRect sRect(_checked ? _st.chkImageRect : _st.imageRect); + p.drawPixmap(_st.imagePos, App::sprite(), sRect); + } + if (a_over.current() > 0) { + p.setOpacity(_opacity * a_over.current()); + QRect sRect(_checked ? _st.chkOverImageRect : _st.overImageRect); + p.drawPixmap(_st.imagePos, App::sprite(), sRect); + } + } +} + +bool FlatCheckbox::animStep(float64 ms) { + float64 dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + a_over.finish(); + res = false; + } else { + a_over.update(dt, _st.bgFunc); + } + update(); + return res; +} + +class RadiobuttonsGroup : public QSet { + typedef QSet Parent; + +public: + RadiobuttonsGroup(const QString &name) : _name(name), _val(0) { + } + + void remove(FlatRadiobutton * const &radio); + int32 val() const { + return _val; + } + void setVal(int32 val) { + _val = val; + } + +private: + QString _name; + int32 _val; + +}; + +class Radiobuttons : public QMap { + typedef QMap Parent; + +public: + + RadiobuttonsGroup *reg(const QString &group) { + Parent::const_iterator i = constFind(group); + if (i == cend()) { + i = insert(group, new RadiobuttonsGroup(group)); + } + return i.value(); + } + + int remove(const QString &group) { + Parent::iterator i = find(group); + if (i != cend()) { + delete i.value(); + erase(i); + return 1; + } + return 0; + } + + ~Radiobuttons() { + for (Parent::const_iterator i = cbegin(), e = cend(); i != e; ++i) { + delete *i; + } + } +}; + +namespace { + Radiobuttons radioButtons; +} + +void RadiobuttonsGroup::remove(FlatRadiobutton * const &radio) { + Parent::remove(radio); + if (isEmpty()) { + radioButtons.remove(_name); + } +} + +FlatRadiobutton::FlatRadiobutton(QWidget *parent, const QString &group, int32 value, const QString &text, bool checked, const style::flatCheckbox &st) : + FlatCheckbox(parent, text, checked, st), _value(value), _group(radioButtons.reg(group)) { + _group->insert(this); + connect(this, SIGNAL(changed()), this, SLOT(onChanged())); + if (this->checked()) onChanged(); +} + +void FlatRadiobutton::onChanged() { + if (checked()) { + int32 uncheck = _group->val(); + if (uncheck != _value) { + _group->setVal(_value); + for (RadiobuttonsGroup::const_iterator i = _group->cbegin(), e = _group->cend(); i != e; ++i) { + if ((*i)->val() == uncheck) { + (*i)->setChecked(false); + } + } + } + } else if (_group->val() == _value) { + setChecked(true); + } +} + +FlatRadiobutton::~FlatRadiobutton() { + _group->remove(this); +} diff --git a/Telegram/SourceFiles/gui/flatcheckbox.h b/Telegram/SourceFiles/gui/flatcheckbox.h new file mode 100644 index 000000000..3db62cc04 --- /dev/null +++ b/Telegram/SourceFiles/gui/flatcheckbox.h @@ -0,0 +1,80 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "gui/button.h" + +class FlatCheckbox : public Button, public Animated { + Q_OBJECT + +public: + + FlatCheckbox(QWidget *parent, const QString &text, bool checked = false, const style::flatCheckbox &st = st::cbDefFlat); + + bool checked() const; + void setChecked(bool checked); + + bool animStep(float64 ms); + void paintEvent(QPaintEvent *e); + + void setOpacity(float64 o); + +public slots: + + void onClicked(); + void onStateChange(int oldState, ButtonStateChangeSource source); + +signals: + + void changed(); + +private: + + style::flatCheckbox _st; + anim::fvalue a_over; + QString _text; + style::font _font; + + float64 _opacity; + + bool _checked; + +}; + +class RadiobuttonsGroup; +class FlatRadiobutton : public FlatCheckbox { + Q_OBJECT + +public: + + FlatRadiobutton(QWidget *parent, const QString &group, int32 value, const QString &text, bool checked = false, const style::flatCheckbox &st = st::rbDefFlat); + int32 val() const { + return _value; + } + ~FlatRadiobutton(); + +public slots: + + void onChanged(); + +private: + + RadiobuttonsGroup *_group; + int32 _value; + +}; diff --git a/Telegram/SourceFiles/gui/flatinput.cpp b/Telegram/SourceFiles/gui/flatinput.cpp new file mode 100644 index 000000000..9b6fb08eb --- /dev/null +++ b/Telegram/SourceFiles/gui/flatinput.cpp @@ -0,0 +1,266 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" + +#include "flatinput.h" + +namespace { + class FlatInputStyle : public QCommonStyle { + public: + FlatInputStyle() { + } + + void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const { + } + QRect subElementRect(SubElement r, const QStyleOption *opt, const QWidget *widget = 0) const { + switch (r) { + case SE_LineEditContents: + const FlatInput *w = widget ? qobject_cast(widget) : 0; + return w ? w->getTextRect() : QCommonStyle::subElementRect(r, opt, widget); + break; + } + return QCommonStyle::subElementRect(r, opt, widget); + } + }; + FlatInputStyle _flatInputStyle; +} + +FlatInput::FlatInput(QWidget *parent, const style::flatInput &st, const QString &pholder, const QString &v) : QLineEdit(v, parent), _oldtext(v), + _st(st), _phVisible(!v.length()), _kev(0), a_borderColor(st.borderColor->c), a_bgColor(st.bgColor->c), _notingBene(0), + a_phLeft(_phVisible ? 0 : st.phShift), a_phAlpha(_phVisible ? 1 : 0), a_phColor(st.phColor->c) { + resize(_st.width, _st.height); + + setFont(_st.font->f); + setAlignment(_st.align); + + _ph = _st.font->m.elidedText(pholder, Qt::ElideRight, width() - _st.textMrg.left() - _st.textMrg.right() - _st.phPos.x() - 1); + + QPalette p(palette()); + p.setColor(QPalette::Text, _st.textColor->c); + setPalette(p); + + connect(this, SIGNAL(textChanged(const QString &)), this, SLOT(onTextChange(const QString &))); + connect(this, SIGNAL(textEdited(const QString &)), this, SLOT(onTextEdited())); + + setStyle(&_flatInputStyle); + setTextMargins(0, 0, 0, 0); + setContentsMargins(0, 0, 0, 0); + + setAttribute(Qt::WA_AcceptTouchEvents); + _touchTimer.setSingleShot(true); + connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer())); +} + +void FlatInput::onTouchTimer() { + _touchRightButton = true; +} + +bool FlatInput::event(QEvent *e) { + if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { + QTouchEvent *ev = static_cast(e); + if (ev->device()->type() == QTouchDevice::TouchScreen) { + touchEvent(ev); + return QLineEdit::event(e); + } + } + return QLineEdit::event(e); +} + +void FlatInput::touchEvent(QTouchEvent *e) { + switch (e->type()) { + case QEvent::TouchBegin: + if (_touchPress || e->touchPoints().isEmpty()) return; + _touchTimer.start(QApplication::startDragTime()); + _touchPress = true; + _touchMove = _touchRightButton = false; + _touchStart = e->touchPoints().cbegin()->screenPos().toPoint(); + break; + + case QEvent::TouchUpdate: + if (!_touchPress || e->touchPoints().isEmpty()) return; + if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) { + _touchMove = true; + } + break; + + case QEvent::TouchEnd: + if (!_touchPress) return; + if (!_touchMove && window()) { + Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton); + QPoint mapped(mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart)); + + if (_touchRightButton) { + QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart); + contextMenuEvent(&contextEvent); + } + } + _touchTimer.stop(); + _touchPress = _touchMove = _touchRightButton = false; + break; + + case QEvent::TouchCancel: + _touchPress = false; + _touchTimer.stop(); + break; + } +} + +QRect FlatInput::getTextRect() const { + return rect().marginsRemoved(_st.textMrg + QMargins(-2, -1, -2, -1)); +} + +void FlatInput::paintEvent(QPaintEvent *e) { + QPainter p(this); + p.fillRect(rect(), a_bgColor.current()); + if (_st.borderWidth) { + p.setPen(a_borderColor.current()); + for (uint32 i = 0; i < _st.borderWidth; ++i) { + p.drawRect(i, i, width() - 2 * i - 1, height() - 2 * i - 1); + } + } + if (_st.imgRect.width()) { + p.drawPixmap(_st.imgPos, App::sprite(), _st.imgRect); + } + + bool phDraw = _phVisible; + if (animating()) { + p.setOpacity(a_phAlpha.current()); + phDraw = true; + } + if (phDraw) { + p.save(); + p.setClipRect(rect()); + QRect phRect(_st.textMrg.left() + _st.phPos.x() + a_phLeft.current(), _st.textMrg.top() + _st.phPos.y(), width() - _st.textMrg.left() - _st.textMrg.right(), height() - _st.textMrg.top() - _st.textMrg.bottom()); + p.setFont(_st.font->f); + p.setPen(a_phColor.current()); + p.drawText(phRect, _ph, QTextOption(_st.phAlign)); + p.restore(); + } + QLineEdit::paintEvent(e); +} + +void FlatInput::focusInEvent(QFocusEvent *e) { + a_phColor.start(_st.phFocusColor->c); + if (_notingBene <= 0) { + a_borderColor.start(_st.borderActive->c); + } + a_bgColor.start(_st.bgActive->c); + anim::start(this); + QLineEdit::focusInEvent(e); + emit focused(); +} + +void FlatInput::focusOutEvent(QFocusEvent *e) { + a_phColor.start(_st.phColor->c); + if (_notingBene <= 0) { + a_borderColor.start(_st.borderColor->c); + } + a_bgColor.start(_st.bgColor->c); + anim::start(this); + QLineEdit::focusOutEvent(e); + emit blurred(); +} + +QSize FlatInput::sizeHint() const { + return geometry().size(); +} + +QSize FlatInput::minimumSizeHint() const { + return geometry().size(); +} + +bool FlatInput::animStep(float64 ms) { + float dt = ms / _st.phDuration; + bool res = true; + if (dt >= 1) { + res = false; + a_phLeft.finish(); + a_phAlpha.finish(); + a_phColor.finish(); + a_bgColor.finish(); + if (_notingBene > 0) { + _notingBene = -1; + a_borderColor.start((hasFocus() ? _st.borderActive : _st.borderColor)->c); + anim::start(this); + return true; + } else if (_notingBene) { + _notingBene = 0; + } + a_borderColor.finish(); + } else { + a_phLeft.update(dt, _st.phLeftFunc); + a_phAlpha.update(dt, _st.phAlphaFunc); + a_phColor.update(dt, _st.phColorFunc); + a_bgColor.update(dt, _st.phColorFunc); + a_borderColor.update(dt, _st.phColorFunc); + } + update(); + return res; +} + +void FlatInput::updatePlaceholder() { + bool vis = !text().length(); + if (vis == _phVisible) return; + + a_phLeft.start(vis ? 0 : _st.phShift); + a_phAlpha.start(vis ? 1 : 0); + anim::start(this); + + _phVisible = vis; +} + +void FlatInput::correctValue(QKeyEvent *e, const QString &was) { +} + +void FlatInput::keyPressEvent(QKeyEvent *e) { + QString was(text()); + _kev = e; + QLineEdit::keyPressEvent(e); + if (was == text()) { // call correct manually + correctValue(_kev, was); + _oldtext = text(); + if (was != _oldtext) emit changed(); + updatePlaceholder(); + } + if (e->key() == Qt::Key_Escape) { + emit cancelled(); + } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { + emit accepted(); + } + _kev = 0; +} + +void FlatInput::onTextEdited() { + QString was(_oldtext); + correctValue(_kev, was); + _oldtext = text(); + if (was != _oldtext) emit changed(); + updatePlaceholder(); +} + +void FlatInput::onTextChange(const QString &text) { + _oldtext = text; +} + +void FlatInput::notaBene() { + _notingBene = 1; + setFocus(); + a_borderColor.start(_st.borderError->c); + anim::start(this); +} diff --git a/Telegram/SourceFiles/gui/flatinput.h b/Telegram/SourceFiles/gui/flatinput.h new file mode 100644 index 000000000..b77d8a44e --- /dev/null +++ b/Telegram/SourceFiles/gui/flatinput.h @@ -0,0 +1,87 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "style.h" +#include "animation.h" + +class FlatInput : public QLineEdit, public Animated { + Q_OBJECT + +public: + + FlatInput(QWidget *parent, const style::flatInput &st, const QString &ph = QString(), const QString &val = QString()); + QString val() const; + + bool event(QEvent *e); + void touchEvent(QTouchEvent *e); + void paintEvent(QPaintEvent *e); + void focusInEvent(QFocusEvent *e); + void focusOutEvent(QFocusEvent *e); + void keyPressEvent(QKeyEvent *e); + + void notaBene(); + + void updatePlaceholder(); + + QRect getTextRect() const; + + bool animStep(float64 ms); + + QSize sizeHint() const; + QSize minimumSizeHint() const; + +public slots: + + void onTextChange(const QString &text); + void onTextEdited(); + + void onTouchTimer(); + +signals: + + void changed(); + void cancelled(); + void accepted(); + void focused(); + void blurred(); + +protected: + + virtual void correctValue(QKeyEvent *e, const QString &was); + +private: + + QString _ph, _oldtext; + QKeyEvent *_kev; + + bool _phVisible; + anim::ivalue a_phLeft; + anim::fvalue a_phAlpha; + anim::cvalue a_phColor, a_borderColor, a_bgColor; + + int _notingBene; + style::flatInput _st; + + style::font _font; + + QTimer _touchTimer; + bool _touchPress, _touchRightButton, _touchMove; + QPoint _touchStart; +}; diff --git a/Telegram/SourceFiles/gui/flatlabel.cpp b/Telegram/SourceFiles/gui/flatlabel.cpp new file mode 100644 index 000000000..9f6d92097 --- /dev/null +++ b/Telegram/SourceFiles/gui/flatlabel.cpp @@ -0,0 +1,122 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" + +#include "gui/flatlabel.h" + +namespace { + TextParseOptions _labelOptions = { + TextParseMultiline, // flags + 0, // maxw + 0, // maxh + Qt::LayoutDirectionAuto, // dir + }; +} + +FlatLabel::FlatLabel(QWidget *parent, const QString &text, const style::flatLabel &st, const style::textStyle &tst) : TWidget(parent), +_st(st), _tst(tst), _text(_st.width ? _st.width : QFIXED_MAX), _opacity(1) { + setRichText(text); +} + +void FlatLabel::setText(const QString &text) { + textstyleSet(&_tst); + _text.setText(_st.font, text, _labelOptions); + textstyleRestore(); + int32 w = _st.width ? _st.width : _text.maxWidth(), h = _text.countHeight(w); + resize(w, h); +} + +void FlatLabel::setRichText(const QString &text) { + textstyleSet(&_tst); + _text.setRichText(_st.font, text, _labelOptions); + textstyleRestore(); + int32 w = _st.width ? _st.width : _text.maxWidth(), h = _text.countHeight(w); + resize(w, h); + setMouseTracking(_text.hasLinks()); +} + +void FlatLabel::setLink(uint16 lnkIndex, const TextLinkPtr &lnk) { + _text.setLink(lnkIndex, lnk); +} + +void FlatLabel::mouseMoveEvent(QMouseEvent *e) { + _lastMousePos = e->globalPos(); + updateHover(); +} + +void FlatLabel::mousePressEvent(QMouseEvent *e) { + _lastMousePos = e->globalPos(); + updateHover(); + if (textlnkOver()) { + textlnkDown(textlnkOver()); + update(); + } +} + +void FlatLabel::mouseReleaseEvent(QMouseEvent *e) { + _lastMousePos = e->globalPos(); + updateHover(); + if (textlnkOver() && textlnkOver() == textlnkDown()) { + textlnkOver()->onClick(e->button()); + } + textlnkDown(TextLinkPtr()); +} + +void FlatLabel::leaveEvent(QEvent *e) { + if (_myLink) { + if (textlnkOver() == _myLink) { + textlnkOver(TextLinkPtr()); + update(); + } + _myLink = TextLinkPtr(); + setCursor(style::cur_default); + } +} + +void FlatLabel::updateLink() { + _lastMousePos = QCursor::pos(); + updateHover(); +} + +void FlatLabel::updateHover() { + QPoint m(mapFromGlobal(_lastMousePos)); + bool wasMy = (_myLink == textlnkOver()); + textstyleSet(&_tst); + _myLink = _text.link(m.x(), m.y(), width(), _st.align); + textstyleRestore(); + if (_myLink != textlnkOver()) { + if (wasMy || _myLink || rect().contains(m)) { + textlnkOver(_myLink); + } + setCursor(_myLink ? style::cur_pointer : style::cur_default); + update(); + } +} + +void FlatLabel::setOpacity(float64 o) { + _opacity = o; + update(); +} + +void FlatLabel::paintEvent(QPaintEvent *e) { + QPainter p(this); + p.setOpacity(_opacity); + textstyleSet(&_tst); + _text.draw(p, 0, 0, width(), _st.align, e->rect().y(), e->rect().bottom()); + textstyleRestore(); +} diff --git a/Telegram/SourceFiles/gui/flatlabel.h b/Telegram/SourceFiles/gui/flatlabel.h new file mode 100644 index 000000000..b4628d966 --- /dev/null +++ b/Telegram/SourceFiles/gui/flatlabel.h @@ -0,0 +1,54 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "style.h" + +class FlatLabel : public TWidget { + Q_OBJECT + +public: + + FlatLabel(QWidget *parent, const QString &text, const style::flatLabel &st = st::labelDefFlat, const style::textStyle &tst = st::defaultTextStyle); + + void paintEvent(QPaintEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void leaveEvent(QEvent *e); + void updateLink(); + void setOpacity(float64 o); + + void setText(const QString &text); + void setRichText(const QString &text); + + void setLink(uint16 lnkIndex, const TextLinkPtr &lnk); + +private: + + void updateHover(); + + Text _text; + style::flatLabel _st; + style::textStyle _tst; + float64 _opacity; + + QPoint _lastMousePos; + TextLinkPtr _myLink; + +}; diff --git a/Telegram/SourceFiles/gui/flattextarea.cpp b/Telegram/SourceFiles/gui/flattextarea.cpp new file mode 100644 index 000000000..ab76cdcda --- /dev/null +++ b/Telegram/SourceFiles/gui/flattextarea.cpp @@ -0,0 +1,483 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" + +#include "flattextarea.h" + +FlatTextarea::FlatTextarea(QWidget *parent, const style::flatTextarea &st, const QString &pholder, const QString &v) : QTextEdit(v, parent), _oldtext(v), + _st(st), _phVisible(!v.length()), _ph(pholder), _fakeMargin(0), + a_phLeft(_phVisible ? 0 : st.phShift), a_phAlpha(_phVisible ? 1 : 0), a_phColor(st.phColor->c), + _touchPress(false), _touchRightButton(false), _touchMove(false), _replacingEmojis(false) { + setAcceptRichText(false); + resize(_st.width, _st.font->height); + + setFont(_st.font->f); + setAlignment(_st.align); + + _phelided = _st.font->m.elidedText(_ph, Qt::ElideRight, width() - _st.textMrg.left() - _st.textMrg.right() - _st.phPos.x() - 1); + + QPalette p(palette()); + p.setColor(QPalette::Text, _st.textColor->c); + setPalette(p); + + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + setFrameStyle(QFrame::NoFrame | QFrame::Plain); + viewport()->setAutoFillBackground(false); + + setContentsMargins(0, 0, 0, 0); + + switch (cScale()) { + case dbisOneAndQuarter: _fakeMargin = 1; break; + case dbisOneAndHalf: _fakeMargin = 2; break; + case dbisTwo: _fakeMargin = 4; break; + } + setStyleSheet(qsl("QTextEdit { margin: %1px; }").arg(_fakeMargin)); + + viewport()->setAttribute(Qt::WA_AcceptTouchEvents); + _touchTimer.setSingleShot(true); + connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer())); + + connect(document(), SIGNAL(contentsChange(int, int, int)), this, SLOT(onDocumentContentsChange(int, int, int))); + connect(document(), SIGNAL(contentsChanged()), this, SLOT(onDocumentContentsChanged())); +} + +void FlatTextarea::onTouchTimer() { + _touchRightButton = true; +} + +bool FlatTextarea::viewportEvent(QEvent *e) { + if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { + QTouchEvent *ev = static_cast(e); + if (ev->device()->type() == QTouchDevice::TouchScreen) { + touchEvent(ev); + return QTextEdit::viewportEvent(e); + } + } + return QTextEdit::viewportEvent(e); +} + +void FlatTextarea::touchEvent(QTouchEvent *e) { + switch (e->type()) { + case QEvent::TouchBegin: + if (_touchPress || e->touchPoints().isEmpty()) return; + _touchTimer.start(QApplication::startDragTime()); + _touchPress = true; + _touchMove = _touchRightButton = false; + _touchStart = e->touchPoints().cbegin()->screenPos().toPoint(); + break; + + case QEvent::TouchUpdate: + if (!_touchPress || e->touchPoints().isEmpty()) return; + if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) { + _touchMove = true; + } + break; + + case QEvent::TouchEnd: + if (!_touchPress) return; + if (!_touchMove && window()) { + Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton); + QPoint mapped(mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart)); + + if (_touchRightButton) { + QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart); + contextMenuEvent(&contextEvent); + } + } + _touchTimer.stop(); + _touchPress = _touchMove = _touchRightButton = false; + break; + + case QEvent::TouchCancel: + _touchPress = false; + _touchTimer.stop(); + break; + } +} + +QRect FlatTextarea::getTextRect() const { + return rect().marginsRemoved(_st.textMrg + st::textRectMargins); +} + +void FlatTextarea::paintEvent(QPaintEvent *e) { + QPainter p(viewport()); + p.fillRect(rect(), _st.bgColor->b); + bool phDraw = _phVisible; + if (animating()) { + p.setOpacity(a_phAlpha.current()); + phDraw = true; + } + if (phDraw) { + p.save(); + p.setClipRect(rect()); + QRect phRect(_st.textMrg.left() - _fakeMargin + _st.phPos.x() + a_phLeft.current(), _st.textMrg.top() - _fakeMargin + _st.phPos.y(), width() - _st.textMrg.left() - _st.textMrg.right(), height() - _st.textMrg.top() - _st.textMrg.bottom()); + p.setFont(_st.font->f); + p.setPen(a_phColor.current()); + p.drawText(phRect, _ph, QTextOption(_st.phAlign)); + p.restore(); + } + QTextEdit::paintEvent(e); +} + +void FlatTextarea::focusInEvent(QFocusEvent *e) { + a_phColor.start(_st.phFocusColor->c); + anim::start(this); + QTextEdit::focusInEvent(e); +} + +void FlatTextarea::focusOutEvent(QFocusEvent *e) { + a_phColor.start(_st.phColor->c); + anim::start(this); + QTextEdit::focusOutEvent(e); +} + +QSize FlatTextarea::sizeHint() const { + return geometry().size(); +} + +QSize FlatTextarea::minimumSizeHint() const { + return geometry().size(); +} + +QString FlatTextarea::getText(int32 start, int32 end) const { + if (end >= 0 && end <= start) return QString(); + + if (start < 0) start = 0; + bool full = (start == 0) && (end < 0); + + QTextDocument *doc(document()); + QTextBlock from = full ? doc->begin() : doc->findBlock(start), till = (end < 0) ? doc->end() : doc->findBlock(end); + if (till.isValid()) till = till.next(); + + int32 possibleLen = 0; + for (QTextBlock b = from; b != till; b = b.next()) { + possibleLen += b.length(); + } + QString result; + result.reserve(possibleLen + 1); + if (!full && end < 0) { + end = possibleLen; + } + + for (QTextBlock b = from; b != till; b = b.next()) { + for (QTextBlock::Iterator iter = b.begin(); !iter.atEnd(); ++iter) { + QTextFragment fragment(iter.fragment()); + if (!fragment.isValid()) continue; + + int32 p = full ? 0 : fragment.position(), e = full ? 0 : (p + fragment.length()); + if (!full) { + if (p >= end || e <= start) { + continue; + } + } + + QTextCharFormat f = fragment.charFormat(); + QString emojiText; + QString t(fragment.text()); + if (!full) { + if (p < start) { + t = t.mid(start - p, end - start - p); + } else if (e > end) { + t = t.mid(0, end - p); + } + } + QChar *ub = t.data(), *uc = ub, *ue = uc + t.size(); + for (; uc != ue; ++uc) { + switch (uc->unicode()) { + case 0xfdd0: // QTextBeginningOfFrame + case 0xfdd1: // QTextEndOfFrame + case QChar::ParagraphSeparator: + case QChar::LineSeparator: + *uc = QLatin1Char('\n'); + break; + case QChar::Nbsp: + *uc = QLatin1Char(' '); + break; + case QChar::ObjectReplacementCharacter: + if (emojiText.isEmpty() && f.isImageFormat()) { + QString imageName = static_cast(&f)->name(); + if (imageName.midRef(0, 8) == qsl("emoji://")) { + uint32 index = imageName.mid(8).toUInt(0, 16); + const EmojiData *emoji = getEmoji(index); + if (emoji) { + emojiText.reserve(emoji->len); + switch (emoji->len) { + case 1: emojiText.append(QChar(emoji->code & 0xFFFF)); break; + case 2: + emojiText.append(QChar((emoji->code >> 16) & 0xFFFF)); + emojiText.append(QChar(emoji->code & 0xFFFF)); + break; + case 4: + emojiText.append(QChar((emoji->code >> 16) & 0xFFFF)); + emojiText.append(QChar(emoji->code & 0xFFFF)); + emojiText.append(QChar((emoji->code2 >> 16) & 0xFFFF)); + emojiText.append(QChar(emoji->code2 & 0xFFFF)); + break; + } + } + } + } + if (uc > ub) result.append(ub, uc - ub); + if (!emojiText.isEmpty()) result.append(emojiText); + ub = uc + 1; + break; + } + } + if (uc > ub) result.append(ub, uc - ub); + } + result.append('\n'); + } + result.chop(1); + return result; +} + +bool FlatTextarea::hasText() const { + QTextDocument *doc(document()); + QTextBlock from = doc->begin(), till = doc->end(); + + if (from == till) return false; + + for (QTextBlock::Iterator iter = from.begin(); !iter.atEnd(); ++iter) { + QTextFragment fragment(iter.fragment()); + if (!fragment.isValid()) continue; + if (!fragment.text().isEmpty()) return true; + } + return (from.next() != till); +} + +void FlatTextarea::insertEmoji(EmojiPtr emoji, QTextCursor c) { + c.removeSelectedText(); + + QPixmap img(App::emojiSingle(emoji, _st.font->height)); + QString url = qsl("emoji://") + QString::number(emoji->code, 16); + document()->addResource(QTextDocument::ImageResource, QUrl(url), QVariant(img)); + QTextImageFormat imageFormat; + imageFormat.setWidth(img.width()); + imageFormat.setHeight(img.height()); + imageFormat.setName(url); + imageFormat.setVerticalAlignment(QTextCharFormat::AlignBaseline); + c.insertImage(imageFormat); +} + +void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) { + int32 emojiPosition = 0; + const EmojiData *emoji = 0; + + QTextDocument *doc(document()); + + while (true) { + int32 start = position, end = position + charsAdded; + QTextBlock from = doc->findBlock(start), till = doc->findBlock(end); + if (till.isValid()) till = till.next(); + + for (QTextBlock b = from; b != till; b = b.next()) { + for (QTextBlock::Iterator iter = b.begin(); !iter.atEnd(); ++iter) { + QTextFragment fragment(iter.fragment()); + if (!fragment.isValid()) continue; + + int32 p = fragment.position(), e = p + fragment.length(); + if (p >= end || e <= start) { + continue; + } + + QString t(fragment.text()); + for (const QChar *ch = t.constData(), *e = ch + t.size(); ch != e; ++ch) { + if (ch + 1 < e && (ch->isHighSurrogate() || (ch->unicode() >= 48 && ch->unicode() < 58 || ch->unicode() == 35) && (ch + 1)->unicode() == 0x20E3)) { + emoji = getEmoji((ch->unicode() << 16) | (ch + 1)->unicode()); + if (emoji) { + if (emoji->len == 4 && (ch + 3 >= e || (((ch + 2)->unicode() << 16) | (ch + 3)->unicode()) != emoji->code2)) { + emoji = 0; + } else { + emojiPosition = p + (ch - t.constData()); + break; + } + } + ++ch; + } else { + emoji = getEmoji(ch->unicode()); + if (emoji) { + emojiPosition = p + (ch - t.constData()); + break; + } + } + } + if (emoji) break; + } + if (emoji) break; + } + if (emoji) { + QTextCursor c(doc->docHandle(), emojiPosition); + c.setPosition(emojiPosition + emoji->len, QTextCursor::KeepAnchor); + int32 removedUpto = c.position(); + + insertEmoji(emoji, c); + + for (Insertions::iterator i = _insertions.begin(), e = _insertions.end(); i != e; ++i) { + if (i->first >= removedUpto) { + i->first -= removedUpto - emojiPosition - 1; + } else if (i->first >= emojiPosition) { + i->second -= removedUpto - emojiPosition; + i->first = emojiPosition + 1; + } else if (i->first + i->second > emojiPosition + 1) { + i->second -= qMin(removedUpto, i->first + i->second) - emojiPosition; + } + } + + charsAdded -= removedUpto - position; + position = emojiPosition + 1; + + emoji = 0; + emojiPosition = 0; + } else { + break; + } + } +} + +void FlatTextarea::onDocumentContentsChange(int position, int charsRemoved, int charsAdded) { + if (_replacingEmojis || document()->availableRedoSteps() > 0) return; + + const int takeBack = 3; + + position -= takeBack; + charsAdded += takeBack; + if (position < 0) { + charsAdded += position; + position = 0; + } + if (charsAdded <= 0) return; + + _insertions.push_back(Insertion(position, charsAdded)); +} + +void FlatTextarea::onDocumentContentsChanged() { + if (_replacingEmojis) return; + + if (!_insertions.isEmpty()) { + if (document()->availableRedoSteps() > 0) { + _insertions.clear(); + } else { + _replacingEmojis = true; + do { + Insertion i = _insertions.front(); + _insertions.pop_front(); + if (i.second > 0) { + processDocumentContentsChange(i.first, i.second); + } + } while (!_insertions.isEmpty()); + _replacingEmojis = false; + } + } + + QString curText(getText()); + if (_oldtext != curText) { + _oldtext = curText; + emit changed(); + } + updatePlaceholder(); +} + +bool FlatTextarea::animStep(float64 ms) { + float dt = ms / _st.phDuration; + bool res = true; + if (dt >= 1) { + res = false; + a_phLeft.finish(); + a_phAlpha.finish(); + a_phColor.finish(); + a_phLeft = anim::ivalue(a_phLeft.current()); + a_phAlpha = anim::fvalue(a_phAlpha.current()); + a_phColor = anim::cvalue(a_phColor.current()); + } else { + a_phLeft.update(dt, _st.phLeftFunc); + a_phAlpha.update(dt, _st.phAlphaFunc); + a_phColor.update(dt, _st.phColorFunc); + } + update(); + return res; +} + +void FlatTextarea::updatePlaceholder() { + bool vis = !hasText(); + if (vis == _phVisible) return; + + a_phLeft.start(vis ? 0 : _st.phShift); + a_phAlpha.start(vis ? 1 : 0); + anim::start(this); + + _phVisible = vis; +} + +QMimeData *FlatTextarea::createMimeDataFromSelection() const { + QMimeData *result = new QMimeData(); + QTextCursor c(textCursor()); + int32 start = c.selectionStart(), end = c.selectionEnd(); + if (end > start) { + result->setText(getText(start, end)); + } + return result; +} + +void FlatTextarea::keyPressEvent(QKeyEvent *e) { + bool shift = e->modifiers().testFlag(Qt::ShiftModifier); + bool ctrl = e->modifiers().testFlag(Qt::ControlModifier), ctrlGood = ctrl && cCtrlEnter() || !ctrl && !shift && !cCtrlEnter(); + bool enter = (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return); + + if (enter && ctrlGood) { + emit submitted(); + } else if (e->key() == Qt::Key_Escape) { + emit cancelled(); + } else if (e->key() == Qt::Key_Tab) { + emit tabbed(); + } else { + QTextCursor tc(textCursor()); + if (enter && ctrl) { + e->setModifiers(e->modifiers() & ~Qt::ControlModifier); + } + QTextEdit::keyPressEvent(e); + if (tc == textCursor()) { + bool check = false; + if (e->key() == Qt::Key_PageUp || e->key() == Qt::Key_Up) { + tc.movePosition(QTextCursor::Start); + check = true; + } else if (e->key() == Qt::Key_PageDown || e->key() == Qt::Key_Down) { + tc.movePosition(QTextCursor::End); + check = true; + } + if (check) { + if (tc == textCursor()) { + e->ignore(); + } else { + setTextCursor(tc); + } + } + } + } +} + +void FlatTextarea::resizeEvent(QResizeEvent *e) { + _phelided = _st.font->m.elidedText(_ph, Qt::ElideRight, width() - _st.textMrg.left() - _st.textMrg.right() - _st.phPos.x() - 1); + QTextEdit::resizeEvent(e); +} + +void FlatTextarea::mousePressEvent(QMouseEvent *e) { + QTextEdit::mousePressEvent(e); +} diff --git a/Telegram/SourceFiles/gui/flattextarea.h b/Telegram/SourceFiles/gui/flattextarea.h new file mode 100644 index 000000000..88198444b --- /dev/null +++ b/Telegram/SourceFiles/gui/flattextarea.h @@ -0,0 +1,94 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "style.h" +#include "animation.h" + +class FlatTextarea : public QTextEdit, public Animated { + Q_OBJECT + +public: + + FlatTextarea(QWidget *parent, const style::flatTextarea &st, const QString &ph = QString(), const QString &val = QString()); + QString val() const; + + bool viewportEvent(QEvent *e); + void touchEvent(QTouchEvent *e); + void paintEvent(QPaintEvent *e); + void focusInEvent(QFocusEvent *e); + void focusOutEvent(QFocusEvent *e); + void keyPressEvent(QKeyEvent *e); + void resizeEvent(QResizeEvent *e); + void mousePressEvent(QMouseEvent *e); + + void updatePlaceholder(); + + QRect getTextRect() const; + + bool animStep(float64 ms); + + QSize sizeHint() const; + QSize minimumSizeHint() const; + + QString getText(int32 start = 0, int32 end = -1) const; + bool hasText() const; + +public slots: + + void onTouchTimer(); + + void onDocumentContentsChange(int position, int charsRemoved, int charsAdded); + void onDocumentContentsChanged(); + +signals: + + void changed(); + void submitted(); + void cancelled(); + void tabbed(); + +protected: + + void insertEmoji(EmojiPtr emoji, QTextCursor c); + +private: + + void processDocumentContentsChange(int position, int charsAdded); + + QMimeData *createMimeDataFromSelection() const; + + QString _ph, _phelided, _oldtext; + bool _phVisible; + anim::ivalue a_phLeft; + anim::fvalue a_phAlpha; + anim::cvalue a_phColor; + style::flatTextarea _st; + + int32 _fakeMargin; + + QTimer _touchTimer; + bool _touchPress, _touchRightButton, _touchMove; + QPoint _touchStart; + + bool _replacingEmojis; + typedef QPair Insertion; + typedef QList Insertions; + Insertions _insertions; +}; diff --git a/Telegram/SourceFiles/gui/images.cpp b/Telegram/SourceFiles/gui/images.cpp new file mode 100644 index 000000000..c523f7ee4 --- /dev/null +++ b/Telegram/SourceFiles/gui/images.cpp @@ -0,0 +1,295 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "gui/images.h" + +#include "mainwidget.h" + +namespace { + typedef QMap LocalImages; + LocalImages localImages; + + Image *blank() { + static Image *img = getImage(qsl(":/gui/art/blank.gif")); + return img; + } + + typedef QMap StorageImages; + StorageImages storageImages; + + QByteArray storageKey(int32 dc, const int64 &volume, int32 local, const int64 &secret) { + QByteArray result(24, Qt::Uninitialized); + memcpy(result.data(), &dc, 4); + memcpy(result.data() + 4, &volume, 8); + memcpy(result.data() + 12, &local, 4); + memcpy(result.data() + 16, &secret, 8); + return result; + } + + int64 globalAquiredSize = 0; +} + +bool Image::isNull() const { + return (this == blank()); +} + +ImagePtr::ImagePtr() : Parent(blank()) { +} + +ImagePtr::ImagePtr(int32 width, int32 height, const MTPFileLocation &location, ImagePtr def) : + Parent((location.type() == mtpc_fileLocation) ? (Image*)(getImage(width, height, location.c_fileLocation().vdc_id.v, location.c_fileLocation().vvolume_id.v, location.c_fileLocation().vlocal_id.v, location.c_fileLocation().vsecret.v)) : def.v()) { +} + +const QPixmap &Image::pix(int32 w, int32 h) const { + restore(); + checkload(); + + if (w <= 0 || !width() || !height()) w = width(); + uint64 k = (uint64(w) << 32) | uint64(h); + Sizes::const_iterator i = _sizesCache.constFind(k); + if (i == _sizesCache.cend()) { + QPixmap p(pixNoCache(w, h, true)); + i = _sizesCache.insert(k, p); + if (!p.isNull()) { + globalAquiredSize += int64(p.width()) * p.height() * 4; + } + } + return i.value(); +} + +QPixmap Image::pixNoCache(int32 w, int32 h, bool smooth) const { + restore(); + loaded(); + + const QPixmap &p(pixData()); + if (p.isNull()) return blank()->pix(); + + if (w <= 0 || !width() || !height() || w == width()) return p; + if (h <= 0) { + return QPixmap::fromImage(p.toImage().scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)); + } + return QPixmap::fromImage(p.toImage().scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)); +} + +void Image::forget() const { + if (forgot) return; + + const QPixmap &p(pixData()); + if (p.isNull()) return; + + invalidateSizeCache(); + if (saved.isEmpty()) { + QBuffer buffer(&saved); + p.save(&buffer, format); + } + globalAquiredSize -= int64(p.width()) * p.height() * 4; + doForget(); + forgot = true; +} + +void Image::restore() const { + if (!forgot) return; + doRestore(); + const QPixmap &p(pixData()); + if (!p.isNull()) { + globalAquiredSize += int64(p.width()) * p.height() * 4; + } + forgot = false; +} + +void Image::invalidateSizeCache() const { + for (Sizes::const_iterator i = _sizesCache.cbegin(), e = _sizesCache.cend(); i != e; ++i) { + if (!i->isNull()) { + globalAquiredSize -= int64(i->width()) * i->height() * 4; + } + } + _sizesCache.clear(); +} + +LocalImage::LocalImage(const QString &file) : data(file) { + if (!data.isNull()) { + globalAquiredSize += int64(data.width()) * data.height() * 4; + } +} + +LocalImage::LocalImage(const QPixmap &pixmap, QByteArray format) : Image(format), data(pixmap) { + if (!data.isNull()) { + globalAquiredSize += int64(data.width()) * data.height() * 4; + } +} + +const QPixmap &LocalImage::pixData() const { + return data; +} + +int32 LocalImage::width() const { + restore(); + return data.width(); +} + +int32 LocalImage::height() const { + restore(); + return data.height(); +} + +LocalImage *getImage(const QString &file) { + LocalImages::const_iterator i = localImages.constFind(file); + if (i == localImages.cend()) { + i = localImages.insert(file, new LocalImage(file)); + } + return i.value(); +} + +LocalImage::~LocalImage() { + if (!data.isNull()) { + globalAquiredSize -= int64(data.width()) * data.height() * 4; + } +} + +LocalImage *getImage(const QPixmap &pixmap, QByteArray format) { + return new LocalImage(pixmap, format); +} + +void clearStorageImages() { + for (StorageImages::const_iterator i = storageImages.cbegin(), e = storageImages.cend(); i != e; ++i) { + delete i.value(); + } + storageImages.clear(); +} + +void clearAllImages() { + for (LocalImages::const_iterator i = localImages.cbegin(), e = localImages.cend(); i != e; ++i) { + delete i.value(); + } + localImages.clear(); + clearStorageImages(); +} + +int64 imageCacheSize() { + return globalAquiredSize; +} + +StorageImage::StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret) : loader(new mtpFileLoader(dc, volume, local, secret)), w(width), h(height) { +} + +StorageImage::StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, QByteArray &bytes) : loader(0), w(width), h(height) { + setData(bytes); +} + +const QPixmap &StorageImage::pixData() const { + return data; +} + +int32 StorageImage::width() const { + return w; +} + +int32 StorageImage::height() const { + return h; +} + +bool StorageImage::check() const { + if (loader->done()) { + switch (loader->fileType()) { + case mtpc_storage_fileGif: format = "GIF"; break; + case mtpc_storage_fileJpeg: format = "JPG"; break; + case mtpc_storage_filePng: format = "PNG"; break; + default: format = QByteArray(); break; + } + if (!data.isNull()) { + globalAquiredSize -= int64(data.width()) * data.height() * 4; + } + QByteArray bytes = loader->bytes(); + data = QPixmap::fromImage(App::readImage(bytes, &format), Qt::ColorOnly); + if (!data.isNull()) { + globalAquiredSize += int64(data.width()) * data.height() * 4; + } + + w = data.width(); + h = data.height(); + invalidateSizeCache(); + loader->deleteLater(); + loader = 0; + + saved = bytes; + forgot = false; + return true; + } + return false; +} + +void StorageImage::setData(QByteArray &bytes, const QByteArray &format) { + QBuffer buffer(&bytes); + + QImageReader reader(&buffer, format); + if (!data.isNull()) { + globalAquiredSize -= int64(data.width()) * data.height() * 4; + } + data = QPixmap::fromImageReader(&reader, Qt::ColorOnly); + if (!data.isNull()) { + globalAquiredSize += int64(data.width()) * data.height() * 4; + } + + w = data.width(); + h = data.height(); + invalidateSizeCache(); + if (loader) { + loader->deleteLater(); + loader = 0; + } + this->saved = bytes; + this->format = reader.format(); + forgot = false; +} + +StorageImage::~StorageImage() { + if (!data.isNull()) { + globalAquiredSize -= int64(data.width()) * data.height() * 4; + } + if (loader) { + loader->deleteLater(); + loader = 0; + } +} + +bool StorageImage::loaded() const { + if (!loader) return true; + return check(); +} + +StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret) { + QByteArray key(storageKey(dc, volume, local, secret)); + StorageImages::const_iterator i = storageImages.constFind(key); + if (i == storageImages.cend()) { + i = storageImages.insert(key, new StorageImage(width, height, dc, volume, local, secret)); + } + return i.value(); +} + +StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, const QByteArray &bytes) { + QByteArray key(storageKey(dc, volume, local, secret)); + StorageImages::const_iterator i = storageImages.constFind(key); + if (i == storageImages.cend()) { + QByteArray bytesArr(bytes); + i = storageImages.insert(key, new StorageImage(width, height, dc, volume, local, secret, bytesArr)); + } else if (!i.value()->loaded()) { + QByteArray bytesArr(bytes); + i.value()->setData(bytesArr); + } + return i.value(); +} diff --git a/Telegram/SourceFiles/gui/images.h b/Telegram/SourceFiles/gui/images.h new file mode 100644 index 000000000..00dbce459 --- /dev/null +++ b/Telegram/SourceFiles/gui/images.h @@ -0,0 +1,168 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include + +class Image { +public: + + Image(QByteArray format = "PNG") : forgot(false), format(format) { + } + virtual bool loaded() const { + return true; + } + const QPixmap &pix(int32 w = 0, int32 h = 0) const; + QPixmap pixNoCache(int32 w = 0, int32 h = 0, bool smooth = false) const; + + virtual int32 width() const = 0; + virtual int32 height() const = 0; + + virtual void load(bool loadFirst = false, bool prior = true) { + } + + virtual void checkload() const { + } + + bool isNull() const; + + void forget() const; + void restore() const; + + virtual ~Image() { + invalidateSizeCache(); + } + +protected: + + virtual const QPixmap &pixData() const = 0; + virtual void doForget() const = 0; + virtual void doRestore() const = 0; + + void invalidateSizeCache() const; + + mutable QByteArray saved, format; + mutable bool forgot; + +private: + + typedef QMap Sizes; + mutable Sizes _sizesCache; + +}; + +class LocalImage : public Image { +public: + + LocalImage(const QString &file); + LocalImage(const QPixmap &pixmap, QByteArray format); + + int32 width() const; + int32 height() const; + + ~LocalImage(); + +protected: + + const QPixmap &pixData() const; + void doForget() const { + data = QPixmap(); + } + void doRestore() const { + QBuffer buffer(&saved); + QImageReader reader(&buffer, format); + data = QPixmap::fromImageReader(&reader, Qt::ColorOnly); + } + +private: + + mutable QPixmap data; +}; + +LocalImage *getImage(const QString &file); +LocalImage *getImage(const QPixmap &pixmap, QByteArray format); + +class StorageImage : public Image { +public: + + StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret); + StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, QByteArray &bytes); + + int32 width() const; + int32 height() const; + bool loaded() const; + void setData(QByteArray &bytes, const QByteArray &format = "JPG"); + + void load(bool loadFirst = false, bool prior = true) { + if (loader) { + loader->start(loadFirst, prior); + check(); + } + } + void checkload() const { + if (loader) { + if (!loader->loading()) { + loader->start(true); + } + check(); + } + } + + ~StorageImage(); + +protected: + + const QPixmap &pixData() const; + bool check() const; + void doForget() const { + data = QPixmap(); + } + void doRestore() const { + QBuffer buffer(&saved); + QImageReader reader(&buffer, format); + data = QPixmap::fromImageReader(&reader, Qt::ColorOnly); + } + +private: + + mutable QPixmap data; + mutable int32 w, h; + mutable mtpFileLoader *loader; +}; + +StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret); +StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, const QByteArray &bytes); +Image *getImage(int32 width, int32 height, const MTPFileLocation &location); + +class ImagePtr : public ManagedPtr { +public: + ImagePtr(); + ImagePtr(const QString &file) : Parent(getImage(file)) { + } + ImagePtr(const QPixmap &pixmap, QByteArray format) : Parent(getImage(pixmap, format)) { + } + ImagePtr(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret) : Parent(getImage(width, height, dc, volume, local, secret)) { + } + ImagePtr(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, const QByteArray &bytes) : Parent(getImage(width, height, dc, volume, local, secret, bytes)) { + } + ImagePtr(int32 width, int32 height, const MTPFileLocation &location, ImagePtr def = ImagePtr()); +}; + +void clearStorageImages(); +void clearAllImages(); +int64 imageCacheSize(); diff --git a/Telegram/SourceFiles/gui/phoneinput.cpp b/Telegram/SourceFiles/gui/phoneinput.cpp new file mode 100644 index 000000000..9695337c0 --- /dev/null +++ b/Telegram/SourceFiles/gui/phoneinput.cpp @@ -0,0 +1,96 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" + +#include "gui/phoneinput.h" + +PhoneInput::PhoneInput(QWidget *parent, const style::flatInput &st, const QString &ph) : FlatInput(parent, st, ph) { +} + +void PhoneInput::correctValue(QKeyEvent *e, const QString &was) { + if (e && e->key() == Qt::Key_Backspace && !was.length()) { + emit voidBackspace(e); + return; + } + QString oldText(text()), newText; + int oldPos(cursorPosition()), newPos(-1), oldLen(oldText.length()), digitCount = 0; + for (int i = 0; i < oldLen; ++i) { + if (oldText[i].isDigit()) { + ++digitCount; + } + } + if (digitCount > MaxPhoneTailLength) digitCount = MaxPhoneTailLength; + bool strict = (digitCount == MaxPhoneTailLength); + + newText.reserve(oldLen); + for (int i = 0; i < oldLen; ++i) { + QChar ch(oldText[i]); + if (ch.isDigit()) { + if (!digitCount--) { + break; + } + newText += ch; + if (strict && !digitCount) { + break; + } + } else if (ch == ' ' || ch == '-' || ch == '(' || ch == ')') { + newText += ch; + } + if (i == oldPos) { + newPos = newText.length(); + } + } + if (newPos < 0) { + newPos = newText.length(); + } + if (newText != oldText) { + setText(newText); + if (newPos != oldPos) { + setCursorPosition(newPos); + } + } +} + +void PhoneInput::addedToNumber(const QString &added) { + setFocus(); + QString was(text()); + setText(added + text()); + setCursorPosition(added.length()); + correctValue(0, was); + updatePlaceholder(); +} + +PortInput::PortInput(QWidget *parent, const style::flatInput &st, const QString &ph, const QString &val) : FlatInput(parent, st, ph, val) { + correctValue(0, QString()); +} + +void PortInput::correctValue(QKeyEvent *e, const QString &was) { + QString oldText(text()), newText(oldText); + + newText.replace(QRegularExpression(qsl("[^\\d]")), QString()); + if (!newText.toInt()) { + newText = QString(); + } else if (newText.toInt() > 65535) { + newText = was; + } + if (newText != oldText) { + setText(newText); + updatePlaceholder(); + } +} diff --git a/Telegram/SourceFiles/gui/phoneinput.h b/Telegram/SourceFiles/gui/phoneinput.h new file mode 100644 index 000000000..abadd6787 --- /dev/null +++ b/Telegram/SourceFiles/gui/phoneinput.h @@ -0,0 +1,54 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "gui/flatinput.h" + +class PhoneInput : public FlatInput { + Q_OBJECT + +public: + + PhoneInput(QWidget *parent, const style::flatInput &st, const QString &ph); + +public slots: + + void addedToNumber(const QString &added); + +signals: + + void voidBackspace(QKeyEvent *e); + +protected: + + void correctValue(QKeyEvent *e, const QString &was); + +}; + +class PortInput : public FlatInput { + Q_OBJECT + +public: + + PortInput(QWidget *parent, const style::flatInput &st, const QString &ph, const QString &val); + +protected: + + void correctValue(QKeyEvent *e, const QString &was); + +}; diff --git a/Telegram/SourceFiles/gui/scrollarea.cpp b/Telegram/SourceFiles/gui/scrollarea.cpp new file mode 100644 index 000000000..dffe381c6 --- /dev/null +++ b/Telegram/SourceFiles/gui/scrollarea.cpp @@ -0,0 +1,597 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" + +#include "gui/scrollarea.h" + +// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html + +ScrollShadow::ScrollShadow(ScrollArea *parent, const style::flatScroll *st) : QWidget(parent), _st(st) { + setVisible(false); +} + +void ScrollShadow::paintEvent(QPaintEvent *e) { + QPainter p(this); + p.fillRect(rect(), _st->shColor->b); +} + +void ScrollShadow::changeVisibility(bool shown) { + setVisible(shown); +} + +ScrollBar::ScrollBar(ScrollArea *parent, bool vert, const style::flatScroll *st) : QWidget(parent), + _st(st), _area(parent), _vertical(vert), _hideIn(-1), + _over(false), _overbar(false), _moving(false), _topSh(false), _bottomSh(false), + a_bg((_st->hiding ? st::transparent : _st->bgColor)->c), a_bar((_st->hiding ? st::transparent : _st->barColor)->c), + _connected(vert ? parent->verticalScrollBar() : parent->horizontalScrollBar()), _scrollMax(_connected->maximum()) { + recountSize(); + + _hideTimer.setSingleShot(true); + connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideTimer())); + + connect(_connected, SIGNAL(valueChanged(int)), this, SLOT(updateBar())); + connect(_connected, SIGNAL(rangeChanged(int, int)), this, SLOT(updateBar())); + + updateBar(); +} + +void ScrollBar::recountSize() { + setGeometry(_vertical ? QRect(_area->width() - _st->width, 0, _st->width, _area->height()) : QRect(0, _area->height() - _st->width, _area->width(), _st->width)); +} + +void ScrollBar::updateBar() { + QRect newBar; + if (_connected->maximum() != _scrollMax) { + int32 oldMax = _scrollMax, newMax = _connected->maximum(); + _scrollMax = newMax; + _area->rangeChanged(oldMax, newMax, _vertical); + } + if (_vertical) { + int sh = _area->scrollHeight(), rh = height() - 2 * _st->deltay, h = sh ? int32((rh * int64(_area->height())) / sh) : 0; + if (h >= rh || !_area->scrollTopMax() || rh < _st->minHeight) { + if (!isHidden()) hide(); + if (_topSh) emit topShadowVisibility(_topSh = (_st->topsh < 0)); + if (_bottomSh) emit bottomShadowVisibility(_bottomSh = (_st->bottomsh < 0)); + return; + } + + if (h <= _st->minHeight) h = _st->minHeight; + int stm = _area->scrollTopMax(), y = stm ? int32(((rh - h) * int64(_area->scrollTop())) / stm) : 0; + if (y > rh - h) y = rh - h; + + newBar = QRect(_st->deltax, y + _st->deltay, width() - 2 * _st->deltax, h); + } else { + int sw = _area->scrollWidth(), rw = width() - 2 * _st->deltay, w = sw ? int32((rw * int64(_area->width())) / sw) : 0; + if (w >= rw || !_area->scrollLeftMax() || rw < _st->minHeight) { + if (!isHidden()) hide(); + return; + } + + if (w <= _st->minHeight) w = _st->minHeight; + int slm = _area->scrollLeftMax(), x = slm ? int32(((rw - w) * int64(_area->scrollLeft())) / slm) : 0; + if (x > rw - w) x = rw - w; + + newBar = QRect(x + _st->deltay, _st->deltax, w, height() - 2 * _st->deltax); + } + if (newBar != _bar) { + _bar = newBar; + update(); + } + if (_vertical) { + bool newTopSh = (_st->topsh < 0) || (_area->scrollTop() > _st->topsh), newBottomSh = (_st->bottomsh < 0) || (_area->scrollTop() < _area->scrollTopMax() - _st->bottomsh); + if (newTopSh != _topSh) emit topShadowVisibility(_topSh = newTopSh); + if (newBottomSh != _bottomSh) emit bottomShadowVisibility(_bottomSh = newBottomSh); + } + if (isHidden()) show(); +} + +void ScrollBar::onHideTimer() { + _hideIn = -1; + a_bg.start(st::transparent->c); + a_bar.start(st::transparent->c); + anim::start(this); +} + +void ScrollBar::paintEvent(QPaintEvent *e) { + if (!_bar.width() && !_bar.height()) { + hide(); + return; + } + if (!a_bg.current().alpha() && !a_bar.current().alpha()) return; + QPainter p(this); + + int32 deltax = _vertical ? _st->deltax : _st->deltay, deltay = _vertical ? _st->deltay : _st->deltax; + p.setPen(Qt::NoPen); + if (_st->round) { + p.setBrush(a_bg.current()); + p.drawRoundedRect(QRect(deltax, deltay, width() - 2 * deltax, height() - 2 * deltay), _st->round, _st->round); + p.setBrush(a_bar.current()); + p.drawRoundedRect(_bar, _st->round, _st->round); + } else { + p.fillRect(QRect(deltax, deltay, width() - 2 * deltax, height() - 2 * deltay), a_bg.current()); + p.fillRect(_bar, a_bar.current()); + } +} + +bool ScrollBar::animStep(float64 ms) { + float64 dt = ms / _st->duration; + bool res = true; + if (dt >= 1) { + a_bg.finish(); + a_bar.finish(); + res = false; + } else { + a_bg.update(dt, anim::linear); + a_bar.update(dt, anim::linear); + } + update(); + return res; +} + +void ScrollBar::hideTimeout(int64 dt) { + if (_hideIn < 0) { + a_bg.start((_over ? _st->bgOverColor : _st->bgColor)->c); + a_bar.start((_overbar ? _st->barOverColor : _st->barColor)->c); + anim::start(this); + } + _hideIn = dt; + if (!_moving && _hideIn >= 0) { + _hideTimer.start(_hideIn); + } +} + +void ScrollBar::enterEvent(QEvent *e) { + _hideTimer.stop(); + setMouseTracking(true); + _over = true; + a_bg.start(_st->bgOverColor->c); + a_bar.start(_st->barColor->c); + anim::start(this); +} + +void ScrollBar::leaveEvent(QEvent *e) { + if (!_moving) { + setMouseTracking(false); + a_bg.start(_st->bgColor->c); + a_bar.start(_st->barColor->c); + anim::start(this); + if (_hideIn >= 0) { + _hideTimer.start(_hideIn); + } + } + _over = _overbar = false; +} + +void ScrollBar::mouseMoveEvent(QMouseEvent *e) { + bool newOverBar = _bar.contains(e->pos()); + if (_overbar != newOverBar) { + _overbar = newOverBar; + if (!_moving) { + a_bar.start((newOverBar ? _st->barOverColor : _st->barColor)->c); + a_bg.start(_st->bgOverColor->c); + anim::start(this); + } + } + if (_moving) { + int delta = 0, barDelta = _vertical ? (_area->height() - _bar.height()) : (_area->width() - _bar.width()); + if (barDelta) { + QPoint d = (e->globalPos() - _dragStart); + delta = int32((_vertical ? (d.y() * int64(_area->scrollTopMax())) : (d.x() * int64(_area->scrollLeftMax()))) / barDelta); + } + _connected->setValue(_startFrom + delta); + } +} + +void ScrollBar::mousePressEvent(QMouseEvent *e) { + if (!width() || !height()) return; + + _dragStart = e->globalPos(); + _moving = true; + if (_overbar) { + _startFrom = _connected->value(); + } else { + _startFrom = _vertical ? int32((e->pos().y() * int64(_area->scrollTopMax())) / height()) : ((e->pos().x() * int64(_area->scrollLeftMax())) / width()); + _connected->setValue(_startFrom); + if (!_overbar) { + _overbar = true; + a_bar.start(_st->barOverColor->c); + a_bg.start(_st->bgOverColor->c); + anim::start(this); + } + } + emit _area->scrollStarted(); +} + +void ScrollBar::mouseReleaseEvent(QMouseEvent *e) { + if (_moving) { + _moving = false; + bool a = false; + if (!_overbar) { + if (!_over || _hideIn) { + a_bar.start(_st->barColor->c); + a = true; + } + } + if (!_over) { + if (_hideIn) { + a_bg.start(_st->bgColor->c); + a = true; + } + if (_hideIn >= 0) { + _hideTimer.start(_hideIn); + } + } + if (a) anim::start(this); + emit _area->scrollFinished(); + } + if (!_over) { + setMouseTracking(false); + } +} + +void ScrollBar::resizeEvent(QResizeEvent *e) { + updateBar(); +} + +ScrollArea::ScrollArea(QWidget *parent, const style::flatScroll &st, bool handleTouch) : QScrollArea(parent), _st(st), _touchEnabled(handleTouch), + hor(this, false, &_st), vert(this, true, &_st), topSh(this, &_st), bottomSh(this, &_st), + _touchScroll(false), _touchPress(false), _touchRightButton(false), _widgetAcceptsTouch(false), + _touchScrollState(TouchScrollManual), _touchPrevPosValid(false), _touchWaitingAcceleration(false), _touchSpeedTime(0), _touchAccelerationTime(0), _touchTime(0) { + connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SIGNAL(scrolled())); + connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SIGNAL(scrolled())); + connect(&vert, SIGNAL(topShadowVisibility(bool)), &topSh, SLOT(changeVisibility(bool))); + connect(&vert, SIGNAL(bottomShadowVisibility(bool)), &bottomSh, SLOT(changeVisibility(bool))); + if (_st.hiding) { + connect(this, SIGNAL(scrolled()), this, SLOT(onScrolled())); + } + + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + setFrameStyle(QFrame::NoFrame | QFrame::Plain); + viewport()->setAutoFillBackground(false); + + _horValue = horizontalScrollBar()->value(); + _vertValue = verticalScrollBar()->value(); + + if (_touchEnabled) { + viewport()->setAttribute(Qt::WA_AcceptTouchEvents); + _touchTimer.setSingleShot(true); + connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer())); + connect(&_touchScrollTimer, SIGNAL(timeout()), this, SLOT(onTouchScrollTimer())); + } +} + +void ScrollArea::touchDeaccelerate(int32 elapsed) { + int32 x = _touchSpeed.x(); + int32 y = _touchSpeed.y(); + _touchSpeed.setX((x == 0) ? x : (x > 0) ? qMax(0, x - elapsed) : qMin(0, x + elapsed)); + _touchSpeed.setY((y == 0) ? y : (y > 0) ? qMax(0, y - elapsed) : qMin(0, y + elapsed)); +} + +void ScrollArea::onScrolled() { + int32 horValue = horizontalScrollBar()->value(), vertValue = verticalScrollBar()->value(); + if (_horValue != horValue) { + _horValue = horValue; + if (_st.hiding) { + hor.hideTimeout(_st.hiding); + } + } + if (_vertValue != vertValue) { + _vertValue = vertValue; + if (_st.hiding) { + vert.hideTimeout(_st.hiding); + } + } +} + +int ScrollArea::scrollWidth() const { + return scrollLeftMax() + width(); +} + +int ScrollArea::scrollHeight() const { + return scrollTopMax() + height(); +} + +int ScrollArea::scrollLeftMax() const { + return horizontalScrollBar()->maximum(); +} + +int ScrollArea::scrollTopMax() const { + return verticalScrollBar()->maximum(); +} + +int ScrollArea::scrollLeft() const { + return horizontalScrollBar()->value(); +} + +int ScrollArea::scrollTop() const { + return verticalScrollBar()->value(); +} + +void ScrollArea::onTouchTimer() { + _touchRightButton = true; +} + +void ScrollArea::onTouchScrollTimer() { + uint64 nowTime = getms(); + if (_touchScrollState == TouchScrollAcceleration && _touchWaitingAcceleration && (nowTime - _touchAccelerationTime) > 40) { + _touchScrollState = TouchScrollManual; + touchResetSpeed(); + } else if (_touchScrollState == TouchScrollAuto || _touchScrollState == TouchScrollAcceleration) { + int32 elapsed = int32(nowTime - _touchTime); + QPoint delta = _touchSpeed * elapsed / 1000; + bool hasScrolled = touchScroll(delta); + + if (_touchSpeed.isNull() || !hasScrolled) { + _touchScrollState = TouchScrollManual; + _touchScroll = false; + _touchScrollTimer.stop(); + } else { + _touchTime = nowTime; + } + touchDeaccelerate(elapsed); + } +} + +void ScrollArea::touchUpdateSpeed() { + const uint64 nowTime = getms(); + if (_touchPrevPosValid) { + const int elapsed = nowTime - _touchSpeedTime; + if (elapsed) { + const QPoint newPixelDiff = (_touchPos - _touchPrevPos); + const QPoint pixelsPerSecond = newPixelDiff * (1000 / elapsed); + + // fingers are inacurates, we ignore small changes to avoid stopping the autoscroll because + // of a small horizontal offset when scrolling vertically + const int newSpeedY = (qAbs(pixelsPerSecond.y()) > FingerAccuracyThreshold) ? pixelsPerSecond.y() : 0; + const int newSpeedX = (qAbs(pixelsPerSecond.x()) > FingerAccuracyThreshold) ? pixelsPerSecond.x() : 0; + if (_touchScrollState == TouchScrollAuto) { + const int oldSpeedY = _touchSpeed.y(); + const int oldSpeedX = _touchSpeed.x(); + if ((oldSpeedY <= 0 && newSpeedY <= 0) || (oldSpeedY >= 0 && newSpeedY >= 0) + && (oldSpeedX <= 0 && newSpeedX <= 0) || (oldSpeedX >= 0 && newSpeedX >= 0)) { + _touchSpeed.setY(snap((oldSpeedY + (newSpeedY / 4)), -MaxScrollAccelerated, +MaxScrollAccelerated)); + _touchSpeed.setX(snap((oldSpeedX + (newSpeedX / 4)), -MaxScrollAccelerated, +MaxScrollAccelerated)); + } else { + _touchSpeed = QPoint(); + } + } else { + // we average the speed to avoid strange effects with the last delta + if (!_touchSpeed.isNull()) { + _touchSpeed.setX(snap((_touchSpeed.x() / 4) + (newSpeedX * 3 / 4), -MaxScrollFlick, +MaxScrollFlick)); + _touchSpeed.setY(snap((_touchSpeed.y() / 4) + (newSpeedY * 3 / 4), -MaxScrollFlick, +MaxScrollFlick)); + } else { + _touchSpeed = QPoint(newSpeedX, newSpeedY); + } + } + } + } else { + _touchPrevPosValid = true; + } + _touchSpeedTime = nowTime; + _touchPrevPos = _touchPos; +} + +void ScrollArea::touchResetSpeed() { + _touchSpeed = QPoint(); + _touchPrevPosValid = false; +} + +bool ScrollArea::eventFilter(QObject *obj, QEvent *e) { + bool res = QScrollArea::eventFilter(obj, e); + if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { + QTouchEvent *ev = static_cast(e); + if (_touchEnabled && ev->device()->type() == QTouchDevice::TouchScreen) { + if (obj == widget()) { + touchEvent(ev); + return true; + } + } + } + return res; +} + +bool ScrollArea::viewportEvent(QEvent *e) { + if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { + QTouchEvent *ev = static_cast(e); + if (_touchEnabled && ev->device()->type() == QTouchDevice::TouchScreen) { + touchEvent(ev); + return true; + } + } + return QScrollArea::viewportEvent(e); +} + +void ScrollArea::touchEvent(QTouchEvent *e) { + if (!e->touchPoints().isEmpty()) { + _touchPrevPos = _touchPos; + _touchPos = e->touchPoints().cbegin()->screenPos().toPoint(); + } + + switch (e->type()) { + case QEvent::TouchBegin: + if (_touchPress || e->touchPoints().isEmpty()) return; + _touchPress = true; + if (_touchScrollState == TouchScrollAuto) { + _touchScrollState = TouchScrollAcceleration; + _touchWaitingAcceleration = true; + _touchAccelerationTime = getms(); + touchUpdateSpeed(); + _touchStart = _touchPos; + } else { + _touchScroll = false; + _touchTimer.start(QApplication::startDragTime()); + } + _touchStart = _touchPrevPos = _touchPos; + _touchRightButton = false; + break; + + case QEvent::TouchUpdate: + if (!_touchPress) return; + if (!_touchScroll && (_touchPos - _touchStart).manhattanLength() >= QApplication::startDragDistance()) { + _touchTimer.stop(); + _touchScroll = true; + touchUpdateSpeed(); + } + if (_touchScroll) { + if (_touchScrollState == TouchScrollManual) { + touchScrollUpdated(_touchPos); + } else if (_touchScrollState == TouchScrollAcceleration) { + touchUpdateSpeed(); + _touchAccelerationTime = getms(); + if (_touchSpeed.isNull()) { + _touchScrollState = TouchScrollManual; + } + } + } + break; + + case QEvent::TouchEnd: + if (!_touchPress) return; + _touchPress = false; + if (_touchScroll) { + if (_touchScrollState == TouchScrollManual) { + _touchScrollState = TouchScrollAuto; + _touchPrevPosValid = false; + _touchScrollTimer.start(15); + _touchTime = getms(); + } else if (_touchScrollState == TouchScrollAuto) { + _touchScrollState = TouchScrollManual; + _touchScroll = false; + touchResetSpeed(); + } else if (_touchScrollState == TouchScrollAcceleration) { + _touchScrollState = TouchScrollAuto; + _touchWaitingAcceleration = false; + _touchPrevPosValid = false; + } + } else if (window() && widget()) { // one short tap -- like left mouse click, one long tap -- like right mouse click +#ifdef Q_OS_WIN + Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton); + QPoint mapped(widget()->mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart)); + + QMouseEvent pressEvent(QEvent::MouseButtonPress, mapped, winMapped, _touchStart, btn, Qt::MouseButtons(btn), Qt::KeyboardModifiers()); + pressEvent.accept(); + qt_sendSpontaneousEvent(widget(), &pressEvent); + + QMouseEvent releaseEvent(QEvent::MouseButtonRelease, mapped, winMapped, _touchStart, btn, Qt::MouseButtons(btn), Qt::KeyboardModifiers()); + qt_sendSpontaneousEvent(widget(), &releaseEvent); + + if (_touchRightButton) { + QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart); + qt_sendSpontaneousEvent(widget(), &contextEvent); + } +#endif + } + _touchTimer.stop(); + _touchRightButton = false; + break; + + case QEvent::TouchCancel: + _touchPress = false; + _touchScroll = false; + _touchScrollState = TouchScrollManual; + _touchTimer.stop(); + break; + } +} + +void ScrollArea::touchScrollUpdated(const QPoint &screenPos) { + _touchPos = screenPos; + touchScroll(_touchPos - _touchPrevPos); + touchUpdateSpeed(); +} + +bool ScrollArea::touchScroll(const QPoint &delta) { + int32 scTop = scrollTop(), scMax = scrollTopMax(), scNew = snap(scTop - delta.y(), 0, scMax); + if (scNew == scTop) return false; + + scrollToY(scNew); + return true; +} + +void ScrollArea::resizeEvent(QResizeEvent *e) { + QScrollArea::resizeEvent(e); + hor.recountSize(); + vert.recountSize(); + topSh.setGeometry(QRect(0, 0, width(), qAbs(_st.topsh))); + bottomSh.setGeometry(QRect(0, height() - qAbs(_st.bottomsh), width(), qAbs(_st.bottomsh))); + emit geometryChanged(); +} + +void ScrollArea::moveEvent(QMoveEvent *e) { + QScrollArea::moveEvent(e); + emit geometryChanged(); +} + +void ScrollArea::enterEvent(QEvent *e) { + if (_st.hiding) { + hor.hideTimeout(_st.hiding); + vert.hideTimeout(_st.hiding); + } +} + +void ScrollArea::leaveEvent(QEvent *e) { + if (_st.hiding) { + hor.hideTimeout(0); + vert.hideTimeout(0); + } +} + +void ScrollArea::scrollToY(int toTop, int toBottom) { + int toMin = 0, toMax = scrollTopMax(); + if (toTop < toMin) { + toTop = toMin; + } else if (toTop > toMax) { + toTop = toMax; + } + bool exact = (toBottom < 0); + + int curTop = scrollTop(), curHeight = height(), curBottom = curTop + curHeight, scToTop = toTop; + if (!exact && toTop >= curTop) { + if (toBottom < toTop) toBottom = toTop; + if (toBottom <= curBottom) return; + + scToTop = toBottom - curHeight; + if (scToTop > toTop) scToTop = toTop; + if (scToTop == curTop) return; + } else { + scToTop = toTop; + } + verticalScrollBar()->setValue(scToTop); +} + +void ScrollArea::setWidget(QWidget *w) { + if (widget() && _touchEnabled) { + widget()->removeEventFilter(this); + if (!_widgetAcceptsTouch) widget()->setAttribute(Qt::WA_AcceptTouchEvents, false); + } + QScrollArea::setWidget(w); + if (w) { + w->setAutoFillBackground(false); + if (_touchEnabled) { + w->installEventFilter(this); + _widgetAcceptsTouch = w->testAttribute(Qt::WA_AcceptTouchEvents); + w->setAttribute(Qt::WA_AcceptTouchEvents); + } + } +} + +void ScrollArea::rangeChanged(int oldMax, int newMax, bool vertical) { +} diff --git a/Telegram/SourceFiles/gui/scrollarea.h b/Telegram/SourceFiles/gui/scrollarea.h new file mode 100644 index 000000000..f74f2e7b7 --- /dev/null +++ b/Telegram/SourceFiles/gui/scrollarea.h @@ -0,0 +1,174 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "style.h" + +enum TouchScrollState { + TouchScrollManual, // Scrolling manually with the finger on the screen + TouchScrollAuto, // Scrolling automatically + TouchScrollAcceleration // Scrolling automatically but a finger is on the screen +}; + +class ScrollArea; + +class ScrollShadow : public QWidget { + Q_OBJECT + +public: + + ScrollShadow(ScrollArea *parent, const style::flatScroll *st); + + void paintEvent(QPaintEvent *e); + +public slots: + + void changeVisibility(bool shown); + +private: + + const style::flatScroll *_st; + +}; + +class ScrollBar : public QWidget, public Animated { + Q_OBJECT + +public: + + ScrollBar(ScrollArea *parent, bool vertical, const style::flatScroll *st); + + void recountSize(); + + void paintEvent(QPaintEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void resizeEvent(QResizeEvent *e); + + bool animStep(float64 ms); + + void hideTimeout(int64 dt); + +public slots: + + void updateBar(); + void onHideTimer(); + +signals: + + void topShadowVisibility(bool); + void bottomShadowVisibility(bool); + +private: + + ScrollArea *_area; + const style::flatScroll *_st; + + bool _vertical; + bool _over, _overbar, _moving; + bool _topSh, _bottomSh; + + QPoint _dragStart; + QScrollBar *_connected; + + int32 _startFrom, _scrollMax; + + int64 _hideIn; + QTimer _hideTimer; + + anim::cvalue a_bg, a_bar; + QRect _bar; +}; + +class ScrollArea : public QScrollArea { + Q_OBJECT + +public: + + ScrollArea(QWidget *parent, const style::flatScroll &st = st::scrollDef, bool handleTouch = true); + + bool viewportEvent(QEvent *e); + void touchEvent(QTouchEvent *e); + + bool eventFilter(QObject *obj, QEvent *e); + + void resizeEvent(QResizeEvent *e); + void moveEvent(QMoveEvent *e); + + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + + int scrollWidth() const; + int scrollHeight() const; + int scrollLeftMax() const; + int scrollTopMax() const; + int scrollLeft() const; + int scrollTop() const; + + void setWidget(QWidget *widget); + + void rangeChanged(int oldMax, int newMax, bool vertical); + +public slots: + + void scrollToY(int toTop, int toBottom = -1); + void onScrolled(); + + void onTouchTimer(); + void onTouchScrollTimer(); + +signals: + + void scrolled(); + void scrollStarted(); + void scrollFinished(); + void geometryChanged(); + +private: + + bool touchScroll(const QPoint &delta); + + void touchScrollUpdated(const QPoint &screenPos); + + void touchResetSpeed(); + void touchUpdateSpeed(); + void touchDeaccelerate(int32 elapsed); + + style::flatScroll _st; + ScrollBar hor, vert; + ScrollShadow topSh, bottomSh; + int32 _horValue, _vertValue; + + bool _touchEnabled; + QTimer _touchTimer; + bool _touchScroll, _touchPress, _touchRightButton; + QPoint _touchStart, _touchPrevPos, _touchPos; + + TouchScrollState _touchScrollState; + bool _touchPrevPosValid, _touchWaitingAcceleration; + QPoint _touchSpeed; + uint64 _touchSpeedTime, _touchAccelerationTime, _touchTime; + QTimer _touchScrollTimer; + + bool _widgetAcceptsTouch; + +}; diff --git a/Telegram/SourceFiles/gui/style_core.cpp b/Telegram/SourceFiles/gui/style_core.cpp new file mode 100644 index 000000000..93b252759 --- /dev/null +++ b/Telegram/SourceFiles/gui/style_core.cpp @@ -0,0 +1,178 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" + +namespace { + typedef QMap FontFamilyMap; + FontFamilyMap _fontFamilyMap; +} + +namespace style { + FontData::FontData(uint32 size, uint32 flags, uint32 family, Font *other) : _size(size), _flags(flags), _family(family), f(_fontFamilies[family]), m(f) { + if (other) { + memcpy(modified, other, sizeof(modified)); + } else { + memset(modified, 0, sizeof(modified)); + } + modified[_flags] = Font(this); + + f.setPixelSize(size); + f.setBold(_flags & FontBold); + f.setItalic(_flags & FontItalic); + f.setUnderline(_flags & FontUnderline); + f.setStyleStrategy(QFont::PreferQuality); + + m = QFontMetrics(f); + height = m.height(); + ascent = m.ascent(); + descent = m.descent(); + spacew = m.width(QLatin1Char(' ')); + elidew = m.width(QLatin1Char('.')) * 3; + } + + Font FontData::bold(bool set) const { + return otherFlagsFont(FontBold, set); + } + + Font FontData::italic(bool set) const { + return otherFlagsFont(FontItalic, set); + } + + Font FontData::underline(bool set) const { + return otherFlagsFont(FontUnderline, set); + } + + uint32 FontData::flags() const { + return _flags; + } + + Font FontData::otherFlagsFont(uint32 flag, bool set) const { + int32 newFlags = set ? (_flags | flag) : (_flags & ~flag); + if (!modified[newFlags].v()) { + modified[newFlags] = Font(_size, newFlags, _family, modified); + } + return modified[newFlags]; + } + + Font::Font(uint32 size, uint32 flags, const QString &family) { + if (_fontFamilyMap.isEmpty()) { + for (uint32 i = 0, s = style::_fontFamilies.size(); i != s; ++i) { + _fontFamilyMap.insert(style::_fontFamilies.at(i), i); + } + } + + FontFamilyMap::const_iterator i = _fontFamilyMap.constFind(family); + if (i == _fontFamilyMap.cend()) { + style::_fontFamilies.push_back(family); + i = _fontFamilyMap.insert(family, style::_fontFamilies.size() - 1); + } + init(i.value(), size, flags, 0); + } + + Font::Font(uint32 size, uint32 flags, uint32 family) { + init(size, flags, family, 0); + } + + Font::Font(uint32 size, uint32 flags, uint32 family, Font *modified) { + init(size, flags, family, modified); + } + + void Font::init(uint32 size, uint32 flags, uint32 family, Font *modified) { + uint32 key = _fontKey(size, flags, family); + FontDatas::const_iterator i = _fontsMap.constFind(key); + if (i == _fontsMap.cend()) { + i = _fontsMap.insert(key, new FontData(size, flags, family, modified)); + } + ptr = i.value(); + } + + Color::Color(const Color &c) : ptr(c.owner ? new ColorData(*c.ptr) : c.ptr), owner(c.owner) { + } + + Color::Color(const QColor &c) : owner(false) { + init(c.red(), c.green(), c.blue(), c.alpha()); + } + + Color::Color(uchar r, uchar g, uchar b, uchar a) : owner(false) { + init(r, g, b, a); + } + + Color &Color::operator=(const Color &c) { + if (this != &c) { + if (owner) { + delete ptr; + } + ptr = c.owner ? new ColorData(*c.ptr) : c.ptr; + owner = c.owner; + } + return *this; + } + + void Color::set(const QColor &newv) { + if (!owner) { + ptr = new ColorData(*ptr); + owner = true; + } + ptr->set(newv); + } + + void Color::set(uchar r, uchar g, uchar b, uchar a) { + if (!owner) { + ptr = new ColorData(*ptr); + owner = true; + } + ptr->set(QColor(r, g, b, a)); + } + + void Color::init(uchar r, uchar g, uchar b, uchar a) { + uint32 key = _colorKey(r, g, b, a); + ColorDatas::const_iterator i = _colorsMap.constFind(key); + if (i == _colorsMap.cend()) { + i = _colorsMap.insert(key, new ColorData(r, g, b, a)); + } + ptr = i.value(); + } + + Color::~Color() { + if (owner) { + delete ptr; + } + } + + ColorData::ColorData(uchar r, uchar g, uchar b, uchar a) : c(int(r), int(g), int(b), int(a)), p(c), b(c) { + } + + void ColorData::set(const QColor &color) { + c = color; + p = QPen(color); + b = QBrush(color); + } + + void stopManager() { + for (FontDatas::const_iterator i = _fontsMap.cbegin(), e = _fontsMap.cend(); i != e; ++i) { + delete i.value(); + } + _fontsMap.clear(); + + for (ColorDatas::const_iterator i = _colorsMap.cbegin(), e = _colorsMap.cend(); i != e; ++i) { + delete i.value(); + } + _colorsMap.clear(); + } + +}; diff --git a/Telegram/SourceFiles/gui/style_core.h b/Telegram/SourceFiles/gui/style_core.h new file mode 100644 index 000000000..746009829 --- /dev/null +++ b/Telegram/SourceFiles/gui/style_core.h @@ -0,0 +1,236 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "gui/animation.h" + +#include +#include +#include +#include +#include +#include + +namespace style { + + class FontData; + class Font { + public: + Font(Qt::Initialization = Qt::Uninitialized) : ptr(0) { + } + Font(uint32 size, uint32 flags, const QString &family); + Font(uint32 size, uint32 flags = 0, uint32 family = 0); + + Font &operator=(const Font &other) { + ptr = other.ptr; + return (*this); + } + + FontData *operator->() const { + return ptr; + } + FontData *v() const { + return ptr; + } + + operator bool() const { + return !!ptr; + } + + private: + FontData *ptr; + + void init(uint32 size, uint32 flags, uint32 family, Font *modified); + friend void startManager(); + + Font(FontData *p) : ptr(p) { + } + Font(uint32 size, uint32 flags, uint32 family, Font *modified); + friend class FontData; + + }; + + enum FontFlagBits { + FontBoldBit, + FontItalicBit, + FontUnderlineBit, + + FontFlagsBits + }; + + enum FontFlags { + FontBold = (1 << FontBoldBit), + FontItalic = (1 << FontItalicBit), + FontUnderline = (1 << FontUnderlineBit), + + FontDifferentFlags = (1 << FontFlagsBits) + }; + + inline uint32 _fontKey(uint32 size, uint32 flags, uint32 family) { + return (((family << 10) | size) << FontFlagsBits) | flags; + } + + class FontData { + public: + + int32 width(const QString &str, int32 from, int32 to) { + return m.width(str.mid(from, to)); + } + + Font bold(bool set = true) const; + Font italic(bool set = true) const; + Font underline(bool set = true) const; + + uint32 flags() const; + + QFont f; + QFontMetrics m; + int32 height, ascent, descent, spacew, elidew; + + private: + mutable Font modified[FontDifferentFlags]; + + Font otherFlagsFont(uint32 flag, bool set) const; + FontData(uint32 size, uint32 flags, uint32 family, Font *other); + + friend class Font; + uint32 _size, _flags, _family; + + }; + +inline bool operator==(const Font &a, const Font &b) { + return a.v() == b.v(); +} +inline bool operator!=(const Font &a, const Font &b) { + return a.v() != b.v(); +} + + class ColorData; + class Color { + public: + Color(Qt::Initialization = Qt::Uninitialized) : ptr(0), owner(false) { + } + Color(const Color &c); + Color(const QColor &c); + Color(uchar r, uchar g, uchar b, uchar a = 255); + Color &operator=(const Color &c); + ~Color(); + + void set(const QColor &newv); + void set(uchar r, uchar g, uchar b, uchar a = 255); + + ColorData *operator->() const { + return ptr; + } + ColorData *v() const { + return ptr; + } + + operator bool() const { + return !!ptr; + } + + private: + ColorData *ptr; + bool owner; + + void init(uchar r, uchar g, uchar b, uchar a); + + friend void startManager(); + + Color(ColorData *p) : ptr(p) { + } + friend class ColorData; + + }; + + inline uint32 _colorKey(uchar r, uchar g, uchar b, uchar a) { + return (((((uint32(r) << 8) | uint32(g)) << 8) | uint32(b)) << 8) | uint32(a); + } + + class ColorData { + public: + + QColor c; + QPen p; + QBrush b; + + private: + + ColorData(uchar r, uchar g, uchar b, uchar a); + void set(const QColor &c); + + friend class Color; + + }; + + inline bool operator==(const Color &a, const Color &b) { + return a->c == b->c; + } + + inline bool operator!=(const Color &a, const Color &b) { + return a->c != b->c; + } + + + typedef QVector FontFamilies; + extern FontFamilies _fontFamilies; + + typedef QMap FontDatas; + extern FontDatas _fontsMap; + + typedef QMap ColorDatas; + extern ColorDatas _colorsMap; + + typedef float64 number; + typedef QString string; + typedef QRect rect; + typedef QPoint point; + typedef QSize size; + typedef anim::transition transition; + + typedef Qt::CursorShape cursor; + static const cursor cur_default(Qt::ArrowCursor); + static const cursor cur_pointer(Qt::PointingHandCursor); + static const cursor cur_text(Qt::IBeamCursor); + static const cursor cur_cross(Qt::CrossCursor); + static const cursor cur_sizever(Qt::SizeVerCursor); + static const cursor cur_sizehor(Qt::SizeHorCursor); + static const cursor cur_sizebdiag(Qt::SizeBDiagCursor); + static const cursor cur_sizefdiag(Qt::SizeFDiagCursor); + static const cursor cur_sizeall(Qt::SizeAllCursor); + + typedef Qt::Alignment align; + static const align al_topleft(Qt::AlignTop | Qt::AlignLeft); + static const align al_top(Qt::AlignTop | Qt::AlignHCenter); + static const align al_topright(Qt::AlignTop | Qt::AlignRight); + static const align al_right(Qt::AlignVCenter | Qt::AlignRight); + static const align al_bottomright(Qt::AlignBottom | Qt::AlignRight); + static const align al_bottom(Qt::AlignBottom | Qt::AlignHCenter); + static const align al_bottomleft(Qt::AlignBottom | Qt::AlignLeft); + static const align al_left(Qt::AlignVCenter | Qt::AlignLeft); + static const align al_center(Qt::AlignVCenter | Qt::AlignHCenter); + + typedef QMargins margins; + typedef Font font; + typedef Color color; + + void startManager(); + void stopManager(); + +}; diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp new file mode 100644 index 000000000..1571d46c6 --- /dev/null +++ b/Telegram/SourceFiles/gui/text.cpp @@ -0,0 +1,4043 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "text.h" + +#include "lang.h" + +#include + +namespace { + + inline bool chIsSpace(QChar ch, bool rich = false) { + return ch.isSpace() || (ch < 32 && !(rich && ch == TextCommand)) || (ch == QChar::ParagraphSeparator) || (ch == QChar::LineSeparator) || (ch == QChar::ObjectReplacementCharacter) || (ch == QChar::SoftHyphen) || (ch == QChar::CarriageReturn) || (ch == QChar::Tabulation); + } + inline bool chIsBad(QChar ch) { + return (ch == 0) || (ch >= 8232 && ch < 8239) || (ch >= 65024 && ch < 65040) || (ch >= 127 && ch < 160 && ch != 156); + } + inline bool chIsTrimmed(QChar ch, bool rich = false) { + return (!rich || ch != TextCommand) && (chIsSpace(ch) || chIsBad(ch)); + } + inline bool chIsDiac(QChar ch) { // diac and variation selectors + return (ch >= 768 && ch < 880) || (ch >= 7616 && ch < 7680) || (ch >= 8400 && ch < 8448) || (ch >= 65056 && ch < 65072); + } + inline int32 chMaxDiacAfterSymbol() { + return 4; + } + inline bool chIsNewline(QChar ch) { + return (ch == QChar::LineFeed || ch == 156); + } + inline bool chIsLinkEnd(QChar ch) { + return ch == TextCommand || chIsBad(ch) || chIsSpace(ch) || chIsNewline(ch) || ch.isLowSurrogate() || ch.isHighSurrogate(); + } + inline bool chIsAlmostLinkEnd(QChar ch) { + switch (ch.unicode()) { + case '?': + case ',': + case '.': + case '"': + case ':': + case '!': + case '\'': + return true; + default: + break; + } + return false; + } + inline bool chIsWordSeparator(QChar ch) { + switch (ch.unicode()) { + case QChar::Space: + case QChar::LineFeed: + case '.': + case ',': + case '?': + case '!': + case '@': + case '#': + case '$': + case ':': + case ';': + case '-': + case '<': + case '>': + case '[': + case ']': + case '(': + case ')': + case '{': + case '}': + case '=': + case '/': + case '+': + case '%': + case '&': + case '^': + case '*': + case '\'': + case '"': + case '`': + case '~': + case '|': + return true; + default: + break; + } + return false; + } + inline bool chIsParagraphSeparator(QChar ch) { + switch (ch.unicode()) { + case QChar::LineFeed: + return true; + default: + break; + } + return false; + } + + const QRegularExpression reDomain(QString::fromUtf8("(? validProtocols, validTopDomains; + void initLinkSets(); + + const style::textStyle *_textStyle = 0; + + TextLinkPtr _overLnk, _downLnk, _zeroLnk; + + void _initDefault() { + _textStyle = &st::defaultTextStyle; + } + + inline int32 _blockHeight(const ITextBlock *b, const style::font &font) { + return (b->type() == TextBlockSkip) ? static_cast(b)->height() : (_textStyle->lineHeight > font->height) ? _textStyle->lineHeight : font->height; + } + + inline QFixed _blockRBearing(const ITextBlock *b) { + return (b->type() == TextBlockText) ? static_cast(b)->f_rbearing() : 0; + } +} + +const style::textStyle *textstyleCurrent() { + return _textStyle; +} + +void textstyleSet(const style::textStyle *style) { + _textStyle = style ? style : &st::defaultTextStyle; +} + +void textlnkOver(const TextLinkPtr &lnk) { + _overLnk = lnk; +} + +const TextLinkPtr &textlnkOver() { + return _overLnk; +} + +void textlnkDown(const TextLinkPtr &lnk) { + _downLnk = lnk; +} + +const TextLinkPtr &textlnkDown() { + return _downLnk; +} + +QString textOneLine(const QString &text, bool trim, bool rich) { + QString result(text); + const QChar *s = text.unicode(), *ch = s, *e = text.unicode() + text.size(); + if (trim) { + while (s < e && chIsTrimmed(*s)) { + ++s; + } + while (s < e && chIsTrimmed(*(e - 1))) { + --e; + } + if (e - s != text.size()) { + result = text.mid(s - text.unicode(), e - s); + } + } + for (const QChar *ch = s; ch != e; ++ch) { + if (chIsNewline(*ch)) { + result[int(ch - s)] = QChar::Space; + } + } + return result; +} + +QString textClean(const QString &text) { + QString result(text); + for (const QChar *s = text.unicode(), *ch = s, *e = text.unicode() + text.size(); ch != e; ++ch) { + if (*ch == TextCommand) { + result[int(ch - s)] = QChar::Space; + } + } + return result; +} + +QString textRichPrepare(const QString &text) { + QString result; + result.reserve(text.size()); + const QChar *s = text.constData(), *ch = s; + for (const QChar *e = s + text.size(); ch != e; ++ch) { + if (*ch == TextCommand) { + if (ch > s) result.append(s, ch - s); + result.append(QChar::Space); + s = ch + 1; + continue; + } + if (ch->unicode() == '\\' || ch->unicode() == '[') { + if (ch > s) result.append(s, ch - s); + result.append('\\'); + s = ch; + continue; + } + } + if (ch > s) result.append(s, ch - s); + return result; +} + +QString textcmdSkipBlock(ushort w, ushort h) { + static QString cmd(5, TextCommand); + cmd[1] = QChar(TextCommandSkipBlock); + cmd[2] = QChar(w); + cmd[3] = QChar(h); + return cmd; +} + +QString textcmdStartLink(ushort lnkIndex) { + static QString cmd(4, TextCommand); + cmd[1] = QChar(TextCommandLinkIndex); + cmd[2] = QChar(lnkIndex); + return cmd; +} + +QString textcmdStartLink(const QString &url) { + if (url.size() >= 4096) return QString(); + + QString result; + result.reserve(url.size() + 4); + return result.append(TextCommand).append(QChar(TextCommandLinkText)).append(QChar(url.size())).append(url).append(TextCommand); +} + +QString textcmdStopLink() { + return textcmdStartLink(0); +} + +QString textcmdLink(ushort lnkIndex, const QString &text) { + QString result; + result.reserve(4 + text.size() + 4); + return result.append(textcmdStartLink(lnkIndex)).append(text).append(textcmdStopLink()); +} + +QString textcmdLink(const QString &url, const QString &text) { + QString result; + result.reserve(4 + url.size() + text.size() + 4); + return result.append(textcmdStartLink(url)).append(text).append(textcmdStopLink()); +} + +QString textcmdStartColor(const style::color &color) { + QString result; + result.reserve(7); + return result.append(TextCommand).append(QChar(TextCommandColor)).append(QChar(color->c.red())).append(QChar(color->c.green())).append(QChar(color->c.blue())).append(QChar(color->c.alpha())).append(TextCommand); +} + +QString textcmdStopColor() { + QString result; + result.reserve(3); + return result.append(TextCommand).append(QChar(TextCommandNoColor)).append(TextCommand); +} + +class TextParser { + struct LinkRange { + LinkRange() : from(0), len(0) { + } + const QChar *from; + int32 len; + }; + +public: + + static Qt::LayoutDirection stringDirection(const QString &str, int32 from, int32 to) { + const ushort *p = reinterpret_cast(str.unicode()) + from; + const ushort *end = p + (to - from); + while (p < end) { + uint ucs4 = *p; + if (QChar::isHighSurrogate(ucs4) && p < end - 1) { + ushort low = p[1]; + if (QChar::isLowSurrogate(low)) { + ucs4 = QChar::surrogateToUcs4(ucs4, low); + ++p; + } + } + switch (QChar::direction(ucs4)) { + case QChar::DirL: + return Qt::LeftToRight; + case QChar::DirR: + case QChar::DirAL: + return Qt::RightToLeft; + default: + break; + } + ++p; + } + return Qt::LayoutDirectionAuto; + } + + void prepareLinks() { // support emails! + if (validProtocols.empty()) { + initLinkSets(); + } + int32 len = src.size(), nextCmd = rich ? 0 : len; + const QChar *srcData = src.unicode(); + for (int32 offset = 0; offset < len; ) { + if (nextCmd <= offset) { + for (nextCmd = offset; nextCmd < len; ++nextCmd) { + if (*(srcData + nextCmd) == TextCommand) { + break; + } + } + } + QRegularExpressionMatch mDomain = reDomain.match(src, offset); + if (!mDomain.hasMatch()) break; + + int32 domainOffset = mDomain.capturedStart(), domainEnd = mDomain.capturedEnd(); + if (domainOffset > nextCmd) { + const QChar *after = skipCommand(srcData + nextCmd, srcData + len); + if (after > srcData + nextCmd && domainOffset < (after - srcData)) { + nextCmd = offset = after - srcData; + continue; + } + } + + QString protocol = mDomain.captured(1).toLower(); + QString topDomain = mDomain.captured(3).toLower(); + + bool isProtocolValid = protocol.isEmpty() || validProtocols.contains(hashCrc32(protocol.constData(), protocol.size() * sizeof(QChar))); + bool isTopDomainValid = validTopDomains.contains(hashCrc32(topDomain.constData(), topDomain.size() * sizeof(QChar))); + + if (!isProtocolValid || !isTopDomainValid) { + offset = domainEnd; + continue; + } + + LinkRange link; + if (protocol.isEmpty() && domainOffset > offset + 1 && *(start + domainOffset - 1) == QChar('@')) { + QString forMailName = src.mid(offset, domainOffset - offset - 1); + QRegularExpressionMatch mMailName = reMailName.match(forMailName); + if (mMailName.hasMatch()) { + int32 mailOffset = offset + mMailName.capturedStart(); + if (mailOffset < offset) { + mailOffset = offset; + } + link.from = start + mailOffset; + link.len = domainEnd - mailOffset; + } + } + if (!link.from || !link.len) { + link.from = start + domainOffset; + + QStack parenth; + const QChar *p = start + mDomain.capturedEnd(); + for (; p < end; ++p) { + QChar ch(*p); + if (chIsLinkEnd(ch)) break; // link finished + if (chIsAlmostLinkEnd(ch)) { + const QChar *endTest = p + 1; + while (endTest < end && chIsAlmostLinkEnd(*endTest)) { + ++endTest; + } + if (endTest >= end || chIsLinkEnd(*endTest)) { + break; // link finished at p + } + p = endTest; + ch = *p; + } + if (ch == '(' || ch == '[' || ch == '{' || ch == '<') { + parenth.push(p); + } else if (ch == ')' || ch == ']' || ch == '}' || ch == '>') { + if (parenth.isEmpty()) break; + const QChar *q = parenth.pop(), open(*q); + if (ch == ')' && open != '(' || ch == ']' && open != '[' || ch == '}' && open != '{' || ch == '>' && open != '<') { + p = q; + break; + } + } + } + + link.len = p - link.from; + } + lnkRanges.push_back(link); + + offset = (link.from - start) + link.len; + } + } + + void blockCreated() { + sumWidth += _t->_blocks.back()->f_width(); + if (sumWidth.toInt() > stopAfterWidth) { + sumFinished = true; + } + } + + void createBlock(int32 skipBack = 0) { + if (lnkIndex < 0x8000 && lnkIndex > maxLnkIndex) maxLnkIndex = lnkIndex; + int32 len = int32(_t->_text.size()) + skipBack - blockStart; + if (len > 0) { + lastSkipped = lastSpace = false; + if (emoji) { + _t->_blocks.push_back(new EmojiBlock(_t->_font, _t->_text, blockStart, len, flags, color, lnkIndex, emoji)); + emoji = 0; + lastSkipped = true; + } else if (len == 1 && _t->_text.at(blockStart) == QChar::LineFeed) { + _t->_blocks.push_back(new NewlineBlock(_t->_font, _t->_text, blockStart, len)); + } else { + _t->_blocks.push_back(new TextBlock(_t->_font, _t->_text, _t->_minResizeWidth, blockStart, len, flags, color, lnkIndex)); + } + blockStart += len; + blockCreated(); + } + } + + void createSkipBlock(int32 w, int32 h) { + createBlock(); + _t->_text.push_back('_'); + _t->_blocks.push_back(new SkipBlock(_t->_font, _t->_text, blockStart++, w, h, lnkIndex)); + blockCreated(); + } + + void getLinkData(const QString &original, QString &result, int32 &fullDisplayed) { + if (reMailStart.match(original).hasMatch()) { + result = original; + fullDisplayed = -1; + } else { + QUrl url(original), good(url.isValid() ? url.toEncoded() : ""); + QString readable = good.isValid() ? good.toDisplayString() : original; + result = _t->_font->m.elidedText(readable, Qt::ElideRight, LinkCropLimit); + fullDisplayed = (result == readable) ? 1 : 0; + } + } + + bool checkWaitedLink() { + if (waitingLink == linksEnd || ptr < waitingLink->from || links.size() >= 0x7FFF) { + return true; + } + + createBlock(); + + QString lnkUrl = QString(waitingLink->from, waitingLink->len), lnkText; + int32 fullDisplayed; + getLinkData(lnkUrl, lnkText, fullDisplayed); + + links.push_back(TextLinkData(lnkUrl, fullDisplayed)); + lnkIndex = 0x8000 + links.size(); + + _t->_text += lnkText; + ptr = waitingLink->from + waitingLink->len; + + createBlock(); + ++waitingLink; + lnkIndex = 0; + + return true; + } + + const QChar *skipCommand(const QChar *from, const QChar *end) { + const QChar *result = from + 1; + if (*from != TextCommand || result >= end) return from; + + ushort cmd = result->unicode(); + ++result; + if (result >= end) return from; + + switch (cmd) { + case TextCommandBold: + case TextCommandNoBold: + case TextCommandItalic: + case TextCommandNoItalic: + case TextCommandUnderline: + case TextCommandNoUnderline: + case TextCommandNoColor: + break; + + case TextCommandLinkIndex: + if (result->unicode() > 0x7FFF) return from; + ++result; + break; + + case TextCommandLinkText: { + ushort len = result->unicode(); + if (len >= 4096 || links.size() >= 0x7FFF) return from; + result += len + 1; + } break; + + case TextCommandColor: { + const QChar *e = result + 4; + if (e >= end) return from; + + for (; result < e; ++result) { + if (result->unicode() >= 256) return from; + } + } break; + + case TextCommandSkipBlock: + result += 2; + break; + } + return (result < end && *result == TextCommand) ? (result + 1) : from; + } + + bool readCommand() { + const QChar *afterCmd = skipCommand(ptr, end); + if (afterCmd == ptr) { + return false; + } + + ushort cmd = (++ptr)->unicode(); + ++ptr; + + switch (cmd) { + case TextCommandBold: + if (!(flags & TextBlockBold)) { + createBlock(); + flags |= TextBlockBold; + } + break; + + case TextCommandNoBold: + if (flags & TextBlockBold) { + createBlock(); + flags &= ~TextBlockBold; + } + break; + + case TextCommandItalic: + if (!(flags & TextBlockItalic)) { + createBlock(); + flags |= TextBlockItalic; + } + break; + + case TextCommandNoItalic: + if (flags & TextBlockItalic) { + createBlock(); + flags &= ~TextBlockItalic; + } + break; + + case TextCommandUnderline: + if (!(flags & TextBlockUnderline)) { + createBlock(); + flags |= TextBlockUnderline; + } + break; + + case TextCommandNoUnderline: + if (flags & TextBlockUnderline) { + createBlock(); + flags &= ~TextBlockUnderline; + } + break; + + case TextCommandLinkIndex: + if (ptr->unicode() != lnkIndex) { + createBlock(); + lnkIndex = ptr->unicode(); + } + break; + + case TextCommandLinkText: { + createBlock(); + int32 len = ptr->unicode(); + links.push_back(TextLinkData(QString(++ptr, len), false)); + lnkIndex = 0x8000 + links.size(); + } break; + + case TextCommandColor: { + style::color c(ptr->unicode(), (ptr + 1)->unicode(), (ptr + 2)->unicode(), (ptr + 3)->unicode()); + if (color != c) { + createBlock(); + color = c; + } + } break; + + case TextCommandSkipBlock: + createBlock(); + createSkipBlock(ptr->unicode(), (ptr + 1)->unicode()); + break; + + case TextCommandNoColor: + if (color) { + createBlock(); + color = style::color(); + } + break; + } + + ptr = afterCmd; + return true; + } + + void parseCurrentChar() { + ch = ((ptr < end) ? *ptr : 0); + while (rich && ch == TextCommand) { + if (readCommand()) { + ch = ((ptr < end) ? *ptr : 0); + } else { + ch = QChar::Space; + } + } + + int skipBack = 0; + chInt = ch.unicode(); + bool skip = false, isNewLine = multiline && chIsNewline(ch), isSpace = chIsSpace(ch, rich), isDiac = chIsDiac(ch); + if (chIsBad(ch) || ch.isLowSurrogate()) { + skip = true; + } else if (isDiac) { + if (lastSkipped || lastSpace || emoji || ++diacs > chMaxDiacAfterSymbol()) { + skip = true; + } + } else if (isSpace && lastSpace && !isNewLine) { + skip = true; + } else if (ch.isHighSurrogate()) { + if (ptr + 1 >= end || !(ptr + 1)->isLowSurrogate()) { + skip = true; + } else { + _t->_text.push_back(ch); + skipBack = -1; + ++ptr; + ch = *ptr; + chInt = (chInt << 16) | ch.unicode(); + } + } else if (ch >= 48 && ch < 58 || ch == 35) { // check for digit emoji + if (ptr + 1 < end && (ptr + 1)->unicode() == 0x20E3) { + _t->_text.push_back(ch); + skipBack = -1; + ++ptr; + ch = *ptr; + chInt = (chInt << 16) | 0x20E3; + } + } + + lastSkipped = skip; + lastSpace = isSpace; + if (skip) { + ch = 0; + } else { + if (isNewLine) { + createBlock(); + _t->_text.push_back(QChar::LineFeed); + createBlock(); + } else if (isSpace) { + _t->_text.push_back(QChar::Space); + } else { + if (emoji) createBlock(skipBack); + _t->_text.push_back(ch); + } + if (!isDiac) diacs = 0; + } + } + + void parseEmojiFromCurrent() { + const EmojiData *e = getEmoji(chInt); + if (!e) return; + + if (e->len > 2) { + if (ptr + 2 >= end || e->code2 != (((ptr + 1)->unicode() << 16) | (ptr + 2)->unicode())) { + return; + } else { + _t->_text.push_back(*++ptr); + _t->_text.push_back(*++ptr); + } + } + + createBlock(-e->len); + emoji = e; + } + + TextParser(Text *t, const QString &text, const TextParseOptions &options) : _t(t), src(text), stopAfterWidth(QFIXED_MAX), + rich(options.flags & TextParseRichText), multiline(options.flags & TextParseMultiline), flags(0), lnkIndex(0), maxLnkIndex(0) { + int flags = options.flags; + if (options.maxw > 0 && options.maxh > 0) { + stopAfterWidth = ((options.maxh / _t->_font->height) + 1) * options.maxw; + } + + start = src.constData(); + end = start + src.size(); + + if (options.flags & TextParseLinks) { + prepareLinks(); + } + + while (start != end && chIsTrimmed(*start, rich)) { + ++start; + } + while (start != end && chIsTrimmed(*(end - 1), rich)) { + --end; + } + + _t->_text.resize(0); + _t->_text.reserve(end - start); + + diacs = 0; + sumWidth = 0; + sumFinished = false; + blockStart = 0; + emoji = 0; + + ch = chInt = 0; + lastSkipped = false; + lastSpace = true; + waitingLink = lnkRanges.isEmpty() ? 0 : lnkRanges.constData(); + linksEnd = lnkRanges.isEmpty() ? 0 : waitingLink + lnkRanges.size(); + for (ptr = start; ptr <= end; ++ptr) { + if (!checkWaitedLink()) { + break; + } + parseCurrentChar(); + + parseEmojiFromCurrent(); + + if (sumFinished || _t->_text.size() >= 0x8000) break; // 32k max + } + createBlock(); + + _t->_links.resize(maxLnkIndex); + for (Text::TextBlocks::const_iterator i = _t->_blocks.cbegin(), e = _t->_blocks.cend(); i != e; ++i) { + ITextBlock *b = *i; + if (b->lnkIndex() > 0x8000) { + lnkIndex = maxLnkIndex + (b->lnkIndex() - 0x8000); + if (_t->_links.size() < lnkIndex) { + _t->_links.resize(lnkIndex); + const TextLinkData &data(links[lnkIndex - maxLnkIndex - 1]); + TextLinkPtr lnk; + if (data.fullDisplayed < 0) { // email + lnk = TextLinkPtr(new EmailLink(data.url)); + } else { + lnk = TextLinkPtr(new TextLink(data.url, data.fullDisplayed > 0)); + } + _t->setLink(lnkIndex, lnk); + } + b->setLnkIndex(lnkIndex); + } + } + _t->_links.squeeze(); + _t->_blocks.squeeze(); + _t->_text.squeeze(); + } + +private: + + Text *_t; + const QString &src; + const QChar *start, *end, *ptr; + bool rich, multiline; + + typedef QVector LinkRanges; + LinkRanges lnkRanges; + const LinkRange *waitingLink, *linksEnd; + + struct TextLinkData { + TextLinkData(const QString &url = QString(), int32 fullDisplayed = 1) : url(url), fullDisplayed(fullDisplayed) { + } + QString url; + int32 fullDisplayed; // < 0 - email + }; + typedef QVector TextLinks; + TextLinks links; + + uint16 maxLnkIndex; + + // current state + int32 flags; + uint16 lnkIndex; + const EmojiData *emoji; // current emoji, if current word is an emoji, or zero + int32 blockStart; // offset in result, from which current parsed block is started + int32 diacs; // diac chars skipped without good char + QFixed sumWidth, stopAfterWidth; // summary width of all added words + bool sumFinished; + style::color color; // current color, could be invalid + + // current char data + QChar ch; // current char (low surrogate, if current char is surrogate pair) + uint32 chInt; // full ch, could be surrogate pair + bool lastSkipped; // did we skip current char + bool lastSpace; // was last char a space character +}; + +namespace { + // COPIED FROM qtextengine.cpp AND MODIFIED + + struct BidiStatus { + BidiStatus() { + eor = QChar::DirON; + lastStrong = QChar::DirON; + last = QChar:: DirON; + dir = QChar::DirON; + } + QChar::Direction eor; + QChar::Direction lastStrong; + QChar::Direction last; + QChar::Direction dir; + }; + + enum { _MaxBidiLevel = 61 }; + enum { _MaxItemLength = 4096 }; + + struct BidiControl { + inline BidiControl(bool rtl) + : cCtx(0), base(rtl ? 1 : 0), level(rtl ? 1 : 0), override(false) {} + + inline void embed(bool rtl, bool o = false) { + unsigned int toAdd = 1; + if((level%2 != 0) == rtl ) { + ++toAdd; + } + if (level + toAdd <= _MaxBidiLevel) { + ctx[cCtx].level = level; + ctx[cCtx].override = override; + cCtx++; + override = o; + level += toAdd; + } + } + inline bool canPop() const { return cCtx != 0; } + inline void pdf() { + Q_ASSERT(cCtx); + --cCtx; + level = ctx[cCtx].level; + override = ctx[cCtx].override; + } + + inline QChar::Direction basicDirection() const { + return (base ? QChar::DirR : QChar:: DirL); + } + inline unsigned int baseLevel() const { + return base; + } + inline QChar::Direction direction() const { + return ((level%2) ? QChar::DirR : QChar:: DirL); + } + + struct { + unsigned int level; + bool override; + } ctx[_MaxBidiLevel]; + unsigned int cCtx; + const unsigned int base; + unsigned int level; + bool override; + }; + + static void eAppendItems(QScriptAnalysis *analysis, int &start, int &stop, const BidiControl &control, QChar::Direction dir) { + if (start > stop) + return; + + int level = control.level; + + if(dir != QChar::DirON && !control.override) { + // add level of run (cases I1 & I2) + if(level % 2) { + if(dir == QChar::DirL || dir == QChar::DirAN || dir == QChar::DirEN) + level++; + } else { + if(dir == QChar::DirR) + level++; + else if(dir == QChar::DirAN || dir == QChar::DirEN) + level += 2; + } + } + + QScriptAnalysis *s = analysis + start; + const QScriptAnalysis *e = analysis + stop; + while (s <= e) { + s->bidiLevel = level; + ++s; + } + ++stop; + start = stop; + } + +} + +class TextPainter { +public: + + static inline uint16 _blockEnd(const Text *t, const Text::TextBlocks::const_iterator &i, const Text::TextBlocks::const_iterator &e) { + return (i + 1 == e) ? t->_text.size() : (*(i + 1))->from(); + } + static inline uint16 _blockLength(const Text *t, const Text::TextBlocks::const_iterator &i, const Text::TextBlocks::const_iterator &e) { + return _blockEnd(t, i, e) - (*i)->from(); + } + + TextPainter(QPainter *p, const Text *t) : _p(p), _t(t), _elideLast(false), _elideSavedBlock(0), _lnkResult(0), _inTextFlag(0), _getSymbol(0), _getSymbolAfter(0), _getSymbolUpon(0), _str(0) { + } + + void initNextParagraph(Text::TextBlocks::const_iterator i) { + _parStartBlock = i; + Text::TextBlocks::const_iterator e = _t->_blocks.cend(); + if (i == e) { + _parStart = _t->_text.size(); + _parLength = 0; + } else { + _parStart = (*i)->from(); + for (; i != e; ++i) { + if ((*i)->type() == TextBlockNewline) { + break; + } + } + _parLength = ((i == e) ? _t->_text.size() : (*i)->from()) - _parStart; + } + _parAnalysis.resize(0); + } + + void initParagraphBidi() { + if (!_parLength || !_parAnalysis.isEmpty()) return; + + Text::TextBlocks::const_iterator i = _parStartBlock, e = _t->_blocks.cend(), n = i + 1; + + bool ignore = false; + bool rtl = (_parDirection == Qt::RightToLeft); + if (!ignore && !rtl) { + ignore = true; + const ushort *start = reinterpret_cast(_str) + _parStart; + const ushort *curr = start; + const ushort *end = start + _parLength; + while (curr < end) { + while (n != e && (*n)->from() <= _parStart + (curr - start)) { + i = n; + ++n; + } + if ((*i)->type() != TextBlockEmoji && *curr >= 0x590) { + ignore = false; + break; + } + ++curr; + } + } + + _parAnalysis.resize(_parLength); + QScriptAnalysis *analysis = _parAnalysis.data(); + + BidiControl control(rtl); + + _parHasBidi = false; + if (ignore) { + memset(analysis, 0, _parLength * sizeof(QScriptAnalysis)); + if (rtl) { + for (int i = 0; i < _parLength; ++i) + analysis[i].bidiLevel = 1; + _parHasBidi = true; + } + } else { + _parHasBidi = eBidiItemize(analysis, control); + } + } + + void draw(int32 left, int32 top, int32 w, style::align align, int32 yFrom, int32 yTo, uint16 selectedFrom = 0, uint16 selectedTo = 0) { + if (_t->_blocks.isEmpty()) return; + + _blocksSize = _t->_blocks.size(); + if (!_textStyle) _initDefault(); + + if (_p) { + _p->setFont(_t->_font->f); + _originalPen = _p->pen(); + } + + _x = left; + _y = top; + _yFrom = yFrom + top; + _yTo = (yTo < 0) ? -1 : (yTo + top); + _selectedFrom = selectedFrom; + _selectedTo = selectedTo; + _wLeft = _w = w; + _str = _t->_text.unicode(); + + if (_p) { + QRectF clip = _p->clipBoundingRect(); + if (clip.width() > 0 || clip.height() > 0) { + if (_yFrom < clip.y()) _yFrom = clip.y(); + if (_yTo < 0 || _yTo > clip.y() + clip.height()) _yTo = clip.y() + clip.height(); + } + } + + _align = align; + + _parDirection = _t->_startDir; + if (_parDirection == Qt::LayoutDirectionAuto) _parDirection = langDir(); + if ((*_t->_blocks.cbegin())->type() != TextBlockNewline) { + initNextParagraph(_t->_blocks.cbegin()); + } + + _lineStart = 0; + _lineStartBlock = 0; + + _lineHeight = 0; + _fontHeight = _t->_font->height; + QFixed last_rBearing = 0, last_rPadding = 0; + + int32 blockIndex = 0; + bool longWordLine = true; + Text::TextBlocks::const_iterator e = _t->_blocks.cend(); + for (Text::TextBlocks::const_iterator i = _t->_blocks.cbegin(); i != e; ++i, ++blockIndex) { + ITextBlock *b = *i; + TextBlockType _btype = b->type(); + int32 blockHeight = _blockHeight(b, _t->_font); + QFixed _rb = _blockRBearing(b); + + if (_btype == TextBlockNewline) { + if (!_lineHeight) _lineHeight = blockHeight; + ushort nextStart = _blockEnd(_t, i, e); + if (!drawLine(nextStart, i + 1, e)) return; + + _y += _lineHeight; + _lineHeight = 0; + _lineStart = nextStart; + _lineStartBlock = blockIndex + 1; + + last_rBearing = _rb; + last_rPadding = b->f_rpadding(); + _wLeft = _w - (b->f_width() - last_rBearing); + + _parDirection = static_cast(b)->nextDirection(); + if (_parDirection == Qt::LayoutDirectionAuto) _parDirection = langDir(); + initNextParagraph(i + 1); + + longWordLine = true; + continue; + } + + QFixed lpadding = b->f_lpadding(); + QFixed newWidthLeft = _wLeft - lpadding - last_rBearing - (last_rPadding + b->f_width() - _rb); + if (newWidthLeft >= 0) { + last_rBearing = _rb; + last_rPadding = b->f_rpadding(); + _wLeft = newWidthLeft; + + _lineHeight = qMax(_lineHeight, blockHeight); + + longWordLine = false; + continue; + } + + if (_btype == TextBlockText) { + TextBlock *t = static_cast(b); + QFixed f_wLeft = _wLeft; + int32 f_lineHeight = _lineHeight; + for (TextBlock::TextWords::const_iterator j = t->_words.cbegin(), en = t->_words.cend(), f = j; j != en; ++j) { + bool wordEndsHere = (j->width >= 0); + QFixed j_width = wordEndsHere ? j->width : -j->width; + + QFixed newWidthLeft = _wLeft - lpadding - last_rBearing - (last_rPadding + j_width - j->f_rbearing()); + lpadding = 0; + if (newWidthLeft >= 0) { + last_rBearing = j->f_rbearing(); + last_rPadding = j->rpadding; + _wLeft = newWidthLeft; + + _lineHeight = qMax(_lineHeight, blockHeight); + + if (wordEndsHere) { + longWordLine = false; + } + if (wordEndsHere || longWordLine) { + f_wLeft = _wLeft; + f_lineHeight = _lineHeight; + f = j + 1; + } + continue; + } + + bool elidedLine = _elideLast && (_y + _lineHeight >= _yTo); + if (f != j && !elidedLine) { + j = f; + _wLeft = f_wLeft; + _lineHeight = f_lineHeight; + j_width = (j->width >= 0) ? j->width : -j->width; + } + if (!drawLine(elidedLine ? ((j + 1 == en) ? _blockEnd(_t, i, e) : (j + 1)->from) : j->from, i, e)) return; + _y += _lineHeight; + _lineHeight = qMax(0, blockHeight); + _lineStart = j->from; + _lineStartBlock = blockIndex; + + last_rBearing = j->f_rbearing(); + last_rPadding = j->rpadding; + _wLeft = _w - (j_width - last_rBearing); + + longWordLine = true; + f = j + 1; + f_wLeft = _wLeft; + f_lineHeight = _lineHeight; + } + continue; + } + + bool elidedLine = _elideLast && (_y + _lineHeight >= _yTo); + if (!drawLine(elidedLine ? _blockEnd(_t, i, e) : b->from(), i, e)) return; + _y += _lineHeight; + _lineHeight = qMax(0, blockHeight); + _lineStart = b->from(); + _lineStartBlock = blockIndex; + + last_rBearing = _rb; + last_rPadding = b->f_rpadding(); + _wLeft = _w - (b->f_width() - last_rBearing); + + longWordLine = true; + continue; + } + if (_lineStart < _t->_text.size()) { + if (!drawLine(_t->_text.size(), e, e)) return; + } + if (_getSymbol) { + *_getSymbol = _t->_text.size(); + *_getSymbolAfter = false; + *_getSymbolUpon = false; + } + } + + void drawElided(int32 left, int32 top, int32 w, style::align align, int32 lines, int32 yFrom, int32 yTo) { + if (lines <= 0) return; + + if (yTo < 0 || (lines - 1) * _t->_font->height < yTo) { + yTo = lines * _t->_font->height; + _elideLast = true; + } + draw(left, top, w, align, yFrom, yTo); + } + + const TextLinkPtr &link(int32 x, int32 y, int32 w, style::align align) { + _lnkX = x; + _lnkY = y; + _lnkResult = &_zeroLnk; + if (_lnkX >= 0 && _lnkX < w && _lnkY >= 0) { + draw(0, 0, w, align, _lnkY, _lnkY + 1); + } + return *_lnkResult; + } + + void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 w, style::align align) { + lnk = TextLinkPtr(); + inText = false; + + if (x >= 0 && x < w && y >= 0) { + _lnkX = x; + _lnkY = y; + _lnkResult = &lnk; + _inTextFlag = &inText; + draw(0, 0, w, align, _lnkY, _lnkY + 1); + lnk = *_lnkResult; + } + } + + void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 w, style::align align) { + symbol = 0; + after = false; + upon = false; + + if (y >= 0) { + _lnkX = x; + _lnkY = y; + _getSymbol = &symbol; + _getSymbolAfter = &after; + _getSymbolUpon = &upon; + draw(0, 0, w, align, _lnkY, _lnkY + 1); + } + } + + const QPen &blockPen(ITextBlock *block) { + if (block->color()) { + return block->color()->p; + } + if (block->lnkIndex()) { + const TextLinkPtr &l(_t->_links.at(block->lnkIndex() - 1)); + if (l == _overLnk) { + if (l == _downLnk) { + return _textStyle->lnkDownColor->p; + } + } + return _textStyle->lnkColor->p; + } + return _originalPen; + } + + bool drawLine(uint16 _lineEnd, const Text::TextBlocks::const_iterator &_endBlockIter, const Text::TextBlocks::const_iterator &_end) { + _yDelta = (_lineHeight - _fontHeight) / 2; + if (_yTo >= 0 && _y + _yDelta >= _yTo) return false; + if (_y + _yDelta + _fontHeight <= _yFrom) return true; + + ITextBlock *_endBlock = (_endBlockIter == _end) ? 0 : (*_endBlockIter); + bool elidedLine = _elideLast && _endBlock && (_y + _lineHeight >= _yTo); + + QFixed x = _x; + if (_align & Qt::AlignHCenter) { + x += _wLeft.toInt() / 2; + } else if ((_align & Qt::AlignLeft) && _parDirection == Qt::RightToLeft || (_align & Qt::AlignRight) && _parDirection == Qt::LeftToRight) { + x += _wLeft; + } + + if (_getSymbol) { + if (_lnkX < x) { + if (_parDirection == Qt::RightToLeft) { + *_getSymbol = (_lineEnd > _lineStart) ? (_lineEnd - 1) : _lineStart; + *_getSymbolAfter = (_lineEnd > _lineStart) ? true : false; + *_getSymbolUpon = ((_lnkX >= _x) && (_lineEnd < _t->_text.size()) && (!_endBlock || _endBlock->type() != TextBlockSkip)) ? true : false; + } else { + *_getSymbol = _lineStart; + *_getSymbolAfter = false; + *_getSymbolUpon = ((_lnkX >= _x) && (_lineStart > 0)) ? true : false; + } + return false; + } else if (_lnkX >= x + (_w - _wLeft)) { + if (_parDirection == Qt::RightToLeft) { + *_getSymbol = _lineStart; + *_getSymbolAfter = false; + *_getSymbolUpon = ((_lnkX < _x + _w) && (_lineStart > 0)) ? true : false; + } else { + *_getSymbol = (_lineEnd > _lineStart) ? (_lineEnd - 1) : _lineStart; + *_getSymbolAfter = (_lineEnd > _lineStart) ? true : false; + *_getSymbolUpon = ((_lnkX < _x + _w) && (_lineEnd < _t->_text.size()) && (!_endBlock || _endBlock->type() != TextBlockSkip)) ? true : false; + } + return false; + } + } + + bool selectFromStart = (_selectedTo > _lineStart) && (_lineStart > 0) && (_selectedFrom <= _lineStart); + bool selectTillEnd = (_selectedTo >= _lineEnd) && (_lineEnd < _t->_text.size()) && (_selectedFrom < _lineEnd) && (!_endBlock || _endBlock->type() != TextBlockSkip); + + if (selectFromStart && _parDirection == Qt::LeftToRight || selectTillEnd && _parDirection == Qt::RightToLeft) { + if (x > _x) { + _p->fillRect(QRectF(_x.toReal(), _y + _yDelta, (x - _x).toReal(), _fontHeight), _textStyle->selectBG->b); + } + } + if (selectTillEnd && _parDirection == Qt::LeftToRight || selectFromStart && _parDirection == Qt::RightToLeft) { + if (x < _x + _wLeft) { + _p->fillRect(QRectF((x + _w - _wLeft).toReal(), _y + _yDelta, (_x + _wLeft - x).toReal(), _fontHeight), _textStyle->selectBG->b); + } + } + + /* // lpadding is counted to _wLeft + for (; _lineStart < _lineEnd; ++_lineStart) { + if (_t->_text.at(_lineStart) != QChar::Space) { + break; + } + }/**/ + for (; _lineEnd > _lineStart + 1; --_lineEnd) { + QChar ch = _t->_text.at(_lineEnd - 1); + if (ch != QChar::Space && ch != QChar::LineFeed) { + break; + } + }/**/ + if (_lineEnd == _lineStart && !elidedLine) return true; + + initParagraphBidi(); // if was not inited + + int blockIndex = _lineStartBlock; + ITextBlock *currentBlock = _t->_blocks[blockIndex]; + ITextBlock *nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + + int32 delta = (currentBlock->from() < _lineStart ? qMin(_lineStart - currentBlock->from(), 2) : 0); + _localFrom = _lineStart - delta; + int32 lineEnd = (_endBlock && _endBlock->from() < _lineEnd && !elidedLine) ? qMin(uint16(_lineEnd + 2), _blockEnd(_t, _endBlockIter, _end)) : _lineEnd; + + QString lineText = _t->_text.mid(_localFrom, lineEnd - _localFrom); + int32 lineStart = delta, lineLength = _lineEnd - _lineStart; + + if (elidedLine) prepareElidedLine(lineText, lineStart, lineLength, _endBlock); + + _f = _t->_font; + QStackTextEngine engine(lineText, _f->f); + engine.option.setTextDirection(_parDirection); + _e = &engine; + + eItemize(); + + QScriptLine line; + line.from = lineStart; + line.length = lineLength; + eShapeLine(line); + + int firstItem = engine.findItem(line.from), lastItem = engine.findItem(line.from + line.length - 1); + int nItems = (firstItem >= 0 && lastItem >= firstItem) ? (lastItem - firstItem + 1) : 0; + if (!nItems) { + if (elidedLine) restoreAfterElided(); + return true; + } + + QVarLengthArray visualOrder(nItems); + QVarLengthArray levels(nItems); + for (int i = 0; i < nItems; ++i) { + QScriptItem &si(engine.layoutData->items[firstItem + i]); + while (nextBlock && nextBlock->from() <= _localFrom + si.position) { + currentBlock = nextBlock; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + } + TextBlockType _type = currentBlock->type(); + if (_type == TextBlockSkip) { + levels[i] = si.analysis.bidiLevel = 0; + } else { + levels[i] = si.analysis.bidiLevel; + } + if (si.analysis.flags == QScriptAnalysis::Object) { + if (_type == TextBlockEmoji || _type == TextBlockSkip) { + si.width = currentBlock->f_width() + (nextBlock == _endBlock && (!nextBlock || nextBlock->from() >= _lineEnd) ? 0 : currentBlock->f_rpadding()); + } + } + } + QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); + + blockIndex = _lineStartBlock; + currentBlock = _t->_blocks[blockIndex]; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + + int32 textY = _y + _yDelta + _t->_font->ascent, emojiY = (_t->_font->height - st::emojiSize) / 2; + + eSetFont(currentBlock); + if (_p) _p->setPen(blockPen(currentBlock)); + for (int i = 0; i < nItems; ++i) { + int item = firstItem + visualOrder[i]; + const QScriptItem &si = engine.layoutData->items.at(item); + bool rtl = (si.analysis.bidiLevel % 2); + + while (blockIndex > _lineStartBlock + 1 && _t->_blocks[blockIndex - 1]->from() > _localFrom + si.position) { + nextBlock = currentBlock; + currentBlock = _t->_blocks[--blockIndex - 1]; + if (_p) _p->setPen(blockPen(currentBlock)); + eSetFont(currentBlock); + } + while (nextBlock && nextBlock->from() <= _localFrom + si.position) { + currentBlock = nextBlock; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + if (_p) _p->setPen(blockPen(currentBlock)); + eSetFont(currentBlock); + } + if (si.analysis.flags >= QScriptAnalysis::TabOrObject) { + TextBlockType _type = currentBlock->type(); + if (_lnkResult && _lnkX >= x && _lnkX < x + si.width) { + if (currentBlock->lnkIndex() && _lnkY >= _y + _yDelta && _lnkY < _y + _yDelta + _fontHeight) { + _lnkResult = &_t->_links.at(currentBlock->lnkIndex() - 1); + } + if (_inTextFlag && _type != TextBlockSkip) { + *_inTextFlag = true; + } + return false; + } else if (_getSymbol && _lnkX >= x && _lnkX < x + si.width) { + if (_type == TextBlockSkip) { + if (_parDirection == Qt::RightToLeft) { + *_getSymbol = _lineStart; + *_getSymbolAfter = false; + *_getSymbolUpon = false; + } else { + *_getSymbol = (_lineEnd > _lineStart) ? (_lineEnd - 1) : _lineStart; + *_getSymbolAfter = (_lineEnd > _lineStart) ? true : false; + *_getSymbolUpon = false; + } + return false; + } + const QChar *chFrom = _str + currentBlock->from(), *chTo = chFrom + ((nextBlock ? nextBlock->from() : _t->_text.size()) - currentBlock->from()); + if (chTo > chFrom && (chTo - 1)->unicode() == QChar::Space) { + if (rtl) { + if (_lnkX < x + (si.width - currentBlock->f_width())) { + *_getSymbol = (chTo - 1 - _str); // up to ending space, included, rtl + *_getSymbolAfter = (_lnkX < x + (si.width - currentBlock->f_width()) / 2) ? true : false; + *_getSymbolUpon = true; + return false; + } + } else if (_lnkX >= x + currentBlock->f_width()) { + *_getSymbol = (chTo - 1 - _str); // up to ending space, inclided, ltr + *_getSymbolAfter = (_lnkX >= x + currentBlock->f_width() + (currentBlock->f_rpadding() / 2)) ? true : false; + *_getSymbolUpon = true; + return false; + } + --chTo; + } + if (_lnkX < x + (rtl ? (si.width - currentBlock->f_width()) : 0) + (currentBlock->f_width() / 2)) { + *_getSymbol = ((rtl && chTo > chFrom) ? (chTo - 1) : chFrom) - _str; + *_getSymbolAfter = (rtl && chTo > chFrom) ? true : false; + *_getSymbolUpon = true; + } else { + *_getSymbol = ((rtl || chTo <= chFrom) ? chFrom : (chTo - 1)) - _str; + *_getSymbolAfter = (rtl || chTo <= chFrom) ? false : true; + *_getSymbolUpon = true; + } + return false; + } else if (_p && _type == TextBlockEmoji) { + QFixed glyphX = x; + if (rtl) { + glyphX += (si.width - currentBlock->f_width()); + } + if (_localFrom + si.position < _selectedTo) { + const QChar *chFrom = _str + currentBlock->from(), *chTo = chFrom + ((nextBlock ? nextBlock->from() : _t->_text.size()) - currentBlock->from()); + if (_localFrom + si.position >= _selectedFrom) { // could be without space + if (chTo == chFrom || (chTo - 1)->unicode() != QChar::Space || _selectedTo >= (chTo - _str)) { + _p->fillRect(QRectF(x.toReal(), _y + _yDelta, si.width.toReal(), _fontHeight), _textStyle->selectBG->b); + } else { // or with space + _p->fillRect(QRectF(glyphX.toReal(), _y + _yDelta, currentBlock->f_width().toReal(), _fontHeight), _textStyle->selectBG->b); + } + } else if (chTo > chFrom && (chTo - 1)->unicode() == QChar::Space && (chTo - 1 - _str) >= _selectedFrom) { + if (rtl) { // rtl space only + _p->fillRect(QRectF(x.toReal(), _y + _yDelta, (glyphX - x).toReal(), _fontHeight), _textStyle->selectBG->b); + } else { // ltr space only + _p->fillRect(QRectF((x + currentBlock->f_width()).toReal(), _y + _yDelta, (si.width - currentBlock->f_width()).toReal(), _fontHeight), _textStyle->selectBG->b); + } + } + } + _p->drawPixmap(QPoint((glyphX + int(st::emojiPadding)).toInt(), _y + _yDelta + emojiY), App::emojis(), QRect(static_cast(currentBlock)->emoji->x, static_cast(currentBlock)->emoji->y, st::emojiSize, st::emojiSize)); +// } else if (_p && currentBlock->type() == TextBlockSkip) { // debug +// _p->fillRect(QRect(x.toInt(), _y, currentBlock->width(), static_cast(currentBlock)->height()), QColor(0, 0, 0, 32)); + } + x += si.width; + continue; + } + + unsigned short *logClusters = engine.logClusters(&si); + QGlyphLayout glyphs = engine.shapedGlyphs(&si); + + int itemStart = qMax(line.from, si.position), itemEnd; + int itemLength = engine.length(item); + int glyphsStart = logClusters[itemStart - si.position], glyphsEnd; + if (line.from + line.length < si.position + itemLength) { + itemEnd = line.from + line.length; + glyphsEnd = logClusters[itemEnd - si.position]; + } else { + itemEnd = si.position + itemLength; + glyphsEnd = si.num_glyphs; + } + + QFixed itemWidth = 0; + for (int g = glyphsStart; g < glyphsEnd; ++g) + itemWidth += glyphs.effectiveAdvance(g); + + if (_lnkResult && _lnkX >= x && _lnkX < x + itemWidth) { + if (currentBlock->lnkIndex() && _lnkY >= _y + _yDelta && _lnkY < _y + _yDelta + _fontHeight) { + _lnkResult = &_t->_links.at(currentBlock->lnkIndex() - 1); + } + if (_inTextFlag) { + *_inTextFlag = true; + } + return false; + } else if (_getSymbol && _lnkX >= x && _lnkX < x + itemWidth) { + QFixed tmpx = rtl ? (x + itemWidth) : x; + for (int ch = 0, g, itemL = itemEnd - itemStart; ch < itemL;) { + g = logClusters[itemStart - si.position + ch]; + QFixed gwidth = glyphs.effectiveAdvance(g); + // ch2 - glyph end, ch - glyph start, (ch2 - ch) - how much chars it takes + int ch2 = ch + 1; + while ((ch2 < itemL) && (g == logClusters[itemStart - si.position + ch2])) { + ++ch2; + } + for (int charsCount = (ch2 - ch); ch < ch2; ++ch) { + QFixed shift1 = QFixed(2 * (charsCount - (ch2 - ch)) + 2) * gwidth / QFixed(2 * charsCount), + shift2 = QFixed(2 * (charsCount - (ch2 - ch)) + 1) * gwidth / QFixed(2 * charsCount); + if (rtl && _lnkX >= tmpx - shift1 || + !rtl && _lnkX < tmpx + shift1) { + *_getSymbol = _localFrom + itemStart + ch; + if (rtl && _lnkX >= tmpx - shift2 || + !rtl && _lnkX < tmpx + shift2) { + *_getSymbolAfter = false; + } else { + *_getSymbolAfter = true; + } + *_getSymbolUpon = true; + return false; + } + } + if (rtl) { + tmpx -= gwidth; + } else { + tmpx += gwidth; + } + } + if (itemEnd > itemStart) { + *_getSymbol = _localFrom + itemEnd - 1; + *_getSymbolAfter = true; + } else { + *_getSymbol = _localFrom + itemStart; + *_getSymbolAfter = false; + } + *_getSymbolUpon = true; + return false; + } else if (_p) { + QTextCharFormat format; +#ifdef Q_OS_WIN + QTextItemInt gf(glyphs.mid(glyphsStart, glyphsEnd - glyphsStart), + &_e->fnt, engine.layoutData->string.unicode() + itemStart, + itemEnd - itemStart, engine.fontEngine(si), format); + gf.logClusters = logClusters + itemStart - si.position; + gf.width = itemWidth; + gf.justified = false; + //TODO + gf.initWithScriptItem(si); +#endif + + if (_localFrom + itemStart < _selectedTo && _localFrom + itemEnd > _selectedFrom) { + QFixed selX = x, selWidth = itemWidth; + if (_localFrom + itemEnd > _selectedTo || _localFrom + itemStart < _selectedFrom) { + selWidth = 0; + int itemL = itemEnd - itemStart; + int selStart = _selectedFrom - (_localFrom + itemStart), selEnd = _selectedTo - (_localFrom + itemStart); + if (selStart < 0) selStart = 0; + if (selEnd > itemL) selEnd = itemL; + for (int ch = 0, g; ch < selEnd;) { + g = logClusters[itemStart - si.position + ch]; + QFixed gwidth = glyphs.effectiveAdvance(g); + // ch2 - glyph end, ch - glyph start, (ch2 - ch) - how much chars it takes + int ch2 = ch + 1; + while ((ch2 < itemL) && (g == logClusters[itemStart - si.position + ch2])) { + ++ch2; + } + if (ch2 <= selStart) { + selX += gwidth; + } else if (ch >= selStart && ch2 <= selEnd) { + selWidth += gwidth; + } else { + int sStart = ch, sEnd = ch2; + if (ch < selStart) { + sStart = selStart; + selX += QFixed(sStart - ch) * gwidth / QFixed(ch2 - ch); + } + if (ch2 >= selEnd) { + sEnd = selEnd; + selWidth += QFixed(sEnd - sStart) * gwidth / QFixed(ch2 - ch); + break; + } + selWidth += QFixed(sEnd - sStart) * gwidth / QFixed(ch2 - ch); + } + ch = ch2; + } + } + if (rtl) selX = x + itemWidth - (selX - x) - selWidth; + _p->fillRect(QRectF(selX.toReal(), _y + _yDelta, selWidth.toReal(), _fontHeight), _textStyle->selectBG->b); + } + +#ifdef Q_OS_WIN + //TODO + _p->drawTextItem(QPointF(x.toReal(), textY), gf); +#endif + } + + x += itemWidth; + } + + if (elidedLine) restoreAfterElided(); + return true; + } + + void elideSaveBlock(int32 blockIndex, ITextBlock *&_endBlock, int32 elideStart, int32 elideWidth) { + _elideSavedIndex = blockIndex; + _elideSavedBlock = _t->_blocks[blockIndex]; + const_cast(_t)->_blocks[blockIndex] = new SkipBlock(_t->_font, _t->_text, elideStart, elideWidth, _f->height, _elideSavedBlock->lnkIndex()); + _blocksSize = blockIndex + 1; + _endBlock = (blockIndex + 1 < _t->_blocks.size() ? _t->_blocks[blockIndex + 1] : 0); + } + + void setElideBidi(int32 elideStart, int32 elideLen) { + int32 newParLength = elideStart + elideLen - _parStart; + if (newParLength > _parAnalysis.size()) { + _parAnalysis.resize(newParLength); + } + for (int32 i = elideLen; i > 0; --i) { + _parAnalysis[newParLength - i].bidiLevel = (_parDirection == Qt::RightToLeft) ? 1 : 0; + } + } + + void prepareElidedLine(QString &lineText, int32 lineStart, int32 &lineLength, ITextBlock *&_endBlock, int repeat = 0) { + static const QString _Elide = qsl("..."); + + _f = _t->_font; + QStackTextEngine engine(lineText, _f->f); + engine.option.setTextDirection(_parDirection); + _e = &engine; + + eItemize(); + + int blockIndex = _lineStartBlock; + ITextBlock *currentBlock = _t->_blocks[blockIndex]; + ITextBlock *nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + + QScriptLine line; + line.from = lineStart; + line.length = lineLength; + eShapeLine(line); + + int32 elideWidth = _f->m.width(_Elide); + _wLeft = _w - elideWidth; + + int firstItem = engine.findItem(line.from), lastItem = engine.findItem(line.from + line.length - 1); + int nItems = (firstItem >= 0 && lastItem >= firstItem) ? (lastItem - firstItem + 1) : 0, i; + + for (i = 0; i < nItems; ++i) { + QScriptItem &si(engine.layoutData->items[firstItem + i]); + while (nextBlock && nextBlock->from() <= _localFrom + si.position) { + currentBlock = nextBlock; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + } + TextBlockType _type = currentBlock->type(); + if (si.analysis.flags == QScriptAnalysis::Object) { + if (_type == TextBlockEmoji || _type == TextBlockSkip) { + si.width = currentBlock->f_width() + currentBlock->f_rpadding(); + } + } + if (_type == TextBlockEmoji || _type == TextBlockSkip || _type == TextBlockNewline) { + if (_wLeft < si.width) { + lineText = lineText.mid(0, currentBlock->from() - _localFrom) + _Elide; + lineLength = currentBlock->from() + _Elide.size() - _lineStart; + setElideBidi(currentBlock->from(), _Elide.size()); + elideSaveBlock(blockIndex - 1, _endBlock, currentBlock->from(), elideWidth); + return; + } + _wLeft -= si.width; + } else if (_type == TextBlockText) { + unsigned short *logClusters = engine.logClusters(&si); + QGlyphLayout glyphs = engine.shapedGlyphs(&si); + + int itemStart = qMax(line.from, si.position), itemEnd; + int itemLength = engine.length(firstItem + i); + int glyphsStart = logClusters[itemStart - si.position], glyphsEnd; + if (line.from + line.length < si.position + itemLength) { + itemEnd = line.from + line.length; + glyphsEnd = logClusters[itemEnd - si.position]; + } else { + itemEnd = si.position + itemLength; + glyphsEnd = si.num_glyphs; + } + + for (int g = glyphsStart; g < glyphsEnd; ++g) { + QFixed adv = glyphs.effectiveAdvance(g); + if (_wLeft < adv) { + int pos = itemStart; + while (pos < itemEnd && logClusters[pos - si.position] < g) { + ++pos; + } + + if (lineText.size() <= pos || repeat > 3) { + lineText += _Elide; + lineLength = _localFrom + pos + _Elide.size() - _lineStart; + setElideBidi(_localFrom + pos, _Elide.size()); + _blocksSize = blockIndex; + _endBlock = nextBlock; + } else { + lineText = lineText.mid(0, pos); + lineLength = _localFrom + pos - _lineStart; + _blocksSize = blockIndex; + _endBlock = nextBlock; + prepareElidedLine(lineText, lineStart, lineLength, _endBlock, repeat + 1); + } + return; + } else { + _wLeft -= adv; + } + } + } + } + + int32 elideStart = _lineStart + lineText.length(); + setElideBidi(elideStart, _Elide.size()); + + lineText += _Elide; + lineLength += _Elide.size(); + + if (!repeat) { + for (; _t->_blocks[blockIndex] != _endBlock && _t->_blocks[blockIndex]->from() < elideStart; ++blockIndex) { + } + elideSaveBlock(blockIndex, _endBlock, elideStart, elideWidth); + } + } + + void restoreAfterElided() { + if (_elideSavedBlock) { + delete _t->_blocks[_elideSavedIndex]; + const_cast(_t)->_blocks[_elideSavedIndex] = _elideSavedBlock; + _elideSavedBlock = 0; + } + } + + // COPIED FROM qtextengine.cpp AND MODIFIED + void eShapeLine(const QScriptLine &line) { + int item = _e->findItem(line.from), end = _e->findItem(line.from + line.length - 1); + if (item == -1) + return; + + int blockIndex = _lineStartBlock; + ITextBlock *currentBlock = _t->_blocks[blockIndex]; + ITextBlock *nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + eSetFont(currentBlock); + for (item = _e->findItem(line.from); item <= end; ++item) { + QScriptItem &si = _e->layoutData->items[item]; + while (nextBlock && nextBlock->from() <= _localFrom + si.position) { + currentBlock = nextBlock; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + eSetFont(currentBlock); + } + _e->shape(item); + } + } + + void eSetFont(ITextBlock *block) { + style::font newFont = _t->_font; + int flags = block->flags(); + if (!flags && block->lnkIndex()) { + const TextLinkPtr &l(_t->_links.at(block->lnkIndex() - 1)); + if (l == _overLnk) { + if (l == _downLnk || !_downLnk) { + flags = _textStyle->lnkOverFlags->flags(); + } else { + flags = _textStyle->lnkFlags->flags(); + } + } else { + flags = _textStyle->lnkFlags->flags(); + } + } + if (flags & TextBlockBold) newFont = newFont->bold(); + if (flags & TextBlockItalic) newFont = newFont->italic(); + if (flags & TextBlockUnderline) newFont = newFont->underline(); + if (newFont != _f) { + _f = newFont; + _e->fnt = _f->f; + _e->resetFontEngineCache(); + } + } + + void eItemize() { + _e->validate(); + if (_e->layoutData->items.size()) + return; + + int length = _e->layoutData->string.length(); + if (!length) + return; + + const ushort *string = reinterpret_cast(_e->layoutData->string.unicode()); + + int blockIndex = _lineStartBlock; + ITextBlock *currentBlock = _t->_blocks[blockIndex]; + ITextBlock *nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + + _e->layoutData->hasBidi = _parHasBidi; + QScriptAnalysis *analysis = _parAnalysis.data() + (_localFrom - _parStart); + + { + QVarLengthArray scripts(length); + QUnicodeTools::initScripts(string, length, scripts.data()); + for (int i = 0; i < length; ++i) + analysis[i].script = scripts.at(i); + } + + blockIndex = _lineStartBlock; + currentBlock = _t->_blocks[blockIndex]; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + + const ushort *start = string; + const ushort *end = start + length; + while (start < end) { + while (nextBlock && nextBlock->from() <= _localFrom + (start - string)) { + currentBlock = nextBlock; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + } + TextBlockType _type = currentBlock->type(); + if (_type == TextBlockEmoji || _type == TextBlockSkip) { + analysis->script = QChar::Script_Common; + analysis->flags = QScriptAnalysis::Object; + } else { + analysis->flags = QScriptAnalysis::None; + } + analysis->script = hbscript_to_script(script_to_hbscript(analysis->script)); // retain the old behavior + ++start; + ++analysis; + } + + { + const QString *i_string = &_e->layoutData->string; + const QScriptAnalysis *i_analysis = _parAnalysis.data() + (_localFrom - _parStart); + QScriptItemArray *i_items = &_e->layoutData->items; + + blockIndex = _lineStartBlock; + currentBlock = _t->_blocks[blockIndex]; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + ITextBlock *startBlock = currentBlock; + + if (!length) + return; + int start = 0, end = start + length; + for (int i = start + 1; i < end; ++i) { + while (nextBlock && nextBlock->from() <= _localFrom + i) { + currentBlock = nextBlock; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + } + // According to the unicode spec we should be treating characters in the Common script + // (punctuation, spaces, etc) as being the same script as the surrounding text for the + // purpose of splitting up text. This is important because, for example, a fullstop + // (0x2E) can be used to indicate an abbreviation and so must be treated as part of a + // word. Thus it must be passed along with the word in languages that have to calculate + // word breaks. For example the thai word "ครม." has no word breaks but the word "ครม" + // does. + // Unfortuntely because we split up the strings for both wordwrapping and for setting + // the font and because Japanese and Chinese are also aliases of the script "Common", + // doing this would break too many things. So instead we only pass the full stop + // along, and nothing else. + if (currentBlock == startBlock + && i_analysis[i].bidiLevel == i_analysis[start].bidiLevel + && i_analysis[i].flags == i_analysis[start].flags + && (i_analysis[i].script == i_analysis[start].script || i_string->at(i) == QLatin1Char('.')) +// && i_analysis[i].flags < QScriptAnalysis::SpaceTabOrObject // only emojis are objects here, no tabs + && i - start < _MaxItemLength) + continue; + i_items->append(QScriptItem(start, i_analysis[start])); + start = i; + startBlock = currentBlock; + } + i_items->append(QScriptItem(start, i_analysis[start])); + } + } + + QChar::Direction eSkipBoundryNeutrals(QScriptAnalysis *analysis, + const ushort *unicode, + int &sor, int &eor, BidiControl &control, + Text::TextBlocks::const_iterator i) { + Text::TextBlocks::const_iterator e = _t->_blocks.cend(), n = i + 1; + + QChar::Direction dir = control.basicDirection(); + int level = sor > 0 ? analysis[sor - 1].bidiLevel : control.level; + while (sor <= _parLength) { + while (i != _parStartBlock && (*i)->from() > _parStart + sor) { + n = i; + --i; + } + while (n != e && (*n)->from() <= _parStart + sor) { + i = n; + ++n; + } + + TextBlockType _itype = (*i)->type(); + if (eor == _parLength) + dir = control.basicDirection(); + else if (_itype == TextBlockEmoji) + dir = QChar::DirCS; + else if (_itype == TextBlockSkip) + dir = QChar::DirCS; + else + dir = QChar::direction(unicode[sor]); + // Keep skipping DirBN as if it doesn't exist + if (dir != QChar::DirBN) + break; + analysis[sor++].bidiLevel = level; + } + + eor = sor; + + return dir; + } + + // creates the next QScript items. + bool eBidiItemize(QScriptAnalysis *analysis, BidiControl &control) { + bool rightToLeft = (control.basicDirection() == 1); + bool hasBidi = rightToLeft; + + int sor = 0; + int eor = -1; + + const ushort *unicode = reinterpret_cast(_t->_text.unicode()) + _parStart; + int current = 0; + + QChar::Direction dir = rightToLeft ? QChar::DirR : QChar::DirL; + BidiStatus status; + + Text::TextBlocks::const_iterator i = _parStartBlock, e = _t->_blocks.cend(), n = i + 1; + + QChar::Direction sdir; + TextBlockType _stype = (*_parStartBlock)->type(); + if (_stype == TextBlockEmoji) + sdir = QChar::DirCS; + else if (_stype == TextBlockSkip) + sdir = QChar::DirCS; + else + sdir = QChar::direction(*unicode); + if (sdir != QChar::DirL && sdir != QChar::DirR && sdir != QChar::DirEN && sdir != QChar::DirAN) + sdir = QChar::DirON; + else + dir = QChar::DirON; + + status.eor = sdir; + status.lastStrong = rightToLeft ? QChar::DirR : QChar::DirL; + status.last = status.lastStrong; + status.dir = sdir; + + while (current <= _parLength) { + while (n != e && (*n)->from() <= _parStart + current) { + i = n; + ++n; + } + + QChar::Direction dirCurrent; + TextBlockType _itype = (*i)->type(); + if (current == (int)_parLength) + dirCurrent = control.basicDirection(); + else if (_itype == TextBlockEmoji) + dirCurrent = QChar::DirCS; + else if (_itype == TextBlockSkip) + dirCurrent = QChar::DirCS; + else + dirCurrent = QChar::direction(unicode[current]); + + switch (dirCurrent) { + + // embedding and overrides (X1-X9 in the BiDi specs) + case QChar::DirRLE: + case QChar::DirRLO: + case QChar::DirLRE: + case QChar::DirLRO: + { + bool rtl = (dirCurrent == QChar::DirRLE || dirCurrent == QChar::DirRLO); + hasBidi |= rtl; + bool override = (dirCurrent == QChar::DirLRO || dirCurrent == QChar::DirRLO); + + unsigned int level = control.level+1; + if ((level%2 != 0) == rtl) ++level; + if (level < _MaxBidiLevel) { + eor = current-1; + eAppendItems(analysis, sor, eor, control, dir); + eor = current; + control.embed(rtl, override); + QChar::Direction edir = (rtl ? QChar::DirR : QChar::DirL); + dir = status.eor = edir; + status.lastStrong = edir; + } + break; + } + case QChar::DirPDF: + { + if (control.canPop()) { + if (dir != control.direction()) { + eor = current-1; + eAppendItems(analysis, sor, eor, control, dir); + dir = control.direction(); + } + eor = current; + eAppendItems(analysis, sor, eor, control, dir); + control.pdf(); + dir = QChar::DirON; status.eor = QChar::DirON; + status.last = control.direction(); + if (control.override) + dir = control.direction(); + else + dir = QChar::DirON; + status.lastStrong = control.direction(); + } + break; + } + + // strong types + case QChar::DirL: + if(dir == QChar::DirON) + dir = QChar::DirL; + switch(status.last) + { + case QChar::DirL: + eor = current; status.eor = QChar::DirL; break; + case QChar::DirR: + case QChar::DirAL: + case QChar::DirEN: + case QChar::DirAN: + if (eor >= 0) { + eAppendItems(analysis, sor, eor, control, dir); + status.eor = dir = eSkipBoundryNeutrals(analysis, unicode, sor, eor, control, i); + } else { + eor = current; status.eor = dir; + } + break; + case QChar::DirES: + case QChar::DirET: + case QChar::DirCS: + case QChar::DirBN: + case QChar::DirB: + case QChar::DirS: + case QChar::DirWS: + case QChar::DirON: + if(dir != QChar::DirL) { + //last stuff takes embedding dir + if(control.direction() == QChar::DirR) { + if(status.eor != QChar::DirR) { + // AN or EN + eAppendItems(analysis, sor, eor, control, dir); + status.eor = QChar::DirON; + dir = QChar::DirR; + } + eor = current - 1; + eAppendItems(analysis, sor, eor, control, dir); + status.eor = dir = eSkipBoundryNeutrals(analysis, unicode, sor, eor, control, i); + } else { + if(status.eor != QChar::DirL) { + eAppendItems(analysis, sor, eor, control, dir); + status.eor = QChar::DirON; + dir = QChar::DirL; + } else { + eor = current; status.eor = QChar::DirL; break; + } + } + } else { + eor = current; status.eor = QChar::DirL; + } + default: + break; + } + status.lastStrong = QChar::DirL; + break; + case QChar::DirAL: + case QChar::DirR: + hasBidi = true; + if(dir == QChar::DirON) dir = QChar::DirR; + switch(status.last) + { + case QChar::DirL: + case QChar::DirEN: + case QChar::DirAN: + if (eor >= 0) + eAppendItems(analysis, sor, eor, control, dir); + // fall through + case QChar::DirR: + case QChar::DirAL: + dir = QChar::DirR; eor = current; status.eor = QChar::DirR; break; + case QChar::DirES: + case QChar::DirET: + case QChar::DirCS: + case QChar::DirBN: + case QChar::DirB: + case QChar::DirS: + case QChar::DirWS: + case QChar::DirON: + if(status.eor != QChar::DirR && status.eor != QChar::DirAL) { + //last stuff takes embedding dir + if(control.direction() == QChar::DirR + || status.lastStrong == QChar::DirR || status.lastStrong == QChar::DirAL) { + eAppendItems(analysis, sor, eor, control, dir); + dir = QChar::DirR; status.eor = QChar::DirON; + eor = current; + } else { + eor = current - 1; + eAppendItems(analysis, sor, eor, control, dir); + dir = QChar::DirR; status.eor = QChar::DirON; + } + } else { + eor = current; status.eor = QChar::DirR; + } + default: + break; + } + status.lastStrong = dirCurrent; + break; + + // weak types: + + case QChar::DirNSM: + if (eor == current-1) + eor = current; + break; + case QChar::DirEN: + // if last strong was AL change EN to AN + if(status.lastStrong != QChar::DirAL) { + if(dir == QChar::DirON) { + if(status.lastStrong == QChar::DirL) + dir = QChar::DirL; + else + dir = QChar::DirEN; + } + switch(status.last) + { + case QChar::DirET: + if (status.lastStrong == QChar::DirR || status.lastStrong == QChar::DirAL) { + eAppendItems(analysis, sor, eor, control, dir); + status.eor = QChar::DirON; + dir = QChar::DirAN; + } + // fall through + case QChar::DirEN: + case QChar::DirL: + eor = current; + status.eor = dirCurrent; + break; + case QChar::DirR: + case QChar::DirAL: + case QChar::DirAN: + if (eor >= 0) + eAppendItems(analysis, sor, eor, control, dir); + else + eor = current; + status.eor = QChar::DirEN; + dir = QChar::DirAN; break; + case QChar::DirES: + case QChar::DirCS: + if(status.eor == QChar::DirEN || dir == QChar::DirAN) { + eor = current; break; + } + case QChar::DirBN: + case QChar::DirB: + case QChar::DirS: + case QChar::DirWS: + case QChar::DirON: + if(status.eor == QChar::DirR) { + // neutrals go to R + eor = current - 1; + eAppendItems(analysis, sor, eor, control, dir); + dir = QChar::DirON; status.eor = QChar::DirEN; + dir = QChar::DirAN; + } + else if(status.eor == QChar::DirL || + (status.eor == QChar::DirEN && status.lastStrong == QChar::DirL)) { + eor = current; status.eor = dirCurrent; + } else { + // numbers on both sides, neutrals get right to left direction + if(dir != QChar::DirL) { + eAppendItems(analysis, sor, eor, control, dir); + dir = QChar::DirON; status.eor = QChar::DirON; + eor = current - 1; + dir = QChar::DirR; + eAppendItems(analysis, sor, eor, control, dir); + dir = QChar::DirON; status.eor = QChar::DirON; + dir = QChar::DirAN; + } else { + eor = current; status.eor = dirCurrent; + } + } + default: + break; + } + break; + } + case QChar::DirAN: + hasBidi = true; + dirCurrent = QChar::DirAN; + if(dir == QChar::DirON) dir = QChar::DirAN; + switch(status.last) + { + case QChar::DirL: + case QChar::DirAN: + eor = current; status.eor = QChar::DirAN; break; + case QChar::DirR: + case QChar::DirAL: + case QChar::DirEN: + if (eor >= 0){ + eAppendItems(analysis, sor, eor, control, dir); + } else { + eor = current; + } + dir = QChar::DirAN; status.eor = QChar::DirAN; + break; + case QChar::DirCS: + if(status.eor == QChar::DirAN) { + eor = current; break; + } + case QChar::DirES: + case QChar::DirET: + case QChar::DirBN: + case QChar::DirB: + case QChar::DirS: + case QChar::DirWS: + case QChar::DirON: + if(status.eor == QChar::DirR) { + // neutrals go to R + eor = current - 1; + eAppendItems(analysis, sor, eor, control, dir); + status.eor = QChar::DirAN; + dir = QChar::DirAN; + } else if(status.eor == QChar::DirL || + (status.eor == QChar::DirEN && status.lastStrong == QChar::DirL)) { + eor = current; status.eor = dirCurrent; + } else { + // numbers on both sides, neutrals get right to left direction + if(dir != QChar::DirL) { + eAppendItems(analysis, sor, eor, control, dir); + status.eor = QChar::DirON; + eor = current - 1; + dir = QChar::DirR; + eAppendItems(analysis, sor, eor, control, dir); + status.eor = QChar::DirAN; + dir = QChar::DirAN; + } else { + eor = current; status.eor = dirCurrent; + } + } + default: + break; + } + break; + case QChar::DirES: + case QChar::DirCS: + break; + case QChar::DirET: + if(status.last == QChar::DirEN) { + dirCurrent = QChar::DirEN; + eor = current; status.eor = dirCurrent; + } + break; + + // boundary neutrals should be ignored + case QChar::DirBN: + break; + // neutrals + case QChar::DirB: + // ### what do we do with newline and paragraph separators that come to here? + break; + case QChar::DirS: + // ### implement rule L1 + break; + case QChar::DirWS: + case QChar::DirON: + break; + default: + break; + } + + if(current >= (int)_parLength) break; + + // set status.last as needed. + switch(dirCurrent) { + case QChar::DirET: + case QChar::DirES: + case QChar::DirCS: + case QChar::DirS: + case QChar::DirWS: + case QChar::DirON: + switch(status.last) + { + case QChar::DirL: + case QChar::DirR: + case QChar::DirAL: + case QChar::DirEN: + case QChar::DirAN: + status.last = dirCurrent; + break; + default: + status.last = QChar::DirON; + } + break; + case QChar::DirNSM: + case QChar::DirBN: + // ignore these + break; + case QChar::DirLRO: + case QChar::DirLRE: + status.last = QChar::DirL; + break; + case QChar::DirRLO: + case QChar::DirRLE: + status.last = QChar::DirR; + break; + case QChar::DirEN: + if (status.last == QChar::DirL) { + status.last = QChar::DirL; + break; + } + // fall through + default: + status.last = dirCurrent; + } + + ++current; + } + + eor = current - 1; // remove dummy char + + if (sor <= eor) + eAppendItems(analysis, sor, eor, control, dir); + + return hasBidi; + } + +private: + + QPainter *_p; + const Text *_t; + bool _elideLast; + style::align _align; + QPen _originalPen; + int32 _yFrom, _yTo; + uint16 _selectedFrom, _selectedTo; + const QChar *_str; + + // current paragraph data + Text::TextBlocks::const_iterator _parStartBlock; + Qt::LayoutDirection _parDirection; + int32 _parStart, _parLength; + bool _parHasBidi; + QVarLengthArray _parAnalysis; + + // current line data + QTextEngine *_e; + style::font _f; + QFixed _x, _w, _wLeft; + int32 _y, _yDelta, _lineHeight, _fontHeight; + + // elided hack support + int32 _blocksSize; + int32 _elideSavedIndex; + ITextBlock *_elideSavedBlock; + + int32 _lineStart, _localFrom; + int32 _lineStartBlock; + + // link and symbol resolve + QFixed _lnkX; + int32 _lnkY; + const TextLinkPtr *_lnkResult; + bool *_inTextFlag; + uint16 *_getSymbol; + bool *_getSymbolAfter, *_getSymbolUpon; + +}; + +const TextParseOptions _defaultOptions = { + TextParseLinks | TextParseMultiline, // flags + 0, // maxw + 0, // maxh + Qt::LayoutDirectionAuto, // dir +}; + +const TextParseOptions _textPlainOptions = { + TextParseMultiline, // flags + 0, // maxw + 0, // maxh + Qt::LayoutDirectionAuto, // dir +}; + +Text::Text(int32 minResizeWidth) : _minResizeWidth(minResizeWidth), _maxWidth(0), _minHeight(0), _startDir(Qt::LayoutDirectionAuto) { +} + +Text::Text(style::font font, const QString &text, const TextParseOptions &options, int32 minResizeWidth, bool richText) : _minResizeWidth(minResizeWidth) { + if (richText) { + setRichText(font, text, options); + } else { + setText(font, text, options); + } +} + +void Text::setText(style::font font, const QString &text, const TextParseOptions &options) { + if (!_textStyle) _initDefault(); + _font = font; + clean(); + + { + TextParser parser(this, text, options); + } + + NewlineBlock *lastNewline = 0; + + int32 lineHeight = 0; + int32 result = 0, lastNewlineStart = 0; + QFixed _width = 0, last_rBearing = 0, last_rPadding = 0; + for (TextBlocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) { + ITextBlock *b = *i; + TextBlockType _btype = b->type(); + int32 blockHeight = _blockHeight(b, _font); + QFixed _rb = _blockRBearing(b); + + if (_btype == TextBlockNewline) { + if (!lineHeight) lineHeight = blockHeight; + Qt::LayoutDirection dir = options.dir; + if (dir == Qt::LayoutDirectionAuto) { + dir = TextParser::stringDirection(_text, lastNewlineStart, b->from()); + } + if (lastNewline) { + lastNewline->_nextDir = dir; + } else { + _startDir = dir; + } + lastNewlineStart = b->from(); + lastNewline = static_cast(b); + + _minHeight += lineHeight; + lineHeight = 0; + last_rBearing = _rb; + last_rPadding = b->f_rpadding(); + if (_maxWidth < _width) { + _maxWidth = _width; + } + _width = (b->f_width() - last_rBearing); + continue; + } + + _width += b->f_lpadding(); + _width += last_rBearing + (last_rPadding + b->f_width() - _rb); + lineHeight = qMax(lineHeight, blockHeight); + + last_rBearing = _rb; + last_rPadding = b->f_rpadding(); + continue; + } + Qt::LayoutDirection dir = options.dir; + if (dir == Qt::LayoutDirectionAuto) { + dir = TextParser::stringDirection(_text, lastNewlineStart, _text.size()); + } + if (lastNewline) { + lastNewline->_nextDir = dir; + } else { + _startDir = dir; + } + if (_width > 0) { + if (!lineHeight) lineHeight = _blockHeight(_blocks.back(), _font); + _minHeight += lineHeight; + if (_maxWidth < _width) { + _maxWidth = _width; + } + } +} + +void Text::setRichText(style::font font, const QString &text, TextParseOptions options, const TextCustomTagsMap &custom) { + QString parsed; + parsed.reserve(text.size()); + const QChar *s = text.constData(), *ch = s; + for (const QChar *b = s, *e = b + text.size(); ch != e; ++ch) { + if (ch->unicode() == '\\') { + if (ch > s) parsed.append(s, ch - s); + s = ch + 1; + + if (s < e) ++ch; + continue; + } + if (ch->unicode() == '[') { + if (ch > s) parsed.append(s, ch - s); + s = ch; + + const QChar *tag = ch + 1; + if (tag >= e) continue; + + bool closing = false, other = false; + if (tag->unicode() == '/') { + closing = true; + if (++tag >= e) continue; + } + + TextCommands cmd; + switch (tag->unicode()) { + case 'b': cmd = closing ? TextCommandNoBold : TextCommandBold; break; + case 'i': cmd = closing ? TextCommandNoItalic : TextCommandItalic; break; + case 'u': cmd = closing ? TextCommandNoUnderline : TextCommandUnderline; break; + default : other = true; break; + } + + if (!other) { + if (++tag >= e || tag->unicode() != ']') continue; + parsed.append(TextCommand).append(QChar(cmd)).append(TextCommand); + ch = tag; + s = ch + 1; + continue; + } + + if (tag->unicode() != 'a') { + TextCustomTagsMap::const_iterator i = custom.constFind(*tag); + if (++tag >= e || tag->unicode() != ']' || i == custom.cend()) continue; + parsed.append(closing ? i->second : i->first); + ch = tag; + s = ch + 1; + continue; + } + + if (closing) { + if (++tag >= e || tag->unicode() != ']') continue; + parsed.append(textcmdStopLink()); + ch = tag; + s = ch + 1; + continue; + } + if (++tag >= e || tag->unicode() != ' ') continue; + while (tag < e && tag->unicode() == ' ') ++tag; + if (tag + 5 < e && text.midRef(tag - b, 6) == qsl("href=\"")) { + tag += 6; + const QChar *tagend = tag; + while (tagend < e && tagend->unicode() != '"') ++tagend; + if (++tagend >= e || tagend->unicode() != ']') continue; + parsed.append(textcmdStartLink(QString(tag, tagend - 1 - tag))); + ch = tagend; + s = ch + 1; + continue; + } + } + } + if (ch > s) parsed.append(s, ch - s); + s = ch; + + options.flags |= TextParseRichText; + setText(font, parsed, options); +} + +void Text::setLink(uint16 lnkIndex, const TextLinkPtr &lnk) { + if (!lnkIndex || lnkIndex > _links.size()) return; + _links[lnkIndex - 1] = lnk; +} + +bool Text::hasLinks() const { + return !_links.isEmpty(); +} + +int32 Text::countHeight(int32 w) const { + QFixed width = w; + if (width < _minResizeWidth) width = _minResizeWidth; + if (width >= _maxWidth) { + return _minHeight; + } + + int32 result = 0, lineHeight = 0; + QFixed widthLeft = width, last_rBearing = 0, last_rPadding = 0; + bool longWordLine = true; + for (TextBlocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) { + ITextBlock *b = *i; + TextBlockType _btype = b->type(); + int32 blockHeight = _blockHeight(b, _font); + QFixed _rb = _blockRBearing(b); + + if (_btype == TextBlockNewline) { + if (!lineHeight) lineHeight = blockHeight; + result += lineHeight; + lineHeight = 0; + last_rBearing = _rb; + last_rPadding = b->f_rpadding(); + widthLeft = width - (b->f_width() - last_rBearing); + + longWordLine = true; + continue; + } + widthLeft -= b->f_lpadding(); + QFixed newWidthLeft = widthLeft - last_rBearing - (last_rPadding + b->f_width() - _rb); + if (newWidthLeft >= 0) { + last_rBearing = _rb; + last_rPadding = b->f_rpadding(); + widthLeft = newWidthLeft; + + lineHeight = qMax(lineHeight, blockHeight); + + longWordLine = false; + continue; + } + + if (_btype == TextBlockText) { + TextBlock *t = static_cast(b); + QFixed f_wLeft = widthLeft; + int32 f_lineHeight = lineHeight; + for (TextBlock::TextWords::const_iterator j = t->_words.cbegin(), e = t->_words.cend(), f = j; j != e; ++j) { + bool wordEndsHere = (j->width >= 0); + QFixed j_width = wordEndsHere ? j->width : -j->width; + + QFixed newWidthLeft = widthLeft - last_rBearing - (last_rPadding + j_width - j->f_rbearing()); + if (newWidthLeft >= 0) { + last_rBearing = j->f_rbearing(); + last_rPadding = j->rpadding; + widthLeft = newWidthLeft; + + lineHeight = qMax(lineHeight, blockHeight); + + if (wordEndsHere) { + longWordLine = false; + } + if (wordEndsHere || longWordLine) { + f_wLeft = widthLeft; + f_lineHeight = lineHeight; + f = j + 1; + } + continue; + } + + if (f != j) { + j = f; + widthLeft = f_wLeft; + lineHeight = f_lineHeight; + j_width = (j->width >= 0) ? j->width : -j->width; + } + + result += lineHeight; + lineHeight = qMax(0, blockHeight); + last_rBearing = j->f_rbearing(); + last_rPadding = j->rpadding; + widthLeft = width - (j_width - last_rBearing); + + longWordLine = true; + f = j + 1; + f_wLeft = widthLeft; + f_lineHeight = lineHeight; + } + continue; + } + + result += lineHeight; + lineHeight = qMax(0, blockHeight); + last_rBearing = _rb; + last_rPadding = b->f_rpadding(); + widthLeft = width - (b->f_width() - last_rBearing); + + longWordLine = true; + continue; + } + if (widthLeft < width) { + result += lineHeight; + } + + return result; +} + +void Text::draw(QPainter &painter, int32 left, int32 top, int32 w, style::align align, int32 yFrom, int32 yTo, uint16 selectedFrom, uint16 selectedTo) const { +// painter.fillRect(QRect(left, top, w, countHeight(w)), QColor(0, 0, 0, 32)); // debug + TextPainter p(&painter, this); + p.draw(left, top, w, align, yFrom, yTo, selectedFrom, selectedTo); +} + +void Text::drawElided(QPainter &painter, int32 left, int32 top, int32 w, int32 lines, style::align align, int32 yFrom, int32 yTo) const { +// painter.fillRect(QRect(left, top, w, countHeight(w)), QColor(0, 0, 0, 32)); // debug + TextPainter p(&painter, this); + p.drawElided(left, top, w, align, lines, yFrom, yTo); +} + +const TextLinkPtr &Text::link(int32 x, int32 y, int32 width, style::align align) const { + TextPainter p(0, this); + return p.link(x, y, width, align); +} + +void Text::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 width, style::align align) const { + TextPainter p(0, this); + p.getState(lnk, inText, x, y, width, align); +} + +void Text::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 width, style::align align) const { + TextPainter p(0, this); + p.getSymbol(symbol, after, upon, x, y, width, align); +} + +uint32 Text::adjustSelection(uint16 from, uint16 to, TextSelectType selectType) const { + if (from < _text.size() && from <= to) { + if (to > _text.size()) to = _text.size() - 1; + if (selectType == TextSelectParagraphs) { + if (!chIsParagraphSeparator(_text.at(from))) { + while (from > 0 && !chIsParagraphSeparator(_text.at(from - 1))) { + --from; + } + } + if (to < _text.size()) { + if (chIsParagraphSeparator(_text.at(to))) { + ++to; + } else { + while (to < _text.size() && !chIsParagraphSeparator(_text.at(to))) { + ++to; + } + } + } + } else if (selectType == TextSelectWords) { + if (!chIsWordSeparator(_text.at(from))) { + while (from > 0 && !chIsWordSeparator(_text.at(from - 1))) { + --from; + } + } + if (to < _text.size()) { + if (chIsWordSeparator(_text.at(to))) { + ++to; + } else { + while (to < _text.size() && !chIsWordSeparator(_text.at(to))) { + ++to; + } + } + } + } + } + return (from << 16) | to; +} + +QString Text::original(uint16 selectedFrom, uint16 selectedTo, bool expandLinks) const { + QString result; + result.reserve(_text.size()); + + int32 lnkFrom = 0, lnkIndex = 0; + for (TextBlocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); true; ++i) { + int32 blockLnkIndex = (i == e) ? 0 : (*i)->lnkIndex(); + int32 blockFrom = (i == e) ? _text.size() : (*i)->from(); + if (blockLnkIndex != lnkIndex) { + if (lnkIndex) { // write link + const TextLinkPtr &lnk(_links.at(lnkIndex - 1)); + const QString &url(lnk ? lnk->text() : QString()); + + int32 rangeFrom = qMax(int32(selectedFrom), lnkFrom), rangeTo = qMin(blockFrom, int32(selectedTo)); + + if (rangeTo > rangeFrom) { + QStringRef r = _text.midRef(rangeFrom, rangeTo - rangeFrom); + if (url.isEmpty() || !expandLinks || lnkFrom != rangeFrom || blockFrom != rangeTo) { + result += r; + } else { + if (r.size() > 3 && _text.midRef(lnkFrom, r.size() - 3) == url.midRef(0, r.size() - 3)) { // same link + result += url; + } else { + result.append(r).append(qsl(" ( ")).append(url).append(qsl(" )")); + } + } + } + } + lnkIndex = blockLnkIndex; + lnkFrom = blockFrom; + } + if (i == e) break; + + TextBlockType type = (*i)->type(); + if (type == TextBlockSkip) continue; + + if (!blockLnkIndex) { + int32 rangeFrom = qMax(selectedFrom, (*i)->from()), rangeTo = qMin(selectedTo, uint16((*i)->from() + TextPainter::_blockLength(this, i, e))); + if (rangeTo > rangeFrom) { + result += _text.midRef(rangeFrom, rangeTo - rangeFrom); + } + } + } + return result; +} + +void Text::clean() { + for (TextBlocks::iterator i = _blocks.begin(), e = _blocks.end(); i != e; ++i) { + delete *i; + } + _blocks.clear(); + _links.clear(); + _maxWidth = _minHeight = 0; + _startDir = Qt::LayoutDirectionAuto; +} + +// COPIED FROM qtextlayout.cpp AND MODIFIED +namespace { + + struct ScriptLine { + int32 length; + QFixed textWidth; + }; + + struct LineBreakHelper + { + LineBreakHelper() + : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0) + { + } + + + ScriptLine tmpData; + ScriptLine spaceData; + + QGlyphLayout glyphs; + + int glyphCount; + int maxGlyphs; + int currentPosition; + glyph_t previousGlyph; + + QFixed rightBearing; + + QFontEngine *fontEngine; + const unsigned short *logClusters; + + inline glyph_t currentGlyph() const + { + Q_ASSERT(currentPosition > 0); + Q_ASSERT(logClusters[currentPosition - 1] < glyphs.numGlyphs); + + return glyphs.glyphs[logClusters[currentPosition - 1]]; + } + + inline void saveCurrentGlyph() + { + previousGlyph = 0; + if (currentPosition > 0 && + logClusters[currentPosition - 1] < glyphs.numGlyphs) { + previousGlyph = currentGlyph(); // needed to calculate right bearing later + } + } + + inline void adjustRightBearing(glyph_t glyph) + { + qreal rb; + fontEngine->getGlyphBearings(glyph, 0, &rb); + rightBearing = qMin(QFixed(), QFixed::fromReal(rb)); + } + + inline void adjustRightBearing() + { + if (currentPosition <= 0) + return; + adjustRightBearing(currentGlyph()); + } + + inline void adjustPreviousRightBearing() + { + if (previousGlyph > 0) + adjustRightBearing(previousGlyph); + } + + }; + + static inline void addNextCluster(int &pos, int end, ScriptLine &line, int &glyphCount, + const QScriptItem ¤t, const unsigned short *logClusters, + const QGlyphLayout &glyphs) + { + int glyphPosition = logClusters[pos]; + do { // got to the first next cluster + ++pos; + ++line.length; + } while (pos < end && logClusters[pos] == glyphPosition); + do { // calculate the textWidth for the rest of the current cluster. + if (!glyphs.attributes[glyphPosition].dontPrint) + line.textWidth += glyphs.advances[glyphPosition]; + ++glyphPosition; + } while (glyphPosition < current.num_glyphs && !glyphs.attributes[glyphPosition].clusterStart); + + Q_ASSERT((pos == end && glyphPosition == current.num_glyphs) || logClusters[pos] == glyphPosition); + + ++glyphCount; + } + +} // anonymous namespace + +class BlockParser { +public: + + BlockParser(QTextEngine *e, TextBlock *b, QFixed minResizeWidth, int32 blockFrom) : eng(e), block(b) { + parseWords(minResizeWidth, blockFrom); + } + + void parseWords(QFixed minResizeWidth, int32 blockFrom) { + LineBreakHelper lbh; + + lbh.maxGlyphs = INT_MAX; + + int item = -1; + int newItem = eng->findItem(0); + + style::align alignment = eng->option.alignment(); + + const QCharAttributes *attributes = eng->attributes(); + if (!attributes) + return; + lbh.currentPosition = 0; + int end = 0; + lbh.logClusters = eng->layoutData->logClustersPtr; + lbh.previousGlyph = 0; + + block->_lpadding = 0; + block->_words.clear(); + + int wordStart = lbh.currentPosition; + + bool addingEachGrapheme = false; + int lastGraphemeBoundaryPosition = -1; + ScriptLine lastGraphemeBoundaryLine; + + while (newItem < eng->layoutData->items.size()) { + if (newItem != item) { + item = newItem; + const QScriptItem ¤t = eng->layoutData->items[item]; + if (!current.num_glyphs) { + eng->shape(item); + attributes = eng->attributes(); + if (!attributes) + return; + lbh.logClusters = eng->layoutData->logClustersPtr; + } + lbh.currentPosition = current.position; + end = current.position + eng->length(item); + lbh.glyphs = eng->shapedGlyphs(¤t); + QFontEngine *fontEngine = eng->fontEngine(current); + if (lbh.fontEngine != fontEngine) { + lbh.fontEngine = fontEngine; + } + } + const QScriptItem ¤t = eng->layoutData->items[item]; + + if (attributes[lbh.currentPosition].whiteSpace) { + while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace) + addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount, + current, lbh.logClusters, lbh.glyphs); + + if (block->_words.isEmpty()) { + block->_lpadding = lbh.spaceData.textWidth; + } else { + block->_words.back().rpadding += lbh.spaceData.textWidth; + block->_width += lbh.spaceData.textWidth; + } + lbh.spaceData.length = 0; + lbh.spaceData.textWidth = 0; + + wordStart = lbh.currentPosition; + + addingEachGrapheme = false; + lastGraphemeBoundaryPosition = -1; + lastGraphemeBoundaryLine = ScriptLine(); + } else { + do { + addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount, + current, lbh.logClusters, lbh.glyphs); + + if (lbh.currentPosition >= eng->layoutData->string.length() + || attributes[lbh.currentPosition].whiteSpace + || attributes[lbh.currentPosition].lineBreak) { + lbh.adjustRightBearing(); + block->_words.push_back(TextWord(wordStart + blockFrom, lbh.tmpData.textWidth, qMin(QFixed(), lbh.rightBearing))); + block->_width += lbh.tmpData.textWidth; + lbh.tmpData.textWidth = 0; + lbh.tmpData.length = 0; + wordStart = lbh.currentPosition; + break; + } else if (attributes[lbh.currentPosition].graphemeBoundary) { + if (!addingEachGrapheme && lbh.tmpData.textWidth > minResizeWidth) { + if (lastGraphemeBoundaryPosition >= 0) { + lbh.adjustPreviousRightBearing(); + block->_words.push_back(TextWord(wordStart + blockFrom, -lastGraphemeBoundaryLine.textWidth, qMin(QFixed(), lbh.rightBearing))); + block->_width += lastGraphemeBoundaryLine.textWidth; + lbh.tmpData.textWidth -= lastGraphemeBoundaryLine.textWidth; + lbh.tmpData.length -= lastGraphemeBoundaryLine.length; + wordStart = lastGraphemeBoundaryPosition; + } + addingEachGrapheme = true; + } + if (addingEachGrapheme) { + lbh.adjustRightBearing(); + block->_words.push_back(TextWord(wordStart + blockFrom, -lbh.tmpData.textWidth, qMin(QFixed(), lbh.rightBearing))); + block->_width += lbh.tmpData.textWidth; + lbh.tmpData.textWidth = 0; + lbh.tmpData.length = 0; + wordStart = lbh.currentPosition; + } else { + lastGraphemeBoundaryPosition = lbh.currentPosition; + lastGraphemeBoundaryLine = lbh.tmpData; + lbh.saveCurrentGlyph(); + } + } + } while (lbh.currentPosition < end); + } + if (lbh.currentPosition == end) + newItem = item + 1; + } + if (block->_words.isEmpty()) { + block->_rpadding = 0; + } else { + block->_rpadding = block->_words.back().rpadding; + block->_width -= block->_rpadding; + block->_words.squeeze(); + } + } + +private: + + TextBlock *block; + QTextEngine *eng; + +}; + +TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResizeWidth, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex) : ITextBlock(font, str, from, length, flags, color, lnkIndex) { + _flags |= ((TextBlockText & 0x0F) << 8); + if (length) { + style::font blockFont = font; + if (!flags && lnkIndex) { + // should use textStyle lnkFlags somehow.. not supported + } + if (flags & TextBlockBold) blockFont = blockFont->bold(); + if (flags & TextBlockItalic) blockFont = blockFont->italic(); + if (flags & TextBlockUnderline) blockFont = blockFont->underline(); + + QStackTextEngine engine(str.mid(_from, length), blockFont->f); + engine.itemize(); + + QTextLayout layout(&engine); + layout.beginLayout(); + layout.createLine(); + + BlockParser parser(&engine, this, minResizeWidth, _from); + + layout.endLayout(); + } +} + +EmojiBlock::EmojiBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex, const EmojiData *emoji) : ITextBlock(font, str, from, length, flags, color, lnkIndex), emoji(emoji) { + _flags |= ((TextBlockEmoji & 0x0F) << 8); + _width = int(st::emojiSize + 2 * st::emojiPadding); +} + +SkipBlock::SkipBlock(const style::font &font, const QString &str, uint16 from, int32 w, int32 h, uint16 lnkIndex) : ITextBlock(font, str, from, 1, 0, style::color(), lnkIndex), _height(h) { + _flags |= ((TextBlockSkip & 0x0F) << 8); + _width = w; +} + +namespace { + void regOneProtocol(const QString &protocol) { + validProtocols.insert(hashCrc32(protocol.constData(), protocol.size() * sizeof(QChar))); + } + void regOneTopDomain(const QString &domain) { + validTopDomains.insert(hashCrc32(domain.constData(), domain.size() * sizeof(QChar))); + } + void initLinkSets() { + regOneProtocol(qsl("itmss")); // itunes + regOneProtocol(qsl("http")); + regOneProtocol(qsl("https")); + regOneProtocol(qsl("ftp")); + + regOneTopDomain(qsl("ac")); + regOneTopDomain(qsl("ad")); + regOneTopDomain(qsl("ae")); + regOneTopDomain(qsl("af")); + regOneTopDomain(qsl("ag")); + regOneTopDomain(qsl("ai")); + regOneTopDomain(qsl("al")); + regOneTopDomain(qsl("am")); + regOneTopDomain(qsl("an")); + regOneTopDomain(qsl("ao")); + regOneTopDomain(qsl("aq")); + regOneTopDomain(qsl("ar")); + regOneTopDomain(qsl("as")); + regOneTopDomain(qsl("at")); + regOneTopDomain(qsl("au")); + regOneTopDomain(qsl("aw")); + regOneTopDomain(qsl("ax")); + regOneTopDomain(qsl("az")); + regOneTopDomain(qsl("ba")); + regOneTopDomain(qsl("bb")); + regOneTopDomain(qsl("bd")); + regOneTopDomain(qsl("be")); + regOneTopDomain(qsl("bf")); + regOneTopDomain(qsl("bg")); + regOneTopDomain(qsl("bh")); + regOneTopDomain(qsl("bi")); + regOneTopDomain(qsl("bj")); + regOneTopDomain(qsl("bm")); + regOneTopDomain(qsl("bn")); + regOneTopDomain(qsl("bo")); + regOneTopDomain(qsl("br")); + regOneTopDomain(qsl("bs")); + regOneTopDomain(qsl("bt")); + regOneTopDomain(qsl("bv")); + regOneTopDomain(qsl("bw")); + regOneTopDomain(qsl("by")); + regOneTopDomain(qsl("bz")); + regOneTopDomain(qsl("ca")); + regOneTopDomain(qsl("cc")); + regOneTopDomain(qsl("cd")); + regOneTopDomain(qsl("cf")); + regOneTopDomain(qsl("cg")); + regOneTopDomain(qsl("ch")); + regOneTopDomain(qsl("ci")); + regOneTopDomain(qsl("ck")); + regOneTopDomain(qsl("cl")); + regOneTopDomain(qsl("cm")); + regOneTopDomain(qsl("cn")); + regOneTopDomain(qsl("co")); + regOneTopDomain(qsl("cr")); + regOneTopDomain(qsl("cu")); + regOneTopDomain(qsl("cv")); + regOneTopDomain(qsl("cx")); + regOneTopDomain(qsl("cy")); + regOneTopDomain(qsl("cz")); + regOneTopDomain(qsl("de")); + regOneTopDomain(qsl("dj")); + regOneTopDomain(qsl("dk")); + regOneTopDomain(qsl("dm")); + regOneTopDomain(qsl("do")); + regOneTopDomain(qsl("dz")); + regOneTopDomain(qsl("ec")); + regOneTopDomain(qsl("ee")); + regOneTopDomain(qsl("eg")); + regOneTopDomain(qsl("eh")); + regOneTopDomain(qsl("er")); + regOneTopDomain(qsl("es")); + regOneTopDomain(qsl("et")); + regOneTopDomain(qsl("eu")); + regOneTopDomain(qsl("fi")); + regOneTopDomain(qsl("fj")); + regOneTopDomain(qsl("fk")); + regOneTopDomain(qsl("fm")); + regOneTopDomain(qsl("fo")); + regOneTopDomain(qsl("fr")); + regOneTopDomain(qsl("ga")); + regOneTopDomain(qsl("gd")); + regOneTopDomain(qsl("ge")); + regOneTopDomain(qsl("gf")); + regOneTopDomain(qsl("gg")); + regOneTopDomain(qsl("gh")); + regOneTopDomain(qsl("gi")); + regOneTopDomain(qsl("gl")); + regOneTopDomain(qsl("gm")); + regOneTopDomain(qsl("gn")); + regOneTopDomain(qsl("gp")); + regOneTopDomain(qsl("gq")); + regOneTopDomain(qsl("gr")); + regOneTopDomain(qsl("gs")); + regOneTopDomain(qsl("gt")); + regOneTopDomain(qsl("gu")); + regOneTopDomain(qsl("gw")); + regOneTopDomain(qsl("gy")); + regOneTopDomain(qsl("hk")); + regOneTopDomain(qsl("hm")); + regOneTopDomain(qsl("hn")); + regOneTopDomain(qsl("hr")); + regOneTopDomain(qsl("ht")); + regOneTopDomain(qsl("hu")); + regOneTopDomain(qsl("id")); + regOneTopDomain(qsl("ie")); + regOneTopDomain(qsl("il")); + regOneTopDomain(qsl("im")); + regOneTopDomain(qsl("in")); + regOneTopDomain(qsl("io")); + regOneTopDomain(qsl("iq")); + regOneTopDomain(qsl("ir")); + regOneTopDomain(qsl("is")); + regOneTopDomain(qsl("it")); + regOneTopDomain(qsl("je")); + regOneTopDomain(qsl("jm")); + regOneTopDomain(qsl("jo")); + regOneTopDomain(qsl("jp")); + regOneTopDomain(qsl("ke")); + regOneTopDomain(qsl("kg")); + regOneTopDomain(qsl("kh")); + regOneTopDomain(qsl("ki")); + regOneTopDomain(qsl("km")); + regOneTopDomain(qsl("kn")); + regOneTopDomain(qsl("kp")); + regOneTopDomain(qsl("kr")); + regOneTopDomain(qsl("kw")); + regOneTopDomain(qsl("ky")); + regOneTopDomain(qsl("kz")); + regOneTopDomain(qsl("la")); + regOneTopDomain(qsl("lb")); + regOneTopDomain(qsl("lc")); + regOneTopDomain(qsl("li")); + regOneTopDomain(qsl("lk")); + regOneTopDomain(qsl("lr")); + regOneTopDomain(qsl("ls")); + regOneTopDomain(qsl("lt")); + regOneTopDomain(qsl("lu")); + regOneTopDomain(qsl("lv")); + regOneTopDomain(qsl("ly")); + regOneTopDomain(qsl("ma")); + regOneTopDomain(qsl("mc")); + regOneTopDomain(qsl("md")); + regOneTopDomain(qsl("me")); + regOneTopDomain(qsl("mg")); + regOneTopDomain(qsl("mh")); + regOneTopDomain(qsl("mk")); + regOneTopDomain(qsl("ml")); + regOneTopDomain(qsl("mm")); + regOneTopDomain(qsl("mn")); + regOneTopDomain(qsl("mo")); + regOneTopDomain(qsl("mp")); + regOneTopDomain(qsl("mq")); + regOneTopDomain(qsl("mr")); + regOneTopDomain(qsl("ms")); + regOneTopDomain(qsl("mt")); + regOneTopDomain(qsl("mu")); + regOneTopDomain(qsl("mv")); + regOneTopDomain(qsl("mw")); + regOneTopDomain(qsl("mx")); + regOneTopDomain(qsl("my")); + regOneTopDomain(qsl("mz")); + regOneTopDomain(qsl("na")); + regOneTopDomain(qsl("nc")); + regOneTopDomain(qsl("ne")); + regOneTopDomain(qsl("nf")); + regOneTopDomain(qsl("ng")); + regOneTopDomain(qsl("ni")); + regOneTopDomain(qsl("nl")); + regOneTopDomain(qsl("no")); + regOneTopDomain(qsl("np")); + regOneTopDomain(qsl("nr")); + regOneTopDomain(qsl("nu")); + regOneTopDomain(qsl("nz")); + regOneTopDomain(qsl("om")); + regOneTopDomain(qsl("pa")); + regOneTopDomain(qsl("pe")); + regOneTopDomain(qsl("pf")); + regOneTopDomain(qsl("pg")); + regOneTopDomain(qsl("ph")); + regOneTopDomain(qsl("pk")); + regOneTopDomain(qsl("pl")); + regOneTopDomain(qsl("pm")); + regOneTopDomain(qsl("pn")); + regOneTopDomain(qsl("pr")); + regOneTopDomain(qsl("ps")); + regOneTopDomain(qsl("pt")); + regOneTopDomain(qsl("pw")); + regOneTopDomain(qsl("py")); + regOneTopDomain(qsl("qa")); + regOneTopDomain(qsl("re")); + regOneTopDomain(qsl("ro")); + regOneTopDomain(qsl("ru")); + regOneTopDomain(qsl("rs")); + regOneTopDomain(qsl("rw")); + regOneTopDomain(qsl("sa")); + regOneTopDomain(qsl("sb")); + regOneTopDomain(qsl("sc")); + regOneTopDomain(qsl("sd")); + regOneTopDomain(qsl("se")); + regOneTopDomain(qsl("sg")); + regOneTopDomain(qsl("sh")); + regOneTopDomain(qsl("si")); + regOneTopDomain(qsl("sj")); + regOneTopDomain(qsl("sk")); + regOneTopDomain(qsl("sl")); + regOneTopDomain(qsl("sm")); + regOneTopDomain(qsl("sn")); + regOneTopDomain(qsl("so")); + regOneTopDomain(qsl("sr")); + regOneTopDomain(qsl("ss")); + regOneTopDomain(qsl("st")); + regOneTopDomain(qsl("su")); + regOneTopDomain(qsl("sv")); + regOneTopDomain(qsl("sx")); + regOneTopDomain(qsl("sy")); + regOneTopDomain(qsl("sz")); + regOneTopDomain(qsl("tc")); + regOneTopDomain(qsl("td")); + regOneTopDomain(qsl("tf")); + regOneTopDomain(qsl("tg")); + regOneTopDomain(qsl("th")); + regOneTopDomain(qsl("tj")); + regOneTopDomain(qsl("tk")); + regOneTopDomain(qsl("tl")); + regOneTopDomain(qsl("tm")); + regOneTopDomain(qsl("tn")); + regOneTopDomain(qsl("to")); + regOneTopDomain(qsl("tp")); + regOneTopDomain(qsl("tr")); + regOneTopDomain(qsl("tt")); + regOneTopDomain(qsl("tv")); + regOneTopDomain(qsl("tw")); + regOneTopDomain(qsl("tz")); + regOneTopDomain(qsl("ua")); + regOneTopDomain(qsl("ug")); + regOneTopDomain(qsl("uk")); + regOneTopDomain(qsl("um")); + regOneTopDomain(qsl("us")); + regOneTopDomain(qsl("uy")); + regOneTopDomain(qsl("uz")); + regOneTopDomain(qsl("va")); + regOneTopDomain(qsl("vc")); + regOneTopDomain(qsl("ve")); + regOneTopDomain(qsl("vg")); + regOneTopDomain(qsl("vi")); + regOneTopDomain(qsl("vn")); + regOneTopDomain(qsl("vu")); + regOneTopDomain(qsl("wf")); + regOneTopDomain(qsl("ws")); + regOneTopDomain(qsl("ye")); + regOneTopDomain(qsl("yt")); + regOneTopDomain(qsl("yu")); + regOneTopDomain(qsl("za")); + regOneTopDomain(qsl("zm")); + regOneTopDomain(qsl("zw")); + regOneTopDomain(qsl("arpa")); + regOneTopDomain(qsl("aero")); + regOneTopDomain(qsl("asia")); + regOneTopDomain(qsl("biz")); + regOneTopDomain(qsl("cat")); + regOneTopDomain(qsl("com")); + regOneTopDomain(qsl("coop")); + regOneTopDomain(qsl("info")); + regOneTopDomain(qsl("int")); + regOneTopDomain(qsl("jobs")); + regOneTopDomain(qsl("mobi")); + regOneTopDomain(qsl("museum")); + regOneTopDomain(qsl("name")); + regOneTopDomain(qsl("net")); + regOneTopDomain(qsl("org")); + regOneTopDomain(qsl("post")); + regOneTopDomain(qsl("pro")); + regOneTopDomain(qsl("tel")); + regOneTopDomain(qsl("travel")); + regOneTopDomain(qsl("xxx")); + regOneTopDomain(qsl("edu")); + regOneTopDomain(qsl("gov")); + regOneTopDomain(qsl("mil")); + regOneTopDomain(qsl("local")); + regOneTopDomain(qsl("xn--lgbbat1ad8j")); + regOneTopDomain(qsl("xn--54b7fta0cc")); + regOneTopDomain(qsl("xn--fiqs8s")); + regOneTopDomain(qsl("xn--fiqz9s")); + regOneTopDomain(qsl("xn--wgbh1c")); + regOneTopDomain(qsl("xn--node")); + regOneTopDomain(qsl("xn--j6w193g")); + regOneTopDomain(qsl("xn--h2brj9c")); + regOneTopDomain(qsl("xn--mgbbh1a71e")); + regOneTopDomain(qsl("xn--fpcrj9c3d")); + regOneTopDomain(qsl("xn--gecrj9c")); + regOneTopDomain(qsl("xn--s9brj9c")); + regOneTopDomain(qsl("xn--xkc2dl3a5ee0h")); + regOneTopDomain(qsl("xn--45brj9c")); + regOneTopDomain(qsl("xn--mgba3a4f16a")); + regOneTopDomain(qsl("xn--mgbayh7gpa")); + regOneTopDomain(qsl("xn--80ao21a")); + regOneTopDomain(qsl("xn--mgbx4cd0ab")); + regOneTopDomain(qsl("xn--l1acc")); + regOneTopDomain(qsl("xn--mgbc0a9azcg")); + regOneTopDomain(qsl("xn--mgb9awbf")); + regOneTopDomain(qsl("xn--mgbai9azgqp6j")); + regOneTopDomain(qsl("xn--ygbi2ammx")); + regOneTopDomain(qsl("xn--wgbl6a")); + regOneTopDomain(qsl("xn--p1ai")); + regOneTopDomain(qsl("xn--mgberp4a5d4ar")); + regOneTopDomain(qsl("xn--90a3ac")); + regOneTopDomain(qsl("xn--yfro4i67o")); + regOneTopDomain(qsl("xn--clchc0ea0b2g2a9gcd")); + regOneTopDomain(qsl("xn--3e0b707e")); + regOneTopDomain(qsl("xn--fzc2c9e2c")); + regOneTopDomain(qsl("xn--xkc2al3hye2a")); + regOneTopDomain(qsl("xn--mgbtf8fl")); + regOneTopDomain(qsl("xn--kprw13d")); + regOneTopDomain(qsl("xn--kpry57d")); + regOneTopDomain(qsl("xn--o3cw4h")); + regOneTopDomain(qsl("xn--pgbs0dh")); + regOneTopDomain(qsl("xn--j1amh")); + regOneTopDomain(qsl("xn--mgbaam7a8h")); + regOneTopDomain(qsl("xn--mgb2ddes")); + regOneTopDomain(qsl("xn--ogbpf8fl")); + regOneTopDomain(QString::fromUtf8("рф")); + } + + // accent char list taken from https://github.com/aristus/accent-folding + inline QChar chNoAccent(int32 code) { + switch (code) { + case 7834: return QChar(97); + case 193: return QChar(97); + case 225: return QChar(97); + case 192: return QChar(97); + case 224: return QChar(97); + case 258: return QChar(97); + case 259: return QChar(97); + case 7854: return QChar(97); + case 7855: return QChar(97); + case 7856: return QChar(97); + case 7857: return QChar(97); + case 7860: return QChar(97); + case 7861: return QChar(97); + case 7858: return QChar(97); + case 7859: return QChar(97); + case 194: return QChar(97); + case 226: return QChar(97); + case 7844: return QChar(97); + case 7845: return QChar(97); + case 7846: return QChar(97); + case 7847: return QChar(97); + case 7850: return QChar(97); + case 7851: return QChar(97); + case 7848: return QChar(97); + case 7849: return QChar(97); + case 461: return QChar(97); + case 462: return QChar(97); + case 197: return QChar(97); + case 229: return QChar(97); + case 506: return QChar(97); + case 507: return QChar(97); + case 196: return QChar(97); + case 228: return QChar(97); + case 478: return QChar(97); + case 479: return QChar(97); + case 195: return QChar(97); + case 227: return QChar(97); + case 550: return QChar(97); + case 551: return QChar(97); + case 480: return QChar(97); + case 481: return QChar(97); + case 260: return QChar(97); + case 261: return QChar(97); + case 256: return QChar(97); + case 257: return QChar(97); + case 7842: return QChar(97); + case 7843: return QChar(97); + case 512: return QChar(97); + case 513: return QChar(97); + case 514: return QChar(97); + case 515: return QChar(97); + case 7840: return QChar(97); + case 7841: return QChar(97); + case 7862: return QChar(97); + case 7863: return QChar(97); + case 7852: return QChar(97); + case 7853: return QChar(97); + case 7680: return QChar(97); + case 7681: return QChar(97); + case 570: return QChar(97); + case 11365: return QChar(97); + case 508: return QChar(97); + case 509: return QChar(97); + case 482: return QChar(97); + case 483: return QChar(97); + case 7682: return QChar(98); + case 7683: return QChar(98); + case 7684: return QChar(98); + case 7685: return QChar(98); + case 7686: return QChar(98); + case 7687: return QChar(98); + case 579: return QChar(98); + case 384: return QChar(98); + case 7532: return QChar(98); + case 385: return QChar(98); + case 595: return QChar(98); + case 386: return QChar(98); + case 387: return QChar(98); + case 262: return QChar(99); + case 263: return QChar(99); + case 264: return QChar(99); + case 265: return QChar(99); + case 268: return QChar(99); + case 269: return QChar(99); + case 266: return QChar(99); + case 267: return QChar(99); + case 199: return QChar(99); + case 231: return QChar(99); + case 7688: return QChar(99); + case 7689: return QChar(99); + case 571: return QChar(99); + case 572: return QChar(99); + case 391: return QChar(99); + case 392: return QChar(99); + case 597: return QChar(99); + case 270: return QChar(100); + case 271: return QChar(100); + case 7690: return QChar(100); + case 7691: return QChar(100); + case 7696: return QChar(100); + case 7697: return QChar(100); + case 7692: return QChar(100); + case 7693: return QChar(100); + case 7698: return QChar(100); + case 7699: return QChar(100); + case 7694: return QChar(100); + case 7695: return QChar(100); + case 272: return QChar(100); + case 273: return QChar(100); + case 7533: return QChar(100); + case 393: return QChar(100); + case 598: return QChar(100); + case 394: return QChar(100); + case 599: return QChar(100); + case 395: return QChar(100); + case 396: return QChar(100); + case 545: return QChar(100); + case 240: return QChar(100); + case 201: return QChar(101); + case 399: return QChar(101); + case 398: return QChar(101); + case 477: return QChar(101); + case 233: return QChar(101); + case 200: return QChar(101); + case 232: return QChar(101); + case 276: return QChar(101); + case 277: return QChar(101); + case 202: return QChar(101); + case 234: return QChar(101); + case 7870: return QChar(101); + case 7871: return QChar(101); + case 7872: return QChar(101); + case 7873: return QChar(101); + case 7876: return QChar(101); + case 7877: return QChar(101); + case 7874: return QChar(101); + case 7875: return QChar(101); + case 282: return QChar(101); + case 283: return QChar(101); + case 203: return QChar(101); + case 235: return QChar(101); + case 7868: return QChar(101); + case 7869: return QChar(101); + case 278: return QChar(101); + case 279: return QChar(101); + case 552: return QChar(101); + case 553: return QChar(101); + case 7708: return QChar(101); + case 7709: return QChar(101); + case 280: return QChar(101); + case 281: return QChar(101); + case 274: return QChar(101); + case 275: return QChar(101); + case 7702: return QChar(101); + case 7703: return QChar(101); + case 7700: return QChar(101); + case 7701: return QChar(101); + case 7866: return QChar(101); + case 7867: return QChar(101); + case 516: return QChar(101); + case 517: return QChar(101); + case 518: return QChar(101); + case 519: return QChar(101); + case 7864: return QChar(101); + case 7865: return QChar(101); + case 7878: return QChar(101); + case 7879: return QChar(101); + case 7704: return QChar(101); + case 7705: return QChar(101); + case 7706: return QChar(101); + case 7707: return QChar(101); + case 582: return QChar(101); + case 583: return QChar(101); + case 602: return QChar(101); + case 605: return QChar(101); + case 7710: return QChar(102); + case 7711: return QChar(102); + case 7534: return QChar(102); + case 401: return QChar(102); + case 402: return QChar(102); + case 500: return QChar(103); + case 501: return QChar(103); + case 286: return QChar(103); + case 287: return QChar(103); + case 284: return QChar(103); + case 285: return QChar(103); + case 486: return QChar(103); + case 487: return QChar(103); + case 288: return QChar(103); + case 289: return QChar(103); + case 290: return QChar(103); + case 291: return QChar(103); + case 7712: return QChar(103); + case 7713: return QChar(103); + case 484: return QChar(103); + case 485: return QChar(103); + case 403: return QChar(103); + case 608: return QChar(103); + case 292: return QChar(104); + case 293: return QChar(104); + case 542: return QChar(104); + case 543: return QChar(104); + case 7718: return QChar(104); + case 7719: return QChar(104); + case 7714: return QChar(104); + case 7715: return QChar(104); + case 7720: return QChar(104); + case 7721: return QChar(104); + case 7716: return QChar(104); + case 7717: return QChar(104); + case 7722: return QChar(104); + case 7723: return QChar(104); + case 817: return QChar(104); + case 7830: return QChar(104); + case 294: return QChar(104); + case 295: return QChar(104); + case 11367: return QChar(104); + case 11368: return QChar(104); + case 205: return QChar(105); + case 237: return QChar(105); + case 204: return QChar(105); + case 236: return QChar(105); + case 300: return QChar(105); + case 301: return QChar(105); + case 206: return QChar(105); + case 238: return QChar(105); + case 463: return QChar(105); + case 464: return QChar(105); + case 207: return QChar(105); + case 239: return QChar(105); + case 7726: return QChar(105); + case 7727: return QChar(105); + case 296: return QChar(105); + case 297: return QChar(105); + case 304: return QChar(105); + case 302: return QChar(105); + case 303: return QChar(105); + case 298: return QChar(105); + case 299: return QChar(105); + case 7880: return QChar(105); + case 7881: return QChar(105); + case 520: return QChar(105); + case 521: return QChar(105); + case 522: return QChar(105); + case 523: return QChar(105); + case 7882: return QChar(105); + case 7883: return QChar(105); + case 7724: return QChar(105); + case 7725: return QChar(105); + case 305: return QChar(105); + case 407: return QChar(105); + case 616: return QChar(105); + case 308: return QChar(106); + case 309: return QChar(106); + case 780: return QChar(106); + case 496: return QChar(106); + case 567: return QChar(106); + case 584: return QChar(106); + case 585: return QChar(106); + case 669: return QChar(106); + case 607: return QChar(106); + case 644: return QChar(106); + case 7728: return QChar(107); + case 7729: return QChar(107); + case 488: return QChar(107); + case 489: return QChar(107); + case 310: return QChar(107); + case 311: return QChar(107); + case 7730: return QChar(107); + case 7731: return QChar(107); + case 7732: return QChar(107); + case 7733: return QChar(107); + case 408: return QChar(107); + case 409: return QChar(107); + case 11369: return QChar(107); + case 11370: return QChar(107); + case 313: return QChar(97); + case 314: return QChar(108); + case 317: return QChar(108); + case 318: return QChar(108); + case 315: return QChar(108); + case 316: return QChar(108); + case 7734: return QChar(108); + case 7735: return QChar(108); + case 7736: return QChar(108); + case 7737: return QChar(108); + case 7740: return QChar(108); + case 7741: return QChar(108); + case 7738: return QChar(108); + case 7739: return QChar(108); + case 321: return QChar(108); + case 322: return QChar(108); + case 803: return QChar(108); + case 319: return QChar(108); + case 320: return QChar(108); + case 573: return QChar(108); + case 410: return QChar(108); + case 11360: return QChar(108); + case 11361: return QChar(108); + case 11362: return QChar(108); + case 619: return QChar(108); + case 620: return QChar(108); + case 621: return QChar(108); + case 564: return QChar(108); + case 7742: return QChar(109); + case 7743: return QChar(109); + case 7744: return QChar(109); + case 7745: return QChar(109); + case 7746: return QChar(109); + case 7747: return QChar(109); + case 625: return QChar(109); + case 323: return QChar(110); + case 324: return QChar(110); + case 504: return QChar(110); + case 505: return QChar(110); + case 327: return QChar(110); + case 328: return QChar(110); + case 209: return QChar(110); + case 241: return QChar(110); + case 7748: return QChar(110); + case 7749: return QChar(110); + case 325: return QChar(110); + case 326: return QChar(110); + case 7750: return QChar(110); + case 7751: return QChar(110); + case 7754: return QChar(110); + case 7755: return QChar(110); + case 7752: return QChar(110); + case 7753: return QChar(110); + case 413: return QChar(110); + case 626: return QChar(110); + case 544: return QChar(110); + case 414: return QChar(110); + case 627: return QChar(110); + case 565: return QChar(110); + case 776: return QChar(116); + case 211: return QChar(111); + case 243: return QChar(111); + case 210: return QChar(111); + case 242: return QChar(111); + case 334: return QChar(111); + case 335: return QChar(111); + case 212: return QChar(111); + case 244: return QChar(111); + case 7888: return QChar(111); + case 7889: return QChar(111); + case 7890: return QChar(111); + case 7891: return QChar(111); + case 7894: return QChar(111); + case 7895: return QChar(111); + case 7892: return QChar(111); + case 7893: return QChar(111); + case 465: return QChar(111); + case 466: return QChar(111); + case 214: return QChar(111); + case 246: return QChar(111); + case 554: return QChar(111); + case 555: return QChar(111); + case 336: return QChar(111); + case 337: return QChar(111); + case 213: return QChar(111); + case 245: return QChar(111); + case 7756: return QChar(111); + case 7757: return QChar(111); + case 7758: return QChar(111); + case 7759: return QChar(111); + case 556: return QChar(111); + case 557: return QChar(111); + case 558: return QChar(111); + case 559: return QChar(111); + case 560: return QChar(111); + case 561: return QChar(111); + case 216: return QChar(111); + case 248: return QChar(111); + case 510: return QChar(111); + case 511: return QChar(111); + case 490: return QChar(111); + case 491: return QChar(111); + case 492: return QChar(111); + case 493: return QChar(111); + case 332: return QChar(111); + case 333: return QChar(111); + case 7762: return QChar(111); + case 7763: return QChar(111); + case 7760: return QChar(111); + case 7761: return QChar(111); + case 7886: return QChar(111); + case 7887: return QChar(111); + case 524: return QChar(111); + case 525: return QChar(111); + case 526: return QChar(111); + case 527: return QChar(111); + case 416: return QChar(111); + case 417: return QChar(111); + case 7898: return QChar(111); + case 7899: return QChar(111); + case 7900: return QChar(111); + case 7901: return QChar(111); + case 7904: return QChar(111); + case 7905: return QChar(111); + case 7902: return QChar(111); + case 7903: return QChar(111); + case 7906: return QChar(111); + case 7907: return QChar(111); + case 7884: return QChar(111); + case 7885: return QChar(111); + case 7896: return QChar(111); + case 7897: return QChar(111); + case 415: return QChar(111); + case 629: return QChar(111); + case 7764: return QChar(112); + case 7765: return QChar(112); + case 7766: return QChar(112); + case 7767: return QChar(112); + case 11363: return QChar(112); + case 420: return QChar(112); + case 421: return QChar(112); + case 771: return QChar(112); + case 672: return QChar(113); + case 586: return QChar(113); + case 587: return QChar(113); + case 340: return QChar(114); + case 341: return QChar(114); + case 344: return QChar(114); + case 345: return QChar(114); + case 7768: return QChar(114); + case 7769: return QChar(114); + case 342: return QChar(114); + case 343: return QChar(114); + case 528: return QChar(114); + case 529: return QChar(114); + case 530: return QChar(114); + case 531: return QChar(114); + case 7770: return QChar(114); + case 7771: return QChar(114); + case 7772: return QChar(114); + case 7773: return QChar(114); + case 7774: return QChar(114); + case 7775: return QChar(114); + case 588: return QChar(114); + case 589: return QChar(114); + case 7538: return QChar(114); + case 636: return QChar(114); + case 11364: return QChar(114); + case 637: return QChar(114); + case 638: return QChar(114); + case 7539: return QChar(114); + case 223: return QChar(115); + case 346: return QChar(115); + case 347: return QChar(115); + case 7780: return QChar(115); + case 7781: return QChar(115); + case 348: return QChar(115); + case 349: return QChar(115); + case 352: return QChar(115); + case 353: return QChar(115); + case 7782: return QChar(115); + case 7783: return QChar(115); + case 7776: return QChar(115); + case 7777: return QChar(115); + case 7835: return QChar(115); + case 350: return QChar(115); + case 351: return QChar(115); + case 7778: return QChar(115); + case 7779: return QChar(115); + case 7784: return QChar(115); + case 7785: return QChar(115); + case 536: return QChar(115); + case 537: return QChar(115); + case 642: return QChar(115); + case 809: return QChar(115); + case 222: return QChar(116); + case 254: return QChar(116); + case 356: return QChar(116); + case 357: return QChar(116); + case 7831: return QChar(116); + case 7786: return QChar(116); + case 7787: return QChar(116); + case 354: return QChar(116); + case 355: return QChar(116); + case 7788: return QChar(116); + case 7789: return QChar(116); + case 538: return QChar(116); + case 539: return QChar(116); + case 7792: return QChar(116); + case 7793: return QChar(116); + case 7790: return QChar(116); + case 7791: return QChar(116); + case 358: return QChar(116); + case 359: return QChar(116); + case 574: return QChar(116); + case 11366: return QChar(116); + case 7541: return QChar(116); + case 427: return QChar(116); + case 428: return QChar(116); + case 429: return QChar(116); + case 430: return QChar(116); + case 648: return QChar(116); + case 566: return QChar(116); + case 218: return QChar(117); + case 250: return QChar(117); + case 217: return QChar(117); + case 249: return QChar(117); + case 364: return QChar(117); + case 365: return QChar(117); + case 219: return QChar(117); + case 251: return QChar(117); + case 467: return QChar(117); + case 468: return QChar(117); + case 366: return QChar(117); + case 367: return QChar(117); + case 220: return QChar(117); + case 252: return QChar(117); + case 471: return QChar(117); + case 472: return QChar(117); + case 475: return QChar(117); + case 476: return QChar(117); + case 473: return QChar(117); + case 474: return QChar(117); + case 469: return QChar(117); + case 470: return QChar(117); + case 368: return QChar(117); + case 369: return QChar(117); + case 360: return QChar(117); + case 361: return QChar(117); + case 7800: return QChar(117); + case 7801: return QChar(117); + case 370: return QChar(117); + case 371: return QChar(117); + case 362: return QChar(117); + case 363: return QChar(117); + case 7802: return QChar(117); + case 7803: return QChar(117); + case 7910: return QChar(117); + case 7911: return QChar(117); + case 532: return QChar(117); + case 533: return QChar(117); + case 534: return QChar(117); + case 535: return QChar(117); + case 431: return QChar(117); + case 432: return QChar(117); + case 7912: return QChar(117); + case 7913: return QChar(117); + case 7914: return QChar(117); + case 7915: return QChar(117); + case 7918: return QChar(117); + case 7919: return QChar(117); + case 7916: return QChar(117); + case 7917: return QChar(117); + case 7920: return QChar(117); + case 7921: return QChar(117); + case 7908: return QChar(117); + case 7909: return QChar(117); + case 7794: return QChar(117); + case 7795: return QChar(117); + case 7798: return QChar(117); + case 7799: return QChar(117); + case 7796: return QChar(117); + case 7797: return QChar(117); + case 580: return QChar(117); + case 649: return QChar(117); + case 7804: return QChar(118); + case 7805: return QChar(118); + case 7806: return QChar(118); + case 7807: return QChar(118); + case 434: return QChar(118); + case 651: return QChar(118); + case 7810: return QChar(119); + case 7811: return QChar(119); + case 7808: return QChar(119); + case 7809: return QChar(119); + case 372: return QChar(119); + case 373: return QChar(119); + case 778: return QChar(121); + case 7832: return QChar(119); + case 7812: return QChar(119); + case 7813: return QChar(119); + case 7814: return QChar(119); + case 7815: return QChar(119); + case 7816: return QChar(119); + case 7817: return QChar(119); + case 7820: return QChar(120); + case 7821: return QChar(120); + case 7818: return QChar(120); + case 7819: return QChar(120); + case 221: return QChar(121); + case 253: return QChar(121); + case 7922: return QChar(121); + case 7923: return QChar(121); + case 374: return QChar(121); + case 375: return QChar(121); + case 7833: return QChar(121); + case 376: return QChar(121); + case 255: return QChar(121); + case 7928: return QChar(121); + case 7929: return QChar(121); + case 7822: return QChar(121); + case 7823: return QChar(121); + case 562: return QChar(121); + case 563: return QChar(121); + case 7926: return QChar(121); + case 7927: return QChar(121); + case 7924: return QChar(121); + case 7925: return QChar(121); + case 655: return QChar(121); + case 590: return QChar(121); + case 591: return QChar(121); + case 435: return QChar(121); + case 436: return QChar(121); + case 377: return QChar(122); + case 378: return QChar(122); + case 7824: return QChar(122); + case 7825: return QChar(122); + case 381: return QChar(122); + case 382: return QChar(122); + case 379: return QChar(122); + case 380: return QChar(122); + case 7826: return QChar(122); + case 7827: return QChar(122); + case 7828: return QChar(122); + case 7829: return QChar(122); + case 437: return QChar(122); + case 438: return QChar(122); + case 548: return QChar(122); + case 549: return QChar(122); + case 656: return QChar(122); + case 657: return QChar(122); + case 11371: return QChar(122); + case 11372: return QChar(122); + case 494: return QChar(122); + case 495: return QChar(122); + case 442: return QChar(122); + case 65298: return QChar(50); + case 65302: return QChar(54); + case 65314: return QChar(66); + case 65318: return QChar(70); + case 65322: return QChar(74); + case 65326: return QChar(78); + case 65330: return QChar(82); + case 65334: return QChar(86); + case 65338: return QChar(90); + case 65346: return QChar(98); + case 65350: return QChar(102); + case 65354: return QChar(106); + case 65358: return QChar(110); + case 65362: return QChar(114); + case 65366: return QChar(118); + case 65370: return QChar(122); + case 65297: return QChar(49); + case 65301: return QChar(53); + case 65305: return QChar(57); + case 65313: return QChar(65); + case 65317: return QChar(69); + case 65321: return QChar(73); + case 65325: return QChar(77); + case 65329: return QChar(81); + case 65333: return QChar(85); + case 65337: return QChar(89); + case 65345: return QChar(97); + case 65349: return QChar(101); + case 65353: return QChar(105); + case 65357: return QChar(109); + case 65361: return QChar(113); + case 65365: return QChar(117); + case 65369: return QChar(121); + case 65296: return QChar(48); + case 65300: return QChar(52); + case 65304: return QChar(56); + case 65316: return QChar(68); + case 65320: return QChar(72); + case 65324: return QChar(76); + case 65328: return QChar(80); + case 65332: return QChar(84); + case 65336: return QChar(88); + case 65348: return QChar(100); + case 65352: return QChar(104); + case 65356: return QChar(108); + case 65360: return QChar(112); + case 65364: return QChar(116); + case 65368: return QChar(120); + case 65299: return QChar(51); + case 65303: return QChar(55); + case 65315: return QChar(67); + case 65319: return QChar(71); + case 65323: return QChar(75); + case 65327: return QChar(79); + case 65331: return QChar(83); + case 65335: return QChar(87); + case 65347: return QChar(99); + case 65351: return QChar(103); + case 65355: return QChar(107); + case 65359: return QChar(111); + case 65363: return QChar(115); + case 65367: return QChar(119); + default: + break; + } + return QChar(0); + } +} + +QString textAccentFold(const QString &text) { + QString result(text); + bool copying = false; + int32 i = 0; + for (const QChar *s = text.unicode(), *ch = s, *e = text.unicode() + text.size(); ch != e; ++ch, ++i) { + if (ch->unicode() < 128) { + if (copying) result[i] = *ch; + continue; + } + if (chIsDiac(*ch)) { + copying = true; + --i; + continue; + } + if (ch->isHighSurrogate() && ch + 1 < e && (ch + 1)->isLowSurrogate()) { + QChar noAccent = QChar::surrogateToUcs4(*ch, *(ch + 1)); + if (noAccent.unicode() > 0) { + copying = true; + result[i] = noAccent; + } else { + if (copying) result[i] = *ch; + ++ch, ++i; + if (copying) result[i] = *ch; + } + } else { + QChar noAccent = chNoAccent(ch->unicode()); + if (noAccent.unicode() > 0 && noAccent != *ch) { + result[i] = noAccent; + } else if (copying) { + result[i] = *ch; + } + } + } + return (i < result.size()) ? result.mid(0, i) : result; +} diff --git a/Telegram/SourceFiles/gui/text.h b/Telegram/SourceFiles/gui/text.h new file mode 100644 index 000000000..5e3bcb1a6 --- /dev/null +++ b/Telegram/SourceFiles/gui/text.h @@ -0,0 +1,435 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "gui/emoji_config.h" +#include "gui/style_core.h" + +#include "../../../QtStatic/qtbase/src/gui/text/qfontengine_p.h" + +enum TextBlockType { + TextBlockNewline = 0x01, + TextBlockText = 0x02, + TextBlockEmoji = 0x03, + TextBlockSkip = 0x04, +}; + +enum TextBlockFlags { + TextBlockBold = 0x01, + TextBlockItalic = 0x02, + TextBlockUnderline = 0x04, +}; + +class ITextBlock { +public: + + ITextBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex) : _from(from), _flags((flags & 0xFF) | ((lnkIndex & 0xFFFF) << 12))/*, _color(color)*/, _lpadding(0) { + if (length) { + if (str.at(_from + length - 1).unicode() == QChar::Space) { + _rpadding = font->spacew; + } + if (length > 1 && str.at(0).unicode() == QChar::Space) { + _lpadding = font->spacew; + } + } + } + + uint16 from() const { + return _from; + } + int32 width() const { + return _width.toInt(); + } + int32 lpadding() const { + return _lpadding.toInt(); + } + int32 rpadding() const { + return _rpadding.toInt(); + } + QFixed f_width() const { + return _width; + } + QFixed f_lpadding() const { + return _lpadding; + } + QFixed f_rpadding() const { + return _rpadding; + } + + uint16 lnkIndex() const { + return (_flags >> 12) & 0xFFFF; + } + void setLnkIndex(uint16 lnkIndex) { + _flags = (_flags & ~(0xFFFF << 12)) | (lnkIndex << 12); + } + + TextBlockType type() const { + return TextBlockType((_flags >> 8) & 0x0F); + } + int32 flags() const { + return (_flags & 0xFF); + } + const style::color &color() const { + static style::color tmp; + return tmp;//_color; + } + + virtual ~ITextBlock() { + } + +protected: + + uint16 _from; + + uint32 _flags; // 4 bits empty, 16 bits lnkIndex, 4 bits type, 8 bits flags + + QFixed _width, _lpadding, _rpadding; + +}; + +class NewlineBlock : public ITextBlock { +public: + + Qt::LayoutDirection nextDirection() const { + return _nextDir; + } + +private: + + NewlineBlock(const style::font &font, const QString &str, uint16 from, uint16 length) : ITextBlock(font, str, from, length, 0, st::transparent, 0), _nextDir(Qt::LayoutDirectionAuto) { + _flags |= ((TextBlockNewline & 0x0F) << 8); + } + + Qt::LayoutDirection _nextDir; + + friend class Text; + friend class TextParser; + + friend class TextPainter; +}; + +struct TextWord { + TextWord() { + } + TextWord(uint16 from, QFixed width, QFixed rbearing, QFixed rpadding = 0) : from(from), width(width), rpadding(rpadding), + _rbearing(rbearing.value() > 0xFFFF ? 0xFFFF : (rbearing.value() < -0xFFFF ? -0xFFFF : rbearing.value())) { + } + QFixed f_rbearing() const { + return QFixed::fromFixed(_rbearing); + } + uint16 from; + int16 _rbearing; + QFixed width, rpadding; +}; + +class TextBlock : public ITextBlock { +public: + + QFixed f_rbearing() const { + return _words.isEmpty() ? 0 : _words.back().f_rbearing(); + } + +private: + + TextBlock(const style::font &font, const QString &str, QFixed minResizeWidth, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex); + + typedef QVector TextWords; + TextWords _words; + + friend class Text; + friend class TextParser; + + friend class BlockParser; + friend class TextPainter; +}; + +class EmojiBlock : public ITextBlock { +public: + +private: + + EmojiBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex, const EmojiData *emoji); + + const EmojiData *emoji; + + friend class Text; + friend class TextParser; + + friend class TextPainter; +}; + +class SkipBlock : public ITextBlock { +public: + + int32 height() const { + return _height; + } + +private: + + SkipBlock(const style::font &font, const QString &str, uint16 from, int32 w, int32 h, uint16 lnkIndex); + + int32 _height; + + friend class Text; + friend class TextParser; + + friend class TextPainter; +}; + +class ITextLink { +public: + + virtual void onClick(Qt::MouseButton) const = 0; + virtual const QString &text() const { + static const QString _tmp; + return _tmp; + } + virtual const QString &readable() const { + static const QString _tmp; + return _tmp; + } + virtual bool fullDisplayed() const { + return true; + } + virtual QString encoded() const { + return QString(); + } + virtual ~ITextLink() { + } + +}; +typedef QSharedPointer TextLinkPtr; + +class TextLink : public ITextLink { +public: + + TextLink(const QString &url, bool fullDisplayed = true) : _url(url), _fullDisplayed(fullDisplayed) { + QUrl u(_url), good(u.isValid() ? u.toEncoded() : QString()); + _readable = good.isValid() ? good.toDisplayString() : _url; + } + + const QString &text() const { + return _url; + } + + void onClick(Qt::MouseButton button) const { + if (button == Qt::LeftButton || button == Qt::MiddleButton) { + QDesktopServices::openUrl(TextLink::encoded()); + } + } + + const QString &readable() const { + return _readable; + } + + bool fullDisplayed() const { + return _fullDisplayed; + } + + QString encoded() const { + QUrl u(_url), good(u.isValid() ? u.toEncoded() : QString()); + QString result(good.isValid() ? good.toEncoded() : _url); + + if (!QRegularExpression(qsl("^[a-zA-Z]+://")).match(result).hasMatch()) { // no protocol + return qsl("http://") + result; + } + return result; + } + +private: + + QString _url, _readable; + bool _fullDisplayed; + +}; + +class EmailLink : public ITextLink { +public: + + EmailLink(const QString &email) : _email(email) { + } + + const QString &text() const { + return _email; + } + + void onClick(Qt::MouseButton button) const { + if (button == Qt::LeftButton || button == Qt::MiddleButton) { + QDesktopServices::openUrl(qsl("mailto:") + _email); + } + } + + const QString &readable() const { + return _email; + } + + QString encoded() const { + return _email; + } + +private: + + QString _email; + +}; + +static const QChar TextCommand(0x0010); +enum TextCommands { + TextCommandBold = 0x01, + TextCommandNoBold = 0x02, + TextCommandItalic = 0x03, + TextCommandNoItalic = 0x04, + TextCommandUnderline = 0x05, + TextCommandNoUnderline = 0x06, + TextCommandLinkIndex = 0x07, // 0 - NoLink + TextCommandLinkText = 0x08, + TextCommandColor = 0x09, + TextCommandNoColor = 0x0A, + TextCommandSkipBlock = 0x0B, +}; + +enum { + TextParseMultiline = 0x01, + TextParseLinks = 0x02, + TextParseRichText = 0x04, +}; + +struct TextParseOptions { + int32 flags; + int32 maxw; + int32 maxh; + Qt::LayoutDirection dir; +}; +extern const TextParseOptions _defaultOptions; +extern const TextParseOptions _textPlainOptions; + +enum TextSelectType { + TextSelectLetters = 0x01, + TextSelectWords = 0x02, + TextSelectParagraphs = 0x03, +}; + +typedef QPair TextCustomTag; // open str and close str +typedef QMap TextCustomTagsMap; + +class Text { +public: + + Text(int32 minResizeWidth = QFIXED_MAX); + Text(style::font font, const QString &text, const TextParseOptions &options = _defaultOptions, int32 minResizeWidth = QFIXED_MAX, bool richText = false); + + int32 countHeight(int32 width) const; + void setText(style::font font, const QString &text, const TextParseOptions &options = _defaultOptions); + void setRichText(style::font font, const QString &text, TextParseOptions options = _defaultOptions, const TextCustomTagsMap &custom = TextCustomTagsMap()); + + void setLink(uint16 lnkIndex, const TextLinkPtr &lnk); + bool hasLinks() const; + + int32 maxWidth() const { + return _maxWidth.toInt(); + } + int32 minHeight() const { + return _minHeight; + } + + void draw(QPainter &p, int32 left, int32 top, int32 width, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, uint16 selectedFrom = 0, uint16 selectedTo = 0) const; + void drawElided(QPainter &p, int32 left, int32 top, int32 width, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1) const; + + const TextLinkPtr &link(int32 x, int32 y, int32 width, style::align align = style::al_left) const; + void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 width, style::align align = style::al_left) const; + void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 width, style::align align = style::al_left) const; + uint32 adjustSelection(uint16 from, uint16 to, TextSelectType selectType) const; + + QString original(uint16 selectedFrom = 0, uint16 selectedTo = 0xFFFF, bool expandLinks = true) const; + + bool lastDots(uint32 dots, uint32 maxdots = 3) { // hack for typing animation + if (_text.size() < maxdots) return false; + + int32 nowDots = 0, from = _text.size() - maxdots, to = _text.size(); + for (int32 i = from; i < to; ++i) { + if (_text.at(i) == QChar('.')) { + ++nowDots; + } + } + if (nowDots == dots) return false; + for (int32 j = from; j < from + dots; ++j) { + _text[j] = QChar('.'); + } + for (int32 j = from + dots; j < to; ++j) { + _text[j] = QChar(' '); + } + return true; + } + + void clean(); + ~Text() { + clean(); + } + +private: + + QFixed _minResizeWidth, _maxWidth; + int32 _minHeight; + + QString _text; + style::font _font; + + typedef QVector TextBlocks; + TextBlocks _blocks; + + typedef QVector TextLinks; + TextLinks _links; + + Qt::LayoutDirection _startDir; + + friend class TextParser; + friend class TextPainter; + +}; + +// text style +const style::textStyle *textstyleCurrent(); +void textstyleSet(const style::textStyle *style); + +inline void textstyleRestore() { + textstyleSet(0); +} + +// text preprocess +QString textClean(const QString &text); +QString textRichPrepare(const QString &text); +QString textOneLine(const QString &text, bool trim = true, bool rich = false); +QString textAccentFold(const QString &text); + +// textlnk +void textlnkOver(const TextLinkPtr &lnk); +const TextLinkPtr &textlnkOver(); + +void textlnkDown(const TextLinkPtr &lnk); +const TextLinkPtr &textlnkDown(); + +// textcmd +QString textcmdSkipBlock(ushort w, ushort h); +QString textcmdStartLink(ushort lnkIndex); +QString textcmdStartLink(const QString &url); +QString textcmdStopLink(); +QString textcmdLink(ushort lnkIndex, const QString &text); +QString textcmdLink(const QString &url, const QString &text); +QString textcmdStartColor(const style::color &color); +QString textcmdStopColor(); diff --git a/Telegram/SourceFiles/gui/twidget.cpp b/Telegram/SourceFiles/gui/twidget.cpp new file mode 100644 index 000000000..4dfff59f2 --- /dev/null +++ b/Telegram/SourceFiles/gui/twidget.cpp @@ -0,0 +1,18 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" diff --git a/Telegram/SourceFiles/gui/twidget.h b/Telegram/SourceFiles/gui/twidget.h new file mode 100644 index 000000000..f98dd8c46 --- /dev/null +++ b/Telegram/SourceFiles/gui/twidget.h @@ -0,0 +1,46 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +class TWidget : public QWidget { + Q_OBJECT + +public: + + TWidget(QWidget *parent = 0) : QWidget(parent) { + } + TWidget *tparent() { + return dynamic_cast(parentWidget()); + } + const TWidget *tparent() const { + return dynamic_cast(parentWidget()); + } + + virtual void leaveToChildEvent(QEvent *e) { // e -- from enterEvent() of child TWidget + } + +protected: + + void enterEvent(QEvent *e) { + TWidget *p(tparent()); + if (p) p->leaveToChildEvent(e); + } + +private: + +}; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp new file mode 100644 index 000000000..c89588aa8 --- /dev/null +++ b/Telegram/SourceFiles/history.cpp @@ -0,0 +1,3144 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" +#include "lang.h" + +#include "history.h" +#include "mainwidget.h" +#include "application.h" +#include "fileuploader.h" +#include "window.h" +#include "gui/filedialog.h" + +TextParseOptions _textNameOptions = { + 0, // flags + 4096, // maxw + 1, // maxh + Qt::LayoutDirectionAuto, // lang-dependent +}; +TextParseOptions _textDlgOptions = { + 0, // flags + 0, // maxw is style-dependent + 1, // maxh + Qt::LayoutDirectionAuto, // lang-dependent +}; + + +namespace { + style::color peerColor(int32 index) { + static const style::color peerColors[8] = { + style::color(st::color1), + style::color(st::color2), + style::color(st::color3), + style::color(st::color4), + style::color(st::color5), + style::color(st::color6), + style::color(st::color7), + style::color(st::color8) + }; + return peerColors[index]; + } + + ImagePtr userDefPhoto(int32 index) { + static const ImagePtr userDefPhotos[8] = { + ImagePtr(":/ava/art/usercolor1.png"), + ImagePtr(":/ava/art/usercolor2.png"), + ImagePtr(":/ava/art/usercolor3.png"), + ImagePtr(":/ava/art/usercolor4.png"), + ImagePtr(":/ava/art/usercolor5.png"), + ImagePtr(":/ava/art/usercolor6.png"), + ImagePtr(":/ava/art/usercolor7.png"), + ImagePtr(":/ava/art/usercolor8.png") + }; + return userDefPhotos[index]; + } + + ImagePtr chatDefPhoto(int32 index) { + static const ImagePtr chatDefPhotos[4] = { + ImagePtr(":/ava/art/chatcolor1.png"), + ImagePtr(":/ava/art/chatcolor2.png"), + ImagePtr(":/ava/art/chatcolor3.png"), + ImagePtr(":/ava/art/chatcolor4.png") + }; + return chatDefPhotos[index]; + } + + int32 peerColorIndex(const PeerId &peer) { + int32 myId(MTP::authedId()), peerId(peer & 0xFFFFFFFFL); + bool chat = (peer & 0x100000000L); + if (chat) { + int ch = 0; + } + QByteArray both(qsl("%1%2").arg(peerId).arg(myId).toUtf8()); + if (both.size() > 15) { + both = both.mid(0, 15); + } + uchar md5[16]; + hashMd5(both.constData(), both.size(), md5); + return (md5[peerId & 0x0F] & (chat ? 0x03 : 0x07)); + } + + TextParseOptions _historyTextOptions = { + TextParseLinks | TextParseMultiline | TextParseRichText, // flags + 0, // maxw + 0, // maxh + Qt::LayoutDirectionAuto, // dir + }; + TextParseOptions _historySrvOptions = { + TextParseLinks | TextParseMultiline | TextParseRichText, // flags + 0, // maxw + 0, // maxh + Qt::LayoutDirectionAuto, // lang-dependent + }; + + inline void _initTextOptions() { + _historySrvOptions.dir = _textNameOptions.dir = _textDlgOptions.dir = langDir(); + _textDlgOptions.maxw = st::dlgMaxWidth * 2; + } +} + +void historyInit() { + _initTextOptions(); +} + +NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats; +NotifySettingsPtr globalNotifyAllPtr = UnknownNotifySettings, globalNotifyUsersPtr = UnknownNotifySettings, globalNotifyChatsPtr = UnknownNotifySettings; + +PeerData::PeerData(const PeerId &id) : id(id), access(0), chat(App::isChat(id)), loaded(false), notify(UnknownNotifySettings), + colorIndex(peerColorIndex(id)), color(peerColor(colorIndex)), photo(chat ? chatDefPhoto(colorIndex) : userDefPhoto(colorIndex)), nameVersion(0) { +} + +UserData *PeerData::asUser() { + return chat ? App::user(id & 0xFFFFFFFFL) : static_cast(this); +} + +const UserData *PeerData::asUser() const { + return chat ? App::user(id & 0xFFFFFFFFL) : static_cast(this); +} + +ChatData *PeerData::asChat() { + return chat ? static_cast(this) : App::chat(id | 0x100000000L); +} + +const ChatData *PeerData::asChat() const { + return chat ? static_cast(this) : App::chat(id | 0x100000000L); +} + +void PeerData::updateName(const QString &newName, const QString &newNameOrPhone) { + if (name == newName && nameOrPhone == newNameOrPhone) return; + + ++nameVersion; + name = newName; + nameOrPhone = newNameOrPhone; + Names oldNames = names; + NameFirstChars oldChars = chars; + fillNames(); + App::history(id)->updateNameText(); + emit App::main()->peerNameChanged(this, oldNames, oldChars); + nameUpdated(); +} + +void UserData::setPhoto(const MTPUserProfilePhoto &p) { + switch (p.type()) { + case mtpc_userProfilePhoto: { + const MTPDuserProfilePhoto d(p.c_userProfilePhoto()); + photoId = d.vphoto_id.v; + photo = ImagePtr(160, 160, d.vphoto_small, userDefPhoto(colorIndex)); +// App::feedPhoto(App::photoFromUserPhoto(MTP_int(id & 0xFFFFFFFF), MTP_int(unixtime()), p)); + } break; + default: { + photoId = 0; + photo = userDefPhoto(colorIndex); + } break; + } + emit App::main()->peerPhotoChanged(this); +} + +void UserData::setName(const QString &first, const QString &last, const QString &phoneName) { + bool updName = !first.isEmpty() || !last.isEmpty(); + + if (updName && first.trimmed().isEmpty()) { + firstName = last; + lastName = QString(); + updateName(firstName, phoneName); + } else { + if (updName) { + firstName = first; + lastName = last; + } + updateName(firstName + qsl(" ") + lastName, phoneName); + } +} + +void UserData::setPhone(const QString &newPhone) { + phone = newPhone; + ++nameVersion; +} + +void UserData::nameUpdated() { + nameText.setText(st::msgNameFont, name, _textNameOptions); +} + +void ChatData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { + switch (p.type()) { + case mtpc_chatPhoto: { + const MTPDchatPhoto d(p.c_chatPhoto()); + photo = ImagePtr(160, 160, d.vphoto_small, chatDefPhoto(colorIndex)); + photoFull = ImagePtr(640, 640, d.vphoto_big, chatDefPhoto(colorIndex)); + if (phId) { + photoId = phId; + } + } break; + default: { + photo = chatDefPhoto(colorIndex); + photoFull = ImagePtr(); + photoId = 0; + } break; + } + emit App::main()->peerPhotoChanged(this); +} + +void PhotoLink::onClick(Qt::MouseButton button) const { + if (button == Qt::LeftButton) App::wnd()->showPhoto(this, App::hoveredLinkItem()); +} + +QString saveFileName(const QString &title, const QString &filter, const QString &prefix, QString name, bool savingAs, const QDir &dir = QDir()) { + if (cAskDownloadPath() || savingAs) { + if (!name.isEmpty() && name.at(0) == QChar::fromLatin1('.')) { + name = filedialogDefaultName(prefix, name); + } else if (dir.path() != qsl(".")) { + cSetDialogLastPath(dir.absolutePath()); + } + + return filedialogGetSaveFile(name, title, filter, name) ? name : QString(); + } + + QString path = cDownloadPath().isEmpty() ? cTempDir() : cDownloadPath(); + if (name.isEmpty()) name = qsl(".unknown"); + if (name.at(0) == QChar::fromLatin1('.')) { + if (!QDir().exists(path)) QDir().mkpath(path); + return filedialogDefaultName(prefix, name, path); + } + if (dir.path() != qsl(".")) { + path = dir.absolutePath() + '/'; + } + + QString nameStart, extension; + int32 extPos = name.lastIndexOf('.'); + if (extPos >= 0) { + nameStart = name.mid(0, extPos); + extension = name.mid(extPos); + } else { + nameStart = name; + } + QString nameBase = path + nameStart; + name = nameBase + extension; + for (int i = 0; QFileInfo(name).exists(); ++i) { + name = nameBase + QString(" (%1)").arg(i + 2) + extension; + } + + if (!QDir().exists(path)) QDir().mkpath(path); + return name; +} + +void VideoOpenLink::onClick(Qt::MouseButton button) const { + VideoData *data = video(); + if (!data->user && !data->date || button != Qt::LeftButton) return; + + QString already = data->already(true); + if (!already.isEmpty()) { + QDesktopServices::openUrl(QUrl::fromLocalFile(already)); + return; + } + + if (data->status != FileReady) return; + + QString filename = saveFileName(lang(lng_save_video), qsl("MOV Video (*.mov);;All files (*.*)"), qsl("video"), qsl(".mov"), false); + if (!filename.isEmpty()) { + data->openOnSave = 1; + data->save(filename); + } +} + +void VideoSaveLink::doSave(bool forceSavingAs) const { + VideoData *data = video(); + if (!data->user && !data->date) return; + + bool openingWith = !data->already().isEmpty(); + + QString already = data->already(true); + if (!already.isEmpty() && !forceSavingAs) { + psOpenFile(already, true); + } else { + QDir alreadyDir(already.isEmpty() ? QDir() : QFileInfo(already).dir()); + QString name = already.isEmpty() ? QString(".mov") : already; + QString filename = saveFileName(lang(lng_save_video), qsl("MOV Video (*.mov);;All files (*.*)"), qsl("video"), name, forceSavingAs, alreadyDir); + if (!filename.isEmpty()) { + if (forceSavingAs) data->cancel(); + if (!already.isEmpty()) data->openOnSave = -1; + data->save(filename); + } + } +} + +void VideoSaveLink::onClick(Qt::MouseButton button) const { + if (button != Qt::LeftButton) return; + doSave(); +} + +void VideoCancelLink::onClick(Qt::MouseButton button) const { + VideoData *data = video(); + if (!data->user && !data->date || button != Qt::LeftButton) return; + + data->cancel(); +} + +void VideoData::save(const QString &toFile) { + cancel(true); + loader = new mtpFileLoader(dc, id, access, mtpc_inputVideoFileLocation, toFile, size); + loader->connect(loader, SIGNAL(progress(mtpFileLoader*)), App::main(), SLOT(videoLoadProgress(mtpFileLoader*))); + loader->connect(loader, SIGNAL(failed(mtpFileLoader*,bool)), App::main(), SLOT(videoLoadFailed(mtpFileLoader*,bool))); + loader->start(); +} + +void AudioOpenLink::onClick(Qt::MouseButton button) const { + AudioData *data = audio(); + if (!data->user && !data->date || button != Qt::LeftButton) return; + + QString already = data->already(true); + if (!already.isEmpty()) { + QDesktopServices::openUrl(QUrl::fromLocalFile(already)); + return; + } + + if (data->status != FileReady) return; + + QString filename = saveFileName(lang(lng_save_audio), qsl("OGG Opus Audio (*.ogg);;All files (*.*)"), qsl("audio"), qsl(".ogg"), false); + if (!filename.isEmpty()) { + data->openOnSave = 1; + data->save(filename); + } +} + +void AudioSaveLink::doSave(bool forceSavingAs) const { + AudioData *data = audio(); + if (!data->user && !data->date) return; + + bool openingWith = !data->already().isEmpty(); + + QString already = data->already(true); + if (!already.isEmpty() && !forceSavingAs) { + psOpenFile(already, true); + } else { + QDir alreadyDir(already.isEmpty() ? QDir() : QFileInfo(already).dir()); + QString name = already.isEmpty() ? QString(".ogg") : already; + QString filename = saveFileName(lang(lng_save_audio), qsl("OGG Opus Audio (*.ogg);;All files (*.*)"), qsl("audio"), name, forceSavingAs, alreadyDir); + if (!filename.isEmpty()) { + if (forceSavingAs) data->cancel(); + if (!already.isEmpty()) data->openOnSave = -1; + data->save(filename); + } + } +} + +void AudioSaveLink::onClick(Qt::MouseButton button) const { + if (button != Qt::LeftButton) return; + doSave(); +} + +void AudioCancelLink::onClick(Qt::MouseButton button) const { + AudioData *data = audio(); + if (!data->user && !data->date || button != Qt::LeftButton) return; + + data->cancel(); +} + +void AudioData::save(const QString &toFile) { + cancel(true); + loader = new mtpFileLoader(dc, id, access, mtpc_inputAudioFileLocation, toFile, size); + loader->connect(loader, SIGNAL(progress(mtpFileLoader*)), App::main(), SLOT(audioLoadProgress(mtpFileLoader*))); + loader->connect(loader, SIGNAL(failed(mtpFileLoader*,bool)), App::main(), SLOT(audioLoadFailed(mtpFileLoader*,bool))); + loader->start(); +} + +void DocumentOpenLink::onClick(Qt::MouseButton button) const { + DocumentData *data = document(); + if (!data->user && !data->date || button != Qt::LeftButton) return; + + QString already = data->already(true); + if (!already.isEmpty()) { + QDesktopServices::openUrl(QUrl::fromLocalFile(already)); + return; + } + + if (data->status != FileReady) return; + + QString name = data->name, filter; + QMimeType mimeType = QMimeDatabase().mimeTypeForName(data->mime); + QStringList p = mimeType.globPatterns(); + QString pattern = p.isEmpty() ? QString() : p.front(); + if (name.isEmpty()) { + name = pattern.isEmpty() ? qsl(".unknown") : pattern.replace('*', QString()); + } + + if (pattern.isEmpty()) { + filter = qsl("All files (*.*)"); + } else { + filter = mimeType.filterString() + qsl(";;All files (*.*)"); + } + + QString filename = saveFileName(lang(lng_save_document), filter, qsl("doc"), name, false); + if (!filename.isEmpty()) { + data->openOnSave = 1; + data->save(filename); + } +} + +void DocumentSaveLink::doSave(bool forceSavingAs) const { + DocumentData *data = document(); + if (!data->user && !data->date) return; + + bool openingWith = !data->already().isEmpty(); + + QString already = data->already(true); + if (!already.isEmpty() && !forceSavingAs) { + psOpenFile(already, true); + } else { + QDir alreadyDir(already.isEmpty() ? QDir() : QFileInfo(already).dir()); + QString name = already.isEmpty() ? data->name : already, filter; + QMimeType mimeType = QMimeDatabase().mimeTypeForName(data->mime); + QStringList p = mimeType.globPatterns(); + QString pattern = p.isEmpty() ? QString() : p.front(); + if (name.isEmpty()) { + name = pattern.isEmpty() ? qsl(".unknown") : pattern.replace('*', QString()); + } + + if (pattern.isEmpty()) { + filter = qsl("All files (*.*)"); + } else { + filter = mimeType.filterString() + qsl(";;All files (*.*)"); + } + + QString filename = saveFileName(lang(lng_save_document), filter, qsl("doc"), name, forceSavingAs, alreadyDir); + if (!filename.isEmpty()) { + if (forceSavingAs) data->cancel(); + if (!already.isEmpty()) data->openOnSave = -1; + data->save(filename); + } + } +} + +void DocumentSaveLink::onClick(Qt::MouseButton button) const { + if (button != Qt::LeftButton) return; + doSave(); +} + +void DocumentCancelLink::onClick(Qt::MouseButton button) const { + DocumentData *data = document(); + if (!data->user && !data->date || button != Qt::LeftButton) return; + + data->cancel(); +} + +void DocumentData::save(const QString &toFile) { + cancel(true); + loader = new mtpFileLoader(dc, id, access, mtpc_inputDocumentFileLocation, toFile, size); + loader->connect(loader, SIGNAL(progress(mtpFileLoader*)), App::main(), SLOT(documentLoadProgress(mtpFileLoader*))); + loader->connect(loader, SIGNAL(failed(mtpFileLoader*, bool)), App::main(), SLOT(documentLoadFailed(mtpFileLoader*, bool))); + loader->start(); +} + +void PeerLink::onClick(Qt::MouseButton button) const { + if (button == Qt::LeftButton && App::main()) { + App::main()->showPeerProfile(peer()); + } +} + +MsgId clientMsgId() { + static MsgId current = -2000000000; + return ++current; +} + +void DialogRow::paint(QPainter &p, int32 w, bool act, bool sel) const { + QRect fullRect(0, 0, w, st::dlgHeight); + p.fillRect(fullRect, (act ? st::dlgActiveBG : (sel ? st::dlgHoverBG : st::dlgBG))->b); + + p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, history->peer->photo->pix(st::dlgPhotoSize)); + + int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding; + int32 namewidth = w - nameleft - st::dlgPaddingHor; + QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height); + + // draw chat icon + if (history->peer->chat) { + p.drawPixmap(QPoint(rectForName.left() + st::dlgChatImgLeft, rectForName.top() + st::dlgChatImgTop), App::sprite(), (act ? st::dlgActiveChatImg : st::dlgChatImg)); + rectForName.setLeft(rectForName.left() + st::dlgChatImgSkip); + } + + if (history->isEmpty()) { + p.setFont(st::dlgHistFont->f); + p.setPen((act ? st::dlgActiveColor : st::dlgSystemColor)->p); + if (history->typing.isEmpty()) { + p.drawText(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgFont->ascent + st::dlgSep, lang(lng_empty_history)); + } else { + history->typingText.drawElided(p, nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, namewidth); + } + } else { + // draw date + HistoryItem *last = history->back()->back(); + QDateTime now(QDateTime::currentDateTime()), lastTime(last->date); + QDate nowDate(now.date()), lastDate(lastTime.date()); + QString dt; + if (lastDate == nowDate) { + dt = lastTime.toString(qsl("hh:mm")); + } else if (lastDate.year() == nowDate.year() && lastDate.weekNumber() == nowDate.weekNumber()) { + dt = langDayOfWeek(lastDate); + } else { + dt = lastDate.toString(qsl("d.MM.yy")); + } + int32 dtWidth = st::dlgDateFont->m.width(dt); + rectForName.setWidth(rectForName.width() - dtWidth - st::dlgDateSkip); + p.setFont(st::dlgDateFont->f); + p.setPen((act ? st::dlgActiveDateColor : st::dlgDateColor)->p); + p.drawText(rectForName.left() + rectForName.width() + st::dlgDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, dt); + + // draw check + if (last->out() && last->needCheck()) { + const QRect *check; + if (last->id > 0) { + if (last->unread()) { + check = act ? &st::dlgActiveCheckImg : &st::dlgCheckImg; + } else { + check = act ? &st::dlgActiveDblCheckImg: &st::dlgDblCheckImg; + } + } else { + check = act ? &st::dlgActiveSendImg : &st::dlgSendImg; + } + rectForName.setWidth(rectForName.width() - check->width() - st::dlgCheckSkip); + p.drawPixmap(QPoint(rectForName.left() + rectForName.width() + st::dlgCheckLeft, rectForName.top() + st::dlgCheckTop), App::sprite(), *check); + } + + // draw unread + int32 lastWidth = namewidth, unread = history->unreadCount; + if (unread) { + QString unreadStr = QString::number(unread); + int32 unreadWidth = st::dlgUnreadFont->m.width(unreadStr); + int32 unreadRectWidth = unreadWidth + 2 * st::dlgUnreadPaddingHor; + int32 unreadRectHeight = st::dlgUnreadFont->height + 2 * st::dlgUnreadPaddingVer; + int32 unreadRectLeft = w - st::dlgPaddingHor - unreadRectWidth; + int32 unreadRectTop = st::dlgHeight - st::dlgPaddingVer - unreadRectHeight; + lastWidth -= unreadRectWidth + st::dlgUnreadPaddingHor; + p.setBrush((act ? st::dlgActiveUnreadBG : st::dlgUnreadBG)->b); + p.setPen(Qt::NoPen); + p.drawRoundedRect(unreadRectLeft, unreadRectTop, unreadRectWidth, unreadRectHeight, st::dlgUnreadRadius, st::dlgUnreadRadius); + p.setFont(st::dlgUnreadFont->f); + p.setPen((act ? st::dlgActiveUnreadColor : st::dlgUnreadColor)->p); + p.drawText(unreadRectLeft + st::dlgUnreadPaddingHor, unreadRectTop + st::dlgUnreadPaddingVer + st::dlgUnreadFont->ascent, unreadStr); + } + if (history->typing.isEmpty()) { + last->drawInDialog(p, QRect(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, lastWidth, st::dlgFont->height), act, history->textCachedFor, history->lastItemTextCache); + } else { + p.setPen((act ? st::dlgActiveColor : st::dlgSystemColor)->p); + history->typingText.drawElided(p, nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, lastWidth); + } + } + + p.setPen((act ? st::dlgActiveColor : st::dlgNameColor)->p); + history->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); +} + +History::History(const PeerId &peerId) : width(0), height(0), myTyping(0), showFrom(0), unreadLoaded(true), unreadBar(0), notifyFrom(0), + msgCount(0), offset(0), peer(App::peer(peerId)), posInDialogs(0), unreadCount(0), inboxReadTill(0), outboxReadTill(0), lastWidth(0), lastScrollTop(History::ScrollMax), + lastItemTextCache(st::dlgRichMinWidth), textCachedFor(0), typingText(st::dlgRichMinWidth), mute(isNotifyMuted(peer->notify)) { +} + +void History::updateNameText() { + nameText.setText(st::msgNameFont, peer->nameOrPhone.isEmpty() ? peer->name : peer->nameOrPhone, _textNameOptions); +} + +bool History::updateTyping(uint64 ms, uint32 dots, bool force) { + if (!ms) ms = getms(); + bool changed = force; + for (TypingUsers::iterator i = typing.begin(), e = typing.end(); i != e;) { + if (ms >= i.value()) { + i = typing.erase(i); + changed = true; + } else { + ++i; + } + } + if (changed) { + QString newTypingStr; + int32 cnt = typing.size(); + if (cnt > 2) { + newTypingStr = lang(lng_many_typing).replace(qsl("{n}"), QString("%1").arg(cnt)); + } else if (cnt > 1) { + newTypingStr = lang(lng_users_typing).replace(qsl("{user1}"), typing.begin().key()->firstName).replace(qsl("{user2}"), (typing.end() - 1).key()->firstName); + } else if (cnt) { + newTypingStr = peer->chat ? lang(lng_user_typing).replace(qsl("{user}"), typing.begin().key()->firstName) : lang(lng_typing); + } + if (!newTypingStr.isEmpty()) { + newTypingStr += qsl("..."); + } + if (typingStr != newTypingStr) { + typingText.setText(st::dlgHistFont, (typingStr = newTypingStr), _textNameOptions); + } + } + if (!typingStr.isEmpty()) { + if (typingText.lastDots(dots % 4)) { + changed = true; + } + } + return changed; +} + +bool DialogsList::del(const PeerId &peerId, DialogRow *replacedBy) { + RowByPeer::iterator i = rowByPeer.find(peerId); + if (i == rowByPeer.cend()) return false; + + DialogRow *row = i.value(); + emit App::main()->dialogRowReplaced(row, replacedBy); + + if (row == current) { + current = row->next; + } + for (DialogRow *change = row->next; change != end; change = change->next) { + change->pos--; + } + end->pos--; + remove(row); + delete row; + --count; + rowByPeer.erase(i); + + return true; +} + +void DialogsIndexed::peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) { + if (byName) { + DialogRow *mainRow = list.adjustByName(peer); + if (!mainRow) return; + + History *history = mainRow->history; + + PeerData::NameFirstChars toRemove = oldChars, toAdd; + for (PeerData::NameFirstChars::const_iterator i = peer->chars.cbegin(), e = peer->chars.cend(); i != e; ++i) { + PeerData::NameFirstChars::iterator j = toRemove.find(*i); + if (j == toRemove.cend()) { + toAdd.insert(*i); + } else { + toRemove.erase(j); + DialogsIndex::iterator k = index.find(*i); + if (k != index.cend()) { + k.value()->adjustByName(peer); + } + } + } + for (PeerData::NameFirstChars::const_iterator i = toRemove.cbegin(), e = toRemove.cend(); i != e; ++i) { + DialogsIndex::iterator j = index.find(*i); + if (j != index.cend()) { + j.value()->del(peer->id, mainRow); + } + } + if (!toAdd.isEmpty()) { + for (PeerData::NameFirstChars::const_iterator i = toAdd.cbegin(), e = toAdd.cend(); i != e; ++i) { + DialogsIndex::iterator j = index.find(*i); + if (j == index.cend()) { + j = index.insert(*i, new DialogsList(byName)); + } + j.value()->addByName(history); + } + } + } else { + DialogsList::RowByPeer::const_iterator i = list.rowByPeer.find(peer->id); + if (i == list.rowByPeer.cend()) return; + + DialogRow *mainRow = i.value(); + History *history = mainRow->history; + + PeerData::NameFirstChars toRemove = oldChars, toAdd; + for (PeerData::NameFirstChars::const_iterator i = peer->chars.cbegin(), e = peer->chars.cend(); i != e; ++i) { + PeerData::NameFirstChars::iterator j = toRemove.find(*i); + if (j == toRemove.cend()) { + toAdd.insert(*i); + } else { + toRemove.erase(j); + } + } + for (PeerData::NameFirstChars::const_iterator i = toRemove.cbegin(), e = toRemove.cend(); i != e; ++i) { + history->dialogs.remove(*i); + DialogsIndex::iterator j = index.find(*i); + if (j != index.cend()) { + j.value()->del(peer->id, mainRow); + } + } + for (PeerData::NameFirstChars::const_iterator i = toAdd.cbegin(), e = toAdd.cend(); i != e; ++i) { + DialogsIndex::iterator j = index.find(*i); + if (j == index.cend()) { + j = index.insert(*i, new DialogsList(byName)); + } + history->dialogs.insert(*i, j.value()->addByPos(history)); + } + } +} + +void DialogsIndexed::clear() { + for (DialogsIndex::iterator i = index.begin(), e = index.end(); i != e; ++i) { + delete i.value(); + } + index.clear(); + list.clear(); +} + +void Histories::clear() { + App::historyClearMsgs(); + for (Parent::const_iterator i = cbegin(), e = cend(); i != e; ++i) { + delete i.value(); + } + App::historyClearItems(); + typing.clear(); + Parent::clear(); +} + +Histories::Parent::iterator Histories::erase(Histories::Parent::iterator i) { + delete i.value(); + return Parent::erase(i); +} + +PeerId Histories::addToBack(const MTPmessage &msg, bool newMsg) { + PeerId from_id = 0, to_id = 0; + switch (msg.type()) { + case mtpc_message: + from_id = App::peerFromUser(msg.c_message().vfrom_id); + to_id = App::peerFromMTP(msg.c_message().vto_id); + break; + case mtpc_messageForwarded: + from_id = App::peerFromUser(msg.c_messageForwarded().vfrom_id); + to_id = App::peerFromMTP(msg.c_messageForwarded().vto_id); + break; + case mtpc_messageService: + from_id = App::peerFromUser(msg.c_messageService().vfrom_id); + to_id = App::peerFromMTP(msg.c_messageService().vto_id); + break; + } + PeerId peer = (to_id == App::peerFromUser(MTP::authedId())) ? from_id : to_id; + + if (!peer) return 0; + + iterator h = find(peer); + if (h == end()) { + h = insert(peer, new History(peer)); + } + h.value()->addToBack(msg, newMsg); + return peer; +} +/* +PeerId Histories::addToBack(const MTPgeoChatMessage &msg, bool newMsg) { + PeerId peer = 0; + switch (msg.type()) { + case mtpc_geoChatMessage: + peer = App::peerFromChat(msg.c_geoChatMessage().vchat_id); + break; + case mtpc_geoChatMessageService: + peer = App::peerFromChat(msg.c_geoChatMessageService().vchat_id); + break; + } + if (!peer) return 0; + + iterator h = find(peer); + if (h == end()) { + h = insert(peer, new History(peer)); + } + h.value()->addToBack(msg, newMsg); + return peer; +}/**/ + +HistoryItem *History::createItem(HistoryBlock *block, const MTPmessage &msg, bool newMsg) { + HistoryItem *result = 0; + + switch (msg.type()) { + case mtpc_messageEmpty: + result = new HistoryServiceMsg(this, block, msg.c_messageEmpty().vid.v, date(), lang(lng_message_empty)); + break; + + case mtpc_message: + result = new HistoryMessage(this, block, msg.c_message()); + break; + + case mtpc_messageForwarded: + result = new HistoryForwarded(this, block, msg.c_messageForwarded()); + break; + + case mtpc_messageService: { + const MTPDmessageService &d(msg.c_messageService()); + result = new HistoryServiceMsg(this, block, d); + + if (newMsg) { + const MTPmessageAction &action(d.vaction); + switch (d.vaction.type()) { + case mtpc_messageActionChatAddUser: { + const MTPDmessageActionChatAddUser &d(action.c_messageActionChatAddUser()); + // App::user(App::peerFromUser(d.vuser_id)); added + } break; + + case mtpc_messageActionChatDeletePhoto: { + ChatData *chat = peer->asChat(); + if (chat) chat->setPhoto(MTP_chatPhotoEmpty()); + } break; + + case mtpc_messageActionChatDeleteUser: { + const MTPDmessageActionChatDeleteUser &d(action.c_messageActionChatDeleteUser()); + // App::peer(App::peerFromUser(d.vuser_id)); left + } break; + + case mtpc_messageActionChatEditPhoto: { + const MTPDmessageActionChatEditPhoto &d(action.c_messageActionChatEditPhoto()); + if (d.vphoto.type() == mtpc_photo) { + const QVector &sizes(d.vphoto.c_photo().vsizes.c_vector().v); + if (!sizes.isEmpty()) { + ChatData *chat = peer->asChat(); + if (chat) { + PhotoData *photo = App::feedPhoto(d.vphoto.c_photo()); + if (photo) photo->chat = chat; + const MTPPhotoSize &smallSize(sizes.front()), &bigSize(sizes.back()); + const MTPFileLocation *smallLoc = 0, *bigLoc = 0; + switch (smallSize.type()) { + case mtpc_photoSize: smallLoc = &smallSize.c_photoSize().vlocation; break; + case mtpc_photoCachedSize: smallLoc = &smallSize.c_photoCachedSize().vlocation; break; + } + switch (bigSize.type()) { + case mtpc_photoSize: bigLoc = &bigSize.c_photoSize().vlocation; break; + case mtpc_photoCachedSize: bigLoc = &bigSize.c_photoCachedSize().vlocation; break; + } + if (smallLoc && bigLoc) { + chat->setPhoto(MTP_chatPhoto(*smallLoc, *bigLoc), photo ? photo->id : 0); + chat->photo->load(); + } + } + } + } + } break; + + case mtpc_messageActionChatEditTitle: { + const MTPDmessageActionChatEditTitle &d(action.c_messageActionChatEditTitle()); + ChatData *chat = peer->asChat(); + if (chat) chat->updateName(qs(d.vtitle), QString()); + } break; + } + } + } break; + } + + return regItem(result); +} + +HistoryItem *History::createItemForwarded(HistoryBlock *block, MsgId id, HistoryMessage *msg) { + HistoryItem *result = 0; + + result = new HistoryForwarded(this, block, id, msg); + + return regItem(result); +} + +/* +HistoryItem *History::createItem(HistoryBlock *block, const MTPgeoChatMessage &msg, bool newMsg) { + HistoryItem *result = 0; + + switch (msg.type()) { + case mtpc_geoChatMessageEmpty: + result = new HistoryServiceMsg(this, block, msg.c_geoChatMessageEmpty().vid.v, date(), lang(lng_message_empty)); + break; + + case mtpc_geoChatMessage: + result = new HistoryMessage(this, block, msg.c_geoChatMessage()); + break; + + case mtpc_geoChatMessageService: + result = new HistoryServiceMsg(this, block, msg.c_geoChatMessageService()); + break; + } + + return regItem(result); +} +/**/ +void History::addToBackService(MsgId msgId, QDateTime date, const QString &text, bool out, bool unread, HistoryMedia *media, bool newMsg) { + HistoryBlock *to = 0; + bool newBlock = isEmpty(); + if (newBlock) { + to = new HistoryBlock(this); + } else { + to = back(); + } + + doAddToBack(to, newBlock, regItem(new HistoryServiceMsg(this, to, msgId, date, text, out, unread, media)), newMsg); +} + +void History::addToBack(const MTPmessage &msg, bool newMsg) { + HistoryBlock *to = 0; + bool newBlock = isEmpty(); + if (newBlock) { + to = new HistoryBlock(this); + } else { + to = back(); + } + doAddToBack(to, newBlock, createItem(to, msg, newMsg), newMsg); +} + +void History::addToBackForwarded(MsgId id, HistoryMessage *item) { + HistoryBlock *to = 0; + bool newBlock = isEmpty(); + if (newBlock) { + to = new HistoryBlock(this); + } else { + to = back(); + } + doAddToBack(to, newBlock, createItemForwarded(to, id, item), true); +} + +/* +void History::addToBack(const MTPgeoChatMessage &msg, bool newMsg) { + HistoryBlock *to = 0; + bool newBlock = isEmpty(); + if (newBlock) { + to = new HistoryBlock(this); + } else { + to = back(); + } + + doAddToBack(to, newBlock, createItem(to, msg, newMsg), newMsg); +} +/**/ + +void History::createInitialDateBlock(const QDateTime &date) { + HistoryBlock *dateBlock = new HistoryBlock(this); // date block + HistoryItem *dayItem = createDayServiceMsg(this, dateBlock, date); + dateBlock->push_back(dayItem); + if (width) { + int32 dh = dayItem->resize(width); + dateBlock->height = dh; + height += dh; + for (int32 i = 0, l = size(); i < l; ++i) { + (*this)[i]->y += dh; + } + } + push_front(dateBlock); // date block +} + +void History::doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *adding, bool newMsg) { + if (!adding) { + if (newBlock) delete to; + return; + } + + if (newBlock) { + createInitialDateBlock(adding->date); + + to->y = height; + push_back(to); + } else if (to->back()->date.date() != adding->date.date()) { + HistoryItem *dayItem = createDayServiceMsg(this, to, adding->date); + to->push_back(dayItem); + dayItem->y = to->height; + if (width) { + int32 dh = dayItem->resize(width); + to->height += dh; + height += dh; + } + } + to->push_back(adding); + adding->y = to->height; + if (width) { + int32 dh = adding->resize(width); + to->height += dh; + height += dh; + } + setMsgCount(msgCount + 1); + if (adding->id > 0) { + ++offset; + } + if (newMsg) { + App::checkImageCacheSize(); + if (adding->from()) { + TypingUsers::iterator i = typing.find(adding->from()); + if (i != typing.end()) { + uint64 ms = getms(); + i.value() = ms; + updateTyping(ms, 0, true); + App::main()->topBar()->update(); + } + } + if (adding->out()) { + inboxRead(false); + if (unreadBar) unreadBar->destroy(); + } else if (adding->unread()) { + if (!notifyFrom) notifyFrom = adding; + App::main()->newUnreadMsg(this, adding->id); + } + if (dialogs.isEmpty()) { + App::main()->createDialogAtTop(this, unreadCount); + } else { + emit App::main()->dialogToTop(dialogs); + } + } +} + +void History::addToFront(const QVector &slice) { + if (slice.isEmpty()) return; + + int32 addToH = 0, skip = 0; + if (!isEmpty()) { + addToH = -front()->height; + pop_front(); // remove date block + } + HistoryItem *till = isEmpty() ? 0 : front()->front(), *prev = 0; + + HistoryBlock *block = new HistoryBlock(this); + block->reserve(slice.size()); + int32 wasMsgCount = msgCount; + for (QVector::const_iterator i = slice.cend() - 1, e = slice.cbegin(); ; --i) { + HistoryItem *adding = createItem(block, *i, false); + if (adding) { + if (prev && prev->date.date() != adding->date.date()) { + HistoryItem *dayItem = createDayServiceMsg(this, block, adding->date); + block->push_back(dayItem); + dayItem->y = block->height; + block->height += dayItem->resize(width); + } + block->push_back(adding); + adding->y = block->height; + block->height += adding->resize(width); + setMsgCount(msgCount + 1); + if (adding->id > 0) { + ++offset; + } + prev = adding; + } + if (i == e) break; + } + if (till && prev && prev->date.date() != till->date.date()) { + HistoryItem *dayItem = createDayServiceMsg(this, block, till->date); + block->push_back(dayItem); + dayItem->y = block->height; + block->height += dayItem->resize(width); + } + if (block->size()) { + if (wasMsgCount < unreadCount && msgCount >= unreadCount) { + for (int32 i = block->size(); i > 0; --i) { + if ((*block)[i - 1]->itemType() == HistoryItem::MsgType) { + ++wasMsgCount; + if (wasMsgCount == unreadCount) { + showFrom = (*block)[i - 1]; + break; + } + } + } + } + push_front(block); + addToH += block->height; + ++skip; + } else { + delete block; + } + if (!isEmpty()) { + HistoryBlock *dateBlock = new HistoryBlock(this); + HistoryItem *dayItem = createDayServiceMsg(this, dateBlock, front()->front()->date); + dateBlock->push_back(dayItem); + int32 dh = dayItem->resize(width); + dateBlock->height = dh; + if (skip) { + front()->y += dh; + } + push_front(dateBlock); // date block + addToH += dh; + ++skip; + } + if (addToH) { + for (iterator i = begin(), e = end(); i != e; ++i) { + if (skip) { + --skip; + } else { + (*i)->y += addToH; + } + } + height += addToH; + } +} + +void History::inboxRead(bool byThisInstance) { + if (unreadCount) { + if (!byThisInstance) App::main()->historyToDown(this); + setUnreadCount(0); + } + if (!isEmpty()) { + int32 till = back()->back()->id; + if (inboxReadTill < till) inboxReadTill = till; + } + if (!dialogs.isEmpty()) { + if (App::main()) App::main()->dlgUpdated(dialogs[0]); + } + App::wnd()->psClearNotify(this); + clearNotifyFrom(); +} + +void History::outboxRead() { + if (!isEmpty()) { + int32 till = back()->back()->id; + if (outboxReadTill < till) outboxReadTill = till; + } +} + +void History::setUnreadCount(int32 newUnreadCount, bool psUpdate) { + if (unreadCount != newUnreadCount) { + if (!unreadCount && newUnreadCount == 1) { + showFrom = isEmpty() ? 0 : back()->back(); + } else if (!newUnreadCount) { + showFrom = 0; + } + App::histories().unreadFull += newUnreadCount - unreadCount; + if (mute) App::histories().unreadMuted += newUnreadCount - unreadCount; + unreadCount = newUnreadCount; + unreadLoaded = (unreadCount <= msgCount); + if (psUpdate) App::wnd()->psUpdateCounter(); + if (unreadBar) unreadBar->setCount(unreadCount); + } +} + +void History::setMsgCount(int32 newMsgCount) { + if (msgCount != newMsgCount) { + msgCount = newMsgCount; + unreadLoaded = (unreadCount <= msgCount); + } +} + + void History::setMute(bool newMute) { + if (mute != newMute) { + App::histories().unreadMuted += newMute ? unreadCount : (-unreadCount); + mute = newMute; + App::wnd()->psUpdateCounter(); + } +} + +void History::getNextShowFrom(HistoryBlock *block, int32 i) { + if (i >= 0) { + int32 l = block->size(); + for (++i; i < l; ++i) { + if ((*block)[i]->itemType() == HistoryItem::MsgType) { + showFrom = (*block)[i]; + return; + } + } + } + + int32 j = indexOf(block), s = size(); + if (j >= 0) { + for (++j; j < s; ++j) { + block = (*this)[j]; + for (int32 i = 0, l = block->size(); i < l; ++i) { + if ((*block)[i]->itemType() == HistoryItem::MsgType) { + showFrom = (*block)[i]; + return; + } + } + } + } + showFrom = 0; +} + +void History::addUnreadBar() { + if (unreadBar || !showFrom || !unreadCount) return; + + HistoryBlock *block = showFrom->block(); + int32 i = block->indexOf(showFrom); + int32 j = indexOf(block); + if (i < 0 || j < 0) return; + + HistoryUnreadBar *bar = new HistoryUnreadBar(this, block, unreadCount, showFrom->date); + block->insert(i, bar); + unreadBar = bar; + + unreadBar->y = showFrom->y; + + int32 dh = unreadBar->resize(width), l = block->size(); + for (++i; i < l; ++i) { + (*block)[i]->y += dh; + } + block->height += dh; + for (++j, l = size(); j < l; ++j) { + (*this)[j]->y += dh; + } + height += dh; +} + +void History::getNextNotifyFrom(HistoryBlock *block, int32 i) { + if (!block) { + if (!notifyFrom) { + return; + } + block = notifyFrom->block(); + i = block->indexOf(notifyFrom); + } + if (i >= 0) { + int32 l = block->size(); + for (++i; i < l; ++i) { + if ((*block)[i]->unread() && !(*block)[i]->out()) { + notifyFrom = (*block)[i]; + return; + } + } + } + + int32 j = indexOf(block), s = size(); + if (j >= 0) { + for (++j; j < s; ++j) { + block = (*this)[j]; + for (int32 i = 0, l = block->size(); i < l; ++i) { + if ((*block)[i]->unread() && !(*block)[i]->out()) { + notifyFrom = (*block)[i]; + return; + } + } + } + } + notifyFrom = 0; +} + +void History::clearNotifyFrom() { + notifyFrom = 0; +} + +int32 History::geomResize(int32 newWidth, int32 *ytransform) { + if (width != newWidth) { + int32 y = 0; + for (iterator i = begin(), e = end(); i != e; ++i) { + HistoryBlock *block = *i; + bool updTransform = ytransform && (*ytransform >= block->y) && (*ytransform < block->y + block->height); + if (updTransform) *ytransform -= block->y; + if (block->y != y) { + block->y = y; + } + y += block->geomResize(newWidth, ytransform); + if (updTransform) { + *ytransform += block->y; + ytransform = 0; + } + } + width = newWidth; + height = y; + } + return height; +} + +void History::clear() { + for (Parent::const_iterator i = cbegin(), e = cend(); i != e; ++i) { + delete *i; + } + Parent::clear(); + setUnreadCount(0); + setMsgCount(0); +} + +History::Parent::iterator History::erase(History::Parent::iterator i) { + delete *i; + return Parent::erase(i); +} + +void History::blockResized(HistoryBlock *block, int32 dh) { + int32 i = indexOf(block), l = size(); + if (i >= 0) { + for (++i; i < l; ++i) { + (*this)[i]->y -= dh; + } + height -= dh; + } +} + +void History::removeBlock(HistoryBlock *block) { + int32 i = indexOf(block), h = block->height; + if (i >= 0) { + removeAt(i); + int32 l = size(); + if (i > 0 && l == 1) { // only fake block with date left + removeBlock((*this)[0]); + height = 0; + } else if (h) { + for (; i < l; ++i) { + (*this)[i]->y -= h; + } + height -= h; + } + } + delete block; +} + +int32 HistoryBlock::geomResize(int32 newWidth, int32 *ytransform) { + int32 y = 0; + for (iterator i = begin(), e = end(); i != e; ++i) { + HistoryItem *item = *i; + bool updTransform = ytransform && (*ytransform >= item->y) && (*ytransform < item->y + item->height()); + if (updTransform) *ytransform -= item->y; + item->y = y; + y += item->resize(newWidth); + if (updTransform) { + *ytransform += item->y; + ytransform = 0; + } + } + height = y; + return height; +} + +void HistoryBlock::clear() { + for (Parent::const_iterator i = cbegin(), e = cend(); i != e; ++i) { + delete *i; + } + Parent::clear(); +} +HistoryBlock::Parent::iterator HistoryBlock::erase(HistoryBlock::Parent::iterator i) { + delete *i; + return Parent::erase(i); +} + +void HistoryBlock::removeItem(HistoryItem *item) { + int32 i = indexOf(item), dh = 0; + if (history->notifyFrom == item) { + history->getNextNotifyFrom(this, i); + } + if (history->showFrom == item) { + history->getNextShowFrom(this, i); + } + if (i < 0) { + return; + } + + bool createInitialDate = false; + QDateTime initialDateTime; + int32 myIndex = history->indexOf(this); + if (myIndex >= 0 && item->itemType() != HistoryItem::DateType) { // fix date items + HistoryItem *nextItem = (i < size() - 1) ? (*this)[i + 1] : ((myIndex < history->size() - 1) ? (*(*history)[myIndex + 1])[0] : 0); + if (nextItem && nextItem == history->unreadBar) { // skip unread bar + if (i < size() - 2) { + nextItem = (*this)[i + 2]; + } else if (i < size() - 1) { + nextItem = ((myIndex < history->size() - 1) ? (*(*history)[myIndex + 1])[0] : 0); + } else if (myIndex < history->size() - 1) { + if (0 < (*history)[myIndex + 1]->size() - 1) { + nextItem = (*(*history)[myIndex + 1])[1]; + } else if (myIndex < history->size() - 2) { + nextItem = (*(*history)[myIndex + 2])[0]; + } else { + nextItem = 0; + } + } else { + nextItem = 0; + } + } + if (!nextItem || nextItem->itemType() == HistoryItem::DateType) { // only if there is no next item or it is a date item + HistoryItem *prevItem = (i > 0) ? (*this)[i - 1] : 0; + if (prevItem && prevItem == history->unreadBar) { // skip unread bar + prevItem = (i > 1) ? (*this)[i - 2] : 0; + } + if (prevItem) { + if (prevItem->itemType() == HistoryItem::DateType) { + prevItem->destroy(); + --i; + } + } else if (myIndex > 0) { + HistoryBlock *prevBlock = (*history)[myIndex - 1]; + if (prevBlock->isEmpty() || (myIndex == 1) && (prevBlock->size() != 1 || (*prevBlock->cbegin())->itemType() != HistoryItem::DateType)) { + LOG(("App Error: Found bad history, with no first date block: %1").arg((*history)[0]->size())); + } else if ((*prevBlock)[prevBlock->size() - 1]->itemType() == HistoryItem::DateType) { + (*prevBlock)[prevBlock->size() - 1]->destroy(); + if (nextItem && myIndex == 1) { // destroy next date (for creating initial then) + initialDateTime = nextItem->date; + createInitialDate = true; + nextItem->destroy(); + } + } + } + } + } + // myIndex can be invalid now, because of destroying previous blocks + + dh = item->height(); + remove(i); + int32 l = size(); + if (!item->out() && item->unread() && history->unreadCount) { + history->setUnreadCount(history->unreadCount - 1); + } + if (item->id > 0) { + --history->offset; + } + int32 itemType = item->itemType(); + if (itemType == HistoryItem::MsgType) { + history->setMsgCount(history->msgCount - 1); + } else if (itemType == HistoryItem::UnreadBarType) { + if (history->unreadBar == item) { + history->unreadBar = 0; + } + } + if (createInitialDate) { + history->createInitialDateBlock(initialDateTime); + } + History *h = history; + if (l) { + for (; i < l; ++i) { + (*this)[i]->y -= dh; + } + height -= dh; + history->blockResized(this, dh); + } else { + history->removeBlock(this); + } + delete item; + if (h->unreadBar && h->back()->back() == h->unreadBar) { + h->unreadBar->destroy(); + } +} + +HistoryItem::HistoryItem(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime msgDate, int32 from) : + y(0), id(msgId), _history(history), _block(block), _out(out), _unread(unread), date(msgDate), _from(App::user(from)), _fromVersion(_from->nameVersion) { +} + +void HistoryItem::markRead() { + if (_unread) { + if (_out) { + _history->outboxRead(); + } else { + _history->inboxRead(); + } + App::main()->msgUpdated(_history->peer->id, this); + _unread = false; + } +} + +HistoryItem::~HistoryItem() { + App::historyUnregItem(this); + if (id < 0) { + App::app()->uploader()->cancel(id); + } +} + +HistoryItem *regItem(HistoryItem *item) { + if (item && App::historyRegItem(item)) { + return item; + } + delete item; + return 0; +} + +HistoryPhoto::HistoryPhoto(const MTPDphoto &photo, int32 width) : data(App::feedPhoto(photo)), w(width), openl(new PhotoLink(data)) { + int32 tw = data->full->width(), th = data->full->height(); + if (!tw || !th) { + tw = th = 1; + } + int32 thumbw = st::msgMinWidth + st::msgPadding.left() + st::msgPadding.right() - 2, maxthumbh = qRound(1.5 * thumbw); + if (data->full->width() < thumbw) { + thumbw = (data->full->width() > 20) ? data->full->width() : 20; + } + if (!w) { + w = thumbw; + } + int32 thumbh = qRound(th * float64(w) / tw); + if (thumbh > maxthumbh) { + w = qRound(w * float64(maxthumbh) / thumbh); + thumbh = maxthumbh; + if (w < 10) { + w = 10; + } + } + _maxw = w; + _height = _minh = thumbh; + data->thumb->load(); +} + +int32 HistoryPhoto::resize(int32 nwidth) { + return _height; +} + +const QString HistoryPhoto::inDialogsText() const { + return lang(lng_in_dlg_photo); +} + +bool HistoryPhoto::hasPoint(int32 x, int32 y) const { + return (x >= 0 && y >= 0 && x < _maxw && y < _height); +} + +TextLinkPtr HistoryPhoto::getLink(int32 x, int32 y, const HistoryItem *parent) const { + if (x >= 0 && y >= 0 && x < _maxw && y < _height) { + return openl; + } + return TextLinkPtr(); +} + +bool HistoryPhoto::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + if (data == photo) { + w = this->w; + x = 0; + y = 0; + return true; + } + return false; +} + +HistoryMedia *HistoryPhoto::clone() const { + return new HistoryPhoto(*this); +} + +void HistoryPhoto::draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const { + data->full->load(false, false); + bool out = parent->out(); + if (parent != App::contextItem() || App::wnd()->photoShown() != data) { + if (data->full->loaded()) { + p.drawPixmap(0, 0, data->full->pix(_maxw, _height)); + } else { + p.drawPixmap(0, 0, data->thumb->pix(_maxw, _height)); + } + + if (selected) { + p.fillRect(0, 0, _maxw, _height, textstyleCurrent()->selectOverlay->b); + } + style::color shadow(selected ? st::msgInSelectShadow : st::msgInShadow); + p.fillRect(0, _height, _maxw, st::msgShadow, shadow->b); + } + + // date + if (time.isEmpty()) return; + int32 dateX = _maxw - timeWidth - st::msgDateImgDelta - 2 * st::msgDateImgPadding.x(); + int32 dateY = _height - st::msgDateFont->height - 2 * st::msgDateImgPadding.y() - st::msgDateImgDelta; + if (parent->out()) { + dateX -= st::msgCheckRect.width() + st::msgDateImgCheckSpace; + } + int32 dateW = _maxw - dateX - st::msgDateImgDelta; + int32 dateH = _height - dateY - st::msgDateImgDelta; + + p.fillRect(dateX, dateY, dateW, dateH, st::msgDateImgBg->b); + p.setFont(st::msgDateFont->f); + p.setPen(st::msgDateImgColor->p); + p.drawText(dateX + st::msgDateImgPadding.x(), dateY + st::msgDateImgPadding.y() + st::msgDateFont->ascent, time); + if (out) { + QPoint iconPos(dateX - 2 + dateW - st::msgDateImgCheckSpace - st::msgCheckRect.width(), dateY + (dateH - st::msgCheckRect.height()) / 2); + const QRect *iconRect; + if (parent->id > 0) { + if (parent->unread()) { + iconRect = &st::msgImgCheckRect; + } else { + iconRect = &st::msgImgDblCheckRect; + } + } else { + iconRect = &st::msgImgSendingRect; + } + p.drawPixmap(iconPos, App::sprite(), *iconRect); + } +} + +QString formatSizeText(qint64 size) { + if (size >= 1024 * 1024) { // more than 1 mb + qint64 sizeTenthMb = (size * 10 / (1024 * 1024)); + return QString::number(sizeTenthMb / 10) + '.' + QString::number(sizeTenthMb % 10) + qsl("Mb"); + } + qint64 sizeTenthKb = (size * 10 / 1024); + return QString::number(sizeTenthKb / 10) + '.' + QString::number(sizeTenthKb % 10) + qsl("Kb"); +} + +QString formatDownloadText(qint64 ready, qint64 total) { + QString readyStr, totalStr, mb; + if (total >= 1024 * 1024) { // more than 1 mb + qint64 readyTenthMb = (ready * 10 / (1024 * 1024)), totalTenthMb = (total * 10 / (1024 * 1024)); + readyStr = QString::number(readyTenthMb / 10) + '.' + QString::number(readyTenthMb % 10); + totalStr = QString::number(totalTenthMb / 10) + '.' + QString::number(totalTenthMb % 10); + mb = qsl("Mb"); + } else { + qint64 readyKb = (ready / 1024), totalKb = (total / 1024); + readyStr = QString::number(readyKb); + totalStr = QString::number(totalKb); + mb = qsl("Kb"); + } + return lang(lng_save_downloaded).replace(qsl("{ready}"), readyStr).replace(qsl("{total}"), totalStr).replace(qsl("{mb}"), mb); +} + +QString formatDurationText(qint64 duration) { + qint64 hours = (duration / 3600), minutes = (duration % 3600) / 60, seconds = duration % 60; + return (hours ? QString::number(hours) + ':' : QString()) + (minutes >= 10 ? QString() : QString('0')) + QString::number(minutes) + ':' + (seconds >= 10 ? QString() : QString('0')) + QString::number(seconds); +} + +QString formatDurationAndSizeText(qint64 duration, qint64 size) { + return lang(lng_duration_and_size).replace(qsl("{duration}"), formatDurationText(duration)).replace(qsl("{size}"), formatSizeText(size)); +} + +int32 _downloadWidth = 0, _openWithWidth = 0, _cancelWidth = 0, _buttonWidth = 0; + +HistoryVideo::HistoryVideo(const MTPDvideo &video, int32 width) : data(App::feedVideo(video)), w(width), _openl(new VideoOpenLink(data)), _savel(new VideoSaveLink(data)), _cancell(new VideoCancelLink(data)), _dldDone(0), _uplDone(0) { + _maxw = st::mediaMaxWidth; + + _size = formatDurationAndSizeText(data->duration, data->size); + + _height = st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom(); + + if (!_openWithWidth) { + _downloadWidth = st::mediaSaveButton.font->m.width(lang(lng_media_download)); + _openWithWidth = st::mediaSaveButton.font->m.width(lang(lng_media_open_with)); + _cancelWidth = st::mediaSaveButton.font->m.width(lang(lng_media_cancel)); + _buttonWidth = (st::mediaSaveButton.width > 0) ? st::mediaSaveButton.width : ((_downloadWidth > _openWithWidth ? (_downloadWidth > _cancelWidth ? _downloadWidth : _cancelWidth) : _openWithWidth) - st::mediaSaveButton.width); + } + + data->thumb->load(); + + int32 tw = data->thumb->width(), th = data->thumb->height(); + if (data->thumb->isNull() || !tw || !th) { + _thumbw = _thumbx = _thumby = 0; + } else if (tw > th) { + _thumbw = (tw * st::mediaThumbSize) / th; + _thumbx = (_thumbw - st::mediaThumbSize) / 2; + _thumby = 0; + } else { + _thumbw = st::mediaThumbSize; + _thumbx = 0; + _thumby = ((th * _thumbw) / tw - st::mediaThumbSize) / 2; + } +} + +void HistoryVideo::reinit() { + _maxw = st::mediaMaxWidth; +} + +void HistoryVideo::initDimensions(const HistoryItem *parent, int32 timeWidth) { + int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right(); + if (!parent->out()) { // add Download / Save As button + _maxw += st::mediaSaveDelta + _buttonWidth; + } +} + +void HistoryVideo::regItem(HistoryItem *item) { + App::regVideoItem(data, item); +} + +void HistoryVideo::unregItem(HistoryItem *item) { + App::unregVideoItem(data, item); +} + +int32 HistoryVideo::resize(int32 nwidth) { + w = nwidth; + return _height; +} + +const QString HistoryVideo::inDialogsText() const { + return lang(lng_in_dlg_video); +} + +bool HistoryVideo::hasPoint(int32 x, int32 y) const { + int32 width = w; + if (width >= _maxw) { + width = _maxw; + } + return (x >= 0 && y >= 0 && x < width && y < _height); +} + +TextLinkPtr HistoryVideo::getLink(int32 x, int32 y, const HistoryItem *parent) const { + int32 width = w; + if (width < 1) return TextLinkPtr(); + + bool out = parent->out(), hovered, pressed; + if (width >= _maxw) { + width = _maxw; + } + + if (!out) { // draw Download / Save As button + int32 btnw = _buttonWidth, btnh = st::mediaSaveButton.height, btnx = width - _buttonWidth, btny = (_height - btnh) / 2; + if (x >= btnx && y >= btny && x < btnx + btnw && y < btny + btnh) { + return data->loader ? _cancell : _savel; + } + width -= btnw + st::mediaSaveDelta; + } + + if (x >= 0 && y >= 0 && x < width && y < _height && !data->loader && data->access) { + return _openl; + } + return TextLinkPtr(); +} + +bool HistoryVideo::getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const { + if (data == video) { + w = this->w; + x = 0; + y = 0; + return true; + } + return false; +} + +HistoryMedia *HistoryVideo::clone() const { + HistoryVideo *n = new HistoryVideo(*this); + n->reinit(); + return n; +} + +void HistoryVideo::draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const { + int32 width = w; + if (width < 1) return; + + data->thumb->checkload(); + + bool out = parent->out(), hovered, pressed; + if (width >= _maxw) { + width = _maxw; + } + + if (!out) { // draw Download / Save As button + hovered = ((data->loader ? _cancell : _savel) == textlnkOver()); + pressed = hovered && ((data->loader ? _cancell : _savel) == textlnkDown()); + if (hovered && !pressed && textlnkDown()) hovered = false; + + int32 btnw = _buttonWidth, btnh = st::mediaSaveButton.height, btnx = width - _buttonWidth, btny = (_height - btnh) / 2; + p.fillRect(QRect(btnx, btny, btnw, btnh), (selected ? st::msgInSelectBG : (hovered ? st::mediaSaveButton.overBgColor : st::mediaSaveButton.bgColor))->b); + + style::color shadow(selected ? (out ? st::msgOutSelectShadow : st::msgInSelectShadow) : (out ? st::msgOutShadow : st::msgInShadow)); + p.fillRect(btnx, btny + btnh, btnw, st::msgShadow, shadow->b); + + p.setPen((hovered ? st::mediaSaveButton.overColor : st::mediaSaveButton.color)->p); + p.setFont(st::mediaSaveButton.font->f); + QString btnText(lang(data->loader ? lng_media_cancel : (data->already().isEmpty() ? lng_media_download : lng_media_open_with))); + int32 btnTextWidth = data->loader ? _cancelWidth : (data->already().isEmpty() ? _downloadWidth : _openWithWidth); + p.drawText(btnx + (btnw - btnTextWidth) / 2, btny + (pressed ? st::mediaSaveButton.downTextTop : st::mediaSaveButton.textTop) + st::mediaSaveButton.font->ascent, btnText); + width -= btnw + st::mediaSaveDelta; + } + + style::color bg(selected ? (out ? st::msgOutSelectBG : st::msgInSelectBG) : (out ? st::msgOutBG : st::msgInBG)); + p.fillRect(QRect(0, 0, width, _height), bg->b); + + style::color shadow(selected ? (out ? st::msgOutSelectShadow : st::msgInSelectShadow) : (out ? st::msgOutShadow : st::msgInShadow)); + p.fillRect(0, _height, width, st::msgShadow, shadow->b); + + if (_thumbw) { + p.drawPixmap(QPoint(st::mediaPadding.left(), st::mediaPadding.top()), data->thumb->pix(_thumbw), QRect(_thumbx, _thumby, st::mediaThumbSize, st::mediaThumbSize)); + } else { + p.drawPixmap(QPoint(st::mediaPadding.left(), st::mediaPadding.top()), App::sprite(), (out ? st::mediaDocOutImg : st::mediaDocInImg)); + } + if (selected) { + p.fillRect(st::mediaPadding.left(), st::mediaPadding.top(), st::mediaThumbSize, st::mediaThumbSize, (out ? st::msgOutSelectOverlay : st::msgInSelectOverlay)->b); + } + + int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right(); + int32 twidth = width - tleft - st::mediaPadding.right(); + int32 fullTimeWidth = timeWidth + st::msgDateSpace + (out ? st::msgDateCheckSpace + st::msgCheckRect.width() : 0) + st::msgPadding.right() - st::msgDateDelta.x(); + int32 secondwidth = width - tleft - fullTimeWidth; + + p.setFont(st::mediaFont->f); + p.setPen(st::black->c); + p.drawText(tleft, st::mediaPadding.top() + 3 + st::mediaFont->ascent, lang(lng_media_video)); + + QString statusText; + + style::color status(selected ? (out ? st::mediaOutSelectColor : st::mediaInSelectColor) : (out ? st::mediaOutColor : st::mediaInColor)); + p.setPen(status->p); + + if (data->loader) { + if (_dldTextCache.isEmpty() || _dldDone != data->loader->currentOffset()) { + _dldDone = data->loader->currentOffset(); + _dldTextCache = formatDownloadText(_dldDone, data->size); + } + statusText = _dldTextCache; + } else { + if (data->status == FileFailed) { + statusText = lang(lng_attach_failed); + } else if (data->status == FileUploading) { + if (_uplTextCache.isEmpty() || _uplDone != data->uploadOffset) { + _uplDone = data->uploadOffset; + _uplTextCache = formatDownloadText(_uplDone, data->size); + } + statusText = _uplTextCache; + } else { + statusText = _size; + } + } + p.drawText(tleft, st::mediaPadding.top() + st::mediaThumbSize - 3 - st::mediaFont->descent, statusText); + + p.setFont(st::msgDateFont->f); + + style::color date(selected ? (out ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (out ? st::msgOutDateColor : st::msgInDateColor)); + p.setPen(date->p); + + p.drawText(width + st::msgDateDelta.x() - fullTimeWidth + st::msgDateSpace, _height - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, time); + if (out) { + QPoint iconPos(width + 5 - st::msgPadding.right() - st::msgCheckRect.width(), _height + 1 - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgCheckRect.height()); + const QRect *iconRect; + if (parent->id > 0) { + if (parent->unread()) { + iconRect = &(selected ? st::msgSelectCheckRect : st::msgCheckRect); + } else { + iconRect = &(selected ? st::msgSelectDblCheckRect : st::msgDblCheckRect); + } + } else { + iconRect = &st::msgSendingRect; + } + p.drawPixmap(iconPos, App::sprite(), *iconRect); + } +} + +HistoryAudio::HistoryAudio(const MTPDaudio &audio, int32 width) : data(App::feedAudio(audio)), w(width), _openl(new AudioOpenLink(data)), _savel(new AudioSaveLink(data)), _cancell(new AudioCancelLink(data)), _dldDone(0), _uplDone(0) { + _maxw = st::mediaMaxWidth; + + _size = formatDurationAndSizeText(data->duration, data->size); + + _height = st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom(); + + if (!_openWithWidth) { + _downloadWidth = st::mediaSaveButton.font->m.width(lang(lng_media_download)); + _openWithWidth = st::mediaSaveButton.font->m.width(lang(lng_media_open_with)); + _cancelWidth = st::mediaSaveButton.font->m.width(lang(lng_media_cancel)); + _buttonWidth = (st::mediaSaveButton.width > 0) ? st::mediaSaveButton.width : ((_downloadWidth > _openWithWidth ? (_downloadWidth > _cancelWidth ? _downloadWidth : _cancelWidth) : _openWithWidth) - st::mediaSaveButton.width); + } +} + +void HistoryAudio::reinit() { + _maxw = st::mediaMaxWidth; +} + +void HistoryAudio::initDimensions(const HistoryItem *parent, int32 timeWidth) { + int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right(); + if (!parent->out()) { // add Download / Save As button + _maxw += st::mediaSaveDelta + _buttonWidth; + } +} + +void HistoryAudio::draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const { + int32 width = w; + if (width < 1) return; + + bool out = parent->out(), hovered, pressed; + if (width >= _maxw) { + width = _maxw; + } + + if (!out) { // draw Download / Save As button + hovered = ((data->loader ? _cancell : _savel) == textlnkOver()); + pressed = hovered && ((data->loader ? _cancell : _savel) == textlnkDown()); + if (hovered && !pressed && textlnkDown()) hovered = false; + + int32 btnw = _buttonWidth, btnh = st::mediaSaveButton.height, btnx = width - _buttonWidth, btny = (_height - btnh) / 2; + p.fillRect(QRect(btnx, btny, btnw, btnh), (selected ? st::msgInSelectBG : (hovered ? st::mediaSaveButton.overBgColor : st::mediaSaveButton.bgColor))->b); + + style::color shadow(selected ? (out ? st::msgOutSelectShadow : st::msgInSelectShadow) : (out ? st::msgOutShadow : st::msgInShadow)); + p.fillRect(btnx, btny + btnh, btnw, st::msgShadow, shadow->b); + + p.setPen((hovered ? st::mediaSaveButton.overColor : st::mediaSaveButton.color)->p); + p.setFont(st::mediaSaveButton.font->f); + QString btnText(lang(data->loader ? lng_media_cancel : (data->already().isEmpty() ? lng_media_download : lng_media_open_with))); + int32 btnTextWidth = data->loader ? _cancelWidth : (data->already().isEmpty() ? _downloadWidth : _openWithWidth); + p.drawText(btnx + (btnw - btnTextWidth) / 2, btny + (pressed ? st::mediaSaveButton.downTextTop : st::mediaSaveButton.textTop) + st::mediaSaveButton.font->ascent, btnText); + width -= btnw + st::mediaSaveDelta; + } + + style::color bg(selected ? (out ? st::msgOutSelectBG : st::msgInSelectBG) : (out ? st::msgOutBG : st::msgInBG)); + p.fillRect(QRect(0, 0, width, _height), bg->b); + + style::color shadow(selected ? (out ? st::msgOutSelectShadow : st::msgInSelectShadow) : (out ? st::msgOutShadow : st::msgInShadow)); + p.fillRect(0, _height, width, st::msgShadow, shadow->b); + + p.drawPixmap(QPoint(st::mediaPadding.left(), st::mediaPadding.top()), App::sprite(), (out ? st::mediaAudioOutImg : st::mediaAudioInImg)); + if (selected) { + p.fillRect(st::mediaPadding.left(), st::mediaPadding.top(), st::mediaThumbSize, st::mediaThumbSize, (out ? st::msgOutSelectOverlay : st::msgInSelectOverlay)->b); + } + + int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right(); + int32 twidth = width - tleft - st::mediaPadding.right(); + int32 fullTimeWidth = timeWidth + st::msgDateSpace + (out ? st::msgDateCheckSpace + st::msgCheckRect.width() : 0) + st::msgPadding.right() - st::msgDateDelta.x(); + int32 secondwidth = width - tleft - fullTimeWidth; + + p.setFont(st::mediaFont->f); + p.setPen(st::black->c); + p.drawText(tleft, st::mediaPadding.top() + 3 + st::mediaFont->ascent, lang(lng_media_audio)); + + QString statusText; + + style::color status(selected ? (out ? st::mediaOutSelectColor : st::mediaInSelectColor) : (out ? st::mediaOutColor : st::mediaInColor)); + p.setPen(status->p); + + if (data->loader) { + if (_dldTextCache.isEmpty() || _dldDone != data->loader->currentOffset()) { + _dldDone = data->loader->currentOffset(); + _dldTextCache = formatDownloadText(_dldDone, data->size); + } + statusText = _dldTextCache; + } else { + if (data->status == FileFailed) { + statusText = lang(lng_attach_failed); + } else if (data->status == FileUploading) { + if (_uplTextCache.isEmpty() || _uplDone != data->uploadOffset) { + _uplDone = data->uploadOffset; + _uplTextCache = formatDownloadText(_uplDone, data->size); + } + statusText = _uplTextCache; + } else { + statusText = _size; + } + } + p.drawText(tleft, st::mediaPadding.top() + st::mediaThumbSize - 3 - st::mediaFont->descent, statusText); + + p.setFont(st::msgDateFont->f); + + style::color date(selected ? (out ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (out ? st::msgOutDateColor : st::msgInDateColor)); + p.setPen(date->p); + + p.drawText(width + st::msgDateDelta.x() - fullTimeWidth + st::msgDateSpace, _height - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, time); + if (out) { + QPoint iconPos(width + 5 - st::msgPadding.right() - st::msgCheckRect.width(), _height + 1 - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgCheckRect.height()); + const QRect *iconRect; + if (parent->id > 0) { + if (parent->unread()) { + iconRect = &(selected ? st::msgSelectCheckRect : st::msgCheckRect); + } else { + iconRect = &(selected ? st::msgSelectDblCheckRect : st::msgDblCheckRect); + } + } else { + iconRect = &st::msgSendingRect; + } + p.drawPixmap(iconPos, App::sprite(), *iconRect); + } +} + +void HistoryAudio::regItem(HistoryItem *item) { + App::regAudioItem(data, item); +} + +void HistoryAudio::unregItem(HistoryItem *item) { + App::unregAudioItem(data, item); +} + +int32 HistoryAudio::resize(int32 nwidth) { + w = nwidth; + return _height; +} + +const QString HistoryAudio::inDialogsText() const { + return lang(lng_in_dlg_audio); +} + +bool HistoryAudio::hasPoint(int32 x, int32 y) const { + int32 width = w; + if (width >= _maxw) { + width = _maxw; + } + return (x >= 0 && y >= 0 && x < width && y < _height); +} + +TextLinkPtr HistoryAudio::getLink(int32 x, int32 y, const HistoryItem *parent) const { + int32 width = w; + if (width < 1) return TextLinkPtr(); + + bool out = parent->out(), hovered, pressed; + if (width >= _maxw) { + width = _maxw; + } + + if (!out) { // draw Download / Save As button + int32 btnw = _buttonWidth, btnh = st::mediaSaveButton.height, btnx = width - _buttonWidth, btny = (_height - btnh) / 2; + if (x >= btnx && y >= btny && x < btnx + btnw && y < btny + btnh) { + return data->loader ? _cancell : _savel; + } + width -= btnw + st::mediaSaveDelta; + } + + if (x >= 0 && y >= 0 && x < width && y < _height && !data->loader && data->access) { + return _openl; + } + return TextLinkPtr(); +} + +HistoryMedia *HistoryAudio::clone() const { + HistoryAudio *n = new HistoryAudio(*this); + n->reinit(); + return n; +} + +HistoryDocument::HistoryDocument(const MTPDdocument &document, int32 width) : data(App::feedDocument(document)), w(width), _openl(new DocumentOpenLink(data)), _savel(new DocumentSaveLink(data)), _cancell(new DocumentCancelLink(data)), _name(data->name), _dldDone(0), _uplDone(0) { + _maxw = st::mediaMaxWidth; + _namew = st::mediaFont->m.width(_name.isEmpty() ? qsl("Document") : _name); + + _size = formatSizeText(data->size); + + _height = st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom(); + + if (!_openWithWidth) { + _downloadWidth = st::mediaSaveButton.font->m.width(lang(lng_media_download)); + _openWithWidth = st::mediaSaveButton.font->m.width(lang(lng_media_open_with)); + _cancelWidth = st::mediaSaveButton.font->m.width(lang(lng_media_cancel)); + _buttonWidth = (st::mediaSaveButton.width > 0) ? st::mediaSaveButton.width : ((_downloadWidth > _openWithWidth ? (_downloadWidth > _cancelWidth ? _downloadWidth : _cancelWidth) : _openWithWidth) - st::mediaSaveButton.width); + } + + data->thumb->load(); + + int32 tw = data->thumb->width(), th = data->thumb->height(); + if (data->thumb->isNull() || !tw || !th) { + _thumbw = _thumbx = _thumby = 0; + } else if (tw > th) { + _thumbw = (tw * st::mediaThumbSize) / th; + _thumbx = (_thumbw - st::mediaThumbSize) / 2; + _thumby = 0; + } else { + _thumbw = st::mediaThumbSize; + _thumbx = 0; + _thumby = ((th * _thumbw) / tw - st::mediaThumbSize) / 2; + } +} + +void HistoryDocument::reinit() { + _maxw = st::mediaMaxWidth; +} + +void HistoryDocument::initDimensions(const HistoryItem *parent, int32 timeWidth) { + int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right(); + if (_namew + tleft + st::mediaPadding.right() > _maxw) { + _maxw = _namew + tleft + st::mediaPadding.right(); + } + if (!parent->out()) { // add Download / Save As button + _maxw += st::mediaSaveDelta + _buttonWidth; + } +} + +void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const { + int32 width = w; + if (width < 1) return; + + data->thumb->checkload(); + + bool out = parent->out(), hovered, pressed; + if (width >= _maxw) { + width = _maxw; + } + + if (!out) { // draw Download / Save As button + hovered = ((data->loader ? _cancell : _savel) == textlnkOver()); + pressed = hovered && ((data->loader ? _cancell : _savel) == textlnkDown()); + if (hovered && !pressed && textlnkDown()) hovered = false; + + int32 btnw = _buttonWidth, btnh = st::mediaSaveButton.height, btnx = width - _buttonWidth, btny = (_height - btnh) / 2; + p.fillRect(QRect(btnx, btny, btnw, btnh), (selected ? st::msgInSelectBG : (hovered ? st::mediaSaveButton.overBgColor : st::mediaSaveButton.bgColor))->b); + + style::color shadow(selected ? (out ? st::msgOutSelectShadow : st::msgInSelectShadow) : (out ? st::msgOutShadow : st::msgInShadow)); + p.fillRect(btnx, btny + btnh, btnw, st::msgShadow, shadow->b); + + p.setPen((hovered ? st::mediaSaveButton.overColor : st::mediaSaveButton.color)->p); + p.setFont(st::mediaSaveButton.font->f); + QString btnText(lang(data->loader ? lng_media_cancel : (data->already().isEmpty() ? lng_media_download : lng_media_open_with))); + int32 btnTextWidth = data->loader ? _cancelWidth : (data->already().isEmpty() ? _downloadWidth : _openWithWidth); + p.drawText(btnx + (btnw - btnTextWidth) / 2, btny + (pressed ? st::mediaSaveButton.downTextTop : st::mediaSaveButton.textTop) + st::mediaSaveButton.font->ascent, btnText); + width -= btnw + st::mediaSaveDelta; + } + + style::color bg(selected ? (out ? st::msgOutSelectBG : st::msgInSelectBG) : (out ? st::msgOutBG : st::msgInBG)); + p.fillRect(QRect(0, 0, width, _height), bg->b); + + style::color shadow(selected ? (out ? st::msgOutSelectShadow : st::msgInSelectShadow) : (out ? st::msgOutShadow : st::msgInShadow)); + p.fillRect(0, _height, width, st::msgShadow, shadow->b); + + if (_thumbw) { + p.drawPixmap(QPoint(st::mediaPadding.left(), st::mediaPadding.top()), data->thumb->pix(_thumbw), QRect(_thumbx, _thumby, st::mediaThumbSize, st::mediaThumbSize)); + } else { + p.drawPixmap(QPoint(st::mediaPadding.left(), st::mediaPadding.top()), App::sprite(), (out ? st::mediaDocOutImg : st::mediaDocInImg)); + } + if (selected) { + p.fillRect(st::mediaPadding.left(), st::mediaPadding.top(), st::mediaThumbSize, st::mediaThumbSize, (out ? st::msgOutSelectOverlay : st::msgInSelectOverlay)->b); + } + + int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right(); + int32 twidth = width - tleft - st::mediaPadding.right(); + int32 fullTimeWidth = timeWidth + st::msgDateSpace + (out ? st::msgDateCheckSpace + st::msgCheckRect.width() : 0) + st::msgPadding.right() - st::msgDateDelta.x(); + int32 secondwidth = width - tleft - fullTimeWidth; + + p.setFont(st::mediaFont->f); + p.setPen(st::black->c); + if (twidth < _namew) { + p.drawText(tleft, st::mediaPadding.top() + 3 + st::mediaFont->ascent, st::mediaFont->m.elidedText(_name, Qt::ElideRight, twidth)); + } else { + p.drawText(tleft, st::mediaPadding.top() + 3 + st::mediaFont->ascent, _name); + } + + QString statusText; + + style::color status(selected ? (out ? st::mediaOutSelectColor : st::mediaInSelectColor) : (out ? st::mediaOutColor : st::mediaInColor)); + p.setPen(status->p); + + if (data->loader) { + if (_dldTextCache.isEmpty() || _dldDone != data->loader->currentOffset()) { + _dldDone = data->loader->currentOffset(); + _dldTextCache = formatDownloadText(_dldDone, data->size); + } + statusText = _dldTextCache; + } else { + if (data->status == FileFailed) { + statusText = lang(lng_attach_failed); + } else if (data->status == FileUploading) { + if (_uplTextCache.isEmpty() || _uplDone != data->uploadOffset) { + _uplDone = data->uploadOffset; + _uplTextCache = formatDownloadText(_uplDone, data->size); + } + statusText = _uplTextCache; + } else { + statusText = _size; + } + } + p.drawText(tleft, st::mediaPadding.top() + st::mediaThumbSize - 3 - st::mediaFont->descent, statusText); + + p.setFont(st::msgDateFont->f); + + style::color date(selected ? (out ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (out ? st::msgOutDateColor : st::msgInDateColor)); + p.setPen(date->p); + + p.drawText(width + st::msgDateDelta.x() - fullTimeWidth + st::msgDateSpace, _height - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, time); + if (out) { + QPoint iconPos(width + 5 - st::msgPadding.right() - st::msgCheckRect.width(), _height + 1 - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgCheckRect.height()); + const QRect *iconRect; + if (parent->id > 0) { + if (parent->unread()) { + iconRect = &(selected ? st::msgSelectCheckRect : st::msgCheckRect); + } else { + iconRect = &(selected ? st::msgSelectDblCheckRect : st::msgDblCheckRect); + } + } else { + iconRect = &st::msgSendingRect; + } + p.drawPixmap(iconPos, App::sprite(), *iconRect); + } +} + +void HistoryDocument::regItem(HistoryItem *item) { + App::regDocumentItem(data, item); +} + +void HistoryDocument::unregItem(HistoryItem *item) { + App::unregDocumentItem(data, item); +} + +void HistoryDocument::updateFrom(const MTPMessageMedia &media) { + if (media.type() == mtpc_messageMediaDocument) { + App::feedDocument(media.c_messageMediaDocument().vdocument, data); + } +} + +int32 HistoryDocument::resize(int32 width) { + w = width; + return _height; +} + +const QString HistoryDocument::inDialogsText() const { + return lang(lng_in_dlg_document); +} + +bool HistoryDocument::hasPoint(int32 x, int32 y) const { + int32 width = w; + if (width >= _maxw) { + width = _maxw; + } + return (x >= 0 && y >= 0 && x < width && y < _height); +} + +TextLinkPtr HistoryDocument::getLink(int32 x, int32 y, const HistoryItem *parent) const { + int32 width = w; + if (width < 1) return TextLinkPtr(); + + bool out = parent->out(), hovered, pressed; + if (width >= _maxw) { + width = _maxw; + } + + if (!out) { // draw Download / Save As button + int32 btnw = _buttonWidth, btnh = st::mediaSaveButton.height, btnx = width - _buttonWidth, btny = (_height - btnh) / 2; + if (x >= btnx && y >= btny && x < btnx + btnw && y < btny + btnh) { + return data->loader ? _cancell : _savel; + } + width -= btnw + st::mediaSaveDelta; + } + + if (x >= 0 && y >= 0 && x < width && y < _height && !data->loader && data->access) { + return _openl; + } + return TextLinkPtr(); +} + +HistoryMedia *HistoryDocument::clone() const { + HistoryDocument *n = new HistoryDocument(*this); + n->reinit(); + return n; +} + +HistoryContact::HistoryContact(int32 userId, const QString &first, const QString &last, const QString &phone) : userId(userId), phone(App::formatPhone(phone)), contact(App::userLoaded(userId)), w(0) { + _maxw = st::mediaMaxWidth; + name.setText(st::mediaFont, (first + ' ' + last).trimmed(), _textNameOptions); + + _height = st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom(); + phonew = st::mediaFont->m.width(phone); + + if (contact) { + if (contact->phone.isEmpty()) { + contact->setPhone(phone); + } + if (contact->contact < 0) { + contact->contact = 0; + } + contact->photo->load(); + } +} + +void HistoryContact::initDimensions(const HistoryItem *parent, int32 timeWidth) { + int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right(); + int32 fullTimeWidth = timeWidth + st::msgDateSpace + (parent->out() ? st::msgDateCheckSpace + st::msgCheckRect.width() : 0) + st::msgPadding.right() - st::msgDateDelta.x(); + if (name.maxWidth() + tleft + fullTimeWidth > _maxw) { + _maxw = name.maxWidth() + tleft + fullTimeWidth; + } + if (phonew + tleft + st::mediaPadding.right() > _maxw) { + _maxw = phonew + tleft + st::mediaPadding.right(); + } +} + +int32 HistoryContact::resize(int32 nwidth) { + w = nwidth; + return _height; +} + +const QString HistoryContact::inDialogsText() const { + return lang(lng_in_dlg_contact); +} + +bool HistoryContact::hasPoint(int32 x, int32 y) const { + return (x >= 0 && y <= 0 && x < _maxw && y < _height); +} + +TextLinkPtr HistoryContact::getLink(int32 x, int32 y, const HistoryItem *parent) const { + if (x >= 0 && y >= 0 && x < _maxw && y < _height && contact) { + return contact->lnk; + } + return TextLinkPtr(); +} + +HistoryMedia *HistoryContact::clone() const { + QStringList names = name.original(0, 0xFFFF, false).split(QChar(' '), QString::SkipEmptyParts); + if (names.isEmpty()) { + names.push_back(QString()); + } + QString fname = names.front(); + names.pop_front(); + HistoryContact *result = new HistoryContact(userId, fname, names.join(QChar(' ')), phone); + return result; +} + +void HistoryContact::draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const { + int32 width = w; + if (width < 1) return; + + bool out = parent->out(); + if (width >= _maxw) { + width = _maxw; + } + + style::color bg(selected ? (out ? st::msgOutSelectBG : st::msgInSelectBG) : (out ? st::msgOutBG : st::msgInBG)); + p.fillRect(QRect(0, 0, width, _height), bg->b); + + style::color shadow(selected ? (out ? st::msgOutSelectShadow : st::msgInSelectShadow) : (out ? st::msgOutShadow : st::msgInShadow)); + p.fillRect(0, _height, width, st::msgShadow, shadow->b); + + p.drawPixmap(st::mediaPadding.left(), st::mediaPadding.top(), (contact ? contact->photo : userDefPhoto(1))->pix(st::mediaThumbSize)); + + int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right(); + int32 twidth = width - tleft - st::mediaPadding.right(); + int32 fullTimeWidth = timeWidth + st::msgDateSpace + (out ? st::msgDateCheckSpace + st::msgCheckRect.width() : 0) + st::msgPadding.right() - st::msgDateDelta.x(); + int32 secondwidth = width - tleft - fullTimeWidth; + + p.setFont(st::mediaFont->f); + p.setPen(st::black->c); + if (twidth < phonew) { + p.drawText(tleft, st::mediaPadding.top() + 3 + st::mediaFont->ascent, st::mediaFont->m.elidedText(phone, Qt::ElideRight, twidth)); + } else { + p.drawText(tleft, st::mediaPadding.top() + 3 + st::mediaFont->ascent, phone); + } + + style::color status(selected ? (out ? st::mediaOutSelectColor : st::mediaInSelectColor) : (out ? st::mediaOutColor : st::mediaInColor)); + p.setPen(status->p); + + name.drawElided(p, tleft, st::mediaPadding.top() + st::mediaThumbSize - 3 - st::mediaFont->height, secondwidth); + + p.setFont(st::msgDateFont->f); + + style::color date(selected ? (out ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (out ? st::msgOutDateColor : st::msgInDateColor)); + p.setPen(date->p); + + p.drawText(width + st::msgDateDelta.x() - fullTimeWidth + st::msgDateSpace, _height - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, time); + if (out) { + QPoint iconPos(width + 5 - st::msgPadding.right() - st::msgCheckRect.width(), _height + 1 - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgCheckRect.height()); + const QRect *iconRect; + if (parent->id > 0) { + if (parent->unread()) { + iconRect = &(selected ? st::msgSelectCheckRect : st::msgCheckRect); + } else { + iconRect = &(selected ? st::msgSelectDblCheckRect : st::msgDblCheckRect); + } + } else { + iconRect = &st::msgSendingRect; + } + p.drawPixmap(iconPos, App::sprite(), *iconRect); + } +} + +HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, const MTPDmessage &msg) : + HistoryItem(history, block, msg.vid.v, msg.vout.v, msg.vunread.v, ::date(msg.vdate), msg.vfrom_id.v), media(0), _text(st::msgMinWidth), _textWidth(0), _textHeight(0) { + QString text(textClean(qs(msg.vmessage))); + initMedia(msg.vmedia, text); + initDimensions(text); +} + +//HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, const MTPDgeoChatMessage &msg) : +// HistoryItem(history, block, msg.vid.v, (msg.vfrom_id.v == MTP::authedId()), false, ::date(msg.vdate), msg.vfrom_id.v), media(0), message(st::msgMinWidth) { +// QString text(qs(msg.vmessage)); +// initMedia(msg.vmedia, text); +// initDimensions(text); +//} + +//HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime date, int32 from, const QString &msg) : message(st::msgMinWidth), +// HistoryItem(history, block, msgId, out, unread, date, from), media(0), _text(st::msgMinWidth), _textWidth(0), _textHeight(0) { +// initDimensions(textClean(msg)); +//} + +HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime date, int32 from, const QString &msg, const MTPMessageMedia &media) : + HistoryItem(history, block, msgId, out, unread, date, from), media(0), _text(st::msgMinWidth), _textWidth(0), _textHeight(0) { + QString text(msg); + initMedia(media, text); + initDimensions(text); +} + +HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime date, int32 from, const QString &msg, HistoryMedia *fromMedia) : + HistoryItem(history, block, msgId, out, unread, date, from), media(0), _text(st::msgMinWidth), _textWidth(0), _textHeight(0) { + QString text(msg); + if (fromMedia) { + media = fromMedia->clone(); + media->regItem(this); + } + initDimensions(text); +} + +void HistoryMessage::initMedia(const MTPMessageMedia &media, QString ¤tText) { + switch (media.type()) { + case mtpc_messageMediaEmpty: break; + case mtpc_messageMediaContact: { + const MTPDmessageMediaContact &d(media.c_messageMediaContact()); + this->media = new HistoryContact(d.vuser_id.v, qs(d.vfirst_name), qs(d.vlast_name), qs(d.vphone_number)); + } break; + case mtpc_messageMediaGeo: { + const MTPGeoPoint &point(media.c_messageMediaGeo().vgeo); + if (point.type() == mtpc_geoPoint) { + const MTPDgeoPoint &d(point.c_geoPoint()); + QString ll = QString("%1,%2").arg(d.vlat.v).arg(d.vlong.v); + currentText.append(QChar('\n') + textcmdLink(qsl("https://maps.google.com/maps?q=") + ll + qsl("&ll=") + ll + qsl("&z=17"), lang(lng_maps_point))); + } + } break; + case mtpc_messageMediaPhoto: { + const MTPPhoto &photo(media.c_messageMediaPhoto().vphoto); + if (photo.type() == mtpc_photo) { + this->media = new HistoryPhoto(photo.c_photo()); + } + } break; + case mtpc_messageMediaVideo: { + const MTPVideo &video(media.c_messageMediaVideo().vvideo); + if (video.type() == mtpc_video) { + this->media = new HistoryVideo(video.c_video()); + } + } break; + case mtpc_messageMediaAudio: { + const MTPAudio &audio(media.c_messageMediaAudio().vaudio); + if (audio.type() == mtpc_audio) { + this->media = new HistoryAudio(audio.c_audio()); + } + } break; + case mtpc_messageMediaDocument: { + const MTPDocument &document(media.c_messageMediaDocument().vdocument); + if (document.type() == mtpc_document) { + this->media = new HistoryDocument(document.c_document()); + } + } break; + case mtpc_messageMediaUnsupported: + default: currentText += " (unsupported media)"; break; + }; + if (this->media) this->media->regItem(this); +} + +void HistoryMessage::initDimensions(const QString &text) { + time = date.toString(qsl("hh:mm")); + timeWidth = st::msgDateFont->m.width(time); + if (media) { + media->initDimensions(this, timeWidth); + _maxw = media->maxWidth(); + _minh = media->height(); + } else { + timeWidth += st::msgDateSpace + (out() ? st::msgDateCheckSpace + st::msgCheckRect.width() : 0) - st::msgDateDelta.x(); + _text.setText(st::msgFont, text + textcmdSkipBlock(timeWidth, st::msgDateFont->height - st::msgDateDelta.y()), _historyTextOptions); + _maxw = _text.maxWidth(); + _minh = _text.minHeight(); + _maxw += st::msgPadding.left() + st::msgPadding.right(); + } + fromNameUpdated(); +} + +void HistoryMessage::fromNameUpdated() const { + if (media) return; + int32 _namew = ((!_out && _history->peer->chat) ? _from->nameText.maxWidth() : 0) + st::msgPadding.left() + st::msgPadding.right(); + if (_namew > _maxw) _maxw = _namew; +} + +bool HistoryMessage::uploading() const { + return media ? media->uploading() : false; +} + +QString HistoryMessage::selectedText(uint32 selection) const { + if (media && selection == FullItemSel) { + return _text.original(0, 0xFFFF) + '[' + media->inDialogsText() + ']'; + } + uint16 selectedFrom = (selection == FullItemSel) ? 0 : (selection >> 16) & 0xFFFF; + uint16 selectedTo = (selection == FullItemSel) ? 0xFFFF : (selection & 0xFFFF); + return _text.original(selectedFrom, selectedTo); +} + +HistoryMedia *HistoryMessage::getMedia() const { + return media; +} + +void HistoryMessage::draw(QPainter &p, uint32 selection) const { + textstyleSet(&(out() ? st::outTextStyle : st::inTextStyle)); + + bool selected = (selection == FullItemSel); + if (_from->nameVersion > _fromVersion) { + fromNameUpdated(); + _fromVersion = _from->nameVersion; + } + int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right(); + if (width > st::msgMaxWidth) { + if (_out) left += width - st::msgMaxWidth; + width = st::msgMaxWidth; + } + + if (!_out && _history->peer->chat) { + p.drawPixmap(left, _height - st::msgMargin.bottom() - st::msgPhotoSize, _from->photo->pix(st::msgPhotoSize)); +// width -= st::msgPhotoSkip; + left += st::msgPhotoSkip; + } + if (width < 1) return; + + if (width >= _maxw) { + if (_out) left += width - _maxw; + width = _maxw; + } + if (media) { + p.save(); + p.translate(left, st::msgMargin.top()); + media->draw(p, this, time, timeWidth, selected); + p.restore(); + } else { + QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom()); + + style::color bg(selected ? (_out ? st::msgOutSelectBG : st::msgInSelectBG) : (_out ? st::msgOutBG : st::msgInBG)); + p.fillRect(r, bg->b); + + style::color shadow(selected ? (_out ? st::msgOutSelectShadow : st::msgInSelectShadow) : (_out ? st::msgOutShadow : st::msgInShadow)); + p.fillRect(left, _height - st::msgMargin.bottom(), width, st::msgShadow, shadow->b); + + if (!_out && _history->peer->chat) { + p.setFont(st::msgNameFont->f); + p.setPen(_from->color->p); + _from->nameText.drawElided(p, r.left() + st::msgPadding.left(), r.top() + st::msgPadding.top(), width - st::msgPadding.left() - st::msgPadding.right()); + r.setTop(r.top() + st::msgNameFont->height); + } + QRect trect(r.marginsAdded(-st::msgPadding)); + drawMessageText(p, trect, selection); + + p.setFont(st::msgDateFont->f); + + style::color date(selected ? (_out ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (_out ? st::msgOutDateColor : st::msgInDateColor)); + p.setPen(date->p); + + p.drawText(r.right() - st::msgPadding.right() + st::msgDateDelta.x() - timeWidth + st::msgDateSpace, r.bottom() - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, time); + if (_out) { + QPoint iconPos(r.right() + 5 - st::msgPadding.right() - st::msgCheckRect.width(), r.bottom() + 1 - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgCheckRect.height()); + const QRect *iconRect; + if (id > 0) { + if (unread()) { + iconRect = &(selected ? st::msgSelectCheckRect : st::msgCheckRect); + } else { + iconRect = &(selected ? st::msgSelectDblCheckRect : st::msgDblCheckRect); + } + } else { + iconRect = &st::msgSendingRect; + } + p.drawPixmap(iconPos, App::sprite(), *iconRect); + } + } +} + +void HistoryMessage::drawMessageText(QPainter &p, const QRect &trect, uint32 selection) const { + p.setPen(st::msgColor->p); + p.setFont(st::msgFont->f); + uint16 selectedFrom = (selection == FullItemSel) ? 0 : (selection >> 16) & 0xFFFF; + uint16 selectedTo = (selection == FullItemSel) ? 0 : selection & 0xFFFF; + _text.draw(p, trect.x(), trect.y(), trect.width(), Qt::AlignLeft, 0, -1, selectedFrom, selectedTo); + + textstyleRestore(); +} + +int32 HistoryMessage::resize(int32 width) { + width -= st::msgMargin.left() + st::msgMargin.right(); + if (media) { + _height = media->resize(width); + } else { + if (width < st::msgPadding.left() + st::msgPadding.right() + 1) { + width = st::msgPadding.left() + st::msgPadding.right() + 1; + } else if (width > st::msgMaxWidth) { + width = st::msgMaxWidth; + } + int32 nwidth = qMax(width - st::msgPadding.left() - st::msgPadding.right(), 0); + if (nwidth != _textWidth) { + _textWidth = nwidth; + _textHeight = _text.countHeight(nwidth); + } + if (width >= _maxw) { + _height = _minh; + } else { + _height = _textHeight; + } + if (!_out && _history->peer->chat) { + _height += st::msgNameFont->height; + } + _height += st::msgPadding.top() + st::msgPadding.bottom(); + } + _height += st::msgMargin.top() + st::msgMargin.bottom(); + return _height; +} + +bool HistoryMessage::hasPoint(int32 x, int32 y) const { + int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right(); + if (width > st::msgMaxWidth) { + if (_out) left += width - st::msgMaxWidth; + width = st::msgMaxWidth; + } + + if (!_out && _history->peer->chat) { // from user left photo + left += st::msgPhotoSkip; + } + if (width < 1) return false; + + if (width >= _maxw) { + if (_out) left += width - _maxw; + width = _maxw; + } + if (media) { + return media->hasPoint(x - left, y - st::msgMargin.top()); + } + QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom()); + return r.contains(x, y); +} + +void HistoryMessage::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const { + inText = false; + lnk = TextLinkPtr(); + + int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right(); + if (width > st::msgMaxWidth) { + if (_out) left += width - st::msgMaxWidth; + width = st::msgMaxWidth; + } + + if (!_out && _history->peer->chat) { // from user left photo + if (x >= left && x < left + st::msgPhotoSize && y >= _height - st::msgMargin.bottom() - st::msgPhotoSize && y < _height - st::msgMargin.bottom()) { + lnk = _from->lnk; + return; + } +// width -= st::msgPhotoSkip; + left += st::msgPhotoSkip; + } + if (width < 1) return; + + if (width >= _maxw) { + if (_out) left += width - _maxw; + width = _maxw; + } + if (media) { + lnk = media->getLink(x - left, y - st::msgMargin.top(), this); + return; + } + QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom()); + if (!_out && _history->peer->chat) { // from user left name + if (x >= r.left() + st::msgPadding.left() && y >= r.top() + st::msgPadding.top() && y < r.top() + st::msgPadding.top() + st::msgNameFont->height && x < r.right() - st::msgPadding.right() && x < r.left() + st::msgPadding.left() + _from->nameText.maxWidth()) { + lnk = _from->lnk; + return; + } + r.setTop(r.top() + st::msgNameFont->height); + } + QRect trect(r.marginsAdded(-st::msgPadding)); + _text.getState(lnk, inText, x - trect.x(), y - trect.y(), trect.width()); +} + +void HistoryMessage::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { + symbol = 0; + after = false; + upon = false; + + int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right(); + if (width > st::msgMaxWidth) { + if (_out) left += width - st::msgMaxWidth; + width = st::msgMaxWidth; + } + + if (!_out && _history->peer->chat) { // from user left photo +// width -= st::msgPhotoSkip; + left += st::msgPhotoSkip; + } + if (width < 1) return; + + if (width >= _maxw) { + if (_out) left += width - _maxw; + width = _maxw; + } + if (media) { + return; + } + QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom()); + if (!_out && _history->peer->chat) { // from user left name + r.setTop(r.top() + st::msgNameFont->height); + } + QRect trect(r.marginsAdded(-st::msgPadding)); + _text.getSymbol(symbol, after, upon, x - trect.x(), y - trect.y(), trect.width()); +} + +bool HistoryMessage::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right(); + if (width > st::msgMaxWidth) { + if (_out) left += width - st::msgMaxWidth; + width = st::msgMaxWidth; + } + + if (!_out && _history->peer->chat) { +// width -= st::msgPhotoSkip; + left += st::msgPhotoSkip; + } + if (width < 1) return false; + + if (width >= _maxw) { + if (_out) left += width - _maxw; + width = _maxw; + } + if (media) { + if (media->getPhotoCoords(photo, x, y, w)) { + x += left; + y += st::msgMargin.top(); + return true; + } + } + return false; +} + +bool HistoryMessage::getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const { + int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right(); + if (width > st::msgMaxWidth) { + if (_out) left += width - st::msgMaxWidth; + width = st::msgMaxWidth; + } + + if (!_out && _history->peer->chat) { +// width -= st::msgPhotoSkip; + left += st::msgPhotoSkip; + } + if (width < 1) return false; + + if (width >= _maxw) { + if (_out) left += width - _maxw; + width = _maxw; + } + if (media) { + if (media->getVideoCoords(video, x, y, w)) { + x += left; + y += st::msgMargin.top(); + return true; + } + } + return false; +} + +void HistoryMessage::drawInDialog(QPainter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const { + if (cacheFor != this) { + cacheFor = this; + QString msg(media ? media->inDialogsText() : _text.original(0, 0xFFFF, false)); + TextCustomTagsMap custom; + if (_history->peer->chat || out()) { + custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink())); + msg = lang(lng_message_with_from).replace(qsl("{from}"), textRichPrepare((_from == App::self()) ? lang(lng_from_you) : _from->firstName)).replace(qsl("{message}"), textRichPrepare(msg)); + } + cache.setRichText(st::dlgHistFont, msg, _textDlgOptions, custom); + } + if (r.width()) { + textstyleSet(&(act ? st::dlgActiveTextStyle : st::dlgTextStyle)); + p.setFont(st::dlgHistFont->f); + p.setPen((act ? st::dlgActiveColor : (media ? st::dlgSystemColor : st::dlgTextColor))->p); + cache.drawElided(p, r.left(), r.top(), r.width(), r.height() / st::dlgHistFont->height); + } +} + +HistoryMessage::~HistoryMessage() { + if (media) media->unregItem(this); + delete media; +} + +HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, const MTPDmessageForwarded &msg) : + HistoryMessage(history, block, msg.vid.v, msg.vout.v, msg.vunread.v, ::date(msg.vdate), msg.vfrom_id.v, textClean(qs(msg.vmessage)), msg.vmedia), + fwdFrom(App::user(msg.vfwd_from_id.v)), fwdFromVersion(fwdFrom->nameVersion), fwdDate(::date(msg.vfwd_date)), fromWidth(st::msgServiceFont->m.width(lang(lng_forwarded_from))), fwdFromName(4096) { + fwdNameUpdated(); +} + +HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, MsgId id, HistoryMessage *msg) : + HistoryMessage(history, block, id, true, true, ::date(unixtime()), MTP::authedId(), msg->HistoryMessage::selectedText(FullItemSel), msg->getMedia()), + fwdFrom(dynamic_cast(msg) ? dynamic_cast(msg)->fromForwarded() : msg->from()), fwdFromVersion(fwdFrom->nameVersion), + fwdDate(dynamic_cast(msg) ? dynamic_cast(msg)->dateForwarded() : msg->date), + fromWidth(st::msgServiceFont->m.width(lang(lng_forwarded_from))), fwdFromName(4096) { + fwdNameUpdated(); +} + +QString HistoryForwarded::selectedText(uint32 selection) const { + if (selection != FullItemSel) return HistoryMessage::selectedText(selection); + QString result, original = HistoryMessage::selectedText(selection); + result.reserve(lang(lng_forwarded_from).size() + fwdFrom->name.size() + 3 + original.size()); + result.append('[').append(lang(lng_forwarded_from)).append(fwdFrom->name).append(qsl("]\n")).append(original); + return result; +} + +void HistoryForwarded::fwdNameUpdated() const { + if (media) return; + fwdFromName.setText(st::msgServiceNameFont, App::peerName(fwdFrom), _textNameOptions); + int32 _namew = fromWidth + fwdFromName.maxWidth() + st::msgPadding.left() + st::msgPadding.right(); + if (_namew > _maxw) _maxw = _namew; +} + +void HistoryForwarded::draw(QPainter &p, uint32 selection) const { + if (!media && fwdFrom->nameVersion > fwdFromVersion) { + fwdNameUpdated(); + fwdFromVersion = fwdFrom->nameVersion; + } + HistoryMessage::draw(p, selection); +} + +void HistoryForwarded::drawMessageText(QPainter &p, const QRect &trect, uint32 selection) const { + style::font serviceFont(st::msgServiceFont), serviceName(st::msgServiceNameFont); + p.setPen((_out ? st::msgOutServiceColor : st::msgInServiceColor)->p); + p.setFont(serviceFont->f); + + int32 h1 = 0, h2 = serviceName->height, h = h1 + (h1 > h2 ? h1 : h2); + + if (trect.width() >= fromWidth) { + p.drawText(trect.x(), trect.y() + h1 + serviceFont->ascent, lang(lng_forwarded_from)); + + p.setFont(serviceName->f); + fwdFromName.drawElided(p, trect.x() + fromWidth, trect.y() + h1, trect.width() - fromWidth); + } else { + p.drawText(trect.x(), trect.y() + h1 + serviceFont->ascent, serviceFont->m.elidedText(lang(lng_forwarded_from), Qt::ElideRight, trect.width())); + } + + QRect realtrect(trect); + realtrect.setY(trect.y() + h); + HistoryMessage::drawMessageText(p, realtrect, selection); +} + +int32 HistoryForwarded::resize(int32 width) { + HistoryMessage::resize(width); + if (!media) { + int32 h1 = 0, h2 = st::msgServiceNameFont->height; + _height += h1 + (h1 > h2 ? h1 : h2); + } + return _height; +} + +bool HistoryForwarded::hasPoint(int32 x, int32 y) const { + if (!media) { + int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right(); + if (width > st::msgMaxWidth) { + if (_out) left += width - st::msgMaxWidth; + width = st::msgMaxWidth; + } + + if (!_out && _history->peer->chat) { // from user left photo +// width -= st::msgPhotoSkip; + left += st::msgPhotoSkip; + } + if (width < 1) return false; + + if (width >= _maxw) { + if (_out) left += width - _maxw; + width = _maxw; + } + QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom()); + return r.contains(x, y); + } + return HistoryMessage::hasPoint(x, y); +} + +void HistoryForwarded::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const { + lnk = TextLinkPtr(); + inText = false; + + if (!media) { + int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right(); + if (width > st::msgMaxWidth) { + if (_out) left += width - st::msgMaxWidth; + width = st::msgMaxWidth; + } + + if (!_out && _history->peer->chat) { // from user left photo + if (x >= left && x < left + st::msgPhotoSize) { + return HistoryMessage::getState(lnk, inText, x, y); + } +// width -= st::msgPhotoSkip; + left += st::msgPhotoSkip; + } + if (width < 1) return; + + if (width >= _maxw) { + if (_out) left += width - _maxw; + width = _maxw; + } + QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom()); + if (!_out && _history->peer->chat) { + style::font nameFont(st::msgNameFont); + if (y >= r.top() + st::msgPadding.top() && y < r.top() + st::msgPadding.top() + nameFont->height) { + return HistoryMessage::getState(lnk, inText, x, y); + } + r.setTop(r.top() + nameFont->height); + } + QRect trect(r.marginsAdded(-st::msgPadding)); + + int32 h1 = 0, h2 = st::msgServiceNameFont->height; + if (y >= trect.top() + h1 && y < trect.top() + (h1 + h2)) { + if (x >= trect.left() + fromWidth && x < trect.right() && x < trect.left() + fromWidth + fwdFromName.maxWidth()) { + lnk = fwdFrom->lnk; + } + return; + } + y -= h1 + (h1 > h2 ? h1 : h2); + } + return HistoryMessage::getState(lnk, inText, x, y); +} + +void HistoryForwarded::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { + symbol = 0; + after = false; + upon = false; + + if (!media) { + int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right(); + if (width > st::msgMaxWidth) { + if (_out) left += width - st::msgMaxWidth; + width = st::msgMaxWidth; + } + + if (!_out && _history->peer->chat) { // from user left photo +// width -= st::msgPhotoSkip; + left += st::msgPhotoSkip; + } + if (width < 1) return; + + if (width >= _maxw) { + if (_out) left += width - _maxw; + width = _maxw; + } + QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom()); + if (!_out && _history->peer->chat) { + style::font nameFont(st::msgNameFont); + if (y >= r.top() + st::msgPadding.top() && y < r.top() + st::msgPadding.top() + nameFont->height) { + return HistoryMessage::getSymbol(symbol, after, upon, x, y); + } + r.setTop(r.top() + nameFont->height); + } + QRect trect(r.marginsAdded(-st::msgPadding)); + + int32 h1 = 0, h2 = st::msgServiceNameFont->height; + y -= h1 + (h1 > h2 ? h1 : h2); + } + return HistoryMessage::getSymbol(symbol, after, upon, x, y); +} + +QString HistoryServiceMsg::messageByAction(const MTPmessageAction &action, TextLinkPtr &second) { + switch (action.type()) { + case mtpc_messageActionChatAddUser: { + const MTPDmessageActionChatAddUser &d(action.c_messageActionChatAddUser()); + if (App::peerFromUser(d.vuser_id) == _from->id) { + return lang(lng_action_user_joined); + } + UserData *u = App::user(App::peerFromUser(d.vuser_id)); + second = TextLinkPtr(new PeerLink(u)); + return lang(lng_action_add_user).replace(qsl("{user}"), textcmdLink(2, u->name)); + } break; + + case mtpc_messageActionChatCreate: { + const MTPDmessageActionChatCreate &d(action.c_messageActionChatCreate()); + return lang(lng_action_created_chat).replace(qsl("{title}"), textClean(qs(d.vtitle))); + } break; + + case mtpc_messageActionChatDeletePhoto: { + return lang(lng_action_removed_photo); + } break; + + case mtpc_messageActionChatDeleteUser: { + const MTPDmessageActionChatDeleteUser &d(action.c_messageActionChatDeleteUser()); + if (App::peerFromUser(d.vuser_id) == _from->id) { + return lang(lng_action_user_left); + } + UserData *u = App::user(App::peerFromUser(d.vuser_id)); + second = TextLinkPtr(new PeerLink(u)); + return lang(lng_action_kick_user).replace(qsl("{user}"), textcmdLink(2, u->name)); + } break; + + case mtpc_messageActionChatEditPhoto: { + const MTPDmessageActionChatEditPhoto &d(action.c_messageActionChatEditPhoto()); + if (d.vphoto.type() == mtpc_photo) { + media = new HistoryPhoto(d.vphoto.c_photo(), 100); + } + return lang(lng_action_changed_photo); + } break; + + case mtpc_messageActionChatEditTitle: { + const MTPDmessageActionChatEditTitle &d(action.c_messageActionChatEditTitle()); + return lang(lng_action_changed_title).replace(qsl("{title}"), textClean(qs(d.vtitle))); + } break; + + case mtpc_messageActionGeoChatCheckin: { + return lang(lng_action_checked_in); + } break; + + case mtpc_messageActionGeoChatCreate: { + const MTPDmessageActionGeoChatCreate &d(action.c_messageActionGeoChatCreate()); + return lang(lng_action_created_chat).replace(qsl("{title}"), textClean(qs(d.vtitle))); + } break; + } + + return lang(lng_message_empty); +} + +HistoryServiceMsg::HistoryServiceMsg(History *history, HistoryBlock *block, const MTPDmessageService &msg) : + HistoryItem(history, block, msg.vid.v, msg.vout.v, msg.vunread.v, ::date(msg.vdate), msg.vfrom_id.v), media(0), _text(st::msgMinWidth) { + + TextLinkPtr second; + QString text(messageByAction(msg.vaction, second)); + int32 fromPos = text.indexOf(qsl("{from}")); + if (fromPos >= 0) { + text = text.replace(qsl("{from}"), textcmdLink(1, _from->name)); + } + _text.setText(st::msgServiceFont, text, _historySrvOptions); + if (fromPos >= 0) { + _text.setLink(1, TextLinkPtr(new PeerLink(_from))); + } + if (second) { + _text.setLink(2, second); + } + _maxw = _text.maxWidth() + st::msgServicePadding.left() + st::msgServicePadding.right(); + _minh = _text.minHeight(); +} +/* +HistoryServiceMsg::HistoryServiceMsg(History *history, HistoryBlock *block, const MTPDgeoChatMessageService &msg) : + HistoryItem(history, block, msg.vid.v, (msg.vfrom_id.v == MTP::authedId()), false, ::date(msg.vdate), msg.vfrom_id.v), media(0), message(st::msgMinWidth) { + + QString text(messageByAction(msg.vaction)); + text = text.replace(qsl("{from}"), _from->name); + message.setText(st::msgServiceFont, text); + _maxw = message.maxWidth() + st::msgServicePadding.left() + st::msgServicePadding.right(); + _minh = message.minHeight(); +} +/**/ +HistoryServiceMsg::HistoryServiceMsg(History *history, HistoryBlock *block, MsgId msgId, QDateTime date, const QString &msg, bool out, bool unread, HistoryMedia *media) : + HistoryItem(history, block, msgId, out, unread, date, 0), media(media), _text(st::msgServiceFont, msg, _historySrvOptions, st::dlgMinWidth) { + _maxw = _text.maxWidth() + st::msgServicePadding.left() + st::msgServicePadding.right(); + _minh = _text.minHeight(); +} + +QString HistoryServiceMsg::selectedText(uint32 selection) const { + uint16 selectedFrom = (selection == FullItemSel) ? 0 : (selection >> 16) & 0xFFFF; + uint16 selectedTo = (selection == FullItemSel) ? 0xFFFF : (selection & 0xFFFF); + return _text.original(selectedFrom, selectedTo); +} + +void HistoryServiceMsg::draw(QPainter &p, uint32 selection) const { + textstyleSet(&st::serviceTextStyle); + + int32 left = st::msgServiceMargin.left(), width = _history->width - st::msgServiceMargin.left() - st::msgServiceMargin.left(), height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins + if (width < 1) return; + + if (media) { + height -= st::msgServiceMargin.top() + media->height(); + p.save(); + p.translate(st::msgServiceMargin.left() + (width - media->maxWidth()) / 2, st::msgServiceMargin.top() + height + st::msgServiceMargin.top()); + media->draw(p, this, QString(), 0, selection == FullItemSel); + p.restore(); + } + + QRect trect(QRect(left, st::msgServiceMargin.top(), width, height).marginsAdded(-st::msgServicePadding)); + + if (width > _maxw) { + left += (width - _maxw) / 2; + width = _maxw; + } +// QRect r(0, st::msgServiceMargin.top(), _history->width, height); + QRect r(left, st::msgServiceMargin.top(), width, height); + p.setBrush(st::msgServiceBG->b); + p.setPen(Qt::NoPen); +// p.fillRect(r, st::msgServiceBG->b); + p.drawRoundedRect(r, st::msgServiceRadius, st::msgServiceRadius); + if (selection == FullItemSel) { + p.setBrush(st::msgServiceSelectBG->b); + p.drawRoundedRect(r, st::msgServiceRadius, st::msgServiceRadius); + } + p.setBrush(Qt::NoBrush); + p.setPen(st::msgServiceColor->p); + p.setFont(st::msgServiceFont->f); + uint16 selectedFrom = (selection == FullItemSel) ? 0 : (selection >> 16) & 0xFFFF; + uint16 selectedTo = (selection == FullItemSel) ? 0 : selection & 0xFFFF; + _text.draw(p, trect.x(), trect.y(), trect.width(), Qt::AlignCenter, 0, -1, selectedFrom, selectedTo); + textstyleRestore(); +} + +int32 HistoryServiceMsg::resize(int32 width) { + width -= st::msgServiceMargin.left() + st::msgServiceMargin.left(); // two small margins + if (width < st::msgServicePadding.left() + st::msgServicePadding.right() + 1) width = st::msgServicePadding.left() + st::msgServicePadding.right() + 1; + + int32 nwidth = qMax(width - st::msgPadding.left() - st::msgPadding.right(), 0); + if (nwidth != _textWidth) { + _textWidth = nwidth; + _textHeight = _text.countHeight(nwidth); + } + if (width >= _maxw) { + _height = _minh; + } else { + _height = _textHeight; + } + _height += st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom(); + if (media) { + _height += st::msgServiceMargin.top() + media->height(); + } + return _height; +} + +bool HistoryServiceMsg::hasPoint(int32 x, int32 y) const { + int32 left = st::msgServiceMargin.left(), width = _history->width - st::msgServiceMargin.left() - st::msgServiceMargin.left(), height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins + if (width < 1) return false; + + if (media) { + height -= st::msgServiceMargin.top() + media->height(); + } + return QRect(left, st::msgServiceMargin.top(), width, height).contains(x, y); +} + +void HistoryServiceMsg::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const { + lnk = TextLinkPtr(); + inText = false; + + int32 left = st::msgServiceMargin.left(), width = _history->width - st::msgServiceMargin.left() - st::msgServiceMargin.left(), height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins + if (width < 1) return; + + if (media) { + height -= st::msgServiceMargin.top() + media->height(); + } + QRect trect(QRect(left, st::msgServiceMargin.top(), width, height).marginsAdded(-st::msgServicePadding)); + if (trect.contains(x, y)) { + return _text.getState(lnk, inText, x - trect.x(), y - trect.y(), trect.width(), Qt::AlignCenter); + } + if (media) { + lnk = media->getLink(x - st::msgServiceMargin.left() - (width - media->maxWidth()) / 2, y - st::msgServiceMargin.top() - height - st::msgServiceMargin.top(), this); + } +} + +void HistoryServiceMsg::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { + symbol = 0; + after = false; + upon = false; + + int32 left = st::msgServiceMargin.left(), width = _history->width - st::msgServiceMargin.left() - st::msgServiceMargin.left(), height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins + if (width < 1) return; + + if (media) { + height -= st::msgServiceMargin.top() + media->height(); + } + QRect trect(QRect(left, st::msgServiceMargin.top(), width, height).marginsAdded(-st::msgServicePadding)); + return _text.getSymbol(symbol, after, upon, x - trect.x(), y - trect.y(), trect.width(), Qt::AlignCenter); +} + +bool HistoryServiceMsg::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + int32 left = st::msgServiceMargin.left(), width = _history->width - st::msgServiceMargin.left() - st::msgServiceMargin.left(), height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins + if (width < 1) return false; + + if (media) { + height -= st::msgServiceMargin.top() + media->height(); + } + if (media) { + if (media->getPhotoCoords(photo, x, y, w)) { + x += st::msgServiceMargin.left() + (width - media->maxWidth()) / 2; + y += st::msgServiceMargin.top() + height + st::msgServicePadding.top(); + return true; + } + } + return false; +} + +void HistoryServiceMsg::drawInDialog(QPainter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const { + if (cacheFor != this) { + cacheFor = this; + cache.setText(st::dlgHistFont, _text.original(0, 0xFFFF), _textDlgOptions); + } + QRect tr(r); + p.setPen((act ? st::dlgActiveColor : st::dlgSystemColor)->p); + cache.drawElided(p, tr.left(), tr.top(), tr.width(), tr.height() / st::dlgHistFont->height); +} + +HistoryServiceMsg::~HistoryServiceMsg() { + delete media; +} + +HistoryDateMsg::HistoryDateMsg(History *history, HistoryBlock *block, const QDate &date) : HistoryServiceMsg(history, block, clientMsgId(), QDateTime(date), langDayOfMonth(date)) { +} + +HistoryItem *createDayServiceMsg(History *history, HistoryBlock *block, QDateTime date) { + return regItem(new HistoryDateMsg(history, block, date.date())); +} + +HistoryUnreadBar::HistoryUnreadBar(History *history, HistoryBlock *block, int32 count, const QDateTime &date) : HistoryItem(history, block, clientMsgId(), false, false, date, 0), freezed(false) { + setCount(count); + _maxw = st::msgPadding.left() + st::msgPadding.right() + 1; + _minh = st::unreadBarHeight; +} + +void HistoryUnreadBar::setCount(int32 count) { + if (!count) freezed = true; + if (freezed) return; + text = lang(lng_unread_bar).arg(count); +} + +void HistoryUnreadBar::draw(QPainter &p, uint32 selection) const { + p.fillRect(0, 1, _history->width, st::unreadBarHeight - 2, st::unreadBarBG->b); + p.setPen(st::unreadBarBorder->p); + p.drawLine(0, st::unreadBarHeight - 1, _history->width, st::unreadBarHeight - 1); + p.setFont(st::unreadBarFont->f); + p.setPen(st::unreadBarColor->p); + p.drawText(QRect(0, 0, _history->width, st::unreadBarHeight - 1), text, style::al_center); +} + +int32 HistoryUnreadBar::resize(int32 width) { + _height = st::unreadBarHeight; + return _height; +} + +void HistoryUnreadBar::drawInDialog(QPainter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const { +} diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h new file mode 100644 index 000000000..1286c84ae --- /dev/null +++ b/Telegram/SourceFiles/history.h @@ -0,0 +1,1416 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +typedef uint64 PeerId; +typedef uint64 PhotoId; +typedef uint64 VideoId; +typedef uint64 AudioId; +typedef uint64 DocumentId; +typedef int32 MsgId; + +void historyInit(); + +class HistoryItem; +static const uint32 FullItemSel = 0xFFFFFFFF; + +extern TextParseOptions _textNameOptions; + +struct NotifySettings { + NotifySettings() : mute(0), sound("default"), previews(true), events(1) { + } + int32 mute; + string sound; + bool previews; + int32 events; +}; +typedef NotifySettings *NotifySettingsPtr; + +static const NotifySettingsPtr UnknownNotifySettings = NotifySettingsPtr(0); +static const NotifySettingsPtr EmptyNotifySettings = NotifySettingsPtr(1); +extern NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats; +extern NotifySettingsPtr globalNotifyAllPtr, globalNotifyUsersPtr, globalNotifyChatsPtr; + +inline bool isNotifyMuted(NotifySettingsPtr settings) { + if (settings == UnknownNotifySettings || settings == EmptyNotifySettings) { + return false; + } + return (settings->mute > unixtime()); +} + +struct ChatData; +struct UserData; +struct PeerData { + PeerData(const PeerId &id); + ~PeerData() { + if (notify != UnknownNotifySettings && notify != EmptyNotifySettings) { + delete notify; + notify = UnknownNotifySettings; + } + } + + UserData *asUser(); + const UserData *asUser() const; + + ChatData *asChat(); + const ChatData *asChat() const; + + void updateName(const QString &newName, const QString &newNameOrPhone); + + void fillNames() { + names.clear(); + chars.clear(); + QString toIndex = textAccentFold(name); + if (nameOrPhone != name) { + toIndex += qsl(" ") + textAccentFold(nameOrPhone); + } + if (cRussianLetters().match(toIndex).hasMatch()) { + toIndex += qsl(" ") + translitRusEng(toIndex); + } + toIndex += qsl(" ") + rusKeyboardLayoutSwitch(toIndex); + + if (name.midRef(0, 8) == "Telegram") { + int a = 0; + } + + QStringList namesList = toIndex.toLower().split(cWordSplit(), QString::SkipEmptyParts); + for (QStringList::const_iterator i = namesList.cbegin(), e = namesList.cend(); i != e; ++i) { + names.insert(*i); + chars.insert(i->at(0)); + } + } + + virtual void nameUpdated() { + } + + PeerId id; + + QString name; + QString nameOrPhone; + typedef QSet Names; + Names names; // for filtering + typedef QSet NameFirstChars; + NameFirstChars chars; + + bool loaded; + bool chat; + uint64 access; + MTPinputPeer input; + MTPinputUser inputUser; + + int32 colorIndex; + style::color color; + ImagePtr photo; + + int32 nameVersion; + + NotifySettingsPtr notify; +}; + +class PeerLink : public ITextLink { +public: + PeerLink(const PeerData *peer) : _peer(peer) { + } + void onClick(Qt::MouseButton button) const; + const PeerData *peer() const { + return _peer; + } + +private: + const PeerData *_peer; +}; + +struct UserData : public PeerData { + UserData(const PeerId &id) : PeerData(id), lnk(new PeerLink(this)), onlineTill(0), contact(-1) { + } + void setPhoto(const MTPUserProfilePhoto &photo); + void setName(const QString &first, const QString &last, const QString &phoneName); + void setPhone(const QString &newPhone); + void nameUpdated(); + + QString firstName; + QString lastName; + QString phone; + Text nameText; + PhotoId photoId; + TextLinkPtr lnk; + int32 onlineTill; + int32 contact; // -1 - not contact, cant add (self, empty, deleted, foreign), 0 - not contact, can add (request), 1 - contact +}; + +struct ChatData : public PeerData { + ChatData(const PeerId &id) : PeerData(id), count(0), date(0), version(0), left(false), forbidden(true), photoId(0) { + } + void setPhoto(const MTPChatPhoto &photo, const PhotoId &phId = 0); + int32 count; + int32 date; + int32 version; + int32 admin; + bool left; + bool forbidden; + typedef QMap Participants; + Participants participants; + typedef QMap CanKick; + CanKick cankick; + ImagePtr photoFull; + PhotoId photoId; + // geo +}; + +typedef QMap PreparedPhotoThumbs; +struct PhotoData { + PhotoData(const PhotoId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, const ImagePtr &thumb = ImagePtr(), const ImagePtr &full = ImagePtr()) : + id(id), access(access), user(user), date(date), thumb(thumb), full(full), chat(0) { + } + void forget() { + thumb->forget(); + full->forget(); + } + PhotoId id; + uint64 access; + int32 user; + int32 date; + ImagePtr thumb; + ImagePtr full; + ChatData *chat; // for chat photos connection + // geo, caption +}; + +class PhotoLink : public ITextLink { +public: + PhotoLink(PhotoData *photo) : _photo(photo) { + } + void onClick(Qt::MouseButton button) const; + PhotoData *photo() const { + return _photo; + } + +private: + PhotoData *_photo; +}; + +enum FileStatus { + FileFailed = -1, + FileUploading = 0, + FileReady = 1, +}; + +struct VideoData { + VideoData(const VideoId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 w = 0, int32 h = 0, const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0) : + id(id), access(access), user(user), date(date), duration(duration), w(w), h(h), thumb(thumb), dc(dc), size(size), openOnSave(0), loader(0), fileType(0), status(FileReady), uploadOffset(0) { + memset(md5, 0, sizeof(md5)); + } + void forget() { + thumb->forget(); + } + + void save(const QString &toFile); + + void cancel(bool beforeDownload = false) { + mtpFileLoader *l = loader; + loader = 0; + if (l) { + l->cancel(); + l->deleteLater(); + } + fileName = QString(); + modDate = QDateTime(); + if (!beforeDownload) { + openOnSave = 0; + } + } + + void finish() { + if (loader->done()) { + fileName = loader->fileName(); + modDate = fileName.isEmpty() ? QDateTime() : QFileInfo(fileName).lastModified(); + } + loader->deleteLater(); + loader = 0; + } + + QString already(bool check = false) { + if (!check) return fileName; + + QString res = modDate.isNull() ? QString() : fileName; + if (!res.isEmpty()) { + QFileInfo f(res); + if (f.exists() && f.lastModified() <= modDate) { + return res; + } + } + return QString(); + } + + VideoId id; + uint64 access; + int32 user; + int32 date; + int32 duration; + int32 w, h; + ImagePtr thumb; + int32 dc, size; + // geo, caption + + FileStatus status; + int32 uploadOffset; + + mtpTypeId fileType; + int32 openOnSave; + mtpFileLoader *loader; + QString fileName; + QDateTime modDate; + int32 md5[8]; +}; + +class VideoLink : public ITextLink { +public: + VideoLink(VideoData *video) : _video(video) { + } + VideoData *video() const { + return _video; + } + +private: + VideoData *_video; +}; + +class VideoSaveLink : public VideoLink { +public: + VideoSaveLink(VideoData *video) : VideoLink(video) { + } + void doSave(bool forceSavingAs = false) const; + void onClick(Qt::MouseButton button) const; +}; + +class VideoOpenLink : public VideoLink { +public: + VideoOpenLink(VideoData *video) : VideoLink(video) { + } + void onClick(Qt::MouseButton button) const; +}; + +class VideoCancelLink : public VideoLink { +public: + VideoCancelLink(VideoData *video) : VideoLink(video) { + } + void onClick(Qt::MouseButton button) const; +}; + +struct AudioData { + AudioData(const AudioId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 dc = 0, int32 size = 0) : + id(id), access(access), user(user), date(date), dc(dc), duration(duration), size(size), openOnSave(0), loader(0), status(FileReady), uploadOffset(0) { + memset(md5, 0, sizeof(md5)); + } + void forget() { + } + + void save(const QString &toFile); + + void cancel(bool beforeDownload = false) { + mtpFileLoader *l = loader; + loader = 0; + if (l) { + l->cancel(); + l->deleteLater(); + } + fileName = QString(); + modDate = QDateTime(); + if (!beforeDownload) { + openOnSave = 0; + } + } + + void finish() { + if (loader->done()) { + fileName = loader->fileName(); + modDate = fileName.isEmpty() ? QDateTime() : QFileInfo(fileName).lastModified(); + } + loader->deleteLater(); + loader = 0; + } + + QString already(bool check = false) { + if (!check) return fileName; + + QString res = modDate.isNull() ? QString() : fileName; + if (!res.isEmpty()) { + QFileInfo f(res); + if (f.exists() && f.lastModified() <= modDate) { + return res; + } + } + return QString(); + } + + AudioId id; + uint64 access; + int32 user; + int32 date; + int32 duration; + int32 dc; + int32 size; + + FileStatus status; + int32 uploadOffset; + + int32 openOnSave; + mtpFileLoader *loader; + QString fileName; + QDateTime modDate; + int32 md5[8]; +}; + +class AudioLink : public ITextLink { +public: + AudioLink(AudioData *audio) : _audio(audio) { + } + AudioData *audio() const { + return _audio; + } + +private: + AudioData *_audio; +}; + +class AudioSaveLink : public AudioLink { +public: + AudioSaveLink(AudioData *audio) : AudioLink(audio) { + } + void doSave(bool forceSavingAs = false) const; + void onClick(Qt::MouseButton button) const; +}; + +class AudioOpenLink : public AudioLink { +public: + AudioOpenLink(AudioData *audio) : AudioLink(audio) { + } + void onClick(Qt::MouseButton button) const; +}; + +class AudioCancelLink : public AudioLink { +public: + AudioCancelLink(AudioData *audio) : AudioLink(audio) { + } + void onClick(Qt::MouseButton button) const; +}; + +struct DocumentData { + DocumentData(const DocumentId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, const QString &name = QString(), const QString &mime = QString(), const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0) : + id(id), access(access), user(user), date(date), name(name), mime(mime), thumb(thumb), dc(dc), size(size), openOnSave(0), loader(0), status(FileReady), uploadOffset(0) { + memset(md5, 0, sizeof(md5)); + } + void forget() { + thumb->forget(); + } + + void save(const QString &toFile); + + void cancel(bool beforeDownload = false) { + mtpFileLoader *l = loader; + loader = 0; + if (l) { + l->cancel(); + l->deleteLater(); + } + fileName = QString(); + modDate = QDateTime(); + if (!beforeDownload) { + openOnSave = 0; + } + } + + void finish() { + if (loader->done()) { + fileName = loader->fileName(); + modDate = fileName.isEmpty() ? QDateTime() : QFileInfo(fileName).lastModified(); + } + loader->deleteLater(); + loader = 0; + } + + QString already(bool check = false) { + if (!check) return fileName; + + QString res = modDate.isNull() ? QString() : fileName; + if (!res.isEmpty()) { + QFileInfo f(res); + if (f.exists() && f.lastModified() <= modDate) { + return res; + } + } + return QString(); + } + + DocumentId id; + uint64 access; + int32 user; + int32 date; + QString name, mime; + ImagePtr thumb; + int32 dc; + int32 size; + + FileStatus status; + int32 uploadOffset; + + int32 openOnSave; + mtpFileLoader *loader; + QString fileName; + QDateTime modDate; + int32 md5[8]; +}; + +class DocumentLink : public ITextLink { +public: + DocumentLink(DocumentData *document) : _document(document) { + } + DocumentData *document() const { + return _document; + } + +private: + DocumentData *_document; +}; + +class DocumentSaveLink : public DocumentLink { +public: + DocumentSaveLink(DocumentData *document) : DocumentLink(document) { + } + void doSave(bool forceSavingAs = false) const; + void onClick(Qt::MouseButton button) const; +}; + +class DocumentOpenLink : public DocumentLink { +public: + DocumentOpenLink(DocumentData *document) : DocumentLink(document) { + } + void onClick(Qt::MouseButton button) const; +}; + +class DocumentCancelLink : public DocumentLink { +public: + DocumentCancelLink(DocumentData *document) : DocumentLink(document) { + } + void onClick(Qt::MouseButton button) const; +}; + +MsgId clientMsgId(); + +struct History; +struct Histories : public QHash { + typedef QHash Parent; + + Histories() : unreadFull(0), unreadMuted(0) { + } + + void clear(); + Parent::iterator erase(Parent::iterator i); + ~Histories() { + clear(); + + unreadFull = unreadMuted = 0; + } + + PeerId addToBack(const MTPmessage &msg, bool newMsg = true); +// PeerId addToBack(const MTPgeoChatMessage &msg, bool newMsg = true); + + typedef QMap TypingHistories; // when typing in this history started + TypingHistories typing; + + int32 unreadFull, unreadMuted; +}; + +struct HistoryBlock; +class HistoryItem; + +struct DialogRow { + DialogRow(History *history = 0, DialogRow *prev = 0, DialogRow *next = 0, int32 pos = 0) : prev(prev), next(next), history(history), pos(pos), attached(0) { + } + + void paint(QPainter &p, int32 w, bool act, bool sel) const; + + DialogRow *prev, *next; + History *history; + int32 pos; + void *attached; // for any attached data, for example View in contacts list +}; + +class HistoryMedia; +class HistoryMessage; +class HistoryUnreadBar; +struct History : public QList { + History(const PeerId &peerId); + + typedef QList Parent; + void clear(); + Parent::iterator erase(Parent::iterator i); + void blockResized(HistoryBlock *block, int32 dh); + void removeBlock(HistoryBlock *block); + + ~History() { + clear(); + } + + HistoryItem *createItem(HistoryBlock *block, const MTPmessage &msg, bool newMsg); + HistoryItem *createItemForwarded(HistoryBlock *block, MsgId id, HistoryMessage *msg); +// HistoryItem *createItem(HistoryBlock *block, const MTPgeoChatMessage &msg, bool newMsg); + void addToBackService(MsgId msgId, QDateTime date, const QString &text, bool out = false, bool unread = false, HistoryMedia *media = 0, bool newMsg = true); + void addToBack(const MTPmessage &msg, bool newMsg = true); + void addToBackForwarded(MsgId id, HistoryMessage *item); +// void addToBack(const MTPgeoChatMessage &msg, bool newMsg = true); + void addToFront(const QVector &slice); + void createInitialDateBlock(const QDateTime &date); + void doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *adding, bool newMsg); + void inboxRead(bool byThisInstance = false); + void outboxRead(); + + void setUnreadCount(int32 newUnreadCount, bool psUpdate = true); + void setMsgCount(int32 newMsgCount); + void setMute(bool newMute); + void getNextShowFrom(HistoryBlock *block, int32 i); + void addUnreadBar(); + void getNextNotifyFrom(HistoryBlock *block = 0, int32 i = 0); + void clearNotifyFrom(); + + int32 geomResize(int32 newWidth, int32 *ytransform = 0); // return new size + int32 width, height, msgCount, offset, unreadCount; + int32 inboxReadTill, outboxReadTill; + HistoryItem *showFrom; + HistoryItem *notifyFrom; + HistoryUnreadBar *unreadBar; + bool unreadLoaded; + + PeerData *peer; + + QString draft; + QTextCursor draftCur; + int32 lastWidth, lastScrollTop; + bool mute; + + // for dialog drawing + Text nameText; + void updateNameText(); + + mutable const HistoryItem *textCachedFor; // cache + mutable Text lastItemTextCache; + + void paintDialog(QPainter &p, int32 w, bool sel) const; + + typedef QMap DialogLinks; + DialogLinks dialogs; + int32 posInDialogs; + + typedef QMap TypingUsers; + TypingUsers typing; + QString typingStr; + Text typingText; + uint32 typingFrame; + bool updateTyping(uint64 ms = 0, uint32 dots = 0, bool force = false); + uint64 myTyping; + + static const int32 ScrollMax = INT_MAX; +}; + +struct DialogsList { + DialogsList(bool sortByName) : end(&last), begin(&last), current(&last), byName(sortByName), count(0) { + } + + void adjustCurrent(int32 y, int32 h) const { + int32 pos = (y > 0) ? (y / h) : 0; + while (current->pos > pos && current != begin) { + current = current->prev; + } + while (current->pos + 1 <= pos && current->next != end) { + current = current->next; + } + } + + void paint(QPainter &p, int32 w, int32 hFrom, int32 hTo, PeerData *act, PeerData *sel) const { + adjustCurrent(hFrom, st::dlgHeight); + + DialogRow *drawFrom = current; + p.translate(0, drawFrom->pos * st::dlgHeight); + while (drawFrom != end && drawFrom->pos * st::dlgHeight < hTo) { + drawFrom->paint(p, w, (drawFrom->history->peer == act), (drawFrom->history->peer == sel)); + drawFrom = drawFrom->next; + p.translate(0, st::dlgHeight); + } + } + + DialogRow *rowAtY(int32 y, int32 h) const { + if (!count) return 0; + + int32 pos = (y > 0) ? (y / h) : 0; + adjustCurrent(y, h); + return (pos == current->pos) ? current : 0; + } + + DialogRow *addToEnd(History *history, bool updatePos = true) { + DialogRow *result = new DialogRow(history, end->prev, end, end->pos); + end->pos++; + if (begin == end) { + begin = current = result; + if (!byName && updatePos) history->posInDialogs = 0; + } else { + end->prev->next = result; + if (!byName && updatePos) history->posInDialogs = end->prev->history->posInDialogs + 1; + } + rowByPeer.insert(history->peer->id, result); + ++count; + return (end->prev = result); + } + + void bringToTop(DialogRow *row, bool updatePos = true) { + if (!byName && updatePos && row != begin) { + row->history->posInDialogs = begin->history->posInDialogs - 1; + } + insertBefore(row, begin); + } + + bool insertBefore(DialogRow *row, DialogRow *before) { + if (row == before) return false; + + if (current == row) current = row->prev; + + DialogRow *updateTill = row->prev; + remove(row); + + // insert row + row->next = before; // update row + row->prev = before->prev; + row->next->prev = row; // update row->next + if (row->prev) { // update row->prev + row->prev->next = row; + } else { + begin = row; + } + + // update y + for (DialogRow *n = row; n != updateTill; n = n->next) { + n->next->pos++; + row->pos--; + } + return true; + } + + bool insertAfter(DialogRow *row, DialogRow *after) { + if (row == after) return false; + + if (current == row) current = row->next; + + DialogRow *updateFrom = row->next; + remove(row); + + // insert row + row->prev = after; // update row + row->next = after->next; + row->prev->next = row; // update row->prev + row->next->prev = row; // update row->next + + // update y + for (DialogRow *n = updateFrom; n != row; n = n->next) { + n->pos--; + row->pos++; + } + return true; + } + + DialogRow *adjustByName(const PeerData *peer) { + if (!byName) return 0; + + RowByPeer::iterator i = rowByPeer.find(peer->id); + if (i == rowByPeer.cend()) return 0; + + DialogRow *row = i.value(), *change = row; + while (change->prev && change->prev->history->peer->name > peer->name) { + change = change->prev; + } + if (!insertBefore(row, change)) { + while (change->next != end && change->next->history->peer->name < peer->name) { + change = change->next; + } + insertAfter(row, change); + } + return row; + } + + DialogRow *addByName(History *history) { + if (!byName) return 0; + + DialogRow *row = addToEnd(history), *change = row; + const QString &peerName(history->peer->name); + while (change->prev && change->prev->history->peer->name > peerName) { + change = change->prev; + } + if (!insertBefore(row, change)) { + while (change->next != end && change->next->history->peer->name < peerName) { + change = change->next; + } + insertAfter(row, change); + } + return row; + } + + void adjustByPos(DialogRow *row) { + if (byName) return; + + DialogRow *change = row; + while (change->prev && change->prev->history->posInDialogs > row->history->posInDialogs) { + change = change->prev; + } + if (!insertBefore(row, change)) { + while (change->next != end && change->next->history->posInDialogs < row->history->posInDialogs) { + change = change->next; + } + insertAfter(row, change); + } + } + + DialogRow *addByPos(History *history) { + if (byName) return 0; + + DialogRow *row = addToEnd(history, false); + adjustByPos(row); + return row; + } + + bool del(const PeerId &peerId, DialogRow *replacedBy = 0); + + void remove(DialogRow *row) { + row->next->prev = row->prev; // update row->next + if (row->prev) { // update row->prev + row->prev->next = row->next; + } else { + begin = row->next; + } + } + + void clear() { + while (begin != end) { + current = begin; + begin = begin->next; + delete current; + } + current = begin; + rowByPeer.clear(); + count = 0; + } + + ~DialogsList() { + clear(); + } + + DialogRow last; + DialogRow *begin, *end; + bool byName; + int32 count; + + typedef QHash RowByPeer; + RowByPeer rowByPeer; + + mutable DialogRow *current; // cache +}; + +struct DialogsIndexed { + DialogsIndexed(bool sortByName) : byName(sortByName), list(byName) { + } + + History::DialogLinks addToEnd(History *history) { + History::DialogLinks result; + DialogsList::RowByPeer::const_iterator i = list.rowByPeer.find(history->peer->id); + if (i != list.rowByPeer.cend()) { + return i.value()->history->dialogs; + } + + result.insert(0, list.addToEnd(history)); + for (PeerData::NameFirstChars::const_iterator i = history->peer->chars.cbegin(), e = history->peer->chars.cend(); i != e; ++i) { + DialogsIndex::iterator j = index.find(*i); + if (j == index.cend()) { + j = index.insert(*i, new DialogsList(byName)); + } + result.insert(*i, j.value()->addToEnd(history)); + } + + return result; + } + + DialogRow *addByName(History *history) { + DialogsList::RowByPeer::const_iterator i = list.rowByPeer.constFind(history->peer->id); + if (i != list.rowByPeer.cend()) { + return i.value(); + } + + DialogRow *res = list.addByName(history); + for (PeerData::NameFirstChars::const_iterator i = history->peer->chars.cbegin(), e = history->peer->chars.cend(); i != e; ++i) { + DialogsIndex::iterator j = index.find(*i); + if (j == index.cend()) { + j = index.insert(*i, new DialogsList(byName)); + } + j.value()->addByName(history); + } + return res; + } + + void bringToTop(const History::DialogLinks &links) { + for (History::DialogLinks::const_iterator i = links.cbegin(), e = links.cend(); i != e; ++i) { + if (i.key() == QChar(0)) { + list.bringToTop(i.value()); + } else { + DialogsIndex::iterator j = index.find(i.key()); + if (j != index.cend()) { + j.value()->bringToTop(i.value()); + } + } + } + } + + void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars); + + void del(const PeerData *peer, DialogRow *replacedBy = 0) { + if (list.del(peer->id, replacedBy)) { + for (PeerData::NameFirstChars::const_iterator i = peer->chars.cbegin(), e = peer->chars.cend(); i != e; ++i) { + DialogsIndex::iterator j = index.find(*i); + if (j != index.cend()) { + j.value()->del(peer->id, replacedBy); + } + } + } + } + + ~DialogsIndexed() { + clear(); + } + + void clear(); + + bool byName; + DialogsList list; + typedef QMap DialogsIndex; + DialogsIndex index; +}; + +class HistoryItem; +struct HistoryBlock : public QVector { + HistoryBlock(History *hist) : y(0), height(0), history(hist) { + } + + typedef QVector Parent; + void clear(); + Parent::iterator erase(Parent::iterator i); + ~HistoryBlock() { + clear(); + } + void removeItem(HistoryItem *item); + + int32 geomResize(int32 newWidth, int32 *ytransform); // return new size + int32 y, height; + History *history; +}; + +class HistoryElem { +public: + + HistoryElem() : _height(0), _maxw(0) { + } + + virtual int32 resize(int32 width) = 0; // return new height + + int32 height() const { + return _height; + } + int32 maxWidth() const { + return _maxw; + } + + virtual ~HistoryElem() { + } + +protected: + + mutable int32 _height, _maxw, _minh; + +}; + +class HistoryItem : public HistoryElem { +public: + + HistoryItem(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime msgDate, int32 from); + + enum { + MsgType = 0, + DateType, + UnreadBarType + }; + + virtual void draw(QPainter &p, uint32 selection) const = 0; + History *history() { + return _history; + } + const History *history() const { + return _history; + } + UserData *from() { + return _from; + } + const UserData *from() const { + return _from; + } + HistoryBlock *block() { + return _block; + } + const HistoryBlock *block() const { + return _block; + } + void destroy() { + markRead(); + _block->removeItem(this); + } + bool out() const { + return _out; + } + bool unread() const { + if (_out && (id > 0 && id < _history->outboxReadTill) || !_out && id > 0 && id < _history->inboxReadTill) return false; + return _unread; + } + virtual bool needCheck() const { + return true; + } + virtual bool hasPoint(int32 x, int32 y) const { + return false; + } + virtual void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const { + lnk = TextLinkPtr(); + inText = false; + } + virtual void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { // from text + upon = hasPoint(x, y); + symbol = upon ? 0xFFFF : 0; + after = false; + } + virtual uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const { + return (from << 16) | to; + } + virtual bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + return false; + } + virtual bool getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const { + return false; + } + virtual int32 itemType() const { + return MsgType; + } + virtual bool serviceMsg() const { + return false; + } + virtual void updateMedia(const MTPMessageMedia &media) { + } + + virtual QString selectedText(uint32 selection) const { + return qsl("[-]"); + } + + virtual void drawInDialog(QPainter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const = 0; + void markRead(); + + int32 y, id; + QDateTime date; + + virtual ~HistoryItem(); + +protected: + + UserData *_from; + mutable int32 _fromVersion; + History *_history; + HistoryBlock *_block; + bool _out, _unread; + +}; + +HistoryItem *regItem(HistoryItem *item); + +enum HistoryMediaType { + MediaTypePhoto, + MediaTypeVideo, + MediaTypeGeo, + MediaTypeContact, + MediaTypeAudio, + MediaTypeDocument, +}; + +class HistoryMedia : public HistoryElem { +public: + + virtual void initDimensions(const HistoryItem *parent, int32 timeWidth) { + } + + virtual HistoryMediaType type() const = 0; + virtual const QString inDialogsText() const = 0; + virtual bool hasPoint(int32 x, int32 y) const = 0; + virtual TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent) const = 0; + virtual void draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const = 0; + virtual bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + return false; + } + virtual bool getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const { + return false; + } + virtual bool uploading() const { + return false; + } + virtual HistoryMedia *clone() const = 0; + + virtual void regItem(HistoryItem *item) { + } + + virtual void unregItem(HistoryItem *item) { + } + + virtual void updateFrom(const MTPMessageMedia &media) { + } + +}; + +class HistoryPhoto : public HistoryMedia { +public: + + HistoryPhoto(const MTPDphoto &photo, int32 width = 0); + + void draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const; + int32 resize(int32 width); + HistoryMediaType type() const { + return MediaTypePhoto; + } + const QString inDialogsText() const; + bool hasPoint(int32 x, int32 y) const; + TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent) const; + bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const; + HistoryMedia *clone() const; + +private: + PhotoData *data; + TextLinkPtr openl; + int32 w; +}; + +class HistoryVideo : public HistoryMedia { +public: + + HistoryVideo(const MTPDvideo &video, int32 width = 0); + void reinit(); + void initDimensions(const HistoryItem *parent, int32 timeWidth); + + void draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const; + int32 resize(int32 width); + HistoryMediaType type() const { + return MediaTypeVideo; + } + const QString inDialogsText() const; + bool hasPoint(int32 x, int32 y) const; + TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent) const; + bool getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const; + bool uploading() const { + return (data->status == FileUploading); + } + HistoryMedia *clone() const; + + void regItem(HistoryItem *item); + void unregItem(HistoryItem *item); + +private: + VideoData *data; + TextLinkPtr _openl, _savel, _cancell; + int32 w; + + QString _size; + int32 _thumbw, _thumbx, _thumby; + + mutable QString _dldTextCache, _uplTextCache; + mutable int32 _dldDone, _uplDone; +}; + +class HistoryAudio : public HistoryMedia { +public: + + HistoryAudio(const MTPDaudio &audio, int32 width = 0); + void reinit(); + void initDimensions(const HistoryItem *parent, int32 timeWidth); + + void draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const; + int32 resize(int32 width); + HistoryMediaType type() const { + return MediaTypeAudio; + } + const QString inDialogsText() const; + bool hasPoint(int32 x, int32 y) const; + TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent) const; + bool uploading() const { + return (data->status == FileUploading); + } + HistoryMedia *clone() const; + + void regItem(HistoryItem *item); + void unregItem(HistoryItem *item); + +private: + AudioData *data; + TextLinkPtr _openl, _savel, _cancell; + int32 w; + + QString _size; + + mutable QString _dldTextCache, _uplTextCache; + mutable int32 _dldDone, _uplDone; +}; + +class HistoryDocument : public HistoryMedia { +public: + + HistoryDocument(const MTPDdocument &document, int32 width = 0); + void reinit(); + void initDimensions(const HistoryItem *parent, int32 timeWidth); + + void draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const; + int32 resize(int32 width); + HistoryMediaType type() const { + return MediaTypeDocument; + } + const QString inDialogsText() const; + bool hasPoint(int32 x, int32 y) const; + bool uploading() const { + return (data->status == FileUploading); + } + TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent) const; + HistoryMedia *clone() const; + + DocumentData *document() { + return data; + } + + void regItem(HistoryItem *item); + void unregItem(HistoryItem *item); + + void updateFrom(const MTPMessageMedia &media); + +private: + + DocumentData *data; + TextLinkPtr _openl, _savel, _cancell; + int32 w; + + int32 _namew; + QString _name, _size; + int32 _thumbw, _thumbx, _thumby; + + mutable QString _dldTextCache, _uplTextCache; + mutable int32 _dldDone, _uplDone; +}; + +class HistoryContact : public HistoryMedia { +public: + + HistoryContact(int32 userId, const QString &first, const QString &last, const QString &phone); + void initDimensions(const HistoryItem *parent, int32 timeWidth); + + void draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const; + int32 resize(int32 width); + HistoryMediaType type() const { + return MediaTypeContact; + } + const QString inDialogsText() const; + bool hasPoint(int32 x, int32 y) const; + TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent) const; + HistoryMedia *clone() const; + +private: + int32 userId; + int32 w, phonew; + Text name; + QString phone; + UserData *contact; +}; + +class HistoryMessage : public HistoryItem { +public: + + HistoryMessage(History *history, HistoryBlock *block, const MTPDmessage &msg); +// HistoryMessage(History *history, HistoryBlock *block, const MTPDgeoChatMessage &msg); +// HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime date, int32 from, const QString &msg); + HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime date, int32 from, const QString &msg, const MTPMessageMedia &media); + HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime date, int32 from, const QString &msg, HistoryMedia *media); + + void initMedia(const MTPMessageMedia &media, QString ¤tText); + void initDimensions(const QString &text); + void fromNameUpdated() const; + + bool uploading() const; + + void draw(QPainter &p, uint32 selection) const; + virtual void drawMessageText(QPainter &p, const QRect &trect, uint32 selection) const; + + int32 resize(int32 width); + bool hasPoint(int32 x, int32 y) const; + void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const; + void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const; + uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const { + return _text.adjustSelection(from, to, type); + } + bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const; + bool getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const; + + void drawInDialog(QPainter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const; + + void updateMedia(const MTPMessageMedia &media) { + if (this->media) this->media->updateFrom(media); + } + + QString selectedText(uint32 selection) const; + HistoryMedia *getMedia() const; + + ~HistoryMessage(); + +protected: + + Text _text; + + int32 _textWidth, _textHeight; + + HistoryMedia *media; + QString time; + int32 timeWidth; + +}; + +class HistoryForwarded : public HistoryMessage { +public: + + HistoryForwarded(History *history, HistoryBlock *block, const MTPDmessageForwarded &msg); + HistoryForwarded(History *history, HistoryBlock *block, MsgId id, HistoryMessage *msg); + + void fwdNameUpdated() const; + + void draw(QPainter &p, uint32 selection) const; + void drawMessageText(QPainter &p, const QRect &trect, uint32 selection) const; + int32 resize(int32 width); + bool hasPoint(int32 x, int32 y) const; + void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const; + void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const; + + QDateTime dateForwarded() const { + return fwdDate; + } + UserData *fromForwarded() const { + return fwdFrom; + } + QString selectedText(uint32 selection) const; + +protected: + + QDateTime fwdDate; + UserData *fwdFrom; + mutable Text fwdFromName; + mutable int32 fwdFromVersion; + int32 fromWidth; + +}; + +class HistoryServiceMsg : public HistoryItem { +public: + + HistoryServiceMsg(History *history, HistoryBlock *block, const MTPDmessageService &msg); +// HistoryServiceMsg(History *history, HistoryBlock *block, const MTPDgeoChatMessageService &msg); + HistoryServiceMsg(History *history, HistoryBlock *block, MsgId msgId, QDateTime date, const QString &msg, bool out = false, bool unread = false, HistoryMedia *media = 0); + + void draw(QPainter &p, uint32 selection) const; + int32 resize(int32 width); + bool hasPoint(int32 x, int32 y) const; + void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const; + void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const; + uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const { + return _text.adjustSelection(from, to, type); + } + bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const; + + void drawInDialog(QPainter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const; + bool needCheck() const { + return false; + } + bool serviceMsg() const { + return true; + } + QString selectedText(uint32 selection) const; + + ~HistoryServiceMsg(); + +protected: + + QString messageByAction(const MTPmessageAction &action, TextLinkPtr &second); + + Text _text; + HistoryMedia *media; + + int32 _textWidth, _textHeight; +}; + +class HistoryDateMsg : public HistoryServiceMsg { +public: + + HistoryDateMsg(History *history, HistoryBlock *block, const QDate &date); + void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const { + lnk = TextLinkPtr(); + inText = false; + } + void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { + symbol = 0xFFFF; + after = false; + upon = false; + } + QString selectedText(uint32 selection) const { + return QString(); + } + int32 itemType() const { + return DateType; + } +}; + +HistoryItem *createDayServiceMsg(History *history, HistoryBlock *block, QDateTime date); + +class HistoryUnreadBar : public HistoryItem { +public: + + HistoryUnreadBar(History *history, HistoryBlock *block, int32 count, const QDateTime &date); + + void setCount(int32 count); + + void draw(QPainter &p, uint32 selection) const; + int32 resize(int32 width); + + void drawInDialog(QPainter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const; + QString selectedText(uint32 selection) const { + return QString(); + } + int32 itemType() const { + return UnreadBarType; + } + +protected: + + QString text; + bool freezed; +}; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp new file mode 100644 index 000000000..eeb286ba9 --- /dev/null +++ b/Telegram/SourceFiles/historywidget.cpp @@ -0,0 +1,2935 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" +#include "lang.h" + +#include "boxes/confirmbox.h" +#include "historywidget.h" +#include "gui/filedialog.h" +#include "boxes/photosendbox.h" +#include "mainwidget.h" +#include "window.h" +#include "fileuploader.h" +#include "supporttl.h" + +// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html + +HistoryList::HistoryList(HistoryWidget *historyWidget, ScrollArea *scroll, History *history) : QWidget(0), + historyWidget(historyWidget), scrollArea(scroll), hist(history), currentBlock(0), currentItem(0), _menu(0), + _dragAction(NoDrag), _dragItem(0), _dragSelFrom(0), _dragSelTo(0), _dragSelecting(false), + _dragSelType(TextSelectLetters), _dragWasInactive(false), + _touchScroll(false), _touchSelect(false), _touchInProgress(false), + _touchScrollState(TouchScrollManual), _touchPrevPosValid(false), _touchWaitingAcceleration(false), _touchSpeedTime(0), _touchAccelerationTime(0), _touchTime(0), + _cursor(style::cur_default) { + + linkTipTimer.setSingleShot(true); + connect(&linkTipTimer, SIGNAL(timeout()), this, SLOT(showLinkTip())); + _touchSelectTimer.setSingleShot(true); + connect(&_touchSelectTimer, SIGNAL(timeout()), this, SLOT(onTouchSelect())); + + setAttribute(Qt::WA_AcceptTouchEvents); + connect(&_touchScrollTimer, SIGNAL(timeout()), this, SLOT(onTouchScrollTimer())); + + _trippleClickTimer.setSingleShot(true); + + setMouseTracking(true); +} + +void HistoryList::messagesReceived(const QVector &messages) { + hist->addToFront(messages); +} + +void HistoryList::updateMsg(HistoryItem *msg) { + if (!msg || !hist || hist != msg->history()) return; + update(0, height() - hist->height - st::historyPadding + msg->block()->y + msg->y, width(), msg->height()); +} + +void HistoryList::paintEvent(QPaintEvent *e) { + QRect r(e->rect()); + bool trivial = (rect() == r); + + QPainter p(this); + if (!trivial) { + p.setClipRect(r); + } else { + bool nt = true; + } + + if (hist->isEmpty()) { + QPoint dogPos((width() - st::msgDogImg.width()) / 2, ((height() - st::msgDogImg.height()) * 4) / 9); + p.drawPixmap(dogPos, App::sprite(), st::msgDogImg); + } else { + adjustCurrent(r.top()); + HistoryBlock *block = (*hist)[currentBlock]; + HistoryItem *item = (*block)[currentItem]; + + SelectedItems::const_iterator selEnd = _selected.cend(); + bool hasSel = !_selected.isEmpty(); + + int32 firstItemY = height() - hist->height - st::historyPadding, drawToY = r.bottom() - firstItemY; + + int32 selfromy = 0, seltoy = 0; + if (_dragSelFrom && _dragSelTo) { + selfromy = _dragSelFrom->y + _dragSelFrom->block()->y; + seltoy = _dragSelTo->y + _dragSelTo->block()->y + _dragSelTo->height(); + } + + int32 iBlock = currentBlock, iItem = currentItem, y = block->y + item->y; + p.translate(0, firstItemY + y); + while (y < drawToY) { + int32 h = item->height(); + uint32 sel = 0; + if (y >= selfromy && y < seltoy) { + sel = (_dragSelecting && !item->serviceMsg() && item->id > 0) ? FullItemSel : 0; + } else if (hasSel) { + SelectedItems::const_iterator i = _selected.constFind(item); + if (i != selEnd) { + sel = i.value(); + } + } + item->draw(p, sel); + p.translate(0, h); + ++iItem; + if (iItem == block->size()) { + iItem = 0; + ++iBlock; + if (iBlock == hist->size()) { + break; + } + block = (*hist)[iBlock]; + } + item = (*block)[iItem]; + y += h; + } + } +} + +bool HistoryList::event(QEvent *e) { + if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { + QTouchEvent *ev = static_cast(e); + if (ev->device()->type() == QTouchDevice::TouchScreen) { + touchEvent(ev); + return true; + } + } + return QWidget::event(e); +} + +void HistoryList::onTouchScrollTimer() { + uint64 nowTime = getms(); + if (_touchScrollState == TouchScrollAcceleration && _touchWaitingAcceleration && (nowTime - _touchAccelerationTime) > 40) { + _touchScrollState = TouchScrollManual; + touchResetSpeed(); + } else if (_touchScrollState == TouchScrollAuto || _touchScrollState == TouchScrollAcceleration) { + int32 elapsed = int32(nowTime - _touchTime); + QPoint delta = _touchSpeed * elapsed / 1000; + bool hasScrolled = historyWidget->touchScroll(delta); + + if (_touchSpeed.isNull() || !hasScrolled) { + _touchScrollState = TouchScrollManual; + _touchScroll = false; + _touchScrollTimer.stop(); + } else { + _touchTime = nowTime; + } + touchDeaccelerate(elapsed); + } +} + +void HistoryList::touchUpdateSpeed() { + const uint64 nowTime = getms(); + if (_touchPrevPosValid) { + const int elapsed = nowTime - _touchSpeedTime; + if (elapsed) { + const QPoint newPixelDiff = (_touchPos - _touchPrevPos); + const QPoint pixelsPerSecond = newPixelDiff * (1000 / elapsed); + + // fingers are inacurates, we ignore small changes to avoid stopping the autoscroll because + // of a small horizontal offset when scrolling vertically + const int newSpeedY = (qAbs(pixelsPerSecond.y()) > FingerAccuracyThreshold) ? pixelsPerSecond.y() : 0; + const int newSpeedX = (qAbs(pixelsPerSecond.x()) > FingerAccuracyThreshold) ? pixelsPerSecond.x() : 0; + if (_touchScrollState == TouchScrollAuto) { + const int oldSpeedY = _touchSpeed.y(); + const int oldSpeedX = _touchSpeed.x(); + if ((oldSpeedY <= 0 && newSpeedY <= 0) || (oldSpeedY >= 0 && newSpeedY >= 0) + && (oldSpeedX <= 0 && newSpeedX <= 0) || (oldSpeedX >= 0 && newSpeedX >= 0)) { + _touchSpeed.setY(snap((oldSpeedY + (newSpeedY / 4)), -MaxScrollAccelerated, +MaxScrollAccelerated)); + _touchSpeed.setX(snap((oldSpeedX + (newSpeedX / 4)), -MaxScrollAccelerated, +MaxScrollAccelerated)); + } else { + _touchSpeed = QPoint(); + } + } else { + // we average the speed to avoid strange effects with the last delta + if (!_touchSpeed.isNull()) { + _touchSpeed.setX(snap((_touchSpeed.x() / 4) + (newSpeedX * 3 / 4), -MaxScrollFlick, +MaxScrollFlick)); + _touchSpeed.setY(snap((_touchSpeed.y() / 4) + (newSpeedY * 3 / 4), -MaxScrollFlick, +MaxScrollFlick)); + } else { + _touchSpeed = QPoint(newSpeedX, newSpeedY); + } + } + } + } else { + _touchPrevPosValid = true; + } + _touchSpeedTime = nowTime; + _touchPrevPos = _touchPos; +} + +void HistoryList::touchResetSpeed() { + _touchSpeed = QPoint(); + _touchPrevPosValid = false; +} + +void HistoryList::touchDeaccelerate(int32 elapsed) { + int32 x = _touchSpeed.x(); + int32 y = _touchSpeed.y(); + _touchSpeed.setX((x == 0) ? x : (x > 0) ? qMax(0, x - elapsed) : qMin(0, x + elapsed)); + _touchSpeed.setY((y == 0) ? y : (y > 0) ? qMax(0, y - elapsed) : qMin(0, y + elapsed)); +} + +void HistoryList::touchEvent(QTouchEvent *e) { + const Qt::TouchPointStates &states(e->touchPointStates()); + if (e->type() == QEvent::TouchCancel) { // cancel + if (!_touchInProgress) return; + _touchInProgress = false; + _touchSelectTimer.stop(); + _touchScroll = _touchSelect = false; + _touchScrollState = TouchScrollManual; + dragActionCancel(); + return; + } + + if (!e->touchPoints().isEmpty()) { + _touchPrevPos = _touchPos; + _touchPos = e->touchPoints().cbegin()->screenPos().toPoint(); + } + + switch (e->type()) { + case QEvent::TouchBegin: + if (_touchInProgress) return; + if (e->touchPoints().isEmpty()) return; + + _touchInProgress = true; + if (_touchScrollState == TouchScrollAuto) { + _touchScrollState = TouchScrollAcceleration; + _touchWaitingAcceleration = true; + _touchAccelerationTime = getms(); + touchUpdateSpeed(); + _touchStart = _touchPos; + } else { + _touchScroll = false; + _touchSelectTimer.start(QApplication::startDragTime()); + } + _touchSelect = false; + _touchStart = _touchPrevPos = _touchPos; + break; + + case QEvent::TouchUpdate: + if (!_touchInProgress) return; + if (_touchSelect) { + dragActionUpdate(_touchPos); + } else if (!_touchScroll && (_touchPos - _touchStart).manhattanLength() >= QApplication::startDragDistance()) { + _touchSelectTimer.stop(); + _touchScroll = true; + touchUpdateSpeed(); + } + if (_touchScroll) { + if (_touchScrollState == TouchScrollManual) { + touchScrollUpdated(_touchPos); + } else if (_touchScrollState == TouchScrollAcceleration) { + touchUpdateSpeed(); + _touchAccelerationTime = getms(); + if (_touchSpeed.isNull()) { + _touchScrollState = TouchScrollManual; + } + } + } + break; + + case QEvent::TouchEnd: + if (!_touchInProgress) return; + _touchInProgress = false; + if (_touchSelect) { + dragActionFinish(_touchPos, Qt::RightButton); + QContextMenuEvent contextMenu(QContextMenuEvent::Mouse, mapFromGlobal(_touchPos), _touchPos); + showContextMenu(&contextMenu, true); + _touchScroll = false; + } else if (_touchScroll) { + if (_touchScrollState == TouchScrollManual) { + _touchScrollState = TouchScrollAuto; + _touchPrevPosValid = false; + _touchScrollTimer.start(15); + _touchTime = getms(); + } else if (_touchScrollState == TouchScrollAuto) { + _touchScrollState = TouchScrollManual; + _touchScroll = false; + touchResetSpeed(); + } else if (_touchScrollState == TouchScrollAcceleration) { + _touchScrollState = TouchScrollAuto; + _touchWaitingAcceleration = false; + _touchPrevPosValid = false; + } + } else { // one short tap -- like mouse click + dragActionStart(_touchPos); + dragActionFinish(_touchPos); + } + _touchSelectTimer.stop(); + _touchSelect = false; + break; + } +} + +void HistoryList::mouseMoveEvent(QMouseEvent *e) { + if (!(e->buttons() & (Qt::LeftButton | Qt::MiddleButton)) && (textlnkDown() || _dragAction != NoDrag)) { + mouseReleaseEvent(e); + } + dragActionUpdate(e->globalPos()); +} + +void HistoryList::dragActionUpdate(const QPoint &screenPos) { + _dragPos = screenPos; + onUpdateSelected(true); +} + +void HistoryList::touchScrollUpdated(const QPoint &screenPos) { + _touchPos = screenPos; + historyWidget->touchScroll(_touchPos - _touchPrevPos); + touchUpdateSpeed(); +} + +QPoint HistoryList::mapMouseToItem(QPoint p, HistoryItem *item) { + if (!item) return QPoint(0, 0); + p.setY(p.y() - (height() - hist->height - st::historyPadding) - item->block()->y - item->y); + return p; +} + +void HistoryList::mousePressEvent(QMouseEvent *e) { + if (_menu) { + e->accept(); + return; // ignore mouse press, that was hiding context menu + } + dragActionStart(e->globalPos(), e->button()); +} + +void HistoryList::dragActionStart(const QPoint &screenPos, Qt::MouseButton button) { + dragActionUpdate(screenPos); + if (button != Qt::LeftButton) return; + + if (App::pressedItem() != App::hoveredItem()) { + updateMsg(App::pressedItem()); + App::pressedItem(App::hoveredItem()); + updateMsg(App::pressedItem()); + } + if (textlnkDown() != textlnkOver()) { + updateMsg(App::pressedLinkItem()); + textlnkDown(textlnkOver()); + App::pressedLinkItem(App::hoveredLinkItem()); + updateMsg(App::pressedLinkItem()); + updateMsg(App::pressedItem()); + } + + _dragAction = NoDrag; + _dragItem = App::mousedItem(); + _dragStartPos = mapMouseToItem(mapFromGlobal(screenPos), _dragItem); + _dragWasInactive = App::wnd()->inactivePress(); + if (_dragWasInactive) App::wnd()->inactivePress(false); + bool textLink = textlnkDown() && !textlnkDown()->encoded().isEmpty(); + if (textLink) { + _dragAction = PrepareDrag; + } else if (!_selected.isEmpty()) { + if (_selected.cbegin().value() == FullItemSel) { + if (_selected.constFind(_dragItem) != _selected.cend() && App::hoveredItem()) { + _dragAction = PrepareDrag; // start items drag + } else { + _dragAction = PrepareSelect; // start items select + } + } + } + if (_dragAction == NoDrag && _dragItem) { + bool afterDragSymbol, uponSymbol; + uint16 symbol; + if (_trippleClickTimer.isActive() && (screenPos - _trippleClickPoint).manhattanLength() < QApplication::startDragDistance()) { + _dragItem->getSymbol(symbol, afterDragSymbol, uponSymbol, _dragStartPos.x(), _dragStartPos.y()); + if (uponSymbol) { + uint32 selStatus = (symbol << 16) | symbol; + if (selStatus != FullItemSel && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) { + if (!_selected.isEmpty()) { + updateMsg(_selected.cbegin().key()); + _selected.clear(); + } + _selected.insert(_dragItem, selStatus); + _dragSymbol = symbol; + _dragAction = Selecting; + _dragSelType = TextSelectParagraphs; + dragActionUpdate(_dragPos); + _trippleClickTimer.start(QApplication::doubleClickInterval()); + } + } + } else if (App::pressedItem()) { + _dragItem->getSymbol(symbol, afterDragSymbol, uponSymbol, _dragStartPos.x(), _dragStartPos.y()); + } + if (_dragSelType != TextSelectParagraphs) { + if (App::pressedItem()) { + _dragSymbol = symbol; + bool uponSelected = uponSymbol; + if (uponSelected) { + if (_selected.isEmpty() || + _selected.cbegin().value() == FullItemSel || + _selected.cbegin().key() != _dragItem + ) { + uponSelected = false; + } else { + uint16 selFrom = (_selected.cbegin().value() >> 16) & 0xFFFF, selTo = _selected.cbegin().value() & 0xFFFF; + if (_dragSymbol < selFrom || _dragSymbol >= selTo) { + uponSelected = false; + } + } + } + if (uponSelected) { + _dragAction = PrepareDrag; // start text drag + } else { + if (afterDragSymbol) ++_dragSymbol; + uint32 selStatus = (_dragSymbol << 16) | _dragSymbol; + if (selStatus != FullItemSel && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) { + if (!_selected.isEmpty()) { + updateMsg(_selected.cbegin().key()); + _selected.clear(); + } + _selected.insert(_dragItem, selStatus); + _dragAction = Selecting; + updateMsg(_dragItem); + } else { + _dragAction = PrepareSelect; + } + } + } else { + _dragAction = PrepareSelect; // start items select + } + } + } + + if (!_dragItem) { + _dragAction = NoDrag; + } else if (_dragAction == NoDrag) { + _dragItem = 0; + } else { + connect(App::main(), SIGNAL(historyItemDeleted(HistoryItem*)), this, SLOT(itemRemoved(HistoryItem*)), Qt::UniqueConnection); + } +} + +void HistoryList::dragActionCancel() { + _dragItem = 0; + _dragAction = NoDrag; + _dragStartPos = QPoint(0, 0); + historyWidget->noSelectingScroll(); +} + +void HistoryList::itemRemoved(HistoryItem *item) { + if (_dragItem == item) { + dragActionCancel(); + } + + SelectedItems::iterator i = _selected.find(item); + if (i != _selected.cend()) { + _selected.erase(i); + update(); + } + + onUpdateSelected(true); + + if (_dragSelFrom == item) _dragSelFrom = 0; + if (_dragSelTo == item) _dragSelTo = 0; + updateDragSelection(_dragSelFrom, _dragSelTo, _dragSelecting, true); + + parentWidget()->update(); +} + +void HistoryList::dragActionFinish(const QPoint &screenPos, Qt::MouseButton button) { + TextLinkPtr needClick; + + dragActionUpdate(screenPos); + + if (textlnkOver()) { + if (textlnkDown() == textlnkOver() && _dragAction != Dragging) { + needClick = textlnkDown(); + } + } + if (textlnkDown()) { + updateMsg(App::pressedLinkItem()); + textlnkDown(TextLinkPtr()); + App::pressedLinkItem(0); + if (!textlnkOver() && _cursor != style::cur_default) { + _cursor = style::cur_default; + setCursor(_cursor); + } + } + if (App::pressedItem()) { + updateMsg(App::pressedItem()); + App::pressedItem(0); + } + if (needClick) { + needClick->onClick(button); + } + if (_dragAction == PrepareSelect && !needClick && !_dragWasInactive && !_selected.isEmpty() && _selected.cbegin().value() == FullItemSel) { + SelectedItems::iterator i = _selected.find(_dragItem); + if (i == _selected.cend() && !_dragItem->serviceMsg() && _dragItem->id > 0) { + if (_selected.size() < MaxSelectedItems) { + if (!_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + _selected.clear(); + } + _selected.insert(_dragItem, FullItemSel); + } + } else { + _selected.erase(i); + } + updateMsg(_dragItem); + } else if (_dragAction == PrepareDrag && !needClick && !_dragWasInactive && button != Qt::RightButton) { + SelectedItems::iterator i = _selected.find(_dragItem); + if (i != _selected.cend() && i.value() == FullItemSel) { + _selected.erase(i); + updateMsg(_dragItem); + } else { + _selected.clear(); + parentWidget()->update(); + } + } else if (_dragAction == Selecting) { + if (_dragSelFrom && _dragSelTo) { + applyDragSelection(); + } else if (!_selected.isEmpty() && !_dragWasInactive) { + uint32 sel = _selected.cbegin().value(); + if (sel != FullItemSel && (sel & 0xFFFF) == ((sel >> 16) & 0xFFFF)) { + _selected.clear(); + App::main()->activate(); + } + } + } + _dragAction = NoDrag; + _dragSelType = TextSelectLetters; + historyWidget->noSelectingScroll(); + historyWidget->updateTopBarSelection(); +} + +void HistoryList::mouseReleaseEvent(QMouseEvent *e) { + dragActionFinish(e->globalPos(), e->button()); + if (!rect().contains(e->pos())) { + leaveEvent(e); + } +} + +void HistoryList::mouseDoubleClickEvent(QMouseEvent *e) { + if (_dragAction == Selecting && _dragSelType == TextSelectLetters && _dragItem && !_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + bool afterDragSymbol, uponSelected; + uint16 symbol; + _dragItem->getSymbol(symbol, afterDragSymbol, uponSelected, _dragStartPos.x(), _dragStartPos.y()); + if (uponSelected) { + _dragSymbol = symbol; + _dragSelType = TextSelectWords; + mouseMoveEvent(e); + + _trippleClickPoint = e->globalPos(); + _trippleClickTimer.start(QApplication::doubleClickInterval()); + } + } +} + +void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { + if (_menu) { + _menu->deleteLater(); + _menu = 0; + } + if (e->reason() == QContextMenuEvent::Mouse) { + dragActionUpdate(e->globalPos()); + } + + // -2 - has full selected items, but not over, -1 - has selection, but no over, 0 - no selection, 1 - over text, 2 - over full selected items + int32 isUponSelected = 0, hasSelected = 0;; + if (!_selected.isEmpty()) { + isUponSelected = -1; + if (_selected.cbegin().value() == FullItemSel) { + hasSelected = 2; + if (App::hoveredItem() && _selected.constFind(App::hoveredItem()) != _selected.cend()) { + isUponSelected = 2; + } else { + isUponSelected = -2; + } + } else { + uint16 symbol, selFrom = (_selected.cbegin().value() >> 16) & 0xFFFF, selTo = _selected.cbegin().value() & 0xFFFF; + hasSelected = (selTo > selFrom) ? 1 : 0; + if (_dragItem && _dragItem == App::hoveredItem()) { + QPoint mousePos(mapMouseToItem(mapFromGlobal(_dragPos), _dragItem)); + bool afterDragSymbol, uponSymbol; + _dragItem->getSymbol(symbol, afterDragSymbol, uponSymbol, mousePos.x(), mousePos.y()); + if (uponSymbol && symbol >= selFrom && symbol < selTo) { + isUponSelected = 1; + } + } + } + } + if (showFromTouch && hasSelected && isUponSelected < hasSelected) { + isUponSelected = hasSelected; + } + + _contextMenuLnk = textlnkOver(); + if (_contextMenuLnk && dynamic_cast(_contextMenuLnk.data())) { + _menu = new QMenu(historyWidget); + if (isUponSelected > 0) { + _menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true); + } + _menu->addAction(lang(lng_context_open_link), this, SLOT(openContextUrl()))->setEnabled(true); + _menu->addAction(lang(lng_context_copy_link), this, SLOT(copyContextUrl()))->setEnabled(true); + } else if (_contextMenuLnk && dynamic_cast(_contextMenuLnk.data())) { + _menu = new QMenu(historyWidget); + if (isUponSelected > 0) { + _menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true); + } + _menu->addAction(lang(lng_context_open_email), this, SLOT(openContextUrl()))->setEnabled(true); + _menu->addAction(lang(lng_context_copy_email), this, SLOT(copyContextUrl()))->setEnabled(true); + } else { + PhotoLink *lnkPhoto = dynamic_cast(_contextMenuLnk.data()); + VideoLink *lnkVideo = dynamic_cast(_contextMenuLnk.data()); + AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); + DocumentLink *lnkDocument = dynamic_cast(_contextMenuLnk.data()); + if (lnkPhoto || lnkVideo || lnkAudio || lnkDocument) { + _menu = new QMenu(historyWidget); + if (isUponSelected > 0) { + _menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true); + } + if (lnkPhoto) { + _menu->addAction(lang(lng_context_open_image), this, SLOT(openContextUrl()))->setEnabled(true); + _menu->addAction(lang(lng_context_save_image), this, SLOT(saveContextImage()))->setEnabled(true); + _menu->addAction(lang(lng_context_copy_image), this, SLOT(copyContextImage()))->setEnabled(true); + } else { + if (lnkVideo && lnkVideo->video()->loader || lnkAudio && lnkAudio->audio()->loader || lnkDocument && lnkDocument->document()->loader) { + _menu->addAction(lang(lng_context_cancel_download), this, SLOT(cancelContextDownload()))->setEnabled(true); + } else { + if (lnkVideo && !lnkVideo->video()->already(true).isEmpty() || lnkAudio && !lnkAudio->audio()->already(true).isEmpty() || lnkDocument && !lnkDocument->document()->already(true).isEmpty()) { + _menu->addAction(lang(lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true); + } + _menu->addAction(lang(lnkVideo ? lng_context_open_video : (lnkAudio ? lng_context_open_audio : lng_context_open_document)), this, SLOT(openContextFile()))->setEnabled(true); + _menu->addAction(lang(lnkVideo ? lng_context_save_video : (lnkAudio ? lng_context_save_audio : lng_context_save_document)), this, SLOT(saveContextFile()))->setEnabled(true); + } + } + if (isUponSelected > 1) { + _menu->addAction(lang(lng_context_forward_selected), historyWidget, SLOT(onForwardSelected())); + _menu->addAction(lang(lng_context_delete_selected), historyWidget, SLOT(onDeleteSelected())); + _menu->addAction(lang(lng_context_clear_selection), historyWidget, SLOT(onClearSelected())); + } else if (isUponSelected != -2 && App::hoveredLinkItem()) { + if (dynamic_cast(App::hoveredLinkItem())) { + _menu->addAction(lang(lng_context_forward_msg), historyWidget, SLOT(forwardMessage()))->setEnabled(true); + } + _menu->addAction(lang(lng_context_delete_msg), historyWidget, SLOT(deleteMessage()))->setEnabled(true); + App::contextItem(App::hoveredLinkItem()); + } + } else { // maybe cursor on some text history item? + HistoryItem *item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem(); + bool canDelete = (item && item->itemType() == HistoryItem::MsgType); + bool canForward = canDelete && (item->id > 0) && !item->serviceMsg(); + + HistoryMessage *msg = dynamic_cast(item); + HistoryServiceMsg *srv = dynamic_cast(item); + + if (isUponSelected > 0) { + if (!_menu) _menu = new QMenu(this); + _menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true); + } else if (item && !isUponSelected && !_contextMenuLnk) { + QString contextMenuText = item->selectedText(FullItemSel); + if (!contextMenuText.isEmpty()) { + if (!_menu) _menu = new QMenu(this); + _menu->addAction(lang(lng_context_copy_text), this, SLOT(copyContextText()))->setEnabled(true); + } + } + + if (isUponSelected > 1) { + if (!_menu) _menu = new QMenu(this); + _menu->addAction(lang(lng_context_forward_selected), historyWidget, SLOT(onForwardSelected())); + _menu->addAction(lang(lng_context_delete_selected), historyWidget, SLOT(onDeleteSelected())); + _menu->addAction(lang(lng_context_clear_selection), historyWidget, SLOT(onClearSelected())); + } else if (isUponSelected != -2) { + if (canForward) { + if (!_menu) _menu = new QMenu(this); + _menu->addAction(lang(lng_context_forward_msg), historyWidget, SLOT(forwardMessage()))->setEnabled(true); + } + + if (canDelete) { + if (!_menu) _menu = new QMenu(this); + _menu->addAction(lang((msg && msg->uploading()) ? lng_context_cancel_upload : lng_context_delete_msg), historyWidget, SLOT(deleteMessage()))->setEnabled(true); + } + } + App::contextItem(item); + } + } + if (_menu) { + _menu->setAttribute(Qt::WA_DeleteOnClose); + connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*))); + _menu->popup(e->globalPos()); + e->accept(); + } +} + +void HistoryList::onMenuDestroy(QObject *obj) { + if (_menu == obj) { + _menu = 0; + } +} + +void HistoryList::copySelectedText() { + QApplication::clipboard()->setText(getSelectedText()); +} + +void HistoryList::openContextUrl() { + HistoryItem *was = App::hoveredLinkItem(); + App::hoveredLinkItem(App::contextItem()); + _contextMenuLnk->onClick(Qt::LeftButton); + App::hoveredLinkItem(was); +} + +void HistoryList::copyContextUrl() { + QString enc = _contextMenuLnk->encoded(); + if (!enc.isEmpty()) { + QApplication::clipboard()->setText(enc); + } +} + +void HistoryList::saveContextImage() { + PhotoLink *lnk = dynamic_cast(_contextMenuLnk.data()); + if (!lnk) return; + + PhotoData *photo = lnk->photo(); + if (!photo || !photo->date || !photo->full->loaded()) return; + + QString file; + if (filedialogGetSaveFile(file, lang(lng_save_photo), qsl("JPEG Image (*.jpg);;All files (*.*)"), filedialogDefaultName(qsl("photo"), qsl(".jpg")))) { + if (!file.isEmpty()) { + photo->full->pix().toImage().save(file, "JPG"); + } + } +} + +void HistoryList::copyContextImage() { + PhotoLink *lnk = dynamic_cast(_contextMenuLnk.data()); + if (!lnk) return; + + PhotoData *photo = lnk->photo(); + if (!photo || !photo->date || !photo->full->loaded()) return; + + QApplication::clipboard()->setPixmap(photo->full->pix()); +} + +void HistoryList::cancelContextDownload() { + VideoLink *lnkVideo = dynamic_cast(_contextMenuLnk.data()); + AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); + DocumentLink *lnkDocument = dynamic_cast(_contextMenuLnk.data()); + mtpFileLoader *loader = lnkVideo ? lnkVideo->video()->loader : (lnkAudio ? lnkAudio->audio()->loader : (lnkDocument ? lnkDocument->document()->loader : 0)); + if (loader) loader->cancel(); +} + +void HistoryList::showContextInFolder() { + VideoLink *lnkVideo = dynamic_cast(_contextMenuLnk.data()); + AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); + DocumentLink *lnkDocument = dynamic_cast(_contextMenuLnk.data()); + QString already = lnkVideo ? lnkVideo->video()->already(true) : (lnkAudio ? lnkAudio->audio()->already(true) : (lnkDocument ? lnkDocument->document()->already(true) : QString())); + if (!already.isEmpty()) psShowInFolder(already); +} + +void HistoryList::openContextFile() { + VideoLink *lnkVideo = dynamic_cast(_contextMenuLnk.data()); + AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); + DocumentLink *lnkDocument = dynamic_cast(_contextMenuLnk.data()); + if (lnkVideo) VideoOpenLink(lnkVideo->video()).onClick(Qt::LeftButton); + if (lnkAudio) AudioOpenLink(lnkAudio->audio()).onClick(Qt::LeftButton); + if (lnkDocument) DocumentOpenLink(lnkDocument->document()).onClick(Qt::LeftButton); +} + +void HistoryList::saveContextFile() { + VideoLink *lnkVideo = dynamic_cast(_contextMenuLnk.data()); + AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); + DocumentLink *lnkDocument = dynamic_cast(_contextMenuLnk.data()); + if (lnkVideo) VideoSaveLink(lnkVideo->video()).doSave(true); + if (lnkAudio) AudioSaveLink(lnkAudio->audio()).doSave(true); + if (lnkDocument) DocumentSaveLink(lnkDocument->document()).doSave(true); +} + +void HistoryList::copyContextText() { + HistoryItem *item = App::contextItem(); + if (item && item->itemType() != HistoryItem::MsgType) { + item = 0; + } + + if (!item) return; + + QString contextMenuText = item->selectedText(FullItemSel); + if (!contextMenuText.isEmpty()) { + QApplication::clipboard()->setText(contextMenuText); + } +} + +bool HistoryList::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + HistoryItem *hoveredItem = App::hoveredLinkItem(); + if (hoveredItem && hoveredItem->getPhotoCoords(photo, x, y, w)) { + y += height() - hist->height - st::historyPadding + hoveredItem->block()->y + hoveredItem->y; + return true; + } + return false; +} + +bool HistoryList::getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const { + HistoryItem *hoveredItem = App::hoveredItem(); + if (hoveredItem && hoveredItem->getVideoCoords(video, x, y, w)) { + y += height() - hist->height - st::historyPadding + hoveredItem->block()->y + hoveredItem->y; + return true; + } + return false; +} + +void HistoryList::resizeEvent(QResizeEvent *e) { + onUpdateSelected(true); +} + +QString HistoryList::getSelectedText() const { + if (_selected.isEmpty()) return QString(); + if (_selected.cbegin().value() != FullItemSel) { + return _selected.cbegin().key()->selectedText(_selected.cbegin().value()); + } + + int32 fullSize = 0; + QString timeFormat(qsl(", [dd.MM.yy hh:mm]\n")); + QMap texts; + for (SelectedItems::const_iterator i = _selected.cbegin(), e = _selected.cend(); i != e; ++i) { + HistoryItem *item = i.key(); + QString text, sel = item->selectedText(FullItemSel), time = item->date.toString(timeFormat); + int32 size = item->from()->name.size() + time.size() + sel.size(); + text.reserve(size); + texts.insert(item->y + item->block()->y, text.append(item->from()->name).append(time).append(sel)); + fullSize += size; + } + + QString result, sep(qsl("\n\n")); + result.reserve(fullSize + (texts.size() - 1) * 2); + for (QMap::const_iterator i = texts.cbegin(), e = texts.cend(); i != e; ++i) { + result.append(i.value()); + if (i + 1 != e) { + result.append(sep); + } + } + return result; +} + +void HistoryList::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + historyWidget->onClearSelected(); + } else if (e == QKeySequence::Copy && !_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + copySelectedText(); + } else if (e == QKeySequence::Delete) { + historyWidget->onDeleteSelected(); + } +} + +int32 HistoryList::recountHeight() { + int32 st = hist->lastScrollTop; + hist->geomResize(scrollArea->width(), &st); + return st; +} + +void HistoryList::updateSize() { + int32 ph = scrollArea->height(), nh = (hist->height + st::historyPadding) > ph ? (hist->height + st::historyPadding) : ph; + if (width() != scrollArea->width() || height() != nh) { + resize(scrollArea->width(), nh); + } else { + update(); + } +} + +void HistoryList::enterEvent(QEvent *e) { +} + +void HistoryList::leaveEvent(QEvent *e) { + if (textlnkOver()) { + updateMsg(App::hoveredItem()); + updateMsg(App::hoveredLinkItem()); + textlnkOver(TextLinkPtr()); + App::hoveredLinkItem(0); + App::hoveredItem(0); + if (!textlnkDown() && _cursor != style::cur_default) { + _cursor = style::cur_default; + setCursor(_cursor); + } + } +} + +HistoryList::~HistoryList() { + delete _menu; +} + +void HistoryList::adjustCurrent(int32 y) { + if (hist->isEmpty()) return; + if (currentBlock >= hist->size()) { + currentBlock = hist->size() - 1; + currentItem = 0; + } + + int32 dh = height() - hist->height - st::historyPadding; + while ((*hist)[currentBlock]->y + dh > y && currentBlock > 0) { + --currentBlock; + currentItem = 0; + } + while ((*hist)[currentBlock]->y + (*hist)[currentBlock]->height + dh <= y && currentBlock + 1 < hist->size()) { + ++currentBlock; + currentItem = 0; + } + HistoryBlock *block = (*hist)[currentBlock]; + if (currentItem >= block->size()) { + currentItem = block->size() - 1; + } + int32 by = block->y; + while ((*block)[currentItem]->y + by + dh > y && currentItem > 0) { + --currentItem; + } + while ((*block)[currentItem]->y + (*block)[currentItem]->height() + by + dh <= y && currentItem + 1 < block->size()) { + ++currentItem; + } +} + +HistoryItem *HistoryList::prevItem(HistoryItem *item) { + if (!item) return 0; + HistoryBlock *block = item->block(); + int32 blockIndex = hist->indexOf(block), itemIndex = block->indexOf(item); + if (blockIndex < 0 || itemIndex < 0) return 0; + if (itemIndex > 0) { + return (*block)[itemIndex - 1]; + } + if (blockIndex > 0) { + return *((*hist)[blockIndex - 1]->cend() - 1); + } + return 0; +} + +HistoryItem *HistoryList::nextItem(HistoryItem *item) { + if (!item) return 0; + HistoryBlock *block = item->block(); + int32 blockIndex = hist->indexOf(block), itemIndex = block->indexOf(item); + if (blockIndex < 0 || itemIndex < 0) return 0; + if (itemIndex + 1 < block->size()) { + return (*block)[itemIndex + 1]; + } + if (blockIndex + 1 < hist->size()) { + return *(*hist)[blockIndex + 1]->cbegin(); + } + return 0; +} + +void HistoryList::getSelectionState(int32 &selectedForForward, int32 &selectedForDelete) const { + selectedForForward = selectedForDelete = 0; + for (SelectedItems::const_iterator i = _selected.cbegin(), e = _selected.cend(); i != e; ++i) { + if (i.key()->itemType() == HistoryItem::MsgType && i.value() == FullItemSel) { + ++selectedForDelete; + if (!i.key()->serviceMsg() && i.key()->id > 0) { + ++selectedForForward; + } + } + } + if (!selectedForDelete && !selectedForForward && !_selected.isEmpty()) { // text selection + selectedForForward = -1; + } +} + +void HistoryList::clearSelectedItems(bool onlyTextSelection) { + if (!_selected.isEmpty() && (!onlyTextSelection || _selected.cbegin().value() != FullItemSel)) { + _selected.clear(); + historyWidget->updateTopBarSelection(); + historyWidget->update(); + } +} + +void HistoryList::fillSelectedItems(HistoryItemSet &sel, bool forDelete) { + if (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel) return; + + for (SelectedItems::const_iterator i = _selected.cbegin(), e = _selected.cend(); i != e; ++i) { + HistoryItem *item = i.key(); + if (item->itemType() == HistoryItem::MsgType && (item->id > 0 && !item->serviceMsg() || forDelete)) { + sel.insert(item->y + item->block()->y, item); + } + } +} + +void HistoryList::onTouchSelect() { + _touchSelect = true; + dragActionStart(_touchPos); +} + +void HistoryList::onUpdateSelected(bool force) { + if (hist->isEmpty()) return; + + QPoint mousePos(mapFromGlobal(_dragPos)); + QPoint m(historyWidget->clampMousePosition(mousePos)); + adjustCurrent(m.y()); + + HistoryBlock *block = (*hist)[currentBlock]; + HistoryItem *item = (*block)[currentItem]; + App::mousedItem(item); + m = mapMouseToItem(m, item); + if (item->hasPoint(m.x(), m.y())) { + updateMsg(App::hoveredItem()); + App::hoveredItem(item); + updateMsg(App::hoveredItem()); + } else if (App::hoveredItem()) { + updateMsg(App::hoveredItem()); + App::hoveredItem(0); + } + linkTipTimer.start(1000); + + Qt::CursorShape cur = style::cur_default; + bool inText, lnkChanged = false; + + TextLinkPtr lnk; + item->getState(lnk, inText, m.x(), m.y()); + if (lnk != textlnkOver()) { + lnkChanged = true; + updateMsg(App::hoveredLinkItem()); + textlnkOver(lnk); + QToolTip::showText(_dragPos, QString(), App::wnd()); + App::hoveredLinkItem(lnk ? item : 0); + updateMsg(App::hoveredLinkItem()); + } + + if (_dragAction == NoDrag) { + if (lnk) { + cur = style::cur_pointer; + } else if (inText && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) { + cur = style::cur_text; + } + } else { + if (item != _dragItem || (m - _dragStartPos).manhattanLength() >= QApplication::startDragDistance()) { + if (_dragAction == PrepareDrag) { + _dragAction = Dragging; + } else if (_dragAction == PrepareSelect) { + _dragAction = Selecting; + } + } + cur = textlnkDown() ? style::cur_pointer : style::cur_default; + if (_dragAction == Selecting) { + if (item == _dragItem && item == App::hoveredItem() && !_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + bool afterSymbol, uponSymbol; + uint16 second; + _dragItem->getSymbol(second, afterSymbol, uponSymbol, m.x(), m.y()); + if (afterSymbol && _dragSelType == TextSelectLetters) ++second; + _selected[_dragItem] = _dragItem->adjustSelection(qMin(second, _dragSymbol), qMax(second, _dragSymbol), _dragSelType); + updateDragSelection(0, 0, false); + } else { + bool selectingDown = (_dragItem->block()->y < item->block()->y) || (_dragItem->block() == item->block()) && (_dragItem->y < item->y || _dragItem == item && _dragStartPos.y() < m.y()); + HistoryItem *dragSelFrom = _dragItem, *dragSelTo = item; + if (!dragSelFrom->hasPoint(_dragStartPos.x(), _dragStartPos.y())) { // maybe exclude dragSelFrom + if (selectingDown) { + if (_dragStartPos.y() >= dragSelFrom->height() - st::msgMargin.bottom() || (item == dragSelFrom) && (m.y() < _dragStartPos.y() + QApplication::startDragDistance())) { + dragSelFrom = (dragSelFrom == dragSelTo) ? 0 : nextItem(dragSelFrom); + } + } else { + if (_dragStartPos.y() < st::msgMargin.top() || (item == dragSelFrom) && (m.y() >= _dragStartPos.y() - QApplication::startDragDistance())) { + dragSelFrom = (dragSelFrom == dragSelTo) ? 0 : prevItem(dragSelFrom); + } + } + } + if (_dragItem != item) { // maybe exclude dragSelTo + if (selectingDown) { + if (m.y() < st::msgMargin.top()) { + dragSelTo = (dragSelFrom == dragSelTo) ? 0 : prevItem(dragSelTo); + } + } else { + if (m.y() >= dragSelTo->height() - st::msgMargin.bottom()) { + dragSelTo = (dragSelFrom == dragSelTo) ? 0 : nextItem(dragSelTo); + } + } + } + bool dragSelecting = false; + HistoryItem *dragFirstAffected = dragSelFrom; + while (dragFirstAffected && (dragFirstAffected->id < 0 || dragFirstAffected->serviceMsg())) { + dragFirstAffected = (dragFirstAffected == dragSelTo) ? 0 : (selectingDown ? nextItem(dragFirstAffected) : prevItem(dragFirstAffected)); + } + if (dragFirstAffected) { + SelectedItems::const_iterator i = _selected.constFind(dragFirstAffected); + dragSelecting = (i == _selected.cend() || i.value() != FullItemSel); + } + updateDragSelection(dragSelFrom, dragSelTo, dragSelecting); + } + } else if (_dragAction == Dragging) { + } + + if (textlnkDown()) { + cur = style::cur_pointer; + } else if (_dragAction == Selecting && !_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + if (!_dragSelFrom || !_dragSelTo) { + cur = style::cur_text; + } + } + } + if (_dragAction == Selecting) { + historyWidget->checkSelectingScroll(mousePos); + } else { + updateDragSelection(0, 0, false); + historyWidget->noSelectingScroll(); + } + + if (lnkChanged || cur != _cursor) { + setCursor(_cursor = cur); + } +} + +void HistoryList::updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dragSelTo, bool dragSelecting, bool force) { + if (_dragSelFrom != dragSelFrom || _dragSelTo != dragSelTo || _dragSelecting != dragSelecting) { + _dragSelFrom = dragSelFrom; + _dragSelTo = dragSelTo; + if (_dragSelFrom && _dragSelTo && _dragSelFrom->y + _dragSelFrom->block()->y > _dragSelTo->y + _dragSelTo->block()->y) { + qSwap(_dragSelFrom, _dragSelTo); + } + _dragSelecting = dragSelecting; + force = true; + } + if (!force) return; + + parentWidget()->update(); +} + +void HistoryList::applyDragSelection() { + if (!_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + _selected.clear(); + } + int32 fromy = _dragSelFrom->y + _dragSelFrom->block()->y, toy = _dragSelTo->y + _dragSelTo->block()->y + _dragSelTo->height(); + if (_dragSelecting) { + int32 fromblock = hist->indexOf(_dragSelFrom->block()), fromitem = _dragSelFrom->block()->indexOf(_dragSelFrom); + int32 toblock = hist->indexOf(_dragSelTo->block()), toitem = _dragSelTo->block()->indexOf(_dragSelTo); + if (fromblock >= 0 && fromitem >= 0 && toblock >= 0 && toitem >= 0) { + for (; fromblock <= toblock; ++fromblock) { + HistoryBlock *block = (*hist)[fromblock]; + for (int32 cnt = (fromblock < toblock) ? block->size() : (toitem + 1); fromitem < cnt; ++fromitem) { + HistoryItem *item = (*block)[fromitem]; + if (item->id > 0 && !item->serviceMsg()) { + SelectedItems::iterator i = _selected.find(item); + if (i == _selected.cend()) { + if (_selected.size() >= MaxSelectedItems) break; + _selected.insert(item, FullItemSel); + } else if (i.value() != FullItemSel) { + *i = FullItemSel; + } + } else { + SelectedItems::iterator i = _selected.find(item); + if (i != _selected.cend()) { + _selected.erase(i); + } + } + } + if (_selected.size() >= MaxSelectedItems) break; + fromitem = 0; + } + } + } else { + for (SelectedItems::iterator i = _selected.begin(); i != _selected.cend(); ) { + int32 iy = i.key()->y + i.key()->block()->y; + if (iy >= fromy && iy < toy) { + i = _selected.erase(i); + } else { + ++i; + } + } + } + _dragSelFrom = _dragSelTo = 0; +} + +void HistoryList::showLinkTip() { + TextLinkPtr lnk = textlnkOver(); + if (lnk && !lnk->fullDisplayed()) { + QToolTip::showText(_dragPos, lnk->readable(), App::wnd()); + } +} + +void HistoryList::onParentGeometryChanged() { + bool needToUpdate = (_dragAction != NoDrag || _touchScroll || rect().contains(mapFromGlobal(QCursor::pos()))); + if (needToUpdate) { + dragActionUpdate(QCursor::pos()); + } +} + +MessageField::MessageField(HistoryWidget *history, const style::flatTextarea &st, const QString &ph, const QString &val) : FlatTextarea(history, st, ph, val), history(history) { + connect(this, SIGNAL(changed()), this, SLOT(onChange())); +} + +void MessageField::onChange() { + int newh = ceil(document()->size().height()); + if (newh > st::maxFieldHeight) { + newh = st::maxFieldHeight; + } else if (newh < st::minFieldHeight) { + newh = st::minFieldHeight; + } + + if (height() != newh) { + resize(width(), newh); + emit resized(); + } +} + +void MessageField::onEmojiInsert(EmojiPtr emoji) { + insertEmoji(emoji, textCursor()); +} + +void MessageField::dropEvent(QDropEvent *e) { + FlatTextarea::dropEvent(e); + if (e->isAccepted()) { + App::wnd()->activateWindow(); + } +} + +void MessageField::resizeEvent(QResizeEvent *e) { + FlatTextarea::resizeEvent(e); + onChange(); +} + +bool MessageField::canInsertFromMimeData(const QMimeData *source) const { + if (source->hasImage()) return true; + return FlatTextarea::canInsertFromMimeData(source); +} + +void MessageField::insertFromMimeData(const QMimeData *source) { + if (source->hasImage()) { + QImage img = qvariant_cast(source->imageData()); + if (!img.isNull()) { + history->uploadImage(img); + return; + } + } + return FlatTextarea::insertFromMimeData(source); +} + +void MessageField::focusInEvent(QFocusEvent *e) { + FlatTextarea::focusInEvent(e); + emit focused(); +} + +HistoryHider::HistoryHider(MainWidget *parent, bool forwardSelected) : QWidget(parent), + aOpacity(0, 1), aOpacityFunc(anim::easeOutCirc), hiding(false), offered(0), _forwardRequest(0), + toTextWidth(0), _forwardSelected(forwardSelected), sharedContact(0), shadow(st::boxShadow), + forwardButton(this, lang(lng_forward), st::btnSelectDone), + cancelButton(this, lang(lng_cancel), st::btnSelectCancel) { + + connect(&forwardButton, SIGNAL(clicked()), this, SLOT(forward())); + connect(&cancelButton, SIGNAL(clicked()), this, SLOT(startHide())); + connect(App::wnd()->getTitle(), SIGNAL(hiderClicked()), this, SLOT(startHide())); + + _chooseWidth = st::forwardFont->m.width(lang(lng_forward_choose)); + + resizeEvent(0); + anim::start(this); +} + +HistoryHider::HistoryHider(MainWidget *parent, UserData *sharedContact) : QWidget(parent), + aOpacity(0, 1), aOpacityFunc(anim::easeOutCirc), hiding(false), offered(0), _forwardRequest(0), + toTextWidth(0), _forwardSelected(false), sharedContact(sharedContact), shadow(st::boxShadow), + forwardButton(this, lang(lng_forward), st::btnSelectDone), + cancelButton(this, lang(lng_cancel), st::btnSelectCancel) { + + connect(&forwardButton, SIGNAL(clicked()), this, SLOT(forward())); + connect(&cancelButton, SIGNAL(clicked()), this, SLOT(startHide())); + connect(App::wnd()->getTitle(), SIGNAL(hiderClicked()), this, SLOT(startHide())); + + _chooseWidth = st::forwardFont->m.width(lang(lng_forward_choose)); + + resizeEvent(0); + anim::start(this); +} + +bool HistoryHider::animStep(float64 ms) { + float64 dt = ms / 200; + bool res = true; + if (dt >= 1) { + aOpacity.finish(); + if (hiding) { + QTimer::singleShot(0, this, SLOT(deleteLater())); + } + res = false; + } else { + aOpacity.update(dt, aOpacityFunc); + } + App::wnd()->getTitle()->setHideLevel(aOpacity.current()); + forwardButton.setOpacity(aOpacity.current()); + cancelButton.setOpacity(aOpacity.current()); + update(); + return res; +} + +void HistoryHider::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (!hiding || !cacheForAnim.isNull() || !offered) { + p.setOpacity(aOpacity.current() * st::layerAlpha); + p.fillRect(0, st::titleShadow, width(), height() - st::titleShadow, st::layerBG->b); + p.setOpacity(aOpacity.current()); + } + if (cacheForAnim.isNull() || !offered) { + p.setFont(st::forwardFont->f); + if (offered) { + shadow.paint(p, box); + + // fill bg + p.fillRect(box, st::boxBG->b); + + // paint shadows + p.fillRect(box.x(), box.y() + box.height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, box.width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); + + // paint button sep + p.setPen(st::btnSelectSep->p); + p.drawLine(box.x() + st::btnSelectCancel.width, box.y() + box.height() - st::btnSelectCancel.height, box.x() + st::btnSelectCancel.width, box.y() + box.height() - 1); + + p.setPen(st::black->p); + toText.drawElided(p, box.left() + (box.width() - toTextWidth) / 2, box.top() + st::boxPadding.top(), toTextWidth + 1); + } else { + p.setBrush(st::forwardBG->b); + p.setPen(Qt::NoPen); + int32 w = st::forwardMargins.left() + _chooseWidth + st::forwardMargins.right(), h = st::forwardMargins.top() + st::forwardFont->height + st::forwardMargins.bottom(); + p.drawRoundedRect((width() - w) / 2, (height() - h) / 2, w, h, st::forwardRadius, st::forwardRadius); + + p.setPen(st::white->p); + p.drawText(box, lang(lng_forward_choose), QTextOption(style::al_center)); + } + } else { + p.drawPixmap(box.left(), box.top(), cacheForAnim); + } +} + +void HistoryHider::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + if (offered) { + offered = 0; + resizeEvent(0); + update(); + App::main()->dialogsActivate(); + } else { + startHide(); + } + } else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + if (offered) { + forward(); + } + } +} + +void HistoryHider::mousePressEvent(QMouseEvent *e) { + if (e->button() == Qt::LeftButton) { + if (!box.contains(e->pos())) { + startHide(); + } + } +} + +void HistoryHider::startHide() { + if (hiding) return; + hiding = true; + if (offered) cacheForAnim = grab(box); + if (_forwardRequest) MTP::cancel(_forwardRequest); + aOpacity.start(0); + anim::start(this); +} + +void HistoryHider::forward() { + if (_forwardRequest) return; + + if (!hiding && offered) { + if (sharedContact) { + parent()->onShareContact(offered->id, sharedContact); + } else { + _forwardRequest = parent()->onForward(offered->id, _forwardSelected); + } + } + if (!_forwardRequest) { + startHide(); + } +} + +void HistoryHider::forwardDone() { + _forwardRequest = 0; + startHide(); +} + +MainWidget *HistoryHider::parent() { + return static_cast(parentWidget()); +} + +void HistoryHider::resizeEvent(QResizeEvent *e) { + int32 w = st::forwardWidth, h = st::boxPadding.top() + st::forwardFont->height + st::boxPadding.bottom(); + if (offered) { + forwardButton.show(); + cancelButton.show(); + h += forwardButton.height() + st::scrollDef.bottomsh; + } else { + forwardButton.hide(); + cancelButton.hide(); + } + box = QRect((width() - w) / 2, (height() - h) / 2, w, h); + cancelButton.move(box.x(), box.y() + h - cancelButton.height()); + forwardButton.move(box.x() + box.width() - forwardButton.width(), cancelButton.y()); +} + +void HistoryHider::offerPeer(PeerId peer) { + offered = App::peer(peer); + toText.setText(st::boxFont, lang(sharedContact ? lng_forward_share_contact : lng_forward_confirm).replace(qsl("{recipient}"), offered->chat ? '«' + offered->name + '»' : offered->name), _textNameOptions); + toTextWidth = toText.maxWidth(); + if (toTextWidth > box.width() - st::boxPadding.left() - st::boxPadding.right()) { + toTextWidth = box.width() - st::boxPadding.left() - st::boxPadding.right(); + } + + resizeEvent(0); + update(); + setFocus(); +} + +bool HistoryHider::wasOffered() const { + return !!offered; +} + +HistoryHider::~HistoryHider() { + if (App::wnd()) App::wnd()->getTitle()->setHideLevel(0); + parent()->noHider(this); +} + +HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent), noTypingUpdate(false), serviceImageCacheSize(0), + _scroll(this, st::historyScroll, false), _list(0), histPeer(0), _activePeer(0), histOffset(0), histCount(-1), + hist(0), histPreloading(0), histReadRequestId(0), hiderOffered(false), _histInited(false), + _send(this, lang(lng_send_button), st::btnSend), histRequestsCount(0), + _attachDocument(this, st::btnAttachDocument), _attachPhoto(this, st::btnAttachPhoto), _attachEmoji(this, st::btnAttachEmoji), + confirmImageId(0), loadingChatId(0), loadingRequestId(0), titlePeerTextWidth(0), + _field(this, st::taMsgField, lang(lng_message_ph)), bg(st::msgBG), imageLoader(this), + _attachType(this), _emojiPan(this), _attachDrag(DragStateNone), _attachDragDocument(this), _attachDragPhoto(this), _scrollDelta(0) { + _scroll.setFocusPolicy(Qt::NoFocus); + + setAcceptDrops(true); + + connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onListScroll())); + connect(&_send, SIGNAL(clicked()), this, SLOT(onSend())); + connect(&_attachDocument, SIGNAL(clicked()), this, SLOT(onDocumentSelect())); + connect(&_attachPhoto, SIGNAL(clicked()), this, SLOT(onPhotoSelect())); + connect(&_field, SIGNAL(submitted()), this, SLOT(onSend())); + connect(&_field, SIGNAL(cancelled()), this, SIGNAL(cancelled())); + connect(&_field, SIGNAL(tabbed()), this, SLOT(onFieldTabbed())); + connect(&_field, SIGNAL(resized()), this, SLOT(onFieldResize())); + connect(&_field, SIGNAL(focused()), this, SLOT(onFieldFocused())); + connect(&imageLoader, SIGNAL(imageReady()), this, SLOT(onPhotoReady())); + connect(&imageLoader, SIGNAL(imageFailed(quint64)), this, SLOT(onPhotoFailed(quint64))); + connect(&_field, SIGNAL(changed()), this, SLOT(onTextChange())); + connect(App::wnd()->windowHandle(), SIGNAL(visibleChanged(bool)), this, SLOT(onVisibleChanged())); + connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer())); + connect(&_emojiPan, SIGNAL(emojiSelected(EmojiPtr)), &_field, SLOT(onEmojiInsert(EmojiPtr))); + + _scrollTimer.setSingleShot(false); + + _scroll.hide(); + _scroll.move(0, 0); + _field.hide(); + _field.resize(width() - _send.width() - _attachDocument.width() - _attachEmoji.width(), _send.height() - 2 * st::sendPadding); + _send.hide(); + + _attachDocument.hide(); + _attachPhoto.hide(); + _attachEmoji.hide(); + + _attachDocument.installEventFilter(&_attachType); + _attachPhoto.installEventFilter(&_attachType); + _attachEmoji.installEventFilter(&_emojiPan); + + connect(_attachType.addButton(new IconedButton(this, st::dropdownAttachDocument, lang(lng_attach_file))), SIGNAL(clicked()), this, SLOT(onDocumentSelect())); + connect(_attachType.addButton(new IconedButton(this, st::dropdownAttachPhoto, lang(lng_attach_photo))), SIGNAL(clicked()), this, SLOT(onPhotoSelect())); + _attachType.hide(); + _emojiPan.hide(); + _attachDragDocument.hide(); + _attachDragPhoto.hide(); + connect(&_attachDragDocument, SIGNAL(dropped(QDropEvent*)), this, SLOT(onDocumentDrop(QDropEvent*))); + connect(&_attachDragPhoto, SIGNAL(dropped(QDropEvent*)), this, SLOT(onPhotoDrop(QDropEvent*))); +} + +void HistoryWidget::onTextChange() { + updateTyping(); +} + +void HistoryWidget::updateTyping(bool typing) { + uint64 ms = getms() + 10000; + if (noTypingUpdate || !hist || typing && (hist->myTyping + 5000 > ms) || !typing && (hist->myTyping + 5000 <= ms)) return; + + hist->myTyping = typing ? ms : 0; + if (typing) MTP::send(MTPmessages_SetTyping(histPeer->input, MTP_bool(typing))); +} + +void HistoryWidget::activate() { + if (App::main()->selectingPeer()) { + if (hiderOffered) { +// hiderOffered = false; + App::main()->focusPeerSelect(); + return; + } else { + App::main()->dialogsActivate(); +// App::main()->hidePeerSelect(); + } + } + if (_list) { + if (_selCount) { + _list->setFocus(); + } else { + _field.setFocus(); + } + } +} + +void HistoryWidget::chatLoaded(const MTPmessages_ChatFull &res) { + const MTPDmessages_chatFull &d(res.c_messages_chatFull()); + PeerId peerId = App::peerFromChat(d.vfull_chat.c_chatFull().vid); + if (peerId == loadingChatId) { + loadingRequestId = 0; + } + App::feedUsers(d.vusers); + App::feedChats(d.vchats); + App::feedParticipants(d.vfull_chat.c_chatFull().vparticipants); + PhotoData *photo = App::feedPhoto(d.vfull_chat.c_chatFull().vchat_photo); + if (photo) { + ChatData *chat = App::peer(peerId)->asChat(); + if (chat) { + chat->photoId = photo->id; + photo->chat = chat; + } + } + peerUpdated(App::chat(peerId)); +} + +void HistoryWidget::showPeer(const PeerId &peer, bool force, bool leaveActive) { + if (App::main()->selectingPeer() && !force) { + hiderOffered = true; + App::main()->offerPeer(peer); + return; + } + if (peer) { + App::main()->dialogsClear(); + } + if (hist) { + if (histPeer->id == peer) { + if (hist->unreadBar) hist->unreadBar->destroy(); + checkUnreadLoaded(); + return activate(); + } + updateTyping(false); + } + if (histPreload.size() && _list) { + _list->messagesReceived(histPreload); + histPreload.clear(); + } + if (hist) { + hist->draft = _field.getText(); + hist->draftCur = _field.textCursor(); + if (hist->unreadLoaded && _scroll.scrollTop() + 1 <= _scroll.scrollTopMax()) { + hist->lastWidth = _list->width(); + } else { + hist->lastWidth = 0; + } + hist->lastScrollTop = _scroll.scrollTop(); + if (hist->unreadBar) hist->unreadBar->destroy(); + } + + _scroll.setWidget(0); + if (_list) _list->deleteLater(); + _list = 0; + updateTopBarSelection(); + + if (leaveActive && histPeer) { + _activePeer = histPeer; + } else { + if (!leaveActive) { + _activePeer = 0; + } + if (hist) { + App::main()->dlgUpdated(hist); + } + } + histPeer = peer ? App::peer(peer) : 0; + histOffset = 0; + histReadRequestId = 0; + titlePeerText = QString(); + titlePeerTextWidth = 0; + histRequestsCount = 0; + histCount = -1; + histPreload.clear(); + if (histPreloading) MTP::cancel(histPreloading); + histPreloading = 0; + hist = 0; + _histInited = false; + noSelectingScroll(); + _selCount = 0; + App::main()->topBar()->showSelected(0); + + App::hoveredItem(0); + App::pressedItem(0); + App::hoveredLinkItem(0); + App::pressedLinkItem(0); + App::contextItem(0); + App::mousedItem(0); + + if (peer) { + App::forgetPhotos(); + App::forgetVideos(); + App::forgetAudios(); + App::forgetDocuments(); + serviceImageCacheSize = imageCacheSize(); + MTP::clearLoaderPriorities(); + histInputPeer = histPeer->input; + if (histInputPeer.type() == mtpc_inputPeerEmpty) { // maybe should load user + } + Histories::iterator i = App::histories().find(peer); + if (i == App::histories().end()) { + hist = new History(peer); + i = App::histories().insert(peer, hist); + } else { + hist = i.value(); + } + if (hist->unreadLoaded) { + _scroll.show(); + } + if (hist) { + App::main()->dlgUpdated(hist); + } + histOffset = hist->offset; + _list = new HistoryList(this, &_scroll, hist); + _list->hide(); + _scroll.setWidget(_list); + _list->show(); + + checkUnreadLoaded(); + + App::main()->peerUpdated(histPeer); + + noTypingUpdate = true; + _field.setPlainText(hist->draft); + _field.setFocus(); + if (!hist->draft.isEmpty()) { + _field.setTextCursor(hist->draftCur); + } + noTypingUpdate = false; + + connect(&_scroll, SIGNAL(geometryChanged()), _list, SLOT(onParentGeometryChanged())); + connect(&_scroll, SIGNAL(scrolled()), _list, SLOT(onUpdateSelected())); + } else { + updateControlsVisibility(); + } + emit peerShown(histPeer); + App::main()->topBar()->update(); + update(); +} + +void HistoryWidget::checkUnreadLoaded(bool checkOnlyShow) { + if (!hist) return; + if (hist->unreadLoaded) { + if (checkOnlyShow && !_scroll.isHidden()) return; + if (!animating()) { + if (_scroll.isHidden()) { + _scroll.show(); + if (!_field.isHidden()) update(); + } + } + } else if (checkOnlyShow) { + return; + } + updateListSize(0, true); + if (!animating()) updateControlsVisibility(); + if (hist->unreadLoaded) { + if (!_scroll.isHidden() && !_list->isHidden()) { + onListScroll(); + } + } else { + loadMessages(); + } +} + +void HistoryWidget::updateControlsVisibility() { + if (!hist) { + _scroll.hide(); + _send.hide(); + _field.hide(); + _attachDocument.hide(); + _attachPhoto.hide(); + _attachEmoji.hide(); + _attachType.hide(); + _emojiPan.hide(); + return; + } + + if (hist->unreadLoaded) { + if (!histPeer->chat || !histPeer->asChat()->forbidden) { + _send.show(); + if (cDefaultAttach() == dbidaPhoto) { + _attachPhoto.show(); + } else { + _attachDocument.show(); + } + _attachEmoji.show(); + if (_field.isHidden()) { + _field.show(); + update(); + } + } else { + _send.hide(); + _attachDocument.hide(); + _attachPhoto.hide(); + _attachEmoji.hide(); + _attachType.hide(); + _emojiPan.hide(); + if (!_field.isHidden()) { + _field.hide(); + update(); + } + } + if (hist->unreadCount && App::wnd()->historyIsActive()) { + historyWasRead(); + } + } else { + loadMessages(); + if (!hist->unreadLoaded) { + _scroll.hide(); + _send.hide(); + _attachDocument.hide(); + _attachPhoto.hide(); + _attachEmoji.hide(); + _attachType.hide(); + _emojiPan.hide(); + if (!_field.isHidden()) { + _field.hide(); + update(); + } + } + } +} + +void HistoryWidget::newUnreadMsg(History *history, MsgId msgId) { + if (App::wnd()->historyIsActive()) { + if (hist == history && hist->unreadLoaded) { + historyWasRead(); + if (_scroll.scrollTop() + 1 > _scroll.scrollTopMax()) { + if (history->unreadBar) history->unreadBar->destroy(); + } + } else { + if (hist != history) { + App::wnd()->psNotify(history, msgId); + } + history->setUnreadCount(history->unreadCount + 1); + } + } else { + if (hist == history && hist->unreadLoaded) { + if (_scroll.scrollTop() + 1 > _scroll.scrollTopMax()) { + if (history->unreadBar) history->unreadBar->destroy(); + } + } + App::wnd()->psNotify(history, msgId); + history->setUnreadCount(history->unreadCount + 1); + history->lastWidth = 0; + } +} + +void HistoryWidget::historyToDown(History *history) { + history->lastScrollTop = History::ScrollMax; + if (history == hist) { + _scroll.scrollToY(_scroll.scrollTopMax()); + } +} + +void HistoryWidget::historyWasRead(bool force) { + if (histReadRequestId || !hist || !force && (!hist->unreadCount || !hist->unreadLoaded)) return; + hist->inboxRead(true); + histReadRequestId = MTP::send(MTPmessages_ReadHistory(histPeer->input, MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::partWasRead, histPeer)); +} + +void HistoryWidget::partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result) { + const MTPDmessages_affectedHistory &d(result.c_messages_affectedHistory()); + App::main()->updUpdated(d.vpts.v, 0, 0, d.vseq.v); + + histReadRequestId = 0; + int32 offset = d.voffset.v; + if (!MTP::authedId() || offset <= 0) return; + + histReadRequestId = MTP::send(MTPmessages_ReadHistory(peer->input, MTP_int(0), MTP_int(offset)), rpcDone(&HistoryWidget::partWasRead, peer)); +} + +bool HistoryWidget::messagesFailed(const RPCError &e, mtpRequestId requestId) { + LOG(("RPC Error: %1 %2: %3").arg(e.code()).arg(e.type()).arg(e.description())); + if (histPreloading == requestId) { + histPreloading = 0; + } + return true; +} + +void HistoryWidget::messagesReceived(const MTPmessages_Messages &messages, mtpRequestId requestId) { + if (histPreloading == requestId) { + histPreloading = 0; + } + if (!hist) return; + + PeerId peer = 0; + int32 count = 0; + const QVector *histList = 0; + switch (messages.type()) { + case mtpc_messages_messages: { + const MTPDmessages_messages &data(messages.c_messages_messages()); + App::feedUsers(data.vusers); + App::feedChats(data.vchats); + histList = &data.vmessages.c_vector().v; + count = histList->size(); + } break; + case mtpc_messages_messagesSlice: { + const MTPDmessages_messagesSlice &data(messages.c_messages_messagesSlice()); + App::feedUsers(data.vusers); + App::feedChats(data.vchats); + histList = &data.vmessages.c_vector().v; + count = data.vcount.v; + } break; + } + if (histList && !histList->isEmpty()) { + const MTPmessage &msg(histList->front()); + PeerId from_id(0), to_id(0); + switch (msg.type()) { + case mtpc_message: + from_id = App::peerFromUser(msg.c_message().vfrom_id); + to_id = App::peerFromMTP(msg.c_message().vto_id); + break; + case mtpc_messageForwarded: + from_id = App::peerFromUser(msg.c_messageForwarded().vfrom_id); + to_id = App::peerFromMTP(msg.c_messageForwarded().vto_id); + break; + case mtpc_messageService: + from_id = App::peerFromUser(msg.c_messageService().vfrom_id); + to_id = App::peerFromMTP(msg.c_messageService().vto_id); + break; + } + peer = (to_id == App::peerFromUser(MTP::authedId())) ? from_id : to_id; + } + + if (peer && peer != histPeer->id) return; + + if (histList) { + if (!histOffset) { + addMessagesToFront(*histList); + } else { + histPreload = *histList; + } + + if (histList->size()) { + histOffset += histList->size(); + histCount = count; + } else { + histCount = histOffset; + } + } else { + histCount = histOffset; + if (!hist->unreadLoaded) { + hist->setUnreadCount(hist->msgCount); + } + checkUnreadLoaded(true); + return; + } + + if (histOffset >= histCount && histPreload.size()) { + addMessagesToFront(histPreload); + histPreload.clear(); + loadMessages(); + } else if (histPreload.size()) { + onListScroll(); + } else { + loadMessages(); + } +} + +void HistoryWidget::windowShown() { + if (hist && !_histInited) { + checkUnreadLoaded(); + } + resizeEvent(0); +} + +void HistoryWidget::loadMessages() { + if (!hist) return; + if (histCount >= 0 && histOffset >= histCount) { + if (!hist->unreadLoaded) { + hist->setUnreadCount(hist->msgCount); + } + checkUnreadLoaded(true); + return; + } + + int32 dh = 0; + if (histPreload.size()) { + bool unreadLoaded = hist->unreadLoaded; + addMessagesToFront(histPreload); + histPreload.clear(); + checkUnreadLoaded(true); + if (!unreadLoaded && hist->unreadLoaded) { + return; + } + } + if (!histPreloading && (!hist->unreadLoaded || _scroll.scrollTop() < 3 * _scroll.height())) { + int32 loadCount = histOffset ? MessagesPerPage : MessagesFirstLoad; + histPreloading = MTP::send(MTPmessages_GetHistory(histInputPeer, MTP_int(histOffset), MTP_int(0), MTP_int(loadCount)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed)); + ++histRequestsCount; + if (!hist->unreadLoaded) update(); + } else { + checkUnreadLoaded(true); + } +} + +void HistoryWidget::onListScroll() { + App::checkImageCacheSize(); + + if (histPreloading || !hist || (_list->isHidden() || _scroll.isHidden() || !App::wnd()->windowHandle()->isVisible()) && hist->unreadLoaded) { + checkUnreadLoaded(true); + return; + } + + if (!hist->unreadLoaded || _scroll.scrollTop() < 3 * _scroll.height()) { + loadMessages(); + } else { + checkUnreadLoaded(true); + } +} + +void HistoryWidget::onVisibleChanged() { + QTimer::singleShot(0, this, SLOT(onListScroll())); +} + +QString HistoryWidget::prepareMessage() { + QString result = _field.getText(); + + result = result.replace('\t', qsl(" ")); + + result = result.replace(" --", QString::fromUtf8(" \xe2\x80\x94")); + result = result.replace("-- ", QString::fromUtf8("\xe2\x80\x94 ")); + result = result.replace("<<", qsl("\xab")); + result = result.replace(">>", qsl("\xbb")); + + return (cReplaceEmojis() ? replaceEmojis(result) : result).trimmed(); +} + +void HistoryWidget::onSend() { + if (!hist) return; + + QString text = prepareMessage(); + if (!text.isEmpty()) { + MsgId newId = clientMsgId(); + uint64 randomId = MTP::nonce(); + + App::historyRegRandom(randomId, newId); + + MTPstring msgText(MTP_string(text)); + hist->addToBack(MTP_message(MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(histPeer->id), MTP_bool(true), MTP_bool(true), MTP_int(unixtime()), msgText, MTP_messageMediaEmpty())); + App::main()->historyToDown(hist); + App::main()->dialogsToUp(); + peerMessagesUpdated(); + + MTP::send(MTPmessages_SendMessage(histInputPeer, msgText, MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentDataReceived, randomId)); + _field.setPlainText(""); + } + _field.setFocus(); +} + +mtpRequestId HistoryWidget::onForward(const PeerId &peer, bool forwardSelected) { + if (!_list) return 0; + + HistoryItemSet toForward; + if (forwardSelected) { + _list->fillSelectedItems(toForward, false); + } else if (App::contextItem()) { + toForward.insert(0, App::contextItem()); + } + if (toForward.isEmpty()) return 0; + + if (toForward.size() == 1) { + App::main()->showPeer(peer, false, true); + if (!hist) return 0; + + HistoryItem *item = toForward.cbegin().value(); + uint64 randomId = MTP::nonce(); + HistoryMessage *msg = dynamic_cast(item); + HistoryServiceMsg *srv = dynamic_cast(item); + MsgId newId = 0; + + if (item->id > 0 && msg) { + newId = clientMsgId(); + hist->addToBackForwarded(newId, msg); + MTP::send(MTPmessages_ForwardMessage(histPeer->input, MTP_int(item->id), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId)); + } else if (srv || msg && msg->selectedText(FullItemSel).isEmpty()) { + // newId = clientMsgId(); + // MTP::send(MTPmessages_ForwardMessage(histPeer->input, MTP_int(item->id), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId)); + } else if (msg) { + newId = clientMsgId(); + + MTPstring msgText(MTP_string(msg->selectedText(FullItemSel))); + + hist->addToBack(MTP_message(MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(histPeer->id), MTP_bool(true), MTP_bool(true), MTP_int(unixtime()), msgText, MTP_messageMediaEmpty())); + MTP::send(MTPmessages_SendMessage(histPeer->input, msgText, MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentDataReceived, randomId)); + } + if (newId) { + App::historyRegRandom(randomId, newId); + App::main()->historyToDown(hist); + App::main()->dialogsToUp(); + peerMessagesUpdated(); + onClearSelected(); + } + return 0; + } + + PeerData *toPeer = App::peerLoaded(peer); + if (!toPeer) return 0; + + QVector ids; + ids.reserve(toForward.size()); + for (HistoryItemSet::const_iterator i = toForward.cbegin(), e = toForward.cend(); i != e; ++i) { + ids.push_back(MTP_int(i.value()->id)); + } + return MTP::send(MTPmessages_ForwardMessages(toPeer->input, MTP_vector(ids)), App::main()->rpcDone(&MainWidget::forwardDone, peer)); +} + +void HistoryWidget::onShareContact(const PeerId &peer, UserData *contact) { + if (!contact || contact->phone.isEmpty()) return; + + App::main()->showPeer(peer, false, true); + if (!hist) return; + + uint64 randomId = MTP::nonce(); + MsgId newId = clientMsgId(); + + hist->addToBack(MTP_message(MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(histPeer->id), MTP_bool(true), MTP_bool(true), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaContact(MTP_string(contact->phone), MTP_string(contact->firstName), MTP_string(contact->lastName), MTP_int(int32(contact->id & 0xFFFFFFFF))))); + + MTP::send(MTPmessages_SendMedia(histPeer->input, MTP_inputMediaContact(MTP_string(contact->phone), MTP_string(contact->firstName), MTP_string(contact->lastName)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId)); + + App::historyRegRandom(randomId, newId); + App::main()->historyToDown(hist); + App::main()->dialogsToUp(); + peerMessagesUpdated(); +} + +PeerData *HistoryWidget::peer() const { + return histPeer; +} + +PeerData *HistoryWidget::activePeer() const { + return histPeer ? histPeer : _activePeer; +} + +void HistoryWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back) { + _bgAnimCache = bgAnimCache; + _bgAnimTopBarCache = bgAnimTopBarCache; + _animCache = grab(rect()); + App::main()->topBar()->showAll(); + _animTopBarCache = App::main()->topBar()->grab(QRect(0, 0, width(), st::topBarHeight)); + App::main()->topBar()->hideAll(); + _scroll.hide(); + _attachDocument.hide(); + _attachPhoto.hide(); + _attachEmoji.hide(); + _field.hide(); + _send.hide(); + a_coord = back ? anim::ivalue(-st::introSlideShift, 0) : anim::ivalue(st::introSlideShift, 0); + a_alpha = anim::fvalue(0, 1); + a_bgCoord = back ? anim::ivalue(0, st::introSlideShift) : anim::ivalue(0, -st::introSlideShift); + a_bgAlpha = anim::fvalue(1, 0); + anim::start(this); + App::main()->topBar()->update(); +} + +bool HistoryWidget::animStep(float64 ms) { + float64 fullDuration = st::introSlideDelta + st::introSlideDuration, dt = ms / fullDuration; + float64 dt1 = (ms > st::introSlideDuration) ? 1 : (ms / st::introSlideDuration), dt2 = (ms > st::introSlideDelta) ? (ms - st::introSlideDelta) / (st::introSlideDuration) : 0; + bool res = true; + if (dt2 >= 1) { + res = false; + a_bgCoord.finish(); + a_bgAlpha.finish(); + a_coord.finish(); + a_alpha.finish(); + _bgAnimCache = _animCache = _animTopBarCache = _bgAnimTopBarCache = QPixmap(); + App::main()->topBar()->showAll(); + updateControlsVisibility(); + if (hist && hist->unreadLoaded) { + _scroll.show(); + if (hist->lastScrollTop == History::ScrollMax) { + _scroll.scrollToY(hist->lastScrollTop); + } + onListScroll(); + } + activate(); + } else { + a_bgCoord.update(dt1, st::introHideFunc); + a_bgAlpha.update(dt1, st::introAlphaHideFunc); + a_coord.update(dt2, st::introShowFunc); + a_alpha.update(dt2, st::introAlphaShowFunc); + } + update(); + App::main()->topBar()->update(); + return res; +} + +void HistoryWidget::animStop() { + if (!animating()) return; + anim::stop(this); +} + +void HistoryWidget::onPhotoSelect() { + if (!hist) return; + + _attachDocument.clearState(); + _attachDocument.hide(); + _attachPhoto.show(); + _attachType.fastHide(); + + if (cDefaultAttach() != dbidaPhoto) { + cSetDefaultAttach(dbidaPhoto); + App::writeUserConfig(); + } + + QStringList photoExtensions(cPhotoExtensions()); + QStringList imgExtensions(cImgExtensions()); + QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;Photo files (*") + photoExtensions.join(qsl(" *")) + qsl(");;All files (*.*)")); + + QStringList files; + QByteArray file; + if (filedialogGetOpenFiles(files, file, lang(lng_choose_images), filter)) { + if (!file.isEmpty()) { + uploadMedia(file, ToPreparePhoto); + } else if (!files.isEmpty()) { + uploadMedias(files, ToPreparePhoto); + } + } +} + +void HistoryWidget::onDocumentSelect() { + if (!hist) return; + + _attachPhoto.clearState(); + _attachPhoto.hide(); + _attachDocument.show(); + _attachType.fastHide(); + + if (cDefaultAttach() != dbidaDocument) { + cSetDefaultAttach(dbidaDocument); + App::writeUserConfig(); + } + + QStringList photoExtensions(cPhotoExtensions()); + QStringList imgExtensions(cImgExtensions()); + QString filter(qsl("All files (*.*);;Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;Photo files (*") + photoExtensions.join(qsl(" *")) + qsl(")")); + + QStringList files; + QByteArray file; + if (filedialogGetOpenFiles(files, file, lang(lng_choose_images), filter)) { + if (!file.isEmpty()) { + uploadMedia(file, ToPrepareDocument); + } else if (!files.isEmpty()) { + uploadMedias(files, ToPrepareDocument); + } + } +} + + +void HistoryWidget::dragEnterEvent(QDragEnterEvent *e) { + if (!hist) return; + + _attachDrag = getDragState(e->mimeData()); + updateDragAreas(); + + if (_attachDrag) { + e->setDropAction(Qt::IgnoreAction); + e->accept(); + } +} + +void HistoryWidget::dragLeaveEvent(QDragLeaveEvent *e) { + _attachDrag = DragStateNone; + updateDragAreas(); +} + +void HistoryWidget::leaveEvent(QEvent *e) { + _attachDrag = DragStateNone; + updateDragAreas(); +} + +void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) { + _attachDrag = DragStateNone; + updateDragAreas(); +} + +DragState HistoryWidget::getDragState(const QMimeData *d) { + if (!d) return DragStateNone; + + if (d->hasImage()) return DragStateImage; + + QString uriListFormat(qsl("text/uri-list")); + if (!d->hasFormat(uriListFormat)) return DragStateNone; + + QStringList imgExtensions(cImgExtensions()), files; + + const QList &urls(d->urls()); + if (urls.isEmpty()) return DragStateNone; + + bool allAreSmallImages = true; + for (QList::const_iterator i = urls.cbegin(), en = urls.cend(); i != en; ++i) { + if (!i->isLocalFile()) return DragStateNone; + + QString file(i->toLocalFile()); + quint64 s = QFileInfo(file).size(); + if (s >= MaxUploadDocumentSize) { + return DragStateNone; + } + if (allAreSmallImages) { + if (s >= MaxUploadPhotoSize) { + allAreSmallImages = false; + } else { + bool foundImageExtension = false; + for (QStringList::const_iterator j = imgExtensions.cbegin(), end = imgExtensions.cend(); j != end; ++j) { + if (file.right(j->size()).toLower() == (*j).toLower()) { + foundImageExtension = true; + break; + } + } + if (!foundImageExtension) { + allAreSmallImages = false; + } + } + } + } + return allAreSmallImages ? DragStatePhotoFiles : DragStateFiles; +} + +void HistoryWidget::updateDragAreas() { + _field.setAcceptDrops(!_attachDrag); + switch (_attachDrag) { + case DragStateNone: + _attachDragDocument.otherLeave(); + _attachDragPhoto.otherLeave(); + break; + case DragStateFiles: + _attachDragDocument.otherEnter(); + _attachDragDocument.setText(lang(lng_drag_files_here), lang(lng_drag_to_send_documents)); + _attachDragPhoto.fastHide(); + break; + case DragStatePhotoFiles: + _attachDragDocument.otherEnter(); + _attachDragDocument.setText(lang(lng_drag_images_here), lang(lng_drag_to_send_no_compression)); + _attachDragPhoto.otherEnter(); + _attachDragPhoto.setText(lang(lng_drag_photos_here), lang(lng_drag_to_send_quick)); + break; + case DragStateImage: + _attachDragDocument.fastHide(); + _attachDragPhoto.otherEnter(); + _attachDragPhoto.setText(lang(lng_drag_images_here), lang(lng_drag_to_send_quick)); + break; + }; + resizeEvent(0); +} + +void HistoryWidget::dropEvent(QDropEvent *e) { + _attachDrag = DragStateNone; + updateDragAreas(); + e->acceptProposedAction(); +} + +void HistoryWidget::onDocumentDrop(QDropEvent *e) { + if (!hist) return; + + QStringList files = getMediasFromMime(e->mimeData()); + if (files.isEmpty()) return; + + uploadMedias(files, ToPrepareDocument); +} + +void HistoryWidget::onPhotoDrop(QDropEvent *e) { + if (!hist) return; + + if (e->mimeData()->hasImage()) { + QImage image = qvariant_cast(e->mimeData()->imageData()); + if (image.isNull()) return; + + uploadImage(image); + } else { + QStringList files = getMediasFromMime(e->mimeData()); + if (files.isEmpty()) return; + + uploadMedias(files, ToPreparePhoto); + } +} + +void HistoryWidget::contextMenuEvent(QContextMenuEvent *e) { + if (!_list) return; + + return _list->showContextMenu(e); +} + +void HistoryWidget::deleteMessage() { + HistoryItem *item = App::contextItem(); + if (!item || item->itemType() != HistoryItem::MsgType) return; + + HistoryMessage *msg = dynamic_cast(item); + App::main()->deleteLayer((msg && msg->uploading()) ? -2 : -1); +} + +void HistoryWidget::forwardMessage() { + HistoryItem *item = App::contextItem(); + if (!item || item->itemType() != HistoryItem::MsgType) return; + + App::main()->forwardLayer(); +} + +void HistoryWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) { + if (animating()) { + p.setOpacity(a_bgAlpha.current()); + p.drawPixmap(a_bgCoord.current(), 0, _bgAnimTopBarCache); + p.setOpacity(a_alpha.current()); + p.drawPixmap(a_coord.current(), 0, _animTopBarCache); + return; + } + + if (!hist) return; + + QRect rectForName(st::topBarForwardPadding.left(), st::topBarForwardPadding.top(), width() - decreaseWidth - st::topBarForwardPadding.left() - st::topBarForwardPadding.right(), st::msgNameFont->height); + p.setFont(st::dlgHistFont->f); + if (hist->typing.isEmpty()) { + p.setPen(st::titleStatusColor->p); + p.drawText(rectForName.x(), st::topBarHeight - st::topBarForwardPadding.bottom() - st::dlgHistFont->height + st::dlgHistFont->ascent, titlePeerText); + } else { + p.setPen(st::titleTypingColor->p); + hist->typingText.drawElided(p, rectForName.x(), st::topBarHeight - st::topBarForwardPadding.bottom() - st::dlgHistFont->height, rectForName.width()); + } + + p.setPen(st::dlgNameColor->p); + hist->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); + + if (!decreaseWidth) { + p.setOpacity(st::topBarForwardAlpha + (1 - st::topBarForwardAlpha) * over); + p.drawPixmap(QPoint(width() - (st::topBarForwardPadding.right() + st::topBarForwardImg.width()) / 2, (st::topBarHeight - st::topBarForwardImg.height()) / 2), App::sprite(), st::topBarForwardImg); + } +} + +void HistoryWidget::topBarClick() { + if (hist) App::main()->showPeerProfile(histPeer); +} + +void HistoryWidget::updateOnlineDisplay(int32 x, int32 w) { + if (!hist) return; + + QString text; + int32 t = unixtime(); + if (histPeer->chat) { + ChatData *chat = histPeer->asChat(); + if (chat->forbidden || chat->count <= 0) { + text = lang(lng_chat_no_members); + } else if (chat->participants.isEmpty()) { + text = titlePeerText.isEmpty() ? lang(lng_chat_members).arg(chat->count) : titlePeerText; + } else { + int32 onlineCount = 0; + for (ChatData::Participants::const_iterator i = chat->participants.cbegin(), e = chat->participants.cend(); i != e; ++i) { + if (i.key()->onlineTill > t) { + ++onlineCount; + } + } + if (onlineCount) { + text = lang(lng_chat_members_online).arg(chat->participants.size()).arg(onlineCount); + } else { + text = lang(lng_chat_members).arg(chat->participants.size()); + } + } + } else { + text = App::onlineText(histPeer->asUser()->onlineTill, t); + } + if (titlePeerText != text) { + titlePeerText = text; + titlePeerTextWidth = st::dlgHistFont->m.width(titlePeerText); + App::main()->topBar()->update(); + } + updateOnlineDisplayTimer(); +} + +void HistoryWidget::updateOnlineDisplayTimer() { + if (!hist) return; + + int32 t = unixtime(), minIn = 86400; + if (histPeer->chat) { + ChatData *chat = histPeer->asChat(); + if (chat->participants.isEmpty()) return; + + for (ChatData::Participants::const_iterator i = chat->participants.cbegin(), e = chat->participants.cend(); i != e; ++i) { + int32 onlineWillChangeIn = App::onlineWillChangeIn(i.key()->onlineTill, t); + if (onlineWillChangeIn < minIn) { + minIn = onlineWillChangeIn; + } + } + } else { + minIn = App::onlineWillChangeIn(histPeer->asUser()->onlineTill, t); + } + App::main()->updateOnlineDisplayIn(minIn * 1000); +} + +void HistoryWidget::onFieldResize() { + _field.move(_attachDocument.x() + _attachDocument.width(), height() - _field.height() - st::sendPadding); + updateListSize(); +} + +void HistoryWidget::onFieldFocused() { + if (_list) _list->clearSelectedItems(true); +} + +void HistoryWidget::uploadImage(const QImage &img) { + if (!hist || confirmImageId) return; + + App::wnd()->activateWindow(); + confirmImageId = imageLoader.append(img, histPeer->id, ToPreparePhoto); +} + +void HistoryWidget::uploadMedias(const QStringList &files, ToPrepareMediaType type) { + if (!hist) return; + + App::wnd()->activateWindow(); + imageLoader.append(files, histPeer->id, type); +} + +void HistoryWidget::uploadMedia(const QByteArray &fileContent, ToPrepareMediaType type) { + if (!hist) return; + + App::wnd()->activateWindow(); + imageLoader.append(fileContent, histPeer->id, type); +} + +void HistoryWidget::onPhotoReady() { + QMutexLocker lock(imageLoader.readyMutex()); + ReadyLocalMedias &list(imageLoader.readyList()); + + for (ReadyLocalMedias::const_iterator i = list.cbegin(), e = list.cend(); i != e; ++i) { + if (i->id == confirmImageId) { + App::wnd()->showLayer(new PhotoSendBox(*i)); + } else { + confirmSendImage(*i); + } + } + list.clear(); +} + +void HistoryWidget::onPhotoFailed(quint64 id) { + id = id; +} + +void HistoryWidget::confirmSendImage(const ReadyLocalMedia &img) { + if (img.id == confirmImageId) { + confirmImageId = 0; + } + MsgId newId = clientMsgId(); + + connect(App::uploader(), SIGNAL(photoReady(MsgId, const MTPInputFile &)), this, SLOT(onPhotoUploaded(MsgId, const MTPInputFile &)), Qt::UniqueConnection); + connect(App::uploader(), SIGNAL(documentReady(MsgId, const MTPInputFile &)), this, SLOT(onDocumentUploaded(MsgId, const MTPInputFile &)), Qt::UniqueConnection); + connect(App::uploader(), SIGNAL(thumbDocumentReady(MsgId, const MTPInputFile &, const MTPInputFile &)), this, SLOT(onThumbDocumentUploaded(MsgId, const MTPInputFile &, const MTPInputFile &)), Qt::UniqueConnection); +// connect(App::uploader(), SIGNAL(photoProgress(MsgId)), this, SLOT(onPhotoProgress(MsgId)), Qt::UniqueConnection); + connect(App::uploader(), SIGNAL(documentProgress(MsgId)), this, SLOT(onDocumentProgress(MsgId)), Qt::UniqueConnection); +// connect(App::uploader(), SIGNAL(photoFailed(MsgId)), this, SLOT(onPhotoFailed(MsgId)), Qt::UniqueConnection); + connect(App::uploader(), SIGNAL(documentFailed(MsgId)), this, SLOT(onDocumentFailed(MsgId)), Qt::UniqueConnection); + + App::uploader()->uploadMedia(newId, img); + + if (img.type == ToPreparePhoto) { + App::history(img.peer)->addToBack(MTP_message(MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTP_bool(true), MTP_bool(true), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(img.photo))); + } else if (img.type == ToPrepareDocument) { + App::history(img.peer)->addToBack(MTP_message(MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTP_bool(true), MTP_bool(true), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(img.document))); + } + + if (hist && histPeer && img.peer == histPeer->id) App::main()->historyToDown(hist); + App::main()->dialogsToUp(); + peerMessagesUpdated(img.peer); +} + +void HistoryWidget::cancelSendImage() { + confirmImageId = 0; +} + +void HistoryWidget::onPhotoUploaded(MsgId newId, const MTPInputFile &file) { + if (!MTP::authedId()) return; + HistoryItem *item = App::histItemById(newId); + if (item) { + uint64 randomId = MTP::nonce(); + App::historyRegRandom(randomId, newId); + MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedPhoto(file), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId)); + } +} + +void HistoryWidget::onDocumentUploaded(MsgId newId, const MTPInputFile &file) { + if (!MTP::authedId()) return; + HistoryMessage *item = dynamic_cast(App::histItemById(newId)); + if (item) { + HistoryDocument *media = dynamic_cast(item->getMedia()); + if (media) { + uint64 randomId = MTP::nonce(); + App::historyRegRandom(randomId, newId); + DocumentData *document = media->document(); + MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedDocument(file, MTP_string(document->name), MTP_string(document->mime)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId)); + } + } +} + +void HistoryWidget::onThumbDocumentUploaded(MsgId newId, const MTPInputFile &file, const MTPInputFile &thumb) { + if (!MTP::authedId()) return; + HistoryMessage *item = dynamic_cast(App::histItemById(newId)); + if (item) { + HistoryDocument *media = dynamic_cast(item->getMedia()); + if (media) { + uint64 randomId = MTP::nonce(); + App::historyRegRandom(randomId, newId); + DocumentData *document = media->document(); + MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedThumbDocument(file, thumb, MTP_string(document->name), MTP_string(document->mime)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId)); + } + } +} + +void HistoryWidget::onDocumentProgress(MsgId newId) { + if (!MTP::authedId()) return; + HistoryItem *item = App::histItemById(newId); + if (item) { + msgUpdated(item->history()->peer->id, item); + } +} + +void HistoryWidget::onDocumentFailed(MsgId newId) { + if (!MTP::authedId()) return; + HistoryItem *item = App::histItemById(newId); + if (item) { + msgUpdated(item->history()->peer->id, item); + } +} + +void HistoryWidget::peerMessagesUpdated(PeerId peer) { + if (histPeer && _list && peer == histPeer->id) { + updateListSize(); + } +} + +void HistoryWidget::peerMessagesUpdated() { + if (_list) updateListSize(); +} + +void HistoryWidget::msgUpdated(PeerId peer, HistoryItem *msg) { + if (histPeer && _list && peer == histPeer->id) { + _list->updateMsg(msg); + } +} + +void HistoryWidget::resizeEvent(QResizeEvent *e) { + _attachDocument.move(0, height() - _attachDocument.height()); + _attachPhoto.move(_attachDocument.x(), _attachDocument.y()); + + _field.move(_attachDocument.x() + _attachDocument.width(), height() - _field.height() - st::sendPadding); + + updateListSize(); + + _field.resize(width() - _send.width() - _attachDocument.width() - _attachEmoji.width(), _field.height()); + _attachEmoji.move(_field.x() + _field.width(), height() - _attachEmoji.height()); + _send.move(width() - _send.width(), _attachDocument.y()); + + _attachType.move(0, _attachDocument.y() - _attachType.height()); + _emojiPan.move(width() - _emojiPan.width(), _attachEmoji.y() - _emojiPan.height()); + + switch (_attachDrag) { + case DragStateFiles: + _attachDragDocument.resize(width() - st::dragMargin.left() - st::dragMargin.right(), height() - st::dragMargin.top() - st::dragMargin.bottom()); + _attachDragDocument.move(st::dragMargin.left(), st::dragMargin.top()); + break; + case DragStatePhotoFiles: + _attachDragDocument.resize(width() - st::dragMargin.left() - st::dragMargin.right(), (height() - st::dragMargin.top() - st::dragMargin.bottom()) / 2); + _attachDragDocument.move(st::dragMargin.left(), st::dragMargin.top()); + _attachDragPhoto.resize(_attachDragDocument.width(), _attachDragDocument.height()); + _attachDragPhoto.move(st::dragMargin.left(), height() - _attachDragPhoto.height() - st::dragMargin.bottom()); + break; + case DragStateImage: + _attachDragPhoto.resize(width() - st::dragMargin.left() - st::dragMargin.right(), height() - st::dragMargin.top() - st::dragMargin.bottom()); + _attachDragPhoto.move(st::dragMargin.left(), st::dragMargin.top()); + break; + } +} + +void HistoryWidget::updateListSize(int32 addToY, bool initial) { + if (!hist || !_histInited && !initial) return; + + if (!App::wnd()->isVisible()) return; // scrollTopMax etc are not working after recountHeight() + + int32 newScrollHeight = height() - (hist->unreadLoaded && (!histPeer->chat || !histPeer->asChat()->forbidden) ? (_field.height() + 2 * st::sendPadding) : 0); + bool wasAtBottom = _scroll.scrollTop() + 1 > _scroll.scrollTopMax(), needResize = _scroll.width() != width() || _scroll.height() != newScrollHeight; + if (needResize) { + _scroll.resize(width(), newScrollHeight); + } + + if (!initial) { + hist->lastScrollTop = _scroll.scrollTop(); + } + int32 newSt = _list->recountHeight(); + bool washidden = _scroll.isHidden(); + if (washidden) { + _scroll.show(); + } + _list->updateSize(); + if (washidden) { + _scroll.hide(); + } + if (!hist->unreadLoaded) return; + + if (!initial && !wasAtBottom) { + _scroll.scrollToY(newSt + addToY); + return; + } + if (!hist->unreadLoaded) return; + + if (initial) { + _histInited = true; + } + + int32 toY = History::ScrollMax; + if (initial && hist->unreadBar) { + toY = hist->unreadBar->y + hist->unreadBar->block()->y; + } else if (hist->showFrom) { + toY = hist->showFrom->y + hist->showFrom->block()->y; + if (toY < _scroll.scrollTopMax() + st::unreadBarHeight) { + hist->addUnreadBar(); + if (hist->unreadBar) { + return updateListSize(0, true); + } + } + } else if (initial && hist->lastWidth) { + toY = newSt; + hist->lastWidth = 0; + } else { + int blabla = 0; + } + _scroll.scrollToY(toY); +} + +void HistoryWidget::addMessagesToFront(const QVector &messages) { + int32 oldH = hist->height; + _list->messagesReceived(messages); + updateListSize(hist->height - oldH); + checkUnreadLoaded(true); +} + +void HistoryWidget::mousePressEvent(QMouseEvent *e) { +} + +void HistoryWidget::keyPressEvent(QKeyEvent *e) { + if (!hist) return; + + if (e->key() == Qt::Key_Escape) { + e->ignore(); + } else if (e->key() == Qt::Key_PageDown) { + if (e->modifiers() & Qt::ControlModifier) { + PeerData *after = App::main()->peerAfter(histPeer); + if (after) App::main()->showPeer(after->id); + } else { + _scroll.scrollToY(_scroll.scrollTop() + _scroll.height()); + } + } else if (e->key() == Qt::Key_PageUp) { + if (e->modifiers() & Qt::ControlModifier) { + PeerData *before = App::main()->peerBefore(histPeer); + if (before) App::main()->showPeer(before->id); + } else { + _scroll.scrollToY(_scroll.scrollTop() - _scroll.height()); + } + } else if (e->key() == Qt::Key_Down) { + _scroll.scrollToY(_scroll.scrollTop() + _scroll.height() / 10); + } else if (e->key() == Qt::Key_Up) { + _scroll.scrollToY(_scroll.scrollTop() - _scroll.height() / 10); + } else { + e->ignore(); + } +} + +void HistoryWidget::onFieldTabbed() { + QString v = _field.getText(), t = supportTemplate(v.trimmed()); + if (!t.isEmpty()) { + if (t.indexOf(qsl("img:")) == 0) { + QImage img(cWorkingDir() + t.mid(4).trimmed()); + if (!img.isNull()) { + _field.setPlainText(QString()); + uploadImage(img); + } + } else { + _field.setPlainText(t); + QTextCursor c = _field.textCursor(); + c.movePosition(QTextCursor::End); + _field.setTextCursor(c); + } + } +} + +void HistoryWidget::peerUpdated(PeerData *data) { + if (data && data == histPeer) { + updateListSize(); + if (!animating()) updateControlsVisibility(); + if (data->chat && data->asChat()->count > 0 && data->asChat()->participants.isEmpty() && (!loadingRequestId || loadingChatId != data->id)) { + loadingChatId = data->id; + loadingRequestId = MTP::send(MTPmessages_GetFullChat(App::peerToMTP(data->id).c_peerChat().vchat_id), rpcDone(&HistoryWidget::chatLoaded)); + } + App::main()->updateOnlineDisplay(); + } +} + +void HistoryWidget::onForwardSelected() { + if (!_list) return; + App::main()->forwardLayer(true); +} + +void HistoryWidget::onDeleteSelected() { + if (!_list) return; + + HistoryItemSet sel; + _list->fillSelectedItems(sel); + if (sel.isEmpty()) return; + + App::main()->deleteLayer(sel.size()); +} + +void HistoryWidget::onDeleteSelectedSure() { + if (!_list) return; + + HistoryItemSet sel; + _list->fillSelectedItems(sel); + if (sel.isEmpty()) return; + + QVector ids; + for (HistoryItemSet::const_iterator i = sel.cbegin(), e = sel.cend(); i != e; ++i) { + if (i.value()->id > 0) { + ids.push_back(MTP_int(i.value()->id)); + } + } + + if (!ids.isEmpty()) { + MTP::send(MTPmessages_DeleteMessages(MTP_vector(ids))); + } + + onClearSelected(); + for (HistoryItemSet::const_iterator i = sel.cbegin(), e = sel.cend(); i != e; ++i) { + i.value()->destroy(); + } + App::wnd()->hideLayer(); +} + +void HistoryWidget::onDeleteContextSure() { + HistoryItem *item = App::contextItem(); + if (!item || item->itemType() != HistoryItem::MsgType) { + return; + } + + if (item->id > 0) { + MTP::send(MTPmessages_DeleteMessages(MTP_vector(QVector(1, MTP_int(item->id))))); + } + item->destroy(); + App::wnd()->hideLayer(); +} + +void HistoryWidget::onClearSelected() { + if (_list) _list->clearSelectedItems(); +} + +void HistoryWidget::updateTopBarSelection() { + if (!_list) { + App::main()->topBar()->showSelected(0); + return; + } + + int32 selectedForForward, selectedForDelete; + _list->getSelectionState(selectedForForward, selectedForDelete); + _selCount = selectedForDelete ? selectedForDelete : selectedForForward; + App::main()->topBar()->showSelected(_selCount > 0 ? _selCount : 0); + updateControlsVisibility(); + updateListSize(); + if (_selCount) { + _list->setFocus(); + } else { + _field.setFocus(); + } + App::main()->topBar()->update(); + update(); +} + +void HistoryWidget::paintEvent(QPaintEvent *e) { + QPainter p(this); + QRect r(e->rect()); + if (r != rect()) { + p.setClipRect(r); + } + if (animating()) { + p.setOpacity(a_bgAlpha.current()); + p.drawPixmap(a_bgCoord.current(), 0, _bgAnimCache); + p.setOpacity(a_alpha.current()); + p.drawPixmap(a_coord.current(), 0, _animCache); + return; + } + if (cCatsAndDogs()) { + int32 i_from = r.left() / bg.width(), i_to = (r.left() + r.width() - 1) / bg.width() + 1; + int32 j_from = r.top() / bg.height(), j_to = (r.top() + r.height() - 1) / bg.height() + 1; + for (int32 i = i_from; i < i_to; ++i) { + for (int32 j = j_from; j < j_to; ++j) { + p.drawPixmap(i * bg.width(), j * bg.height(), bg); + } + } + } else { + p.fillRect(r, st::historyBG->b); + } + if (_list) { + if (!_scroll.isHidden()) { + if (!_field.isHidden()) { + p.fillRect(0, _field.y() - st::sendPadding, width(), _field.height() + 2 * st::sendPadding, st::taMsgField.bgColor->b); + } + } else { + QPoint dogPos((width() - st::msgDogImg.width()) / 2, ((height() - _field.height() - 2 * st::sendPadding - st::msgDogImg.height()) * 4) / 9); + p.drawPixmap(dogPos, App::sprite(), st::msgDogImg); + + int32 pointsCount = 8, w = pointsCount * (st::introPointWidth + 2 * st::introPointDelta), h = st::introPointHeight; + int32 pointsLeft = (width() - w) / 2 + st::introPointDelta - st::introPointLeft, pointsTop = dogPos.y() + (st::msgDogImg.height() * 6) / 5; + + int32 curPoint = histRequestsCount % pointsCount; + + p.setOpacity(st::introPointHoverAlpha); + p.fillRect(pointsLeft + curPoint * (st::introPointWidth + 2 * st::introPointDelta), pointsTop, st::introPointHoverWidth, st::introPointHoverHeight, st::introPointHoverColor->b); + + // points + p.setOpacity(st::introPointAlpha); + int x = pointsLeft + st::introPointLeft; + for (uint32 i = 0; i < pointsCount; ++i) { + p.fillRect(x, pointsTop + st::introPointTop, st::introPointWidth, st::introPointHeight, st::introPointColor->b); + x += (st::introPointWidth + 2 * st::introPointDelta); + } + } + } else { + style::font font(st::msgServiceFont); + int32 w = font->m.width(lang(lng_willbe_history)) + st::msgPadding.left() + st::msgPadding.right(), h = font->height + st::msgServicePadding.top() + st::msgServicePadding.bottom() + 2; + QRect tr((width() - w) / 2, (height() - _field.height() - 2 * st::sendPadding - h) / 2, w, h); + p.setPen(Qt::NoPen); + p.setBrush(st::msgServiceBG->b); + p.drawRoundedRect(tr, st::msgServiceRadius, st::msgServiceRadius); + + p.setPen(st::msgServiceColor->p); + p.setFont(font->f); + p.drawText(tr.left() + st::msgPadding.left(), tr.top() + st::msgServicePadding.top() + 1 + font->ascent, lang(lng_willbe_history)); + } +} + +bool HistoryWidget::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + if (_list && _list->getPhotoCoords(photo, x, y, w)) { + x += _list->x(); + y += _list->y(); + return true; + } + return false; +} + +bool HistoryWidget::getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const { + if (_list && _list->getVideoCoords(video, x, y, w)) { + x += _list->x(); + y += _list->y(); + return true; + } + return false; +} + +QRect HistoryWidget::historyRect() const { + return _scroll.geometry(); +} + +void HistoryWidget::destroyData() { + showPeer(0); +} + +QStringList HistoryWidget::getMediasFromMime(const QMimeData *d) { + QString uriListFormat(qsl("text/uri-list")); + QStringList photoExtensions(cPhotoExtensions()), files; + if (!d->hasFormat(uriListFormat)) return QStringList(); + + const QList &urls(d->urls()); + if (urls.isEmpty()) return QStringList(); + + files.reserve(urls.size()); + for (QList::const_iterator i = urls.cbegin(), en = urls.cend(); i != en; ++i) { + if (!i->isLocalFile()) return QStringList(); + + QString file(i->toLocalFile()); + QFileInfo info(file); + uint64 s = info.size(); + if (s >= MaxUploadDocumentSize) { + if (s >= MaxUploadPhotoSize) { + continue; + } else { + bool foundGoodExtension = false; + for (QStringList::const_iterator j = photoExtensions.cbegin(), end = photoExtensions.cend(); j != end; ++j) { + if (file.right(j->size()).toLower() == (*j).toLower()) { + foundGoodExtension = true; + } + } + if (!foundGoodExtension) { + continue; + } + } + } + files.push_back(file); + } + return files; +} + +QPoint HistoryWidget::clampMousePosition(QPoint point) { + if (point.x() < 0) { + point.setX(0); + } else if (point.x() >= _scroll.width()) { + point.setX(_scroll.width() - 1); + } + if (point.y() < _scroll.scrollTop()) { + point.setY(_scroll.scrollTop()); + } else if (point.y() >= _scroll.scrollTop() + _scroll.height()) { + point.setY(_scroll.scrollTop() + _scroll.height() - 1); + } + return point; +} + +void HistoryWidget::onScrollTimer() { + int32 d = (_scrollDelta > 0) ? qMin(_scrollDelta * 3 / 20 + 1, int32(MaxScrollSpeed)) : qMax(_scrollDelta * 3 / 20 - 1, -int32(MaxScrollSpeed)); + _scroll.scrollToY(_scroll.scrollTop() + d); +} + +void HistoryWidget::checkSelectingScroll(QPoint point) { + if (point.y() < _scroll.scrollTop()) { + _scrollDelta = point.y() - _scroll.scrollTop(); + } else if (point.y() >= _scroll.scrollTop() + _scroll.height()) { + _scrollDelta = point.y() - _scroll.scrollTop() - _scroll.height() + 1; + } else { + _scrollDelta = 0; + } + if (_scrollDelta) { + _scrollTimer.start(15); + } else { + _scrollTimer.stop(); + } +} + +void HistoryWidget::noSelectingScroll() { + _scrollTimer.stop(); +} + +bool HistoryWidget::touchScroll(const QPoint &delta) { + int32 scTop = _scroll.scrollTop(), scMax = _scroll.scrollTopMax(), scNew = snap(scTop - delta.y(), 0, scMax); + if (scNew == scTop) return false; + + _scroll.scrollToY(scNew); + return true; +} + +HistoryWidget::~HistoryWidget() { + delete _list; +} diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h new file mode 100644 index 000000000..017d91058 --- /dev/null +++ b/Telegram/SourceFiles/historywidget.h @@ -0,0 +1,427 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "localimageloader.h" +#include "gui/boxshadow.h" + +#include "dropdown.h" + +enum DragState { + DragStateNone = 0x00, + DragStateFiles = 0x01, + DragStatePhotoFiles = 0x02, + DragStateImage = 0x03, +}; + +typedef QMap HistoryItemSet; + +class HistoryWidget; +class HistoryList : public QWidget { + Q_OBJECT + +public: + + HistoryList(HistoryWidget *historyWidget, ScrollArea *scroll, History *history); + + void messagesReceived(const QVector &messages); + + bool event(QEvent *e); // calls touchEvent when necessary + void touchEvent(QTouchEvent *e); + void paintEvent(QPaintEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void resizeEvent(QResizeEvent *e); + void keyPressEvent(QKeyEvent *e); + void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false); + + QString getSelectedText() const; + + void dragActionStart(const QPoint &screenPos, Qt::MouseButton button = Qt::LeftButton); + void dragActionUpdate(const QPoint &screenPos); + void dragActionFinish(const QPoint &screenPos, Qt::MouseButton button = Qt::LeftButton); + void dragActionCancel(); + + void touchScrollUpdated(const QPoint &screenPos); + QPoint mapMouseToItem(QPoint p, HistoryItem *item); + + int32 recountHeight(); + void updateSize(); + + void updateMsg(HistoryItem *msg); + + bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const; + bool getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const; + + void getSelectionState(int32 &selectedForForward, int32 &selectedForDelete) const; + void clearSelectedItems(bool onlyTextSelection = false); + void fillSelectedItems(HistoryItemSet &sel, bool forDelete = true); + + ~HistoryList(); + +public slots: + + void onUpdateSelected(bool force = false); + void onParentGeometryChanged(); + + void showLinkTip(); + + void itemRemoved(HistoryItem *item); + + void openContextUrl(); + void copyContextUrl(); + void saveContextImage(); + void copyContextImage(); + void cancelContextDownload(); + void showContextInFolder(); + void openContextFile(); + void saveContextFile(); + void copyContextText(); + void copySelectedText(); + + void onMenuDestroy(QObject *obj); + void onTouchSelect(); + void onTouchScrollTimer(); + +private: + + void touchResetSpeed(); + void touchUpdateSpeed(); + void touchDeaccelerate(int32 elapsed); + + void adjustCurrent(int32 y); + HistoryItem *prevItem(HistoryItem *item); + HistoryItem *nextItem(HistoryItem *item); + void updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dragSelTo, bool dragSelecting, bool force = false); + void applyDragSelection(); + + History *hist; + HistoryWidget *historyWidget; + ScrollArea *scrollArea; + int32 currentBlock, currentItem; + + QTimer linkTipTimer; + + Qt::CursorShape _cursor; + typedef QMap SelectedItems; + SelectedItems _selected; + enum DragAction { + NoDrag = 0x00, + PrepareDrag = 0x01, + Dragging = 0x02, + PrepareSelect = 0x03, + Selecting = 0x04, + }; + DragAction _dragAction; + TextSelectType _dragSelType; + QPoint _dragStartPos, _dragPos; + HistoryItem *_dragItem; + uint16 _dragSymbol; + bool _dragWasInactive; + + QPoint _trippleClickPoint; + QTimer _trippleClickTimer; + + TextLinkPtr _contextMenuLnk; + + HistoryItem *_dragSelFrom, *_dragSelTo; + bool _dragSelecting; + + bool _touchScroll, _touchSelect, _touchInProgress; + QPoint _touchStart, _touchPrevPos, _touchPos; + QTimer _touchSelectTimer; + + TouchScrollState _touchScrollState; + bool _touchPrevPosValid, _touchWaitingAcceleration; + QPoint _touchSpeed; + uint64 _touchSpeedTime, _touchAccelerationTime, _touchTime; + QTimer _touchScrollTimer; + + QMenu *_menu; + +}; + +class MessageField : public FlatTextarea { + Q_OBJECT + +public: + MessageField(HistoryWidget *history, const style::flatTextarea &st, const QString &ph = QString(), const QString &val = QString()); + void dropEvent(QDropEvent *e); + void resizeEvent(QResizeEvent *e); + bool canInsertFromMimeData(const QMimeData *source) const; + void insertFromMimeData(const QMimeData *source); + + void focusInEvent(QFocusEvent *e); + +public slots: + + void onChange(); + void onEmojiInsert(EmojiPtr emoji); + +signals: + + void resized(); + void focused(); + +private: + HistoryWidget *history; +}; + +class HistoryHider : public QWidget, public Animated { + Q_OBJECT + +public: + + HistoryHider(MainWidget *parent, bool forwardSelected); + HistoryHider(MainWidget *parent, UserData *sharedContact); + + bool animStep(float64 ms); + + void paintEvent(QPaintEvent *e); + void keyPressEvent(QKeyEvent *e); + void mousePressEvent(QMouseEvent *e); + void resizeEvent(QResizeEvent *e); + + void offerPeer(PeerId peer); + + bool wasOffered() const; + + void forwardDone(); + + ~HistoryHider(); + +public slots: + + void startHide(); + void forward(); + +private: + + MainWidget *parent(); + + UserData *sharedContact; + bool _forwardSelected; + + FlatButton forwardButton; + FlatButton cancelButton; + PeerData *offered; + anim::fvalue aOpacity; + anim::transition aOpacityFunc; + QRect box; + bool hiding; + + mtpRequestId _forwardRequest; + + int32 _chooseWidth; + + Text toText; + int32 toTextWidth; + QPixmap cacheForAnim; + + BoxShadow shadow; + +}; + +class HistoryWidget : public QWidget, public RPCSender, public Animated { + Q_OBJECT + +public: + + HistoryWidget(QWidget *parent); + + void messagesReceived(const MTPmessages_Messages &messages, mtpRequestId requestId); + + void windowShown(); + + void resizeEvent(QResizeEvent *e); + void keyPressEvent(QKeyEvent *e); + void mousePressEvent(QMouseEvent *e); + void paintEvent(QPaintEvent *e); + void dragEnterEvent(QDragEnterEvent *e); + void dragLeaveEvent(QDragLeaveEvent *e); + void leaveEvent(QEvent *e); + void dropEvent(QDropEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void contextMenuEvent(QContextMenuEvent *e); + + void updateTopBarSelection(); + + void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth); + void topBarClick(); + + void loadMessages(); + void peerMessagesUpdated(PeerId peer); + void peerMessagesUpdated(); + + void msgUpdated(PeerId peer, HistoryItem *msg); + void newUnreadMsg(History *history, MsgId msgId); + void historyToDown(History *history); + void historyWasRead(bool force = true); + + bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const; + bool getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const; + QRect historyRect() const; + + void updateTyping(bool typing = true); + + void destroyData(); + void uploadImage(const QImage &img); + void uploadMedias(const QStringList &files, ToPrepareMediaType type); + void uploadMedia(const QByteArray &fileContent, ToPrepareMediaType type); + void confirmSendImage(const ReadyLocalMedia &img); + void cancelSendImage(); + + void checkUnreadLoaded(bool checkOnlyShow = false); + void updateControlsVisibility(); + void updateOnlineDisplay(int32 x, int32 w); + void updateOnlineDisplayTimer(); + + mtpRequestId onForward(const PeerId &peer, bool forwardSelected); + void onShareContact(const PeerId &peer, UserData *contact); + + PeerData *peer() const; + PeerData *activePeer() const; + + void animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false); + bool animStep(float64 ms); + void animStop(); + + QPoint clampMousePosition(QPoint point); + + void checkSelectingScroll(QPoint point); + void noSelectingScroll(); + + bool touchScroll(const QPoint &delta); + + ~HistoryWidget(); + +signals: + + void cancelled(); + void peerShown(PeerData *); + +public slots: + + void peerUpdated(PeerData *data); + + void onPhotoUploaded(MsgId msgId, const MTPInputFile &file); + void onDocumentUploaded(MsgId msgId, const MTPInputFile &file); + void onThumbDocumentUploaded(MsgId msgId, const MTPInputFile &file, const MTPInputFile &thumb); + + void onDocumentProgress(MsgId msgId); + + void onDocumentFailed(MsgId msgId); + + void onListScroll(); + void onSend(); + + void onPhotoSelect(); + void onDocumentSelect(); + void onPhotoDrop(QDropEvent *e); + void onDocumentDrop(QDropEvent *e); + + void onPhotoReady(); + void onPhotoFailed(quint64 id); + void showPeer(const PeerId &peer, bool force = false, bool leaveActive = false); + void activate(); + void onTextChange(); + + void onFieldTabbed(); + + void onVisibleChanged(); + + void forwardMessage(); + void deleteMessage(); + + void onFieldFocused(); + void onFieldResize(); + void onScrollTimer(); + + void onForwardSelected(); + void onDeleteSelected(); + void onDeleteSelectedSure(); + void onDeleteContextSure(); + void onClearSelected(); + +private: + + bool messagesFailed(const RPCError &error, mtpRequestId requestId); + void partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result); + void updateListSize(int32 addToY = 0, bool initial = false); + void addMessagesToFront(const QVector &messages); + void chatLoaded(const MTPmessages_ChatFull &res); + + QStringList getMediasFromMime(const QMimeData *d); + DragState getDragState(const QMimeData *d); + + void updateDragAreas(); + + QString prepareMessage(); + + int32 histOffset, histCount, histReadRequestId; + int32 histRequestsCount; + PeerData *histPeer, *_activePeer; + MTPinputPeer histInputPeer; + mtpRequestId histPreloading; + QVector histPreload; + + ScrollArea _scroll; + HistoryList *_list; + History *hist; + bool _histInited; // initial updateListSize() called + + FlatButton _send; + IconedButton _attachDocument, _attachPhoto, _attachEmoji; + MessageField _field; + + Dropdown _attachType; + EmojiPan _emojiPan; + DragState _attachDrag; + DragArea _attachDragDocument, _attachDragPhoto; + + int32 _selCount; // < 0 - text selected, focus list, not _field + + LocalImageLoader imageLoader; + bool noTypingUpdate; + + PeerId loadingChatId; + mtpRequestId loadingRequestId; + + int64 serviceImageCacheSize; + PhotoId confirmImageId; + + QString titlePeerText; + int32 titlePeerTextWidth; + + QPixmap bg; + + bool hiderOffered; + + QPixmap _animCache, _bgAnimCache, _animTopBarCache, _bgAnimTopBarCache; + anim::ivalue a_coord, a_bgCoord; + anim::fvalue a_alpha, a_bgAlpha; + + QTimer _scrollTimer; + int32 _scrollDelta; + +}; + diff --git a/Telegram/SourceFiles/intro/intro.cpp b/Telegram/SourceFiles/intro/intro.cpp new file mode 100644 index 000000000..c6b8b9a7b --- /dev/null +++ b/Telegram/SourceFiles/intro/intro.cpp @@ -0,0 +1,297 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" +#include "style.h" + +#include "intro/intro.h" +#include "intro/introsteps.h" +#include "intro/introphone.h" +#include "intro/introcode.h" +#include "intro/introsignup.h" +#include "mainwidget.h" +#include "window.h" +#include "application.h" +#include "gui/text.h" + +namespace { + IntroWidget *signalEmitOn = 0; + QString countryForReg; + void gotNearestDC(const MTPNearestDc &result) { + const MTPDnearestDc &nearest(result.c_nearestDc()); + DEBUG_LOG(("Got nearest dc, country: %1, nearest: %2, this: %3").arg(nearest.vcountry.c_string().v.c_str()).arg(nearest.vnearest_dc.v).arg(nearest.vthis_dc.v)); + MTP::setdc(result.c_nearestDc().vnearest_dc.v, true); + if (countryForReg != nearest.vcountry.c_string().v.c_str()) { + countryForReg = nearest.vcountry.c_string().v.c_str(); + emit signalEmitOn->countryChanged(); + } + if (App::app()) App::app()->startUpdateCheck(); + } +} + +IntroWidget::IntroWidget(Window *window) : QWidget(window), + wnd(window), cacheForHideInd(0), cacheForShowInd(0), _callTimeout(60), + steps(new IntroSteps(this)), phone(0), code(0), signup(0), current(0), moving(0), visibilityChanging(0) { + setGeometry(QRect(0, st::titleHeight, wnd->width(), wnd->height() - st::titleHeight)); + + countryForReg = psCurrentCountry(); + + MTP::send(MTPhelp_GetNearestDc(), rpcDone(gotNearestDC)); + signalEmitOn = this; + + stages[0] = steps; + memset(stages + 1, 0, sizeof(QWidget*) * 3); + + connect(window, SIGNAL(resized(const QSize &)), this, SLOT(onParentResize(const QSize &))); + + show(); + setFocus(); +} + +void IntroWidget::onParentResize(const QSize &newSize) { + resize(newSize); +} + +void IntroWidget::onIntroBack() { + if (!current) return; + moving = -1; + prepareMove(); +} + +void IntroWidget::onIntroNext() { + if (!createNext()) return; + moving = 1; + prepareMove(); +} + +bool IntroWidget::createNext() { + if (current == sizeof(stages) / sizeof(stages[0]) - 1) return false; + if (!stages[current + 1]) { + switch (current) { + case 0: stages[current + 1] = phone = new IntroPhone(this); break; + case 1: stages[current + 1] = code = new IntroCode(this); break; + case 2: stages[current + 1] = signup = new IntroSignup(this); break; + } + } + return true; +} + +void IntroWidget::prepareMove() { + if (cacheForHide.isNull() || cacheForHideInd != current) makeHideCache(); + if (cacheForShow.isNull() || cacheForShowInd != current + moving) makeShowCache(); + + xCoordHide = anim::ivalue(0, -moving * st::introSlideShift); + cAlphaHide = anim::fvalue(1, 0); + xCoordShow = anim::ivalue(moving * st::introSlideShift, 0); + cAlphaShow = anim::fvalue(0, 1); + anim::start(this); + + stages[current]->deactivate(); + stages[current + moving]->hide(); +} + +void IntroWidget::onDoneStateChanged(int oldState, ButtonStateChangeSource source) { + if (animating()) return; + if (source == ButtonByPress) { + if (oldState & Button::StateDown) { + cacheForHide = QPixmap(); + } else { + makeHideCache(); + } + } else if (source == ButtonByHover) { + if (!createNext()) return; + if (!cacheForShow) makeShowCache(current + 1); + } +} + +void IntroWidget::makeHideCache(int stage) { + if (stage < 0) stage = current; + int w = st::introSize.width(), h = st::introSize.height(); + cacheForHide = stages[stage]->grab(QRect(st::introSlideShift, 0, w, h)); + cacheForHideInd = stage; +} + +void IntroWidget::makeShowCache(int stage) { + if (stage < 0) stage = current + moving; + int w = st::introSize.width(), h = st::introSize.height(); + cacheForShow = stages[stage]->grab(QRect(st::introSlideShift, 0, w, h)); + cacheForShowInd = stage; +} + +void IntroWidget::animShow(const QPixmap &bgAnimCache, bool back) { + _bgAnimCache = bgAnimCache; + + anim::stop(this); + stages[current]->show(); + _animCache = grab(rect()); + + visibilityChanging = 1; + a_coord = back ? anim::ivalue(-st::introSlideShift, 0) : anim::ivalue(st::introSlideShift, 0); + a_alpha = anim::fvalue(0, 1); + a_bgCoord = back ? anim::ivalue(0, st::introSlideShift) : anim::ivalue(0, -st::introSlideShift); + a_bgAlpha = anim::fvalue(1, 0); + + stages[current]->deactivate(); + stages[current]->hide(); + anim::start(this); + show(); +} + +bool IntroWidget::animStep(float64 ms) { + float64 fullDuration = st::introSlideDelta + st::introSlideDuration, dt = ms / fullDuration; + float64 dt1 = (ms > st::introSlideDuration) ? 1 : (ms / st::introSlideDuration), dt2 = (ms > st::introSlideDelta) ? (ms - st::introSlideDelta) / (st::introSlideDuration) : 0; + bool res = true; + if (visibilityChanging) { + if (dt2 >= 1) { + res = false; + a_bgCoord.finish(); + a_bgAlpha.finish(); + a_coord.finish(); + a_alpha.finish(); + + _animCache = _bgAnimCache = QPixmap(); + + visibilityChanging = 0; + setFocus(); + stages[current]->show(); + stages[current]->activate(); + } else { + a_bgCoord.update(dt1, st::introHideFunc); + a_bgAlpha.update(dt1, st::introAlphaHideFunc); + a_coord.update(dt2, st::introShowFunc); + a_alpha.update(dt2, st::introAlphaShowFunc); + } + } else if (dt >= 1) { + res = false; + xCoordShow.finish(); + cAlphaShow.finish(); + + cacheForHide = cacheForShow = QPixmap(); + + current += moving; + moving = 0; + setFocus(); + stages[current]->activate(); + } else { + xCoordShow.update(dt2, st::introShowFunc); + cAlphaShow.update(dt2, st::introAlphaShowFunc); + xCoordHide.update(dt1, st::introHideFunc); + cAlphaHide.update(dt1, st::introAlphaHideFunc); + } + update(); + return res; +} + +void IntroWidget::paintEvent(QPaintEvent *e) { + bool trivial = (rect() == e->rect()); + setMouseTracking(true); + + QPainter p(this); + if (!trivial) { + p.setClipRect(e->rect()); + } + if (animating()) { + if (visibilityChanging) { + p.setOpacity(a_bgAlpha.current()); + p.drawPixmap(a_bgCoord.current(), 0, _bgAnimCache); + p.setOpacity(a_alpha.current()); + p.drawPixmap(a_coord.current(), 0, _animCache); + } else { + p.setOpacity(cAlphaHide.current()); + p.drawPixmap(stages[current]->x() + st::introSlideShift + xCoordHide.current(), stages[current]->y(), cacheForHide.width(), cacheForHide.height(), cacheForHide); + p.setOpacity(cAlphaShow.current()); + p.drawPixmap(stages[current + moving]->x() + st::introSlideShift + xCoordShow.current(), stages[current + moving]->y(), cacheForShow.width(), cacheForShow.height(), cacheForShow); + } + } +} + +QRect IntroWidget::innerRect() const { + int innerWidth = st::introSize.width() + 2 * st::introSlideShift, innerHeight = st::introSize.height(); + return QRect((width() - innerWidth) / 2, (height() - innerHeight) / 2, innerWidth, (height() + innerHeight) / 2); +} + +QString IntroWidget::currentCountry() const { + return countryForReg; +} + +void IntroWidget::setPhone(const QString &phone, const QString &phone_hash, bool registered) { + _phone = phone; + _phone_hash = phone_hash; + _registered = registered; +} + +void IntroWidget::setCode(const QString &code) { + _code = code; +} + +void IntroWidget::setCallTimeout(int32 callTimeout) { + _callTimeout = callTimeout; +} + +const QString &IntroWidget::getPhone() const { + return _phone; +} + +const QString &IntroWidget::getPhoneHash() const { + return _phone_hash; +} + +const QString &IntroWidget::getCode() const { + return _code; +} + +int32 IntroWidget::getCallTimeout() const { + return _callTimeout; +} + +void IntroWidget::resizeEvent(QResizeEvent *e) { + QRect r(innerRect()); + if (steps) steps->setGeometry(r); + if (phone) phone->setGeometry(r); + if (code) code->setGeometry(r); + if (signup) signup->setGeometry(r); +} + +void IntroWidget::mousePressEvent(QMouseEvent *e) { + +} + +void IntroWidget::finish(const MTPUser &user, const QImage &photo) { + wnd->setupMain(true); + wnd->startMain(user); + if (!photo.isNull()) { + App::app()->uploadProfilePhoto(photo, MTP::authedId()); + } +} + +void IntroWidget::keyPressEvent(QKeyEvent *e) { + if (animating()) return; + if (e->key() == Qt::Key_Escape) { + stages[current]->onBack(); + } else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return || e->key() == Qt::Key_Space) { + stages[current]->onNext(); + } +} + +IntroWidget::~IntroWidget() { + delete steps; + delete phone; + delete code; + delete signup; + if (App::wnd()) App::wnd()->noIntro(this); +} diff --git a/Telegram/SourceFiles/intro/intro.h b/Telegram/SourceFiles/intro/intro.h new file mode 100644 index 000000000..c43b0cbb7 --- /dev/null +++ b/Telegram/SourceFiles/intro/intro.h @@ -0,0 +1,124 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "gui/flatbutton.h" + +class Window; +class IntroSteps; +class IntroPhone; +class IntroCode; +class IntroSignup; +class IntroStage; +class Text; + +class IntroWidget : public QWidget, public Animated { + Q_OBJECT + +public: + + IntroWidget(Window *window); + + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void mousePressEvent(QMouseEvent *e); + void keyPressEvent(QKeyEvent *e); + + void animShow(const QPixmap &bgAnimCache, bool back = false); + bool animStep(float64 ms); + + QRect innerRect() const; + QString currentCountry() const; + + void setPhone(const QString &phone, const QString &phone_hash, bool registered); + void setCode(const QString &code); + void setCallTimeout(int32 callTimeout); + + const QString &getPhone() const; + const QString &getPhoneHash() const; + const QString &getCode() const; + int32 getCallTimeout() const; + + void finish(const MTPUser &user, const QImage &photo = QImage()); + + ~IntroWidget(); + +public slots: + + void onIntroNext(); + void onIntroBack(); + void onDoneStateChanged(int oldState, ButtonStateChangeSource source); + void onParentResize(const QSize &newSize); + +signals: + + void countryChanged(); + +private: + + void makeHideCache(int stage = -1); + void makeShowCache(int stage = -1); + void prepareMove(); + bool createNext(); + + QPixmap cacheForHide, cacheForShow; + int cacheForHideInd, cacheForShowInd; + anim::ivalue xCoordHide, xCoordShow; + anim::fvalue cAlphaHide, cAlphaShow; + + QPixmap _animCache, _bgAnimCache; + anim::ivalue a_coord, a_bgCoord; + anim::fvalue a_alpha, a_bgAlpha; + + Window *wnd; + IntroSteps *steps; + IntroPhone *phone; + IntroCode *code; + IntroSignup *signup; + IntroStage *stages[4]; + int current, moving, visibilityChanging; + + QString _phone, _phone_hash; + int32 _callTimeout; + bool _registered; + + QString _code; + + QString _firstname, _lastname; + +}; + +class IntroStage : public QWidget { +public: + + IntroStage(IntroWidget *parent) : QWidget(parent) { + } + + virtual void activate() = 0; // show and activate + virtual void deactivate() = 0; // deactivate and hide + virtual void onNext() = 0; + virtual void onBack() = 0; + +protected: + + IntroWidget *intro() { + return qobject_cast(parent()); + } + +}; diff --git a/Telegram/SourceFiles/intro/introcode.cpp b/Telegram/SourceFiles/intro/introcode.cpp new file mode 100644 index 000000000..371c07978 --- /dev/null +++ b/Telegram/SourceFiles/intro/introcode.cpp @@ -0,0 +1,279 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" +#include "style.h" + +#include "application.h" + +#include "intro/introcode.h" +#include "intro/intro.h" + +CodeInput::CodeInput(QWidget *parent, const style::flatInput &st, const QString &ph) : FlatInput(parent, st, ph) { +} + +void CodeInput::correctValue(QKeyEvent *e, const QString &was) { + QString oldText(text()), newText; + int oldPos(cursorPosition()), newPos(-1), oldLen(oldText.length()), digitCount = 0; + for (int i = 0; i < oldLen; ++i) { + if (oldText[i].isDigit()) { + ++digitCount; + } + } + if (digitCount > 5) digitCount = 5; + bool strict = (digitCount == 5); + + newText.reserve(oldLen); + for (int i = 0; i < oldLen; ++i) { + QChar ch(oldText[i]); + if (ch.isDigit()) { + if (!digitCount--) { + break; + } + newText += ch; + if (strict && !digitCount) { + break; + } + } + if (i == oldPos) { + newPos = newText.length(); + } + } + if (newPos < 0) { + newPos = newText.length(); + } + if (newText != oldText) { + setText(newText); + if (newPos != oldPos) { + setCursorPosition(newPos); + } + } + + if (strict) emit codeEntered(); +} + +IntroCode::IntroCode(IntroWidget *parent) : IntroStage(parent), + next(this, lang(lng_intro_next), st::btnIntroNext), + back(this, lang(lng_intro_back), st::btnIntroBack), + code(this, st::inpIntroCode, lang(lng_code_ph)), errorAlpha(0), waitTillCall(intro()->getCallTimeout()) { + setVisible(false); + setGeometry(parent->innerRect()); + + connect(&next, SIGNAL(stateChanged(int, ButtonStateChangeSource)), parent, SLOT(onDoneStateChanged(int, ButtonStateChangeSource))); + connect(&next, SIGNAL(clicked()), this, SLOT(onSubmitCode())); + connect(&back, SIGNAL(clicked()), parent, SLOT(onIntroBack())); + connect(&code, SIGNAL(changed()), this, SLOT(onInputChange())); + connect(&callTimer, SIGNAL(timeout()), this, SLOT(onSendCall())); + connect(&checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest())); +} + +void IntroCode::paintEvent(QPaintEvent *e) { + bool trivial = (rect() == e->rect()); + + QPainter p(this); + if (!trivial) { + p.setClipRect(e->rect()); + } + if (trivial || e->rect().intersects(textRect)) { + p.setFont(st::introHeaderFont->f); + p.drawText(textRect, intro()->getPhone(), style::al_topleft); + p.setFont(st::introFont->f); + p.drawText(textRect, lang(lng_code_desc), style::al_bottomleft); + } + QString callText = lang(lng_code_calling); + if (waitTillCall >= 3600) { + callText = lang(lng_code_call).arg(QString("%1:%2").arg(waitTillCall / 3600).arg((waitTillCall / 60) % 60, 2, 10, QChar('0'))).arg(waitTillCall % 60, 2, 10, QChar('0')); + } else if (waitTillCall > 0) { + callText = lang(lng_code_call).arg(waitTillCall / 60).arg(waitTillCall % 60, 2, 10, QChar('0')); + } else if (waitTillCall < 0) { + callText = lang(lng_code_called); + } + p.drawText(QRect(textRect.left(), code.y() + code.height() + st::introSkip, st::introTextSize.width(), st::introErrHeight), callText, style::al_left); + if (animating() || error.length()) { + p.setOpacity(errorAlpha.current()); + p.setFont(st::introErrFont->f); + p.setPen(st::introErrColor->p); + p.drawText(textRect.left(), next.y() + next.height() + st::introErrTop + st::introErrFont->ascent, error); + } +} + +void IntroCode::resizeEvent(QResizeEvent *e) { + int sumBack = st::btnIntroNext.width + st::btnIntroBack.width + st::btnIntroSep; + if (e->oldSize().width() != width()) { + int sumNext = st::btnIntroNext.width - st::btnIntroBack.width - st::btnIntroSep; + back.move((width() - sumBack) / 2, st::introBtnTop); + next.move((width() - sumNext) / 2, st::introBtnTop); + code.move((width() - sumBack) / 2, st::introTextSize.height() + 24); + } + textRect = QRect((width() - sumBack) / 2, 0, st::introTextSize.width(), st::introTextSize.height()); +} + +void IntroCode::showError(const QString &err) { + if (!err.isEmpty()) code.notaBene(); + if (!animating() && err == error) return; + + if (err.length()) { + error = err; + errorAlpha.start(1); + } else { + errorAlpha.start(0); + } + anim::start(this); +} + +bool IntroCode::animStep(float64 ms) { + float64 dt = ms / st::introErrDuration; + + bool res = true; + if (dt >= 1) { + res = false; + errorAlpha.finish(); + if (!errorAlpha.current()) { + error = ""; + } + } else { + errorAlpha.update(dt, st::introErrFunc); + } + update(); + return res; +} + +void IntroCode::activate() { + waitTillCall = intro()->getCallTimeout(); + callTimer.start(1000); + error = ""; + errorAlpha = anim::fvalue(0); + show(); + code.setDisabled(false); + code.setFocus(); +} + +void IntroCode::deactivate() { + callTimer.stop(); + hide(); + code.clearFocus(); +} + +void IntroCode::stopCheck() { + checkRequest.stop(); +} + +void IntroCode::onCheckRequest() { + int32 status = MTP::state(sentRequest); + if (status < 0) { + int32 leftms = -status; + if (leftms >= 1000) { + if (sentRequest) { + MTP::cancel(sentRequest); + sentCode = ""; + } + sentRequest = 0; + if (!code.isEnabled()) { + code.setDisabled(false); + code.setFocus(); + } + } + } + if (!sentRequest && status == MTP::RequestSent) { + stopCheck(); + } +} + +void IntroCode::codeSubmitDone(const MTPauth_Authorization &result) { + stopCheck(); + code.setDisabled(false); + const MTPDauth_authorization &d(result.c_auth_authorization()); + if (d.vuser.type() != mtpc_userSelf) { // wtf? + showError(lang(lng_server_error)); + return; + } + cSetLoggedPhoneNumber(intro()->getPhone()); + intro()->finish(d.vuser); +} + +bool IntroCode::codeSubmitFail(const RPCError &error) { + stopCheck(); + code.setDisabled(false); + const QString &err = error.type(); + if (err == "PHONE_NUMBER_INVALID" || err == "PHONE_CODE_EXPIRED") { // show error + onBack(); + return true; + } else if (err == "PHONE_CODE_EMPTY" || err == "PHONE_CODE_INVALID") { + showError(lang(lng_bad_code)); + code.setFocus(); + return true; + } else if (err == "PHONE_NUMBER_UNOCCUPIED") { // success, need to signUp + intro()->setCode(sentCode); + intro()->onIntroNext(); + return true; + } + if (QRegularExpression("^FLOOD_WAIT_(\\d+)$").match(err).hasMatch()) { + showError(lang(lng_flood_error)); + code.setFocus(); + return true; + } + if (cDebug()) { // internal server error + showError(err + ": " + error.description()); + } else { + showError(lang(lng_server_error)); + } + code.setFocus(); + return false; +} + +void IntroCode::onInputChange() { + showError(""); + if (code.text().length() == 5) onSubmitCode(); +} + +void IntroCode::onSendCall() { + if (!--waitTillCall) { + callTimer.stop(); + MTP::send(MTPauth_SendCall(MTP_string(intro()->getPhone()), MTP_string(intro()->getPhoneHash())), rpcDone(&IntroCode::callDone)); + } + update(); +} + +void IntroCode::callDone(const MTPBool &v) { + if (!waitTillCall) { + waitTillCall = -1; + update(); + } +} + +void IntroCode::onSubmitCode(bool force) { + if (!force && (code.text() == sentCode || !code.isEnabled())) return; + + code.setDisabled(true); + setFocus(); + + showError(""); + + checkRequest.start(1000); + + sentCode = code.text(); + sentRequest = MTP::send(MTPauth_SignIn(MTP_string(intro()->getPhone()), MTP_string(intro()->getPhoneHash()), MTP_string(sentCode)), rpcDone(&IntroCode::codeSubmitDone), rpcFail(&IntroCode::codeSubmitFail)); +} + +void IntroCode::onNext() { + onSubmitCode(); +} + +void IntroCode::onBack() { + intro()->onIntroBack(); +} diff --git a/Telegram/SourceFiles/intro/introcode.h b/Telegram/SourceFiles/intro/introcode.h new file mode 100644 index 000000000..a0ba452d4 --- /dev/null +++ b/Telegram/SourceFiles/intro/introcode.h @@ -0,0 +1,89 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "gui/flatbutton.h" +#include "gui/flatinput.h" +#include "intro.h" + +class CodeInput : public FlatInput { + Q_OBJECT + +public: + + CodeInput(QWidget *parent, const style::flatInput &st, const QString &ph); + +signals: + + void codeEntered(); + +protected: + + void correctValue(QKeyEvent *e, const QString &was); + +}; + +class IntroCode : public IntroStage, public Animated, public RPCSender { + Q_OBJECT + +public: + + IntroCode(IntroWidget *parent); + + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + + bool animStep(float64 ms); + + void activate(); + void deactivate(); + void onNext(); + void onBack(); + + void codeSubmitDone(const MTPauth_Authorization &result); + bool codeSubmitFail(const RPCError &error); + +public slots: + + void onSubmitCode(bool force = false); + void onInputChange(); + void onSendCall(); + void onCheckRequest(); + +private: + + void showError(const QString &err); + void callDone(const MTPBool &v); + void stopCheck(); + + QString error; + anim::fvalue errorAlpha; + + FlatButton next, back; + + QRect textRect; + + CodeInput code; + QString sentCode; + mtpRequestId sentRequest; + QTimer callTimer; + int32 waitTillCall; + + QTimer checkRequest; +}; diff --git a/Telegram/SourceFiles/intro/introphone.cpp b/Telegram/SourceFiles/intro/introphone.cpp new file mode 100644 index 000000000..ae03ddef4 --- /dev/null +++ b/Telegram/SourceFiles/intro/introphone.cpp @@ -0,0 +1,300 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" +#include "style.h" + +#include "application.h" + +#include "intro/introphone.h" +#include "intro/intro.h" + +namespace { + class SignUpLink : public ITextLink { + public: + + SignUpLink(IntroPhone *widget) : _widget(widget) { + } + + void onClick(Qt::MouseButton) const { + _widget->toSignUp(); + } + + private: + IntroPhone *_widget; + }; +} + +IntroPhone::IntroPhone(IntroWidget *parent) : IntroStage(parent), changed(false), + next(this, lang(lng_intro_next), st::btnIntroStart), + country(this, st::introCountry), errorAlpha(0), _signup(this, lang(lng_phone_notreg).replace(qsl("{signup}"), textcmdStartLink(1)).replace(qsl("{/signup}"), textcmdStopLink()), st::introErrLabel), _showSignup(false), + phone(this, st::inpIntroPhone, lang(lng_phone_ph)), code(this, st::inpIntroCountryCode) { + setVisible(false); + setGeometry(parent->innerRect()); + + connect(&next, SIGNAL(stateChanged(int, ButtonStateChangeSource)), parent, SLOT(onDoneStateChanged(int, ButtonStateChangeSource))); + connect(&next, SIGNAL(clicked()), this, SLOT(onSubmitPhone())); + connect(&phone, SIGNAL(voidBackspace(QKeyEvent*)), &code, SLOT(startErasing(QKeyEvent*))); + connect(&country, SIGNAL(codeChanged(const QString &)), &code, SLOT(codeSelected(const QString &))); + connect(&code, SIGNAL(codeChanged(const QString &)), &country, SLOT(onChooseCode(const QString &))); + connect(&code, SIGNAL(addedToNumber(const QString &)), &phone, SLOT(addedToNumber(const QString &))); + connect(&country, SIGNAL(selectClosed()), this, SLOT(onSelectClose())); + connect(&phone, SIGNAL(changed()), this, SLOT(onInputChange())); + connect(&code, SIGNAL(changed()), this, SLOT(onInputChange())); + connect(intro(), SIGNAL(countryChanged()), this, SLOT(countryChanged())); + connect(&checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest())); + + _signup.setLink(1, TextLinkPtr(new SignUpLink(this))); + _signup.hide(); + + _signupCache = _signup.grab(_signup.rect()); + + if (!country.onChooseCountry(intro()->currentCountry())) { + country.onChooseCountry(qsl("US")); + } + changed = false; +} + +void IntroPhone::paintEvent(QPaintEvent *e) { + bool trivial = (rect() == e->rect()); + + QPainter p(this); + if (!trivial) { + p.setClipRect(e->rect()); + } + if (trivial || e->rect().intersects(textRect)) { + p.setFont(st::introHeaderFont->f); + p.drawText(textRect, lang(lng_phone_title), style::al_topleft); + p.setFont(st::introFont->f); + p.drawText(textRect, lang(lng_phone_desc), style::al_bottomleft); + } + if (animating() || error.length()) { + p.setOpacity(errorAlpha.current()); + p.setFont(st::introErrFont->f); + p.setPen(st::introErrColor->p); + p.drawText(textRect.x(), next.y() + next.height() + st::introErrTop + st::introErrFont->ascent, error); + + if (_signup.isHidden() && _showSignup) { + p.drawPixmap(_signup.x(), _signup.y(), _signupCache); + } + } +} + +void IntroPhone::resizeEvent(QResizeEvent *e) { + if (e->oldSize().width() != width()) { + next.move((width() - next.width()) / 2, st::introBtnTop); + country.move((width() - country.width()) / 2, st::introTextSize.height() + st::introCountry.top); + int phoneTop = country.y() + country.height() + st::introPhoneTop; + phone.move((width() + country.width()) / 2 - st::inpIntroPhone.width, phoneTop); + code.move((width() - country.width()) / 2, phoneTop); + } + _signup.move((width() - next.width()) / 2, next.y() + next.height() + st::introErrTop * 2 + st::introErrFont->height); + textRect = QRect((width() - next.width()) / 2, 0, st::introTextSize.width(), st::introTextSize.height()); +} + +void IntroPhone::showError(const QString &err, bool signUp) { + if (!err.isEmpty()) { + phone.notaBene(); + _showSignup = signUp; + } + + if (!animating() && err == error) return; + + if (err.length()) { + error = err; + errorAlpha.start(1); + } else { + errorAlpha.start(0); + } + _signup.hide(); + anim::start(this); +} + +bool IntroPhone::animStep(float64 ms) { + float64 dt = ms / st::introErrDuration; + + bool res = true; + if (dt >= 1) { + res = false; + errorAlpha.finish(); + if (!errorAlpha.current()) { + error = ""; + _signup.hide(); + } else if (!error.isEmpty() && _showSignup) { + _signup.show(); + } + } else { + errorAlpha.update(dt, st::introErrFunc); + } + update(); + return res; +} + +void IntroPhone::countryChanged() { + if (!changed) { + selectCountry(intro()->currentCountry()); + } +} + +void IntroPhone::onSelectClose() { + phone.setFocus(); +} + +void IntroPhone::onInputChange() { + changed = true; + showError(""); +} + +void IntroPhone::disableAll() { + next.setDisabled(true); + phone.setDisabled(true); + country.setDisabled(true); + code.setDisabled(true); + setFocus(); +} + +void IntroPhone::enableAll(bool failed) { + next.setDisabled(false); + phone.setDisabled(false); + country.setDisabled(false); + code.setDisabled(false); + if (failed) phone.setFocus(); +} + +void IntroPhone::onSubmitPhone(bool force) { + if (!force && !next.isEnabled()) return; + + if (!App::isValidPhone(fullNumber())) { + showError(lang(lng_bad_phone)); + phone.setFocus(); + return; + } + + disableAll(); + showError(""); + + checkRequest.start(1000); + + sentPhone = fullNumber(); + sentRequest = MTP::send(MTPauth_CheckPhone(MTP_string(sentPhone)), rpcDone(&IntroPhone::phoneCheckDone), rpcFail(&IntroPhone::phoneSubmitFail)); +} + +void IntroPhone::stopCheck() { + checkRequest.stop(); +} + +void IntroPhone::onCheckRequest() { + int32 status = MTP::state(sentRequest); + if (status < 0) { + int32 leftms = -status; + if (leftms >= 1000) { + MTP::cancel(sentRequest); + sentRequest = 0; + if (!phone.isEnabled()) enableAll(true); + } + } + if (!sentRequest && status == MTP::RequestSent) { + stopCheck(); + } +} + +void IntroPhone::phoneCheckDone(const MTPauth_CheckedPhone &result) { + stopCheck(); + + const MTPDauth_checkedPhone &d(result.c_auth_checkedPhone()); + if (d.vphone_registered.v) { + disableAll(); + showError(""); + + checkRequest.start(1000); + + sentRequest = MTP::send(MTPauth_SendCode(MTP_string(sentPhone), MTP_int(0), MTP_int(ApiId), MTP_string(ApiHash), MTP_string(Application::lang())), rpcDone(&IntroPhone::phoneSubmitDone), rpcFail(&IntroPhone::phoneSubmitFail)); + } else { + showError(lang(lng_bad_phone_noreg), true); + enableAll(true); + } +} + +void IntroPhone::phoneSubmitDone(const MTPauth_SentCode &result) { + stopCheck(); + enableAll(false); + + const MTPDauth_sentCode &d(result.c_auth_sentCode()); + intro()->setPhone(sentPhone, d.vphone_code_hash.c_string().v.c_str(), d.vphone_registered.v); + intro()->setCallTimeout(result.c_auth_sentCode().vsend_call_timeout.v); + intro()->onIntroNext(); +} + +void IntroPhone::toSignUp() { + disableAll(); + showError(""); + + checkRequest.start(1000); + + sentRequest = MTP::send(MTPauth_SendCode(MTP_string(sentPhone), MTP_int(0), MTP_int(ApiId), MTP_string(ApiHash), MTP_string(Application::lang())), rpcDone(&IntroPhone::phoneSubmitDone), rpcFail(&IntroPhone::phoneSubmitFail)); +} + +bool IntroPhone::phoneSubmitFail(const RPCError &error) { + stopCheck(); + const QString &err = error.type(); + if (err == "PHONE_NUMBER_INVALID") { // show error + showError(lang(lng_bad_phone)); + enableAll(true); + return true; + } + if (QRegularExpression("^FLOOD_WAIT_(\\d+)$").match(err).hasMatch()) { + showError(lang(lng_flood_error)); + enableAll(true); + return true; + } + if (cDebug()) { // internal server error + showError(err + ": " + error.description()); + } else { + showError(lang(lng_server_error)); + } + enableAll(true); + return false; +} + +QString IntroPhone::fullNumber() const { + return code.text() + phone.text(); +} + +void IntroPhone::selectCountry(const QString &c) { + country.onChooseCountry(c); +} + +void IntroPhone::activate() { + error = ""; + errorAlpha = anim::fvalue(0); + show(); + enableAll(true); +} + +void IntroPhone::deactivate() { + checkRequest.stop(); + hide(); + phone.clearFocus(); +} + +void IntroPhone::onNext() { + onSubmitPhone(); +} + +void IntroPhone::onBack() { +} diff --git a/Telegram/SourceFiles/intro/introphone.h b/Telegram/SourceFiles/intro/introphone.h new file mode 100644 index 000000000..b993d25b9 --- /dev/null +++ b/Telegram/SourceFiles/intro/introphone.h @@ -0,0 +1,89 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "gui/flatbutton.h" +#include "gui/phoneinput.h" +#include "gui/countrycodeinput.h" +#include "gui/countryinput.h" +#include "intro.h" + +class IntroPhone : public IntroStage, public Animated, public RPCSender { + Q_OBJECT + +public: + + IntroPhone(IntroWidget *parent); + + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + + bool animStep(float64 ms); + + void selectCountry(const QString &country); + + void activate(); + void deactivate(); + void onNext(); + void onBack(); + + void phoneCheckDone(const MTPauth_CheckedPhone &result); + void phoneSubmitDone(const MTPauth_SentCode &result); + bool phoneSubmitFail(const RPCError &error); + + void toSignUp(); + +public slots: + + void countryChanged(); + void onSelectClose(); + void onInputChange(); + void onSubmitPhone(bool force = false); + void onCheckRequest(); + +private: + + QString fullNumber() const; + void disableAll(); + void enableAll(bool failed); + void stopCheck(); + + void showError(const QString &err, bool signUp = false); + + QString error; + anim::fvalue errorAlpha; + + bool changed; + FlatButton next; + + QRect textRect; + + CountryInput country; + PhoneInput phone; + CountryCodeInput code; + + FlatLabel _signup; + QPixmap _signupCache; + bool _showSignup; + + QString sentPhone; + mtpRequestId sentRequest; + + QTimer checkRequest; +}; diff --git a/Telegram/SourceFiles/intro/introsignup.cpp b/Telegram/SourceFiles/intro/introsignup.cpp new file mode 100644 index 000000000..9b597eb4d --- /dev/null +++ b/Telegram/SourceFiles/intro/introsignup.cpp @@ -0,0 +1,283 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" +#include "style.h" + +#include "gui/filedialog.h" +#include "boxes/photocropbox.h" + +#include "application.h" + +#include "intro/introsignup.h" +#include "intro/intro.h" + +IntroSignup::IntroSignup(IntroWidget *parent) : IntroStage(parent), + next(this, lang(lng_intro_finish), st::btnIntroFinish), errorAlpha(0), a_photo(0), + first(this, st::inpIntroName, lang(lng_signup_firstname)), + last(this, st::inpIntroName, lang(lng_signup_lastname)) { + setVisible(false); + setGeometry(parent->innerRect()); + + connect(&next, SIGNAL(clicked()), this, SLOT(onSubmitName())); + connect(&checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest())); + + setMouseTracking(true); +} + +void IntroSignup::mouseMoveEvent(QMouseEvent *e) { + bool photoOver = QRect(_phLeft, _phTop, st::setPhotoSize, st::setPhotoSize).contains(e->pos()); + if (photoOver != _photoOver) { + _photoOver = photoOver; + if (_photoSmall.isNull()) { + a_photo.start(_photoOver ? 1 : 0); + errorAlpha.restart(); + anim::start(this); + } + } + + setCursor(_photoOver ? style::cur_pointer : style::cur_default); +} + +void IntroSignup::mousePressEvent(QMouseEvent *e) { + mouseMoveEvent(e); + if (QRect(_phLeft, _phTop, st::setPhotoSize, st::setPhotoSize).contains(e->pos())) { + QStringList imgExtensions(cImgExtensions()); + QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;All files (*.*)")); + + QImage img; + QString file; + QByteArray remoteContent; + if (filedialogGetOpenFile(file, remoteContent, lang(lng_choose_images), filter)) { + if (!remoteContent.isEmpty()) { + img = App::readImage(remoteContent); + } else { + if (!file.isEmpty()) { + img = App::readImage(file); + } + } + } else { + return; + } + + if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) { + showError(lang(lng_bad_photo)); + return; + } + PhotoCropBox *box = new PhotoCropBox(img, 0); + connect(box, SIGNAL(ready(const QImage &)), this, SLOT(onPhotoReady(const QImage &))); + App::wnd()->showLayer(box); + } +} + +void IntroSignup::paintEvent(QPaintEvent *e) { + bool trivial = (rect() == e->rect()); + + QPainter p(this); + if (!trivial) { + p.setClipRect(e->rect()); + } + if (trivial || e->rect().intersects(textRect)) { + p.setFont(st::introTitleFont->f); + p.drawText(textRect, lang(lng_signup_title), QTextOption(Qt::AlignHCenter | Qt::AlignTop)); + } + if (animating() || error.length()) { + p.setOpacity(errorAlpha.current()); + + QRect errRect((width() - st::introErrWidth) / 2, (last.y() + last.height() + next.y() - st::introErrHeight) / 2, st::introErrWidth, st::introErrHeight); + p.fillRect(errRect, st::introErrBG->b); + p.setFont(st::introErrFont->f); + p.setPen(st::introErrColor->p); + p.drawText(errRect, error, QTextOption(style::al_center)); + + p.setOpacity(1); + } + + if (_photoSmall.isNull()) { + if (a_photo.current() < 1) { + p.drawPixmap(QPoint(_phLeft, _phTop), App::sprite(), st::setPhotoImg); + } + if (a_photo.current() > 0) { + p.setOpacity(a_photo.current()); + p.drawPixmap(QPoint(_phLeft, _phTop), App::sprite(), st::setOverPhotoImg); + p.setOpacity(1); + } + } else { + p.drawPixmap(_phLeft, _phTop, _photoSmall); + } +} + +void IntroSignup::resizeEvent(QResizeEvent *e) { + textRect = QRect((width() - st::introTextSize.width()) / 2, 0, st::introTextSize.width(), st::introTextSize.height()); + _phLeft = (width() - st::setPhotoImg.width()) / 2; + _phTop = st::introHeaderFont->height + st::introFinishSkip; + if (e->oldSize().width() != width()) { + int sumNext = st::btnIntroNext.width - st::btnIntroBack.width - st::btnIntroSep; + next.move((width() - sumNext) / 2, st::introSize.height() - st::btnIntroNext.height); + } + if (e->oldSize().width() != width()) { + next.move((width() - next.width()) / 2, st::introSize.height() - st::btnIntroNext.height); + first.move((width() - first.width()) / 2, _phTop + st::setPhotoImg.height() + st::introFinishSkip); + last.move((width() - last.width()) / 2, first.y() + first.height() + st::introFinishSkip); + } +} + +void IntroSignup::showError(const QString &err) { + if (!animating() && err == error) return; + + if (err.length()) { + error = err; + errorAlpha.start(1); + } else { + errorAlpha.start(0); + } + a_photo.restart(); + anim::start(this); +} + +bool IntroSignup::animStep(float64 ms) { + float64 dt = ms / st::introErrDuration; + + bool res = true; + if (dt >= 1) { + res = false; + errorAlpha.finish(); + if (!errorAlpha.current()) { + error = ""; + } + a_photo.finish(); + } else { + errorAlpha.update(dt, st::introErrFunc); + a_photo.update(dt, anim::linear); + } + update(); + return res; +} + +void IntroSignup::activate() { + show(); + first.setFocus(); +} + +void IntroSignup::deactivate() { + hide(); +} + +void IntroSignup::stopCheck() { + checkRequest.stop(); +} + +void IntroSignup::onCheckRequest() { + int32 status = MTP::state(sentRequest); + if (status < 0) { + int32 leftms = -status; + if (leftms >= 1000) { + MTP::cancel(sentRequest); + sentRequest = 0; + if (!first.isEnabled()) { + first.setDisabled(false); + last.setDisabled(false); + last.setFocus(); + } + } + } + if (!sentRequest && status == MTP::RequestSent) { + stopCheck(); + } +} + +void IntroSignup::onPhotoReady(const QImage &img) { + _photoBig = img; + _photoSmall = QPixmap::fromImage(img.scaled(st::setPhotoSize, st::setPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + App::wnd()->hideLayer(); +} + +void IntroSignup::nameSubmitDone(const MTPauth_Authorization &result) { + stopCheck(); + first.setDisabled(false); + last.setDisabled(false); + const MTPDauth_authorization &d(result.c_auth_authorization()); + if (d.vuser.type() != mtpc_userSelf) { // wtf? + showError(lang(lng_server_error)); + return; + } + intro()->finish(d.vuser, _photoBig); +} + +bool IntroSignup::nameSubmitFail(const RPCError &error) { + stopCheck(); + first.setDisabled(false); + last.setDisabled(false); + const QString &err = error.type(); + if (err == "PHONE_NUMBER_INVALID" || err == "PHONE_CODE_EXPIRED" || err == "PHONE_CODE_EMPTY" || err == "PHONE_CODE_INVALID" || err == "PHONE_NUMBER_OCCUPIED") { + intro()->onIntroBack(); + return true; + } else if (err == "FIRSTNAME_INVALID") { + showError(lang(lng_bad_name)); + first.setFocus(); + return true; + } else if (err == "LASTNAME_INVALID") { + showError(lang(lng_bad_name)); + last.setFocus(); + return true; + } + if (QRegularExpression("^FLOOD_WAIT_(\\d+)$").match(err).hasMatch()) { + showError(lang(lng_flood_error)); + last.setFocus(); + return true; + } + if (cDebug()) { // internal server error + showError(err + ": " + error.description()); + } else { + showError(lang(lng_server_error)); + } + first.setFocus(); + return false; +} + +void IntroSignup::onInputChange() { + showError(""); +} + +void IntroSignup::onSubmitName(bool force) { + if ((first.hasFocus() || first.text().trimmed().length()) && !last.text().trimmed().length()) { + last.setFocus(); + return; + } else if (!first.text().trimmed().length()) { + first.setFocus(); + return; + } + if (!force && !first.isEnabled()) return; + + first.setDisabled(true); + last.setDisabled(true); + setFocus(); + + showError(""); + + firstName = first.text().trimmed(); + lastName = last.text().trimmed(); + sentRequest = MTP::send(MTPauth_SignUp(MTP_string(intro()->getPhone()), MTP_string(intro()->getPhoneHash()), MTP_string(intro()->getCode()), MTP_string(firstName), MTP_string(lastName)), rpcDone(&IntroSignup::nameSubmitDone), rpcFail(&IntroSignup::nameSubmitFail)); +} + +void IntroSignup::onNext() { + onSubmitName(); +} + +void IntroSignup::onBack() { +} diff --git a/Telegram/SourceFiles/intro/introsignup.h b/Telegram/SourceFiles/intro/introsignup.h new file mode 100644 index 000000000..183e2a1a5 --- /dev/null +++ b/Telegram/SourceFiles/intro/introsignup.h @@ -0,0 +1,76 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "gui/flatbutton.h" +#include "gui/flatinput.h" +#include "intro.h" + +class IntroSignup : public IntroStage, public Animated, public RPCSender { + Q_OBJECT + +public: + + IntroSignup(IntroWidget *parent); + + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + + bool animStep(float64 ms); + + void activate(); + void deactivate(); + void onNext(); + void onBack(); + + void nameSubmitDone(const MTPauth_Authorization &result); + bool nameSubmitFail(const RPCError &error); + +public slots: + + void onSubmitName(bool force = false); + void onInputChange(); + void onCheckRequest(); + void onPhotoReady(const QImage &img); + +private: + + void showError(const QString &err); + void stopCheck(); + + QString error; + anim::fvalue errorAlpha, a_photo; + + FlatButton next; + + QRect textRect; + + bool _photoOver; + QImage _photoBig; + QPixmap _photoSmall; + int32 _phLeft, _phTop; + + FlatInput first, last; + QString firstName, lastName; + mtpRequestId sentRequest; + + QTimer checkRequest; +}; diff --git a/Telegram/SourceFiles/intro/introsteps.cpp b/Telegram/SourceFiles/intro/introsteps.cpp new file mode 100644 index 000000000..dae62f7e3 --- /dev/null +++ b/Telegram/SourceFiles/intro/introsteps.cpp @@ -0,0 +1,80 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" +#include "style.h" + +#include "application.h" + +#include "intro/introsteps.h" +#include "intro/intro.h" + +IntroSteps::IntroSteps(IntroWidget *parent) : IntroStage(parent), + _intro1(this, lang(lng_intro1), st::introLabel), + _intro2(this, lang(lng_intro2), st::introLabel), + _next(this, lang(lng_start_msgs), st::btnIntroStart) { + + _headerWidth = st::introHeaderFont->m.width(lang(lng_maintitle)); + + setGeometry(parent->innerRect()); + + connect(&_next, SIGNAL(stateChanged(int, ButtonStateChangeSource)), parent, SLOT(onDoneStateChanged(int, ButtonStateChangeSource))); + connect(&_next, SIGNAL(clicked()), parent, SLOT(onIntroNext())); + + setMouseTracking(true); +} + +void IntroSteps::paintEvent(QPaintEvent *e) { + bool trivial = (rect() == e->rect()); + + QPainter p(this); + if (!trivial) { + p.setClipRect(e->rect()); + } + int32 hy = _intro1.y() - st::introHeaderFont->height - st::introHeaderSkip + st::introHeaderFont->ascent; + + p.setFont(st::introHeaderFont->f); + p.drawText(_next.x(), hy, lang(lng_maintitle)); + p.setPen(st::introColor->p); + p.setFont(st::introVersionFont->f); + p.setPen(st::introVersionColor->p); + p.drawText(_next.x() + _headerWidth + st::introVersionSkip, hy, qsl("alpha ") + QString::fromWCharArray(AppVersionStr)); +} + +void IntroSteps::resizeEvent(QResizeEvent *e) { + if (e->oldSize().width() != width()) { + _next.move((width() - st::btnIntroStart.width) / 2, st::introBtnTop); + _intro2.move(_next.x(), _next.y() - _intro2.height() - st::intro2Skip); + _intro1.move(_next.x(), _intro2.y() - _intro1.height() - st::intro1Skip); + } +} + +void IntroSteps::activate() { + show(); +} + +void IntroSteps::deactivate() { + hide(); +} + +void IntroSteps::onNext() { + intro()->onIntroNext(); +} + +void IntroSteps::onBack() { +} diff --git a/Telegram/SourceFiles/intro/introsteps.h b/Telegram/SourceFiles/intro/introsteps.h new file mode 100644 index 000000000..e4354b25c --- /dev/null +++ b/Telegram/SourceFiles/intro/introsteps.h @@ -0,0 +1,43 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "gui/flatbutton.h" +#include "intro.h" + +class IntroSteps : public IntroStage { +public: + + IntroSteps(IntroWidget *parent); + + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + + void activate(); + void deactivate(); + void onNext(); + void onBack(); + +private: + + FlatLabel _intro1, _intro2; + + FlatButton _next; + int32 _headerWidth; +}; diff --git a/Telegram/SourceFiles/langloaderplain.cpp b/Telegram/SourceFiles/langloaderplain.cpp new file mode 100644 index 000000000..8286e0a4c --- /dev/null +++ b/Telegram/SourceFiles/langloaderplain.cpp @@ -0,0 +1,135 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "langloaderplain.h" + +namespace { + + bool skipWhitespaces(const char *&from, const char *end) { + while (from < end && (*from == ' ' || *from == '\n' || *from == '\t' || *from == '\r')) { + ++from; + } + return (from < end); + } + + bool skipComment(const char *&from, const char *end) { + if (from >= end) return false; + if (*from == '/') { + if (from + 1 >= end) return true; + if (*(from + 1) == '*') { + from += 2; + while (from + 1 < end && (*from != '*' || *(from + 1) != '/')) { + ++from; + } + from += 2; + return (from < end); + } else if (*(from + 1) == '/') { + from += 2; + while (from < end && *from != '\n' && *from != '\r') { + ++from; + } + ++from; + return (from < end); + } else { + return true; + } + } + return true; + } + + bool skipJunk(const char *&from, const char *end) { + const char *start; + do { + start = from; + if (!skipWhitespaces(from, end)) return false; + if (!skipComment(from, end)) throw Exception("Unexpected end of comment!"); + } while (start != from); + return true; + } + + bool readKeyValue(const char *&from, const char *end, QString &name, QString &value) { + if (!skipJunk(from, end)) return false; + + const char *nameStart = from; + while (from < end && (*from >= 'a' && *from <= 'z' || *from >= 'A' && *from <= 'Z' || *from == '_' || *from >= '0' && *from <= '9')) { + ++from; + } + + QString varName = QString::fromUtf8(nameStart, from - nameStart); + + if (!skipJunk(from, end)) throw Exception("Unexpected end of file!"); + if (*from != ':') throw Exception(QString("':' expected after '%1'").arg(varName)); + + if (!skipJunk(++from, end)) throw Exception("Unexpected end of file!"); + if (*from != '"') throw Exception(QString("Expected string after '%1:'").arg(varName)); + + QByteArray varValue; + const char *start = ++from; + while (from < end && *from != '"') { + if (*from == '\\') { + if (from + 1 >= end) throw Exception("Unexpected end of file!"); + if (*(from + 1) == '"' || *(from + 1) == '\\') { + if (from > start) varValue.append(start, from - start); + start = ++from; + } + } + ++from; + } + if (from >= end) throw Exception("Unexpected end of file!"); + if (from > start) varValue.append(start, from - start); + + if (!skipJunk(++from, end)) throw Exception("Unexpected end of file!"); + if (*from != ';') throw Exception(QString("';' expected after '%1: \"value\"'").arg(varName)); + + skipJunk(++from, end); + + name = varName; + value = QString::fromUtf8(varValue); + return true; + } +} + +LangLoaderPlain::LangLoaderPlain(const QString &file) { + QFile f(file); + if (!f.open(QIODevice::ReadOnly)) { + error(qsl("Could not open input file!")); + return; + } + if (f.size() > 1024 * 1024) { + error(qsl("Too big file: %1").arg(f.size())); + return; + } + QByteArray data = f.readAll(); + f.close(); + + try { + const char *from = data.constData(), *end = data.constData() + data.size(); + while (true) { + QString name, value; + if (!readKeyValue(from, end, name, value)) { + break; + } + if (!feedKeyValue(name, value)) { + break; + } + } + } catch (exception &e) { + error(QString::fromUtf8(e.what())); + return; + } +} diff --git a/Telegram/SourceFiles/langloaderplain.h b/Telegram/SourceFiles/langloaderplain.h new file mode 100644 index 000000000..5438c841c --- /dev/null +++ b/Telegram/SourceFiles/langloaderplain.h @@ -0,0 +1,27 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "lang.h" + +class LangLoaderPlain : public LangLoader { +public: + + LangLoaderPlain(const QString &file); + +}; diff --git a/Telegram/SourceFiles/layerwidget.cpp b/Telegram/SourceFiles/layerwidget.cpp new file mode 100644 index 000000000..86421e353 --- /dev/null +++ b/Telegram/SourceFiles/layerwidget.cpp @@ -0,0 +1,424 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" + +#include "layerwidget.h" +#include "application.h" +#include "window.h" +#include "mainwidget.h" +#include "gui/filedialog.h" + +BackgroundWidget::BackgroundWidget(QWidget *parent, LayeredWidget *w) : QWidget(parent), w(w), _hidden(0), + aBackground(0), aBackgroundFunc(anim::easeOutCirc), hiding(false), shadow(st::boxShadow) { + w->setParent(this); + setGeometry(0, 0, App::wnd()->width(), App::wnd()->height()); + aBackground.start(1); + anim::start(this); + show(); + connect(w, SIGNAL(closed()), this, SLOT(onInnerClose())); + connect(w, SIGNAL(resized()), this, SLOT(update())); + w->setFocus(); +} + +void BackgroundWidget::paintEvent(QPaintEvent *e) { + bool trivial = (rect() == e->rect()); + + QPainter p(this); + if (!trivial) { + p.setClipRect(e->rect()); + } + p.setOpacity(st::layerAlpha * aBackground.current()); + p.fillRect(rect(), st::layerBG->b); + + p.setOpacity(aBackground.current()); + shadow.paint(p, w->boxRect()); +} + +void BackgroundWidget::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + startHide(); + } +} + +void BackgroundWidget::mousePressEvent(QMouseEvent *e) { +} + +void BackgroundWidget::onClose() { + startHide(); +} + +void BackgroundWidget::onInnerClose() { + if (_hidden) { + w->deleteLater(); + w = _hidden; + _hidden = 0; + w->show(); + resizeEvent(0); + w->animStep(1); + update(); + } else { + onClose(); + } +} + +void BackgroundWidget::startHide() { + if (App::main()) App::main()->setInnerFocus(); + hiding = true; + aBackground.start(0); + anim::start(this); + w->startHide(); +} + +void BackgroundWidget::resizeEvent(QResizeEvent *e) { + w->parentResized(); +} + +void BackgroundWidget::replaceInner(LayeredWidget *n) { + if (_hidden) _hidden->deleteLater(); + _hidden = w; + _hidden->hide(); + w = n; + w->setParent(this); + connect(w, SIGNAL(closed()), this, SLOT(onInnerClose())); + connect(w, SIGNAL(resized()), this, SLOT(update())); + w->show(); + resizeEvent(0); + w->animStep(1); + update(); +} + +bool BackgroundWidget::animStep(float64 ms) { + float64 dt = ms / (hiding ? st::layerHideDuration : st::layerSlideDuration); + w->animStep(dt); + bool res = true; + if (dt >= 1) { + aBackground.finish(); + if (hiding) { + QTimer::singleShot(0, App::wnd(), SLOT(layerHidden())); + } + res = false; + } else { + aBackground.update(dt, aBackgroundFunc); + } + update(); + return res; +} + +BackgroundWidget::~BackgroundWidget() { + if (App::wnd()) App::wnd()->noBox(this); + w->deleteLater(); + if (_hidden) _hidden->deleteLater(); +} + +LayerWidget::LayerWidget(QWidget *parent, PhotoData *photo, HistoryItem *item) : QWidget(parent), photo(photo), video(0), + aBackground(0), aOver(0), iX(App::wnd()->width() / 2), iY(App::wnd()->height() / 2), iW(0), iCoordFunc(anim::sineInOut), aOverFunc(anim::linear), aBackgroundFunc(anim::easeOutCirc), hiding(false), + _touchPress(false), _touchMove(false), _touchRightButton(false), _menu(0) { + int32 x, y, w; + if (App::wnd()->getPhotoCoords(photo, x, y, w)) { + iX = anim::ivalue(x); + iY = anim::ivalue(y); + iW = anim::ivalue(w); + } + photo->full->load(); + setGeometry(0, 0, App::wnd()->width(), App::wnd()->height()); + aBackground.start(1); + aOver.start(1); + anim::start(this); + show(); + setFocus(); + App::contextItem(item); + + setAttribute(Qt::WA_AcceptTouchEvents); + _touchTimer.setSingleShot(true); + connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer())); +} + +LayerWidget::LayerWidget(QWidget *parent, VideoData *video, HistoryItem *item) : QWidget(parent), photo(0), video(video), + aBackground(0), aOver(0), iX(App::wnd()->width() / 2), iY(App::wnd()->height() / 2), iW(0), iCoordFunc(anim::sineInOut), aOverFunc(anim::linear), aBackgroundFunc(anim::easeOutCirc), hiding(false), + _touchPress(false), _touchMove(false), _touchRightButton(false), _menu(0) { + int32 x, y, w; + if (App::wnd()->getVideoCoords(video, x, y, w)) { + iX = anim::ivalue(x); + iY = anim::ivalue(y); + iW = anim::ivalue(w); + } + setGeometry(0, 0, App::wnd()->width(), App::wnd()->height()); + aBackground.start(1); + aOver.start(1); + anim::start(this); + show(); + setFocus(); + App::contextItem(item); + + setAttribute(Qt::WA_AcceptTouchEvents); + _touchTimer.setSingleShot(true); + connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer())); +} + +PhotoData *LayerWidget::photoShown() { + return hiding ? 0 : photo; +} + +void LayerWidget::onTouchTimer() { + _touchRightButton = true; +} + +bool LayerWidget::event(QEvent *e) { + if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { + QTouchEvent *ev = static_cast(e); + if (ev->device()->type() == QTouchDevice::TouchScreen) { + touchEvent(ev); + return true; + } + } + return QWidget::event(e); +} + +void LayerWidget::touchEvent(QTouchEvent *e) { + switch (e->type()) { + case QEvent::TouchBegin: + if (_touchPress || e->touchPoints().isEmpty()) return; + _touchTimer.start(QApplication::startDragTime()); + _touchPress = true; + _touchMove = _touchRightButton = false; + _touchStart = e->touchPoints().cbegin()->screenPos().toPoint(); + break; + + case QEvent::TouchUpdate: + if (!_touchPress || e->touchPoints().isEmpty()) return; + if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) { + _touchMove = true; + } + break; + + case QEvent::TouchEnd: + if (!_touchPress) return; + if (!_touchMove && App::wnd()) { + Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton); + QPoint mapped(mapFromGlobal(_touchStart)), winMapped(App::wnd()->mapFromGlobal(_touchStart)); + + QMouseEvent pressEvent(QEvent::MouseButtonPress, mapped, winMapped, _touchStart, btn, Qt::MouseButtons(btn), Qt::KeyboardModifiers()); + pressEvent.accept(); + mousePressEvent(&pressEvent); + + QMouseEvent releaseEvent(QEvent::MouseButtonRelease, mapped, winMapped, _touchStart, btn, Qt::MouseButtons(btn), Qt::KeyboardModifiers()); + mouseReleaseEvent(&releaseEvent); + + if (_touchRightButton) { + QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart); + contextMenuEvent(&contextEvent); + } + } + _touchTimer.stop(); + _touchPress = _touchMove = _touchRightButton = false; + break; + + case QEvent::TouchCancel: + _touchPress = false; + _touchTimer.stop(); + break; + } +} + +void LayerWidget::onMenuDestroy(QObject *obj) { + if (_menu == obj) { + _menu = 0; + } +} + +void LayerWidget::paintEvent(QPaintEvent *e) { + bool trivial = (rect() == e->rect()); + + QPainter p(this); + if (!trivial) { + p.setClipRect(e->rect()); + } + p.setOpacity(st::layerAlpha * aBackground.current()); + p.fillRect(rect(), st::layerBG->b); + if (iW.current()) { + if (!hiding) p.setOpacity(aOver.current()); + if (animating()) { + const QPixmap &pm((photo ? (photo->full->loaded() ? photo->full : photo->thumb) : video->thumb)->pix()); + int32 h = pm.width() ? (pm.height() * iW.current() / pm.width()) : 1; + p.drawPixmap(iX.current(), iY.current(), iW.current(), h, pm); + if (!hiding) { + p.setOpacity(1); + p.setClipRect(App::wnd()->photoRect(), Qt::IntersectClip); + p.drawPixmap(iX.current(), iY.current(), iW.current(), h, pm); + } + } else { + const QPixmap &pm((photo ? (photo->full->loaded() ? photo->full : photo->thumb) : video->thumb)->pixNoCache(iW.current(), 0, !animating())); + p.drawPixmap(iX.current(), iY.current(), pm); + } + } +} + +void LayerWidget::keyPressEvent(QKeyEvent *e) { + if (!_menu && e->key() == Qt::Key_Escape) { + startHide(); + } else if (photo && photo->full->loaded() && (e == QKeySequence::Save || e == QKeySequence::SaveAs)) { + QString file; + if (filedialogGetSaveFile(file, lang(lng_save_photo), qsl("JPEG Image (*.jpg);;All files (*.*)"), filedialogDefaultName(qsl("photo"), qsl(".jpg")))) { + if (!file.isEmpty()) { + photo->full->pix().toImage().save(file, "JPG"); + } + } + } else if (photo && photo->full->loaded() && (e->key() == Qt::Key_Copy || e->key() == Qt::Key_C && e->modifiers().testFlag(Qt::ControlModifier))) { + QApplication::clipboard()->setPixmap(photo->full->pix()); + } +} + +void LayerWidget::mousePressEvent(QMouseEvent *e) { + if (_menu) return; + if (e->button() == Qt::LeftButton) startHide(); +} + +void LayerWidget::contextMenuEvent(QContextMenuEvent *e) { + if (photo && photo->full->loaded() && !hiding) { + if (_menu) { + _menu->deleteLater(); + _menu = 0; + } + _menu = new QMenu(this); + _menu->addAction(lang(lng_context_save_image), this, SLOT(saveContextImage()))->setEnabled(true); + _menu->addAction(lang(lng_context_copy_image), this, SLOT(copyContextImage()))->setEnabled(true); + _menu->addAction(lang(lng_context_close_image), this, SLOT(startHide()))->setEnabled(true); + if (App::contextItem()) { + if (dynamic_cast(App::contextItem())) { + _menu->addAction(lang(lng_context_forward_image), this, SLOT(forwardMessage()))->setEnabled(true); + } + _menu->addAction(lang(lng_context_delete_image), this, SLOT(deleteMessage()))->setEnabled(true); + } else if (App::self() && App::self()->photoId == photo->id || photo->chat && photo->chat->photoId == photo->id) { + _menu->addAction(lang(lng_context_delete_image), this, SLOT(deleteMessage()))->setEnabled(true); + } + _menu->setAttribute(Qt::WA_DeleteOnClose); + + _menu->setAttribute(Qt::WA_DeleteOnClose); + connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*))); + _menu->popup(e->globalPos()); + e->accept(); + } +} + +void LayerWidget::deleteMessage() { + if (!App::contextItem()) { + if (App::self() && photo && App::self()->photoId == photo->id) { + App::app()->peerClearPhoto(App::self()->id); + } else if (photo->chat && photo->chat->photoId == photo->id) { + App::app()->peerClearPhoto(photo->chat->id); + } + startHide(); + } else { + App::wnd()->layerHidden(); + App::main()->deleteLayer(); + } +} + +void LayerWidget::forwardMessage() { + startHide(); + App::main()->forwardLayer(); +} + +void LayerWidget::saveContextImage() { + if (!photo || !photo->full->loaded() || hiding) return; + + QString file; + if (filedialogGetSaveFile(file, lang(lng_save_photo), qsl("JPEG Image (*.jpg);;All files (*.*)"), filedialogDefaultName(qsl("photo"), qsl(".jpg")))) { + if (!file.isEmpty()) { + photo->full->pix().toImage().save(file, "JPG"); + } + } +} + +void LayerWidget::copyContextImage() { + if (!photo || !photo->full->loaded() || hiding) return; + + QApplication::clipboard()->setPixmap(photo->full->pix()); +} + +void LayerWidget::startHide() { + hiding = true; + aBackground.start(0); + anim::start(this); +} + +void LayerWidget::resizeEvent(QResizeEvent *e) { + int32 w = width() - st::layerPadding.left() - st::layerPadding.right(), h = height() - st::layerPadding.top() - st::layerPadding.bottom(); + int32 iw = (photo ? photo->full : video->thumb)->width(), ih = (photo ? photo->full : video->thumb)->height(); + if (!iw || !ih) { + iw = ih = 1; + } else { + switch (cScale()) { + case dbisOneAndQuarter: iw = qRound(float64(iw) * 1.25 - 0.01); ih = qRound(float64(ih) * 1.25 - 0.01); break; + case dbisOneAndHalf: iw = qRound(float64(iw) * 1.5 - 0.01); ih = qRound(float64(ih) * 1.5 - 0.01); break; + case dbisTwo: iw *= 2; ih *= 2; break; + } + } + if (w >= iw && h >= ih) { + iW.start(iw); + iX.start(st::layerPadding.left() + (w - iw) / 2); + iY.start(st::layerPadding.top() + (h - ih) / 2); + } else if (w * ih > iw * h) { + int32 nw = qRound(iw * float64(h) / ih); + iW.start(nw); + iX.start(st::layerPadding.left() + (w - nw) / 2); + iY.start(st::layerPadding.top()); + } else { + int32 nh = qRound(ih * float64(w) / iw); + iW.start(w); + iX.start(st::layerPadding.left()); + iY.start(st::layerPadding.top() + (h - nh) / 2); + } + if (!animating() || hiding) { + iX.finish(); + iY.finish(); + iW.finish(); + } +} + +bool LayerWidget::animStep(float64 ms) { + float64 dt = ms / (hiding ? st::layerHideDuration : st::layerSlideDuration); + bool res = true; + if (dt >= 1) { + aBackground.finish(); + aOver.finish(); + iX.finish(); + iY.finish(); + iW.finish(); + if (hiding) { + QTimer::singleShot(0, App::wnd(), SLOT(layerHidden())); + } + res = false; + } else { + aBackground.update(dt, aBackgroundFunc); + if (!hiding) { + aOver.update(dt, aOverFunc); + iX.update(dt, iCoordFunc); + iY.update(dt, iCoordFunc); + iW.update(dt, iCoordFunc); + } + } + update(); + return res; +} + +LayerWidget::~LayerWidget() { + if (App::wnd()) App::wnd()->noLayer(this); + delete _menu; +} diff --git a/Telegram/SourceFiles/layerwidget.h b/Telegram/SourceFiles/layerwidget.h new file mode 100644 index 000000000..0cd9a97c1 --- /dev/null +++ b/Telegram/SourceFiles/layerwidget.h @@ -0,0 +1,134 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "gui/boxshadow.h" + +class LayeredWidget : public QWidget { + Q_OBJECT + +public: + + virtual void animStep(float64 ms) { + } + virtual void parentResized() = 0; + virtual void startHide() { + } + + virtual void resizeEvent(QResizeEvent *e) { + emit resized(); + } + + virtual QRect boxRect() const { + QRect res(rect()); + res.moveTopLeft(geometry().topLeft()); + return res; + } + +signals: + + void closed(); + void resized(); + +}; + +class BackgroundWidget : public QWidget, public Animated { + Q_OBJECT + +public: + + BackgroundWidget(QWidget *parent, LayeredWidget *w); + + void paintEvent(QPaintEvent *e); + void keyPressEvent(QKeyEvent *e); + void mousePressEvent(QMouseEvent *e); + void resizeEvent(QResizeEvent *e); + + void replaceInner(LayeredWidget *n); + + bool animStep(float64 ms); + + ~BackgroundWidget(); + +public slots: + + void onClose(); + void onInnerClose(); + +private: + + void startHide(); + + LayeredWidget *w, *_hidden; + anim::fvalue aBackground; + anim::transition aBackgroundFunc; + bool hiding; + + BoxShadow shadow; +}; + +class LayerWidget : public QWidget, public Animated { + Q_OBJECT + +public: + + LayerWidget(QWidget *parent, PhotoData *photo, HistoryItem *item); + LayerWidget(QWidget *parent, VideoData *video, HistoryItem *item); + + PhotoData *photoShown(); + + bool event(QEvent *e); + void touchEvent(QTouchEvent *e); + void paintEvent(QPaintEvent *e); + void keyPressEvent(QKeyEvent *e); + void mousePressEvent(QMouseEvent *e); + void resizeEvent(QResizeEvent *e); + void contextMenuEvent(QContextMenuEvent *e); + + bool animStep(float64 ms); + + ~LayerWidget(); + +public slots: + + void onTouchTimer(); + + void saveContextImage(); + void copyContextImage(); + void startHide(); + + void deleteMessage(); + void forwardMessage(); + + void onMenuDestroy(QObject *obj); + +private: + + PhotoData *photo; + VideoData *video; + anim::fvalue aBackground, aOver; + anim::ivalue iX, iY, iW; + anim::transition iCoordFunc, aBackgroundFunc, aOverFunc; + bool hiding; + + bool _touchPress, _touchMove, _touchRightButton; + QTimer _touchTimer; + QPoint _touchStart; + + QMenu *_menu; +}; diff --git a/Telegram/SourceFiles/localimageloader.cpp b/Telegram/SourceFiles/localimageloader.cpp new file mode 100644 index 000000000..ed6d97b85 --- /dev/null +++ b/Telegram/SourceFiles/localimageloader.cpp @@ -0,0 +1,297 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "localimageloader.h" +#include + +LocalImageLoaderPrivate::LocalImageLoaderPrivate(int32 currentUser, LocalImageLoader *loader, QThread *thread) : QObject(0), user(currentUser), loader(loader) { + moveToThread(thread); + connect(loader, SIGNAL(needToPrepare()), this, SLOT(prepareImages())); + connect(this, SIGNAL(imageReady()), loader, SLOT(onImageReady())); + connect(this, SIGNAL(imageFailed(quint64)), loader, SLOT(onImageFailed(quint64))); +}; + +void LocalImageLoaderPrivate::prepareImages() { + QString file, filename, mime; + int32 filesize; + QImage img; + QByteArray data; + PeerId peer; + uint64 id, jpeg_id; + ToPrepareMediaType type; + { + QMutexLocker lock(loader->toPrepareMutex()); + ToPrepareMedias &list(loader->toPrepareMedias()); + if (list.isEmpty()) return; + + file = list.front().file; + img = list.front().img; + data = list.front().data; + peer = list.front().peer; + id = list.front().id; + type = list.front().type; + } + + if (img.isNull()) { + if (!file.isEmpty()) { + QFileInfo info(file); + if (type == ToPrepareAuto) { + QString lower(file.toLower()); + const QStringList &photoExtensions(cPhotoExtensions()); + for (QStringList::const_iterator i = photoExtensions.cbegin(), e = photoExtensions.cend(); i != e; ++i) { + if (lower.lastIndexOf(*i) == lower.size() - i->size()) { + if (info.size() < MaxUploadPhotoSize) { + type = ToPreparePhoto; + break; + } + } + } + if (type == ToPrepareAuto && info.size() < MaxUploadDocumentSize) { + type = ToPrepareDocument; + } + } + if (type != ToPrepareAuto && info.size() < MaxUploadPhotoSize) { + img = App::readImage(file); + } + if (type == ToPrepareDocument) { + mime = QMimeDatabase().mimeTypeForFile(info).name(); + } + filename = info.fileName(); + filesize = info.size(); + } else if (!data.isEmpty()) { + img = App::readImage(data); + if (type == ToPrepareAuto) { + if (!img.isNull() && data.size() < MaxUploadPhotoSize) { + type = ToPreparePhoto; + } else if (data.size() < MaxUploadDocumentSize) { + type = ToPrepareDocument; + } else { + img = QImage(); + } + } + QMimeType mimeType = QMimeDatabase().mimeTypeForData(data); + if (type == ToPrepareDocument) { + mime = mimeType.name(); + } + filename = qsl("Document"); + QStringList patterns = mimeType.globPatterns(); + if (!patterns.isEmpty()) { + filename = patterns.front().replace('*', filename); + } + filesize = data.size(); + } + } else { + type = ToPreparePhoto; // only photo from QImage + filename = qsl("Photo.jpg"); + filesize = 0; + } + + if (img.isNull() && (type != ToPrepareDocument || !filesize) || type == ToPrepareAuto || img.isNull() && file.isEmpty() && data.isEmpty()) { // if could not decide what type + { + QMutexLocker lock(loader->toPrepareMutex()); + ToPrepareMedias &list(loader->toPrepareMedias()); + list.pop_front(); + } + + QTimer::singleShot(1, this, SLOT(prepareImages())); + + emit imageFailed(id); + } else { + PreparedPhotoThumbs photoThumbs; + QVector photoSizes; + + MTPPhotoSize thumb(MTP_photoSizeEmpty(MTP_string(""))); + MTPPhoto photo(MTP_photoEmpty(MTP_long(0))); + MTPDocument document(MTP_documentEmpty(MTP_long(0))); + + QByteArray jpeg; + if (type == ToPreparePhoto) { + int32 w = img.width(), h = img.height(); + + QPixmap thumb = (w > 100 || h > 100) ? QPixmap::fromImage(img.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(img); + photoThumbs.insert('s', thumb); + photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0))); + + QPixmap full = (w > 800 || h > 800) ? QPixmap::fromImage(img.scaled(800, 800, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(img); + photoThumbs.insert('x', full); + photoSizes.push_back(MTP_photoSize(MTP_string("x"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0))); + + { + QBuffer jpegBuffer(&jpeg); + full.save(&jpegBuffer, "JPG", 87); + } + if (!filesize) filesize = jpeg.size(); + + photo = MTP_photo(MTP_long(id), MTP_long(0), MTP_int(user), MTP_int(unixtime()), MTP_string(""), MTP_geoPointEmpty(), MTP_vector(photoSizes)); + + jpeg_id = id; + } else if ((type == ToPrepareVideo || type == ToPrepareDocument) && !img.isNull()) { + int32 w = img.width(), h = img.height(); + + QPixmap full = (w > 90 || h > 90) ? QPixmap::fromImage(img.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(img); + + { + QBuffer jpegBuffer(&jpeg); + full.save(&jpegBuffer, "JPG", 87); + } + + photoThumbs.insert('0', full); + thumb = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0)); + + jpeg_id = MTP::nonce(); + } + + if (type == ToPrepareDocument) { + document = MTP_document(MTP_long(id), MTP_long(0), MTP_int(MTP::authedId()), MTP_int(unixtime()), MTP_string(filename), MTP_string(mime), MTP_int(filesize), thumb, MTP_int(MTP::maindc())); + } + + { + QMutexLocker lock(loader->readyMutex()); + loader->readyList().push_back(ReadyLocalMedia(type, file, filename, filesize, data, id, jpeg_id, peer, photo, photoThumbs, document, jpeg)); + } + + { + QMutexLocker lock(loader->toPrepareMutex()); + ToPrepareMedias &list(loader->toPrepareMedias()); + list.pop_front(); + } + + QTimer::singleShot(1, this, SLOT(prepareImages())); + + emit imageReady(); + } +} + +LocalImageLoaderPrivate::~LocalImageLoaderPrivate() { + loader = 0; +} + +LocalImageLoader::LocalImageLoader(QObject *parent) : QObject(parent), thread(0), priv(0) { +} + +void LocalImageLoader::append(const QStringList &files, const PeerId &peer, ToPrepareMediaType t) { + { + QMutexLocker lock(toPrepareMutex()); + for (QStringList::const_iterator i = files.cbegin(), e = files.cend(); i != e; ++i) { + toPrepare.push_back(ToPrepareMedia(*i, peer, t)); + } + } + if (!thread) { + thread = new QThread(); + priv = new LocalImageLoaderPrivate(MTP::authedId(), this, thread); + thread->start(); + } + emit needToPrepare(); +} + +PhotoId LocalImageLoader::append(const QByteArray &img, const PeerId &peer, ToPrepareMediaType t) { + PhotoId result = 0; + { + QMutexLocker lock(toPrepareMutex()); + toPrepare.push_back(ToPrepareMedia(img, peer, t)); + result = toPrepare.back().id; + } + if (!thread) { + thread = new QThread(); + priv = new LocalImageLoaderPrivate(MTP::authedId(), this, thread); + thread->start(); + } + emit needToPrepare(); + return result; +} + +PhotoId LocalImageLoader::append(const QImage &img, const PeerId &peer, ToPrepareMediaType t) { + PhotoId result = 0; + { + QMutexLocker lock(toPrepareMutex()); + toPrepare.push_back(ToPrepareMedia(img, peer, t)); + result = toPrepare.back().id; + } + if (!thread) { + thread = new QThread(); + priv = new LocalImageLoaderPrivate(MTP::authedId(), this, thread); + thread->start(); + } + emit needToPrepare(); + return result; +} + +PhotoId LocalImageLoader::append(const QString &file, const PeerId &peer, ToPrepareMediaType t) { + PhotoId result = 0; + { + QMutexLocker lock(toPrepareMutex()); + toPrepare.push_back(ToPrepareMedia(file, peer, t)); + result = toPrepare.back().id; + } + if (!thread) { + thread = new QThread(); + priv = new LocalImageLoaderPrivate(MTP::authedId(), this, thread); + thread->start(); + } + emit needToPrepare(); + return result; +} + +void LocalImageLoader::onImageReady() { + { + QMutexLocker lock(toPrepareMutex()); + if (toPrepare.isEmpty()) { + if (priv) priv->deleteLater(); + priv = 0; + if (thread) thread->deleteLater(); + thread = 0; + } + } + + emit imageReady(); +} + +void LocalImageLoader::onImageFailed(quint64 id) { + { + QMutexLocker lock(toPrepareMutex()); + if (toPrepare.isEmpty()) { + if (priv) priv->deleteLater(); + priv = 0; + if (thread) thread->deleteLater(); + thread = 0; + } + } + + emit imageFailed(id); +} + +QMutex *LocalImageLoader::readyMutex() { + return &readyLock; +} + +ReadyLocalMedias &LocalImageLoader::readyList() { + return ready; +} + +QMutex *LocalImageLoader::toPrepareMutex() { + return &toPrepareLock; +} + +ToPrepareMedias &LocalImageLoader::toPrepareMedias() { + return toPrepare; +} + +LocalImageLoader::~LocalImageLoader() { + delete priv; + delete thread; +} diff --git a/Telegram/SourceFiles/localimageloader.h b/Telegram/SourceFiles/localimageloader.h new file mode 100644 index 000000000..a0cf22097 --- /dev/null +++ b/Telegram/SourceFiles/localimageloader.h @@ -0,0 +1,134 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +enum ToPrepareMediaType { + ToPrepareAuto, + ToPreparePhoto, + ToPrepareVideo, + ToPrepareDocument, +}; + +struct ToPrepareMedia { + ToPrepareMedia(const QString &file, const PeerId &peer, ToPrepareMediaType t) : file(file), peer(peer), id(MTP::nonce()), type(t) { + } + ToPrepareMedia(const QImage &img, const PeerId &peer, ToPrepareMediaType t) : img(img), peer(peer), id(MTP::nonce()), type(t) { + } + ToPrepareMedia(const QByteArray &data, const PeerId &peer, ToPrepareMediaType t) : data(data), peer(peer), id(MTP::nonce()), type(t) { + } + PhotoId id; + QString file; + QImage img; + QByteArray data; + PeerId peer; + ToPrepareMediaType type; +}; +typedef QList ToPrepareMedias; + +typedef QMap LocalFileParts; +struct ReadyLocalMedia { + ReadyLocalMedia(ToPrepareMediaType type, const QString &file, const QString &filename, int32 filesize, const QByteArray &data, const uint64 &id, const uint64 &jpeg_id, const PeerId &peer, const MTPPhoto &photo, const PreparedPhotoThumbs &photoThumbs, const MTPDocument &document, const QByteArray &jpeg) : + type(type), file(file), filename(filename), filesize(filesize), data(data), id(id), jpeg_id(jpeg_id), peer(peer), photo(photo), photoThumbs(photoThumbs), document(document) { + if (!jpeg.isEmpty()) { + int32 size = jpeg.size(); + for (int32 i = 0, part = 0; i < size; i += UploadPartSize, ++part) { + parts.insert(part, jpeg.mid(i, UploadPartSize)); + } + jpeg_md5.resize(32); + hashMd5Hex(jpeg.constData(), jpeg.size(), jpeg_md5.data()); + } + } + ToPrepareMediaType type; + QString file, filename; + int32 filesize; + QByteArray data; + uint64 id, jpeg_id; // id always file-id of media, jpeg_id is file-id of thumb ( == id for photos) + PeerId peer; + + MTPPhoto photo; + MTPDocument document; + PreparedPhotoThumbs photoThumbs; + LocalFileParts parts; + QByteArray jpeg_md5; +}; +typedef QList ReadyLocalMedias; + +class LocalImageLoader; +class LocalImageLoaderPrivate : public QObject { + Q_OBJECT + +public: + + LocalImageLoaderPrivate(int32 currentUser, LocalImageLoader *loader, QThread *thread); + ~LocalImageLoaderPrivate(); + +public slots: + + void prepareImages(); + +signals: + + void imageReady(); + void imageFailed(quint64 id); + +private: + + LocalImageLoader *loader; + int32 user; + +}; + +class LocalImageLoader : public QObject { + Q_OBJECT + +public: + + LocalImageLoader(QObject *parent); + void append(const QStringList &files, const PeerId &peer, ToPrepareMediaType t = ToPrepareAuto); + PhotoId append(const QByteArray &img, const PeerId &peer, ToPrepareMediaType t = ToPrepareAuto); + PhotoId append(const QImage &img, const PeerId &peer, ToPrepareMediaType t = ToPreparePhoto); + PhotoId append(const QString &file, const PeerId &peer, ToPrepareMediaType t = ToPrepareAuto); + + QMutex *readyMutex(); + ReadyLocalMedias &readyList(); + + QMutex *toPrepareMutex(); + ToPrepareMedias &toPrepareMedias(); + + ~LocalImageLoader(); + +public slots: + + void onImageReady(); + void onImageFailed(quint64 id); + +signals: + + void imageReady(); + void imageFailed(quint64 id); + void needToPrepare(); + +private: + + ReadyLocalMedias ready; + ToPrepareMedias toPrepare; + QMutex readyLock, toPrepareLock; + QThread *thread; + LocalImageLoaderPrivate *priv; + +}; diff --git a/Telegram/SourceFiles/logs.cpp b/Telegram/SourceFiles/logs.cpp new file mode 100644 index 000000000..4c81c504d --- /dev/null +++ b/Telegram/SourceFiles/logs.cpp @@ -0,0 +1,207 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "pspecific.h" + +namespace { + QFile debugLog, tcpLog, mtpLog, mainLog; + QTextStream *debugLogStream = 0, *tcpLogStream = 0, *mtpLogStream = 0, *mainLogStream = 0; + QChar zero('0'); + + QMutex debugLogMutex, mainLogMutex; + + class _StreamCreator { + public: + ~_StreamCreator() { + logsClose(); + } + }; + + QString debugLogEntryStart() { + static uint32 logEntry = 0; + + QDateTime tm(QDateTime::currentDateTime()); + + QThread *thread = QThread::currentThread(); + MTPThread *mtpThread = dynamic_cast(thread); + uint32 threadId = mtpThread ? mtpThread->getThreadId() : 0; + + return QString("[%1 %2-%3]").arg(tm.toString("hh:mm:ss.zzz")).arg(QString("%1").arg(threadId, 2, 10, zero)).arg(++logEntry, 7, 10, zero); + } +} + +void debugLogWrite(const char *file, int32 line, const QString &v) { + if (!cDebug() || !debugLogStream) return; + + const char *last = strstr(file, "/"), *found = 0; + while (last) { + found = last; + last = strstr(last + 1, "/"); + } + last = strstr(file, "\\"); + while (last) { + found = last; + last = strstr(last + 1, "\\"); + } + if (found) { + file = found + 1; + } + + { + QMutexLocker lock(&debugLogMutex); + QString msg(QString("%1 %2 (%3 : %4)\n").arg(debugLogEntryStart()).arg(v).arg(file).arg(line)); + (*debugLogStream) << msg; + debugLogStream->flush(); +#ifdef Q_OS_WIN + OutputDebugString(reinterpret_cast(msg.utf16())); +#endif + } +} + +void tcpLogWrite(const QString &v) { + if (!cDebug() || !tcpLogStream) return; + + { + QMutexLocker lock(&debugLogMutex); + (*tcpLogStream) << QString("%1 %2\n").arg(debugLogEntryStart()).arg(v); + tcpLogStream->flush(); + } +} + +void mtpLogWrite(int32 dc, const QString &v) { + if (!cDebug() || !mtpLogStream) return; + + { + QMutexLocker lock(&debugLogMutex); + (*mtpLogStream) << QString("%1 (dc:%2) %3\n").arg(debugLogEntryStart()).arg(dc).arg(v); + mtpLogStream->flush(); + } +} + +void logWrite(const QString &v) { + if (!mainLog.isOpen()) return; + + time_t t = time(NULL); + struct tm tm; + mylocaltime(&tm, &t); + + { + QMutexLocker lock(&mainLogMutex); + QString msg(QString("[%1.%2.%3 %4:%5:%6] %7\n").arg(tm.tm_year + 1900).arg(tm.tm_mon + 1, 2, 10, zero).arg(tm.tm_mday, 2, 10, zero).arg(tm.tm_hour, 2, 10, zero).arg(tm.tm_min, 2, 10, zero).arg(tm.tm_sec, 2, 10, zero).arg(v)); + (*mainLogStream) << msg; + mainLogStream->flush(); + } + + if (cDebug()) debugLogWrite("logs", 0, v); +} + +void logsInit() { + static _StreamCreator streamCreator; + if (mainLogStream) return; + + QString oldDir = cWorkingDir(); + mainLog.setFileName(cWorkingDir() + "log.txt"); + mainLog.open(QIODevice::WriteOnly | QIODevice::Text); + if (!mainLog.isOpen()) { + cForceWorkingDir(cExeDir()); + mainLog.setFileName(cWorkingDir() + "log.txt"); + mainLog.open(QIODevice::WriteOnly | QIODevice::Text); + if (!mainLog.isOpen()) { + cForceWorkingDir(psAppDataPath()); + mainLog.setFileName(cWorkingDir() + "log.txt"); + mainLog.open(QIODevice::WriteOnly | QIODevice::Text); + } + } + if (mainLog.isOpen()) { + mainLogStream = new QTextStream(); + mainLogStream->setDevice(&mainLog); + mainLogStream->setCodec("UTF-8"); + } else { + cForceWorkingDir(oldDir); + } + cForceWorkingDir(QDir(cWorkingDir()).absolutePath() + '/'); + if (cDebug()) logsInitDebug(); +} + +void logsInitDebug() { + if (debugLogStream) return; + + time_t t = time(NULL); + struct tm tm; + mylocaltime(&tm, &t); + + QString logPrefix = QString("%1%2%3_%4%5%6_").arg(tm.tm_year + 1900).arg(tm.tm_mon + 1, 2, 10, zero).arg(tm.tm_mday, 2, 10, zero).arg(tm.tm_hour, 2, 10, zero).arg(tm.tm_min, 2, 10, zero).arg(tm.tm_sec, 2, 10, zero); + + debugLog.setFileName(cWorkingDir() + "DebugLogs/" + logPrefix + "log.txt"); + if (!debugLog.open(QIODevice::WriteOnly | QIODevice::Text)) { + QDir dir(QDir::current()); + dir.mkdir(cWorkingDir() + "DebugLogs"); + debugLog.open(QIODevice::WriteOnly | QIODevice::Text); + } + if (debugLog.isOpen()) { + debugLogStream = new QTextStream(); + debugLogStream->setDevice(&debugLog); + debugLogStream->setCodec("UTF-8"); + } + tcpLog.setFileName(cWorkingDir() + "DebugLogs/" + logPrefix + "tcp.txt"); + if (tcpLog.open(QIODevice::WriteOnly | QIODevice::Text)) { + tcpLogStream = new QTextStream(); + tcpLogStream->setDevice(&tcpLog); + tcpLogStream->setCodec("UTF-8"); + } + mtpLog.setFileName(cWorkingDir() + "DebugLogs/" + logPrefix + "mtp.txt"); + if (mtpLog.open(QIODevice::WriteOnly | QIODevice::Text)) { + mtpLogStream = new QTextStream(); + mtpLogStream->setDevice(&mtpLog); + mtpLogStream->setCodec("UTF-8"); + } +} + +void logsClose() { + if (cDebug()) { + if (debugLogStream) { + delete debugLogStream; + debugLogStream = 0; + debugLog.close(); + } + if (tcpLogStream) { + delete tcpLogStream; + tcpLogStream = 0; + tcpLog.close(); + } + if (mtpLogStream) { + delete mtpLogStream; + mtpLogStream = 0; + mtpLog.close(); + } + } + if (mainLogStream) { + delete mainLogStream; + mainLogStream = 0; + mainLog.close(); + } +} + +QString logVectorLong(const QVector &ids) { + if (!ids.size()) return "[void list]"; + QString idsStr = QString("[%1").arg(ids.cbegin()->v); + for (QVector::const_iterator i = ids.cbegin() + 1, e = ids.cend(); i != e; ++i) { + idsStr += QString(", %2").arg(i->v); + } + return idsStr + "]"; +} diff --git a/Telegram/SourceFiles/logs.h b/Telegram/SourceFiles/logs.h new file mode 100644 index 000000000..513b8ee34 --- /dev/null +++ b/Telegram/SourceFiles/logs.h @@ -0,0 +1,83 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#ifdef Q_OS_WIN +#define OUTPUT_LOG(msg) (OutputDebugString((QString msg + "\n").toStdWString().c_str())) +#endif + +#if (defined _DEBUG || defined _WITH_DEBUG) + +struct DebugLogMemoryBuffer { + DebugLogMemoryBuffer(const void *ptr, uint32 size) : p(ptr), s(size) { + } + QString str() const { + QString result; + const uchar *buf((const uchar*)p); + const char *hex = "0123456789ABCDEF"; + result.reserve(s * 3); + for (uint32 i = 0; i < s; ++i) { + result += hex[(buf[i] >> 4)]; + result += hex[buf[i] & 0x0F]; + result += ' '; + } + result.chop(1); + return result; + } + + const void *p; + uint32 s; +}; + +inline DebugLogMemoryBuffer mb(const void *ptr, uint32 size) { + return DebugLogMemoryBuffer(ptr, size); +} + +void debugLogWrite(const char *file, int32 line, const QString &v); +#define DEBUG_LOG(msg) (debugLogWrite(__FILE__, __LINE__, QString msg)) +//usage DEBUG_LOG(("log: %1 %2").arg(1).arg(2)) + +void tcpLogWrite(const QString &v); +#define TCP_LOG(msg) (tcpLogWrite(QString msg)) +//usage TCP_LOG(("log: %1 %2").arg(1).arg(2)) + +void mtpLogWrite(int32 dc, const QString &v); +#define MTP_LOG(dc, msg) (mtpLogWrite(dc, QString msg)) +//usage MTP_LOG(dc, ("log: %1 %2").arg(1).arg(2)) + +#else +#define DEBUG_LOG(msg) (void(0)) +#define TCP_LOG(msg) (void(0)) +#define MTP_LOG(dc, msg) (void(0)) +#endif + +inline const char *logBool(bool v) { + return v ? "[TRUE]" : "[FALSE]"; +} + +class MTPlong; +QString logVectorLong(const QVector &ids); + +#define LOG(msg) (logWrite(QString msg)) +//usage LOG(("log: %1 %2").arg(1).arg(2)) + +void logWrite(const QString &v); + +void logsInit(); +void logsInitDebug(); +void logsClose(); diff --git a/Telegram/SourceFiles/main.cpp b/Telegram/SourceFiles/main.cpp new file mode 100644 index 000000000..d6ecc5058 --- /dev/null +++ b/Telegram/SourceFiles/main.cpp @@ -0,0 +1,63 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "application.h" +#include "pspecific.h" + +int main(int argc, char *argv[]) { +#ifdef _NEED_WIN_GENERATE_DUMP + _oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter); +#endif + + settingsParseArgs(argc, argv); + for (uint32 i = 0; i < argc; ++i) { + if (string("-fixprevious") == argv[i]) { + return psFixPrevious(); + } else if (string("-cleanup") == argv[i]) { + return psCleanup(); + } + } + logsInit(); + + App::readConfig(); + if (cFromAutoStart() && !cAutoStart()) { + psAutoStart(false, true); + return 0; + } + + DEBUG_LOG(("Application Info: Telegram started, test mode: %1, exe dir: %2").arg(logBool(cTestMode())).arg(cExeDir())); + if (cDebug()) LOG(("Application Info: Telegram started in debug mode")); + + DEBUG_LOG(("Application Info: ideal thread count: %1, using %2 connections per session").arg(QThread::idealThreadCount()).arg(cConnectionsInSession())); + + Application app(argc, argv); + int result = App::quiting() ? 0 : app.exec(); + + DEBUG_LOG(("Application Info: Telegram done, result: %1").arg(result)); + + if (cRestartingUpdate()) { + DEBUG_LOG(("Application Info: executing updater to install update..")); + psExecUpdater(); + } else if (cRestarting()) { + DEBUG_LOG(("Application Info: executing Telegram, because of restart..")); + psExecTelegram(); + } + + logsClose(); + return result; +} diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp new file mode 100644 index 000000000..d373f283b --- /dev/null +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -0,0 +1,1648 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" +#include "lang.h" + +#include "boxes/addcontactbox.h" +#include "application.h" +#include "window.h" +#include "settingswidget.h" +#include "mainwidget.h" +#include "boxes/confirmbox.h" + +TopBarWidget::TopBarWidget(MainWidget *w) : QWidget(w), a_over(0), _drawShadow(true), _selCount(0), _selStrWidth(0), + _clearSelection(this, lang(lng_selected_clear), st::topBarButton), + _forward(this, lang(lng_selected_forward), st::topBarActionButton), + _delete(this, lang(lng_selected_delete), st::topBarActionButton), + _edit(this, lang(lng_profile_edit_contact), st::topBarButton), + _leaveGroup(this, lang(lng_profile_delete_and_exit), st::topBarButton), + _addContact(this, lang(lng_profile_add_contact), st::topBarButton), + _deleteContact(this, lang(lng_profile_delete_contact), st::topBarButton) { + + connect(&_forward, SIGNAL(clicked()), this, SLOT(onForwardSelection())); + connect(&_delete, SIGNAL(clicked()), this, SLOT(onDeleteSelection())); + connect(&_clearSelection, SIGNAL(clicked()), this, SLOT(onClearSelection())); + connect(&_addContact, SIGNAL(clicked()), this, SLOT(onAddContact())); + connect(&_deleteContact, SIGNAL(clicked()), this, SLOT(onDeleteContact())); + connect(&_edit, SIGNAL(clicked()), this, SLOT(onEdit())); + connect(&_leaveGroup, SIGNAL(clicked()), this, SLOT(onDeleteAndExit())); + + setCursor(style::cur_pointer); + showAll(); +} + +void TopBarWidget::onForwardSelection() { + if (App::main()) App::main()->forwardSelectedItems(); +} + +void TopBarWidget::onDeleteSelection() { + if (App::main()) App::main()->deleteSelectedItems(); +} + +void TopBarWidget::onClearSelection() { + if (App::main()) App::main()->clearSelectedItems(); +} + +void TopBarWidget::onEdit() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + if (p) App::wnd()->showLayer(new AddContactBox(p)); +} + +void TopBarWidget::onAddContact() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + UserData *u = (p && !p->chat) ? p->asUser() : 0; + if (u) App::wnd()->showLayer(new AddContactBox(u->firstName, u->lastName, u->phone)); +} + +void TopBarWidget::onDeleteContact() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + UserData *u = (p && !p->chat) ? p->asUser() : 0; + if (u) { + ConfirmBox *box = new ConfirmBox(lang(lng_sure_delete_contact).replace(qsl("{contact}"), p->name)); + connect(box, SIGNAL(confirmed()), this, SLOT(onDeleteContactSure())); + App::wnd()->showLayer(box); + } +} + +void TopBarWidget::onDeleteContactSure() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + UserData *u = (p && !p->chat) ? p->asUser() : 0; + if (u) { + App::main()->showPeer(0, true); + App::wnd()->hideLayer(); + MTP::send(MTPcontacts_DeleteContact(u->inputUser), App::main()->rpcDone(&MainWidget::deletedContact, u)); + } +} + +void TopBarWidget::onDeleteAndExit() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + ChatData *c = (p && p->chat) ? p->asChat() : 0; + if (c) { + ConfirmBox *box = new ConfirmBox(lang(lng_sure_delete_and_exit).replace(qsl("{group}"), p->name)); + connect(box, SIGNAL(confirmed()), this, SLOT(onDeleteAndExitSure())); + App::wnd()->showLayer(box); + } +} + +void TopBarWidget::onDeleteAndExitSure() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + ChatData *c = (p && p->chat) ? p->asChat() : 0; + if (c) { + App::main()->showPeer(0, true); + App::wnd()->hideLayer(); + MTP::send(MTPmessages_DeleteChatUser(MTP_int(p->id & 0xFFFFFFFF), App::self()->inputUser), App::main()->rpcDone(&MainWidget::deleteHistory, p), App::main()->rpcFail(&MainWidget::leaveChatFailed, p)); + } +} + +void TopBarWidget::enterEvent(QEvent *e) { + a_over.start(1); + anim::start(this); +} + +void TopBarWidget::leaveEvent(QEvent *e) { + a_over.start(0); + anim::start(this); +} + +bool TopBarWidget::animStep(float64 ms) { + float64 dt = ms / st::topBarDuration; + bool res = true; + if (dt >= 1) { + a_over.finish(); + res = false; + } else { + a_over.update(dt, anim::linear); + } + update(); + return res; +} + +void TopBarWidget::enableShadow(bool enable) { + _drawShadow = enable; +} + +void TopBarWidget::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (e->rect().top() < st::topBarHeight) { + p.fillRect(QRect(0, 0, width(), st::topBarHeight), st::topBarBG->b); + if (_clearSelection.isHidden()) { + p.save(); + main()->paintTopBar(p, a_over.current(), 0); + p.restore(); + } else { + p.setFont(st::linkFont->f); + p.setPen(st::btnDefLink.color->p); + p.drawText(st::topBarSelectedPos.x(), st::topBarSelectedPos.y() + st::linkFont->ascent, _selStr); + } + } else { + int a = 0; // optimize shadow-only drawing + } + if (_drawShadow) { + p.setPen(st::titleShadowColor->p); + for (int32 i = 0; i < st::titleShadow; ++i) { + p.drawLine(st::titleShadow, st::topBarHeight + i, width(), st::topBarHeight + i); + } + } +} + +void TopBarWidget::mousePressEvent(QMouseEvent *e) { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + if (e->button() == Qt::LeftButton && e->pos().y() < st::topBarHeight && (p || !_selCount)) { + emit clicked(); + } +} + +void TopBarWidget::resizeEvent(QResizeEvent *e) { + int32 r = width(); + if (!_forward.isHidden()) { + int32 availX = st::topBarSelectedPos.x() + _selStrWidth, availW = r - (_clearSelection.width() + st::topBarButton.width / 2) - availX; + _forward.move(availX + (availW - _forward.width() - _delete.width() - st::topBarActionSkip) / 2, (st::topBarHeight - _forward.height()) / 2); + _delete.move(availX + (availW + _forward.width() - _delete.width() + st::topBarActionSkip) / 2, (st::topBarHeight - _forward.height()) / 2); + } + if (!_clearSelection.isHidden()) _clearSelection.move(r -= _clearSelection.width(), 0); + if (!_deleteContact.isHidden()) _deleteContact.move(r -= _deleteContact.width(), 0); + if (!_leaveGroup.isHidden()) _leaveGroup.move(r -= _leaveGroup.width(), 0); + if (!_edit.isHidden()) _edit.move(r -= _edit.width(), 0); + if (!_addContact.isHidden()) _addContact.move(r -= _addContact.width(), 0); +} + +void TopBarWidget::hideAll() { + _edit.hide(); + _leaveGroup.hide(); + _addContact.hide(); + _deleteContact.hide(); +} + +void TopBarWidget::showAll() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + if (p && (p->chat || p->asUser()->contact >= 0)) { + if (p->chat) { + if (p->asChat()->forbidden) { + _edit.hide(); + } else { + _edit.show(); + } + _leaveGroup.show(); + _addContact.hide(); + _deleteContact.hide(); + } else if (p->asUser()->contact > 0) { + _edit.show(); + _leaveGroup.hide(); + _addContact.hide(); + _deleteContact.show(); + } else { + _edit.hide(); + _leaveGroup.hide(); + _addContact.show(); + _deleteContact.hide(); + } + _clearSelection.hide(); + _delete.hide(); + _forward.hide(); + } else { + _edit.hide(); + _leaveGroup.hide(); + _addContact.hide(); + _deleteContact.hide(); + if (!p && _selCount) { + _clearSelection.show(); + _delete.show(); + _forward.show(); + } else { + _clearSelection.hide(); + _delete.hide(); + _forward.hide(); + } + } + resizeEvent(0); +} + +void TopBarWidget::showSelected(uint32 selCount) { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + _selCount = selCount; + _selStr = (_selCount > 0) ? lang((_selCount == 1) ? lng_selected_count_1 : lng_selected_count_5).arg(_selCount) : QString(); + _selStrWidth = st::btnDefLink.font->m.width(_selStr); + setCursor((!p && _selCount) ? style::cur_default : style::cur_pointer); + showAll(); +} + +MainWidget *TopBarWidget::main() { + return static_cast(parentWidget()); +} + +MainWidget::MainWidget(Window *window) : QWidget(window), profile(0), _dialogsWidth(st::dlgMinWidth), + updPts(0), updDate(0), updQts(0), updSeq(0), updInited(false), failedObjId(0), + dialogs(this), history(this), onlineRequest(0), hider(0), _topBar(this) { + setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight)); + + connect(window, SIGNAL(resized(const QSize &)), this, SLOT(onParentResize(const QSize &))); + connect(&dialogs, SIGNAL(peerChosen(const PeerId &)), this, SLOT(showPeer(const PeerId &))); + connect(&dialogs, SIGNAL(cancelled()), this, SLOT(dialogsCancelled())); + connect(&history, SIGNAL(cancelled()), &dialogs, SLOT(activate())); + connect(this, SIGNAL(peerPhotoChanged(PeerData *)), this, SIGNAL(dialogsUpdated())); + connect(&noUpdatesTimer, SIGNAL(timeout()), this, SLOT(getDifference())); + connect(&onlineTimer, SIGNAL(timeout()), this, SLOT(setOnline())); + connect(window->windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(mainStateChanged(Qt::WindowState))); + connect(&onlineUpdater, SIGNAL(timeout()), this, SLOT(updateOnlineDisplay())); + connect(this, SIGNAL(peerUpdated(PeerData*)), &history, SLOT(peerUpdated(PeerData*))); + connect(&_topBar, SIGNAL(clicked()), this, SLOT(onTopBarClick())); + connect(&history, SIGNAL(peerShown(PeerData*)), this, SLOT(onPeerShown(PeerData*))); + connect(&updateNotifySettingTimer, SIGNAL(timeout()), this, SLOT(onUpdateNotifySettings())); + + noUpdatesTimer.setSingleShot(true); + onlineTimer.setSingleShot(true); + onlineUpdater.setSingleShot(true); + updateNotifySettingTimer.setSingleShot(true); + + dialogs.show(); + history.show(); + _topBar.hide(); + + _topBar.raise(); + dialogs.raise(); + + MTP::setGlobalFailHandler(rpcFail(&MainWidget::updateFail)); + + show(); + setFocus(); +} + +mtpRequestId MainWidget::onForward(const PeerId &peer, bool forwardSelected) { + return history.onForward(peer, forwardSelected); +} + +void MainWidget::onShareContact(const PeerId &peer, UserData *contact) { + history.onShareContact(peer, contact); +} + +void MainWidget::noHider(HistoryHider *destroyed) { + if (hider == destroyed) { + hider = 0; + } +} + +void MainWidget::forwardLayer(bool forwardSelected) { + hider = new HistoryHider(this, forwardSelected); + hider->show(); + resizeEvent(0); + dialogs.activate(); +} + +void MainWidget::deleteLayer(int32 selectedCount) { + QString str(lang((selectedCount < -1) ? lng_selected_cancel_sure_this : (selectedCount < 0 ? lng_selected_delete_sure_this : (selectedCount > 1 ? lng_selected_delete_sure_5 : lng_selected_delete_sure_1)))); + ConfirmBox *box = new ConfirmBox((selectedCount < 0) ? str : str.arg(selectedCount), lang(lng_selected_delete_confirm)); + if (selectedCount < 0) { + connect(box, SIGNAL(confirmed()), &history, SLOT(onDeleteContextSure())); + } else { + connect(box, SIGNAL(confirmed()), &history, SLOT(onDeleteSelectedSure())); + } + App::wnd()->showLayer(box); +} + +void MainWidget::shareContactLayer(UserData *contact) { + hider = new HistoryHider(this, contact); + hider->show(); + resizeEvent(0); + dialogs.activate(); +} + +bool MainWidget::selectingPeer() { + return !!hider; +} + +void MainWidget::offerPeer(PeerId peer) { + hider->offerPeer(peer); +} + +void MainWidget::hidePeerSelect() { + hider->startHide(); +} + +void MainWidget::focusPeerSelect() { + hider->setFocus(); +} + +void MainWidget::dialogsActivate() { + dialogs.activate(); +} + +bool MainWidget::leaveChatFailed(PeerData *peer, const RPCError &e) { + if (e.type() == "CHAT_ID_INVALID") { // left this chat already + if (profile && profile->peer() == peer || profileStack.indexOf(peer) >= 0 || history.peer() == peer) { + showPeer(0); + } + dialogs.removePeer(peer); + MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer)); + return true; + } + return false; +} + +void MainWidget::deleteHistory(PeerData *peer, const MTPmessages_StatedMessage &result) { + sentFullDataReceived(0, result); + if (profile && profile->peer() == peer || profileStack.indexOf(peer) >= 0 || history.peer() == peer) { + showPeer(0); + } + dialogs.removePeer(peer); + MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer)); +} + +void MainWidget::deleteHistoryPart(PeerData *peer, const MTPmessages_AffectedHistory &result) { + const MTPDmessages_affectedHistory &d(result.c_messages_affectedHistory()); + App::main()->updUpdated(d.vpts.v, 0, 0, d.vseq.v); + + int32 offset = d.voffset.v; + if (!MTP::authedId() || offset <= 0) return; + + MTP::send(MTPmessages_DeleteHistory(peer->input, d.voffset), rpcDone(&MainWidget::deleteHistoryPart, peer)); +} + +void MainWidget::deletedContact(UserData *user, const MTPcontacts_Link &result) { + const MTPDcontacts_link &d(result.c_contacts_link()); + App::feedUsers(MTP_vector(QVector(1, d.vuser))); + App::feedUserLink(MTP_int(user->id & 0xFFFFFFFF), d.vmy_link, d.vforeign_link); +} + +void MainWidget::deleteHistoryAndContact(UserData *user, const MTPcontacts_Link &result) { + const MTPDcontacts_link &d(result.c_contacts_link()); + App::feedUsers(MTP_vector(QVector(1, d.vuser))); + App::feedUserLink(MTP_int(user->id & 0xFFFFFFFF), d.vmy_link, d.vforeign_link); + + if (profile && profile->peer() == user || profileStack.indexOf(user) >= 0 || history.peer() == user) { + showPeer(0); + } + dialogs.removePeer(user); + MTP::send(MTPmessages_DeleteHistory(user->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, (PeerData*)user)); +} + +void MainWidget::clearHistory(PeerData *peer) { + if (!peer->chat && peer->asUser()->contact <= 0) { + dialogs.removePeer(peer->asUser()); + } + dialogs.dialogsToUp(); + dialogs.update(); + App::history(peer->id)->clear(); + MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer)); +} + +void MainWidget::removeContact(UserData *user) { + dialogs.removeContact(user); +} + +void MainWidget::addParticipants(ChatData *chat, const QVector &users) { + for (QVector::const_iterator i = users.cbegin(), e = users.cend(); i != e; ++i) { + MTP::send(MTPmessages_AddChatUser(MTP_int(chat->id & 0xFFFFFFFF), (*i)->inputUser, MTP_int(ForwardOnAdd)), rpcDone(&MainWidget::addParticipantDone, chat), rpcFail(&MainWidget::addParticipantFail, chat), 0, 5); + } + App::wnd()->hideLayer(); + showPeer(chat->id, false); +} + +void MainWidget::addParticipantDone(ChatData *chat, const MTPmessages_StatedMessage &result) { + sentFullDataReceived(0, result); +} + +bool MainWidget::addParticipantFail(ChatData *chat, const RPCError &e) { + if (e.type() == "USER_LEFT_CHAT") { // trying to return banned user to his group + } + return false; +} + +void MainWidget::kickParticipant(ChatData *chat, UserData *user) { + MTP::send(MTPmessages_DeleteChatUser(MTP_int(chat->id & 0xFFFFFFFF), user->inputUser), rpcDone(&MainWidget::kickParticipantDone, chat), rpcFail(&MainWidget::kickParticipantFail, chat)); + App::wnd()->hideLayer(); + showPeer(chat->id, false); +} + +void MainWidget::kickParticipantDone(ChatData *chat, const MTPmessages_StatedMessage &result) { + sentFullDataReceived(0, result); +} + +bool MainWidget::kickParticipantFail(ChatData *chat, const RPCError &e) { + e.type(); + return false; +} + +void MainWidget::checkPeerHistory(PeerData *peer) { + MTP::send(MTPmessages_GetHistory(peer->input, MTP_int(0), MTP_int(0), MTP_int(1)), rpcDone(&MainWidget::checkedHistory, peer)); +} + +void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &result) { + const QVector *v = 0; + if (result.type() == mtpc_messages_messages) { + const MTPDmessages_messages &d(result.c_messages_messages()); + App::feedChats(d.vchats); + App::feedUsers(d.vusers); + v = &d.vmessages.c_vector().v; + } else if (result.type() == mtpc_messages_messagesSlice) { + const MTPDmessages_messagesSlice &d(result.c_messages_messagesSlice()); + App::feedChats(d.vchats); + App::feedUsers(d.vusers); + v = &d.vmessages.c_vector().v; + } + if (!v) return; + + if (v->isEmpty()) { + if (profile && profile->peer() == peer || profileStack.indexOf(peer) >= 0 || history.peer() == peer) { + showPeer(0); + } + dialogs.removePeer(peer); + } else { + if (App::historyLoaded(peer->id)) { + History *h = App::history(peer->id); + h->addToBack((*v)[0], false); + } + } +} + +void MainWidget::forwardSelectedItems() { + history.onForwardSelected(); +} + +void MainWidget::deleteSelectedItems() { + history.onDeleteSelected(); +} + +void MainWidget::clearSelectedItems() { + history.onClearSelected(); +} + +QRect MainWidget::rectForTitleAnim() const { + int w = width(); + w -= history.x() + st::sysBtnDelta * 2 + st::sysCls.img.width() + st::sysRes.img.width() + st::sysMin.img.width(); + return QRect(history.x(), 0, w, App::wnd()->getTitle()->height()); +} + +DialogsIndexed &MainWidget::contactsList() { + return dialogs.contactsList(); +} + +void MainWidget::videoLoadProgress(mtpFileLoader *loader) { + VideoData *video = App::video(loader->objId()); + if (video->loader) { + if (video->loader->done()) { + video->finish(); + QString already = video->already(); + if (!already.isEmpty() && video->openOnSave) { + psOpenFile(already, video->openOnSave < 0); + } + } + } + const VideoItems &items(App::videoItems()); + VideoItems::const_iterator i = items.constFind(video); + if (i != items.cend()) { + for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) { + history.msgUpdated(j.key()->history()->peer->id, j.key()); + } + } +} + +void MainWidget::loadFailed(mtpFileLoader *loader, bool started, const char *retrySlot) { + failedObjId = loader->objId(); + failedFileName = loader->fileName(); + ConfirmBox *box = new ConfirmBox(lang(started ? lng_download_finish_failed : lng_download_path_failed), started ? QString() : lang(lng_download_path_settings)); + if (started) { + connect(box, SIGNAL(confirmed()), this, retrySlot); + } else { + connect(box, SIGNAL(confirmed()), App::wnd(), SLOT(showSettings())); + } + App::wnd()->showLayer(box); +} + +void MainWidget::videoLoadFailed(mtpFileLoader *loader, bool started) { + loadFailed(loader, started, SLOT(videoLoadRetry())); + VideoData *video = App::video(loader->objId()); + if (video && video->loader) video->finish(); +} + +void MainWidget::videoLoadRetry() { + App::wnd()->hideLayer(); + VideoData *video = App::video(failedObjId); + if (video) video->save(failedFileName); +} + +void MainWidget::audioLoadProgress(mtpFileLoader *loader) { + AudioData *audio = App::audio(loader->objId()); + if (audio->loader) { + if (audio->loader->done()) { + audio->finish(); + QString already = audio->already(); + if (!already.isEmpty() && audio->openOnSave) { + psOpenFile(already, audio->openOnSave < 0); + } + } + } + const AudioItems &items(App::audioItems()); + AudioItems::const_iterator i = items.constFind(audio); + if (i != items.cend()) { + for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) { + history.msgUpdated(j.key()->history()->peer->id, j.key()); + } + } +} + +void MainWidget::audioLoadFailed(mtpFileLoader *loader, bool started) { + loadFailed(loader, started, SLOT(audioLoadRetry())); + AudioData *audio = App::audio(loader->objId()); + if (audio && audio->loader) audio->finish(); +} + +void MainWidget::audioLoadRetry() { + App::wnd()->hideLayer(); + AudioData *audio = App::audio(failedObjId); + if (audio) audio->save(failedFileName); +} + +void MainWidget::documentLoadProgress(mtpFileLoader *loader) { + DocumentData *document = App::document(loader->objId()); + if (document->loader) { + if (document->loader->done()) { + document->finish(); + QString already = document->already(); + if (!already.isEmpty() && document->openOnSave) { + psOpenFile(already, document->openOnSave < 0); + } + } + } + const DocumentItems &items(App::documentItems()); + DocumentItems::const_iterator i = items.constFind(document); + if (i != items.cend()) { + for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) { + history.msgUpdated(j.key()->history()->peer->id, j.key()); + } + } +} + +void MainWidget::documentLoadFailed(mtpFileLoader *loader, bool started) { + loadFailed(loader, started, SLOT(documentLoadRetry())); + DocumentData *document = App::document(loader->objId()); + if (document && document->loader) document->finish(); +} + +void MainWidget::documentLoadRetry() { + App::wnd()->hideLayer(); + DocumentData *document = App::document(failedObjId); + if (document) document->save(failedFileName); +} + +void MainWidget::onParentResize(const QSize &newSize) { + resize(newSize); +} + +void MainWidget::updateOnlineDisplay() { + history.updateOnlineDisplay(history.x(), width() - history.x() - st::sysBtnDelta * 2 - st::sysCls.img.width() - st::sysRes.img.width() - st::sysMin.img.width()); + if (profile) profile->updateOnlineDisplay(); + if (App::wnd()->settingsWidget()) App::wnd()->settingsWidget()->updateOnlineDisplay(); +} + +void MainWidget::confirmSendImage(const ReadyLocalMedia &img) { + history.confirmSendImage(img); +} + +void MainWidget::cancelSendImage() { + history.cancelSendImage(); +} + +void MainWidget::dialogsCancelled() { + if (hider) { + hider->startHide(); + } else { + history.activate(); + } +} + +void MainWidget::setInnerFocus() { + if (hider || !history.peer()) { + if (hider && hider->wasOffered()) { + hider->setFocus(); + } else { + dialogs.setInnerFocus(); + } + } else { + history.activate(); + } +} + +void MainWidget::createDialogAtTop(History *history, int32 unreadCount) { + dialogs.createDialogAtTop(history, unreadCount); +} + +bool MainWidget::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + if (history.getPhotoCoords(photo, x, y, w)) { + x += history.x(); + y += history.y(); + return true; + } else if (profile && profile->getPhotoCoords(photo, x, y, w)) { + x += profile->x(); + y += profile->y(); + return true; + } + return false; +} + +bool MainWidget::getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const { + if (history.getVideoCoords(video, x, y, w)) { + x += history.x(); + y += history.y(); + return true; + } + return false; +} + +void MainWidget::showPeer(const PeerId &peerId, bool back, bool force) { + if (!back && profileStack.size() == 1 && profileStack[0]->id == peerId) { + back = true; + } + App::wnd()->hideLayer(); + QPixmap animCache, animTopBarCache; + if (force && hider) { + hider->startHide(); + hider = 0; + } + if (force || !selectingPeer()) { + if (history.isHidden() && profile) { + dialogs.enableShadow(false); + if (peerId) { + _topBar.enableShadow(false); + animCache = grab(history.geometry()); + } else { + animCache = grab(QRect(_dialogsWidth, 0, width() - _dialogsWidth, height())); + } + animTopBarCache = grab(QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight)); + dialogs.enableShadow(); + _topBar.enableShadow(); + history.show(); + } + } + history.showPeer(peerId, force); + if (force || !selectingPeer()) { + if (profile) { + if (profile) profile->deleteLater(); + profile = 0; + profileStack.clear(); + if (!history.peer() || !history.peer()->id) { + _topBar.hide(); + resizeEvent(0); + } + if (!animCache.isNull()) { + history.animShow(animCache, animTopBarCache, back); + } + } + } + dialogs.scrollToPeer(peerId); + dialogs.update(); +} + +PeerData *MainWidget::peerBefore(const PeerData *peer) { + if (selectingPeer()) return 0; + return dialogs.peerBefore(peer); +} + +PeerData *MainWidget::peerAfter(const PeerData *peer) { + if (selectingPeer()) return 0; + return dialogs.peerAfter(peer); +} + +PeerData *MainWidget::peer() { + return history.peer(); +} + +PeerData *MainWidget::activePeer() { + return history.activePeer(); +} + +PeerData *MainWidget::profilePeer() { + return profile ? profile->peer() : 0; +} + +void MainWidget::showPeerProfile(const PeerData *peer, bool back) { + dialogs.enableShadow(false); + _topBar.enableShadow(false); + QPixmap animCache = grab(history.geometry()), animTopBarCache = grab(QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight)); + dialogs.enableShadow(); + _topBar.enableShadow(); + if (!back) { + if (profile) { + profileStack.push_back(profile->peer()); + } else { + profileStack.push_back(history.peer()); + } + } + if (profile) profile->deleteLater(); + profile = new ProfileWidget(this, peer); + _topBar.show(); + resizeEvent(0); + profile->animShow(animCache, animTopBarCache, back); + history.animStop(); + history.showPeer(0, false, true); + history.hide(); + _topBar.raise(); + dialogs.raise(); + if (hider) hider->raise(); +} + +void MainWidget::showPeerBack() { + if (profileStack.isEmpty() || selectingPeer()) return; + PeerData *peer = profileStack.back(); + profileStack.pop_back(); + if (profileStack.isEmpty()) { + showPeer(peer->id, true); + } else { + showPeerProfile(peer, true); + } +} + +QRect MainWidget::historyRect() const { + QRect r(history.historyRect()); + r.moveLeft(r.left() + history.x()); + r.moveTop(r.top() + history.y()); + return r; +} + +void MainWidget::dlgUpdated(DialogRow *row) { + dialogs.dlgUpdated(row); +} + +void MainWidget::dlgUpdated(History *row) { + dialogs.dlgUpdated(row); +} + +void MainWidget::windowShown() { + history.windowShown(); +} + +void MainWidget::sentDataReceived(uint64 randomId, const MTPmessages_SentMessage &result) { + switch (result.type()) { + case mtpc_messages_sentMessage: { + const MTPDmessages_sentMessage &d(result.c_messages_sentMessage()); + + if (updInited && d.vseq.v) { + if (d.vseq.v <= updSeq) return; + if (d.vseq.v > updSeq + 1) return getDifference(); + } + + feedUpdate(MTP_updateMessageID(d.vid, MTP_long(randomId))); // ignore real date + if (updInited) { + updSetState(d.vpts.v, d.vdate.v, updQts, d.vseq.v); + } + } break; + + case mtpc_messages_sentMessageLink: { + const MTPDmessages_sentMessageLink &d(result.c_messages_sentMessageLink()); + + if (updInited && d.vseq.v) { + if (d.vseq.v <= updSeq) return; + if (d.vseq.v > updSeq + 1) return getDifference(); + } + + feedUpdate(MTP_updateMessageID(d.vid, MTP_long(randomId))); // ignore real date + if (updInited) { + updSetState(d.vpts.v, d.vdate.v, updQts, d.vseq.v); + } + + App::feedUserLinks(d.vlinks); + } break; + }; +} + +void MainWidget::sentFullDataReceived(uint64 randomId, const MTPmessages_StatedMessage &result) { + if (randomId) { + const MTPMessage *msg = 0; + switch (result.type()) { + case mtpc_messages_statedMessage: msg = &result.c_messages_statedMessage().vmessage; break; + case mtpc_messages_statedMessageLink: msg = &result.c_messages_statedMessageLink().vmessage; break; + } + if (msg) { + MsgId msgId = 0; + switch (msg->type()) { + case mtpc_message: msgId = msg->c_message().vid.v; break; + case mtpc_messageEmpty: msgId = msg->c_messageEmpty().vid.v; break; + case mtpc_messageForwarded: msgId = msg->c_messageForwarded().vid.v; break; + case mtpc_messageService: msgId = msg->c_messageService().vid.v; break; + } + if (msgId) { + feedUpdate(MTP_updateMessageID(MTP_int(msgId), MTP_long(randomId))); // ignore real date + App::feedMessageMedia(msgId, *msg); + } + } + } + + switch (result.type()) { + case mtpc_messages_statedMessage: { + const MTPDmessages_statedMessage &d(result.c_messages_statedMessage()); + + if (updInited && d.vseq.v) { + if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference(); + } + + App::feedChats(d.vchats); + App::feedUsers(d.vusers); + if (!randomId) { + feedUpdate(MTP_updateNewMessage(d.vmessage, d.vpts)); + } + if (updInited) { + updSetState(d.vpts.v, updDate, updQts, d.vseq.v); + } + } break; + + case mtpc_messages_statedMessageLink: { + const MTPDmessages_statedMessageLink &d(result.c_messages_statedMessageLink()); + + if (updInited && d.vseq.v) { + if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference(); + } + + App::feedChats(d.vchats); + App::feedUsers(d.vusers); + if (!randomId) { + feedUpdate(MTP_updateNewMessage(d.vmessage, d.vpts)); + } + if (updInited) { + updSetState(d.vpts.v, updDate, updQts, d.vseq.v); + } + + App::feedUserLinks(d.vlinks); + } break; + }; +} + +void MainWidget::sentFullDatasReceived(const MTPmessages_StatedMessages &result) { + switch (result.type()) { + case mtpc_messages_statedMessages: { + const MTPDmessages_statedMessages &d(result.c_messages_statedMessages()); + if (updInited && d.vseq.v) { + if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference(); + } + + App::feedUsers(d.vusers); + App::feedChats(d.vchats); + App::feedMsgs(d.vmessages, true); + history.peerMessagesUpdated(); + + if (updInited) { + updSetState(d.vpts.v, updDate, updQts, d.vseq.v); + } + } break; + + case mtpc_messages_statedMessagesLinks: { + const MTPDmessages_statedMessagesLinks &d(result.c_messages_statedMessagesLinks()); + + if (updInited && d.vseq.v) { + if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference(); + } + + App::feedUsers(d.vusers); + App::feedChats(d.vchats); + App::feedMsgs(d.vmessages, true); + history.peerMessagesUpdated(); + if (updInited) { + updSetState(d.vpts.v, updDate, updQts, d.vseq.v); + } + + App::feedUserLinks(d.vlinks); + } break; + }; +} + +void MainWidget::forwardDone(PeerId peer, const MTPmessages_StatedMessages &result) { + sentFullDatasReceived(result); + if (hider) hider->forwardDone(); + showPeer(peer, false, true); + history.onClearSelected(); +} + +void MainWidget::msgUpdated(PeerId peer, HistoryItem *msg) { + history.msgUpdated(peer, msg); + if (!msg->history()->dialogs.isEmpty()) { + dialogs.dlgUpdated(msg->history()->dialogs[0]); + } +} + +void MainWidget::historyToDown(History *hist) { + history.historyToDown(hist); +} + +void MainWidget::dialogsToUp() { + dialogs.dialogsToUp(); +} + +void MainWidget::dialogsClear() { + dialogs.onCancel(); +} + +void MainWidget::newUnreadMsg(History *hist, MsgId msgId) { + history.newUnreadMsg(hist, msgId); +} + +void MainWidget::historyWasRead() { + history.historyWasRead(false); +} + +void MainWidget::animShow(const QPixmap &bgAnimCache, bool back) { + _bgAnimCache = bgAnimCache; + + anim::stop(this); + showAll(); + _animCache = grab(rect()); + + a_coord = back ? anim::ivalue(-st::introSlideShift, 0) : anim::ivalue(st::introSlideShift, 0); + a_alpha = anim::fvalue(0, 1); + a_bgCoord = back ? anim::ivalue(0, st::introSlideShift) : anim::ivalue(0, -st::introSlideShift); + a_bgAlpha = anim::fvalue(1, 0); + + hideAll(); + anim::start(this); + show(); +} + +bool MainWidget::animStep(float64 ms) { + float64 fullDuration = st::introSlideDelta + st::introSlideDuration, dt = ms / fullDuration; + float64 dt1 = (ms > st::introSlideDuration) ? 1 : (ms / st::introSlideDuration), dt2 = (ms > st::introSlideDelta) ? (ms - st::introSlideDelta) / (st::introSlideDuration) : 0; + bool res = true; + if (dt2 >= 1) { + res = false; + a_bgCoord.finish(); + a_bgAlpha.finish(); + a_coord.finish(); + a_alpha.finish(); + + _animCache = _bgAnimCache = QPixmap(); + + anim::stop(this); + showAll(); + activate(); + } else { + a_bgCoord.update(dt1, st::introHideFunc); + a_bgAlpha.update(dt1, st::introAlphaHideFunc); + a_coord.update(dt2, st::introShowFunc); + a_alpha.update(dt2, st::introAlphaShowFunc); + } + update(); + return res; +} + +void MainWidget::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (animating()) { + p.setOpacity(a_bgAlpha.current()); + p.drawPixmap(a_bgCoord.current(), 0, _bgAnimCache); + p.setOpacity(a_alpha.current()); + p.drawPixmap(a_coord.current(), 0, _animCache); + } else { + } +} + +void MainWidget::hideAll() { + dialogs.hide(); + history.hide(); + if (profile) { + profile->hide(); + } + _topBar.hide(); +} + +void MainWidget::showAll() { + dialogs.show(); + if (profile) { + profile->show(); + } else { + history.show(); + } + if (profile || history.peer()) { + _topBar.show(); + } + App::wnd()->checkHistoryActivation(); +} + +void MainWidget::resizeEvent(QResizeEvent *e) { + _dialogsWidth = snap((width() * 5) / 14, st::dlgMinWidth, st::dlgMaxWidth); + int32 tbh = _topBar.isHidden() ? 0 : st::topBarHeight; + dialogs.setGeometry(0, 0, _dialogsWidth + st::dlgShadow, height()); + _topBar.setGeometry(_dialogsWidth, 0, width() - _dialogsWidth, st::topBarHeight + st::titleShadow); + history.setGeometry(_dialogsWidth, tbh, width() - _dialogsWidth, height() - tbh); + if (profile) profile->setGeometry(history.geometry()); + if (hider) hider->setGeometry(QRect(_dialogsWidth, 0, width() - _dialogsWidth, height())); +} + +void MainWidget::keyPressEvent(QKeyEvent *e) { +} + +void MainWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) { + if (profile) { + profile->paintTopBar(p, over, decreaseWidth); + } else { + history.paintTopBar(p, over, decreaseWidth); + } +} + +TopBarWidget *MainWidget::topBar() { + return &_topBar; +} + +void MainWidget::onTopBarClick() { + if (profile) { + profile->topBarClick(); + } else { + history.topBarClick(); + } +} + +void MainWidget::onPeerShown(PeerData *peer) { + if (profile || peer && peer->id) { + _topBar.show(); + } else { + _topBar.hide(); + } + resizeEvent(0); +} + +void MainWidget::onUpdateNotifySettings() { + while (!updateNotifySettingPeers.isEmpty()) { + PeerData *peer = *updateNotifySettingPeers.begin(); + updateNotifySettingPeers.erase(updateNotifySettingPeers.begin()); + + if (peer->notify == UnknownNotifySettings || peer->notify == EmptyNotifySettings) { + peer->notify = new NotifySettings(); + } + MTP::send(MTPaccount_UpdateNotifySettings(MTP_inputNotifyPeer(peer->input), MTP_inputPeerNotifySettings(MTP_int(peer->notify->mute), MTP_string(peer->notify->sound), MTP_bool(peer->notify->previews), MTP_int(peer->notify->events))), RPCResponseHandler(), 0, updateNotifySettingPeers.isEmpty() ? 0 : 10); + } +} + +void MainWidget::feedUpdates(const MTPVector &updates, bool skipMessageIds) { + const QVector &v(updates.c_vector().v); + for (QVector::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) { + if (skipMessageIds && i->type() == mtpc_updateMessageID) continue; + feedUpdate(*i); + } +} + +void MainWidget::feedMessageIds(const MTPVector &updates) { + const QVector &v(updates.c_vector().v); + for (QVector::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) { + if (i->type() == mtpc_updateMessageID) { + feedUpdate(*i); + } + } +} + +bool MainWidget::updateFail(const RPCError &e) { + if (MTP::authedId()) { + App::logOut(); + } + return true; +} + +void MainWidget::updSetState(int32 pts, int32 date, int32 qts, int32 seq) { + if (updPts < pts) updPts = pts; + if (updDate < date) updDate = date; + if (updQts < qts) updQts = qts; + if (seq) updSeq = seq; +} + +void MainWidget::gotState(const MTPupdates_State &state) { + const MTPDupdates_state &d(state.c_updates_state()); + updSetState(d.vpts.v, d.vdate.v, d.vqts.v, d.vseq.v); + + MTP::setGlobalDoneHandler(rpcDone(&MainWidget::updateReceived)); + noUpdatesTimer.start(NoUpdatesTimeout); + updInited = true; + + dialogs.loadDialogs(); + setOnline(); +} + +void MainWidget::gotDifference(const MTPupdates_Difference &diff) { + switch (diff.type()) { + case mtpc_updates_differenceEmpty: { + const MTPDupdates_differenceEmpty &d(diff.c_updates_differenceEmpty()); + updSetState(updPts, d.vdate.v, updQts, d.vseq.v); + + MTP::setGlobalDoneHandler(rpcDone(&MainWidget::updateReceived)); + noUpdatesTimer.start(NoUpdatesTimeout); + updInited = true; + } break; + case mtpc_updates_differenceSlice: { + const MTPDupdates_differenceSlice &d(diff.c_updates_differenceSlice()); + feedDifference(d.vusers, d.vchats, d.vnew_messages, d.vother_updates); + + const MTPDupdates_state &s(d.vintermediate_state.c_updates_state()); + updSetState(s.vpts.v, s.vdate.v, s.vqts.v, s.vseq.v); + + updInited = true; + + getDifference(); + } break; + case mtpc_updates_difference: { + const MTPDupdates_difference &d(diff.c_updates_difference()); + feedDifference(d.vusers, d.vchats, d.vnew_messages, d.vother_updates); + + gotState(d.vstate); + } break; + }; +} + +void MainWidget::updUpdated(int32 pts, int32 date, int32 qts, int32 seq) { + if (!updInited) return; + if (seq && (seq < updSeq || seq > updSeq + 1)) return getDifference(); + updSetState(pts, date, qts, seq); +} + +void MainWidget::feedDifference(const MTPVector &users, const MTPVector &chats, const MTPVector &msgs, const MTPVector &other) { + App::feedUsers(users); + App::feedChats(chats); + feedMessageIds(other); + App::feedMsgs(msgs, true); + feedUpdates(other, true); + history.peerMessagesUpdated(); +} + +bool MainWidget::failDifference(const RPCError &e) { + LOG(("RPC Error: %1 %2: %3").arg(e.code()).arg(e.type()).arg(e.description())); + if (MTP::authedId()) { + updInited = true; + getDifference(); + } + return true; +} + +void MainWidget::getDifference() { + if (!updInited) return; + updInited = false; + MTP::setGlobalDoneHandler(RPCDoneHandlerPtr(0)); + MTP::send(MTPupdates_GetDifference(MTP_int(updPts), MTP_int(updDate), MTP_int(updQts)), rpcDone(&MainWidget::gotDifference), rpcFail(&MainWidget::failDifference)); +} + +void MainWidget::start(const MTPUser &user) { + MTP::authed(user.c_userSelf().vid.v); + App::initMedia(); + App::feedUsers(MTP_vector(QVector(1, user))); + App::app()->startUpdateCheck(); + MTP::send(MTPupdates_GetState(), rpcDone(&MainWidget::gotState)); + update(); +} + +void MainWidget::startFull(const MTPVector &users) { + const QVector &v(users.c_vector().v); + if (v.isEmpty() || v[0].type() != mtpc_userSelf) { // wtf?.. + return App::logOut(); + } + start(v[0]); +} + +void MainWidget::applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *history) { + switch (settings.type()) { + case mtpc_peerNotifySettingsEmpty: + switch (peer.type()) { + case mtpc_notifyAll: globalNotifyAllPtr = EmptyNotifySettings; break; + case mtpc_notifyUsers: globalNotifyUsersPtr = EmptyNotifySettings; break; + case mtpc_notifyChats: globalNotifyChatsPtr = EmptyNotifySettings; break; + case mtpc_notifyPeer: { + PeerData *data = App::peerLoaded(App::peerFromMTP(peer.c_notifyPeer().vpeer)); + if (data && data->notify != EmptyNotifySettings) { + if (data->notify != UnknownNotifySettings) { + delete data->notify; + } + data->notify = EmptyNotifySettings; + App::history(data->id)->setMute(false); + } + } break; + } + break; + case mtpc_peerNotifySettings: { + const MTPDpeerNotifySettings &d(settings.c_peerNotifySettings()); + NotifySettingsPtr setTo = UnknownNotifySettings; + PeerId peerId = 0; + switch (peer.type()) { + case mtpc_notifyAll: setTo = globalNotifyAllPtr = &globalNotifyAll; break; + case mtpc_notifyUsers: setTo = globalNotifyUsersPtr = &globalNotifyUsers; break; + case mtpc_notifyChats: setTo = globalNotifyChatsPtr = &globalNotifyChats; break; + case mtpc_notifyPeer: { + PeerData *data = App::peerLoaded(App::peerFromMTP(peer.c_notifyPeer().vpeer)); + if (!data) break; + + peerId = data->id; + if (data->notify == UnknownNotifySettings || data->notify == EmptyNotifySettings) { + data->notify = new NotifySettings(); + } + setTo = data->notify; + } break; + } + if (setTo == UnknownNotifySettings) break; + + setTo->mute = d.vmute_until.v; + setTo->sound = d.vsound.c_string().v; + setTo->previews = d.vshow_previews.v; + setTo->events = d.vevents_mask.v; + if (peerId) { + if (!history) history = App::history(peerId); + if (isNotifyMuted(setTo)) { + App::wnd()->psClearNotify(history); + history->setMute(true); + } else { + history->setMute(false); + } + } + } break; + } + + if (profile) { + profile->updateNotifySettings(); + } +} + +void MainWidget::gotNotifySetting(MTPInputNotifyPeer peer, const MTPPeerNotifySettings &settings) { + switch (peer.type()) { + case mtpc_inputNotifyAll: applyNotifySetting(MTP_notifyAll(), settings); break; + case mtpc_inputNotifyUsers: applyNotifySetting(MTP_notifyUsers(), settings); break; + case mtpc_inputNotifyChats: applyNotifySetting(MTP_notifyChats(), settings); break; + case mtpc_inputNotifyGeoChatPeer: break; // no MTP_peerGeoChat + case mtpc_inputNotifyPeer: + switch (peer.c_inputNotifyPeer().vpeer.type()) { + case mtpc_inputPeerEmpty: applyNotifySetting(MTP_notifyPeer(MTP_peerUser(MTP_int(0))), settings); break; + case mtpc_inputPeerSelf: applyNotifySetting(MTP_notifyPeer(MTP_peerUser(MTP_int(MTP::authedId()))), settings); break; + case mtpc_inputPeerContact: applyNotifySetting(MTP_notifyPeer(MTP_peerUser(peer.c_inputNotifyPeer().vpeer.c_inputPeerContact().vuser_id)), settings); break; + case mtpc_inputPeerForeign: applyNotifySetting(MTP_notifyPeer(MTP_peerUser(peer.c_inputNotifyPeer().vpeer.c_inputPeerForeign().vuser_id)), settings); break; + case mtpc_inputPeerChat: applyNotifySetting(MTP_notifyPeer(MTP_peerChat(peer.c_inputNotifyPeer().vpeer.c_inputPeerChat().vchat_id)), settings); break; + } + break; + } + App::wnd()->psNotifySettingGot(); +} + +bool MainWidget::failNotifySetting(MTPInputNotifyPeer peer) { + gotNotifySetting(peer, MTP_peerNotifySettingsEmpty()); + return true; +} + +void MainWidget::updateNotifySetting(PeerData *peer, bool enabled) { + updateNotifySettingPeers.insert(peer); + if (peer->notify == EmptyNotifySettings) { + if (!enabled) { + peer->notify = new NotifySettings(); + peer->notify->sound = ""; + peer->notify->mute = unixtime() + 86400 * 365; + } + } else { + if (peer->notify == UnknownNotifySettings) { + peer->notify = new NotifySettings(); + } + peer->notify->sound = enabled ? "default" : ""; + peer->notify->mute = enabled ? 0 : (unixtime() + 86400 * 365); + } + App::history(peer->id)->setMute(!enabled); + updateNotifySettingTimer.start(NotifySettingSaveTimeout); +} + +void MainWidget::activate() { + if (!profile) { + if (hider) { + if (hider->wasOffered()) { + hider->setFocus(); + } else { + dialogs.activate(); + } + } else if (history.peer()) { + history.activate(); + } else { + dialogs.activate(); + } + } + App::wnd()->fixOrder(); +} + +void MainWidget::destroyData() { + history.destroyData(); + dialogs.destroyData(); +} + +void MainWidget::updateOnlineDisplayIn(int32 msecs) { + onlineUpdater.start(msecs); +} + +void MainWidget::addNewContact(int32 uid, bool show) { + if (dialogs.addNewContact(uid, show)) { + showPeer(App::peerFromUser(uid)); + } +} + +bool MainWidget::isActive() const { + return isVisible() && !animating(); +} + +bool MainWidget::historyIsActive() const { + return isActive() && !profile; +} + +int32 MainWidget::dlgsWidth() const { + return dialogs.width(); +} + +MainWidget::~MainWidget() { + delete hider; + MTP::clearGlobalHandlers(); + App::deinitMedia(false); + if (App::wnd()) App::wnd()->noMain(this); +} + +void MainWidget::setOnline(int windowState) { + if (onlineRequest) { + MTP::cancel(onlineRequest); + onlineRequest = 0; + } + onlineTimer.stop(); + bool isOnline = App::wnd()->psIsOnline(windowState); + if (isOnline || windowState >= 0) { + onlineRequest = MTP::send(MTPaccount_UpdateStatus(MTP_bool(!isOnline))); + } + if (App::self()) App::self()->onlineTill = unixtime() + (isOnline ? 60 : -1); + if (profile) { + profile->updateOnlineDisplayTimer(); + } else { + history.updateOnlineDisplayTimer(); + } + onlineTimer.start(55000); +} + +void MainWidget::mainStateChanged(Qt::WindowState state) { + setOnline(state); +} + +void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) { + if (end <= from || !MTP::authedId()) return; + + if (*from == mtpc_new_session_created) { + MTPNewSession newSession(from, end); + updSeq = 0; + return getDifference(); + } else { + try { + MTPUpdates updates(from, end); + + noUpdatesTimer.start(NoUpdatesTimeout); + + switch (updates.type()) { + case mtpc_updates: { + const MTPDupdates &d(updates.c_updates()); + if (d.vseq.v) { + if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference(); + } + + App::feedChats(d.vchats); + App::feedUsers(d.vusers); + feedUpdates(d.vupdates); + + updSetState(updPts, d.vdate.v, updQts, d.vseq.v); + } break; + + case mtpc_updatesCombined: { + const MTPDupdatesCombined &d(updates.c_updatesCombined()); + if (d.vseq.v) { + if (d.vseq_start.v <= updSeq || d.vseq_start.v > updSeq + 1) return getDifference(); + } + + App::feedChats(d.vchats); + App::feedUsers(d.vusers); + feedUpdates(d.vupdates); + + updSetState(updPts, d.vdate.v, updQts, d.vseq.v); + } break; + + case mtpc_updateShort: { + const MTPDupdateShort &d(updates.c_updateShort()); + + feedUpdate(d.vupdate); + + updSetState(updPts, d.vdate.v, updQts, updSeq); + } break; + + case mtpc_updateShortMessage: { + const MTPDupdateShortMessage &d(updates.c_updateShortMessage()); + if (d.vseq.v) { + if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference(); + } + + if (!App::userLoaded(d.vfrom_id.v)) return getDifference(); + PeerId peer = App::histories().addToBack(MTP_message(d.vid, d.vfrom_id, MTP_peerUser(MTP_int(MTP::authedId())), MTP_bool(false), MTP_bool(true), d.vdate, d.vmessage, MTP_messageMediaEmpty())); + history.peerMessagesUpdated(peer); + + updSetState(d.vpts.v, d.vdate.v, updQts, d.vseq.v); + } break; + + case mtpc_updateShortChatMessage: { + const MTPDupdateShortChatMessage &d(updates.c_updateShortChatMessage()); + if (d.vseq.v) { + if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference(); + } + + if (!App::chatLoaded(d.vchat_id.v) || !App::userLoaded(d.vfrom_id.v)) return getDifference(); + PeerId peer = App::histories().addToBack(MTP_message(d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), MTP_bool(false), MTP_bool(true), d.vdate, d.vmessage, MTP_messageMediaEmpty())); + history.peerMessagesUpdated(peer); + + updSetState(d.vpts.v, d.vdate.v, updQts, d.vseq.v); + } break; + + case mtpc_updatesTooLong: { + return getDifference(); + } break; + } + } catch(mtpErrorUnexpected &e) { // just some other type + } + } + update(); +/**/ +} + +void MainWidget::feedUpdate(const MTPUpdate &update) { + if (!MTP::authedId()) return; + + switch (update.type()) { + case mtpc_updateNewMessage: { + const MTPDupdateNewMessage &d(update.c_updateNewMessage()); + PeerId peer = App::histories().addToBack(d.vmessage); + history.peerMessagesUpdated(peer); + if (updPts < d.vpts.v) updPts = d.vpts.v; + } break; + + case mtpc_updateMessageID: { + const MTPDupdateMessageID &d(update.c_updateMessageID()); + MsgId msg = App::histItemByRandom(d.vrandom_id.v); + if (msg) { + HistoryItem *msgRow = App::histItemById(msg); + if (msgRow) { + App::historyUnregItem(msgRow); + if (msgRow->id > 0) --msgRow->history()->offset; + msgRow->id = d.vid.v; + if (msgRow->id > 0) ++msgRow->history()->offset; + if (App::historyRegItem(msgRow)) { + msgUpdated(msgRow->history()->peer->id, msgRow); + } else { + msgRow->destroy(); + history.peerMessagesUpdated(); + } + } + App::historyUnregRandom(d.vrandom_id.v); + } + } break; + + case mtpc_updateReadMessages: { + const MTPDupdateReadMessages &d(update.c_updateReadMessages()); + App::feedWereRead(d.vmessages.c_vector().v); + if (updPts < d.vpts.v) updPts = d.vpts.v; + } break; + + case mtpc_updateDeleteMessages: { + const MTPDupdateDeleteMessages &d(update.c_updateDeleteMessages()); + App::feedWereDeleted(d.vmessages.c_vector().v); + history.peerMessagesUpdated(); + if (updPts < d.vpts.v) updPts = d.vpts.v; + } break; + + case mtpc_updateRestoreMessages: { + const MTPDupdateRestoreMessages &d(update.c_updateRestoreMessages()); + if (updPts < d.vpts.v) updPts = d.vpts.v; + } break; + + case mtpc_updateUserTyping: { + const MTPDupdateUserTyping &d(update.c_updateUserTyping()); + History *history = App::historyLoaded(App::peerFromUser(d.vuser_id)); + UserData *user = App::userLoaded(d.vuser_id.v); + if (history && user) { + dialogs.regTyping(history, user); + } + } break; + + case mtpc_updateChatUserTyping: { + const MTPDupdateChatUserTyping &d(update.c_updateChatUserTyping()); + History *history = App::historyLoaded(App::peerFromChat(d.vchat_id)); + UserData *user = (d.vuser_id.v == MTP::authedId()) ? 0 : App::userLoaded(d.vuser_id.v); + if (history && user) { + dialogs.regTyping(history, user); + } + } break; + + case mtpc_updateChatParticipants: { + const MTPDupdateChatParticipants &d(update.c_updateChatParticipants()); + App::feedParticipants(d.vparticipants); + } break; + + case mtpc_updateChatParticipantAdd: { + const MTPDupdateChatParticipantAdd &d(update.c_updateChatParticipantAdd()); + App::feedParticipantAdd(d); + } break; + + case mtpc_updateChatParticipantDelete: { + const MTPDupdateChatParticipantDelete &d(update.c_updateChatParticipantDelete()); + App::feedParticipantDelete(d); + } break; + + case mtpc_updateUserStatus: { + const MTPDupdateUserStatus &d(update.c_updateUserStatus()); + if (d.vuser_id.v == MTP::authedId() && (d.vstatus.type() == mtpc_userStatusOffline || d.vstatus.type() == mtpc_userStatusEmpty)) { + setOnline(); + } else { + UserData *user = App::userLoaded(d.vuser_id.v); + if (user) { + switch (d.vstatus.type()) { + case mtpc_userStatusEmpty: user->onlineTill = 0; break; + case mtpc_userStatusOffline: user->onlineTill = d.vstatus.c_userStatusOffline().vwas_online.v; break; + case mtpc_userStatusOnline: user->onlineTill = d.vstatus.c_userStatusOnline().vexpires.v; break; + } + if (App::main()) App::main()->peerUpdated(user); + } + } + } break; + + case mtpc_updateUserName: { + const MTPDupdateUserName &d(update.c_updateUserName()); + UserData *user = App::userLoaded(d.vuser_id.v); + if (user && user->contact <= 0) { + user->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), user->nameOrPhone); + if (App::main()) App::main()->peerUpdated(user); + } + } break; + + case mtpc_updateUserPhoto: { + const MTPDupdateUserPhoto &d(update.c_updateUserPhoto()); + UserData *user = App::userLoaded(d.vuser_id.v); + if (user) { + user->setPhoto(d.vphoto); + user->photo->load(); + if (false && !d.vprevious.v && d.vuser_id.v != MTP::authedId() && d.vphoto.type() == mtpc_userProfilePhoto) { + MTPPhoto photo(App::photoFromUserPhoto(MTP_int(user->id & 0xFFFFFFFF), d.vdate, d.vphoto)); + HistoryMedia *media = new HistoryPhoto(photo.c_photo(), 100); + App::history(user->id)->addToBackService(clientMsgId(), date(d.vdate), lang(lng_action_user_photo).replace(qsl("{from}"), user->name), false, true, media); + } + if (App::main()) App::main()->peerUpdated(user); + } + } break; + + case mtpc_updateContactRegistered: { + const MTPDupdateContactRegistered &d(update.c_updateContactRegistered()); + UserData *user = App::userLoaded(d.vuser_id.v); + if (user) { + App::history(user->id)->addToBackService(clientMsgId(), date(d.vdate), lang(lng_action_user_registered).replace(qsl("{from}"), user->name), false, true); + } + } break; + + case mtpc_updateContactLink: { + const MTPDupdateContactLink &d(update.c_updateContactLink()); + App::feedUserLink(d.vuser_id, d.vmy_link, d.vforeign_link); + } break; + + case mtpc_updateActivation: { + const MTPDupdateActivation &d(update.c_updateActivation()); + } break; + + case mtpc_updateNewAuthorization: { + const MTPDupdateNewAuthorization &d(update.c_updateNewAuthorization()); + } break; + + case mtpc_updateNewEncryptedMessage: { + const MTPDupdateNewEncryptedMessage &d(update.c_updateNewEncryptedMessage()); + if (updQts < d.vqts.v) updQts = d.vqts.v; + } break; + + case mtpc_updateEncryptedChatTyping: { + const MTPDupdateEncryptedChatTyping &d(update.c_updateEncryptedChatTyping()); + } break; + + case mtpc_updateEncryption: { + const MTPDupdateEncryption &d(update.c_updateEncryption()); + } break; + + case mtpc_updateEncryptedMessagesRead: { + const MTPDupdateEncryptedMessagesRead &d(update.c_updateEncryptedMessagesRead()); + } break; + + case mtpc_updateNewGeoChatMessage: { + const MTPDupdateNewGeoChatMessage &d(update.c_updateNewGeoChatMessage()); +// PeerId peer = App::histories().addToBack(d.vmessage); +// history.peerMessagesUpdated(peer); + } break; + + case mtpc_updateUserBlocked: { + const MTPDupdateUserBlocked &d(update.c_updateUserBlocked()); + // + } break; + + case mtpc_updateNotifySettings: { + const MTPDupdateNotifySettings &d(update.c_updateNotifySettings()); + applyNotifySetting(d.vpeer, d.vnotify_settings); + } break; + } +} diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h new file mode 100644 index 000000000..801bafd5d --- /dev/null +++ b/Telegram/SourceFiles/mainwidget.h @@ -0,0 +1,278 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "gui/flatbutton.h" + +#include "dialogswidget.h" +#include "historywidget.h" +#include "profilewidget.h" + +class Window; +class DialogRow; +class MainWidget; + +class TopBarWidget : public QWidget, public Animated { + Q_OBJECT + +public: + + TopBarWidget(MainWidget *w); + + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void paintEvent(QPaintEvent *e); + void mousePressEvent(QMouseEvent *e); + void resizeEvent(QResizeEvent *e); + + bool animStep(float64 ms); + void enableShadow(bool enable = true); + + void hideAll(); + void showAll(); + void showSelected(uint32 selCount); + +public slots: + + void onForwardSelection(); + void onDeleteSelection(); + void onClearSelection(); + void onAddContact(); + void onEdit(); + void onDeleteContact(); + void onDeleteContactSure(); + void onDeleteAndExit(); + void onDeleteAndExitSure(); + +signals: + + void clicked(); + +private: + + MainWidget *main(); + anim::fvalue a_over; + bool _drawShadow; + + uint32 _selCount; + QString _selStr; + int32 _selStrWidth; + + FlatButton _clearSelection; + FlatButton _forward, _delete; + FlatButton _edit, _leaveGroup, _addContact, _deleteContact; + +}; + +class MainWidget : public QWidget, public Animated, public RPCSender { + Q_OBJECT + +public: + + MainWidget(Window *window); + + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void keyPressEvent(QKeyEvent *e); + + void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth); + TopBarWidget *topBar(); + + void animShow(const QPixmap &bgAnimCache, bool back = false); + bool animStep(float64 ms); + + void start(const MTPUser &user); + void startFull(const MTPVector &users); + void applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *history = 0); + void gotNotifySetting(MTPInputNotifyPeer peer, const MTPPeerNotifySettings &settings); + bool failNotifySetting(MTPInputNotifyPeer peer); + + void updateNotifySetting(PeerData *peer, bool enabled); + + void activate(); + + void createDialogAtTop(History *history, int32 unreadCount); + void dlgUpdated(DialogRow *row); + void dlgUpdated(History *row); + + void windowShown(); + + void sentDataReceived(uint64 randomId, const MTPmessages_SentMessage &data); + void sentFullDataReceived(uint64 randomId, const MTPmessages_StatedMessage &result); // randomId = 0 - new message, <> 0 - already added new message + void sentFullDatasReceived(const MTPmessages_StatedMessages &result); + void forwardDone(PeerId peer, const MTPmessages_StatedMessages &result); + void msgUpdated(PeerId peer, HistoryItem *msg); + void historyToDown(History *hist); + void dialogsToUp(); + void dialogsClear(); // after showing peer history + void newUnreadMsg(History *history, MsgId msgId); + void updUpdated(int32 pts, int32 date, int32 qts, int32 seq); + void historyWasRead(); + + bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const; + bool getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const; + PeerData *peerBefore(const PeerData *peer); + PeerData *peerAfter(const PeerData *peer); + PeerData *peer(); + PeerData *activePeer(); + PeerData *profilePeer(); + void showPeerProfile(const PeerData *peer, bool back = false); + void showPeerBack(); + QRect historyRect() const; + + void confirmSendImage(const ReadyLocalMedia &img); + void cancelSendImage(); + + void destroyData(); + void updateOnlineDisplayIn(int32 msecs); + + void addNewContact(int32 uid, bool show = true); + + bool isActive() const; + bool historyIsActive() const; + + int32 dlgsWidth() const; + + void forwardLayer(bool forwardSelected = false); + void deleteLayer(int32 selectedCount = -1); // -1 - context item, else selected, -2 - cancel upload + void shareContactLayer(UserData *contact); + void noHider(HistoryHider *destroyed); + mtpRequestId onForward(const PeerId &peer, bool forwardSelected); + void onShareContact(const PeerId &peer, UserData *contact); + bool selectingPeer(); + void offerPeer(PeerId peer); + void hidePeerSelect(); + void focusPeerSelect(); + void dialogsActivate(); + + bool leaveChatFailed(PeerData *peer, const RPCError &e); + void deleteHistory(PeerData *peer, const MTPmessages_StatedMessage &result); + void deleteHistoryPart(PeerData *peer, const MTPmessages_AffectedHistory &result); + void deletedContact(UserData *user, const MTPcontacts_Link &result); + void deleteHistoryAndContact(UserData *user, const MTPcontacts_Link &result); + void clearHistory(PeerData *peer); + void removeContact(UserData *user); + + void addParticipants(ChatData *chat, const QVector &users); + void addParticipantDone(ChatData *chat, const MTPmessages_StatedMessage &result); + bool addParticipantFail(ChatData *chat, const RPCError &e); + + void kickParticipant(ChatData *chat, UserData *user); + void kickParticipantDone(ChatData *chat, const MTPmessages_StatedMessage &result); + bool kickParticipantFail(ChatData *chat, const RPCError &e); + + void checkPeerHistory(PeerData *peer); + void checkedHistory(PeerData *peer, const MTPmessages_Messages &result); + + void forwardSelectedItems(); + void deleteSelectedItems(); + void clearSelectedItems(); + + QRect rectForTitleAnim() const; + + DialogsIndexed &contactsList(); + + ~MainWidget(); + +signals: + + void peerUpdated(PeerData *peer); + void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars); + void peerPhotoChanged(PeerData *peer); + void dialogRowReplaced(DialogRow *oldRow, DialogRow *newRow); + void dialogToTop(const History::DialogLinks &links); + void dialogsUpdated(); + void historyItemDeleted(HistoryItem *item); + +public slots: + + void videoLoadProgress(mtpFileLoader *loader); + void videoLoadFailed(mtpFileLoader *loader, bool started); + void videoLoadRetry(); + void audioLoadProgress(mtpFileLoader *loader); + void audioLoadFailed(mtpFileLoader *loader, bool started); + void audioLoadRetry(); + void documentLoadProgress(mtpFileLoader *loader); + void documentLoadFailed(mtpFileLoader *loader, bool started); + void documentLoadRetry(); + + void setInnerFocus(); + void dialogsCancelled(); + + void onParentResize(const QSize &newSize); + void getDifference(); + + void setOnline(int windowState = -1); + void mainStateChanged(Qt::WindowState state); + void updateOnlineDisplay(); + + void showPeer(const PeerId &peer, bool back = false, bool force = false); + void onTopBarClick(); + void onPeerShown(PeerData *peer); + + void onUpdateNotifySettings(); + +private: + + uint64 failedObjId; + QString failedFileName; + void loadFailed(mtpFileLoader *loader, bool started, const char *retrySlot); + + void gotDifference(const MTPupdates_Difference &diff); + bool failDifference(const RPCError &e); + void feedDifference(const MTPVector &users, const MTPVector &chats, const MTPVector &msgs, const MTPVector &other); + void gotState(const MTPupdates_State &state); + void updSetState(int32 pts, int32 date, int32 qts, int32 seq); + + void feedUpdates(const MTPVector &updates, bool skipMessageIds = false); + void feedMessageIds(const MTPVector &updates); + void feedUpdate(const MTPUpdate &update); + + void updateReceived(const mtpPrime *from, const mtpPrime *end); + bool updateFail(const RPCError &e); + + void hideAll(); + void showAll(); + + QPixmap _animCache, _bgAnimCache; + anim::ivalue a_coord, a_bgCoord; + anim::fvalue a_alpha, a_bgAlpha; + + int32 _dialogsWidth; + + MTPDuserSelf self; + DialogsWidget dialogs; + HistoryWidget history; + ProfileWidget *profile; + TopBarWidget _topBar; + HistoryHider *hider; + QVector profileStack; + QPixmap profileAnimCache; + + int updPts, updDate, updQts, updSeq; + bool updInited; + QTimer noUpdatesTimer; + + mtpRequestId onlineRequest; + QTimer onlineTimer; + QTimer onlineUpdater; + + QSet updateNotifySettingPeers; + QTimer updateNotifySettingTimer; +}; diff --git a/Telegram/SourceFiles/mtproto/generate.py b/Telegram/SourceFiles/mtproto/generate.py new file mode 100644 index 000000000..3ce26816c --- /dev/null +++ b/Telegram/SourceFiles/mtproto/generate.py @@ -0,0 +1,605 @@ +''' +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +''' +import glob +import re + +funcs = 0 +types = 0; +consts = 0 +funcsNow = 0 +enums = []; +funcsDict = {}; +typesDict = {}; +TypesDict = {}; +typesList = []; +boxed = {}; +funcsText = ''; +typesText = ''; +dataTexts = ''; +inlineMethods = ''; +textSerialize = ''; +forwards = ''; +forwTypedefs = ''; +out = open('mtpScheme.h', 'w') +out.write('/*\n'); +out.write('Created from \'/SourceFiles/mtproto/scheme.tl\' by \'/SourceFiles/mtproto/generate.py\' script\n\n'); +out.write('WARNING! All changes made in this file will be lost!\n\n'); +out.write('This file is part of Telegram Desktop,\n'); +out.write('an unofficial desktop messaging app, see https://telegram.org\n'); +out.write('\n'); +out.write('Telegram Desktop is free software: you can redistribute it and/or modify\n'); +out.write('it under the terms of the GNU General Public License as published by\n'); +out.write('the Free Software Foundation, either version 3 of the License, or\n'); +out.write('(at your option) any later version.\n'); +out.write('\n'); +out.write('It is distributed in the hope that it will be useful,\n'); +out.write('but WITHOUT ANY WARRANTY; without even the implied warranty of\n'); +out.write('MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n'); +out.write('GNU General Public License for more details.\n'); +out.write('\n'); +out.write('Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n'); +out.write('Copyright (c) 2014 John Preston, https://tdesktop.com\n'); +out.write('*/\n'); +out.write('#pragma once\n\n#include "mtpCoreTypes.h"\n'); +with open('scheme.tl') as f: + for line in f: + nocomment = re.match(r'^(.*?)//', line) + if (nocomment): + line = nocomment.group(1); + if (re.match(r'\-\-\-functions\-\-\-', line)): + funcsNow = 1; + continue; + if (re.match(r'\-\-\-types\-\-\-', line)): + funcsNow = 0; + continue; + if (re.match(r'^\s*$', line)): + continue; + + nametype = re.match(r'([a-zA-Z\.0-9_]+)#([0-9a-f]+)([^=]*)=\s*([a-zA-Z\.<>0-9_]+);', line); + if (not nametype): + print('Bad line found: ' + line); + continue; + + name = nametype.group(1); + nameInd = name.find('.'); + if (nameInd >= 0): + Name = name[0:nameInd] + '_' + name[nameInd + 1:nameInd + 2].upper() + name[nameInd + 2:]; + name = name.replace('.', '_'); + else: + Name = name[0:1].upper() + name[1:]; + typeid = nametype.group(2); + params = nametype.group(3); + restype = nametype.group(4); + if (restype.find('<') >= 0): + templ = re.match(r'^([vV]ector<)([A-Za-z0-9\._]+)>$', restype); + if (templ): + restype = templ.group(1) + 'MTP' + templ.group(2).replace('.', '_') + '>'; + else: + print('Bad template type: ' + restype); + continue; + resType = restype.replace('.', '_'); + if (restype.find('.') >= 0): + parts = re.match(r'([a-z]+)\.([A-Z][A-Za-z0-9<>\._]+)', restype) + if (parts): + restype = parts.group(1) + '_' + parts.group(2)[0:1].lower() + parts.group(2)[1:]; + else: + print('Bad result type name with dot: ' + restype); + continue; + else: + if (re.match(r'^[A-Z]', restype)): + restype = restype[:1].lower() + restype[1:]; + else: + print('Bad result type name: ' + restype); + continue; + + boxed[resType] = restype; + boxed[Name] = name; + + enums.append('\tmtpc_' + name + ' = 0x' + typeid); + + paramsList = params.strip().split(' '); + prms = {}; + prmsList = []; + isTemplate = ''; + for param in paramsList: + if (re.match(r'^\s*$', param)): + continue; + pnametype = re.match(r'([a-z_][a-z0-9_]*):([A-Za-z0-9<>\._]+)', param); + if (not pnametype): + pnametypeX = re.match(r'([a-z_][a-z0-9_]*):!X', param); + if (not pnametypeX or isTemplate != ''): + print('Bad param found: "' + param + '" in line: ' + line); + continue; + else: + pname = isTemplate = pnametypeX.group(1); + ptype = 'TQueryType'; + else: + pname = pnametype.group(1); + ptype = pnametype.group(2); + if (ptype.find('<') >= 0): + templ = re.match(r'^([vV]ector<)([A-Za-z0-9\._]+)>$', ptype); + if (templ): + ptype = templ.group(1) + 'MTP' + templ.group(2).replace('.', '_') + '>'; + else: + print('Bad template type: ' + ptype); + continue; + prmsList.append(pname); + prms[pname] = ptype.replace('.', '_'); + + if (isTemplate == '' and resType == 'X'): + print('Bad response type "X" in "' + name +'" in line: ' + line); + continue; + + if funcsNow: + if (isTemplate != ''): + funcsText += '\ntemplate '; + funcsText += '\nclass MTP' + name + ' { // RPC method \'' + nametype.group(1) + '\'\n'; # class + + funcsText += 'public:\n'; + + prmsStr = []; + prmsInit = []; + prmsNames = []; + if (len(prms)): + for paramName in prmsList: + paramType = prms[paramName]; + prmsInit.append('v' + paramName + '(_' + paramName + ')'); + prmsNames.append('_' + paramName); + if (paramName == isTemplate): + ptypeFull = paramType; + else: + ptypeFull = 'MTP' + paramType; + funcsText += '\t' + ptypeFull + ' v' + paramName + ';\n'; + if (paramType in ['int', 'Int', 'bool', 'Bool']): + prmsStr.append(ptypeFull + ' _' + paramName); + else: + prmsStr.append('const ' + ptypeFull + ' &_' + paramName); + funcsText += '\n'; + + funcsText += '\tMTP' + name + '() {\n\t}\n'; # constructor + funcsText += '\tMTP' + name + '(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_' + name + ') {\n\t\tread(from, end, cons);\n\t}\n'; # stream constructor + if (len(prms)): + funcsText += '\tMTP' + name + '(' + ', '.join(prmsStr) + ') : ' + ', '.join(prmsInit) + ' {\n\t}\n'; + funcsText += '\n'; + + funcsText += '\tuint32 size() const {\n'; # count size + size = []; + for k in prmsList: + v = prms[k]; + size.append('v' + k + '.size()'); + if (not len(size)): + size.append('0'); + funcsText += '\t\treturn ' + ' + '.join(size) + ';\n'; + funcsText += '\t}\n'; + + funcsText += '\tmtpTypeId type() const {\n\t\treturn mtpc_' + name + ';\n\t}\n'; # type id + + funcsText += '\tvoid read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_' + name + ') {\n'; # read method + for k in prmsList: + v = prms[k]; + funcsText += '\t\tv' + k + '.read(from, end);\n'; + funcsText += '\t}\n'; + + funcsText += '\tvoid write(mtpBuffer &to) const {\n'; # write method + for k in prmsList: + v = prms[k]; + funcsText += '\t\tv' + k + '.write(to);\n'; + funcsText += '\t}\n'; + + if (isTemplate != ''): + funcsText += '\n\ttypedef typename TQueryType::ResponseType ResponseType;\n'; + else: + funcsText += '\n\ttypedef MTP' + resType + ' ResponseType;\n'; # method return type + + funcsText += '};\n'; # class ending + if (isTemplate != ''): + funcsText += 'template \n'; + funcsText += 'class MTP' + Name + ' : public MTPBoxed > {\n'; + funcsText += 'public:\n'; + funcsText += '\tMTP' + Name + '() {\n\t}\n'; + funcsText += '\tMTP' + Name + '(const MTP' + name + ' &v) : MTPBoxed >(v) {\n\t}\n'; + if (len(prms)): + funcsText += '\tMTP' + Name + '(' + ', '.join(prmsStr) + ') : MTPBoxed >(MTP' + name + '(' + ', '.join(prmsNames) + ')) {\n\t}\n'; + funcsText += '};\n'; + else: + funcsText += 'class MTP' + Name + ' : public MTPBoxed {\n'; + funcsText += 'public:\n'; + funcsText += '\tMTP' + Name + '() {\n\t}\n'; + funcsText += '\tMTP' + Name + '(const MTP' + name + ' &v) : MTPBoxed(v) {\n\t}\n'; + funcsText += '\tMTP' + Name + '(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) {\n\t}\n'; + if (len(prms)): + funcsText += '\tMTP' + Name + '(' + ', '.join(prmsStr) + ') : MTPBoxed(MTP' + name + '(' + ', '.join(prmsNames) + ')) {\n\t}\n'; + funcsText += '};\n'; + funcs = funcs + 1; + + if (not restype in funcsDict): + funcsDict[restype] = []; +# TypesDict[restype] = resType; + funcsDict[restype].append([name, typeid, prmsList, prms]); + else: + if (isTemplate != ''): + print('Template types not allowed: "' + resType + '" in line: ' + line); + continue; + if (not restype in typesDict): + typesList.append(restype); + typesDict[restype] = []; + TypesDict[restype] = resType; + typesDict[restype].append([name, typeid, prmsList, prms]); + + consts = consts + 1; + +# text serialization: types and funcs +def addTextSerialize(dct): + result = ''; + for restype in dct: + v = dct[restype]; + for data in v: + name = data[0]; + prmsList = data[2]; + prms = data[3]; + + if len(result): + result += '\n'; + result += '\t\tcase mtpc_' + name + ':\n'; + if (len(prms)): + result += '\t\t\tresult += "\\n" + add;\n'; + for k in prmsList: + v = prms[k]; + result += '\t\t\tresult += " ' + k + ': " + mtpTextSerialize(from, end'; + vtypeget = re.match(r'^[Vv]ector', v); + if (vtypeget): + if (not re.match(r'^[A-Z]', v)): + result += ', mtpc_vector'; + else: + result += ', 0'; + result += ', level + 1'; + + restype = vtypeget.group(1); + try: + if boxed[restype]: + restype = 0; + except KeyError: + if re.match(r'^[A-Z]', restype): + restype = 0; + else: + restype = v; + try: + if boxed[restype]: + restype = 0; + except KeyError: + if re.match(r'^[A-Z]', restype): + restype = 0; + if (restype): + try: + conses = typesDict[restype]; + if (len(conses) > 1): + print('Complex bare type found: "' + restype + '" trying to serialize "' + k + '" of type "' + v + '"'); + continue; + result += ', mtpc_' + conses[0][0]; + except KeyError: + result += ', mtpc_' + restype; + if (not vtypeget): + result += ', level + 1'; + else: + if (not vtypeget): + result += ', 0, level + 1'; + result += ') + ",\\n" + add;\n'; + else: + result += '\t\t\tresult = " ";\n'; + result += '\t\treturn "{ ' + name + '" + result + "}";\n'; + return result; + +textSerialize += addTextSerialize(typesDict) + '\n'; +textSerialize += addTextSerialize(funcsDict); + +for restype in typesList: + v = typesDict[restype]; + resType = TypesDict[restype]; + withData = 0; + creatorsText = ''; + constructsText = ''; + constructsInline = ''; + + forwards += 'class MTP' + restype + ';\n'; + forwTypedefs += 'typedef MTPBoxed MTP' + resType + ';\n'; + + withType = (len(v) > 1); + switchLines = ''; + friendDecl = ''; + getters = ''; + reader = ''; + writer = ''; + sizeList = []; + sizeFast = ''; + newFast = ''; + sizeCases = ''; + for data in v: + name = data[0]; + typeid = data[1]; + prmsList = data[2]; + prms = data[3]; + + dataText = ''; + dataText += '\nclass MTPD' + name + ' : public mtpDataImpl {\n'; # data class + dataText += 'public:\n'; + + sizeList = []; + creatorParams = []; + creatorParamsList = []; + readText = ''; + writeText = ''; + dataText += '\tMTPD' + name + '() {\n\t}\n'; # default constructor + switchLines += '\t\tcase mtpc_' + name + ': '; # for by-type-id type constructor + if (len(prms)): + switchLines += 'setData(new MTPD' + name + '()); '; + withData = 1; + + getters += '\n\tMTPD' + name + ' &_' + name + '() {\n'; # splitting getter + getters += '\t\tif (!data) throw mtpErrorUninitialized();\n'; + if (withType): + getters += '\t\tif (_type != mtpc_' + name + ') throw mtpErrorWrongTypeId(_type, mtpc_' + name + ');\n'; + getters += '\t\tsplit();\n'; + getters += '\t\treturn *(MTPD' + name + '*)data;\n'; + getters += '\t}\n'; + + getters += '\tconst MTPD' + name + ' &c_' + name + '() const {\n'; # const getter + getters += '\t\tif (!data) throw mtpErrorUninitialized();\n'; + if (withType): + getters += '\t\tif (_type != mtpc_' + name + ') throw mtpErrorWrongTypeId(_type, mtpc_' + name + ');\n'; + getters += '\t\treturn *(const MTPD' + name + '*)data;\n'; + getters += '\t}\n'; + + constructsText += '\texplicit MTP' + restype + '(MTPD' + name + ' *_data);\n'; # by-data type constructor + constructsInline += 'inline MTP' + restype + '::MTP' + restype + '(MTPD' + name + ' *_data) : '; + if (withType): + constructsInline += '_type(mtpc_' + name + '), '; + constructsInline += 'mtpDataOwner(_data) {\n}\n'; + + dataText += '\tMTPD' + name + '('; # params constructor + prmsStr = []; + prmsInit = []; + for paramName in prmsList: + paramType = prms[paramName]; + + if (paramType in ['int', 'Int', 'bool', 'Bool']): + prmsStr.append('MTP' + paramType + ' _' + paramName); + creatorParams.append('MTP' + paramType + ' _' + paramName); + else: + prmsStr.append('const MTP' + paramType + ' &_' + paramName); + creatorParams.append('const MTP' + paramType + ' &_' + paramName); + creatorParamsList.append('_' + paramName); + prmsInit.append('v' + paramName + '(_' + paramName + ')'); + if (withType): + readText += '\t\t'; + writeText += '\t\t'; + readText += '\tv.v' + paramName + '.read(from, end);\n'; + writeText += '\tv.v' + paramName + '.write(to);\n'; + sizeList.append('v.v' + paramName + '.size()'); + + forwards += 'class MTPD' + name + ';\n'; # data class forward declaration + + dataText += ', '.join(prmsStr) + ') : ' + ', '.join(prmsInit) + ' {\n\t}\n'; + + dataText += '\n'; + for paramName in prmsList: # fields declaration + paramType = prms[paramName]; + dataText += '\tMTP' + paramType + ' v' + paramName + ';\n'; + sizeCases += '\t\tcase mtpc_' + name + ': {\n'; + sizeCases += '\t\t\tconst MTPD' + name + ' &v(c_' + name + '());\n'; + sizeCases += '\t\t\treturn ' + ' + '.join(sizeList) + ';\n'; + sizeCases += '\t\t}\n'; + sizeFast = '\tconst MTPD' + name + ' &v(c_' + name + '());\n\treturn ' + ' + '.join(sizeList) + ';\n'; + newFast = 'new MTPD' + name + '()'; + else: + sizeFast = '\treturn 0;\n'; + + switchLines += 'break;\n'; + dataText += '};\n'; # class ending + + if (len(prms)): + dataTexts += dataText; # add data class + + friendDecl += '\tfriend MTP' + restype + ' MTP_' + name + '(' + ', '.join(creatorParams) + ');\n'; + creatorsText += 'inline MTP' + restype + ' MTP_' + name + '(' + ', '.join(creatorParams) + ') {\n'; + if (len(prms)): # creator with params + creatorsText += '\treturn MTP' + restype + '(new MTPD' + name + '(' + ', '.join(creatorParamsList) + '));\n'; + else: + if (withType): # creator by type + creatorsText += '\treturn MTP' + restype + '(mtpc_' + name + ');\n'; + else: # single creator + creatorsText += '\treturn MTP' + restype + '();\n'; + creatorsText += '}\n'; + + if (withType): + reader += '\t\tcase mtpc_' + name + ': _type = cons; '; # read switch line + if (len(prms)): + reader += '{\n'; + reader += '\t\t\tif (!data) setData(new MTPD' + name + '());\n'; + reader += '\t\t\tMTPD' + name + ' &v(_' + name + '());\n'; + reader += readText; + reader += '\t\t} break;\n'; + + writer += '\t\tcase mtpc_' + name + ': {\n'; # write switch line + writer += '\t\t\tconst MTPD' + name + ' &v(c_' + name + '());\n'; + writer += writeText; + writer += '\t\t} break;\n'; + else: + reader += 'break;\n'; + else: + if (len(prms)): + reader += '\n\tif (!data) setData(new MTPD' + name + '());\n'; + reader += '\tMTPD' + name + ' &v(_' + name + '());\n'; + reader += readText; + + writer += '\tconst MTPD' + name + ' &v(c_' + name + '());\n'; + writer += writeText; + + forwards += '\n'; + + typesText += '\nclass MTP' + restype; # type class declaration + if (withData): + typesText += ' : private mtpDataOwner'; # if has data fields + typesText += ' {\n'; + typesText += 'public:\n'; + typesText += '\tMTP' + restype + '()'; # default constructor + inits = []; + if (withType): + if (withData): + inits.append('mtpDataOwner(0)'); + inits.append('_type(0)'); + else: + if (withData): + inits.append('mtpDataOwner(' + newFast + ')'); + if (withData and not withType): + typesText += ';\n'; + inlineMethods += '\ninline MTP' + restype + '::MTP' + restype + '()'; + if (inits): + inlineMethods += ' : ' + ', '.join(inits); + inlineMethods += ' {\n}\n'; + else: + if (inits): + typesText += ' : ' + ', '.join(inits); + typesText += ' {\n\t}\n'; + + inits = []; + if (withData): + inits.append('mtpDataOwner(0)'); + if (withType): + inits.append('_type(0)'); + typesText += '\tMTP' + restype + '(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons'; + if (not withType): + typesText += ' = mtpc_' + name; + typesText += ')'; # read constructor + if (inits): + typesText += ' : ' + ', '.join(inits); + typesText += ' {\n\t\tread(from, end, cons);\n\t}\n'; + + if (withData): + typesText += getters; + + typesText += '\n\tuint32 size() const;\n'; # size method + inlineMethods += '\ninline uint32 MTP' + restype + '::size() const {\n'; + if (withType and sizeCases): + inlineMethods += '\tswitch (_type) {\n'; + inlineMethods += sizeCases; + inlineMethods += '\t}\n'; + inlineMethods += '\treturn 0;\n'; + else: + inlineMethods += sizeFast; + inlineMethods += '}\n'; + + typesText += '\tmtpTypeId type() const;\n'; # type id method + inlineMethods += 'inline mtpTypeId MTP' + restype + '::type() const {\n'; + if (withType): + inlineMethods += '\tif (!_type) throw mtpErrorUninitialized();\n'; + inlineMethods += '\treturn _type;\n'; + else: + inlineMethods += '\treturn mtpc_' + v[0][0] + ';\n'; + inlineMethods += '}\n'; + + typesText += '\tvoid read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons'; # read method + if (not withType): + typesText += ' = mtpc_' + name; + typesText += ');\n'; + inlineMethods += 'inline void MTP' + restype + '::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {\n'; + if (withData): + if (withType): + inlineMethods += '\tif (cons != _type) setData(0);\n'; + else: + inlineMethods += '\tif (cons != mtpc_' + v[0][0] + ') throw mtpErrorUnexpected(cons, "MTP' + restype + '");\n'; + if (withType): + inlineMethods += '\tswitch (cons) {\n' + inlineMethods += reader; + inlineMethods += '\t\tdefault: throw mtpErrorUnexpected(cons, "MTP' + restype + '");\n'; + inlineMethods += '\t}\n'; + else: + inlineMethods += reader; + inlineMethods += '}\n'; + + typesText += '\tvoid write(mtpBuffer &to) const;\n'; # write method + inlineMethods += 'inline void MTP' + restype + '::write(mtpBuffer &to) const {\n' + if (withType): + inlineMethods += '\tswitch (_type) {\n'; + inlineMethods += writer; + inlineMethods += '\t}\n'; + else: + inlineMethods += writer; + inlineMethods += '}\n'; + + typesText += '\n\ttypedef void ResponseType;\n'; # no response types declared + + typesText += '\nprivate:\n'; # private constructors + if (withType): # by-type-id constructor + typesText += '\texplicit MTP' + restype + '(mtpTypeId type);\n'; + inlineMethods += 'inline MTP' + restype + '::MTP' + restype + '(mtpTypeId type) : _type(type)'; + if (withData): + inlineMethods += ', mtpDataOwner(0)'; + inlineMethods += ' {\n'; + inlineMethods += '\tswitch (type) {\n'; # type id check + inlineMethods += switchLines; + inlineMethods += '\t\tdefault: throw mtpErrorBadTypeId(type, "MTP' + restype + '");\n\t}\n'; + inlineMethods += '}\n'; # by-type-id constructor end + + if (withData): + typesText += constructsText; + inlineMethods += constructsInline; + + if (friendDecl): + typesText += '\n' + friendDecl; + + if (withType): + typesText += '\n\tmtpTypeId _type;\n'; # type field var + + typesText += '};\n'; # type class ended + + inlineMethods += creatorsText; + typesText += 'typedef MTPBoxed MTP' + resType + ';\n'; # boxed type definition + +textSerializeFull = '\ninline QString mtpTextSerialize(const mtpPrime *&from, const mtpPrime *end, mtpPrime cons, uint32 level, mtpPrime vcons) {\n'; +textSerializeFull += '\tQString add = QString(" ").repeated(level * 2);\n\n'; +textSerializeFull += '\tconst mtpPrime *start = from;\n'; +textSerializeFull += '\ttry {\n'; +textSerializeFull += '\t\tif (!cons) {\n'; +textSerializeFull += '\t\t\tif (from >= end) {\n'; +textSerializeFull += '\t\t\t\tthrow Exception("from >= 2");\n'; +textSerializeFull += '\t\t\t}\n'; +textSerializeFull += '\t\t\tcons = *from;\n'; +textSerializeFull += '\t\t\t++from;\n'; +textSerializeFull += '\t\t\t++start;\n'; +textSerializeFull += '\t\t}\n\n'; +textSerializeFull += '\t\tQString result;\n'; +textSerializeFull += '\t\tswitch (cons) {\n' + textSerialize + '\t\t}\n\n'; +textSerializeFull += '\t\treturn mtpTextSerializeCore(from, end, cons, level, vcons);\n'; +textSerializeFull += '\t} catch (Exception &e) {\n'; +textSerializeFull += '\t\tQString result = "(" + QString(e.what()) + QString("), cons: %1").arg(cons);\n'; +textSerializeFull += '\t\tif (vcons) result += QString(", vcons: %1").arg(vcons);\n'; +textSerializeFull += '\t\tresult += ", " + mb(start, (end - start) * sizeof(mtpPrime)).str();\n'; +textSerializeFull += '\t\treturn "[ERROR] " + result;\n'; +textSerializeFull += '\t}\n'; +textSerializeFull += '}\n'; + +out.write('\n// Type id constants\nenum {\n' + ',\n'.join(enums) + '\n};\n'); +out.write('\n// Type forward declarations\n' + forwards); +out.write('\n// Boxed types definitions\n' + forwTypedefs); +out.write('\n// Type classes definitions\n' + typesText); +out.write('\n// Type constructors with data\n' + dataTexts); +out.write('\n// RPC methods\n' + funcsText); +out.write('\n// Inline methods definition\n' + inlineMethods); +out.write('\n// Human-readable text serialization\n#if (defined _DEBUG || defined _WITH_DEBUG)\n' + textSerializeFull + '\n#endif\n'); + +print('Done, written {0} constructors, {1} functions.'.format(consts, funcs)); diff --git a/Telegram/SourceFiles/mtproto/mtp.cpp b/Telegram/SourceFiles/mtproto/mtp.cpp new file mode 100644 index 000000000..5a5516a96 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtp.cpp @@ -0,0 +1,594 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "mtp.h" + +namespace { + typedef QMap Sessions; + Sessions sessions; + MTProtoSessionPtr mainSession; + + typedef QMap RequestsByDC; // holds dc for request to this dc or -dc for request to main dc + RequestsByDC requestsByDC; + QMutex requestByDCLock; + + typedef QMap AuthExportRequests; // holds target dc for auth export request + AuthExportRequests authExportRequests; + + bool started = false; + bool loadingConfig = false; + + uint32 layer; + + typedef QMap ParserMap; + ParserMap parserMap; + + typedef QMap RequestMap; + RequestMap requestMap; + + typedef QPair DelayedRequest; + typedef QList DelayedRequestsList; + DelayedRequestsList delayedRequests; + + typedef QVector DCAuthWaiters; + typedef QMap AuthWaiters; + AuthWaiters authWaiters; + + QMutex toClearLock; + RPCCallbackClears toClear; + + RPCResponseHandler globalHandler; + MTPStateChangedHandler stateChangedHandler = 0; + _mtp_internal::RequestResender *resender = 0; + + mtpAuthKey _localKey; + + void importDone(const MTPauth_Authorization &result, mtpRequestId req) { + QMutexLocker locker(&requestByDCLock); + RequestsByDC::iterator i = requestsByDC.find(req); + if (i == requestsByDC.end()) { + LOG(("MTP Error: auth import request not found in requestsByDC, requestId: %1").arg(req)); + RPCError error(rpcClientError("AUTH_IMPORT_FAIL", QString("did not find import request in requestsByDC, request %1").arg(req))); + if (globalHandler.onFail && MTP::authedId()) (*globalHandler.onFail)(req, error); // auth failed in main dc + return; + } + int32 newdc = i.value(); + + DEBUG_LOG(("MTP Info: auth import to dc %1 succeeded").arg(newdc)); + + DCAuthWaiters &waiters(authWaiters[newdc]); + MTProtoSessionPtr session(_mtp_internal::getSession(newdc)); + if (waiters.size()) { + for (DCAuthWaiters::iterator i = waiters.begin(), e = waiters.end(); i != e; ++i) { + mtpRequestId requestId = *i; + RequestMap::const_iterator j = requestMap.constFind(requestId); + if (j == requestMap.cend()) { + LOG(("MTP Error: could not find request %1 for resending").arg(requestId)); + continue; + } + { + RequestsByDC::iterator k = requestsByDC.find(requestId); + if (k == requestsByDC.cend()) { + LOG(("MTP Error: could not find request %1 by dc for resending").arg(requestId)); + continue; + } + if (k.value() < 0) { + MTP::setdc(newdc); + k.value() = -newdc; + } else { + k.value() = k.value() - (k.value() % _mtp_internal::dcShift) + newdc; + } + DEBUG_LOG(("MTP Info: resending request %1 to dc %2 after import auth").arg(requestId).arg(k.value())); + } + session->sendPrepared(j.value()); + } + waiters.clear(); + } + } + + bool importFail(const RPCError &error, mtpRequestId req) { + if (globalHandler.onFail && MTP::authedId()) (*globalHandler.onFail)(req, error); // auth import failed + return true; + } + + void exportDone(const MTPauth_ExportedAuthorization &result, mtpRequestId req) { + AuthExportRequests::const_iterator i = authExportRequests.constFind(req); + if (i == authExportRequests.cend()) { + LOG(("MTP Error: auth export request target dc not found, requestId: %1").arg(req)); + RPCError error(rpcClientError("AUTH_IMPORT_FAIL", QString("did not find target dc, request %1").arg(req))); + if (globalHandler.onFail && MTP::authedId()) (*globalHandler.onFail)(req, error); // auth failed in main dc + return; + } + + const MTPDauth_exportedAuthorization &data(result.c_auth_exportedAuthorization()); + MTP::send(MTPauth_ImportAuthorization(data.vid, data.vbytes), rpcDone(importDone), rpcFail(importFail), i.value()); + authExportRequests.remove(req); + } + + bool exportFail(const RPCError &error, mtpRequestId req) { + AuthExportRequests::const_iterator i = authExportRequests.constFind(req); + if (i != authExportRequests.cend()) { + authWaiters[i.value()].clear(); + } + if (globalHandler.onFail && MTP::authedId()) (*globalHandler.onFail)(req, error); // auth failed in main dc + return true; + } + + bool onErrorDefault(mtpRequestId requestId, const RPCError &error) { + const QString &err(error.type()); + QRegularExpressionMatch m;; + if ((m = QRegularExpression("^(FILE|PHONE|NETWORK|USER)_MIGRATE_(\\d+)$").match(err)).hasMatch()) { + if (!requestId) return false; + + int32 dc = 0, newdc = m.captured(2).toInt(); + { + QMutexLocker locker(&requestByDCLock); + RequestsByDC::iterator i = requestsByDC.find(requestId); + if (i == requestsByDC.end()) { + LOG(("MTP Error: could not find request %1 for migrating to %2").arg(requestId).arg(newdc)); + } else { + dc = i.value(); + } + } + if (!dc || !newdc) return false; + + DEBUG_LOG(("MTP Info: changing request %1 dc%2 to %3").arg(requestId).arg((dc > 0) ? "" : " and main dc").arg(newdc)); + if (dc < 0) { + if (MTP::authedId()) { // import auth, set dc and resend + DEBUG_LOG(("MTP Info: importing auth to dc %1").arg(newdc)); + DCAuthWaiters &waiters(authWaiters[newdc]); + if (!waiters.size()) { + authExportRequests.insert(MTP::send(MTPauth_ExportAuthorization(MTP_int(newdc)), rpcDone(exportDone), rpcFail(exportFail)), newdc); + } + waiters.push_back(requestId); + return true; + } else { + MTP::setdc(newdc); + } + } + + RequestMap::const_iterator i = requestMap.constFind(requestId); + if (i == requestMap.cend()) { + LOG(("MTP Error: could not find request %1").arg(requestId)); + return false; + } + _mtp_internal::registerRequest(requestId, (dc < 0) ? -newdc : newdc); + _mtp_internal::getSession(newdc)->sendPrepared(i.value()); + return true; + } else if ((m = QRegularExpression("^FLOOD_WAIT_(\\d+)$").match(err)).hasMatch()) { + if (!requestId) return false; + + int32 secs = m.captured(1).toInt(); + uint64 sendAt = getms() + secs * 1000 + 10; + DelayedRequestsList::iterator i = delayedRequests.begin(), e = delayedRequests.end(); + for (; i != e; ++i) { + if (i->first == requestId) return true; + if (i->second > sendAt) break; + } + delayedRequests.insert(i, DelayedRequest(requestId, sendAt)); + + if (resender) resender->checkDelayed(); + + return true; + } else if (error.code() == 401) { + int32 dc = 0; + { + QMutexLocker locker(&requestByDCLock); + RequestsByDC::iterator i = requestsByDC.find(requestId); + if (i != requestsByDC.end()) { + dc = i.value(); + } else { + LOG(("MTP Error: unauthorized request without dc info, requestId %1").arg(requestId)); + } + } + int32 newdc = abs(dc) % _mtp_internal::dcShift; + if (!newdc || newdc == mtpMainDC() || !MTP::authedId()) { + if (globalHandler.onFail) (*globalHandler.onFail)(requestId, error); // auth failed in main dc + return false; + } + + DEBUG_LOG(("MTP Info: importing auth to dc %1").arg(dc)); + DCAuthWaiters &waiters(authWaiters[newdc]); + if (!waiters.size()) { + authExportRequests.insert(MTP::send(MTPauth_ExportAuthorization(MTP_int(newdc)), rpcDone(exportDone), rpcFail(exportFail)), newdc); + } + waiters.push_back(requestId); + return true; + } else if (err == qsl("CONNECTION_NOT_INITED") || err == qsl("CONNECTION_LAYER_INVALID")) { + RequestMap::const_iterator i = requestMap.constFind(requestId); + if (i == requestMap.cend()) { + LOG(("MTP Error: could not find request %1").arg(requestId)); + return false; + } + int32 dc = 0; + { + QMutexLocker locker(&requestByDCLock); + RequestsByDC::iterator i = requestsByDC.find(requestId); + if (i == requestsByDC.end()) { + LOG(("MTP Error: could not find request %1 for resending with init connection").arg(requestId)); + } else { + dc = i.value(); + } + } + if (!dc) return false; + + _mtp_internal::getSession(dc < 0 ? (-dc) : dc)->sendPreparedWithInit(i.value()); + return true; + } + return false; + } + +} + +namespace _mtp_internal { + MTProtoSessionPtr getSession(int32 dc) { + if (!started) return MTProtoSessionPtr(); + if (!dc) return mainSession; + if (!(dc % _mtp_internal::dcShift)) { + dc += mainSession->getDC(); + } + + Sessions::const_iterator i = sessions.constFind(dc); + if (i != sessions.cend()) return *i; + + MTProtoSessionPtr result(new MTProtoSession()); + result->start(dc); + + sessions.insert(dc, result); + return result; + } + + void registerRequest(mtpRequestId requestId, int32 dc) { + { + QMutexLocker locker(&requestByDCLock); + requestsByDC.insert(requestId, dc); + } + _mtp_internal::performDelayedClear(); // need to do it somewhere.. + } + + void unregisterRequest(mtpRequestId requestId) { + QMutexLocker locker(&requestByDCLock); + RequestsByDC::iterator i = requestsByDC.find(requestId); + if (i != requestsByDC.end()) { + requestsByDC.erase(i); + } + } + + uint32 getLayer() { + return layer; + } + + mtpRequestId storeRequest(mtpRequest &request, const RPCResponseHandler &parser) { + mtpRequestId res = reqid(); + request->requestId = res; + if (parser.onDone || parser.onFail) { + parserMap.insert(res, parser); + requestMap.insert(res, request); + } + return res; + } + + void replaceRequest(mtpRequest &newRequest, const mtpRequest &oldRequest) { + newRequest->requestId = oldRequest->requestId; + RequestMap::iterator i = requestMap.find(oldRequest->requestId); + if (i != requestMap.cend()) { + i.value() = newRequest; + } + } + + void clearCallbacks(mtpRequestId requestId, int32 errorCode) { + ParserMap::iterator i = parserMap.find(requestId); + if (i != parserMap.end()) { + if (errorCode) { + rpcErrorOccured(requestId, i.value(), rpcClientError("CLEAR_CALLBACK", QString("did not handle request %1, error code %2").arg(requestId).arg(errorCode))); + } + parserMap.erase(i); + } + requestMap.remove(requestId); + _mtp_internal::unregisterRequest(requestId); + } + + void clearCallbacksDelayed(const RPCCallbackClears &requestIds) { + uint32 idsCount = requestIds.size(); + if (!idsCount) return; + + if (cDebug()) { + QString idsStr = QString("%1").arg(requestIds[0].requestId); + for (uint32 i = 1; i < idsCount; ++i) { + idsStr += QString(", %1").arg(requestIds[i].requestId); + } + DEBUG_LOG(("RPC Info: clear callbacks delayed, msgIds: %1").arg(idsStr)); + } + + QMutexLocker lock(&toClearLock); + uint32 toClearNow = toClear.size(); + if (toClearNow) { + toClear.resize(toClearNow + idsCount); + memcpy(toClear.data() + toClearNow, requestIds.constData(), idsCount * sizeof(RPCCallbackClear)); + } else { + toClear = requestIds; + } + } + + void performDelayedClear() { + QMutexLocker lock(&toClearLock); + if (!toClear.isEmpty()) { + for (RPCCallbackClears::iterator i = toClear.begin(), e = toClear.end(); i != e; ++i) { + if (cDebug()) { + if (parserMap.find(i->requestId) != parserMap.end()) { + DEBUG_LOG(("RPC Info: clearing delayed callback %1, error code %2").arg(i->requestId).arg(i->errorCode)); + } + } + clearCallbacks(i->requestId, i->errorCode); + } + toClear.clear(); + } + } + + void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) { + ParserMap::iterator i = parserMap.find(requestId); + if (i != parserMap.cend()) { + DEBUG_LOG(("RPC Info: found parser for request %1, trying to parse response..").arg(requestId)); + try { + if (from >= end) throw mtpErrorInsufficient(); + + if (*from == mtpc_rpc_error) { + RPCError err(MTPRpcError(from, end)); + DEBUG_LOG(("RPC Info: error received, code %1, type %2, description: %3").arg(err.code()).arg(err.type()).arg(err.description())); + if (!rpcErrorOccured(requestId, i.value(), err)) { + return; + } + } else { + if (i.value().onDone) (*i.value().onDone)(requestId, from, end); + } + } catch (Exception &e) { + if (!rpcErrorOccured(requestId, i.value(), rpcClientError("RESPONSE_PARSE_FAILED", QString("exception text: ") + e.what()))) { + return; + } + } + parserMap.erase(i); + requestMap.remove(requestId); + } else { + DEBUG_LOG(("RPC Info: parser not found for %1").arg(requestId)); + } + unregisterRequest(requestId); + } + + void globalCallback(const mtpPrime *from, const mtpPrime *end) { + if (globalHandler.onDone) (*globalHandler.onDone)(0, from, end); // some updates were received + } + + void onStateChange(int32 dc, int32 state) { + if (stateChangedHandler) stateChangedHandler(dc, state); + } + + bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err) { // return true if need to clean request data + if (onErrorDefault(requestId, err)) { + return false; + } + LOG(("RPC Error: request %1 got fail with code %2, error %3%4").arg(requestId).arg(err.code()).arg(err.type()).arg(err.description().isEmpty() ? QString() : QString(": %1").arg(err.description()))); + onFail && (*onFail)(requestId, err); + return true; + } + + void RequestResender::checkDelayed() { + uint64 now = getms(); + while (!delayedRequests.isEmpty() && now >= delayedRequests.front().second) { + mtpRequestId requestId = delayedRequests.front().first; + delayedRequests.pop_front(); + + int32 dc = 0; + { + QMutexLocker locker(&requestByDCLock); + RequestsByDC::const_iterator i = requestsByDC.constFind(requestId); + if (i != requestsByDC.cend()) { + dc = i.value(); + } else { + LOG(("MTP Error: could not find request dc for delayed resend, requestId %1").arg(requestId)); + continue; + } + } + + RequestMap::const_iterator j = requestMap.constFind(requestId); + if (j == requestMap.cend()) { + DEBUG_LOG(("MTP Error: could not find request %1").arg(requestId)); + continue; + } + _mtp_internal::getSession(dc < 0 ? (-dc) : dc)->sendPrepared(j.value(), 0, false); + } + + if (!delayedRequests.isEmpty()) { + QTimer::singleShot(delayedRequests.front().second - now, this, SLOT(checkDelayed())); + } + } +}; + +namespace MTP { + mtpAuthKey &localKey() { + return _localKey; + } + + void createLocalKey(const QByteArray &pass, QByteArray *salt) { + uchar key[LocalEncryptKeySize] = { 0 }; + int32 iterCount = pass.size() ? LocalEncryptIterCount : LocalEncryptNoPwdIterCount; // dont slow down for no password + QByteArray newSalt; + if (!salt) { + newSalt.resize(LocalEncryptSaltSize); + memset_rand(newSalt.data(), newSalt.size()); + salt = &newSalt; + + cSetLocalSalt(newSalt); + } + + PKCS5_PBKDF2_HMAC_SHA1(pass.constData(), pass.size(), (uchar*)salt->data(), salt->size(), iterCount, LocalEncryptKeySize, key); + + _localKey.setKey(key); + } + + void start() { + if (!localKey().created()) { + LOG(("App Error: trying to start MTP without local key!")); + return; + } + + mtpLoadData(); + MTProtoDCMap &dcs(mtpDCMap()); + + mainSession = MTProtoSessionPtr(new MTProtoSession()); + mainSession->start(mtpMainDC()); + sessions[mainSession->getDC()] = mainSession; + + started = true; + resender = new _mtp_internal::RequestResender(); + + if (mtpNeedConfig()) { + mtpConfigLoader()->load(); + } + } + + void restart() { + if (!started) return; + + for (Sessions::const_iterator i = sessions.cbegin(), e = sessions.cend(); i != e; ++i) { + (*i)->restart(); + } + } + + void setLayer(uint32 l) { + if (l > mtpLayerMax) { + l = mtpLayerMax; + } else if (!l) { + l = 1; + } + layer = l - 1; + } + + void setdc(int32 dc, bool fromZeroOnly) { + if (!started) return; + + int32 m = mainSession->getDC(); + if (!dc || m == dc || m && fromZeroOnly) return; + mtpSetDC(dc); + mainSession = _mtp_internal::getSession(dc); + } + + int32 maindc() { + if (!started) return 0; + + return mainSession->getDC(); + } + + int32 dcstate(int32 dc) { + if (!started) return 0; + + if (!dc) return mainSession->getState(); + if (!(dc % _mtp_internal::dcShift)) { + dc += mainSession->getDC(); + } + + Sessions::const_iterator i = sessions.constFind(dc); + if (i != sessions.cend()) return (*i)->getState(); + + return MTProtoConnection::Disconnected; + } + + QString dctransport(int32 dc) { + if (!started) return QString(); + + if (!dc) return mainSession->transport(); + if (!(dc % _mtp_internal::dcShift)) { + dc += mainSession->getDC(); + } + + Sessions::const_iterator i = sessions.constFind(dc); + if (i != sessions.cend()) return (*i)->transport(); + + return QString(); + } + + void initdc(int32 dc) { + if (!started) return; + _mtp_internal::getSession(dc); + } + + void cancel(mtpRequestId requestId) { + { + QMutexLocker locker(&requestByDCLock); + RequestsByDC::iterator i = requestsByDC.find(requestId); + if (i != requestsByDC.end()) { + _mtp_internal::getSession(abs(i.value()))->cancel(requestId); + } + } + _mtp_internal::clearCallbacks(requestId); + } + + int32 state(mtpRequestId requestId) { + if (requestId > 0) { + QMutexLocker locker(&requestByDCLock); + RequestsByDC::iterator i = requestsByDC.find(requestId); + if (i != requestsByDC.end()) { + return _mtp_internal::getSession(abs(i.value()))->requestState(requestId); + } + return MTP::RequestSent; + } + return _mtp_internal::getSession(-requestId)->requestState(0); + } + + void stop() { + for (Sessions::iterator i = sessions.begin(), e = sessions.end(); i != e; ++i) { + i.value()->stop(); + } + delete resender; + resender = 0; + } + + void authed(int32 uid) { + mtpAuthed(uid); + } + + int32 authedId() { + return mtpAuthed(); + } + + void setGlobalDoneHandler(RPCDoneHandlerPtr handler) { + globalHandler.onDone = handler; + } + + void setGlobalFailHandler(RPCFailHandlerPtr handler) { + globalHandler.onFail = handler; + } + + void setStateChangedHandler(MTPStateChangedHandler handler) { + stateChangedHandler = handler; + } + + void clearGlobalHandlers() { + setGlobalDoneHandler(RPCDoneHandlerPtr()); + setGlobalFailHandler(RPCFailHandlerPtr()); + setStateChangedHandler(0); + } + + void writeConfig(QDataStream &stream) { + return mtpWriteConfig(stream); + } + + bool readConfigElem(int32 blockId, QDataStream &stream) { + return mtpReadConfigElem(blockId, stream); + } + +}; diff --git a/Telegram/SourceFiles/mtproto/mtp.h b/Telegram/SourceFiles/mtproto/mtp.h new file mode 100644 index 000000000..d755cab71 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtp.h @@ -0,0 +1,114 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "mtproto/mtpSession.h" +#include "mtproto/mtpFileLoader.h" + +namespace _mtp_internal { + MTProtoSessionPtr getSession(int32 dc = 0); // 0 - current set dc + + void registerRequest(mtpRequestId requestId, int32 dc); + void unregisterRequest(mtpRequestId requestId); + + uint32 getLayer(); + + static const uint32 dcShift = 10000; + + mtpRequestId storeRequest(mtpRequest &request, const RPCResponseHandler &parser); + void replaceRequest(mtpRequest &newRequest, const mtpRequest &oldRequest); + void clearCallbacks(mtpRequestId requestId, int32 errorCode = RPCError::NoError); // 0 - do not toggle onError callback + void clearCallbacksDelayed(const RPCCallbackClears &requestIds); + void performDelayedClear(); + void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end); + void globalCallback(const mtpPrime *from, const mtpPrime *end); + void onStateChange(int32 dc, int32 state); + bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err); // return true if need to clean request data + inline bool rpcErrorOccured(mtpRequestId requestId, const RPCResponseHandler &handler, const RPCError &err) { + return rpcErrorOccured(requestId, handler.onFail, err); + } + + class RequestResender : public QObject { + Q_OBJECT + + public slots: + + void checkDelayed(); + }; +}; + +namespace MTP { + + mtpAuthKey &localKey(); + void createLocalKey(const QByteArray &pass, QByteArray *salt = 0); + + static const uint32 dld = 1 * _mtp_internal::dcShift; // send(req, callbacks, MTP::dld + dc) - for download + static const uint32 upl = 2 * _mtp_internal::dcShift; // send(req, callbacks, MTP::upl + dc) - for upload + + void start(); + void restart(); + + void setLayer(uint32 layer); + + void setdc(int32 dc, bool fromZeroOnly = false); + int32 maindc(); + int32 dcstate(int32 dc = 0); + QString dctransport(int32 dc = 0); + void initdc(int32 dc); + template + inline mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), int32 dc = 0, uint64 msCanWait = 0) { + return _mtp_internal::getSession(dc)->send(request, callbacks, msCanWait, _mtp_internal::getLayer(), !dc); + } + template + inline mtpRequestId send(const TRequest &request, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail = RPCFailHandlerPtr(), int32 dc = 0, uint64 msCanWait = 0) { + return send(request, RPCResponseHandler(onDone, onFail), dc, msCanWait); + } + void cancel(mtpRequestId req); + + enum { + RequestSent = 0, + RequestConnecting = 1, + RequestSending = 2 + }; + int32 state(mtpRequestId req); // < 0 means waiting for such count of ms + + void defOnError(const RPCError &err); + + void stop(); + + void authed(int32 uid); + int32 authedId(); + + void setGlobalDoneHandler(RPCDoneHandlerPtr handler); + void setGlobalFailHandler(RPCFailHandlerPtr handler); + void setStateChangedHandler(MTPStateChangedHandler handler); + void clearGlobalHandlers(); + + template + T nonce() { + T result; + memset_rand(&result, sizeof(T)); + return result; + } + + void writeConfig(QDataStream &stream); + bool readConfigElem(int32 blockId, QDataStream &stream); + +}; + +#include "mtproto/mtpSessionImpl.h" diff --git a/Telegram/SourceFiles/mtproto/mtpAuthKey.h b/Telegram/SourceFiles/mtproto/mtpAuthKey.h new file mode 100644 index 000000000..61909a03b --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpAuthKey.h @@ -0,0 +1,151 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +class mtpAuthKey { +public: + + mtpAuthKey() : _isset(false), _dc(0) { + } + + bool created() const { + return _isset; + } + + void setKey(const void *from) { + memcpy(_key, from, 256); + uchar sha1Buffer[20]; + _keyId = *(uint64*)(hashSha1(_key, 256, sha1Buffer) + 3); + _isset = true; + } + + void setDC(uint32 dc) { + _dc = dc; + } + + uint32 getDC() const { + if (!_isset) throw mtpErrorKeyNotReady("getDC()"); + return _dc; + } + + uint64 keyId() const { + if (!_isset) throw mtpErrorKeyNotReady("keyId()"); + return _keyId; + } + + void prepareAES(const MTPint128 &msgKey, MTPint256 &aesKey, MTPint256 &aesIV, bool send = true) { + if (!_isset) throw mtpErrorKeyNotReady(QString("prepareAES(.., %1)").arg(logBool(send))); + + uint32 x = send ? 0 : 8; + + uchar data_a[16 + 32], sha1_a[20]; + memcpy(data_a, &msgKey, 16); + memcpy(data_a + 16, _key + x, 32); + hashSha1(data_a, 16 + 32, sha1_a); + + uchar data_b[16 + 16 + 16], sha1_b[20]; + memcpy(data_b, _key + 32 + x, 16); + memcpy(data_b + 16, &msgKey, 16); + memcpy(data_b + 32, _key + 48 + x, 16); + hashSha1(data_b, 16 + 16 + 16, sha1_b); + + uchar data_c[32 + 16], sha1_c[20]; + memcpy(data_c, _key + 64 + x, 32); + memcpy(data_c + 32, &msgKey, 16); + hashSha1(data_c, 32 + 16, sha1_c); + + uchar data_d[16 + 32], sha1_d[20]; + memcpy(data_d, &msgKey, 16); + memcpy(data_d + 16, _key + 96 + x, 32); + hashSha1(data_d, 16 + 32, sha1_d); + + uchar *key((uchar*)&aesKey), *iv((uchar*)&aesIV); + memcpy(key, sha1_a, 8); + memcpy(key + 8, sha1_b + 8, 12); + memcpy(key + 8 + 12, sha1_c + 4, 12); + memcpy(iv, sha1_a + 8, 12); + memcpy(iv + 12, sha1_b, 8); + memcpy(iv + 12 + 8, sha1_c + 16, 4); + memcpy(iv + 12 + 8 + 4, sha1_d, 8); + } + + void write(QDataStream &to) const { + if (!_isset) throw mtpErrorKeyNotReady("write(..)"); + to.writeRawData(_key, 256); + } + + static const uint64 RecreateKeyId = 0xFFFFFFFFFFFFFFFFL; + +private: + + char _key[256]; + uint64 _keyId; + bool _isset; + uint32 _dc; + +}; + +typedef QSharedPointer mtpAuthKeyPtr; + +inline void aesEncrypt(const void *src, void *dst, uint32 len, void *key, void *iv) { + uchar aes_key[32], aes_iv[32]; + memcpy(aes_key, key, 32); + memcpy(aes_iv, iv, 32); + + AES_KEY aes; + AES_set_encrypt_key(aes_key, 256, &aes); + AES_ige_encrypt((const uchar*)src, (uchar*)dst, len, &aes, aes_iv, AES_ENCRYPT); +} + +inline void aesEncrypt(const void *src, void *dst, uint32 len, mtpAuthKeyPtr authKey, const MTPint128 &msgKey) { + MTPint256 aesKey, aesIV; + authKey->prepareAES(msgKey, aesKey, aesIV); + + return aesEncrypt(src, dst, len, &aesKey, &aesIV); +} + +inline void aesEncryptLocal(const void *src, void *dst, uint32 len, mtpAuthKey *authKey, const void *key128) { + MTPint256 aesKey, aesIV; + authKey->prepareAES(*(const MTPint128*)key128, aesKey, aesIV, false); + + return aesEncrypt(src, dst, len, &aesKey, &aesIV); +} + +inline void aesDecrypt(const void *src, void *dst, uint32 len, void *key, void *iv) { + uchar aes_key[32], aes_iv[32]; + memcpy(aes_key, key, 32); + memcpy(aes_iv, iv, 32); + + AES_KEY aes; + AES_set_decrypt_key(aes_key, 256, &aes); + AES_ige_encrypt((const uchar*)src, (uchar*)dst, len, &aes, aes_iv, AES_DECRYPT); +} + +inline void aesDecrypt(const void *src, void *dst, uint32 len, mtpAuthKeyPtr authKey, const MTPint128 &msgKey) { + MTPint256 aesKey, aesIV; + authKey->prepareAES(msgKey, aesKey, aesIV, false); + + return aesDecrypt(src, dst, len, &aesKey, &aesIV); +} + +inline void aesDecryptLocal(const void *src, void *dst, uint32 len, mtpAuthKey *authKey, const void *key128) { + MTPint256 aesKey, aesIV; + authKey->prepareAES(*(const MTPint128*)key128, aesKey, aesIV, false); + + return aesDecrypt(src, dst, len, &aesKey, &aesIV); +} diff --git a/Telegram/SourceFiles/mtproto/mtpConnection.cpp b/Telegram/SourceFiles/mtproto/mtpConnection.cpp new file mode 100644 index 000000000..29fccb131 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpConnection.cpp @@ -0,0 +1,2941 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" + +#include + +namespace { + bool parsePQ(const std::string &pqStr, std::string &pStr, std::string &qStr) { + if (pqStr.length() > 8) return false; // more than 64 bit pq + + uint64 pq = 0, p, q; + const uchar *pqChars = (const uchar*)&pqStr[0]; + for (uint32 i = 0, l = pqStr.length(); i < l; ++i) { + pq <<= 8; + pq |= (uint64)pqChars[i]; + } + uint64 pqSqrt = (uint64)sqrtl((long double)pq), ySqr, y; + while (pqSqrt * pqSqrt > pq) --pqSqrt; + while (pqSqrt * pqSqrt < pq) ++pqSqrt; + for (ySqr = pqSqrt * pqSqrt - pq; ; ++pqSqrt, ySqr = pqSqrt * pqSqrt - pq) { + y = (uint64)sqrtl((long double)ySqr); + while (y * y > ySqr) --y; + while (y * y < ySqr) ++y; + if (!ySqr || y + pqSqrt >= pq) return false; + if (y * y == ySqr) { + p = pqSqrt + y; + q = (pqSqrt > y) ? (pqSqrt - y) : (y - pqSqrt); + break; + } + } + if (p > q) swap(p, q); + + pStr.resize(4); + uchar *pChars = (uchar*)&pStr[0]; + for (uint32 i = 0; i < 4; ++i) { + *(pChars + 3 - i) = (uchar)(p & 0xFF); + p >>= 8; + } + + qStr.resize(4); + uchar *qChars = (uchar*)&qStr[0]; + for (uint32 i = 0; i < 4; ++i) { + *(qChars + 3 - i) = (uchar)(q & 0xFF); + q >>= 8; + } + + return true; + } + + class _BigNumCounter { + public: + bool count(const void *power, const void *modul, uint32 g, void *gResult, const void *g_a, void *g_aResult) { + DEBUG_LOG(("BigNum Info: counting g_b = g ^ b % dh_prime and auth_key = g_a ^ b % dh_prime")); + uint32 g_be = qToBigEndian(g); + if ( + !BN_bin2bn((const uchar*)power, 64 * sizeof(uint32), &bnPower) || + !BN_bin2bn((const uchar*)modul, 64 * sizeof(uint32), &bnModul) || + !BN_bin2bn((const uchar*)&g_be, sizeof(uint32), &bn_g) || + !BN_bin2bn((const uchar*)g_a, 64 * sizeof(uint32), &bn_g_a) + ) { + ERR_load_crypto_strings(); + LOG(("BigNum Error: BN_bin2bn failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0))); + DEBUG_LOG(("BigNum Error: base %1, power %2, modul %3").arg(mb(&g_be, sizeof(uint32)).str()).arg(mb(power, 64 * sizeof(uint32)).str()).arg(mb(modul, 64 * sizeof(uint32)).str())); + return false; + } + + if (!BN_mod_exp(&bnResult, &bn_g, &bnPower, &bnModul, ctx)) { + ERR_load_crypto_strings(); + LOG(("BigNum Error: BN_mod_exp failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0))); + DEBUG_LOG(("BigNum Error: base %1, power %2, modul %3").arg(mb(&g_be, sizeof(uint32)).str()).arg(mb(power, 64 * sizeof(uint32)).str()).arg(mb(modul, 64 * sizeof(uint32)).str())); + return false; + } + + uint32 resultLen = BN_num_bytes(&bnResult); + if (resultLen != 64 * sizeof(uint32)) { + DEBUG_LOG(("BigNum Error: bad gResult len (%1)").arg(resultLen)); + return false; + } + resultLen = BN_bn2bin(&bnResult, (uchar*)gResult); + if (resultLen != 64 * sizeof(uint32)) { + DEBUG_LOG(("BigNum Error: bad gResult export len (%1)").arg(resultLen)); + return false; + } + + BN_add_word(&bnResult, 1); // check g_b < dh_prime - 1 + if (BN_cmp(&bnResult, &bnModul) >= 0) { + DEBUG_LOG(("BigNum Error: bad g_b >= dh_prime - 1")); + return false; + } + + if (!BN_mod_exp(&bnResult, &bn_g_a, &bnPower, &bnModul, ctx)) { + ERR_load_crypto_strings(); + LOG(("BigNum Error: BN_mod_exp failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0))); + DEBUG_LOG(("BigNum Error: base %1, power %2, modul %3").arg(mb(&g_be, sizeof(uint32)).str()).arg(mb(power, 64 * sizeof(uint32)).str()).arg(mb(modul, 64 * sizeof(uint32)).str())); + return false; + } + + resultLen = BN_num_bytes(&bnResult); + if (resultLen != 64 * sizeof(uint32)) { + DEBUG_LOG(("BigNum Error: bad g_aResult len (%1)").arg(resultLen)); + return false; + } + resultLen = BN_bn2bin(&bnResult, (uchar*)g_aResult); + if (resultLen != 64 * sizeof(uint32)) { + DEBUG_LOG(("BigNum Error: bad g_aResult export len (%1)").arg(resultLen)); + return false; + } + + BN_add_word(&bn_g_a, 1); // check g_a < dh_prime - 1 + if (BN_cmp(&bn_g_a, &bnModul) >= 0) { + DEBUG_LOG(("BigNum Error: bad g_a >= dh_prime - 1")); + return false; + } + + return true; + } + + _BigNumCounter() : ctx(BN_CTX_new()) { + BN_init(&bnPower); + BN_init(&bnModul); + BN_init(&bn_g); + BN_init(&bn_g_a); + BN_init(&bnResult); + } + ~_BigNumCounter() { + BN_CTX_free(ctx); + BN_clear_free(&bnPower); + BN_clear_free(&bnModul); + BN_clear_free(&bn_g); + BN_clear_free(&bn_g_a); + BN_clear_free(&bnResult); + } + + private: + BIGNUM bnPower, bnModul, bn_g, bn_g_a, bnResult; + BN_CTX *ctx; + }; + + // Miller-Rabin primality test + class _BigNumPrimeTest { + public: + + bool isPrimeAndGood(const void *pData, uint32 iterCount, int32 g) { + if (!memcmp(pData, "\xC7\x1C\xAE\xB9\xC6\xB1\xC9\x04\x8E\x6C\x52\x2F\x70\xF1\x3F\x73\x98\x0D\x40\x23\x8E\x3E\x21\xC1\x49\x34\xD0\x37\x56\x3D\x93\x0F\x48\x19\x8A\x0A\xA7\xC1\x40\x58\x22\x94\x93\xD2\x25\x30\xF4\xDB\xFA\x33\x6F\x6E\x0A\xC9\x25\x13\x95\x43\xAE\xD4\x4C\xCE\x7C\x37\x20\xFD\x51\xF6\x94\x58\x70\x5A\xC6\x8C\xD4\xFE\x6B\x6B\x13\xAB\xDC\x97\x46\x51\x29\x69\x32\x84\x54\xF1\x8F\xAF\x8C\x59\x5F\x64\x24\x77\xFE\x96\xBB\x2A\x94\x1D\x5B\xCD\x1D\x4A\xC8\xCC\x49\x88\x07\x08\xFA\x9B\x37\x8E\x3C\x4F\x3A\x90\x60\xBE\xE6\x7C\xF9\xA4\xA4\xA6\x95\x81\x10\x51\x90\x7E\x16\x27\x53\xB5\x6B\x0F\x6B\x41\x0D\xBA\x74\xD8\xA8\x4B\x2A\x14\xB3\x14\x4E\x0E\xF1\x28\x47\x54\xFD\x17\xED\x95\x0D\x59\x65\xB4\xB9\xDD\x46\x58\x2D\xB1\x17\x8D\x16\x9C\x6B\xC4\x65\xB0\xD6\xFF\x9C\xA3\x92\x8F\xEF\x5B\x9A\xE4\xE4\x18\xFC\x15\xE8\x3E\xBE\xA0\xF8\x7F\xA9\xFF\x5E\xED\x70\x05\x0D\xED\x28\x49\xF4\x7B\xF9\x59\xD9\x56\x85\x0C\xE9\x29\x85\x1F\x0D\x81\x15\xF6\x35\xB1\x05\xEE\x2E\x4E\x15\xD0\x4B\x24\x54\xBF\x6F\x4F\xAD\xF0\x34\xB1\x04\x03\x11\x9C\xD8\xE3\xB9\x2F\xCC\x5B", 256)) { + if (g == 3 || g == 4 || g == 5 || g == 7) { + return true; + } + } + if ( + !BN_bin2bn((const uchar*)pData, 64 * sizeof(uint32), &bnPrime) + ) { + ERR_load_crypto_strings(); + LOG(("BigNum PT Error: BN_bin2bn failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0))); + DEBUG_LOG(("BigNum PT Error: prime %1").arg(mb(pData, 64 * sizeof(uint32)).str())); + return false; + } + + int32 numBits = BN_num_bits(&bnPrime); + if (numBits != 2048) { + LOG(("BigNum PT Error: BN_bin2bn failed, bad dh_prime num bits: %1").arg(numBits)); + return false; + } + + if (BN_is_prime_ex(&bnPrime, MTPMillerRabinIterCount, ctx, NULL) == 0) { + return false; + } + + BN_sub_word(&bnPrime, 1); // (p - 1) / 2 + BN_div_word(&bnPrime, 2); + + if (BN_is_prime_ex(&bnPrime, MTPMillerRabinIterCount, ctx, NULL) == 0) { + return false; + } + switch (g) { + case 2: { + int32 mod8 = BN_mod_word(&bnPrime, 8); + if (mod8 != 7) { + LOG(("BigNum PT Error: bad g value: %1, mod8: %2").arg(g).arg(mod8)); + return false; + } + } break; + case 3: { + int32 mod3 = BN_mod_word(&bnPrime, 3); + if (mod3 != 2) { + LOG(("BigNum PT Error: bad g value: %1, mod3: %2").arg(g).arg(mod3)); + return false; + } + } break; + case 4: break; + case 5: { + int32 mod5 = BN_mod_word(&bnPrime, 5); + if (mod5 != 1 && mod5 != 4) { + LOG(("BigNum PT Error: bad g value: %1, mod5: %2").arg(g).arg(mod5)); + return false; + } + } break; + case 6: { + int32 mod24 = BN_mod_word(&bnPrime, 24); + if (mod24 != 19 && mod24 != 23) { + LOG(("BigNum PT Error: bad g value: %1, mod24: %2").arg(g).arg(mod24)); + return false; + } + } break; + case 7: { + int32 mod7 = BN_mod_word(&bnPrime, 7); + if (mod7 != 3 && mod7 != 5 && mod7 != 6) { + LOG(("BigNum PT Error: bad g value: %1, mod7: %2").arg(g).arg(mod7)); + return false; + } + } break; + default: + LOG(("BigNum PT Error: bad g value: %1").arg(g)); + return false; + break; + } + + return true; + } + + _BigNumPrimeTest() : ctx(BN_CTX_new()) { + BN_init(&bnPrime); + } + ~_BigNumPrimeTest() { + BN_CTX_free(ctx); + BN_clear_free(&bnPrime); + } + + private: + BIGNUM bnPrime; + BN_CTX *ctx; + }; + + typedef QMap PublicRSAKeys; + PublicRSAKeys gPublicRSA; + + MTProtoConnection gMainConnection; + + bool gConfigInited = false; + void initRSAConfig() { + if (gConfigInited) return; + gConfigInited = true; + + DEBUG_LOG(("MTP Info: MTP config init")); + + // read all public keys + uint32 keysCnt; + const char **keys = cPublicRSAKeys(keysCnt); + for (uint32 i = 0; i < keysCnt; ++i) { + mtpPublicRSA key(keys[i]); + if (key.key()) { + gPublicRSA.insert(key.fingerPrint(), key); + } else { + LOG(("MTP Error: could not read this public RSA key:")); + LOG((keys[i])); + } + } + DEBUG_LOG(("MTP Info: read %1 public RSA keys").arg(gPublicRSA.size())); + } +} + +MTPThread::MTPThread(QObject *parent) : QThread(parent) { + static uint32 gThreadId = 0; + threadId = ++gThreadId; +} + +uint32 MTPThread::getThreadId() const { + return threadId; +} + +MTProtoConnection::MTProtoConnection() : thread(0), data(0) { +} + +int32 MTProtoConnection::start(MTPSessionData *sessionData, int32 dc) { + initRSAConfig(); + + if (thread) { + DEBUG_LOG(("MTP Info: MTP start called for already working connection")); + return dc; + } + + thread = new MTPThread(QApplication::instance()); + data = new MTProtoConnectionPrivate(thread, this, sessionData, dc); + + dc = data->getDC(); + if (!dc) { + return 0; + } + thread->start(); + return dc; +} + +void MTProtoConnection::restart() { + emit data->needToRestart(); +} + +void MTProtoConnection::stop() { + thread->quit(); +} + +void MTProtoConnection::stopped() { + if (thread) thread->deleteLater(); + if (data) data->deleteLater(); + thread = 0; + data = 0; +} + +int32 MTProtoConnection::state() const { + if (!data) return Disconnected; + + return data->getState(); +} + +QString MTProtoConnection::transport() const { + if (!data) return QString(); + + return data->transport(); +} + +namespace { + mtpBuffer _handleHttpResponse(QNetworkReply *reply) { + QByteArray response = reply->readAll(); + TCP_LOG(("HTTP Info: read %1 bytes %2").arg(response.size()).arg(mb(response.constData(), response.size()).str())); + + if (response.isEmpty()) return mtpBuffer(); + + if (response.size() & 0x03 || response.size() < 8) { + LOG(("HTTP Error: bad response size %1").arg(response.size())); + return mtpBuffer(1, -500); + } + + mtpBuffer data(response.size() >> 2); + memcpy(data.data(), response.constData(), response.size()); + + return data; + } + + bool _handleHttpError(QNetworkReply *reply) { // returnes "maybe bad key" + bool mayBeBadKey = false; + + QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + if (statusCode.isValid()) { + int status = statusCode.toInt(); + mayBeBadKey = (status == 404); + if (status == 429) { + LOG(("Protocol Error: 429 flood code returned!")); + } + } + + switch (reply->error()) { + case QNetworkReply::ConnectionRefusedError: LOG(("HTTP Error: connection refused - %1").arg(reply->errorString())); break; + case QNetworkReply::RemoteHostClosedError: LOG(("HTTP Error: remote host closed - %1").arg(reply->errorString())); break; + case QNetworkReply::HostNotFoundError: LOG(("HTTP Error: host not found - %2").arg(reply->error()).arg(reply->errorString())); break; + case QNetworkReply::TimeoutError: LOG(("HTTP Error: timeout - %2").arg(reply->error()).arg(reply->errorString())); break; + case QNetworkReply::OperationCanceledError: LOG(("HTTP Error: cancelled - %2").arg(reply->error()).arg(reply->errorString())); break; + case QNetworkReply::SslHandshakeFailedError: + case QNetworkReply::TemporaryNetworkFailureError: + case QNetworkReply::NetworkSessionFailedError: + case QNetworkReply::BackgroundRequestNotAllowedError: + case QNetworkReply::UnknownNetworkError: LOG(("HTTP Error: network error %1 - %2").arg(reply->error()).arg(reply->errorString())); break; + + // proxy errors (101-199): + case QNetworkReply::ProxyConnectionRefusedError: + case QNetworkReply::ProxyConnectionClosedError: + case QNetworkReply::ProxyNotFoundError: + case QNetworkReply::ProxyTimeoutError: + case QNetworkReply::ProxyAuthenticationRequiredError: + case QNetworkReply::UnknownProxyError:LOG(("HTTP Error: proxy error %1 - %2").arg(reply->error()).arg(reply->errorString())); break; + + // content errors (201-299): + case QNetworkReply::ContentAccessDenied: + case QNetworkReply::ContentOperationNotPermittedError: + case QNetworkReply::ContentNotFoundError: + case QNetworkReply::AuthenticationRequiredError: + case QNetworkReply::ContentReSendError: + case QNetworkReply::UnknownContentError: LOG(("HTTP Error: content error %1 - %2").arg(reply->error()).arg(reply->errorString())); break; + + // protocol errors + case QNetworkReply::ProtocolUnknownError: + case QNetworkReply::ProtocolInvalidOperationError: + case QNetworkReply::ProtocolFailure: LOG(("HTTP Error: protocol error %1 - %2").arg(reply->error()).arg(reply->errorString())); break; + }; + TCP_LOG(("HTTP Error %1, restarting! - %2").arg(reply->error()).arg(reply->errorString())); + + return mayBeBadKey; + } + + mtpBuffer _handleTcpResponse(mtpPrime *packet, uint32 size) { + if (size < 4 || size * sizeof(mtpPrime) > MTPPacketSizeMax) { + LOG(("TCP Error: bad packet size %1").arg(size * sizeof(mtpPrime))); + return mtpBuffer(1, -500); + } + if (packet[0] != size * sizeof(mtpPrime)) { + LOG(("TCP Error: bad packet header")); + TCP_LOG(("TCP Error: bad packet header, packet: %1").arg(mb(packet, size * sizeof(mtpPrime)).str())); + return mtpBuffer(1, -500); + } + if (packet[size - 1] != hashCrc32(packet, (size - 1) * sizeof(mtpPrime))) { + LOG(("TCP Error: bad packet checksum")); + TCP_LOG(("TCP Error: bad packet checksum, packet: %1").arg(mb(packet, size * sizeof(mtpPrime)).str())); + return mtpBuffer(1, -500); + } + TCP_LOG(("TCP Info: packet received, num = %1, size = %2").arg(packet[1]).arg(size * sizeof(mtpPrime))); + if (size == 4) { + if (packet[2] == -429) { + LOG(("Protocol Error: -429 flood code returned!")); + } else { + LOG(("TCP Error: error packet received, code = %1").arg(packet[2])); + } + return mtpBuffer(1, packet[2]); + } + + mtpBuffer data(size - 3); + memcpy(data.data(), packet + 2, (size - 3) * sizeof(mtpPrime)); + + return data; + } + + void _handleTcpError(QAbstractSocket::SocketError e, QTcpSocket &sock) { + switch (e) { + case QAbstractSocket::ConnectionRefusedError: + LOG(("TCP Error: socket connection refused - %1").arg(sock.errorString())); + break; + + case QAbstractSocket::RemoteHostClosedError: + TCP_LOG(("TCP Info: remote host closed socket connection - %1").arg(sock.errorString())); + break; + + case QAbstractSocket::HostNotFoundError: + LOG(("TCP Error: host not found - %1").arg(sock.errorString())); + break; + + case QAbstractSocket::SocketTimeoutError: + LOG(("TCP Error: socket timeout - %1").arg(sock.errorString())); + break; + + case QAbstractSocket::NetworkError: + LOG(("TCP Error: network - %1").arg(sock.errorString())); + break; + + case QAbstractSocket::ProxyAuthenticationRequiredError: + case QAbstractSocket::ProxyConnectionRefusedError: + case QAbstractSocket::ProxyConnectionClosedError: + case QAbstractSocket::ProxyConnectionTimeoutError: + case QAbstractSocket::ProxyNotFoundError: + case QAbstractSocket::ProxyProtocolError: + LOG(("TCP Error: proxy (%1) - %2").arg(e).arg(sock.errorString())); + break; + + default: + LOG(("TCP Error: other (%1) - %2").arg(e).arg(sock.errorString())); + break; + } + + TCP_LOG(("TCP Error %1, restarting! - %2").arg(e).arg(sock.errorString())); + } + + mtpBuffer _preparePQFake(const MTPint128 &nonce) { + MTPReq_pq req_pq(nonce); + mtpBuffer buffer; + uint32 requestSize = req_pq.size() >> 2; + + buffer.resize(0); + buffer.reserve(8 + requestSize); + buffer.push_back(0); // tcp packet len + buffer.push_back(0); // tcp packet num + buffer.push_back(0); + buffer.push_back(0); + buffer.push_back(0); + buffer.push_back(unixtime()); + buffer.push_back(requestSize * 4); + req_pq.write(buffer); + buffer.push_back(0); // tcp crc32 hash + + return buffer; + } + + MTPResPQ _readPQFakeReply(const mtpBuffer &buffer) { + const mtpPrime *answer(buffer.constData()); + uint32 len = buffer.size(); + if (len < 5) { + LOG(("Fake PQ Error: bad request answer, len = %1").arg(len * sizeof(mtpPrime))); + DEBUG_LOG(("Fake PQ Error: answer bytes %1").arg(mb(answer, len * sizeof(mtpPrime)).str())); + throw Exception("bad pq reply"); + } + if (answer[0] != 0 || answer[1] != 0 || (((uint32)answer[2]) & 0x03) != 1/* || (unixtime() - answer[3] > 300) || (answer[3] - unixtime() > 60)*/) { // didnt sync time yet + LOG(("Fake PQ Error: bad request answer start (%1 %2 %3)").arg(answer[0]).arg(answer[1]).arg(answer[2])); + DEBUG_LOG(("Fake PQ Error: answer bytes %1").arg(mb(answer, len * sizeof(mtpPrime)).str())); + throw Exception("bad pq reply"); + } + uint32 answerLen = (uint32)answer[4]; + if (answerLen != (len - 5) * sizeof(mtpPrime)) { + LOG(("Fake PQ Error: bad request answer %1 <> %2").arg(answerLen).arg((len - 5) * sizeof(mtpPrime))); + DEBUG_LOG(("Fake PQ Error: answer bytes %1").arg(mb(answer, len * sizeof(mtpPrime)).str())); + throw Exception("bad pq reply"); + } + const mtpPrime *from(answer + 5), *end(from + len - 5); + MTPResPQ response; + response.read(from, end); + return response; + } + +} + +MTPabstractTcpConnection::MTPabstractTcpConnection() : +currentPos((char*)shortBuffer), packetRead(0), packetLeft(0), readingToShort(true), packetNum(0) { +} + +void MTPabstractTcpConnection::socketRead() { + if (sock.state() != QAbstractSocket::ConnectedState) { + LOG(("MTP error: socket not connected in socketRead(), state: %1").arg(sock.state())); + emit error(); + return; + } + + do { + char *readTo = currentPos; + uint32 toRead = packetLeft ? packetLeft : (readingToShort ? (MTPShortBufferSize * sizeof(mtpPrime)-packetRead) : 4); + if (readingToShort) { + if (currentPos + toRead > ((char*)shortBuffer) + MTPShortBufferSize * sizeof(mtpPrime)) { + longBuffer.resize(((packetRead + toRead) >> 2) + 1); + memcpy(&longBuffer[0], shortBuffer, packetRead); + readTo = ((char*)&longBuffer[0]) + packetRead; + } + } else { + if (longBuffer.size() * sizeof(mtpPrime) < packetRead + toRead) { + longBuffer.resize(((packetRead + toRead) >> 2) + 1); + readTo = ((char*)&longBuffer[0]) + packetRead; + } + } + int32 bytes = (int32)sock.read(readTo, toRead); + if (bytes > 0) { + TCP_LOG(("TCP Info: read %1 bytes %2").arg(bytes).arg(mb(readTo, bytes).str())); + + packetRead += bytes; + currentPos += bytes; + if (packetLeft) { + packetLeft -= bytes; + if (!packetLeft) { + socketPacket((mtpPrime*)(currentPos - packetRead), packetRead >> 2); + currentPos = (char*)shortBuffer; + packetRead = packetLeft = 0; + readingToShort = true; + } else { + TCP_LOG(("TCP Info: not enough %1 for packet! read %2").arg(packetLeft).arg(packetRead)); + emit receivedSome(); + } + } else { + bool move = false; + while (packetRead >= 4) { + uint32 packetSize = *(uint32*)(currentPos - packetRead); + if (packetSize < 16 || packetSize > MTPPacketSizeMax || (packetSize & 0x03)) { + LOG(("TCP Error: packet size = %1").arg(packetSize)); + emit error(); + return; + } + if (packetRead >= packetSize) { + socketPacket((mtpPrime*)(currentPos - packetRead), packetSize >> 2); + packetRead -= packetSize; + packetLeft = 0; + move = true; + } else { + packetLeft = packetSize - packetRead; + TCP_LOG(("TCP Info: not enough %1 for packet! size %2 read %3").arg(packetLeft).arg(packetSize).arg(packetRead)); + emit receivedSome(); + break; + } + } + if (move) { + if (!packetRead) { + currentPos = (char*)shortBuffer; + readingToShort = true; + } else if (!readingToShort && packetRead < MTPShortBufferSize * sizeof(mtpPrime)) { + memcpy(shortBuffer, currentPos - packetRead, packetRead); + currentPos = (char*)shortBuffer; + readingToShort = true; + } + } + } + } else if (bytes < 0) { + LOG(("TCP Error: socket read return -1")); + emit error(); + return; + } else { + TCP_LOG(("TCP Info: no bytes read, but bytes available was true..")); + break; + } + } while (sock.state() == QAbstractSocket::ConnectedState && sock.bytesAvailable()); +} + +MTPautoConnection::MTPautoConnection(QThread *thread) : status(WaitingBoth), +tcpNonce(MTP::nonce()), httpNonce(MTP::nonce()) { + moveToThread(thread); + + manager.moveToThread(thread); + manager.setProxy(QNetworkProxy(QNetworkProxy::DefaultProxy)); + + httpStartTimer.moveToThread(thread); + httpStartTimer.setSingleShot(true); + connect(&httpStartTimer, SIGNAL(timeout()), this, SLOT(onHttpStart())); + + sock.moveToThread(thread); + sock.setProxy(QNetworkProxy(QNetworkProxy::NoProxy)); + connect(&sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); +// connect(&sock, SIGNAL(connected()), this, SIGNAL(connected())); +// connect(&sock, SIGNAL(disconnected()), this, SIGNAL(disconnected())); + connect(&sock, SIGNAL(connected()), this, SLOT(onSocketConnected())); + connect(&sock, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); +} + +void MTPautoConnection::onHttpStart() { + if (status == HttpReady) { + DEBUG_LOG(("Connection Info: Http-transport chosen by timer")); + status = UsingHttp; + sock.disconnect(); + emit connected(); + } +} + +void MTPautoConnection::onSocketConnected() { + if (status == HttpReady || status == WaitingBoth || status == WaitingTcp) { + mtpBuffer buffer(_preparePQFake(tcpNonce)); + + DEBUG_LOG(("Connection Info: sending fake req_pq through tcp transport")); + + tcpSend(buffer); + } else if (status == WaitingHttp || status == UsingHttp) { + sock.disconnect(); + } +} + +void MTPautoConnection::onSocketDisconnected() { + if (status == WaitingBoth) { + status = WaitingHttp; + } else if (status == WaitingTcp || status == UsingTcp) { + emit disconnected(); + } else if (status == HttpReady) { + DEBUG_LOG(("Connection Info: Http-transport chosen by socket disconnect")); + status = UsingHttp; + emit connected(); + } +} + +void MTPautoConnection::sendData(mtpBuffer &buffer) { + if (buffer.size() < 3) { + LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime))); + TCP_LOG(("TCP Error: bad packet %1").arg(mb(&buffer[0], buffer.size() * sizeof(mtpPrime)).str())); + emit error(); + return; + } + + if (status == UsingTcp) { + tcpSend(buffer); + } else { + httpSend(buffer); + } +} + +void MTPautoConnection::tcpSend(mtpBuffer &buffer) { + uint32 size = buffer.size(), len = size * 4; + + buffer[0] = len; + buffer[1] = packetNum++; + buffer[size - 1] = hashCrc32(&buffer[0], len - 4); + TCP_LOG(("TCP Info: write %1 packet %2 bytes %3").arg(packetNum).arg(len).arg(mb(&buffer[0], len).str())); + + sock.write((const char*)&buffer[0], len); +} + +void MTPautoConnection::httpSend(mtpBuffer &buffer) { + int32 requestSize = (buffer.size() - 3) * sizeof(mtpPrime); + + QNetworkRequest request(address); + request.setHeader(QNetworkRequest::ContentLengthHeader, QVariant(requestSize)); + + TCP_LOG(("HTTP Info: sending %1 len request %2").arg(requestSize).arg(mb(&buffer[2], requestSize).str())); + requests.insert(manager.post(request, QByteArray((const char*)(&buffer[2]), requestSize))); +} + +void MTPautoConnection::disconnectFromServer() { + Requests copy = requests; + requests.clear(); + for (Requests::const_iterator i = copy.cbegin(), e = copy.cend(); i != e; ++i) { + (*i)->abort(); + (*i)->deleteLater(); + } + + disconnect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*))); + + address = QUrl(); + + disconnect(&sock, SIGNAL(readyRead()), 0, 0); + sock.close(); + + httpStartTimer.stop(); + status = WaitingBoth; +} + +void MTPautoConnection::connectToServer(const QString &addr, int32 port) { + address = QUrl(qsl("http://%1:%2/api").arg(addr).arg(80));//not port - always 80 port for http transport + connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*))); + + mtpBuffer buffer(_preparePQFake(httpNonce)); + + DEBUG_LOG(("Connection Info: sending fake req_pq through http transport")); + + httpSend(buffer); + + sock.connectToHost(QHostAddress(addr), port); + connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead())); +} + +bool MTPautoConnection::isConnected() { + return !address.isEmpty(); +} + +void MTPautoConnection::requestFinished(QNetworkReply *reply) { + reply->deleteLater(); + if (reply->error() == QNetworkReply::NoError) { + requests.remove(reply); + + mtpBuffer data = _handleHttpResponse(reply); + if (data.size() == 1) { + if (status == WaitingBoth) { + status = WaitingTcp; + } else { + emit error(); + } + } else if (!data.isEmpty()) { + if (status == UsingHttp) { + receivedQueue.push_back(data); + emit receivedData(); + } else if (status == WaitingBoth || status == WaitingHttp) { + try { + MTPResPQ res_pq = _readPQFakeReply(data); + const MTPDresPQ &res_pq_data(res_pq.c_resPQ()); + if (res_pq_data.vnonce == httpNonce) { + if (status == WaitingBoth) { + status = HttpReady; + httpStartTimer.start(MTPTcpConnectionWaitTimeout); + } else { + DEBUG_LOG(("Connection Info: Http-transport chosen by pq-response, awaited")); + status = UsingHttp; + sock.disconnect(); + emit connected(); + } + } + } catch (Exception &e) { + if (status == WaitingBoth) { + status = WaitingTcp; + } else { + emit error(); + } + } + } else if (status == UsingTcp) { + DEBUG_LOG(("Connection Info: already using tcp, ignoring http response")); + } + } + } else { + if (!requests.remove(reply)) { + return; + } + + bool mayBeBadKey = _handleHttpError(reply); + if (status == WaitingBoth) { + status = WaitingTcp; + } else if (status == WaitingHttp || status == UsingHttp) { + emit error(mayBeBadKey); + } else { + LOG(("Strange Http Error: status %1").arg(status)); + } + } +} + +void MTPautoConnection::socketPacket(mtpPrime *packet, uint32 size) { + mtpBuffer data = _handleTcpResponse(packet, size); + if (data.size() == 1) { + if (status == WaitingBoth) { + status = WaitingHttp; + sock.disconnect(); + } else if (status == HttpReady) { + DEBUG_LOG(("Connection Info: Http-transport chosen by bad tcp response, ready")); + status = UsingHttp; + sock.disconnect(); + emit connected(); + } else if (status == WaitingTcp || status == UsingTcp) { + emit error(data[0] == -404); + } else { + LOG(("Strange Tcp Error; status %1").arg(status)); + } + } else if (status == UsingTcp) { + receivedQueue.push_back(data); + emit receivedData(); + } else if (status == WaitingBoth || status == WaitingTcp || status == HttpReady) { + try { + MTPResPQ res_pq = _readPQFakeReply(data); + const MTPDresPQ &res_pq_data(res_pq.c_resPQ()); + if (res_pq_data.vnonce == tcpNonce) { + DEBUG_LOG(("Connection Info: Tcp-transport chosen by pq-response")); + status = UsingTcp; + emit connected(); + } + } catch (Exception &e) { + if (status == WaitingBoth) { + status = WaitingHttp; + sock.disconnect(); + } else if (status == HttpReady) { + DEBUG_LOG(("Connection Info: Http-transport chosen by bad tcp response, awaited")); + status = UsingHttp; + sock.disconnect(); + emit connected(); + } else { + emit error(); + } + } + } +} + +bool MTPautoConnection::needHttpWait() { + return (status == UsingHttp) ? requests.isEmpty() : false; +} + +int32 MTPautoConnection::debugState() const { + return (status == UsingHttp) ? -1 : (UsingTcp ? sock.state() : -777); +} + +QString MTPautoConnection::transport() const { + if (status == UsingTcp) { + return qsl("TCP"); + } else if (status == UsingHttp) { + return qsl("HTTP"); + } else { + return QString(); + } +} + +void MTPautoConnection::socketError(QAbstractSocket::SocketError e) { + _handleTcpError(e, sock); + if (status == WaitingBoth) { + status = WaitingHttp; + } else if (status == HttpReady) { + DEBUG_LOG(("Connection Info: Http-transport chosen by tcp error, ready")); + status = UsingHttp; + emit connected(); + } else if (status == WaitingTcp || status == UsingTcp) { + emit error(); + } else { + LOG(("Strange Tcp Error: status %1").arg(status)); + } +} + +MTPtcpConnection::MTPtcpConnection(QThread *thread) { + moveToThread(thread); + sock.moveToThread(thread); + App::setProxySettings(sock); + connect(&sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); + connect(&sock, SIGNAL(connected()), this, SIGNAL(connected())); + connect(&sock, SIGNAL(disconnected()), this, SIGNAL(disconnected())); +} + +void MTPtcpConnection::sendData(mtpBuffer &buffer) { + if (buffer.size() < 3) { + LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime))); + TCP_LOG(("TCP Error: bad packet %1").arg(mb(&buffer[0], buffer.size() * sizeof(mtpPrime)).str())); + emit error(); + return; + } + + uint32 size = buffer.size(), len = size * 4; + + buffer[0] = len; + buffer[1] = packetNum++; + buffer[size - 1] = hashCrc32(&buffer[0], len - 4); + TCP_LOG(("TCP Info: write %1 packet %2 bytes %3").arg(packetNum).arg(len).arg(mb(&buffer[0], len).str())); + + sock.write((const char*)&buffer[0], len); +} + +void MTPtcpConnection::disconnectFromServer() { + disconnect(&sock, SIGNAL(readyRead()), 0, 0); + sock.close(); +} + +void MTPtcpConnection::connectToServer(const QString &addr, int32 port) { + sock.connectToHost(QHostAddress(addr), port); + connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead())); +} + +void MTPtcpConnection::socketPacket(mtpPrime *packet, uint32 size) { + mtpBuffer data = _handleTcpResponse(packet, size); + if (data.size() == 1) { + emit error(data[0] == -404); + } + + receivedQueue.push_back(data); + emit receivedData(); +} + +bool MTPtcpConnection::isConnected() { + return sock.state() == QAbstractSocket::ConnectedState; +} + +int32 MTPtcpConnection::debugState() const { + return sock.state(); +} + +QString MTPtcpConnection::transport() const { + return qsl("TCP"); +} + +void MTPtcpConnection::socketError(QAbstractSocket::SocketError e) { + _handleTcpError(e, sock); + emit error(); +} + +MTPhttpConnection::MTPhttpConnection(QThread *thread) { + moveToThread(thread); + manager.moveToThread(thread); + App::setProxySettings(manager); +} + +void MTPhttpConnection::sendData(mtpBuffer &buffer) { + if (buffer.size() < 3) { + LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime))); + TCP_LOG(("TCP Error: bad packet %1").arg(mb(&buffer[0], buffer.size() * sizeof(mtpPrime)).str())); + emit error(); + return; + } + + int32 requestSize = (buffer.size() - 3) * sizeof(mtpPrime); + + QNetworkRequest request(address); + request.setHeader(QNetworkRequest::ContentLengthHeader, QVariant(requestSize)); + + TCP_LOG(("HTTP Info: sending %1 len request %2").arg(requestSize).arg(mb(&buffer[2], requestSize).str())); + requests.insert(manager.post(request, QByteArray((const char*)(&buffer[2]), requestSize))); +} + +void MTPhttpConnection::disconnectFromServer() { + Requests copy = requests; + requests.clear(); + for (Requests::const_iterator i = copy.cbegin(), e = copy.cend(); i != e; ++i) { + (*i)->abort(); + (*i)->deleteLater(); + } + + disconnect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*))); + + address = QUrl(); +} + +void MTPhttpConnection::connectToServer(const QString &addr, int32 p) { + address = QUrl(qsl("http://%1:%2/api").arg(addr).arg(80));//not p - always 80 port for http transport + connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*))); + emit connected(); +} + +bool MTPhttpConnection::isConnected() { + return !address.isEmpty(); +} + +void MTPhttpConnection::requestFinished(QNetworkReply *reply) { + reply->deleteLater(); + if (reply->error() == QNetworkReply::NoError) { + requests.remove(reply); + + mtpBuffer data = _handleHttpResponse(reply); + if (data.size() == 1) { + emit error(); + } else if (!data.isEmpty()) { + receivedQueue.push_back(data); + emit receivedData(); + } + } else { + if (!requests.remove(reply)) { + return; + } + + bool mayBeBadKey = _handleHttpError(reply); + + emit error(mayBeBadKey); + } +} + +bool MTPhttpConnection::needHttpWait() { + return requests.isEmpty(); +} + +int32 MTPhttpConnection::debugState() const { + return -1; +} + +QString MTPhttpConnection::transport() const { + return qsl("HTTP"); +} + +void MTProtoConnectionPrivate::createConn() { + if (conn) { + conn->deleteLater(); + } + if (cConnectionType() == dbictAuto) { + conn = new MTPautoConnection(thread()); + } else if (cConnectionType() == dbictTcpProxy) { + conn = new MTPtcpConnection(thread()); + } else { + conn = new MTPhttpConnection(thread()); + } + connect(conn, SIGNAL(error(bool)), this, SLOT(onError(bool))); + connect(conn, SIGNAL(receivedSome()), this, SLOT(onReceivedSome())); + firstSentAt = 0; + if (oldConnection) { + oldConnection = false; + DEBUG_LOG(("This connection marked as not old!")); + } + oldConnectionTimer.start(MTPConnectionOldTimeout); +} + +MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConnection *owner, MTPSessionData *data, uint32 _dc) + : QObject(0) + , dc(_dc) + , conn(0) + , retryTimeout(1) + , receiveDelay(MinReceiveDelay) + , firstSentAt(-1) + , oldConnection(true) + , _state(MTProtoConnection::Disconnected) + , _owner(owner) + , sessionData(data) + , keyId(0) + , pingId(0) + , toSendPingId(0) + , pingMsgId(0) + , restarted(false) + , ackRequest(MTP_msgs_ack(MTPVector())) + , myKeyLock(false) + , authKeyData(0) { + + ackRequestData = &ackRequest._msgs_ack().vmsg_ids._vector().v; + + oldConnectionTimer.moveToThread(thread); + connCheckTimer.moveToThread(thread); + retryTimer.moveToThread(thread); + pinger.moveToThread(thread); + moveToThread(thread); + +// createConn(); + + if (!dc) { + const mtpDcOptions &gDcOptions(mtpDCOptions()); + if (!gDcOptions.size()) { + LOG(("MTP Error: connect failed, no DCs")); + dc = 0; + return; + } + dc = gDcOptions.cbegin().value().id; + DEBUG_LOG(("MTP Info: searching for any DC, %1 selected..").arg(dc)); + } + + connect(thread, SIGNAL(started()), this, SLOT(socketStart())); + connect(thread, SIGNAL(finished()), this, SLOT(doFinish())); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + + connect(&retryTimer, SIGNAL(timeout()), this, SLOT(retryByTimer())); + connect(&connCheckTimer, SIGNAL(timeout()), this, SLOT(onBadConnection())); + connect(&oldConnectionTimer, SIGNAL(timeout()), this, SLOT(onOldConnection())); + connect(sessionData->owner(), SIGNAL(authKeyCreated()), this, SLOT(updateAuthKey())); + + connect(this, SIGNAL(needToRestart()), this, SLOT(restartNow())); + connect(this, SIGNAL(needToReceive()), sessionData->owner(), SLOT(tryToReceive())); + connect(this, SIGNAL(stateChanged(qint32)), sessionData->owner(), SLOT(onConnectionStateChange(qint32))); + connect(sessionData->owner(), SIGNAL(needToSend()), this, SLOT(tryToSend())); + + oldConnectionTimer.setSingleShot(true); + connCheckTimer.setSingleShot(true); + retryTimer.setSingleShot(true); +} + +void MTProtoConnectionPrivate::onConfigLoaded() { + socketStart(true); +} + +int32 MTProtoConnectionPrivate::getDC() const { + return dc; +} + +int32 MTProtoConnectionPrivate::getState() const { + QReadLocker lock(&stateMutex); + int32 result = _state; + if (_state < 0) { + if (retryTimer.isActive()) { + result = int32(getms() - retryWillFinish); + if (result >= 0) { + result = -1; + } + } + } + return result; +} + +QString MTProtoConnectionPrivate::transport() const { + if (!conn || _state < 0) { + return QString(); + } + return conn->transport(); +} + +bool MTProtoConnectionPrivate::setState(int32 state, int32 ifState) { + if (ifState != MTProtoConnection::UpdateAlways) { + QReadLocker lock(&stateMutex); + if (_state != ifState) return false; + } + QWriteLocker lock(&stateMutex); + if (_state == state) return false; + _state = state; + if (state < 0) { + retryTimeout = -state; + retryTimer.start(retryTimeout); + retryWillFinish = getms() + retryTimeout; + } + emit stateChanged(state); + return true; +} + +mtpMsgId MTProtoConnectionPrivate::prepareToSend(mtpRequest &request) { + if (request->size() < 9) return 0; + mtpMsgId msgId = *(mtpMsgId*)(request->constData() + 4); + if (msgId) { // resending this request + QWriteLocker locker(sessionData->toResendMutex()); + mtpRequestIdsMap &toResend(sessionData->toResendMap()); + mtpRequestIdsMap::iterator i = toResend.find(msgId); + if (i != toResend.cend()) { + toResend.erase(i); + } + } else { + msgId = *(mtpMsgId*)(request->data() + 4) = msgid(); + *(request->data() + 6) = sessionData->nextRequestSeqNumber(mtpRequestData::needAck(request)); + } + return msgId; +} + +void MTProtoConnectionPrivate::tryToSend() { + if (!conn) return; + + bool prependOnly = false, havePrepend = false; + mtpRequest prepend; + if (toSendPingId) { +/* + MTPPing_delay_disconnect ping; + ping.ping_id = MTP_long(toSendPingId); + ping.disconnect_delay.v = 45; + + DEBUG_LOG(("MTP Info: sending ping_delay_disconnect, delay: %1s, ping_id: %2").arg(ping.disconnect_delay.v).arg(ping.ping_id.v)); +/**/ + MTPPing ping(MTPping(MTP_long(toSendPingId))); + + prependOnly = (getState() != MTProtoConnection::Connected); + DEBUG_LOG(("MTP Info: sending ping, ping_id: %1, prepend_only: %2").arg(ping.vping_id.v).arg(prependOnly ? "[TRUE]" : "[FALSE]")); + + uint32 pingSize = ping.size() >> 2; // copy from MTProtoSession::send + prepend = mtpRequestData::prepare(pingSize); + ping.write(*prepend); + + prepend->msDate = getms(); // > 0 - can send without container + prepend->requestId = 0; // dont add to haveSent / wereAcked maps + havePrepend = true; + + pingId = toSendPingId; + toSendPingId = 0; + } else { + int32 st = getState(); + DEBUG_LOG(("MTP Info: trying to send after ping, state: %1").arg(st)); + if (st != MTProtoConnection::Connected) { + return; // just do nothing, if is not connected yet + } + } + + bool needAnyResponse = false; + mtpRequest toSendRequest; + { + QWriteLocker locker1(sessionData->toSendMutex()); + + mtpPreRequestMap toSendDummy, &toSend(prependOnly ? toSendDummy : sessionData->toSendMap()); + if (prependOnly) locker1.unlock(); + + uint32 toSendCount = toSend.size(); + if (havePrepend) ++toSendCount; + + if (!toSendCount) return; // nothing to send + + mtpRequest first = havePrepend ? prepend : toSend.cbegin().value(); + if (toSendCount == 1 && first->msDate > 0) { // if can send without container + toSendRequest = first; + if (!prependOnly) { + toSend.clear(); + locker1.unlock(); + } + + mtpMsgId msgId = prepareToSend(toSendRequest); + if (havePrepend) pingMsgId = msgId; + + if (toSendRequest->requestId) { + if (mtpRequestData::needAck(toSendRequest)) { + toSendRequest->msDate = mtpRequestData::isStateRequest(toSendRequest) ? 0 : getms(); + + QWriteLocker locker2(sessionData->haveSentMutex()); + sessionData->haveSentMap().insert(msgId, toSendRequest); + + needAnyResponse = true; + } else { + QWriteLocker locker3(sessionData->wereAckedMutex()); + sessionData->wereAckedMap().insert(msgId, toSendRequest->requestId); + } + } + } else { // send in container + uint32 containerSize = 1 + 1, idsWrapSize = (toSendCount << 1); // cons + vector size, idsWrapSize - size of "request-like" wrap for msgId vector + if (havePrepend) containerSize += mtpRequestData::messageSize(prepend); + for (mtpPreRequestMap::iterator i = toSend.begin(), e = toSend.end(); i != e; ++i) { + containerSize += mtpRequestData::messageSize(i.value()); + } + toSendRequest = mtpRequestData::prepare(containerSize); // prepare container + toSendRequest->push_back(mtpc_msg_container); + toSendRequest->push_back(toSendCount); + + QWriteLocker locker2(sessionData->haveSentMutex()); + mtpRequestMap &haveSent(sessionData->haveSentMap()); + + QWriteLocker locker3(sessionData->wereAckedMutex()); + mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); + + mtpRequest haveSentIdsWrap(mtpRequestData::prepare(idsWrapSize)); // prepare "request-like" wrap for msgId vector + haveSentIdsWrap->requestId = 0; + haveSentIdsWrap->resize(haveSentIdsWrap->size() + idsWrapSize); + mtpMsgId *haveSentArr = (mtpMsgId*)(haveSentIdsWrap->data() + 8); + + if (havePrepend) { + mtpMsgId msgId = prepareToSend(prepend); + *(haveSentArr++) = msgId; + if (havePrepend) pingMsgId = msgId; + + uint32 from = toSendRequest->size(), len = mtpRequestData::messageSize(prepend); + toSendRequest->resize(from + len); + memcpy(toSendRequest->data() + from, prepend->constData() + 4, len * sizeof(mtpPrime)); + + needAnyResponse = true; + } + for (mtpPreRequestMap::iterator i = toSend.begin(), e = toSend.end(); i != e; ++i) { + mtpRequest &req(i.value()); + mtpMsgId msgId = prepareToSend(req); + *(haveSentArr++) = msgId; + + if (req->requestId) { + if (mtpRequestData::needAck(req)) { + req->msDate = mtpRequestData::isStateRequest(req) ? 0 : getms(); + haveSent.insert(msgId, req); + + needAnyResponse = true; + } else { + wereAcked.insert(msgId, req->requestId); + } + } + uint32 from = toSendRequest->size(), len = mtpRequestData::messageSize(req); + toSendRequest->resize(from + len); + memcpy(toSendRequest->data() + from, req->constData() + 4, len * sizeof(mtpPrime)); + } + + mtpMsgId contMsgId = prepareToSend(toSendRequest); + *(mtpMsgId*)(haveSentIdsWrap->data() + 4) = contMsgId; + (*haveSentIdsWrap)[6] = 0; // for container, msDate = 0, seqNo = 0 + haveSent.insert(contMsgId, haveSentIdsWrap); + toSend.clear(); + } + } + mtpRequestData::padding(toSendRequest); + sendRequest(toSendRequest, needAnyResponse); +} + +void MTProtoConnectionPrivate::retryByTimer() { + if (retryTimeout < 3) { + ++retryTimeout; + } else if (retryTimeout == 3) { + retryTimeout = 1000; + } else if (retryTimeout < 64000) { + retryTimeout *= 2; + } + if (keyId == mtpAuthKey::RecreateKeyId) { + if (sessionData->getKey()) { + QWriteLocker lock(sessionData->keyMutex()); + sessionData->owner()->destroyKey(); + } + keyId = 0; + } + socketStart(); +} + +void MTProtoConnectionPrivate::restartNow() { + retryTimeout = 1; + retryTimer.stop(); + restart(); +} + +void MTProtoConnectionPrivate::socketStart(bool afterConfig) { + if (!conn) createConn(); + + if (conn->isConnected()) { + onConnected(); + return; + } + + setState(MTProtoConnection::Connecting); + pingId = pingMsgId = toSendPingId = 0; + + const mtpDcOption *dcOption = 0; + const mtpDcOptions &gDcOptions(mtpDCOptions()); + mtpDcOptions::const_iterator dcIndex = gDcOptions.constFind(dc % _mtp_internal::dcShift); + DEBUG_LOG(("MTP Info: connecting to DC %1..").arg(dc)); + if (dcIndex == gDcOptions.cend()) { + if (afterConfig) { + LOG(("MTP Error: DC %1 options not found right after config load!").arg(dc)); + return restart(); + } else { + DEBUG_LOG(("MTP Info: DC %1 options not found, waiting for config").arg(dc)); + connect(mtpConfigLoader(), SIGNAL(loaded()), this, SLOT(onConfigLoaded())); + mtpConfigLoader()->load(); + return; + } + } + dcOption = &dcIndex.value(); + + const char *ip(dcOption->ip.c_str()); + uint32 port(dcOption->port); + DEBUG_LOG(("MTP Info: socket connection to %1:%2..").arg(ip).arg(port)); + + connect(conn, SIGNAL(connected()), this, SLOT(onConnected())); + connect(conn, SIGNAL(disconnected()), this, SLOT(restart())); + + conn->connectToServer(ip, port); +} + +void MTProtoConnectionPrivate::restart(bool maybeBadKey) { + DEBUG_LOG(("MTP Info: restarting MTProtoConnection, maybe bad key = %1").arg(logBool(maybeBadKey))); + + connCheckTimer.stop(); + + mtpAuthKeyPtr key(sessionData->getKey()); + if (key) { + if (!sessionData->isCheckedKey()) { + if (maybeBadKey) { + clearMessages(); + keyId = mtpAuthKey::RecreateKeyId; +// retryTimeout = 1; // no ddos please + LOG(("MTP Info: key may be bad and was not checked - will be destroyed")); + } + } else { + sessionData->setCheckedKey(false); + } + } + + doDisconnect(); + restarted = true; + if (retryTimer.isActive()) return; + + DEBUG_LOG(("MTP Info: restart timeout: %1ms").arg(retryTimeout)); + setState(-retryTimeout); +} + +void MTProtoConnectionPrivate::onSentSome(uint64 size) { + if (!connCheckTimer.isActive()) { + uint64 remain = receiveDelay; + if (!oldConnection) { + uint64 remainBySize = size * receiveDelay / 8192; // 8kb / sec, so 512 kb give 64 sec + remain = snap(remainBySize, remain, uint64(MTPMaxReceiveDelay)); + if (remain != receiveDelay) { + DEBUG_LOG(("Checking connect for request with size %1 bytes, delay will be %2").arg(size).arg(remain)); + } + } + connCheckTimer.start(remain); + } + if (!firstSentAt) firstSentAt = getms(); +} + +void MTProtoConnectionPrivate::onReceivedSome() { + if (oldConnection) { + oldConnection = false; + DEBUG_LOG(("This connection marked as not old!")); + } + oldConnectionTimer.start(MTPConnectionOldTimeout); + connCheckTimer.stop(); + if (firstSentAt > 0) { + int32 ms = getms() - firstSentAt; + DEBUG_LOG(("MTP Info: response in %1ms, receiveDelay: %2ms").arg(ms).arg(receiveDelay)); + + if (ms > 0 && ms * 2 < receiveDelay) receiveDelay = qMax(ms * 2, int32(MinReceiveDelay)); + firstSentAt = -1; + } +} + +void MTProtoConnectionPrivate::onOldConnection() { + oldConnection = true; + receiveDelay = MinReceiveDelay; + DEBUG_LOG(("This connection marked as old! delay now %1ms").arg(receiveDelay)); +} + +void MTProtoConnectionPrivate::onBadConnection() { + if (cConnectionType() != dbictAuto && cConnectionType() != dbictTcpProxy) { + return; + } + + DEBUG_LOG(("MTP Info: bad connection, delay: %1ms").arg(receiveDelay)); + if (receiveDelay < MTPMaxReceiveDelay) { + receiveDelay *= 2; + } + doDisconnect(); + restarted = true; + if (retryTimer.isActive()) return; + + DEBUG_LOG(("MTP Info: immediate restart!")); + QTimer::singleShot(0, this, SLOT(socketStart())); +} + +void MTProtoConnectionPrivate::doDisconnect() { + if (conn) { + disconnect(conn, SIGNAL(disconnected()), 0, 0); + disconnect(conn, SIGNAL(receivedData()), 0, 0); + disconnect(conn, SIGNAL(receivedSome()), 0, 0); + + conn->disconnectFromServer(); + conn->deleteLater(); + conn = 0; + } + + unlockKey(); + + pinger.stop(); + clearAuthKeyData(); + + setState(MTProtoConnection::Disconnected); + restarted = false; +} + +void MTProtoConnectionPrivate::doFinish() { + doDisconnect(); + _owner->stopped(); +} + +void MTProtoConnectionPrivate::handleReceived() { + onReceivedSome(); + + ReadLockerAttempt lock(sessionData->keyMutex()); + if (!lock) { + DEBUG_LOG(("MTP Error: auth_key for dc %1 busy, cant lock").arg(dc)); + clearMessages(); + keyId = 0; + return restart(); + } + + mtpAuthKeyPtr key(sessionData->getKey()); + if (!key || key->keyId() != keyId) { + DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(dc)); + return restart(); + } + + + while (conn->received().size()) { + const mtpBuffer &encryptedBuf(conn->received().front()); + uint32 len = encryptedBuf.size(); + const mtpPrime *encrypted(encryptedBuf.data()); + if (len < 18) { // 2 auth_key_id, 4 msg_key, 2 salt, 2 session, 2 msg_id, 1 seq_no, 1 length, (1 data + 3 padding) min + LOG(("TCP Error: bad message received, len %1").arg(len * sizeof(mtpPrime))); + TCP_LOG(("TCP Error: bad message %1").arg(mb(encrypted, len * sizeof(mtpPrime)).str())); + return restart(); + } + if (keyId != *(uint64*)encrypted) { + LOG(("TCP Error: bad auth_key_id %1 instead of %2 received").arg(keyId).arg(*(uint64*)encrypted)); + TCP_LOG(("TCP Error: bad message %1").arg(mb(encrypted, len * sizeof(mtpPrime)).str())); + return restart(); + } + + QByteArray dataBuffer((len - 6) * sizeof(mtpPrime), Qt::Uninitialized); + mtpPrime *data((mtpPrime*)dataBuffer.data()), *msg = data + 8; + const mtpPrime *from(msg), *end; + MTPint128 msgKey(*(MTPint128*)(encrypted + 2)); + + aesDecrypt(encrypted + 6, data, dataBuffer.size(), key, msgKey); + + uint64 serverSalt = *(uint64*)&data[0], session = *(uint64*)&data[2], msgId = *(uint64*)&data[4]; + uint32 seqNo = *(uint32*)&data[6], msgLen = *(uint32*)&data[7]; + bool needAck = (seqNo & 0x01); + + if (dataBuffer.size() < msgLen + 8 * sizeof(mtpPrime) || (msgLen & 0x03)) { + LOG(("TCP Error: bad msg_len received %1, data size: %2").arg(msgLen).arg(dataBuffer.size())); + TCP_LOG(("TCP Error: bad message %1").arg(mb(encrypted, len * sizeof(mtpPrime)).str())); + conn->received().pop_front(); + return restart(); + } + uchar sha1Buffer[20]; + if (memcmp(&msgKey, hashSha1(data, msgLen + 8 * sizeof(mtpPrime), sha1Buffer) + 1, sizeof(msgKey))) { + LOG(("TCP Error: bad SHA1 hash after aesDecrypt in message")); + TCP_LOG(("TCP Error: bad message %1").arg(mb(encrypted, len * sizeof(mtpPrime)).str())); + conn->received().pop_front(); + return restart(); + } + TCP_LOG(("TCP Info: decrypted message %1,%2,%3 is %4").arg(msgId).arg(seqNo).arg(logBool(needAck)).arg(mb(data, msgLen + 8 * sizeof(mtpPrime)).str())); + + uint64 serverSession = sessionData->getSession(); + if (session != serverSession) { + LOG(("MTP Error: bad server session received")); + TCP_LOG(("MTP Error: bad server session %1 instead of %2 in message received").arg(session).arg(serverSession)); + conn->received().pop_front(); + return restart(); + } + + conn->received().pop_front(); + + int32 serverTime((int32)(msgId >> 32)), clientTime(unixtime()); + bool isReply = ((msgId & 0x03) == 1); + if (!isReply && ((msgId & 0x03) != 3)) { + LOG(("MTP Error: bad msg_id %1 in message received").arg(msgId)); + return restart(); + } + + bool badTime = false; + uint64 mySalt = sessionData->getSalt(); + if (serverTime > clientTime + 60 || serverTime + 300 < clientTime) { + DEBUG_LOG(("MTP Info: bad server time from msg_id: %1, my time: %2").arg(serverTime).arg(clientTime)); + badTime = true; + } + + bool wasConnected = (getState() == MTProtoConnection::Connected); + if (serverSalt != mySalt) { + if (!badTime) { + DEBUG_LOG(("MTP Info: other salt received.. received: %1, my salt: %2, updating..").arg(serverSalt).arg(mySalt)); + sessionData->setSalt(serverSalt); + if (setState(MTProtoConnection::Connected, MTProtoConnection::Connecting)) { // only connected + if (restarted) { + sessionData->owner()->resendAll(); + restarted = false; + } + } + } else { + DEBUG_LOG(("MTP Info: other salt received.. received: %1, my salt: %2").arg(serverSalt).arg(mySalt)); + } + } else { + serverSalt = 0; // dont pass to handle method, so not to lock in setSalt() + } + + if (needAck) ackRequestData->push_back(MTP_long(msgId)); + + int32 res = 1; // if no need to handle, then succeed + end = data + 8 + (msgLen >> 2); + const mtpPrime *sfrom(data + 4); + MTP_LOG(dc, ("Recv: ") + mtpTextSerialize(sfrom, end, mtpc_core_message)); + + bool needToHandle = false; + { + QWriteLocker lock(sessionData->receivedIdsMutex()); + mtpMsgIdsSet &receivedIds(sessionData->receivedIdsSet()); + needToHandle = receivedIds.insert(msgId, needAck); + } + if (needToHandle) { + res = handleOneReceived(from, end, msgId, serverTime, serverSalt, badTime); + } + { + QWriteLocker lock(sessionData->receivedIdsMutex()); + mtpMsgIdsSet &receivedIds(sessionData->receivedIdsSet()); + uint32 receivedIdsSize = receivedIds.size(); + while (receivedIdsSize-- > MTPIdsBufferSize) { + receivedIds.erase(receivedIds.begin()); + } + } + + // send acks + uint32 toAckSize = ackRequestData->size(); + if (toAckSize) { + DEBUG_LOG(("MTP Info: sending %1 acks, ids: %2").arg(toAckSize).arg(logVectorLong(*ackRequestData))); + sessionData->owner()->send(ackRequest, RPCResponseHandler(), 10000); + ackRequestData->clear(); + } + + bool emitSignal = false; + { + QReadLocker locker(sessionData->haveReceivedMutex()); + emitSignal = !sessionData->haveReceivedMap().isEmpty(); + if (emitSignal) { + DEBUG_LOG(("MTP Info: emitting needToReceive() - need to parse in another thread, haveReceivedMap.size() = %1").arg(sessionData->haveReceivedMap().size())); + } + } + + if (emitSignal) { + emit needToReceive(); + } + + if (res < 0) { + return restart(); + } + + if (!sessionData->isCheckedKey()) { + DEBUG_LOG(("MTP Info: marked auth key as checked")); + sessionData->setCheckedKey(true); + } + + if (!wasConnected) { + if (getState() == MTProtoConnection::Connected) { + emit sessionData->owner()->needToSendAsync(); + } + } + } + if (conn->needHttpWait()) { + sessionData->owner()->send(MTPHttpWait(MTP_http_wait(MTP_int(100), MTP_int(30), MTP_int(25000)))); + } +} + +int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime *end, uint64 msgId, int32 serverTime, uint64 serverSalt, bool badTime) { + mtpTypeId cons = *from; + try { + + switch (cons) { + + case mtpc_gzip_packed: { + DEBUG_LOG(("Message Info: gzip container")); + mtpBuffer response = ungzip(++from, end); + if (!response.size()) { + return -1; + } + return handleOneReceived(response.data(), response.data() + response.size(), msgId, serverTime, serverSalt, badTime); + } + + case mtpc_msg_container: { + if (++from >= end) throw mtpErrorInsufficient(); + + const mtpPrime *otherEnd; + uint32 msgsCount = (uint32)*(from++); + DEBUG_LOG(("Message Info: container received, count: %1").arg(msgsCount)); + for (uint32 i = 0; i < msgsCount; ++i) { + if (from + 4 >= end) throw mtpErrorInsufficient(); + otherEnd = from + 4; + + MTPlong inMsgId(from, otherEnd); + bool isReply = ((inMsgId.v & 0x03) == 1); + if (!isReply && ((inMsgId.v & 0x03) != 3)) { + LOG(("Message Error: bad msg_id %1 in contained message received").arg(inMsgId.v)); + return -1; + } + + MTPint inSeqNo(from, otherEnd); + MTPint bytes(from, otherEnd); + if ((bytes.v & 0x03) || bytes.v < 4) { + LOG(("Message Error: bad length %1 of contained message received").arg(bytes.v)); + return -1; + } + + bool needAck = (inSeqNo.v & 0x01); + if (needAck) ackRequestData->push_back(inMsgId); + + DEBUG_LOG(("Message Info: message from container, msg_id: %1, needAck: %2").arg(inMsgId.v).arg(logBool(needAck))); + + otherEnd = from + (bytes.v >> 2); + if (otherEnd > end) throw mtpErrorInsufficient(); + + bool needToHandle = false; + { + QWriteLocker lock(sessionData->receivedIdsMutex()); + mtpMsgIdsSet &receivedIds(sessionData->receivedIdsSet()); + needToHandle = receivedIds.insert(inMsgId.v, needAck); + } + int32 res = 1; // if no need to handle, then succeed + if (needToHandle) { + res = handleOneReceived(from, otherEnd, inMsgId.v, serverTime, serverSalt, badTime); + badTime = false; + } + if (res <= 0) { + return res; + } + + from = otherEnd; + } + } return 1; + + case mtpc_msgs_ack: { + MTPMsgsAck msg(from, end); + const QVector &ids(msg.c_msgs_ack().vmsg_ids.c_vector().v); + uint32 idsCount = ids.size(); + + DEBUG_LOG(("Message Info: acks received, ids: %1").arg(logVectorLong(ids))); + if (!idsCount) return (badTime ? 0 : 1); + + if (badTime) { + if (requestsFixTimeSalt(ids, serverTime, serverSalt)) { + badTime = false; + } else { + return 0; + } + } + requestsAcked(ids); + } return 1; + + case mtpc_bad_msg_notification: { + MTPBadMsgNotification msg(from, end); + const MTPDbad_msg_notification &data(msg.c_bad_msg_notification()); + LOG(("Message Info: bad message notification received (error_code %3) for msg_id = %1, seq_no = %2").arg(data.vbad_msg_id.v).arg(data.vbad_msg_seqno.v).arg(data.verror_code.v)); + + bool needResend = (data.verror_code.v == 16 || data.verror_code.v == 17); // bad msg_id + + mtpMsgId resendId = data.vbad_msg_id.v; + if (!wasSent(resendId)) { + DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId)); + return (badTime ? 0 : 1); + } + + if (needResend) { // bad msg_id + if (serverSalt) sessionData->setSalt(serverSalt); + unixtimeSet(serverTime, true); + + DEBUG_LOG(("Message Info: unixtime updated, now %1, resending in container..").arg(serverTime)); + + resend(resendId, 0, true); + } else { + if (badTime) { + if (serverSalt) sessionData->setSalt(serverSalt); + unixtimeSet(serverTime); + badTime = false; + } + LOG(("Message Error: bad message notification received, msgId %1, error_code %2").arg(data.vbad_msg_id.v).arg(data.verror_code.v)); + return -1; + } + } return 1; + + case mtpc_bad_server_salt: { + MTPBadMsgNotification msg(from, end); + const MTPDbad_server_salt &data(msg.c_bad_server_salt()); + DEBUG_LOG(("Message Info: bad server salt received (error_code %4) for msg_id = %1, seq_no = %2, new salt: %3").arg(data.vbad_msg_id.v).arg(data.vbad_msg_seqno.v).arg(data.vnew_server_salt.v).arg(data.verror_code.v)); + + mtpMsgId resendId = data.vbad_msg_id.v; + if (!wasSent(resendId)) { + DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId)); + return (badTime ? 0 : 1); + } + + uint64 serverSalt = data.vnew_server_salt.v; + sessionData->setSalt(serverSalt); + unixtimeSet(serverTime); + + if (setState(MTProtoConnection::Connected, MTProtoConnection::Connecting)) { // maybe only connected + if (restarted) { + sessionData->owner()->resendAll(); + restarted = false; + } + } + + badTime = false; + + DEBUG_LOG(("Message Info: unixtime updated, now %1, server_salt updated, now %2, resending..").arg(serverTime).arg(serverSalt)); + resend(resendId); + } return 1; + + case mtpc_msgs_state_req: { + if (badTime) { + DEBUG_LOG(("Message Info: skipping with bad time..")); + return 0; + } + MTPMsgsStateReq msg(from, end); + const QVector ids(msg.c_msgs_state_req().vmsg_ids.c_vector().v); + uint32 idsCount = ids.size(); + DEBUG_LOG(("Message Info: msgs_state_req received, ids: %1").arg(logVectorLong(ids))); + if (!idsCount) return 1; + + MTPMsgsStateInfo req(MTP_msgs_state_info(MTP_long(msgId), MTPstring())); + string &info(req._msgs_state_info().vinfo._string().v); + info.resize(idsCount); + + { + QReadLocker lock(sessionData->receivedIdsMutex()); + const mtpMsgIdsSet &receivedIds(sessionData->receivedIdsSet()); + mtpMsgIdsSet::const_iterator receivedIdsEnd(receivedIds.cend()); + uint64 minRecv = receivedIds.min(), maxRecv = receivedIds.max(); + + QReadLocker locker(sessionData->wereAckedMutex()); + const mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); + mtpRequestIdsMap::const_iterator wereAckedEnd(wereAcked.cend()); + + for (uint32 i = 0, l = idsCount; i < l; ++i) { + char state = 0; + uint64 reqMsgId = ids[i].v; + if (reqMsgId < minRecv) { + state |= 0x01; + } else if (reqMsgId > maxRecv) { + state |= 0x03; + } else { + mtpMsgIdsSet::const_iterator recv = receivedIds.constFind(reqMsgId); + if (recv == receivedIdsEnd) { + state |= 0x02; + } else { + state |= 0x04; + if (wereAcked.constFind(reqMsgId) != wereAckedEnd) { + state |= 0x80; // we know, that server knows, that we received request + } + if (recv.value()) { // need ack, so we sent ack + state |= 0x08; + } else { + state |= 0x10; + } + } + } + info[i] = state; + } + } + + sessionData->owner()->send(req); + } return 1; + + case mtpc_msgs_state_info: { + MTPMsgsStateInfo msg(from, end); + const MTPDmsgs_state_info &data(msg.c_msgs_state_info()); + + uint64 reqMsgId = data.vreq_msg_id.v; + const string &states(data.vinfo.c_string().v); + + DEBUG_LOG(("Message Info: msg state received, msgId %1, reqMsgId: %2, states %3").arg(msgId).arg(reqMsgId).arg(mb(states.data(), states.length()).str())); + mtpRequest requestBuffer; + { // find this request in session-shared sent requests map + QReadLocker locker(sessionData->haveSentMutex()); + const mtpRequestMap &haveSent(sessionData->haveSentMap()); + mtpRequestMap::const_iterator replyTo = haveSent.constFind(reqMsgId); + if (replyTo == haveSent.cend()) { // do not look in toResend, because we do not resend msgs_state_req requests + DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(reqMsgId)); + return (badTime ? 0 : 1); + } + if (serverSalt) sessionData->setSalt(serverSalt); // requestsFixTimeSalt with no lookup + unixtimeSet(serverTime); + + DEBUG_LOG(("Message Info: unixtime updated from mtpc_msgs_state_info, now %1").arg(serverTime)); + + badTime = false; + requestBuffer = replyTo.value(); + } + QVector toAck(1, MTP_long(reqMsgId)); + if (requestBuffer->size() < 9) { + LOG(("Message Error: bad request %1 found in requestMap, size: %2").arg(reqMsgId).arg(requestBuffer->size())); + return -1; + } + try { + const mtpPrime *rFrom = requestBuffer->constData() + 8, *rEnd = requestBuffer->constData() + requestBuffer->size(); + MTPMsgsStateReq request(rFrom, rEnd); + handleMsgsStates(request.c_msgs_state_req().vmsg_ids.c_vector().v, states, toAck); + } catch(Exception &e) { + LOG(("Message Error: could not parse sent msgs_state_req")); + throw; + } + + requestsAcked(toAck); + } return 1; + + case mtpc_msgs_all_info: { + if (badTime) { + DEBUG_LOG(("Message Info: skipping with bad time..")); + return 0; + } + + MTPMsgsAllInfo msg(from, end); + const MTPDmsgs_all_info &data(msg.c_msgs_all_info()); + const QVector ids(data.vmsg_ids.c_vector().v); + const string &states(data.vinfo.c_string().v); + + QVector toAck; + + DEBUG_LOG(("Message Info: msgs all info received, msgId %1, reqMsgIds: %2, states %3").arg(msgId).arg(logVectorLong(ids)).arg(mb(states.data(), states.length()).str())); + handleMsgsStates(ids, states, toAck); + + requestsAcked(toAck); + } return 1; + + case mtpc_msg_detailed_info: { + MTPMsgDetailedInfo msg(from, end); + const MTPDmsg_detailed_info &data(msg.c_msg_detailed_info()); + + DEBUG_LOG(("Message Info: msg detailed info, sent msgId %1, answerId %2, status %3, bytes %4").arg(data.vmsg_id.v).arg(data.vanswer_msg_id.v).arg(data.vstatus.v).arg(data.vbytes.v)); + + QVector ids(1, data.vmsg_id); + if (badTime) { + if (requestsFixTimeSalt(ids, serverTime, serverSalt)) { + DEBUG_LOG(("Message Info: error, such message was not sent recently %1").arg(data.vmsg_id.v)); + badTime = false; + } else { + return 0; + } + } + requestsAcked(ids); + + bool received = false; + MTPlong resMsgId = data.vanswer_msg_id; + { + QReadLocker lock(sessionData->receivedIdsMutex()); + const mtpMsgIdsSet &receivedIds(sessionData->receivedIdsSet()); + received = (receivedIds.find(resMsgId.v) != receivedIds.cend()) && (receivedIds.min() < resMsgId.v); + } + if (!received) { + DEBUG_LOG(("Message Info: answer message %1 was not received, requesting..").arg(resMsgId.v)); + MTPMsgResendReq resendRequest(MTP_msg_resend_req(MTPVector(1))); + resendRequest._msg_resend_req().vmsg_ids._vector().v.push_back(resMsgId); + sessionData->owner()->send(resendRequest); + } + } return 1; + + case mtpc_msg_new_detailed_info: { + if (badTime) { + DEBUG_LOG(("Message Info: skipping msg_new_detailed_info with bad time..")); + return 0; + } + MTPMsgDetailedInfo msg(from, end); + const MTPDmsg_new_detailed_info &data(msg.c_msg_new_detailed_info()); + + DEBUG_LOG(("Message Info: msg new detailed info, answerId %2, status %3, bytes %4").arg(data.vanswer_msg_id.v).arg(data.vstatus.v).arg(data.vbytes.v)); + + bool received = false; + MTPlong resMsgId = data.vanswer_msg_id; + { + QReadLocker lock(sessionData->receivedIdsMutex()); + const mtpMsgIdsSet &receivedIds(sessionData->receivedIdsSet()); + received = (receivedIds.find(resMsgId.v) != receivedIds.cend()) && (receivedIds.min() < resMsgId.v); + } + if (!received) { + DEBUG_LOG(("Message Info: answer message %1 was not received, requesting..").arg(resMsgId.v)); + MTPMsgResendReq resendRequest(MTP_msg_resend_req(MTPVector(1))); + resendRequest._msg_resend_req().vmsg_ids._vector().v.push_back(resMsgId); + sessionData->owner()->send(resendRequest); + } + } return 1; + + case mtpc_msg_resend_req: { + MTPMsgResendReq msg(from, end); + const QVector &ids(msg.c_msg_resend_req().vmsg_ids.c_vector().v); + + uint32 idsCount = ids.size(); + DEBUG_LOG(("Message Info: resend of msgs requested, ids: %1").arg(logVectorLong(ids))); + if (!idsCount) return (badTime ? 0 : 1); + + for (QVector::const_iterator i = ids.cbegin(), e = ids.cend(); i != e; ++i) { + resend(i->v, 0, false, true); + } + } return 1; + + case mtpc_rpc_result: { + if (from + 3 > end) throw mtpErrorInsufficient(); + mtpResponse response; + + MTPlong reqMsgId(++from, end); + mtpTypeId typeId = from[0]; + + DEBUG_LOG(("RPC Info: response received for %1, queueing..").arg(reqMsgId.v)); + + QVector ids(1, reqMsgId); + if (badTime) { + if (requestsFixTimeSalt(ids, serverTime, serverSalt)) { + DEBUG_LOG(("Message Info: error, such message was not sent recently %1").arg(reqMsgId.v)); + badTime = false; + } else { + return 0; + } + } + requestsAcked(ids); + + if (typeId == mtpc_gzip_packed) { + DEBUG_LOG(("RPC Info: gzip container")); + response = ungzip(++from, end); + if (!response.size()) { + return -1; + } + typeId = response[0]; + } else { + response.resize(end - from); + memcpy(response.data(), from, (end - from) * sizeof(mtpPrime)); + } + + mtpRequestId requestId = wasSent(reqMsgId.v); + if (requestId && requestId != 0xFFFFFFFF) { + QWriteLocker locker(sessionData->haveReceivedMutex()); + sessionData->haveReceivedMap().insert(requestId, response); // save rpc_result for processing in main mtp thread + } else { + DEBUG_LOG(("RPC Info: requestId not found for msgId %1").arg(reqMsgId.v)); + } + } return 1; + + case mtpc_new_session_created: { + if (badTime) return 0; + + MTPNewSession msg(from, end); + const MTPDnew_session_created &data(msg.c_new_session_created()); + DEBUG_LOG(("Message Info: new server session created, unique_id %1, first_msg_id %2, server_salt %3").arg(data.vunique_id.v).arg(data.vfirst_msg_id.v).arg(data.vserver_salt.v)); + sessionData->setSalt(data.vserver_salt.v); + + mtpMsgId firstMsgId = data.vfirst_msg_id.v; + QVector toResend; + { + QReadLocker locker(sessionData->haveSentMutex()); + const mtpRequestMap &haveSent(sessionData->haveSentMap()); + toResend.reserve(haveSent.size()); + for (mtpRequestMap::const_iterator i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { + if (i.key() >= firstMsgId) break; + if (i.value()->requestId) toResend.push_back(i.key()); + } + } + for (uint32 i = 0, l = toResend.size(); i < l; ++i) { + resend(toResend[i], 10, true); + } + + mtpBuffer update(end - from); + if (end > from) memcpy(update.data(), from, (end - from) * sizeof(mtpPrime)); + + QWriteLocker locker(sessionData->haveReceivedMutex()); + mtpResponseMap &haveReceived(sessionData->haveReceivedMap()); + mtpRequestId fakeRequestId = sessionData->nextFakeRequestId(); + haveReceived.insert(fakeRequestId, mtpResponse(update)); // notify main process about new session - need to get difference + } return 1; + + case mtpc_ping: { + if (badTime) return 0; + + MTPPing msg(from, end); + DEBUG_LOG(("Message Info: ping received, ping_id: %1, sending pong..").arg(msg.vping_id.v)); + + sessionData->owner()->send(MTP_pong(MTP_long(msgId), msg.vping_id)); + } return 1; + + case mtpc_pong: { + MTPPong msg(from, end); + const MTPDpong &data(msg.c_pong()); + DEBUG_LOG(("Message Info: pong received, msg_id: %1, ping_id: %2").arg(data.vmsg_id.v).arg(data.vping_id.v)); + + if (!wasSent(data.vmsg_id.v)) { + DEBUG_LOG(("Message Error: such msg_id %1 ping_id %2 was not sent recently").arg(data.vmsg_id.v).arg(data.vping_id.v)); + return 0; + } + if (data.vping_id.v == pingId) { + pingId = 0; + } else { + DEBUG_LOG(("Message Info: just pong..")); + } + + QVector ids(1, data.vmsg_id); + if (badTime) { + if (requestsFixTimeSalt(ids, serverTime, serverSalt)) { + badTime = false; + } else { + return 0; + } + } + requestsAcked(ids); + + retryTimeout = 1; // reset restart() timer + } return 1; + + } + + } catch (Exception &e) { + return -1; + } + + if (badTime) { + DEBUG_LOG(("Message Error: bad time in updates cons")); + return 0; + } + + mtpBuffer update(end - from); + if (end > from) memcpy(update.data(), from, (end - from) * sizeof(mtpPrime)); + + QWriteLocker locker(sessionData->haveReceivedMutex()); + mtpResponseMap &haveReceived(sessionData->haveReceivedMap()); + mtpRequestId fakeRequestId = sessionData->nextFakeRequestId(); + haveReceived.insert(fakeRequestId, mtpResponse(update)); // notify main process about new updates + + if (cons != mtpc_updatesTooLong && cons != mtpc_updateShortMessage && cons != mtpc_updateShortChatMessage && cons != mtpc_updateShort && cons != mtpc_updatesCombined && cons != mtpc_updates) { + LOG(("Message Error: unknown constructor %1").arg(cons)); // maybe new api?.. + } + + return 1; +} + +mtpBuffer MTProtoConnectionPrivate::ungzip(const mtpPrime *from, const mtpPrime *end) const { + MTPstring packed(from, end); // read packed string as serialized mtp string type + uint32 packedLen = packed.c_string().v.size(), unpackedChunk = packedLen, unpackedLen = 0; + + mtpBuffer result; // * 4 because of mtpPrime type + result.resize(0); + z_stream stream; + stream.zalloc = 0; + stream.zfree = 0; + stream.opaque = 0; + stream.avail_in = 0; + stream.next_in = 0; + int res = inflateInit2(&stream, 16 + MAX_WBITS); + if (res != Z_OK) { + LOG(("RPC Error: could not init zlib stream, code: %1").arg(res)); + return result; + } + stream.avail_in = packedLen; + stream.next_in = (Bytef*)&packed._string().v[0]; + + stream.avail_out = 0; + while (!stream.avail_out) { + result.resize(result.size() + unpackedChunk); + stream.avail_out = unpackedChunk * sizeof(mtpPrime); + stream.next_out = (Bytef*)&result[result.size() - unpackedChunk]; + int res = inflate(&stream, Z_NO_FLUSH); + if (res != Z_OK && res != Z_STREAM_END) { + inflateEnd(&stream); + LOG(("RPC Error: could not unpack gziped data, code: %1").arg(res)); + DEBUG_LOG(("RPC Error: bad gzip: %1").arg(mb(&packed.c_string().v[0], packedLen).str())); + return mtpBuffer(); + } + } + if (stream.avail_out & 0x03) { + uint32 badSize = result.size() * sizeof(mtpPrime) - stream.avail_out; + LOG(("RPC Error: bad length of unpacked data %1").arg(badSize)); + DEBUG_LOG(("RPC Error: bad unpacked data %1").arg(mb(result.data(), badSize).str())); + return mtpBuffer(); + } + result.resize(result.size() - (stream.avail_out >> 2)); + inflateEnd(&stream); + if (!result.size()) { + LOG(("RPC Error: bad length of unpacked data 0")); + } + return result; +} + +bool MTProtoConnectionPrivate::requestsFixTimeSalt(const QVector &ids, int32 serverTime, uint64 serverSalt) { + uint32 idsCount = ids.size(); + + for (uint32 i = 0; i < idsCount; ++i) { + if (wasSent(ids[i].v)) {// found such msg_id in recent acked requests or in recent sent requests + if (serverSalt) sessionData->setSalt(serverSalt); + unixtimeSet(serverTime); + return true; + } + } + return false; +} + +void MTProtoConnectionPrivate::requestsAcked(const QVector &ids) { + uint32 idsCount = ids.size(); + + DEBUG_LOG(("Message Info: requests acked, ids %1").arg(logVectorLong(ids))); + + RPCCallbackClears clearedAcked; + QVector toAckMore; + { + QWriteLocker locker1(sessionData->wereAckedMutex()); + mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); + + { + QWriteLocker locker2(sessionData->haveSentMutex()); + mtpRequestMap &haveSent(sessionData->haveSentMap()); + + for (uint32 i = 0; i < idsCount; ++i) { + mtpMsgId msgId = ids[i].v; + mtpRequestMap::iterator req = haveSent.find(msgId); + if (req != haveSent.cend()) { + if (!req.value()->msDate) { + DEBUG_LOG(("Message Info: container ack received, msgId %1").arg(ids[i].v)); + uint32 inContCount = ((*req)->size() - 8) / 2; + const mtpMsgId *inContId = (const mtpMsgId *)(req.value()->constData() + 8); + toAckMore.reserve(toAckMore.size() + inContCount); + for (uint32 j = 0; j < inContCount; ++j) { + toAckMore.push_back(MTP_long(*(inContId++))); + } + } else { + wereAcked.insert(msgId, req.value()->requestId); + } + haveSent.erase(req); + } else { + DEBUG_LOG(("Message Info: msgId %1 was not found in recent sent, while acking requests, searching in resend..").arg(msgId)); + QWriteLocker locker3(sessionData->toResendMutex()); + mtpRequestIdsMap &toResend(sessionData->toResendMap()); + mtpRequestIdsMap::iterator reqIt = toResend.find(msgId); + if (reqIt != toResend.cend()) { + mtpRequestId reqId = reqIt.value(); + QWriteLocker locker4(sessionData->toSendMutex()); + mtpPreRequestMap &toSend(sessionData->toSendMap()); + mtpPreRequestMap::iterator req = toSend.find(reqId); + if (req != toSend.cend()) { + wereAcked.insert(msgId, req.value()->requestId); + if (req.value()->requestId != reqId) { + DEBUG_LOG(("Message Error: for msgId %1 found resent request, requestId %2, contains requestId %3").arg(msgId).arg(reqId).arg(req.value()->requestId)); + } else { + DEBUG_LOG(("Message Info: acked msgId %1 that was prepared to resend, requestId %2").arg(msgId).arg(reqId)); + } + toSend.erase(req); + } else { + DEBUG_LOG(("Message Info: msgId %1 was found in recent resent, requestId %2 was not found in prepared to send").arg(msgId)); + } + toResend.erase(reqIt); + } else { + DEBUG_LOG(("Message Info: msgId %1 was not found in recent resent either").arg(msgId)); + } + } + } + } + + uint32 ackedCount = wereAcked.size(); + if (ackedCount > MTPIdsBufferSize) { + DEBUG_LOG(("Message Info: removing some old acked sent msgIds %1").arg(ackedCount - MTPIdsBufferSize)); + clearedAcked.reserve(ackedCount - MTPIdsBufferSize); + while (ackedCount-- > MTPIdsBufferSize) { + mtpRequestIdsMap::iterator i(wereAcked.begin()); + clearedAcked.push_back(RPCCallbackClear(i.key(), RPCError::TimeoutError)); + wereAcked.erase(i); + } + } + } + + if (clearedAcked.size()) { + _mtp_internal::clearCallbacksDelayed(clearedAcked); + } + + if (toAckMore.size()) { + requestsAcked(toAckMore); + } +} + +void MTProtoConnectionPrivate::handleMsgsStates(const QVector &ids, const string &states, QVector &acked) { + uint32 idsCount = ids.size(); + if (!idsCount) { + DEBUG_LOG(("Message Info: void ids vector in handleMsgsStates()")); + return; + } + + acked.reserve(acked.size() + idsCount); + + for (uint32 i = 0, count = idsCount; i < count; ++i) { + char state = states[i]; + uint64 requestMsgId = ids[i].v; + { + QReadLocker locker(sessionData->haveSentMutex()); + const mtpRequestMap &haveSent(sessionData->haveSentMap()); + mtpRequestMap::const_iterator haveSentEnd = haveSent.cend(); + if (haveSent.find(requestMsgId) == haveSentEnd) { + DEBUG_LOG(("Message Info: state was received for msgId %1, but request is not found, looking in resent requests..").arg(requestMsgId)); + QWriteLocker locker2(sessionData->toResendMutex()); + mtpRequestIdsMap &toResend(sessionData->toResendMap()); + mtpRequestIdsMap::iterator reqIt = toResend.find(requestMsgId); + if (reqIt != toResend.cend()) { + if ((state & 0x07) != 0x04) { // was received + DEBUG_LOG(("Message Info: state was received for msgId %1, state %2, already resending in container").arg(requestMsgId).arg((int32)state)); + } else { + DEBUG_LOG(("Message Info: state was received for msgId %1, state %2, ack, cancelling resend").arg(requestMsgId).arg((int32)state)); + acked.push_back(MTP_long(requestMsgId)); // will remove from resend in requestsAcked + } + } else { + DEBUG_LOG(("Message Info: msgId %1 was not found in recent resent either").arg(requestMsgId)); + } + continue; + } + } + if ((state & 0x07) != 0x04) { // was received + DEBUG_LOG(("Message Info: state was received for msgId %1, state %2, resending in container").arg(requestMsgId).arg((int32)state)); + resend(requestMsgId, 10, true); + } else { + DEBUG_LOG(("Message Info: state was received for msgId %1, state %2, ack").arg(requestMsgId).arg((int32)state)); + acked.push_back(MTP_long(requestMsgId)); + } + } +} + +mtpRequestId MTProtoConnectionPrivate::resend(mtpMsgId msgId, uint64 msCanWait, bool forceContainer, bool sendMsgStateInfo) { + if (msgId == pingMsgId) return 0xFFFFFFFF; + return sessionData->owner()->resend(msgId, msCanWait, forceContainer, sendMsgStateInfo); +} + + +void MTProtoConnectionPrivate::onConnected() { + disconnect(conn, SIGNAL(connected()), this, SLOT(onConnected())); + if (!conn->isConnected()) { + LOG(("Connection Error: not connected in onConnected(), state: %1").arg(conn->debugState())); + return restart(); + } + + TCP_LOG(("Connection Info: connection succeed.")); + + if (updateAuthKey()) { + DEBUG_LOG(("MTP Info: returning from socketConnected..")); + return; + } + + DEBUG_LOG(("MTP Info: will be creating auth_key")); + lockKey(); + + const mtpAuthKeyPtr &key(sessionData->getKey()); + if (key) { + if (keyId != key->keyId()) clearMessages(); + keyId = key->keyId(); + unlockKey(); + return authKeyCreated(); + } + + authKeyData = new MTProtoConnectionPrivate::AuthKeyCreateData(); + authKeyData->req_num = 0; + authKeyData->nonce = MTP::nonce(); + + MTPReq_pq req_pq; + req_pq.vnonce = authKeyData->nonce; + + connect(conn, SIGNAL(receivedData()), this, SLOT(pqAnswered())); + + DEBUG_LOG(("AuthKey Info: sending Req_pq..")); + sendRequestNotSecure(req_pq); +} + +bool MTProtoConnectionPrivate::updateAuthKey() { + if (!conn) return false; + + DEBUG_LOG(("AuthKey Info: MTProtoConnection updating key from MTProtoSession, dc %1").arg(dc)); + uint64 newKeyId = 0; + { + ReadLockerAttempt lock(sessionData->keyMutex()); + if (!lock) { + DEBUG_LOG(("MTP Info: could not lock auth_key for read, waiting signal emit")); + clearMessages(); + keyId = newKeyId; + return true; // some other connection is getting key + } + const mtpAuthKeyPtr &key(sessionData->getKey()); + newKeyId = key ? key->keyId() : 0; + } + if (keyId != newKeyId) { + clearMessages(); + keyId = newKeyId; + } + DEBUG_LOG(("AuthKey Info: MTProtoConnection update key from MTProtoSession, dc %1 result: %2").arg(dc).arg(mb(&keyId, sizeof(keyId)).str())); + if (keyId) { + authKeyCreated(); + return true; + } + DEBUG_LOG(("AuthKey Info: Key update failed")); + return false; +} + +void MTProtoConnectionPrivate::clearMessages() { + if (keyId && keyId != mtpAuthKey::RecreateKeyId && conn) { + conn->received().clear(); + } +} + +void MTProtoConnectionPrivate::pqAnswered() { + disconnect(conn, SIGNAL(receivedData()), this, SLOT(pqAnswered())); + DEBUG_LOG(("AuthKey Info: receiving Req_pq answer..")); + + MTPReq_pq::ResponseType res_pq; + if (!readResponseNotSecure(res_pq)) { + return restart(); + } + + const MTPDresPQ &res_pq_data(res_pq.c_resPQ()); + if (res_pq_data.vnonce != authKeyData->nonce) { + LOG(("AuthKey Error: received nonce <> sent nonce (in res_pq)!")); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(mb(&res_pq_data.vnonce, 16).str()).arg(mb(&authKeyData->nonce, 16).str())); + return restart(); + } + + mtpPublicRSA *rsaKey = 0; + const QVector &fingerPrints(res_pq.c_resPQ().vserver_public_key_fingerprints.c_vector().v); + for (uint32 i = 0, l = fingerPrints.size(); i < l; ++i) { + uint64 print(fingerPrints[i].v); + PublicRSAKeys::iterator rsaIndex = gPublicRSA.find(print); + if (rsaIndex != gPublicRSA.end()) { + rsaKey = &rsaIndex.value(); + break; + } + } + if (!rsaKey) { + QStringList suggested, my; + for (uint32 i = 0, l = fingerPrints.size(); i < l; ++i) { + suggested.push_back(QString("%1").arg(fingerPrints[i].v)); + } + for (PublicRSAKeys::const_iterator i = gPublicRSA.cbegin(), e = gPublicRSA.cend(); i != e; ++i) { + my.push_back(QString("%1").arg(i.key())); + } + LOG(("AuthKey Error: could not choose public RSA key, suggested fingerprints: %1, my fingerprints: %2").arg(suggested.join(", ")).arg(my.join(", "))); + return restart(); + } + + authKeyData->server_nonce = res_pq_data.vserver_nonce; + + MTPP_Q_inner_data p_q_inner; + MTPDp_q_inner_data &p_q_inner_data(p_q_inner._p_q_inner_data()); + p_q_inner_data.vnonce = authKeyData->nonce; + p_q_inner_data.vserver_nonce = authKeyData->server_nonce; + p_q_inner_data.vpq = res_pq_data.vpq; + + const string &pq(res_pq_data.vpq.c_string().v); + string &p(p_q_inner_data.vp._string().v), &q(p_q_inner_data.vq._string().v); + + if (!parsePQ(pq, p, q)) { + LOG(("AuthKey Error: could not factor pq!")); + DEBUG_LOG(("AuthKey Error: problematic pq: %1").arg(mb(&pq[0], pq.length()).str())); + return restart(); + } + + authKeyData->new_nonce = MTP::nonce(); + p_q_inner_data.vnew_nonce = authKeyData->new_nonce; + + MTPReq_DH_params req_DH_params; + req_DH_params.vnonce = authKeyData->nonce; + req_DH_params.vserver_nonce = authKeyData->server_nonce; + req_DH_params.vpublic_key_fingerprint = MTP_long(rsaKey->fingerPrint()); + req_DH_params.vp = p_q_inner_data.vp; + req_DH_params.vq = p_q_inner_data.vq; + + string &dhEncString(req_DH_params.vencrypted_data._string().v); + + uint32 p_q_inner_size = p_q_inner.size(), encSize = (p_q_inner_size >> 2) + 6; + if (encSize >= 65) { + mtpBuffer tmp; + tmp.reserve(encSize); + p_q_inner.write(tmp); + LOG(("AuthKey Error: too large data for RSA encrypt, size %1").arg(encSize * sizeof(mtpPrime))); + DEBUG_LOG(("AuthKey Error: bad data for RSA encrypt %1").arg(mb(&tmp[0], tmp.size() * 4).str())); + return restart(); // can't be 255-byte string + } + + mtpBuffer encBuffer; + encBuffer.reserve(65); // 260 bytes + encBuffer.resize(6); + encBuffer[0] = 0; + p_q_inner.write(encBuffer); + + hashSha1(&encBuffer[6], p_q_inner_size, &encBuffer[1]); + if (encSize < 65) { + encBuffer.resize(65); + memset_rand(&encBuffer[encSize], (65 - encSize) * sizeof(mtpPrime)); + } + + dhEncString.resize(256); + int32 res = RSA_public_encrypt(256, ((const uchar*)&encBuffer[0]) + 3, (uchar*)&dhEncString[0], rsaKey->key(), RSA_NO_PADDING); + if (res != 256) { + ERR_load_crypto_strings(); + LOG(("RSA Error: RSA_public_encrypt failed, key fp: %1, result: %2, error: %3").arg(rsaKey->fingerPrint()).arg(res).arg(ERR_error_string(ERR_get_error(), 0))); + return restart(); + } + + connect(conn, SIGNAL(receivedData()), this, SLOT(dhParamsAnswered())); + + DEBUG_LOG(("AuthKey Info: sending Req_DH_params..")); + sendRequestNotSecure(req_DH_params); +} + +void MTProtoConnectionPrivate::dhParamsAnswered() { + disconnect(conn, SIGNAL(receivedData()), this, SLOT(dhParamsAnswered())); + DEBUG_LOG(("AuthKey Info: receiving Req_DH_params answer..")); + + MTPReq_DH_params::ResponseType res_DH_params; + if (!readResponseNotSecure(res_DH_params)) { + return restart(); + } + + switch (res_DH_params.type()) { + case mtpc_server_DH_params_ok: { + const MTPDserver_DH_params_ok &encDH(res_DH_params.c_server_DH_params_ok()); + if (encDH.vnonce != authKeyData->nonce) { + LOG(("AuthKey Error: received nonce <> sent nonce (in server_DH_params_ok)!")); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(mb(&encDH.vnonce, 16).str()).arg(mb(&authKeyData->nonce, 16).str())); + return restart(); + } + if (encDH.vserver_nonce != authKeyData->server_nonce) { + LOG(("AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_params_ok)!")); + DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(mb(&encDH.vserver_nonce, 16).str()).arg(mb(&authKeyData->server_nonce, 16).str())); + return restart(); + } + + const string &encDHStr(encDH.vencrypted_answer.c_string().v); + uint32 encDHLen = encDHStr.length(), encDHBufLen = encDHLen >> 2; + if ((encDHLen & 0x03) || encDHBufLen < 6) { + LOG(("AuthKey Error: bad encrypted data length %1 (in server_DH_params_ok)!").arg(encDHLen)); + DEBUG_LOG(("AuthKey Error: received encrypted data %1").arg(mb(&encDHStr[0], encDHLen).str())); + return restart(); + } + + uint32 nlen = authKeyData->new_nonce.size(), slen = authKeyData->server_nonce.size(); + uchar tmp_aes[1024], sha1ns[20], sha1sn[20], sha1nn[20]; + memcpy(tmp_aes, &authKeyData->new_nonce, nlen); + memcpy(tmp_aes + nlen, &authKeyData->server_nonce, slen); + memcpy(tmp_aes + nlen + slen, &authKeyData->new_nonce, nlen); + memcpy(tmp_aes + nlen + slen + nlen, &authKeyData->new_nonce, nlen); + hashSha1(tmp_aes, nlen + slen, sha1ns); + hashSha1(tmp_aes + nlen, nlen + slen, sha1sn); + hashSha1(tmp_aes + nlen + slen, nlen + nlen, sha1nn); + + mtpBuffer decBuffer; + decBuffer.resize(encDHBufLen); + + memcpy(authKeyData->aesKey, sha1ns, 20); + memcpy(authKeyData->aesKey + 20, sha1sn, 12); + memcpy(authKeyData->aesIV, sha1sn + 12, 8); + memcpy(authKeyData->aesIV + 8, sha1nn, 20); + memcpy(authKeyData->aesIV + 28, &authKeyData->new_nonce, 4); + + aesDecrypt(&encDHStr[0], &decBuffer[0], encDHLen, authKeyData->aesKey, authKeyData->aesIV); + + const mtpPrime *from(&decBuffer[5]), *to(from), *end(from + (encDHBufLen - 5)); + MTPServer_DH_inner_data dh_inner(to, end); + const MTPDserver_DH_inner_data &dh_inner_data(dh_inner.c_server_DH_inner_data()); + if (dh_inner_data.vnonce != authKeyData->nonce) { + LOG(("AuthKey Error: received nonce <> sent nonce (in server_DH_inner_data)!")); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(mb(&dh_inner_data.vnonce, 16).str()).arg(mb(&authKeyData->nonce, 16).str())); + return restart(); + } + if (dh_inner_data.vserver_nonce != authKeyData->server_nonce) { + LOG(("AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_inner_data)!")); + DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(mb(&dh_inner_data.vserver_nonce, 16).str()).arg(mb(&authKeyData->server_nonce, 16).str())); + return restart(); + } + uchar sha1Buffer[20]; + if (memcmp(&decBuffer[0], hashSha1(&decBuffer[5], (to - from) * sizeof(mtpPrime), sha1Buffer), 20)) { + LOG(("AuthKey Error: sha1 hash of encrypted part did not match!")); + DEBUG_LOG(("AuthKey Error: sha1 did not match, server_nonce: %1, new_nonce %2, encrypted data %3").arg(mb(&authKeyData->server_nonce, 16).str()).arg(mb(&authKeyData->new_nonce, 16).str()).arg(mb(&encDHStr[0], encDHLen).str())); + return restart(); + } + unixtimeSet(dh_inner_data.vserver_time.v); + + const string &dhPrime(dh_inner_data.vdh_prime.c_string().v), &g_a(dh_inner_data.vg_a.c_string().v); + if (dhPrime.length() != 256 || g_a.length() != 256) { + LOG(("AuthKey Error: bad dh_prime len (%1) or g_a len (%2)").arg(dhPrime.length()).arg(g_a.length())); + DEBUG_LOG(("AuthKey Error: dh_prime %1, g_a %2").arg(mb(&dhPrime[0], dhPrime.length()).str()).arg(mb(&g_a[0], g_a.length()).str())); + return restart(); + } + + // check that dhPrime and (dhPrime - 1) / 2 are really prime using openssl BIGNUM methods + _BigNumPrimeTest bnPrimeTest; + if (!bnPrimeTest.isPrimeAndGood(&dhPrime[0], MTPMillerRabinIterCount, dh_inner_data.vg.v)) { + LOG(("AuthKey Error: bad dh_prime primality!").arg(dhPrime.length()).arg(g_a.length())); + DEBUG_LOG(("AuthKey Error: dh_prime %1").arg(mb(&dhPrime[0], dhPrime.length()).str())); + return restart(); + } + + authKeyData->dh_prime = dhPrime; + authKeyData->g = dh_inner_data.vg.v; + authKeyData->g_a = g_a; + authKeyData->retry_id = MTP_long(0); + authKeyData->retries = 0; + } return dhClientParamsSend(); + + case mtpc_server_DH_params_fail: { + const MTPDserver_DH_params_fail &encDH(res_DH_params.c_server_DH_params_fail()); + if (encDH.vnonce != authKeyData->nonce) { + LOG(("AuthKey Error: received nonce <> sent nonce (in server_DH_params_fail)!")); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(mb(&encDH.vnonce, 16).str()).arg(mb(&authKeyData->nonce, 16).str())); + return restart(); + } + if (encDH.vserver_nonce != authKeyData->server_nonce) { + LOG(("AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_params_fail)!")); + DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(mb(&encDH.vserver_nonce, 16).str()).arg(mb(&authKeyData->server_nonce, 16).str())); + return restart(); + } + uchar sha1Buffer[20]; + if (encDH.vnew_nonce_hash != *(MTPint128*)(hashSha1(&authKeyData->new_nonce, 32, sha1Buffer) + 1)) { + LOG(("AuthKey Error: received new_nonce_hash did not match!")); + DEBUG_LOG(("AuthKey Error: received new_nonce_hash: %1, new_nonce: %2").arg(mb(&encDH.vnew_nonce_hash, 16).str()).arg(mb(&authKeyData->new_nonce, 32).str())); + return restart(); + } + LOG(("AuthKey Error: server_DH_params_fail received!")); + } return restart(); + + } + LOG(("AuthKey Error: unknown server_DH_params received, typeId = %1").arg(res_DH_params.type())); + return restart(); +} + +void MTProtoConnectionPrivate::dhClientParamsSend() { + if (++authKeyData->retries > 5) { + LOG(("AuthKey Error: could not create auth_key for %1 retries").arg(authKeyData->retries - 1)); + return restart(); + } + + MTPClient_DH_Inner_Data client_dh_inner; + MTPDclient_DH_inner_data &client_dh_inner_data(client_dh_inner._client_DH_inner_data()); + client_dh_inner_data.vnonce = authKeyData->nonce; + client_dh_inner_data.vserver_nonce = authKeyData->server_nonce; + client_dh_inner_data.vretry_id = authKeyData->retry_id; + client_dh_inner_data.vg_b._string().v.resize(256); + + // gen rand 'b' + uint32 b[64], *g_b((uint32*)&client_dh_inner_data.vg_b._string().v[0]), g_b_len; + memset_rand(b, sizeof(b)); + + // count g_b and auth_key using openssl BIGNUM methods + _BigNumCounter bnCounter; + if (!bnCounter.count(b, &authKeyData->dh_prime[0], authKeyData->g, g_b, &authKeyData->g_a[0], authKeyData->auth_key)) { + return dhClientParamsSend(); + } + + // count auth_key hashes - parts of sha1(auth_key) + uchar sha1Buffer[20]; + int32 *auth_key_sha = hashSha1(authKeyData->auth_key, 256, sha1Buffer); + memcpy(&authKeyData->auth_key_aux_hash, auth_key_sha, 8); + memcpy(&authKeyData->auth_key_hash, auth_key_sha + 3, 8); + + MTPSet_client_DH_params req_client_DH_params; + req_client_DH_params.vnonce = authKeyData->nonce; + req_client_DH_params.vserver_nonce = authKeyData->server_nonce; + + string &sdhEncString(req_client_DH_params.vencrypted_data._string().v); + + uint32 client_dh_inner_size = client_dh_inner.size(), encSize = (client_dh_inner_size >> 2) + 5, encFullSize = encSize; + if (encSize & 0x03) { + encFullSize += 4 - (encSize & 0x03); + } + + mtpBuffer encBuffer; + encBuffer.reserve(encFullSize); + encBuffer.resize(5); + client_dh_inner.write(encBuffer); + + hashSha1(&encBuffer[5], client_dh_inner_size, &encBuffer[0]); + if (encSize < encFullSize) { + encBuffer.resize(encFullSize); + memset_rand(&encBuffer[encSize], (encFullSize - encSize) * sizeof(mtpPrime)); + } + + sdhEncString.resize(encFullSize * 4); + + aesEncrypt(&encBuffer[0], &sdhEncString[0], encFullSize * sizeof(mtpPrime), authKeyData->aesKey, authKeyData->aesIV); + + connect(conn, SIGNAL(receivedData()), this, SLOT(dhClientParamsAnswered())); + + DEBUG_LOG(("AuthKey Info: sending Req_client_DH_params..")); + sendRequestNotSecure(req_client_DH_params); +} + +void MTProtoConnectionPrivate::dhClientParamsAnswered() { + disconnect(conn, SIGNAL(receivedData()), this, SLOT(dhClientParamsAnswered())); + DEBUG_LOG(("AuthKey Info: receiving Req_client_DH_params answer..")); + + MTPSet_client_DH_params::ResponseType res_client_DH_params; + if (!readResponseNotSecure(res_client_DH_params)) { + return restart(); + } + + switch (res_client_DH_params.type()) { + case mtpc_dh_gen_ok: { + const MTPDdh_gen_ok &resDH(res_client_DH_params.c_dh_gen_ok()); + if (resDH.vnonce != authKeyData->nonce) { + LOG(("AuthKey Error: received nonce <> sent nonce (in dh_gen_ok)!")); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(mb(&resDH.vnonce, 16).str()).arg(mb(&authKeyData->nonce, 16).str())); + return restart(); + } + if (resDH.vserver_nonce != authKeyData->server_nonce) { + LOG(("AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_ok)!")); + DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(mb(&resDH.vserver_nonce, 16).str()).arg(mb(&authKeyData->server_nonce, 16).str())); + return restart(); + } + authKeyData->new_nonce_buf[32] = 1; + uchar sha1Buffer[20]; + if (resDH.vnew_nonce_hash1 != *(MTPint128*)(hashSha1(authKeyData->new_nonce_buf, 41, sha1Buffer) + 1)) { + LOG(("AuthKey Error: received new_nonce_hash1 did not match!")); + DEBUG_LOG(("AuthKey Error: received new_nonce_hash1: %1, new_nonce_buf: %2").arg(mb(&resDH.vnew_nonce_hash1, 16).str()).arg(mb(authKeyData->new_nonce_buf, 41).str())); + return restart(); + } + + uint64 salt1 = authKeyData->new_nonce.l.l, salt2 = authKeyData->server_nonce.l, serverSalt = salt1 ^ salt2; + sessionData->setSalt(serverSalt); + + mtpAuthKeyPtr authKey(new mtpAuthKey()); + authKey->setKey(authKeyData->auth_key); + authKey->setDC(dc % _mtp_internal::dcShift); + + DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2, auth key: %3").arg(authKey->keyId()).arg(serverSalt).arg(mb(authKeyData->auth_key, 256).str())); + + sessionData->owner()->keyCreated(authKey); // slot will call authKeyCreated() + sessionData->clear(); + unlockKey(); + } return; + + case mtpc_dh_gen_retry: { + const MTPDdh_gen_retry &resDH(res_client_DH_params.c_dh_gen_retry()); + if (resDH.vnonce != authKeyData->nonce) { + LOG(("AuthKey Error: received nonce <> sent nonce (in dh_gen_retry)!")); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(mb(&resDH.vnonce, 16).str()).arg(mb(&authKeyData->nonce, 16).str())); + return restart(); + } + if (resDH.vserver_nonce != authKeyData->server_nonce) { + LOG(("AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_retry)!")); + DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(mb(&resDH.vserver_nonce, 16).str()).arg(mb(&authKeyData->server_nonce, 16).str())); + return restart(); + } + authKeyData->new_nonce_buf[32] = 2; + uchar sha1Buffer[20]; + if (resDH.vnew_nonce_hash2 != *(MTPint128*)(hashSha1(authKeyData->new_nonce_buf, 41, sha1Buffer) + 1)) { + LOG(("AuthKey Error: received new_nonce_hash2 did not match!")); + DEBUG_LOG(("AuthKey Error: received new_nonce_hash2: %1, new_nonce_buf: %2").arg(mb(&resDH.vnew_nonce_hash2, 16).str()).arg(mb(authKeyData->new_nonce_buf, 41).str())); + return restart(); + } + authKeyData->retry_id = authKeyData->auth_key_aux_hash; + } return dhClientParamsSend(); + + case mtpc_dh_gen_fail: { + const MTPDdh_gen_fail &resDH(res_client_DH_params.c_dh_gen_fail()); + if (resDH.vnonce != authKeyData->nonce) { + LOG(("AuthKey Error: received nonce <> sent nonce (in dh_gen_fail)!")); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(mb(&resDH.vnonce, 16).str()).arg(mb(&authKeyData->nonce, 16).str())); + return restart(); + } + if (resDH.vserver_nonce != authKeyData->server_nonce) { + LOG(("AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_fail)!")); + DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(mb(&resDH.vserver_nonce, 16).str()).arg(mb(&authKeyData->server_nonce, 16).str())); + return restart(); + } + authKeyData->new_nonce_buf[32] = 3; + uchar sha1Buffer[20]; + if (resDH.vnew_nonce_hash3 != *(MTPint128*)(hashSha1(authKeyData->new_nonce_buf, 41, sha1Buffer) + 1)) { + LOG(("AuthKey Error: received new_nonce_hash3 did not match!")); + DEBUG_LOG(("AuthKey Error: received new_nonce_hash3: %1, new_nonce_buf: %2").arg(mb(&resDH.vnew_nonce_hash3, 16).str()).arg(mb(authKeyData->new_nonce_buf, 41).str())); + return restart(); + } + LOG(("AuthKey Error: dh_gen_fail received!")); + } return restart(); + + } + LOG(("AuthKey Error: unknown set_client_DH_params_answer received, typeId = %1").arg(res_client_DH_params.type())); + return restart(); +} + +void MTProtoConnectionPrivate::authKeyCreated() { + clearAuthKeyData(); + + connect(conn, SIGNAL(receivedData()), this, SLOT(handleReceived())); + + if (sessionData->getSalt()) { // else receive salt in bad_server_salt first, then try to send all the requests + setState(MTProtoConnection::Connected); + if (restarted) { + sessionData->owner()->resendAll(); + restarted = false; + } + } + + toSendPingId = MTP::nonce(); // get server_salt + + emit sessionData->owner()->needToSendAsync(); + +// disconnect(&pinger, SIGNAL(timeout()), 0, 0); +// connect(&pinger, SIGNAL(timeout()), this, SLOT(sendPing())); +// pinger.start(30000); +} + +void MTProtoConnectionPrivate::clearAuthKeyData() { + if (authKeyData) { +#ifdef Q_OS_WIN + SecureZeroMemory(authKeyData, sizeof(AuthKeyCreateData)); +#else + memset(authKeyData, 0, sizeof(AuthKeyCreateData)); +#endif + delete authKeyData; + authKeyData = 0; + } +} + +void MTProtoConnectionPrivate::sendPing() { + sessionData->owner()->send(MTPPing(MTPping(MTP::nonce()))); +} + +void MTProtoConnectionPrivate::onError(bool mayBeBadKey) { + MTP_LOG(dc, ("Restarting after error..")); + return restart(mayBeBadKey); +} + +void MTProtoConnectionPrivate::onReadyData() { +} + +template +void MTProtoConnectionPrivate::sendRequestNotSecure(const TRequest &request) { + try { + mtpBuffer buffer; + uint32 requestSize = request.size() >> 2; + + buffer.resize(0); + buffer.reserve(8 + requestSize); + buffer.push_back(0); // tcp packet len + buffer.push_back(0); // tcp packet num + buffer.push_back(0); + buffer.push_back(0); + buffer.push_back(authKeyData->req_num); + buffer.push_back(unixtime()); + buffer.push_back(requestSize * 4); + request.write(buffer); + buffer.push_back(0); // tcp crc32 hash + ++authKeyData->msgs_sent; + + DEBUG_LOG(("AuthKey Info: sending request, size: %1, num: %2, time: %3").arg(requestSize).arg(authKeyData->req_num).arg(buffer[5])); + + conn->sendData(buffer); + + onSentSome(buffer.size() * sizeof(mtpPrime)); + + } catch(Exception &e) { + return restart(); + } +} + +template +bool MTProtoConnectionPrivate::readResponseNotSecure(TResponse &response) { + onReceivedSome(); + + try { + if (conn->received().isEmpty()) { + LOG(("AuthKey Error: trying to read response from empty received list")); + return false; + } + mtpBuffer buffer(conn->received().front()); + conn->received().pop_front(); + + const mtpPrime *answer(buffer.constData()); + uint32 len = buffer.size(); + if (len < 5) { + LOG(("AuthKey Error: bad request answer, len = %1").arg(len * sizeof(mtpPrime))); + DEBUG_LOG(("AuthKey Error: answer bytes %1").arg(mb(answer, len * sizeof(mtpPrime)).str())); + return false; + } + if (answer[0] != 0 || answer[1] != 0 || (((uint32)answer[2]) & 0x03) != 1/* || (unixtime() - answer[3] > 300) || (answer[3] - unixtime() > 60)*/) { // didnt sync time yet + LOG(("AuthKey Error: bad request answer start (%1 %2 %3)").arg(answer[0]).arg(answer[1]).arg(answer[2])); + DEBUG_LOG(("AuthKey Error: answer bytes %1").arg(mb(answer, len * sizeof(mtpPrime)).str())); + return false; + } + uint32 answerLen = (uint32)answer[4]; + if (answerLen != (len - 5) * sizeof(mtpPrime)) { + LOG(("AuthKey Error: bad request answer %1 <> %2").arg(answerLen).arg((len - 5) * sizeof(mtpPrime))); + DEBUG_LOG(("AuthKey Error: answer bytes %1").arg(mb(answer, len * sizeof(mtpPrime)).str())); + return false; + } + const mtpPrime *from(answer + 5), *end(from + len - 5); + response.read(from, end); + } catch(Exception &e) { + return false; + } + return true; +} + +bool MTProtoConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResponse) { + uint32 fullSize = request->size(); + if (fullSize < 9) return false; + + uint32 messageSize = mtpRequestData::messageSize(request); + if (messageSize < 5 || fullSize < messageSize + 4) return false; + + ReadLockerAttempt lock(sessionData->keyMutex()); + if (!lock) { + DEBUG_LOG(("MTP Info: could not lock key for read in sendBuffer(), dc %1, restarting..").arg(dc)); + restart(); + return false; + } + + mtpAuthKeyPtr key(sessionData->getKey()); + if (!key || key->keyId() != keyId) { + DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(dc)); + restart(); + return false; + } + + uint32 padding = fullSize - 4 - messageSize; + uint64 session(sessionData->getSession()), salt(sessionData->getSalt()); + + memcpy(request->data() + 0, &salt, 2 * sizeof(mtpPrime)); + memcpy(request->data() + 2, &session, 2 * sizeof(mtpPrime)); + + const mtpPrime *from = request->constData() + 4; + MTP_LOG(dc, ("Send: ") + mtpTextSerialize(from, from + messageSize, mtpc_core_message)); + + uchar encryptedSHA[20]; + MTPint128 &msgKey(*(MTPint128*)(encryptedSHA + 4)); + hashSha1(request->constData(), (fullSize - padding) * sizeof(mtpPrime), encryptedSHA); + + mtpBuffer result; + result.resize(9 + fullSize); + *((uint64*)&result[2]) = keyId; + *((MTPint128*)&result[4]) = msgKey; + + aesEncrypt(request->constData(), &result[8], fullSize * sizeof(mtpPrime), key, msgKey); + + DEBUG_LOG(("MTP Info: sending request, size: %1, num: %2, time: %3").arg(fullSize + 6).arg((*request)[4]).arg((*request)[5])); + + conn->sendData(result); + + if (needAnyResponse) { + onSentSome(result.size() * sizeof(mtpPrime)); + } + + return true; +} + +mtpRequestId MTProtoConnectionPrivate::wasSent(mtpMsgId msgId) const { + if (msgId == pingMsgId) return 0xFFFFFFFF; + { + QReadLocker locker(sessionData->haveSentMutex()); + const mtpRequestMap &haveSent(sessionData->haveSentMap()); + mtpRequestMap::const_iterator i = haveSent.constFind(msgId); + if (i != haveSent.cend()) return i.value()->requestId || 0xFFFFFFFF; + } + { + QReadLocker locker(sessionData->toResendMutex()); + const mtpRequestIdsMap &toResend(sessionData->toResendMap()); + mtpRequestIdsMap::const_iterator i = toResend.constFind(msgId); + if (i != toResend.cend()) return i.value(); + } + { + QReadLocker locker(sessionData->wereAckedMutex()); + const mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); + mtpRequestIdsMap::const_iterator i = wereAcked.constFind(msgId); + if (i != wereAcked.cend()) return i.value(); + } + return 0; +} + +void MTProtoConnectionPrivate::lockKey() { + unlockKey(); + sessionData->keyMutex()->lockForWrite(); + myKeyLock = true; +} + +void MTProtoConnectionPrivate::unlockKey() { + if (myKeyLock) { + myKeyLock = false; + sessionData->keyMutex()->unlock(); + } +} + +MTProtoConnectionPrivate::~MTProtoConnectionPrivate() { + doDisconnect(); +} + +MTProtoConnection::~MTProtoConnection() { + stopped(); +} diff --git a/Telegram/SourceFiles/mtproto/mtpConnection.h b/Telegram/SourceFiles/mtproto/mtpConnection.h new file mode 100644 index 000000000..de781ae48 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpConnection.h @@ -0,0 +1,432 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "mtproto/mtpCoreTypes.h" +#include "mtproto/mtpScheme.h" +#include "mtproto/mtpPublicRSA.h" +#include "mtproto/mtpAuthKey.h" + +inline bool mtpRequestData::isSentContainer(const mtpRequest &request) { // "request-like" wrap for msgIds vector + if (request->size() < 9) return false; + return (!request->msDate && !(*request)[6]); // msDate = 0, seqNo = 0 +} +inline bool mtpRequestData::isStateRequest(const mtpRequest &request) { + if (request->size() < 9) return false; + return ((*request)[8] == mtpc_msgs_state_req); +} +inline bool mtpRequestData::needAck(const mtpRequest &request) { + if (request->size() < 9) return false; + return mtpRequestData::needAckByType((*request)[8]); +} +inline bool mtpRequestData::needAckByType(mtpTypeId type) { + switch (type) { + case mtpc_msg_container: + case mtpc_msgs_ack: + case mtpc_http_wait: + case mtpc_bad_msg_notification: + case mtpc_msgs_all_info: + case mtpc_msg_detailed_info: + case mtpc_msg_new_detailed_info: + return false; + } + return true; +} + +class MTProtoConnectionPrivate; +class MTPSessionData; + +class MTPThread : public QThread { +public: + MTPThread(QObject *parent = 0); + uint32 getThreadId() const; + +private: + uint32 threadId; +}; + +class MTProtoConnection { +public: + + enum ConnectionType { + TcpConnection, + HttpConnection + }; + + MTProtoConnection(); + int32 start(MTPSessionData *data, int32 dc = 0); // return dc + void restart(); + void stop(); + void stopped(); + ~MTProtoConnection(); + + enum { + Disconnected = 0, + Connecting = 1, + Connected = 2, + + UpdateAlways = 666 + }; + + int32 state() const; + QString transport() const; + + /*template // not used + uint64 sendAsync(const TRequest &request) { + return data->sendAsync(request); + }*/ + +private: + + QThread *thread; + MTProtoConnectionPrivate *data; + +}; + +class MTPabstractConnection : public QObject { + Q_OBJECT + + typedef QList BuffersQueue; + +public: + + virtual void sendData(mtpBuffer &buffer) = 0; // has size + 3, buffer[0] = len, buffer[1] = packetnum, buffer[last] = crc32 + virtual void disconnectFromServer() = 0; + virtual void connectToServer(const QString &addr, int32 port) = 0; + virtual bool isConnected() = 0; + virtual bool needHttpWait() { + return false; + } + + virtual int32 debugState() const = 0; + + virtual QString transport() const = 0; + + BuffersQueue &received() { + return receivedQueue; + } + +signals: + + void receivedData(); + void receivedSome(); // to stop restart timer + + void error(bool maybeBadKey = false); + + void connected(); + void disconnected(); + +protected: + + BuffersQueue receivedQueue; // list of received packets, not processed yet + +}; + +class MTPabstractTcpConnection : public MTPabstractConnection { + Q_OBJECT + +public: + + MTPabstractTcpConnection(); + +public slots: + + void socketRead(); + +protected: + + QTcpSocket sock; + uint32 packetNum; // sent packet number + + uint32 packetRead, packetLeft; // reading from socket + bool readingToShort; + char *currentPos; + mtpBuffer longBuffer; + mtpPrime shortBuffer[MTPShortBufferSize]; + virtual void socketPacket(mtpPrime *packet, uint32 packetSize) = 0; + +}; + +class MTPautoConnection : public MTPabstractTcpConnection { + Q_OBJECT + +public: + + MTPautoConnection(QThread *thread); + + void sendData(mtpBuffer &buffer); + void disconnectFromServer(); + void connectToServer(const QString &addr, int32 port); + bool isConnected(); + bool needHttpWait(); + + int32 debugState() const; + + QString transport() const; + +public slots: + + void socketError(QAbstractSocket::SocketError e); + void requestFinished(QNetworkReply *reply); + + void onSocketConnected(); + void onSocketDisconnected(); + void onHttpStart(); + +protected: + + void socketPacket(mtpPrime *packet, uint32 packetSize); + +private: + + void tcpSend(mtpBuffer &buffer); + void httpSend(mtpBuffer &buffer); + enum Status { + WaitingBoth = 0, + WaitingHttp, + WaitingTcp, + HttpReady, + UsingHttp, + UsingTcp, + }; + Status status; + MTPint128 tcpNonce, httpNonce; + QTimer httpStartTimer; + + QNetworkAccessManager manager; + QUrl address; + + typedef QSet Requests; + Requests requests; + +}; + +class MTPtcpConnection : public MTPabstractTcpConnection { + Q_OBJECT + +public: + + MTPtcpConnection(QThread *thread); + + void sendData(mtpBuffer &buffer); + void disconnectFromServer(); + void connectToServer(const QString &addr, int32 port); + bool isConnected(); + + int32 debugState() const; + + QString transport() const; + +public slots: + + void socketError(QAbstractSocket::SocketError e); + +protected: + + void socketPacket(mtpPrime *packet, uint32 packetSize); + +}; + +class MTPhttpConnection : public MTPabstractConnection { + Q_OBJECT + +public: + + MTPhttpConnection(QThread *thread); + + void sendData(mtpBuffer &buffer); + void disconnectFromServer(); + void connectToServer(const QString &addr, int32 port); + bool isConnected(); + bool needHttpWait(); + + int32 debugState() const; + + QString transport() const; + +public slots: + + void requestFinished(QNetworkReply *reply); + +private: + + QNetworkAccessManager manager; + QUrl address; + + typedef QSet Requests; + Requests requests; + +}; + +class MTProtoConnectionPrivate : public QObject { + Q_OBJECT + +public: + + MTProtoConnectionPrivate(QThread *thread, MTProtoConnection *owner, MTPSessionData *data, uint32 dc); + ~MTProtoConnectionPrivate(); + + int32 getDC() const; + + int32 getState() const; + QString transport() const; + +signals: + + void needToReceive(); + void needToRestart(); + void stateChanged(qint32 newState); + +public slots: + + void retryByTimer(); + void restartNow(); + void restart(bool maybeBadKey = false); + + void onBadConnection(); + void onOldConnection(); + void onSentSome(uint64 size); + void onReceivedSome(); + + void onError(bool maybeBadKey = false); + void onReadyData(); + void socketStart(bool afterConfig = false); + void onConnected(); + void doDisconnect(); + void doFinish(); + + // Auth key creation packet receive slots + void pqAnswered(); + void dhParamsAnswered(); + void dhClientParamsAnswered(); + + // General packet receive slot, connected to conn->receivedData signal + void handleReceived(); + + // Sessions signals, when we need to send something + void tryToSend(); + + bool updateAuthKey(); + + void sendPing(); + + void onConfigLoaded(); + +private: + + void createConn(); + + mtpMsgId prepareToSend(mtpRequest &request); + + bool sendRequest(mtpRequest &request, bool needAnyResponse); + mtpRequestId wasSent(mtpMsgId msgId) const; + + int32 handleOneReceived(const mtpPrime *from, const mtpPrime *end, uint64 msgId, int32 serverTime, uint64 serverSalt, bool badTime); + mtpBuffer ungzip(const mtpPrime *from, const mtpPrime *end) const; + void handleMsgsStates(const QVector &ids, const string &states, QVector &acked); + + void clearMessages(); + + bool setState(int32 state, int32 ifState = MTProtoConnection::UpdateAlways); + mutable QReadWriteLock stateMutex; + int32 _state; + + uint32 dc; + MTProtoConnection *_owner; + MTPabstractConnection *conn; + + QTimer retryTimer; // exp retry timer + uint32 retryTimeout; + quint64 retryWillFinish; + + QTimer oldConnectionTimer; + bool oldConnection; + + QTimer connCheckTimer; + uint32 receiveDelay; + int64 firstSentAt; + + MTPMsgsAck ackRequest; + QVector *ackRequestData; + + // if badTime received - search for ids in sessionData->haveSent and sessionData->wereAcked and sync time/salt, return true if found + bool requestsFixTimeSalt(const QVector &ids, int32 serverTime, uint64 serverSalt); + + // remove msgs with such ids from sessionData->haveSent, add to sessionData->wereAcked + void requestsAcked(const QVector &ids); + + mtpPingId pingId, toSendPingId; + mtpMsgId pingMsgId; + + mtpRequestId resend(mtpMsgId msgId, uint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false); + + template + void sendRequestNotSecure(const TRequest &request); + + template + bool readResponseNotSecure(TResponse &response); + + bool restarted; + + uint64 keyId; + MTPSessionData *sessionData; + bool myKeyLock; + void lockKey(); + void unlockKey(); + + // Auth key creation fields and methods + struct AuthKeyCreateData { + AuthKeyCreateData() + : retries(0) + , g(0) + , new_nonce(*(MTPint256*)((uchar*)new_nonce_buf)) + , auth_key_aux_hash(*(MTPlong*)((uchar*)new_nonce_buf + 33)) + , req_num(0) + , msgs_sent(0) { + memset(new_nonce_buf, 0, sizeof(new_nonce_buf)); + memset(aesKey, 0, sizeof(aesKey)); + memset(aesIV, 0, sizeof(aesIV)); + memset(auth_key, 0, sizeof(auth_key)); + } + MTPint128 nonce, server_nonce; + uchar new_nonce_buf[41]; // 32 bytes new_nonce + 1 check byte + 8 bytes of auth_key_aux_hash + MTPint256 &new_nonce; + MTPlong &auth_key_aux_hash; + + uint32 retries; + MTPlong retry_id; + + string dh_prime; + int32 g; + string g_a; + + uchar aesKey[32], aesIV[32]; + uint32 auth_key[64]; + MTPlong auth_key_hash; + + uint32 req_num; // sent not encrypted request number + uint32 msgs_sent; + }; + AuthKeyCreateData *authKeyData; + void dhClientParamsSend(); + void authKeyCreated(); + void clearAuthKeyData(); + + QTimer pinger; + +}; diff --git a/Telegram/SourceFiles/mtproto/mtpCoreTypes.h b/Telegram/SourceFiles/mtproto/mtpCoreTypes.h new file mode 100644 index 000000000..595d6b713 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpCoreTypes.h @@ -0,0 +1,1146 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "types.h" +#include + +//#define DEBUG_MTPPRIME + +#ifdef DEBUG_MTPPRIME +class mtpPrime { // for debug visualization, not like int32 :( in default constructor +public: + explicit mtpPrime() : _v(0) { + } + mtpPrime(int32 v) : _v(v) { + } + mtpPrime &operator=(int32 v) { + _v = v; + return (*this); + } + operator int32&() { + return _v; + } + operator const int32 &() const { + return _v; + } +private: + int32 _v; +}; +#else +typedef int32 mtpPrime; +#endif + +typedef int32 mtpRequestId; +typedef uint64 mtpMsgId; +typedef uint64 mtpPingId; + +typedef QVector mtpBuffer; +typedef int32 mtpTypeId; + +class mtpRequestData; +class mtpRequest : public QSharedPointer { +public: + + mtpRequest() { + } + explicit mtpRequest(mtpRequestData *ptr) : QSharedPointer(ptr) { + } + + uint32 size() const; + void write(mtpBuffer &to) const; + + typedef void ResponseType; // don't know real response type =( + +}; + +class mtpRequestData : public mtpBuffer { +public: + // in toSend: = 0 - must send in container, > 0 - can send without container + // in haveSent: = 0 - container with msgIds, > 0 - when was sent + uint64 msDate; + mtpRequestId requestId; + + mtpRequestData(bool/* sure*/) : msDate(0) { + } + + static mtpRequest prepare(uint32 requestSize) { + mtpRequest result(new mtpRequestData(true)); + result->reserve(8 + requestSize + _padding(requestSize)); // 2: salt, 2: session_id, 2: msg_id, 1: seq_no, 1: message_length + result->resize(7); + result->push_back(requestSize << 2); + return result; + } + + static void padding(mtpRequest &request) { + if (request->size() < 9) return; + + uint32 requestSize = ((*request)[7] >> 2), padding = _padding(requestSize), fullSize = 8 + requestSize + padding; // 2: salt, 2: session_id, 2: msg_id, 1: seq_no, 1: message_length + if (uint32(request->size()) != fullSize) { + request->resize(fullSize); + if (padding) { + memset_rand(request->data() + (fullSize - padding), padding * sizeof(mtpPrime)); + } + } + } + + static uint32 messageSize(const mtpRequest &request) { + if (request->size() < 9) return 0; + return 4 + ((*request)[7] >> 2); // 2: msg_id, 1: seq_no, q: message_length + } + + static bool isSentContainer(const mtpRequest &request); // "request-like" wrap for msgIds vector + static bool isStateRequest(const mtpRequest &request); + static bool needAck(const mtpRequest &request); + static bool needAckByType(mtpTypeId type); + +private: + + static uint32 _padding(uint32 requestSize) { + return ((8 + requestSize) & 0x03) ? (4 - ((8 + requestSize) & 0x03)) : 0; + } + +}; + +inline uint32 mtpRequest::size() const { // for template MTP requests and MTPBoxed instanciation + mtpRequestData *value = data(); + if (!value || value->size() < 9) return 0; + return value->at(7); +} + +inline void mtpRequest::write(mtpBuffer &to) const { + mtpRequestData *value = data(); + if (!value || value->size() < 9) return; + uint32 was = to.size(), s = size() / sizeof(mtpPrime); + to.resize(was + s); + memcpy(to.data() + was, value->constData() + 8, s * sizeof(mtpPrime)); +} + +class mtpResponse : public mtpBuffer { +public: + mtpResponse() { + } + mtpResponse(const mtpBuffer &v) : mtpBuffer(v) { + } + mtpResponse &operator=(const mtpBuffer &v) { + mtpBuffer::operator=(v); + return (*this); + } + bool needAck() const { + if (size() < 8) return false; + uint32 seqNo = *(uint32*)(constData() + 6); + return (seqNo & 0x01) ? true : false; + } +}; + +typedef QMap mtpPreRequestMap; +typedef QMap mtpRequestMap; + +class mtpMsgIdsSet : public QMap { +public: + typedef QMap ParentType; + + bool insert(const mtpMsgId &k, bool v) { + ParentType::const_iterator i = constFind(k); + if (i == cend()) { + if (size() >= MTPIdsBufferSize && k < min()) { + MTP_LOG(-1, ("No need to handle - %1 < min = %2").arg(k).arg(min())); + return false; + } else { + ParentType::insert(k, v); + return true; + } + } else { + MTP_LOG(-1, ("No need to handle - %1 already is in map").arg(k)); + return false; + } + } + + mtpMsgId min() const { + return size() ? cbegin().key() : 0; + } + + mtpMsgId max() const { + ParentType::const_iterator e(cend()); + return size() ? (--e).key() : 0; + } +}; + +class mtpRequestIdsMap : public QMap { +public: + typedef QMap ParentType; + + mtpMsgId min() const { + return size() ? cbegin().key() : 0; + } + + mtpMsgId max() const { + ParentType::const_iterator e(cend()); + return size() ? (--e).key() : 0; + } +}; + +typedef QMap mtpResponseMap; + +class mtpErrorUnexpected : public Exception { +public: + mtpErrorUnexpected(mtpTypeId typeId, const QString &type) : Exception(QString("MTP Unexpected type id %1 read in %2").arg(typeId).arg(type), false) { // maybe api changed?.. + } +}; + +class mtpErrorInsufficient : public Exception { +public: + mtpErrorInsufficient() : Exception("MTP Insufficient bytes in input buffer") { + } +}; + +class mtpErrorUninitialized : public Exception { +public: + mtpErrorUninitialized() : Exception("MTP Uninitialized variable write attempt") { + } +}; + +class mtpErrorBadTypeId : public Exception { +public: + mtpErrorBadTypeId(mtpTypeId typeId, const QString &type) : Exception(QString("MTP Bad type id %1 passed to constructor of %2").arg(typeId).arg(type)) { + } +}; + +class mtpErrorWrongTypeId : public Exception { +public: + mtpErrorWrongTypeId(mtpTypeId typeId, mtpTypeId required) : Exception(QString("MTP Wrong type id %1 for this data conversion, must be %2").arg(typeId).arg(required)) { + } +}; + +class mtpErrorKeyNotReady : public Exception { +public: + mtpErrorKeyNotReady(const QString &method) : Exception(QString("MTP Auth key is used in %1 without being created").arg(method)) { + } +}; + +class mtpData { +public: + mtpData() : cnt(1) { + } + mtpData(const mtpData &) : cnt(1) { + } + + mtpData *incr() { + ++cnt; + return this; + } + bool decr() { + return !--cnt; + } + bool needSplit() { + return (cnt > 1); + } + + virtual mtpData *clone() = 0; + virtual ~mtpData() { + } + +private: + uint32 cnt; +}; + +template +class mtpDataImpl : public mtpData { +public: + virtual mtpData *clone() { + return new T(*(T*)this); + } +}; + +class mtpDataOwner { +public: + mtpDataOwner(const mtpDataOwner &v) : data(v.data ? v.data->incr() : 0) { + } + mtpDataOwner &operator=(const mtpDataOwner &v) { + setData(v.data ? v.data->incr() : v.data); + return *this; + } + ~mtpDataOwner() { + if (data && data->decr()) delete data; + } + +protected: + explicit mtpDataOwner(mtpData *_data) : data(_data) { + } + void split() { + if (data && data->needSplit()) { + mtpData *clone = data->clone(); + if (data->decr()) delete data; + data = clone; + } + } + void setData(mtpData *_data) { + if (data != _data) { + if (data && data->decr()) delete data; + data = _data; + } + } + mtpData *data; +}; + +enum { + // core types + mtpc_int = 0xa8509bda, + mtpc_long = 0x22076cba, + mtpc_int128 = 0x4bb5362b, + mtpc_int256 = 0x929c32f, + mtpc_double = 0x2210c154, + mtpc_string = 0xb5286e24, + + mtpc_boolTrue = 0x997275b5, + mtpc_boolFalse = 0xbc799737, + mtpc_vector = 0x1cb5c415, + mtpc_error = 0xc4b9f9bb, + mtpc_null = 0x56730bcc, + + // layers + mtpc_invokeWithLayer1 = 0x53835315, + mtpc_invokeWithLayer2 = 0x289dd1f6, + mtpc_invokeWithLayer3 = 0xb7475268, + mtpc_invokeWithLayer4 = 0xdea0d430, + mtpc_invokeWithLayer5 = 0x417a57ae, + mtpc_invokeWithLayer6 = 0x3a64d54d, + mtpc_invokeWithLayer7 = 0xa5be56d3, + mtpc_invokeWithLayer8 = 0xe9abd9fd, + mtpc_invokeWithLayer9 = 0x76715a63, + mtpc_invokeWithLayer10 = 0x39620c41, + mtpc_invokeWithLayer11 = 0xa6b88fdf, + mtpc_invokeWithLayer12 = 0xdda60d3c, + mtpc_invokeWithLayer13 = 0x427c8ea2, + mtpc_invokeWithLayer14 = 0x2b9b08fa, + + // manually parsed + mtpc_rpc_result = 0xf35c6d01, + mtpc_msg_container = 0x73f1f8dc, +// mtpc_msg_copy = 0xe06046b2, + mtpc_gzip_packed = 0x3072cfa1 +}; +static const int32 mtpc_bytes = mtpc_string; +static const int32 mtpc_core_message = -1; // undefined type, but is used +static const uint32 mtpLayers[] = { + mtpc_invokeWithLayer1, + mtpc_invokeWithLayer2, + mtpc_invokeWithLayer3, + mtpc_invokeWithLayer4, + mtpc_invokeWithLayer5, + mtpc_invokeWithLayer6, + mtpc_invokeWithLayer7, + mtpc_invokeWithLayer8, + mtpc_invokeWithLayer9, + mtpc_invokeWithLayer10, + mtpc_invokeWithLayer11, + mtpc_invokeWithLayer12, + mtpc_invokeWithLayer13, + mtpc_invokeWithLayer14, +}, mtpLayerMax = sizeof(mtpLayers) / sizeof(mtpLayers[0]); + +template +class MTPBoxed : public bareT { +public: + MTPBoxed() { + } + MTPBoxed(const bareT &v) : bareT(v) { + } + MTPBoxed(const MTPBoxed &v) : bareT(v) { + } + MTPBoxed(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) { + read(from, end, cons); + } + + MTPBoxed &operator=(const bareT &v) { + *((bareT*)this) = v; + return *this; + } + MTPBoxed &operator=(const MTPBoxed &v) { + *((bareT*)this) = v; + return *this; + } + + uint32 size() const { + return sizeof(mtpTypeId) + bareT::size(); + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) { + if (from + 1 > end) throw mtpErrorInsufficient(); + cons = (mtpTypeId)*(from++); + bareT::read(from, end, cons); + } + void write(mtpBuffer &to) const { + to.push_back(bareT::type()); + bareT::write(to); + } +}; +template +class MTPBoxed > { + typename T::CantMakeBoxedBoxedType v; +}; + +class MTPint { +public: + int32 v; + + MTPint() { + } + MTPint(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_int) { + read(from, end, cons); + } + + uint32 size() const { + return sizeof(int32); + } + mtpTypeId type() const { + return mtpc_int; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_int) { + if (from + 1 > end) throw mtpErrorInsufficient(); + if (cons != mtpc_int) throw mtpErrorUnexpected(cons, "MTPint"); + v = (int32)*(from++); + } + void write(mtpBuffer &to) const { + to.push_back((mtpPrime)v); + } + +private: + explicit MTPint(int32 val) : v(val) { + } + + friend MTPint MTP_int(int32 v); +}; +inline MTPint MTP_int(int32 v) { + return MTPint(v); +} +typedef MTPBoxed MTPInt; + +inline bool operator==(const MTPint &a, const MTPint &b) { + return a.v == b.v; +} +inline bool operator!=(const MTPint &a, const MTPint &b) { + return a.v != b.v; +} + +class MTPlong { +public: + uint64 v; + + MTPlong() { + } + MTPlong(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_long) { + read(from, end, cons); + } + + uint32 size() const { + return sizeof(uint64); + } + mtpTypeId type() const { + return mtpc_long; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_long) { + if (from + 2 > end) throw mtpErrorInsufficient(); + if (cons != mtpc_long) throw mtpErrorUnexpected(cons, "MTPlong"); + v = (uint64)(((uint32*)from)[0]) | ((uint64)(((uint32*)from)[1]) << 32); + from += 2; + } + void write(mtpBuffer &to) const { + to.push_back((mtpPrime)(v & 0xFFFFFFFFL)); + to.push_back((mtpPrime)(v >> 32)); + } + +private: + explicit MTPlong(uint64 val) : v(val) { + } + + friend MTPlong MTP_long(uint64 v); +}; +inline MTPlong MTP_long(uint64 v) { + return MTPlong(v); +} +typedef MTPBoxed MTPLong; + +inline bool operator==(const MTPlong &a, const MTPlong &b) { + return a.v == b.v; +} +inline bool operator!=(const MTPlong &a, const MTPlong &b) { + return a.v != b.v; +} + +class MTPint128 { +public: + uint64 l; + uint64 h; + + MTPint128() { + } + MTPint128(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_int128) { + read(from, end, cons); + } + + uint32 size() const { + return sizeof(uint64) + sizeof(uint64); + } + mtpTypeId type() const { + return mtpc_int128; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_int128) { + if (from + 4 > end) throw mtpErrorInsufficient(); + if (cons != mtpc_int128) throw mtpErrorUnexpected(cons, "MTPint128"); + l = (uint64)(((uint32*)from)[0]) | ((uint64)(((uint32*)from)[1]) << 32); + h = (uint64)(((uint32*)from)[2]) | ((uint64)(((uint32*)from)[3]) << 32); + from += 4; + } + void write(mtpBuffer &to) const { + to.push_back((mtpPrime)(l & 0xFFFFFFFFL)); + to.push_back((mtpPrime)(l >> 32)); + to.push_back((mtpPrime)(h & 0xFFFFFFFFL)); + to.push_back((mtpPrime)(h >> 32)); + } + +private: + explicit MTPint128(uint64 low, uint64 high) : l(low), h(high) { + } + + friend MTPint128 MTP_int128(uint64 l, uint64 h); +}; +inline MTPint128 MTP_int128(uint64 l, uint64 h) { + return MTPint128(l, h); +} +typedef MTPBoxed MTPInt128; + +inline bool operator==(const MTPint128 &a, const MTPint128 &b) { + return a.l == b.l && a.h == b.h; +} +inline bool operator!=(const MTPint128 &a, const MTPint128 &b) { + return a.l != b.l || a.h != b.h; +} + +class MTPint256 { +public: + MTPint128 l; + MTPint128 h; + + MTPint256() { + } + MTPint256(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_int256) { + read(from, end, cons); + } + + uint32 size() const { + return l.size() + h.size(); + } + mtpTypeId type() const { + return mtpc_int256; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_int256) { + if (cons != mtpc_int256) throw mtpErrorUnexpected(cons, "MTPint256"); + l.read(from, end); + h.read(from, end); + } + void write(mtpBuffer &to) const { + l.write(to); + h.write(to); + } + +private: + explicit MTPint256(MTPint128 low, MTPint128 high) : l(low), h(high) { + } + + friend MTPint256 MTP_int256(const MTPint128 &l, const MTPint128 &h); +}; +inline MTPint256 MTP_int256(const MTPint128 &l, const MTPint128 &h) { + return MTPint256(l, h); +} +typedef MTPBoxed MTPInt256; + +inline bool operator==(const MTPint256 &a, const MTPint256 &b) { + return a.l == b.l && a.h == b.h; +} +inline bool operator!=(const MTPint256 &a, const MTPint256 &b) { + return a.l != b.l || a.h != b.h; +} + +class MTPdouble { +public: + float64 v; + + MTPdouble() { + } + MTPdouble(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_double) { + read(from, end, cons); + } + + uint32 size() const { + return sizeof(float64); + } + mtpTypeId type() const { + return mtpc_double; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_double) { + if (from + 2 > end) throw mtpErrorInsufficient(); + if (cons != mtpc_double) throw mtpErrorUnexpected(cons, "MTPdouble"); + *(uint64*)(&v) = (uint64)(((uint32*)from)[0]) | ((uint64)(((uint32*)from)[1]) << 32); + from += 2; + } + void write(mtpBuffer &to) const { + uint64 iv = *(uint64*)(&v); + to.push_back((mtpPrime)(iv & 0xFFFFFFFFL)); + to.push_back((mtpPrime)(iv >> 32)); + } + +private: + explicit MTPdouble(float64 val) : v(val) { + } + + friend MTPdouble MTP_double(float64 v); +}; +inline MTPdouble MTP_double(float64 v) { + return MTPdouble(v); +} +typedef MTPBoxed MTPDouble; + +inline bool operator==(const MTPdouble &a, const MTPdouble &b) { + return a.v == b.v; +} +inline bool operator!=(const MTPdouble &a, const MTPdouble &b) { + return a.v != b.v; +} + +class MTPDstring : public mtpDataImpl { +public: + MTPDstring() { + } + MTPDstring(const string &val) : v(val) { + } + MTPDstring(const QString &val) : v(val.toUtf8().constData()) { + } + MTPDstring(const QByteArray &val) : v(val.constData(), val.size()) { + } + MTPDstring(const char *val) : v(val) { + } + + string v; +}; + +class MTPstring : private mtpDataOwner { +public: + MTPstring() : mtpDataOwner(new MTPDstring()) { + } + MTPstring(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_string) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDstring &_string() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDstring*)data; + } + const MTPDstring &c_string() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDstring*)data; + } + + uint32 size() const { + uint32 l = c_string().v.length(); + if (l < 254) { + l += 1; + } else { + l += 4; + } + uint32 d = l & 0x03; + if (d) l += (4 - d); + return l; + } + mtpTypeId type() const { + return mtpc_string; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_string) { + if (from + 1 > end) throw mtpErrorInsufficient(); + if (cons != mtpc_string) throw mtpErrorUnexpected(cons, "MTPstring"); + + uint32 l; + const uchar *buf = (const uchar*)from; + if (buf[0] == 254) { + l = (uint32)buf[1] + ((uint32)buf[2] << 8) + ((uint32)buf[3] << 16); + buf += 4; + from += ((l + 4) >> 2) + (((l + 4) & 0x03) ? 1 : 0); + } else { + l = (uint32)buf[0]; + ++buf; + from += ((l + 1) >> 2) + (((l + 1) & 0x03) ? 1 : 0); + } + if (from > end) throw mtpErrorInsufficient(); + + if (!data) setData(new MTPDstring()); + MTPDstring &v(_string()); + v.v.resize(l); + memcpy(&v.v[0], buf, l); + } + void write(mtpBuffer &to) const { + uint32 l = c_string().v.length(), s = l + ((l < 254) ? 1 : 4), was = to.size(); + if (s & 0x03) { + s += 4; + } + s >>= 2; + to.resize(was + s); + char *buf = (char*)&to[was]; + if (l < 254) { + uchar sl = (uchar)l; + *(buf++) = *(char*)(&sl); + } else { + *(buf++) = (char)254; + *(buf++) = (char)(l & 0xFF); + *(buf++) = (char)((l >> 8) & 0xFF); + *(buf++) = (char)((l >> 16) & 0xFF); + } + memcpy(buf, c_string().v.c_str(), l); + } + +private: + explicit MTPstring(MTPDstring *_data) : mtpDataOwner(_data) { + } + + friend MTPstring MTP_string(const string &v); + friend MTPstring MTP_string(const QString &v); + friend MTPstring MTP_string(const QByteArray &v); + friend MTPstring MTP_string(const char *v); +}; +inline MTPstring MTP_string(const string &v) { + return MTPstring(new MTPDstring(v)); +} +inline MTPstring MTP_string(const QString &v) { + return MTPstring(new MTPDstring(v)); +} +inline MTPstring MTP_string(const QByteArray &v) { + return MTPstring(new MTPDstring(v)); +} +inline MTPstring MTP_string(const char *v) { + return MTPstring(new MTPDstring(v)); +} +typedef MTPBoxed MTPString; + +typedef MTPstring MTPbytes; +typedef MTPString MTPBytes; + +inline bool operator==(const MTPstring &a, const MTPstring &b) { + return a.c_string().v == b.c_string().v; +} +inline bool operator!=(const MTPstring &a, const MTPstring &b) { + return a.c_string().v != b.c_string().v; +} + +inline QString qs(const MTPstring &v) { + const string &d(v.c_string().v); + return QString::fromUtf8(d.c_str(), d.length()); +} + +class MTPbool { +public: + bool v; + + MTPbool() { + } + MTPbool(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + read(from, end, cons); + } + + uint32 size() const { + return 0; + } + mtpTypeId type() const { + return v ? mtpc_boolTrue : mtpc_boolFalse; + } + void read(const mtpPrime *& /*from*/, const mtpPrime * /*end*/, mtpTypeId cons) { + switch (cons) { + case mtpc_boolFalse: v = false; break; + case mtpc_boolTrue: v = true; break; + default: throw mtpErrorUnexpected(cons, "MTPbool"); + } + } + void write(mtpBuffer & /*to*/) const { + } + +private: + explicit MTPbool(bool val) : v(val) { + } + + friend MTPbool MTP_bool(bool v); +}; +inline MTPbool MTP_bool(bool v) { + return MTPbool(v); +} +inline MTPbool MTP_boolFalse() { + return MTP_bool(false); +} +inline MTPbool MTP_boolTrue() { + return MTP_bool(true); +} +typedef MTPBoxed MTPBool; + +inline bool operator==(const MTPbool &a, const MTPbool &b) { + return a.v == b.v; +} +inline bool operator!=(const MTPbool &a, const MTPbool &b) { + return a.v != b.v; +} + +template +class MTPDvector : public mtpDataImpl > { +public: + MTPDvector() { + } + MTPDvector(uint32 count) : v(count) { + } + MTPDvector(const QVector &vec) : v(vec) { + } + + typedef QVector VType; + VType v; +}; + + + +template +class MTPvector; +template +MTPvector MTP_vector(uint32 count); + +template +MTPvector MTP_vector(const QVector &v); + +template +class MTPvector : private mtpDataOwner { +public: + MTPvector() : mtpDataOwner(new MTPDvector()) { + } + MTPvector(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_vector) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDvector &_vector() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDvector*)data; + } + const MTPDvector &c_vector() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDvector*)data; + } + + uint32 size() const { + uint32 result(sizeof(uint32)); + for (typename VType::const_iterator i = c_vector().v.cbegin(), e = c_vector().v.cend(); i != e; ++i) { + result += i->size(); + } + return result; + } + mtpTypeId type() const { + return mtpc_vector; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_vector) { + if (from + 1 > end) throw mtpErrorInsufficient(); + if (cons != mtpc_vector) throw mtpErrorUnexpected(cons, "MTPvector"); + uint32 count = (uint32)*(from++); + + if (!data) setData(new MTPDvector()); + MTPDvector &v(_vector()); + v.v.resize(0); + v.v.reserve(count); + for (uint32 i = 0; i < count; ++i) { + v.v.push_back(T(from, end)); + } + } + void write(mtpBuffer &to) const { + to.push_back(c_vector().v.size()); + for (typename VType::const_iterator i = c_vector().v.cbegin(), e = c_vector().v.cend(); i != e; ++i) { + (*i).write(to); + } + } + +private: + explicit MTPvector(MTPDvector *_data) : mtpDataOwner(_data) { + } + + friend MTPvector MTP_vector(uint32 count); + friend MTPvector MTP_vector(const QVector &v); + typedef typename MTPDvector::VType VType; +}; +template +inline MTPvector MTP_vector(uint32 count) { + return MTPvector(new MTPDvector(count)); +} +template +inline MTPvector MTP_vector(const QVector &v) { + return MTPvector(new MTPDvector(v)); +} +template +class MTPVector : public MTPBoxed > { +public: + MTPVector() { + } + MTPVector(uint32 count) : MTPBoxed >(MTP_vector(count)) { + } + MTPVector(const MTPvector &v) : MTPBoxed >(v) { + } + MTPVector(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed >(from, end, cons) { + } +}; + +template +inline bool operator==(const MTPvector &a, const MTPvector &b) { + return a.c_vector().v == b.c_vector().v; +} +template +inline bool operator!=(const MTPvector &a, const MTPvector &b) { + return a.c_vector().v != b.c_vector().v; +} + +class MTPDerror : public mtpDataImpl { +public: + MTPint vcode; + MTPstring vtext; + + MTPDerror() { + } + MTPDerror(MTPint code, MTPString text) : vcode(code), vtext(text) { + } +}; +class MTPerror : private mtpDataOwner { +public: + MTPerror() : mtpDataOwner(0) { + } + MTPerror(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_error) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDerror &_error() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDerror*)data; + } + const MTPDerror &c_error() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDerror*)data; + } + + uint32 size() const { + return c_error().vcode.size() + c_error().vtext.size(); + } + mtpTypeId type() const { + return mtpc_error; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_error) { + if (cons != mtpc_error) throw mtpErrorUnexpected(cons, "MTPerror"); + + if (!data) setData(new MTPDerror()); + MTPDerror &v(_error()); + v.vcode.read(from, end); + v.vtext.read(from, end); + } + void write(mtpBuffer &to) const { + c_error().vcode.write(to); + c_error().vtext.write(to); + } + +private: + explicit MTPerror(MTPDerror *_data) : mtpDataOwner(_data) { + } + + friend MTPerror MTP_error(MTPint code, MTPstring text); +}; +inline MTPerror MTP_error(MTPint code, MTPstring text) { + return MTPerror(new MTPDerror(code, text)); +} +typedef MTPBoxed MTPError; + +class MTPnull { +public: + MTPnull() { + } + MTPnull(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_null) { + read(from, end, cons); + } + + uint32 size() const { + return 0; + } + mtpTypeId type() const { + return mtpc_null; + } + void read(const mtpPrime *& /*from*/, const mtpPrime * /*end*/, mtpTypeId cons = mtpc_null) { + if (cons != mtpc_null) throw mtpErrorUnexpected(cons, "MTPnull"); + } + void write(mtpBuffer & /*to*/) const { + } +}; +inline MTPnull MTP_null() { + return MTPnull(); +} +typedef MTPBoxed MTPNull; + +// Human-readable text serialization +#if (defined _DEBUG || defined _WITH_DEBUG) + +QString mtpTextSerialize(const mtpPrime *&from, const mtpPrime *end, mtpPrime cons = 0, uint32 level = 0, mtpPrime vcons = 0); + +inline QString mtpTextSerializeCore(const mtpPrime *&from, const mtpPrime *end, mtpPrime cons, uint32 level, mtpPrime vcons = 0) { + QString add = QString(" ").repeated(level * 2); + + switch (cons) { + case mtpc_int: { + MTPint value(from, end, cons); + return QString("%1 [INT]").arg(value.v); } + + case mtpc_long: { + MTPlong value(from, end, cons); + return QString("%2 [LONG]").arg(value.v); } + + case mtpc_int128: { + MTPint128 value(from, end, cons); + return QString("%1 * 2^64 + %2 [INT128]").arg(value.h).arg(value.l); } + + case mtpc_int256: { + MTPint256 value(from, end, cons); + return QString("%1 * 2^192 + %2 * 2^128 + %3 * 2^64 + %4 [INT256]").arg(value.h.h).arg(value.h.l).arg(value.l.h).arg(value.l.l); } + + case mtpc_double: { + MTPdouble value(from, end, cons); + return QString("%1 [DOUBLE]").arg(value.v); } + + case mtpc_string: { + MTPstring value(from, end, cons); + QByteArray strUtf8(value.c_string().v.c_str(), value.c_string().v.length()); + QString str = QString::fromUtf8(strUtf8); + if (str.toUtf8() == strUtf8) { + str = QString("\"%1\" [STRING]").arg(str.replace('\\', "\\\\").replace('"', "\\\"").replace('\n', "\\n")); + } else { + str = mb(strUtf8.constData(), strUtf8.size()).str() + QString(" [%1 BYTES]").arg(strUtf8.size()); + } + return str; } + + case mtpc_boolTrue: + case mtpc_boolFalse: { + MTPbool value(from, end, cons); + return (value.v ? "[TRUE]" : "[FALSE]"); } + + case mtpc_vector: { + if (from >= end) { + throw Exception("from >= end in vector"); + } + int32 cnt = *(from++); + QString result; + if (cnt) { + result += "\n" + add; + for (uint32 i = 0; i < cnt; ++i) { + result += " " + mtpTextSerialize(from, end, vcons, level + 1) + ",\n" + add; + } + } else { + result = " "; + } + return QString("[ vector<%1>").arg(vcons) + result + "]"; } + + case mtpc_error: { + QString result; + result += "\n" + add; + result += " code: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " text: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ error" + result + "}"; } + + case mtpc_null: { + QString result; + result = " "; + return "{ null" + result + "}"; } + + case mtpc_rpc_result: { + QString result; + result += "\n" + add; + result += " req_msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " result: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ rpc_result" + result + "}"; } + + case mtpc_msg_container: { + QString result; + result += "\n" + add; + result += " messages: " + mtpTextSerialize(from, end, mtpc_vector, level + 1, mtpc_core_message) + ",\n" + add; + return "{ msg_container" + result + "}"; } + + case mtpc_core_message: { + QString result; + result += "\n" + add; + result += " msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " seq_no: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " body: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ core_message" + result + "}"; } + + case mtpc_gzip_packed: { + MTPstring packed(from, end); // read packed string as serialized mtp string type + uint32 packedLen = packed.c_string().v.size(), unpackedChunk = packedLen, unpackedLen = 0; + mtpBuffer result; // * 4 because of mtpPrime type + result.resize(0); + + z_stream stream; + stream.zalloc = 0; + stream.zfree = 0; + stream.opaque = 0; + stream.avail_in = 0; + stream.next_in = 0; + int res = inflateInit2(&stream, 16 + MAX_WBITS); + if (res != Z_OK) { + throw Exception(QString("ungzip init, code: %1").arg(res)); + } + stream.avail_in = packedLen; + stream.next_in = (Bytef*)&packed._string().v[0]; + stream.avail_out = 0; + while (!stream.avail_out) { + result.resize(result.size() + unpackedChunk); + stream.avail_out = unpackedChunk * sizeof(mtpPrime); + stream.next_out = (Bytef*)&result[result.size() - unpackedChunk]; + int res = inflate(&stream, Z_NO_FLUSH); + if (res != Z_OK && res != Z_STREAM_END) { + inflateEnd(&stream); + throw Exception(QString("ungzip unpack, code: %1").arg(res)); + } + } + if (stream.avail_out & 0x03) { + uint32 badSize = result.size() * sizeof(mtpPrime) - stream.avail_out; + throw Exception(QString("ungzip bad length, size: %1").arg(badSize)); + } + result.resize(result.size() - (stream.avail_out >> 2)); + inflateEnd(&stream); + + if (!result.size()) { + throw Exception("ungzip void data"); + } + const mtpPrime *newFrom = result.constData(), *newEnd = result.constData() + result.size(); + return "[GZIPPED] " + mtpTextSerialize(newFrom, newEnd, 0, level); } + + default: { + for (int i = 1; i < mtpLayerMax; ++i) { + if (cons == mtpLayers[i]) { + return QString("[LAYER%1] ").arg(i + 1) + mtpTextSerialize(from, end, 0, level); + } + } + } + } + + throw Exception(QString("unknown cons %1").arg(cons)); +} + +#endif diff --git a/Telegram/SourceFiles/mtproto/mtpDC.cpp b/Telegram/SourceFiles/mtproto/mtpDC.cpp new file mode 100644 index 000000000..0116805fc --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpDC.cpp @@ -0,0 +1,475 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "mtpDC.h" +#include "mtp.h" + +namespace { + + MTProtoDCMap gDCs; + bool configLoadedOnce = false; + int32 mainDC = 1; + int userId = 0; + mtpDcOptions gDCOptions; + + typedef QMap _KeysMapForWrite; + _KeysMapForWrite _keysMapForWrite; + QMutex _keysMapForWriteMutex; + + int32 readAuthKeysFields(QIODevice *io) { + if (!io->isOpen()) io->open(QIODevice::ReadOnly); + + QDataStream stream(io); + stream.setVersion(QDataStream::Qt_5_1); + + int32 oldFound = 0; + + while (true) { + quint32 blockId; + stream >> blockId; + if (stream.status() == QDataStream::ReadPastEnd) { + DEBUG_LOG(("MTP Info: keys file read end")); + break; + } else if (stream.status() != QDataStream::Ok) { + LOG(("MTP Error: could not read block id, status: %1 - keys file is corrupted?..").arg(stream.status())); + break; + } + + if (blockId == dbiVersion) { + qint32 keysVersion; + stream >> keysVersion; + continue; // should not be in encrypted part, just ignore + } + + if (blockId != dbiEncrypted && blockId != dbiKey) { + oldFound = 2; + } + + switch (blockId) { + case dbiEncrypted: { + QByteArray data, decrypted; + stream >> data; + + if (!MTP::localKey().created()) { + LOG(("MTP Error: reading encrypted keys without local key!")); + continue; + } + + if (data.size() <= 16 || (data.size() & 0x0F)) { + LOG(("MTP Error: bad encrypted part size: %1").arg(data.size())); + continue; + } + uint32 fullDataLen = data.size() - 16; + decrypted.resize(fullDataLen); + const char *dataKey = data.constData(), *encrypted = data.constData() + 16; + aesDecryptLocal(encrypted, decrypted.data(), fullDataLen, &MTP::localKey(), dataKey); + uchar sha1Buffer[20]; + if (memcmp(hashSha1(decrypted.constData(), decrypted.size(), sha1Buffer), dataKey, 16)) { + LOG(("MTP Error: bad decrypt key, data from user-config not decrypted")); + continue; + } + uint32 dataLen = *(const uint32*)decrypted.constData(); + if (dataLen > decrypted.size() || dataLen <= fullDataLen - 16 || dataLen < 4) { + LOG(("MTP Error: bad decrypted part size: %1, fullDataLen: %2, decrypted size: %3").arg(dataLen).arg(fullDataLen).arg(decrypted.size())); + continue; + } + decrypted.resize(dataLen); + QBuffer decryptedStream(&decrypted); + decryptedStream.open(QIODevice::ReadOnly); + decryptedStream.seek(4); // skip size + readAuthKeysFields(&decryptedStream); + } break; + + case dbiKey: { + qint32 dcId; + quint32 key[64]; + stream >> dcId; + stream.readRawData((char*)key, 256); + if (stream.status() == QDataStream::Ok) { + DEBUG_LOG(("MTP Info: key found, dc %1, key: %2").arg(dcId).arg(mb(key, 256).str())); + dcId = dcId % _mtp_internal::dcShift; + mtpAuthKeyPtr keyPtr(new mtpAuthKey()); + keyPtr->setKey(key); + keyPtr->setDC(dcId); + + MTProtoDCPtr dc(new MTProtoDC(dcId, keyPtr)); + gDCs.insert(dcId, dc); + } + } break; + + case dbiUser: { + quint32 dcId; + qint32 uid; + stream >> uid >> dcId; + if (stream.status() == QDataStream::Ok) { + DEBUG_LOG(("MTP Info: user found, dc %1, uid %2").arg(dcId).arg(uid)); + + userId = uid; + mainDC = dcId; + } + } break; + + case dbiDcOption: { + quint32 dcId, port; + QString host, ip; + stream >> dcId >> host >> ip >> port; + + if (stream.status() == QDataStream::Ok) { + gDCOptions.insert(dcId, mtpDcOption(dcId, host.toUtf8().constData(), ip.toUtf8().constData(), port)); + } + } break; + + case dbiConfig1: { + quint32 maxSize; + stream >> maxSize; + if (stream.status() == QDataStream::Ok) { + cSetMaxGroupCount(maxSize); + } + } break; + } + + if (stream.status() != QDataStream::Ok) { + LOG(("MTP Error: could not read data, status: %1 - keys file is corrupted?..").arg(stream.status())); + break; + } + } + + return oldFound; + } + + int32 readAuthKeys(QFile &file) { + QDataStream stream(&file); + stream.setVersion(QDataStream::Qt_5_1); + + int32 oldFound = 0; + quint32 blockId; + stream >> blockId; + if (stream.status() == QDataStream::ReadPastEnd) { + DEBUG_LOG(("MTP Info: keys file read end")); + return oldFound; + } else if (stream.status() != QDataStream::Ok) { + LOG(("MTP Error: could not read block id, status: %1 - keys file is corrupted?..").arg(stream.status())); + return oldFound; + } + + if (blockId == dbiVersion) { + qint32 keysVersion; + stream >> keysVersion; + if (keysVersion > AppVersion) return oldFound; + + stream >> blockId; + if (stream.status() == QDataStream::ReadPastEnd) { + DEBUG_LOG(("MTP Info: keys file read end")); + return oldFound; + } else if (stream.status() != QDataStream::Ok) { + LOG(("MTP Error: could not read block id, status: %1 - keys file is corrupted?..").arg(stream.status())); + return oldFound; + } + if (blockId != dbiEncrypted) { + oldFound = (blockId != dbiKey) ? 2 : 1; + } + } else { + oldFound = 2; + } + + file.reset(); + oldFound = qMax(oldFound, readAuthKeysFields(&file)); + + return oldFound; + } + + void writeAuthKeys(); + void readAuthKeys() { + QFile keysFile(cWorkingDir() + cDataFile()); + if (keysFile.open(QIODevice::ReadOnly)) { + DEBUG_LOG(("MTP Info: keys file opened for reading")); + int32 oldFound = readAuthKeys(keysFile); + + if (gDCOptions.isEmpty() || mainDC && gDCOptions.find(mainDC) == gDCOptions.cend()) { // load first dc info + gDCOptions.insert(1, mtpDcOption(1, "", cFirstDCIp(), cFirstDCPort())); + userId = 0; + mainDC = 0; + DEBUG_LOG(("MTP Info: first DC connect options: %1:%2").arg(cFirstDCIp()).arg(cFirstDCPort())); + } else { + configLoadedOnce = true; + DEBUG_LOG(("MTP Info: config loaded, dc option count: %1").arg(gDCOptions.size())); + } + + if (oldFound > 0) { + writeAuthKeys(); + if (oldFound > 1) { + App::writeUserConfig(); + } + DEBUG_LOG(("MTP Info: rewritten old data / config to new data and config")); + } + } else { + DEBUG_LOG(("MTP Info: could not open keys file for reading")); + gDCOptions.insert(1, mtpDcOption(1, "", cFirstDCIp(), cFirstDCPort())); + DEBUG_LOG(("MTP Info: first DC connect options: %1:%2").arg(cFirstDCIp()).arg(cFirstDCPort())); + } + } + + typedef QVector _KeysToWrite; + void writeAuthKeys() { + _KeysToWrite keysToWrite; + { + QMutexLocker lock(&_keysMapForWriteMutex); + for (_KeysMapForWrite::const_iterator i = _keysMapForWrite.cbegin(), e = _keysMapForWrite.cend(); i != e; ++i) { + keysToWrite.push_back(i.value()); + } + } + + QFile keysFile(cWorkingDir() + cDataFile()); + if (keysFile.open(QIODevice::WriteOnly)) { + DEBUG_LOG(("MTP Info: writing keys data for encrypt")); + QByteArray toEncrypt; + toEncrypt.reserve(65536); + toEncrypt.resize(4); + { + QBuffer buffer(&toEncrypt); + buffer.open(QIODevice::Append); + + QDataStream stream(&buffer); + stream.setVersion(QDataStream::Qt_5_1); + + for (_KeysToWrite::const_iterator i = keysToWrite.cbegin(), e = keysToWrite.cend(); i != e; ++i) { + stream << quint32(dbiKey) << quint32((*i)->getDC()); + (*i)->write(stream); + } + + if (stream.status() != QDataStream::Ok) { + LOG(("MTP Error: could not write keys to memory buf, status: %1").arg(stream.status())); + } + } + *(uint32*)(toEncrypt.data()) = toEncrypt.size(); + + uint32 size = toEncrypt.size(), fullSize = size; + if (fullSize & 0x0F) { + fullSize += 0x10 - (fullSize & 0x0F); + toEncrypt.resize(fullSize); + memset_rand(toEncrypt.data() + size, fullSize - size); + } + QByteArray encrypted(16 + fullSize, Qt::Uninitialized); // 128bit of sha1 - key128, sizeof(data), data + hashSha1(toEncrypt.constData(), toEncrypt.size(), encrypted.data()); + aesEncryptLocal(toEncrypt.constData(), encrypted.data() + 16, fullSize, &MTP::localKey(), encrypted.constData()); + + DEBUG_LOG(("MTP Info: keys file opened for writing %1 keys").arg(keysToWrite.size())); + QDataStream keysStream(&keysFile); + keysStream.setVersion(QDataStream::Qt_5_1); + keysStream << quint32(dbiVersion) << qint32(AppVersion); + + keysStream << quint32(dbiEncrypted) << encrypted; // write all encrypted data + + if (keysStream.status() != QDataStream::Ok) { + LOG(("MTP Error: could not write keys, status: %1").arg(keysStream.status())); + } + } else { + LOG(("MTP Error: could not open keys file for writing")); + } + } + + class _KeysReader { + public: + _KeysReader() { + readAuthKeys(); + } + }; + +} + +void mtpLoadData() { + static _KeysReader keysReader; +} + +int32 mtpAuthed() { + return userId; +} + +void mtpAuthed(int32 uid) { + if (userId != uid && mainDC) { + userId = uid; + App::writeUserConfig(); + } +} + +MTProtoDCMap &mtpDCMap() { + return gDCs; +} + +const mtpDcOptions &mtpDCOptions() { + return gDCOptions; +} + +bool mtpNeedConfig() { + return !configLoadedOnce; +} + +int32 mtpMainDC() { + return mainDC; +} + +void mtpSetDC(int32 dc) { + if (dc != mainDC) { + mainDC = dc; + if (userId) { + App::writeUserConfig(); + } + } +} + +MTProtoDC::MTProtoDC(int32 id, const mtpAuthKeyPtr &key) : _id(id), _key(key), _connectionInited(false), _connectionInitSent(false) { + connect(this, SIGNAL(authKeyCreated()), this, SLOT(authKeyWrite()), Qt::QueuedConnection); + + QMutexLocker lock(&_keysMapForWriteMutex); + if (_key) { + _keysMapForWrite[_id] = _key; + } else { + _keysMapForWrite.remove(_id); + } +} + +void MTProtoDC::authKeyWrite() { + DEBUG_LOG(("AuthKey Info: MTProtoDC::authKeyWrite() slot, dc %1").arg(_id)); + if (_key) { + writeAuthKeys(); + } +} + +void MTProtoDC::setKey(const mtpAuthKeyPtr &key) { + DEBUG_LOG(("AuthKey Info: MTProtoDC::setKey(%1), emitting authKeyCreated, dc %2").arg(key ? key->keyId() : 0).arg(_id)); + _key = key; + emit authKeyCreated(); + + QMutexLocker lock(&_keysMapForWriteMutex); + if (_key) { + _keysMapForWrite[_id] = _key; + } else { + _keysMapForWrite.remove(_id); + } +} + +QReadWriteLock *MTProtoDC::keyMutex() const { + return &keyLock; +} + +const mtpAuthKeyPtr &MTProtoDC::getKey() const { + return _key; +} + +void MTProtoDC::destroyKey() { + setKey(mtpAuthKeyPtr()); + + QMutexLocker lock(&_keysMapForWriteMutex); + _keysMapForWrite.remove(_id); +} + +namespace { + MTProtoConfigLoader configLoader; + bool loadingConfig = false; + void configLoaded(const MTPConfig &result) { + loadingConfig = false; + + const MTPDconfig &data(result.c_config()); + + DEBUG_LOG(("MTP Info: got config, chat_size_max: %1, date: %2, test_mode: %3, this_dc: %4, dc_options.length: %5").arg(data.vchat_size_max.v).arg(data.vdate.v).arg(data.vtest_mode.v).arg(data.vthis_dc.v).arg(data.vdc_options.c_vector().v.size())); + + QSet already; + const QVector &options(data.vdc_options.c_vector().v); + for (QVector::const_iterator i = options.cbegin(), e = options.cend(); i != e; ++i) { + const MTPDdcOption &optData(i->c_dcOption()); + if (already.constFind(optData.vid.v) == already.cend()) { + already.insert(optData.vid.v); + gDCOptions.insert(optData.vid.v, mtpDcOption(optData.vid.v, optData.vhostname.c_string().v, optData.vip_address.c_string().v, optData.vport.v)); + } + } + cSetMaxGroupCount(data.vchat_size_max.v); + + configLoadedOnce = true; + App::writeUserConfig(); + + emit mtpConfigLoader()->loaded(); + } + bool configFailed(const RPCError &err) { + loadingConfig = false; + LOG(("MTP Error: failed to get config!")); + return false; + } +}; + +void MTProtoConfigLoader::load() { + if (loadingConfig) return; + loadingConfig = true; + + MTPhelp_GetConfig request; + MTP::send(request, rpcDone(configLoaded), rpcFail(configFailed)); +} + +MTProtoConfigLoader *mtpConfigLoader() { + return &configLoader; +} + +void mtpWriteConfig(QDataStream &stream) { + if (userId) { + stream << quint32(dbiUser) << qint32(userId) << quint32(mainDC); + } + if (configLoadedOnce) { + for (mtpDcOptions::const_iterator i = gDCOptions.cbegin(), e = gDCOptions.cend(); i != e; ++i) { + stream << quint32(dbiDcOption) << i->id << QString(i->host.c_str()) << QString(i->ip.c_str()) << i->port; + } + stream << quint32(dbiConfig1) << qint32(cMaxGroupCount()); + } +} + +bool mtpReadConfigElem(int32 blockId, QDataStream &stream) { + switch (blockId) { + case dbiUser: { + quint32 dcId; + qint32 uid; + stream >> uid >> dcId; + if (stream.status() == QDataStream::Ok) { + DEBUG_LOG(("MTP Info: user found, dc %1, uid %2").arg(dcId).arg(uid)); + + userId = uid; + mainDC = dcId; + return true; + } + } break; + + case dbiDcOption: { + quint32 dcId, port; + QString host, ip; + stream >> dcId >> host >> ip >> port; + + if (stream.status() == QDataStream::Ok) { + gDCOptions.insert(dcId, mtpDcOption(dcId, host.toUtf8().constData(), ip.toUtf8().constData(), port)); + return true; + } + } break; + + case dbiConfig1: { + quint32 maxSize; + stream >> maxSize; + if (stream.status() == QDataStream::Ok) { + cSetMaxGroupCount(maxSize); + return true; + } + } break; + } + + return false; +} diff --git a/Telegram/SourceFiles/mtproto/mtpDC.h b/Telegram/SourceFiles/mtproto/mtpDC.h new file mode 100644 index 000000000..37b953514 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpDC.h @@ -0,0 +1,109 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +class MTProtoDC : public QObject { + Q_OBJECT + +public: + + MTProtoDC(int32 id, const mtpAuthKeyPtr &key); + + QReadWriteLock *keyMutex() const; + const mtpAuthKeyPtr &getKey() const; + void setKey(const mtpAuthKeyPtr &key); + void destroyKey(); + + bool needConnectionInit() { + QMutexLocker lock(&initLock); + if (_connectionInited || _connectionInitSent) return false; + _connectionInitSent = true; + return true; + } + + bool connectionInited() const { + QMutexLocker lock(&initLock); + bool res = _connectionInited; + return res; + } + void setConnectionInited(bool connectionInited = true) { + QMutexLocker lock(&initLock); + _connectionInited = connectionInited; + } + +signals: + + void authKeyCreated(); + +private slots: + + void authKeyWrite(); + +private: + + mutable QReadWriteLock keyLock; + mutable QMutex initLock; + int32 _id; + mtpAuthKeyPtr _key; + bool _connectionInited; + bool _connectionInitSent; +}; + +typedef QSharedPointer MTProtoDCPtr; +typedef QMap MTProtoDCMap; + +struct mtpDcOption { + mtpDcOption(int _id, const string &_host, const string &_ip, int _port) : id(_id), host(_host), ip(_ip), port(_port) { + } + + int id; + string host; + string ip; + int port; +}; +typedef QMap mtpDcOptions; + +class MTProtoConfigLoader : public QObject { + Q_OBJECT + +public: + + void load(); + +signals: + + void loaded(); + +}; + +MTProtoConfigLoader *mtpConfigLoader(); + +const mtpDcOptions &mtpDCOptions(); +MTProtoDCMap &mtpDCMap(); +bool mtpNeedConfig(); +int32 mtpMainDC(); +void mtpSetDC(int32 dc); +uint32 mtpMaxChatSize(); + +void mtpWriteAuthKeys(); +void mtpLoadData(); +int32 mtpAuthed(); +void mtpAuthed(int32 uid); + +void mtpWriteConfig(QDataStream &stream); +bool mtpReadConfigElem(int32 blockId, QDataStream &stream); diff --git a/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp b/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp new file mode 100644 index 000000000..c6f57145c --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp @@ -0,0 +1,333 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "mainwidget.h" +#include "window.h" + +namespace { + int32 _priority = 1; +} +struct mtpFileLoaderQueue { + mtpFileLoaderQueue() : queries(0), start(0), end(0) { + } + int32 queries; + mtpFileLoader *start, *end; +}; + +namespace { + typedef QMap LoaderQueues; + LoaderQueues queues; +} + +mtpFileLoader::mtpFileLoader(int32 dc, const int64 &volume, int32 local, const int64 &secret) : next(0), prev(0), inQueue(false), complete(false), requestId(0), priority(0), initialSize(0), + dc(dc), volume(volume), local(local), secret(secret), size(0), type(MTP_storage_fileUnknown()), locationType(0), id(0), access(0) { + LoaderQueues::iterator i = queues.find(dc); + if (i == queues.cend()) { + i = queues.insert(dc, mtpFileLoaderQueue()); + } + queue = &i.value(); +} + +mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size) : next(0), prev(0), inQueue(false), complete(false), requestId(0), priority(0), + dc(dc), id(id), access(access), type(MTP_storage_fileUnknown()), locationType(locType), file(to), initialSize(size) { + LoaderQueues::iterator i = queues.find(MTP::dld + dc); + if (i == queues.cend()) { + i = queues.insert(MTP::dld + dc, mtpFileLoaderQueue()); + } + queue = &i.value(); +} + +QString mtpFileLoader::fileName() const { + return file.fileName(); +} + +bool mtpFileLoader::done() const { + return complete; +} + +mtpTypeId mtpFileLoader::fileType() const { + return type.type(); +} + +const QByteArray &mtpFileLoader::bytes() const { + return data; +} + +float64 mtpFileLoader::currentProgress() const { + if (complete) return 1; + if (!fullSize()) return 0; + return float64(currentOffset()) / fullSize(); +} + +int32 mtpFileLoader::currentOffset() const { + return file.isOpen() ? file.size() : data.size(); +} + +int32 mtpFileLoader::fullSize() const { + return size; +} + +uint64 mtpFileLoader::objId() const { + return id; +} + +void mtpFileLoader::loadNext() { + if (queue->queries >= MaxFileQueries) return; + for (mtpFileLoader *i = queue->start; i; i = i->next) { + if (i->loadPart() && queue->queries >= MaxFileQueries) return; + } +} + +void mtpFileLoader::finishFail() { + bool started = currentOffset() > 0; + if (requestId) { + requestId = 0; + --queue->queries; + } + type = MTP_storage_fileUnknown(); + complete = true; + if (file.isOpen()) { + file.close(); + file.remove(); + } + data = QByteArray(); + emit failed(this, started); + file.setFileName(QString()); + loadNext(); +} + +bool mtpFileLoader::loadPart() { + if (complete || requestId) return false; + + int32 limit = DocumentDownloadPartSize; + MTPInputFileLocation loc; + switch (locationType) { + case 0: loc = MTP_inputFileLocation(MTP_long(volume), MTP_int(local), MTP_long(secret)); limit = DownloadPartSize; break; + case mtpc_inputVideoFileLocation: loc = MTP_inputVideoFileLocation(MTP_long(id), MTP_long(access)); break; + case mtpc_inputAudioFileLocation: loc = MTP_inputAudioFileLocation(MTP_long(id), MTP_long(access)); break; + case mtpc_inputDocumentFileLocation: loc = MTP_inputDocumentFileLocation(MTP_long(id), MTP_long(access)); break; + default: + finishFail(); + return false; + break; + } + + ++queue->queries; + int32 offset = currentOffset(); + MTPupload_GetFile request(MTPupload_getFile(loc, MTP_int(offset), MTP_int(limit))); + requestId = MTP::send(request, rpcDone(&mtpFileLoader::partLoaded, offset), rpcFail(&mtpFileLoader::partFailed), MTP::dld + dc, 50); + return true; +} + +void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result) { + if (requestId) { + --queue->queries; + requestId = 0; + } + if (offset == currentOffset()) { + int32 limit = locationType ? DocumentDownloadPartSize : DownloadPartSize; + const MTPDupload_file &d(result.c_upload_file()); + const string &bytes(d.vbytes.c_string().v); + if (bytes.size()) { + if (file.isOpen()) { + if (file.write(bytes.data(), bytes.size()) != bytes.size()) { + return finishFail(); + } + } else { + data.append(bytes.data(), bytes.size()); + } + } + if (bytes.size() && !(bytes.size() % 1024)) { // good next offset +// offset += bytes.size(); + } else { + type = d.vtype; + complete = true; + if (file.isOpen()) { + file.close(); + psPostprocessFile(QFileInfo(file).absoluteFilePath()); + } + removeFromQueue(); + App::wnd()->update(); + App::wnd()->psUpdateNotifies(); + } + emit progress(this); + } + loadNext(); +} + +bool mtpFileLoader::partFailed(const RPCError &error) { + finishFail(); + return true; +} + +void mtpFileLoader::removeFromQueue() { + if (!inQueue) return; + if (next) { + next->prev = prev; + } + if (prev) { + prev->next = next; + } + if (queue->end == this) { + queue->end = prev; + } + if (queue->start == this) { + queue->start = next; + } + next = prev = 0; + inQueue = false; +} + +void mtpFileLoader::pause() { + removeFromQueue(); +} + +void mtpFileLoader::start(bool loadFirst, bool prior) { + if (complete) return; + + if (!file.fileName().isEmpty()) { + if (!file.open(QIODevice::WriteOnly)) { + finishFail(); + return; + } + } + + mtpFileLoader *before = 0, *after = 0; + if (prior) { + if (inQueue && priority == _priority) { + if (loadFirst) { + if (!prev) return started(loadFirst, prior); + before = queue->start; + } else { + if (!next || next->priority < _priority) return started(loadFirst, prior); + after = next; + while (after->next && after->next->priority == _priority) { + after = after->next; + } + } + } else { + priority = _priority; + if (loadFirst) { + if (inQueue && !prev) return started(loadFirst, prior); + before = queue->start; + } else { + if (inQueue) { + if (next && next->priority == _priority) { + after = next; + } else if (prev && prev->priority < _priority) { + before = prev; + while (before->prev && before->prev->priority < _priority) { + before = before->prev; + } + } else { + return started(loadFirst, prior); + } + } else { + if (queue->start && queue->start->priority == _priority) { + after = queue->start; + } else { + before = queue->start; + } + } + if (after) { + while (after->next && after->next->priority == _priority) { + after = after->next; + } + } + } + } + } else { + if (loadFirst) { + if (inQueue && (!prev || prev->priority == _priority)) return started(loadFirst, prior); + before = prev; + while (before->prev && before->prev->priority != _priority) { + before = before->prev; + } + } else { + if (inQueue && !next) return started(loadFirst, prior); + after = queue->end; + } + } + + removeFromQueue(); + + inQueue = true; + if (!queue->start) { + queue->start = queue->end = this; + } else if (before) { + if (before != next) { + prev = before->prev; + next = before; + next->prev = this; + if (prev) { + prev->next = this; + } + if (queue->start->prev) queue->start = queue->start->prev; + } + } else if (after) { + if (after != prev) { + next = after->next; + prev = after; + after->next = this; + if (next) { + next->prev = this; + } + if (queue->end->next) queue->end = queue->end->next; + } + } else { + LOG(("Queue Error: _start && !before && !after")); + } + return started(loadFirst, prior); +} + +void mtpFileLoader::cancel() { + bool started = currentOffset() > 0; + if (requestId) { + requestId = 0; + --queue->queries; + } + type = MTP_storage_fileUnknown(); + complete = true; + if (file.isOpen()) { + file.close(); + file.remove(); + } + data = QByteArray(); + file.setFileName(QString()); + emit progress(this); + loadNext(); +} + +bool mtpFileLoader::loading() const { + return inQueue; +} + +void mtpFileLoader::started(bool loadFirst, bool prior) { + if (queue->queries >= MaxFileQueries && (!loadFirst || !prior) || complete) return; + loadPart(); +} + +mtpFileLoader::~mtpFileLoader() { + removeFromQueue(); +} + +namespace MTP { + void clearLoaderPriorities() { + ++_priority; + } +} diff --git a/Telegram/SourceFiles/mtproto/mtpFileLoader.h b/Telegram/SourceFiles/mtproto/mtpFileLoader.h new file mode 100644 index 000000000..c87c2910d --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpFileLoader.h @@ -0,0 +1,88 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +namespace MTP { + void clearLoaderPriorities(); +} + +struct mtpFileLoaderQueue; +class mtpFileLoader : public QObject, public RPCSender { + Q_OBJECT + +public: + + mtpFileLoader(int32 dc, const int64 &volume, int32 local, const int64 &secret); + mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size); + bool done() const; + mtpTypeId fileType() const; + const QByteArray &bytes() const; + QString fileName() const; + float64 currentProgress() const; + int32 currentOffset() const; + int32 fullSize() const; + + void pause(); + void start(bool loadFirst = false, bool prior = true); + void cancel(); + bool loading() const; + + uint64 objId() const; + + ~mtpFileLoader(); + + mtpFileLoader *prev, *next; + int32 priority; + +signals: + + void progress(mtpFileLoader *loader); + void failed(mtpFileLoader *loader, bool started); + +private: + + mtpFileLoaderQueue *queue; + bool inQueue, complete; + int32 requestId; + void started(bool loadFirst, bool prior); + void removeFromQueue(); + + void loadNext(); + void finishFail(); + bool loadPart(); + void partLoaded(int32 offset, const MTPupload_File &result); + bool partFailed(const RPCError &error); + + int32 dc; + mtpTypeId locationType; // 0 or mtpc_inputVideoFileLocation / mtpc_inputAudioFileLocation / mtpc_inputDocumentFileLocation + + int64 volume; // for photo locations + int32 local; + int64 secret; + + uint64 id; // for other locations + uint64 access; + QFile file; + int32 initialSize; + + QByteArray data; + + int32 size; + MTPstorage_FileType type; + +}; diff --git a/Telegram/SourceFiles/mtproto/mtpPublicRSA.h b/Telegram/SourceFiles/mtproto/mtpPublicRSA.h new file mode 100644 index 000000000..e6342b0a7 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpPublicRSA.h @@ -0,0 +1,82 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +class mtpPublicRSA { +public: + mtpPublicRSA(const char *key) : data(new mtpPublicRSAInner(PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast(key), -1), 0, 0, 0), 0)) { + if (!data->prsa) return; + + int32 nBytes = BN_num_bytes(data->prsa->n); + int32 eBytes = BN_num_bytes(data->prsa->e); + string nStr(nBytes, 0), eStr(eBytes, 0); + BN_bn2bin(data->prsa->n, (uchar*)&nStr[0]); + BN_bn2bin(data->prsa->e, (uchar*)&eStr[0]); + + mtpBuffer tmp; + MTP_string(nStr).write(tmp); + MTP_string(eStr).write(tmp); + + uchar sha1Buffer[20]; + data->fp = *(uint64*)(hashSha1(&tmp[0], tmp.size() * sizeof(mtpPrime), sha1Buffer) + 3); + } + + mtpPublicRSA(const mtpPublicRSA &v) : data(v.data) { + ++data->cnt; + } + + mtpPublicRSA &operator=(const mtpPublicRSA &v) { + if (data != v.data) { + destroy(); + data = v.data; + ++data->cnt; + } + return *this; + } + + uint64 fingerPrint() const { + return data->fp; + } + + RSA *key() { + return data->prsa; + } + + ~mtpPublicRSA() { + destroy(); + } + +private: + void destroy() { + if (!--data->cnt) { + delete data; + } + } + + struct mtpPublicRSAInner { + mtpPublicRSAInner(RSA *_prsa, uint64 _fp) : prsa(_prsa), fp(_fp), cnt(1) { + } + ~mtpPublicRSAInner() { + RSA_free(prsa); + } + RSA *prsa; + uint32 cnt; + uint64 fp; + }; + mtpPublicRSAInner *data; +}; diff --git a/Telegram/SourceFiles/mtproto/mtpRPC.cpp b/Telegram/SourceFiles/mtproto/mtpRPC.cpp new file mode 100644 index 000000000..b2d01e005 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpRPC.cpp @@ -0,0 +1,35 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "mtproto/mtpRPC.h" + +RPCOwnedDoneHandler::RPCOwnedDoneHandler(RPCSender *owner) : _owner(owner) { + _owner->regHandler(this); +} + +RPCOwnedDoneHandler::~RPCOwnedDoneHandler() { + if (_owner) _owner->unregHandler(this); +} + +RPCOwnedFailHandler::RPCOwnedFailHandler(RPCSender *owner) : _owner(owner) { + _owner->regHandler(this); +} + +RPCOwnedFailHandler::~RPCOwnedFailHandler() { + if (_owner) _owner->unregHandler(this); +} diff --git a/Telegram/SourceFiles/mtproto/mtpRPC.h b/Telegram/SourceFiles/mtproto/mtpRPC.h new file mode 100644 index 000000000..fdf3d8e26 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpRPC.h @@ -0,0 +1,790 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +class RPCError { +public: + + RPCError(const MTPrpcError &error) : _code(error.c_rpc_error().verror_code.v) { + const string &msg(error.c_rpc_error().verror_message.c_string().v); + const QString &text(QString::fromUtf8(msg.c_str(), msg.length())); + QRegularExpressionMatch m = QRegularExpression("^([A-Z0-9_]+)(: .*)?$", reMultiline).match(text); + if (m.hasMatch()) { + _type = m.captured(1); + _description = m.captured(2).mid(2); + } else { + _type = "CLIENT_BAD_RPC_ERROR"; + _description = "Bad rpc error received, text = '" + text + "'"; + } + } + + int32 code() const { + return _code; + } + + const QString &type() const { + return _type; + } + + const QString &description() const { + return _description; + } + + enum { + NoError, + TimeoutError + }; + +private: + + int32 _code; + QString _type, _description; +}; + +class RPCAbstractDoneHandler { // abstract done +public: + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const = 0; + virtual ~RPCAbstractDoneHandler() { + } +}; +typedef QSharedPointer RPCDoneHandlerPtr; + +class RPCAbstractFailHandler { // abstract fail +public: + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const = 0; + virtual ~RPCAbstractFailHandler() { + } +}; +typedef QSharedPointer RPCFailHandlerPtr; + +struct RPCResponseHandler { + RPCResponseHandler() { + } + RPCResponseHandler(const RPCDoneHandlerPtr &ondone, const RPCFailHandlerPtr &onfail) : onDone(ondone), onFail(onfail) { + } + + RPCDoneHandlerPtr onDone; + RPCFailHandlerPtr onFail; +}; +inline RPCResponseHandler rpcCb(const RPCDoneHandlerPtr &onDone = RPCDoneHandlerPtr(), const RPCFailHandlerPtr &onFail = RPCFailHandlerPtr()) { + return RPCResponseHandler(onDone, onFail); +} + +template +class RPCDoneHandlerBare : public RPCAbstractDoneHandler { // done(from, end) + typedef TReturn (*CallbackType)(const mtpPrime *, const mtpPrime *); + +public: + RPCDoneHandlerBare(CallbackType onDone) : _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + (*_onDone)(from, end); + } + +private: + CallbackType _onDone; + +}; + +template +class RPCDoneHandlerBareReq : public RPCAbstractDoneHandler { // done(from, end, req_id) + typedef TReturn (*CallbackType)(const mtpPrime *, const mtpPrime *, mtpRequestId); + +public: + RPCDoneHandlerBareReq(CallbackType onDone) : _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + (*_onDone)(from, end, requestId); + } + +private: + CallbackType _onDone; + +}; + +template +class RPCDoneHandlerPlain : public RPCAbstractDoneHandler { // done(result) + typedef TReturn (*CallbackType)(const TResponse &); + +public: + RPCDoneHandlerPlain(CallbackType onDone) : _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + (*_onDone)(TResponse(from, end)); + } + +private: + CallbackType _onDone; + +}; + +template +class RPCDoneHandlerReq : public RPCAbstractDoneHandler { // done(result, req_id) + typedef TReturn (*CallbackType)(const TResponse &, mtpRequestId); + +public: + RPCDoneHandlerReq(CallbackType onDone) : _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + (*_onDone)(TResponse(from, end), requestId); + } + +private: + CallbackType _onDone; + +}; + +template +class RPCDoneHandlerNo : public RPCAbstractDoneHandler { // done() + typedef TReturn (*CallbackType)(); + +public: + RPCDoneHandlerNo(CallbackType onDone) : _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + (*_onDone)(); + } + +private: + CallbackType _onDone; + +}; + +template +class RPCDoneHandlerNoReq : public RPCAbstractDoneHandler { // done(req_id) + typedef TReturn (*CallbackType)(mtpRequestId); + +public: + RPCDoneHandlerNoReq(CallbackType onDone) : _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + (*_onDone)(requestId); + } + +private: + CallbackType _onDone; + +}; + +class RPCFailHandlerPlain : public RPCAbstractFailHandler { // fail(error) + typedef bool (*CallbackType)(const RPCError &); + +public: + RPCFailHandlerPlain(CallbackType onFail) : _onFail(onFail) { + } + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const { + return (*_onFail)(e); + } + +private: + CallbackType _onFail; + +}; + +class RPCFailHandlerReq : public RPCAbstractFailHandler { // fail(error, req_id) + typedef bool (*CallbackType)(const RPCError &, mtpRequestId); + +public: + RPCFailHandlerReq(CallbackType onFail) : _onFail(onFail) { + } + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const { + return (*_onFail)(e, requestId); + } + +private: + CallbackType _onFail; + +}; + +class RPCFailHandlerNo : public RPCAbstractFailHandler { // fail() + typedef bool (*CallbackType)(); + +public: + RPCFailHandlerNo(CallbackType onFail) : _onFail(onFail) { + } + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const { + return (*_onFail)(); + } + +private: + CallbackType _onFail; + +}; + +class RPCFailHandlerNoReq : public RPCAbstractFailHandler { // fail(req_id) + typedef bool (*CallbackType)(mtpRequestId); + +public: + RPCFailHandlerNoReq(CallbackType onFail) : _onFail(onFail) { + } + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const { + return (*_onFail)(requestId); + } + +private: + CallbackType _onFail; + +}; + +struct RPCCallbackClear { + RPCCallbackClear(mtpRequestId id = 0, int32 code = RPCError::NoError) : requestId(id), errorCode(code) { + } + + mtpRequestId requestId; + int32 errorCode; +}; +typedef QVector RPCCallbackClears; + +template +inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)(const mtpPrime *, const mtpPrime *)) { // done(from, end) + return RPCDoneHandlerPtr(new RPCDoneHandlerBare(onDone)); +} + +template +inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)(const mtpPrime *, const mtpPrime *, mtpRequestId)) { // done(from, end, req_id) + return RPCDoneHandlerPtr(new RPCDoneHandlerBareReq(onDone)); +} + +template +inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)(const TResponse &)) { // done(result) + return RPCDoneHandlerPtr(new RPCDoneHandlerPlain(onDone)); +} + +template +inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)(const TResponse &, mtpRequestId)) { // done(result, req_id) + return RPCDoneHandlerPtr(new RPCDoneHandlerReq(onDone)); +} + +template +inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)()) { // done() + return RPCDoneHandlerPtr(new RPCDoneHandlerNo(onDone)); +} + +template +inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)(mtpRequestId)) { // done(req_id) + return RPCDoneHandlerPtr(new RPCDoneHandlerNoReq(onDone)); +} + +inline RPCFailHandlerPtr rpcFail(bool (*onFail)(const RPCError &)) { // fail(error) + return RPCFailHandlerPtr(new RPCFailHandlerPlain(onFail)); +} + +inline RPCFailHandlerPtr rpcFail(bool (*onFail)(const RPCError &, mtpRequestId)) { // fail(error, req_id) + return RPCFailHandlerPtr(new RPCFailHandlerReq(onFail)); +} + +inline RPCFailHandlerPtr rpcFail(bool (*onFail)()) { // fail() + return RPCFailHandlerPtr(new RPCFailHandlerNo(onFail)); +} + +inline RPCFailHandlerPtr rpcFail(bool (*onFail)(mtpRequestId)) { // fail(req_id) + return RPCFailHandlerPtr(new RPCFailHandlerNoReq(onFail)); +} + +class RPCSender; + +class RPCOwnedDoneHandler : public RPCAbstractDoneHandler { // abstract done +public: + RPCOwnedDoneHandler(RPCSender *owner); + void invalidate() { + _owner = 0; + } + ~RPCOwnedDoneHandler(); + +protected: + RPCSender *_owner; +}; + +class RPCOwnedFailHandler : public RPCAbstractFailHandler { // abstract fail +public: + RPCOwnedFailHandler(RPCSender *owner); + void invalidate() { + _owner = 0; + } + ~RPCOwnedFailHandler(); + +protected: + RPCSender *_owner; +}; + +template +class RPCDoneHandlerBareOwned : public RPCOwnedDoneHandler { // done(from, end) + typedef TReturn (TReceiver::*CallbackType)(const mtpPrime *, const mtpPrime *); + +public: + RPCDoneHandlerBareOwned(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + if (_owner) (static_cast(_owner)->*_onDone)(from, end); + } + +private: + CallbackType _onDone; + +}; + +template +class RPCDoneHandlerBareOwnedReq : public RPCOwnedDoneHandler { // done(from, end, req_id) + typedef TReturn (TReceiver::*CallbackType)(const mtpPrime *, const mtpPrime *, mtpRequestId); + +public: + RPCDoneHandlerBareOwnedReq(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + if (_owner) (static_cast(_owner)->*_onDone)(from, end, requestId); + } + +private: + CallbackType _onDone; + +}; + +template +class RPCDoneHandlerOwned : public RPCOwnedDoneHandler { // done(result) + typedef TReturn (TReceiver::*CallbackType)(const TResponse &); + +public: + RPCDoneHandlerOwned(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + if (_owner) (static_cast(_owner)->*_onDone)(TResponse(from, end)); + } + +private: + CallbackType _onDone; + +}; + +template +class RPCDoneHandlerOwnedReq : public RPCOwnedDoneHandler { // done(result, req_id) + typedef TReturn (TReceiver::*CallbackType)(const TResponse &, mtpRequestId); + +public: + RPCDoneHandlerOwnedReq(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + if (_owner) (static_cast(_owner)->*_onDone)(TResponse(from, end), requestId); + } + +private: + CallbackType _onDone; + +}; + +template +class RPCDoneHandlerOwnedNo : public RPCOwnedDoneHandler { // done() + typedef TReturn (TReceiver::*CallbackType)(); + +public: + RPCDoneHandlerOwnedNo(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + if (_owner) (static_cast(_owner)->*_onDone)(); + } + +private: + CallbackType _onDone; + +}; + +template +class RPCDoneHandlerOwnedNoReq : public RPCOwnedDoneHandler { // done(req_id) + typedef TReturn (TReceiver::*CallbackType)(mtpRequestId); + +public: + RPCDoneHandlerOwnedNoReq(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + if (_owner) (static_cast(_owner)->*_onDone)(requestId); + } + +private: + CallbackType _onDone; + +}; + +template +class RPCBindedDoneHandlerBareOwned : public RPCOwnedDoneHandler { // done(b, from, end) + typedef TReturn (TReceiver::*CallbackType)(T, const mtpPrime *, const mtpPrime *); + +public: + RPCBindedDoneHandlerBareOwned(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _b(b), _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + if (_owner) (static_cast(_owner)->*_onDone)(_b, from, end); + } + +private: + CallbackType _onDone; + T _b; + +}; + +template +class RPCBindedDoneHandlerBareOwnedReq : public RPCOwnedDoneHandler { // done(b, from, end, req_id) + typedef TReturn (TReceiver::*CallbackType)(T, const mtpPrime *, const mtpPrime *, mtpRequestId); + +public: + RPCBindedDoneHandlerBareOwnedReq(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _b(b), _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + if (_owner) (static_cast(_owner)->*_onDone)(_b, from, end, requestId); + } + +private: + CallbackType _onDone; + T _b; + +}; + +template +class RPCBindedDoneHandlerOwned : public RPCOwnedDoneHandler { // done(b, result) + typedef TReturn (TReceiver::*CallbackType)(T, const TResponse &); + +public: + RPCBindedDoneHandlerOwned(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _b(b), _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + if (_owner) (static_cast(_owner)->*_onDone)(_b, TResponse(from, end)); + } + +private: + CallbackType _onDone; + T _b; + +}; + +template +class RPCBindedDoneHandlerOwnedReq : public RPCOwnedDoneHandler { // done(b, result, req_id) + typedef TReturn (TReceiver::*CallbackType)(T, const TResponse &, mtpRequestId); + +public: + RPCBindedDoneHandlerOwnedReq(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _b(b), _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + if (_owner) (static_cast(_owner)->*_onDone)(_b, TResponse(from, end), requestId); + } + +private: + CallbackType _onDone; + T _b; + +}; + +template +class RPCBindedDoneHandlerOwnedNo : public RPCOwnedDoneHandler { // done(b) + typedef TReturn (TReceiver::*CallbackType)(T); + +public: + RPCBindedDoneHandlerOwnedNo(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _b(b), _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + if (_owner) (static_cast(_owner)->*_onDone)(_b); + } + +private: + CallbackType _onDone; + T _b; + +}; + +template +class RPCBindedDoneHandlerOwnedNoReq : public RPCOwnedDoneHandler { // done(b, req_id) + typedef TReturn (TReceiver::*CallbackType)(T, mtpRequestId); + +public: + RPCBindedDoneHandlerOwnedNoReq(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _b(b), _onDone(onDone) { + } + virtual void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + if (_owner) (static_cast(_owner)->*_onDone)(_b, requestId); + } + +private: + CallbackType _onDone; + T _b; + +}; + +template +class RPCFailHandlerOwned : public RPCOwnedFailHandler { // fail(error) + typedef bool (TReceiver::*CallbackType)(const RPCError &); + +public: + RPCFailHandlerOwned(TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _onFail(onFail) { + } + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const { + return _owner ? (static_cast(_owner)->*_onFail)(e) : true; + } + +private: + CallbackType _onFail; + +}; + +template +class RPCFailHandlerOwnedReq : public RPCOwnedFailHandler { // fail(error, req_id) + typedef bool (TReceiver::*CallbackType)(const RPCError &, mtpRequestId); + +public: + RPCFailHandlerOwnedReq(TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _onFail(onFail) { + } + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const { + return _owner ? (static_cast(_owner)->*_onFail)(e, requestId) : true; + } + +private: + CallbackType _onFail; + +}; + +template +class RPCFailHandlerOwnedNo : public RPCOwnedFailHandler { // fail() + typedef bool (TReceiver::*CallbackType)(); + +public: + RPCFailHandlerOwnedNo(TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _onFail(onFail) { + } + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const { + return _owner ? (static_cast(_owner)->*_onFail)() : true; + } + +private: + CallbackType _onFail; + +}; + +template +class RPCFailHandlerOwnedNoReq : public RPCOwnedFailHandler { // fail(req_id) + typedef bool (TReceiver::*CallbackType)(mtpRequestId); + +public: + RPCFailHandlerOwnedNoReq(TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _onFail(onFail) { + } + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const { + return _owner ? (static_cast(_owner)->*_onFail)(requestId) : true; + } + +private: + CallbackType _onFail; + +}; + +template +class RPCBindedFailHandlerOwned : public RPCOwnedFailHandler { // fail(b, error) + typedef bool (TReceiver::*CallbackType)(T, const RPCError &); + +public: + RPCBindedFailHandlerOwned(T b, TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _b(b), _onFail(onFail) { + } + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const { + return _owner ? (static_cast(_owner)->*_onFail)(_b, e) : true; + } + +private: + CallbackType _onFail; + T _b; + +}; + +template +class RPCBindedFailHandlerOwnedReq : public RPCOwnedFailHandler { // fail(b, error, req_id) + typedef bool (TReceiver::*CallbackType)(T, const RPCError &, mtpRequestId); + +public: + RPCBindedFailHandlerOwnedReq(T b, TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _b(b), _onFail(onFail) { + } + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const { + return _owner ? (static_cast(_owner)->*_onFail)(_b, e, requestId) : true; + } + +private: + CallbackType _onFail; + T _b; + +}; + +template +class RPCBindedFailHandlerOwnedNo : public RPCOwnedFailHandler { // fail(b) + typedef bool (TReceiver::*CallbackType)(T); + +public: + RPCBindedFailHandlerOwnedNo(T b, TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _b(b), _onFail(onFail) { + } + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const { + return _owner ? (static_cast(_owner)->*_onFail)(_b) : true; + } + +private: + CallbackType _onFail; + T _b; + +}; + +template +class RPCBindedFailHandlerOwnedNoReq : public RPCOwnedFailHandler { // fail(b, req_id) + typedef bool (TReceiver::*CallbackType)(T, mtpRequestId); + +public: + RPCBindedFailHandlerOwnedNoReq(T b, TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _b(b), _onFail(onFail) { + } + virtual bool operator()(mtpRequestId requestId, const RPCError &e) const { + return _owner ? (static_cast(_owner)->*_onFail)(_b, requestId) : true; + } + +private: + CallbackType _onFail; + T _b; + +}; + +class RPCSender { + typedef QSet DoneHandlers; + DoneHandlers doneHandlers; + typedef QSet FailHandlers; + FailHandlers failHandlers; + +public: + + template // done(from, end) + RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(const mtpPrime *, const mtpPrime *)) { + return RPCDoneHandlerPtr(new RPCDoneHandlerBareOwned(static_cast(this), onDone)); + } + + template // done(from, end, req_id) + RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(const mtpPrime *, const mtpPrime *, mtpRequestId)) { + return RPCDoneHandlerPtr(new RPCDoneHandlerBareOwnedReq(static_cast(this), onDone)); + } + + template // done(result) + RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(const TResponse &)) { + return RPCDoneHandlerPtr(new RPCDoneHandlerOwned(static_cast(this), onDone)); + } + + template // done(result, req_id) + RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(const TResponse &, mtpRequestId)) { + return RPCDoneHandlerPtr(new RPCDoneHandlerOwnedReq(static_cast(this), onDone)); + } + + template // done() + RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)()) { + return RPCDoneHandlerPtr(new RPCDoneHandlerOwnedNo(static_cast(this), onDone)); + } + + template // done(req_id) + RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(mtpRequestId)) { + return RPCDoneHandlerPtr(new RPCDoneHandlerOwnedNoReq(static_cast(this), onDone)); + } + + template // fail(error) + RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(const RPCError &)) { + return RPCFailHandlerPtr(new RPCFailHandlerOwned(static_cast(this), onFail)); + } + + template // fail(error, req_id) + RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(const RPCError &, mtpRequestId)) { + return RPCFailHandlerPtr(new RPCFailHandlerOwnedReq(static_cast(this), onFail)); + } + + template // fail() + RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)()) { + return RPCFailHandlerPtr(new RPCFailHandlerOwnedNo(static_cast(this), onFail)); + } + + template // fail(req_id) + RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(mtpRequestId)) { + return RPCFailHandlerPtr(new RPCFailHandlerOwnedNo(static_cast(this), onFail)); + } + + template // done(b, from, end) + RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(T, const mtpPrime *, const mtpPrime *), T b) { + return RPCDoneHandlerPtr(new RPCBindedDoneHandlerBareOwned(b, static_cast(this), onDone)); + } + + template // done(b, from, end, req_id) + RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(T, const mtpPrime *, const mtpPrime *, mtpRequestId), T b) { + return RPCDoneHandlerPtr(new RPCBindedDoneHandlerBareOwnedReq(b, static_cast(this), onDone)); + } + + template // done(b, result) + RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(T, const TResponse &), T b) { + return RPCDoneHandlerPtr(new RPCBindedDoneHandlerOwned(b, static_cast(this), onDone)); + } + + template // done(b, result, req_id) + RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(T, const TResponse &, mtpRequestId), T b) { + return RPCDoneHandlerPtr(new RPCBindedDoneHandlerOwnedReq(b, static_cast(this), onDone)); + } + + template // done(b) + RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(T), T b) { + return RPCDoneHandlerPtr(new RPCBindedDoneHandlerOwnedNo(b, static_cast(this), onDone)); + } + + template // done(b, req_id) + RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(T, mtpRequestId), T b) { + return RPCDoneHandlerPtr(new RPCBindedDoneHandlerOwnedNoReq(b, static_cast(this), onDone)); + } + + template // fail(b, error) + RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(T, const RPCError &), T b) { + return RPCFailHandlerPtr(new RPCBindedFailHandlerOwned(b, static_cast(this), onFail)); + } + + template // fail(b, error, req_id) + RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(T, const RPCError &, mtpRequestId), T b) { + return RPCFailHandlerPtr(new RPCBindedFailHandlerOwnedReq(b, static_cast(this), onFail)); + } + + template // fail(b) + RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(T), T b) { + return RPCFailHandlerPtr(new RPCBindedFailHandlerOwnedNo(b, static_cast(this), onFail)); + } + + template // fail(b, req_id) + RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(T, mtpRequestId), T b) { + return RPCFailHandlerPtr(new RPCBindedFailHandlerOwnedNo(b, static_cast(this), onFail)); + } + + void regHandler(RPCOwnedDoneHandler *handler) { + doneHandlers.insert(handler); + } + + void unregHandler(RPCOwnedDoneHandler *handler) { + doneHandlers.remove(handler); + } + + void regHandler(RPCOwnedFailHandler *handler) { + failHandlers.insert(handler); + } + + void unregHandler(RPCOwnedFailHandler *handler) { + failHandlers.remove(handler); + } + + ~RPCSender() { + for (DoneHandlers::iterator i = doneHandlers.begin(), e = doneHandlers.end(); i != e; ++i) { + (*i)->invalidate(); + } + for (FailHandlers::iterator i = failHandlers.begin(), e = failHandlers.end(); i != e; ++i) { + (*i)->invalidate(); + } + } + +}; + +typedef void (*MTPStateChangedHandler)(int32 dcId, int32 state); diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.h b/Telegram/SourceFiles/mtproto/mtpScheme.h new file mode 100644 index 000000000..53c1c5fca --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpScheme.h @@ -0,0 +1,24565 @@ +/* +Created from '/SourceFiles/mtproto/scheme.tl' by '/SourceFiles/mtproto/generate.py' script + +WARNING! All changes made in this file will be lost! + +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "mtpCoreTypes.h" + +// Type id constants +enum { + mtpc_resPQ = 0x05162463, + mtpc_p_q_inner_data = 0x83c95aec, + mtpc_server_DH_params_fail = 0x79cb045d, + mtpc_server_DH_params_ok = 0xd0e8075c, + mtpc_server_DH_inner_data = 0xb5890dba, + mtpc_client_DH_inner_data = 0x6643b654, + mtpc_dh_gen_ok = 0x3bcbf734, + mtpc_dh_gen_retry = 0x46dc1fb9, + mtpc_dh_gen_fail = 0xa69dae02, + mtpc_req_pq = 0x60469778, + mtpc_req_DH_params = 0xd712e4be, + mtpc_set_client_DH_params = 0xf5045f1f, + mtpc_msgs_ack = 0x62d6b459, + mtpc_bad_msg_notification = 0xa7eff811, + mtpc_bad_server_salt = 0xedab447b, + mtpc_msgs_state_req = 0xda69fb52, + mtpc_msgs_state_info = 0x04deb57d, + mtpc_msgs_all_info = 0x8cc0d131, + mtpc_msg_detailed_info = 0x276d3ec6, + mtpc_msg_new_detailed_info = 0x809db6df, + mtpc_msg_resend_req = 0x7d861a08, + mtpc_rpc_error = 0x2144ca19, + mtpc_rpc_answer_unknown = 0x5e2ad36e, + mtpc_rpc_answer_dropped_running = 0xcd78e586, + mtpc_rpc_answer_dropped = 0xa43ad8b7, + mtpc_future_salt = 0x0949d9dc, + mtpc_future_salts = 0xae500895, + mtpc_pong = 0x347773c5, + mtpc_destroy_session_ok = 0xe22045fc, + mtpc_destroy_session_none = 0x62d350c9, + mtpc_new_session_created = 0x9ec20908, + mtpc_http_wait = 0x9299359f, + mtpc_rpc_drop_answer = 0x58e4a740, + mtpc_get_future_salts = 0xb921bd04, + mtpc_ping = 0x7abe77ec, + mtpc_ping_delay_disconnect = 0xf3427b8c, + mtpc_destroy_session = 0xe7512126, + mtpc_register_saveDeveloperInfo = 0x9a5f6e95, + mtpc_inputPeerEmpty = 0x7f3b18ea, + mtpc_inputPeerSelf = 0x7da07ec9, + mtpc_inputPeerContact = 0x1023dbe8, + mtpc_inputPeerForeign = 0x9b447325, + mtpc_inputPeerChat = 0x179be863, + mtpc_inputUserEmpty = 0xb98886cf, + mtpc_inputUserSelf = 0xf7c1b13f, + mtpc_inputUserContact = 0x86e94f65, + mtpc_inputUserForeign = 0x655e74ff, + mtpc_inputPhoneContact = 0xf392b7f4, + mtpc_inputFile = 0xf52ff27f, + mtpc_inputMediaEmpty = 0x9664f57f, + mtpc_inputMediaUploadedPhoto = 0x2dc53a7d, + mtpc_inputMediaPhoto = 0x8f2ab2ec, + mtpc_inputMediaGeoPoint = 0xf9c44144, + mtpc_inputMediaContact = 0xa6e45987, + mtpc_inputMediaUploadedVideo = 0x133ad6f6, + mtpc_inputMediaUploadedThumbVideo = 0x9912dabf, + mtpc_inputMediaVideo = 0x7f023ae6, + mtpc_inputChatPhotoEmpty = 0x1ca48f57, + mtpc_inputChatUploadedPhoto = 0x94254732, + mtpc_inputChatPhoto = 0xb2e1bf08, + mtpc_inputGeoPointEmpty = 0xe4c123d6, + mtpc_inputGeoPoint = 0xf3b7acc9, + mtpc_inputPhotoEmpty = 0x1cd7bf0d, + mtpc_inputPhoto = 0xfb95c6c4, + mtpc_inputVideoEmpty = 0x5508ec75, + mtpc_inputVideo = 0xee579652, + mtpc_inputFileLocation = 0x14637196, + mtpc_inputVideoFileLocation = 0x3d0364ec, + mtpc_inputPhotoCropAuto = 0xade6b004, + mtpc_inputPhotoCrop = 0xd9915325, + mtpc_inputAppEvent = 0x770656a8, + mtpc_peerUser = 0x9db1bc6d, + mtpc_peerChat = 0xbad0e5bb, + mtpc_storage_fileUnknown = 0xaa963b05, + mtpc_storage_fileJpeg = 0x7efe0e, + mtpc_storage_fileGif = 0xcae1aadf, + mtpc_storage_filePng = 0xa4f63c0, + mtpc_storage_filePdf = 0xae1e508d, + mtpc_storage_fileMp3 = 0x528a0677, + mtpc_storage_fileMov = 0x4b09ebbc, + mtpc_storage_filePartial = 0x40bc6f52, + mtpc_storage_fileMp4 = 0xb3cea0e4, + mtpc_storage_fileWebp = 0x1081464c, + mtpc_fileLocationUnavailable = 0x7c596b46, + mtpc_fileLocation = 0x53d69076, + mtpc_userEmpty = 0x200250ba, + mtpc_userSelf = 0x720535ec, + mtpc_userContact = 0xf2fb8319, + mtpc_userRequest = 0x22e8ceb0, + mtpc_userForeign = 0x5214c89d, + mtpc_userDeleted = 0xb29ad7cc, + mtpc_userProfilePhotoEmpty = 0x4f11bae1, + mtpc_userProfilePhoto = 0xd559d8c8, + mtpc_userStatusEmpty = 0x9d05049, + mtpc_userStatusOnline = 0xedb93949, + mtpc_userStatusOffline = 0x8c703f, + mtpc_chatEmpty = 0x9ba2d800, + mtpc_chat = 0x6e9c9bc7, + mtpc_chatForbidden = 0xfb0ccc41, + mtpc_chatFull = 0x630e61be, + mtpc_chatParticipant = 0xc8d7493e, + mtpc_chatParticipantsForbidden = 0xfd2bb8a, + mtpc_chatParticipants = 0x7841b415, + mtpc_chatPhotoEmpty = 0x37c1011c, + mtpc_chatPhoto = 0x6153276a, + mtpc_messageEmpty = 0x83e5de54, + mtpc_message = 0x22eb6aba, + mtpc_messageForwarded = 0x5f46804, + mtpc_messageService = 0x9f8d60bb, + mtpc_messageMediaEmpty = 0x3ded6320, + mtpc_messageMediaPhoto = 0xc8c45a2a, + mtpc_messageMediaVideo = 0xa2d24290, + mtpc_messageMediaGeo = 0x56e0d474, + mtpc_messageMediaContact = 0x5e7d2f39, + mtpc_messageMediaUnsupported = 0x29632a36, + mtpc_messageActionEmpty = 0xb6aef7b0, + mtpc_messageActionChatCreate = 0xa6638b9a, + mtpc_messageActionChatEditTitle = 0xb5a1ce5a, + mtpc_messageActionChatEditPhoto = 0x7fcb13a8, + mtpc_messageActionChatDeletePhoto = 0x95e3fbef, + mtpc_messageActionChatAddUser = 0x5e3cfc4b, + mtpc_messageActionChatDeleteUser = 0xb2ae9b0c, + mtpc_dialog = 0xab3a99ac, + mtpc_photoEmpty = 0x2331b22d, + mtpc_photo = 0x22b56751, + mtpc_photoSizeEmpty = 0xe17e23c, + mtpc_photoSize = 0x77bfb61b, + mtpc_photoCachedSize = 0xe9a734fa, + mtpc_videoEmpty = 0xc10658a8, + mtpc_video = 0x388fa391, + mtpc_geoPointEmpty = 0x1117dd5f, + mtpc_geoPoint = 0x2049d70c, + mtpc_auth_checkedPhone = 0xe300cc3b, + mtpc_auth_sentCode = 0xefed51d9, + mtpc_auth_authorization = 0xf6b673a4, + mtpc_auth_exportedAuthorization = 0xdf969c2d, + mtpc_inputNotifyPeer = 0xb8bc5b0c, + mtpc_inputNotifyUsers = 0x193b4417, + mtpc_inputNotifyChats = 0x4a95e84e, + mtpc_inputNotifyAll = 0xa429b886, + mtpc_inputPeerNotifyEventsEmpty = 0xf03064d8, + mtpc_inputPeerNotifyEventsAll = 0xe86a2c74, + mtpc_inputPeerNotifySettings = 0x46a2ce98, + mtpc_peerNotifyEventsEmpty = 0xadd53cb3, + mtpc_peerNotifyEventsAll = 0x6d1ded88, + mtpc_peerNotifySettingsEmpty = 0x70a68512, + mtpc_peerNotifySettings = 0x8d5e11ee, + mtpc_wallPaper = 0xccb03657, + mtpc_userFull = 0x771095da, + mtpc_contact = 0xf911c994, + mtpc_importedContact = 0xd0028438, + mtpc_contactBlocked = 0x561bc879, + mtpc_contactFound = 0xea879f95, + mtpc_contactSuggested = 0x3de191a1, + mtpc_contactStatus = 0xaa77b873, + mtpc_chatLocated = 0x3631cf4c, + mtpc_contacts_foreignLinkUnknown = 0x133421f8, + mtpc_contacts_foreignLinkRequested = 0xa7801f47, + mtpc_contacts_foreignLinkMutual = 0x1bea8ce1, + mtpc_contacts_myLinkEmpty = 0xd22a1c60, + mtpc_contacts_myLinkRequested = 0x6c69efee, + mtpc_contacts_myLinkContact = 0xc240ebd9, + mtpc_contacts_link = 0xeccea3f5, + mtpc_contacts_contacts = 0x6f8b8cb2, + mtpc_contacts_contactsNotModified = 0xb74ba9d2, + mtpc_contacts_importedContacts = 0xad524315, + mtpc_contacts_blocked = 0x1c138d15, + mtpc_contacts_blockedSlice = 0x900802a1, + mtpc_contacts_found = 0x566000e, + mtpc_contacts_suggested = 0x5649dcc5, + mtpc_messages_dialogs = 0x15ba6c40, + mtpc_messages_dialogsSlice = 0x71e094f3, + mtpc_messages_messages = 0x8c718e87, + mtpc_messages_messagesSlice = 0xb446ae3, + mtpc_messages_messageEmpty = 0x3f4e0648, + mtpc_messages_message = 0xff90c417, + mtpc_messages_statedMessages = 0x969478bb, + mtpc_messages_statedMessage = 0xd07ae726, + mtpc_messages_sentMessage = 0xd1f4d35c, + mtpc_messages_chat = 0x40e9002a, + mtpc_messages_chats = 0x8150cbd8, + mtpc_messages_chatFull = 0xe5d7d19c, + mtpc_messages_affectedHistory = 0xb7de36f2, + mtpc_inputMessagesFilterEmpty = 0x57e2f66c, + mtpc_inputMessagesFilterPhotos = 0x9609a51c, + mtpc_inputMessagesFilterVideo = 0x9fc00e65, + mtpc_inputMessagesFilterPhotoVideo = 0x56e9f0e4, + mtpc_inputMessagesFilterDocument = 0x9eddf188, + mtpc_updateNewMessage = 0x13abdb3, + mtpc_updateMessageID = 0x4e90bfd6, + mtpc_updateReadMessages = 0xc6649e31, + mtpc_updateDeleteMessages = 0xa92bfe26, + mtpc_updateRestoreMessages = 0xd15de04d, + mtpc_updateUserTyping = 0x6baa8508, + mtpc_updateChatUserTyping = 0x3c46cfe6, + mtpc_updateChatParticipants = 0x7761198, + mtpc_updateUserStatus = 0x1bfbd823, + mtpc_updateUserName = 0xda22d9ad, + mtpc_updateUserPhoto = 0x95313b0c, + mtpc_updateContactRegistered = 0x2575bbb9, + mtpc_updateContactLink = 0x51a48a9a, + mtpc_updateActivation = 0x6f690963, + mtpc_updateNewAuthorization = 0x8f06529a, + mtpc_updates_state = 0xa56c2a3e, + mtpc_updates_differenceEmpty = 0x5d75a138, + mtpc_updates_difference = 0xf49ca0, + mtpc_updates_differenceSlice = 0xa8fb1981, + mtpc_updatesTooLong = 0xe317af7e, + mtpc_updateShortMessage = 0xd3f45784, + mtpc_updateShortChatMessage = 0x2b2fbd4e, + mtpc_updateShort = 0x78d4dec1, + mtpc_updatesCombined = 0x725b04c3, + mtpc_updates = 0x74ae4240, + mtpc_photos_photos = 0x8dca6aa5, + mtpc_photos_photosSlice = 0x15051f54, + mtpc_photos_photo = 0x20212ca8, + mtpc_upload_file = 0x96a18d5, + mtpc_dcOption = 0x2ec2a43c, + mtpc_config = 0x2e54dd74, + mtpc_nearestDc = 0x8e1a1775, + mtpc_help_appUpdate = 0x8987f311, + mtpc_help_noAppUpdate = 0xc45a6536, + mtpc_help_inviteText = 0x18cb9f78, + mtpc_messages_statedMessagesLinks = 0x3e74f5c6, + mtpc_messages_statedMessageLink = 0xa9af2881, + mtpc_messages_sentMessageLink = 0xe9db4a3f, + mtpc_inputGeoChat = 0x74d456fa, + mtpc_inputNotifyGeoChatPeer = 0x4d8ddec8, + mtpc_geoChat = 0x75eaea5a, + mtpc_geoChatMessageEmpty = 0x60311a9b, + mtpc_geoChatMessage = 0x4505f8e1, + mtpc_geoChatMessageService = 0xd34fa24e, + mtpc_geochats_statedMessage = 0x17b1578b, + mtpc_geochats_located = 0x48feb267, + mtpc_geochats_messages = 0xd1526db1, + mtpc_geochats_messagesSlice = 0xbc5863e8, + mtpc_messageActionGeoChatCreate = 0x6f038ebc, + mtpc_messageActionGeoChatCheckin = 0xc7d53de, + mtpc_updateNewGeoChatMessage = 0x5a68e3f7, + mtpc_wallPaperSolid = 0x63117f24, + mtpc_updateNewEncryptedMessage = 0x12bcbd9a, + mtpc_updateEncryptedChatTyping = 0x1710f156, + mtpc_updateEncryption = 0xb4a2e88d, + mtpc_updateEncryptedMessagesRead = 0x38fe25b7, + mtpc_encryptedChatEmpty = 0xab7ec0a0, + mtpc_encryptedChatWaiting = 0x3bf703dc, + mtpc_encryptedChatRequested = 0xc878527e, + mtpc_encryptedChat = 0xfa56ce36, + mtpc_encryptedChatDiscarded = 0x13d6dd27, + mtpc_inputEncryptedChat = 0xf141b5e1, + mtpc_encryptedFileEmpty = 0xc21f497e, + mtpc_encryptedFile = 0x4a70994c, + mtpc_inputEncryptedFileEmpty = 0x1837c364, + mtpc_inputEncryptedFileUploaded = 0x64bd0306, + mtpc_inputEncryptedFile = 0x5a17b5e5, + mtpc_inputEncryptedFileLocation = 0xf5235d55, + mtpc_encryptedMessage = 0xed18c118, + mtpc_encryptedMessageService = 0x23734b06, + mtpc_decryptedMessageLayer = 0x99a438cf, + mtpc_decryptedMessage = 0x1f814f1f, + mtpc_decryptedMessageService = 0xaa48327d, + mtpc_decryptedMessageMediaEmpty = 0x89f5c4a, + mtpc_decryptedMessageMediaPhoto = 0x32798a8c, + mtpc_decryptedMessageMediaVideo = 0x524a415d, + mtpc_decryptedMessageMediaGeoPoint = 0x35480a59, + mtpc_decryptedMessageMediaContact = 0x588a0a97, + mtpc_decryptedMessageActionSetMessageTTL = 0xa1733aec, + mtpc_messages_dhConfigNotModified = 0xc0e24635, + mtpc_messages_dhConfig = 0x2c221edd, + mtpc_messages_sentEncryptedMessage = 0x560f8935, + mtpc_messages_sentEncryptedFile = 0x9493ff32, + mtpc_inputFileBig = 0xfa4f0bb5, + mtpc_inputEncryptedFileBigUploaded = 0x2dc173c8, + mtpc_updateChatParticipantAdd = 0x3a0eeb22, + mtpc_updateChatParticipantDelete = 0x6e5f8c22, + mtpc_updateDcOptions = 0x8e5e9873, + mtpc_inputMediaUploadedAudio = 0x4e498cab, + mtpc_inputMediaAudio = 0x89938781, + mtpc_inputMediaUploadedDocument = 0x34e794bd, + mtpc_inputMediaUploadedThumbDocument = 0x3e46de5d, + mtpc_inputMediaDocument = 0xd184e841, + mtpc_messageMediaDocument = 0x2fda2204, + mtpc_messageMediaAudio = 0xc6b68300, + mtpc_inputAudioEmpty = 0xd95adc84, + mtpc_inputAudio = 0x77d440ff, + mtpc_inputDocumentEmpty = 0x72f0eaae, + mtpc_inputDocument = 0x18798952, + mtpc_inputAudioFileLocation = 0x74dc404d, + mtpc_inputDocumentFileLocation = 0x4e45abe9, + mtpc_decryptedMessageMediaDocument = 0xb095434b, + mtpc_decryptedMessageMediaAudio = 0x57e0a9cb, + mtpc_audioEmpty = 0x586988d8, + mtpc_audio = 0xc7ac6496, + mtpc_documentEmpty = 0x36f8c871, + mtpc_document = 0x9efc6326, + mtpc_help_support = 0x17c6b5f6, + mtpc_decryptedMessageActionReadMessages = 0xc4f40be, + mtpc_decryptedMessageActionDeleteMessages = 0x65614304, + mtpc_decryptedMessageActionScreenshotMessages = 0x8ac1f475, + mtpc_decryptedMessageActionFlushHistory = 0x6719e45c, + mtpc_decryptedMessageActionNotifyLayer = 0xf3048883, + mtpc_notifyPeer = 0x9fd40bd8, + mtpc_notifyUsers = 0xb4c83b4c, + mtpc_notifyChats = 0xc007cec3, + mtpc_notifyAll = 0x74d07c60, + mtpc_updateUserBlocked = 0x80ece81a, + mtpc_updateNotifySettings = 0xbec268ef, + mtpc_invokeAfterMsg = 0xcb9f372d, + mtpc_invokeAfterMsgs = 0x3dc4b4f0, + mtpc_auth_checkPhone = 0x6fe51dfb, + mtpc_auth_sendCode = 0x768d5f4d, + mtpc_auth_sendCall = 0x3c51564, + mtpc_auth_signUp = 0x1b067634, + mtpc_auth_signIn = 0xbcd51581, + mtpc_auth_logOut = 0x5717da40, + mtpc_auth_resetAuthorizations = 0x9fab0d1a, + mtpc_auth_sendInvites = 0x771c1d97, + mtpc_auth_exportAuthorization = 0xe5bfffcd, + mtpc_auth_importAuthorization = 0xe3ef9613, + mtpc_account_registerDevice = 0x446c712c, + mtpc_account_unregisterDevice = 0x65c55b40, + mtpc_account_updateNotifySettings = 0x84be5b93, + mtpc_account_getNotifySettings = 0x12b3ad31, + mtpc_account_resetNotifySettings = 0xdb7e1747, + mtpc_account_updateProfile = 0xf0888d68, + mtpc_account_updateStatus = 0x6628562c, + mtpc_account_getWallPapers = 0xc04cfac2, + mtpc_users_getUsers = 0xd91a548, + mtpc_users_getFullUser = 0xca30a5b1, + mtpc_contacts_getStatuses = 0xc4a353ee, + mtpc_contacts_getContacts = 0x22c6aa08, + mtpc_contacts_importContacts = 0xda30b32d, + mtpc_contacts_search = 0x11f812d8, + mtpc_contacts_getSuggested = 0xcd773428, + mtpc_contacts_deleteContact = 0x8e953744, + mtpc_contacts_deleteContacts = 0x59ab389e, + mtpc_contacts_block = 0x332b49fc, + mtpc_contacts_unblock = 0xe54100bd, + mtpc_contacts_getBlocked = 0xf57c350f, + mtpc_messages_getMessages = 0x4222fa74, + mtpc_messages_getDialogs = 0xeccf1df6, + mtpc_messages_getHistory = 0x92a1df2f, + mtpc_messages_search = 0x7e9f2ab, + mtpc_messages_readHistory = 0xb04f2510, + mtpc_messages_deleteHistory = 0xf4f8fb61, + mtpc_messages_deleteMessages = 0x14f2dd0a, + mtpc_messages_restoreMessages = 0x395f9d7e, + mtpc_messages_receivedMessages = 0x28abcb68, + mtpc_messages_setTyping = 0x719839e9, + mtpc_messages_sendMessage = 0x4cde0aab, + mtpc_messages_sendMedia = 0xa3c85d76, + mtpc_messages_forwardMessages = 0x514cd10f, + mtpc_messages_getChats = 0x3c6aa187, + mtpc_messages_getFullChat = 0x3b831c66, + mtpc_messages_editChatTitle = 0xb4bc68b5, + mtpc_messages_editChatPhoto = 0xd881821d, + mtpc_messages_addChatUser = 0x2ee9ee9e, + mtpc_messages_deleteChatUser = 0xc3c5cd23, + mtpc_messages_createChat = 0x419d9aee, + mtpc_updates_getState = 0xedd4882a, + mtpc_updates_getDifference = 0xa041495, + mtpc_photos_updateProfilePhoto = 0xeef579a0, + mtpc_photos_uploadProfilePhoto = 0xd50f9c88, + mtpc_upload_saveFilePart = 0xb304a621, + mtpc_upload_getFile = 0xe3a6cfb5, + mtpc_help_getConfig = 0xc4f9186b, + mtpc_help_getNearestDc = 0x1fb33026, + mtpc_help_getAppUpdate = 0xc812ac7e, + mtpc_help_saveAppLog = 0x6f02f748, + mtpc_help_getInviteText = 0xa4a95186, + mtpc_photos_getUserPhotos = 0xb7ee553c, + mtpc_messages_forwardMessage = 0x3f3f4f2, + mtpc_messages_sendBroadcast = 0x41bb0972, + mtpc_geochats_getLocated = 0x7f192d8f, + mtpc_geochats_getRecents = 0xe1427e6f, + mtpc_geochats_checkin = 0x55b3e8fb, + mtpc_geochats_getFullChat = 0x6722dd6f, + mtpc_geochats_editChatTitle = 0x4c8e2273, + mtpc_geochats_editChatPhoto = 0x35d81a95, + mtpc_geochats_search = 0xcfcdc44d, + mtpc_geochats_getHistory = 0xb53f7a68, + mtpc_geochats_setTyping = 0x8b8a729, + mtpc_geochats_sendMessage = 0x61b0044, + mtpc_geochats_sendMedia = 0xb8f0deff, + mtpc_geochats_createGeoChat = 0xe092e16, + mtpc_messages_getDhConfig = 0x26cf8950, + mtpc_messages_requestEncryption = 0xf64daf43, + mtpc_messages_acceptEncryption = 0x3dbc0415, + mtpc_messages_discardEncryption = 0xedd923c5, + mtpc_messages_setEncryptedTyping = 0x791451ed, + mtpc_messages_readEncryptedHistory = 0x7f4b690a, + mtpc_messages_sendEncrypted = 0xa9776773, + mtpc_messages_sendEncryptedFile = 0x9a901b66, + mtpc_messages_sendEncryptedService = 0x32d439a4, + mtpc_messages_receivedQueue = 0x55a5bb66, + mtpc_upload_saveBigFilePart = 0xde7b673d, + mtpc_initConnection = 0x69796de9, + mtpc_help_getSupport = 0x9cdf08cd +}; + +// Type forward declarations +class MTPresPQ; +class MTPDresPQ; + +class MTPp_Q_inner_data; +class MTPDp_q_inner_data; + +class MTPserver_DH_Params; +class MTPDserver_DH_params_fail; +class MTPDserver_DH_params_ok; + +class MTPserver_DH_inner_data; +class MTPDserver_DH_inner_data; + +class MTPclient_DH_Inner_Data; +class MTPDclient_DH_inner_data; + +class MTPset_client_DH_params_answer; +class MTPDdh_gen_ok; +class MTPDdh_gen_retry; +class MTPDdh_gen_fail; + +class MTPmsgsAck; +class MTPDmsgs_ack; + +class MTPbadMsgNotification; +class MTPDbad_msg_notification; +class MTPDbad_server_salt; + +class MTPmsgsStateReq; +class MTPDmsgs_state_req; + +class MTPmsgsStateInfo; +class MTPDmsgs_state_info; + +class MTPmsgsAllInfo; +class MTPDmsgs_all_info; + +class MTPmsgDetailedInfo; +class MTPDmsg_detailed_info; +class MTPDmsg_new_detailed_info; + +class MTPmsgResendReq; +class MTPDmsg_resend_req; + +class MTPrpcError; +class MTPDrpc_error; + +class MTPrpcDropAnswer; +class MTPDrpc_answer_dropped; + +class MTPfutureSalt; +class MTPDfuture_salt; + +class MTPfutureSalts; +class MTPDfuture_salts; + +class MTPpong; +class MTPDpong; + +class MTPdestroySessionRes; +class MTPDdestroy_session_ok; +class MTPDdestroy_session_none; + +class MTPnewSession; +class MTPDnew_session_created; + +class MTPhttpWait; +class MTPDhttp_wait; + +class MTPinputPeer; +class MTPDinputPeerContact; +class MTPDinputPeerForeign; +class MTPDinputPeerChat; + +class MTPinputUser; +class MTPDinputUserContact; +class MTPDinputUserForeign; + +class MTPinputContact; +class MTPDinputPhoneContact; + +class MTPinputFile; +class MTPDinputFile; +class MTPDinputFileBig; + +class MTPinputMedia; +class MTPDinputMediaUploadedPhoto; +class MTPDinputMediaPhoto; +class MTPDinputMediaGeoPoint; +class MTPDinputMediaContact; +class MTPDinputMediaUploadedVideo; +class MTPDinputMediaUploadedThumbVideo; +class MTPDinputMediaVideo; +class MTPDinputMediaUploadedAudio; +class MTPDinputMediaAudio; +class MTPDinputMediaUploadedDocument; +class MTPDinputMediaUploadedThumbDocument; +class MTPDinputMediaDocument; + +class MTPinputChatPhoto; +class MTPDinputChatUploadedPhoto; +class MTPDinputChatPhoto; + +class MTPinputGeoPoint; +class MTPDinputGeoPoint; + +class MTPinputPhoto; +class MTPDinputPhoto; + +class MTPinputVideo; +class MTPDinputVideo; + +class MTPinputFileLocation; +class MTPDinputFileLocation; +class MTPDinputVideoFileLocation; +class MTPDinputEncryptedFileLocation; +class MTPDinputAudioFileLocation; +class MTPDinputDocumentFileLocation; + +class MTPinputPhotoCrop; +class MTPDinputPhotoCrop; + +class MTPinputAppEvent; +class MTPDinputAppEvent; + +class MTPpeer; +class MTPDpeerUser; +class MTPDpeerChat; + +class MTPstorage_fileType; + +class MTPfileLocation; +class MTPDfileLocationUnavailable; +class MTPDfileLocation; + +class MTPuser; +class MTPDuserEmpty; +class MTPDuserSelf; +class MTPDuserContact; +class MTPDuserRequest; +class MTPDuserForeign; +class MTPDuserDeleted; + +class MTPuserProfilePhoto; +class MTPDuserProfilePhoto; + +class MTPuserStatus; +class MTPDuserStatusOnline; +class MTPDuserStatusOffline; + +class MTPchat; +class MTPDchatEmpty; +class MTPDchat; +class MTPDchatForbidden; +class MTPDgeoChat; + +class MTPchatFull; +class MTPDchatFull; + +class MTPchatParticipant; +class MTPDchatParticipant; + +class MTPchatParticipants; +class MTPDchatParticipantsForbidden; +class MTPDchatParticipants; + +class MTPchatPhoto; +class MTPDchatPhoto; + +class MTPmessage; +class MTPDmessageEmpty; +class MTPDmessage; +class MTPDmessageForwarded; +class MTPDmessageService; + +class MTPmessageMedia; +class MTPDmessageMediaPhoto; +class MTPDmessageMediaVideo; +class MTPDmessageMediaGeo; +class MTPDmessageMediaContact; +class MTPDmessageMediaUnsupported; +class MTPDmessageMediaDocument; +class MTPDmessageMediaAudio; + +class MTPmessageAction; +class MTPDmessageActionChatCreate; +class MTPDmessageActionChatEditTitle; +class MTPDmessageActionChatEditPhoto; +class MTPDmessageActionChatAddUser; +class MTPDmessageActionChatDeleteUser; +class MTPDmessageActionGeoChatCreate; + +class MTPdialog; +class MTPDdialog; + +class MTPphoto; +class MTPDphotoEmpty; +class MTPDphoto; + +class MTPphotoSize; +class MTPDphotoSizeEmpty; +class MTPDphotoSize; +class MTPDphotoCachedSize; + +class MTPvideo; +class MTPDvideoEmpty; +class MTPDvideo; + +class MTPgeoPoint; +class MTPDgeoPoint; + +class MTPauth_checkedPhone; +class MTPDauth_checkedPhone; + +class MTPauth_sentCode; +class MTPDauth_sentCode; + +class MTPauth_authorization; +class MTPDauth_authorization; + +class MTPauth_exportedAuthorization; +class MTPDauth_exportedAuthorization; + +class MTPinputNotifyPeer; +class MTPDinputNotifyPeer; +class MTPDinputNotifyGeoChatPeer; + +class MTPinputPeerNotifyEvents; + +class MTPinputPeerNotifySettings; +class MTPDinputPeerNotifySettings; + +class MTPpeerNotifyEvents; + +class MTPpeerNotifySettings; +class MTPDpeerNotifySettings; + +class MTPwallPaper; +class MTPDwallPaper; +class MTPDwallPaperSolid; + +class MTPuserFull; +class MTPDuserFull; + +class MTPcontact; +class MTPDcontact; + +class MTPimportedContact; +class MTPDimportedContact; + +class MTPcontactBlocked; +class MTPDcontactBlocked; + +class MTPcontactFound; +class MTPDcontactFound; + +class MTPcontactSuggested; +class MTPDcontactSuggested; + +class MTPcontactStatus; +class MTPDcontactStatus; + +class MTPchatLocated; +class MTPDchatLocated; + +class MTPcontacts_foreignLink; +class MTPDcontacts_foreignLinkRequested; + +class MTPcontacts_myLink; +class MTPDcontacts_myLinkRequested; + +class MTPcontacts_link; +class MTPDcontacts_link; + +class MTPcontacts_contacts; +class MTPDcontacts_contacts; + +class MTPcontacts_importedContacts; +class MTPDcontacts_importedContacts; + +class MTPcontacts_blocked; +class MTPDcontacts_blocked; +class MTPDcontacts_blockedSlice; + +class MTPcontacts_found; +class MTPDcontacts_found; + +class MTPcontacts_suggested; +class MTPDcontacts_suggested; + +class MTPmessages_dialogs; +class MTPDmessages_dialogs; +class MTPDmessages_dialogsSlice; + +class MTPmessages_messages; +class MTPDmessages_messages; +class MTPDmessages_messagesSlice; + +class MTPmessages_message; +class MTPDmessages_message; + +class MTPmessages_statedMessages; +class MTPDmessages_statedMessages; +class MTPDmessages_statedMessagesLinks; + +class MTPmessages_statedMessage; +class MTPDmessages_statedMessage; +class MTPDmessages_statedMessageLink; + +class MTPmessages_sentMessage; +class MTPDmessages_sentMessage; +class MTPDmessages_sentMessageLink; + +class MTPmessages_chat; +class MTPDmessages_chat; + +class MTPmessages_chats; +class MTPDmessages_chats; + +class MTPmessages_chatFull; +class MTPDmessages_chatFull; + +class MTPmessages_affectedHistory; +class MTPDmessages_affectedHistory; + +class MTPmessagesFilter; + +class MTPupdate; +class MTPDupdateNewMessage; +class MTPDupdateMessageID; +class MTPDupdateReadMessages; +class MTPDupdateDeleteMessages; +class MTPDupdateRestoreMessages; +class MTPDupdateUserTyping; +class MTPDupdateChatUserTyping; +class MTPDupdateChatParticipants; +class MTPDupdateUserStatus; +class MTPDupdateUserName; +class MTPDupdateUserPhoto; +class MTPDupdateContactRegistered; +class MTPDupdateContactLink; +class MTPDupdateActivation; +class MTPDupdateNewAuthorization; +class MTPDupdateNewGeoChatMessage; +class MTPDupdateNewEncryptedMessage; +class MTPDupdateEncryptedChatTyping; +class MTPDupdateEncryption; +class MTPDupdateEncryptedMessagesRead; +class MTPDupdateChatParticipantAdd; +class MTPDupdateChatParticipantDelete; +class MTPDupdateDcOptions; +class MTPDupdateUserBlocked; +class MTPDupdateNotifySettings; + +class MTPupdates_state; +class MTPDupdates_state; + +class MTPupdates_difference; +class MTPDupdates_differenceEmpty; +class MTPDupdates_difference; +class MTPDupdates_differenceSlice; + +class MTPupdates; +class MTPDupdateShortMessage; +class MTPDupdateShortChatMessage; +class MTPDupdateShort; +class MTPDupdatesCombined; +class MTPDupdates; + +class MTPphotos_photos; +class MTPDphotos_photos; +class MTPDphotos_photosSlice; + +class MTPphotos_photo; +class MTPDphotos_photo; + +class MTPupload_file; +class MTPDupload_file; + +class MTPdcOption; +class MTPDdcOption; + +class MTPconfig; +class MTPDconfig; + +class MTPnearestDc; +class MTPDnearestDc; + +class MTPhelp_appUpdate; +class MTPDhelp_appUpdate; + +class MTPhelp_inviteText; +class MTPDhelp_inviteText; + +class MTPinputGeoChat; +class MTPDinputGeoChat; + +class MTPgeoChatMessage; +class MTPDgeoChatMessageEmpty; +class MTPDgeoChatMessage; +class MTPDgeoChatMessageService; + +class MTPgeochats_statedMessage; +class MTPDgeochats_statedMessage; + +class MTPgeochats_located; +class MTPDgeochats_located; + +class MTPgeochats_messages; +class MTPDgeochats_messages; +class MTPDgeochats_messagesSlice; + +class MTPencryptedChat; +class MTPDencryptedChatEmpty; +class MTPDencryptedChatWaiting; +class MTPDencryptedChatRequested; +class MTPDencryptedChat; +class MTPDencryptedChatDiscarded; + +class MTPinputEncryptedChat; +class MTPDinputEncryptedChat; + +class MTPencryptedFile; +class MTPDencryptedFile; + +class MTPinputEncryptedFile; +class MTPDinputEncryptedFileUploaded; +class MTPDinputEncryptedFile; +class MTPDinputEncryptedFileBigUploaded; + +class MTPencryptedMessage; +class MTPDencryptedMessage; +class MTPDencryptedMessageService; + +class MTPdecryptedMessageLayer; +class MTPDdecryptedMessageLayer; + +class MTPdecryptedMessage; +class MTPDdecryptedMessage; +class MTPDdecryptedMessageService; + +class MTPdecryptedMessageMedia; +class MTPDdecryptedMessageMediaPhoto; +class MTPDdecryptedMessageMediaVideo; +class MTPDdecryptedMessageMediaGeoPoint; +class MTPDdecryptedMessageMediaContact; +class MTPDdecryptedMessageMediaDocument; +class MTPDdecryptedMessageMediaAudio; + +class MTPdecryptedMessageAction; +class MTPDdecryptedMessageActionSetMessageTTL; +class MTPDdecryptedMessageActionReadMessages; +class MTPDdecryptedMessageActionDeleteMessages; +class MTPDdecryptedMessageActionScreenshotMessages; +class MTPDdecryptedMessageActionNotifyLayer; + +class MTPmessages_dhConfig; +class MTPDmessages_dhConfigNotModified; +class MTPDmessages_dhConfig; + +class MTPmessages_sentEncryptedMessage; +class MTPDmessages_sentEncryptedMessage; +class MTPDmessages_sentEncryptedFile; + +class MTPinputAudio; +class MTPDinputAudio; + +class MTPinputDocument; +class MTPDinputDocument; + +class MTPaudio; +class MTPDaudioEmpty; +class MTPDaudio; + +class MTPdocument; +class MTPDdocumentEmpty; +class MTPDdocument; + +class MTPhelp_support; +class MTPDhelp_support; + +class MTPnotifyPeer; +class MTPDnotifyPeer; + + +// Boxed types definitions +typedef MTPBoxed MTPResPQ; +typedef MTPBoxed MTPP_Q_inner_data; +typedef MTPBoxed MTPServer_DH_Params; +typedef MTPBoxed MTPServer_DH_inner_data; +typedef MTPBoxed MTPClient_DH_Inner_Data; +typedef MTPBoxed MTPSet_client_DH_params_answer; +typedef MTPBoxed MTPMsgsAck; +typedef MTPBoxed MTPBadMsgNotification; +typedef MTPBoxed MTPMsgsStateReq; +typedef MTPBoxed MTPMsgsStateInfo; +typedef MTPBoxed MTPMsgsAllInfo; +typedef MTPBoxed MTPMsgDetailedInfo; +typedef MTPBoxed MTPMsgResendReq; +typedef MTPBoxed MTPRpcError; +typedef MTPBoxed MTPRpcDropAnswer; +typedef MTPBoxed MTPFutureSalt; +typedef MTPBoxed MTPFutureSalts; +typedef MTPBoxed MTPPong; +typedef MTPBoxed MTPDestroySessionRes; +typedef MTPBoxed MTPNewSession; +typedef MTPBoxed MTPHttpWait; +typedef MTPBoxed MTPInputPeer; +typedef MTPBoxed MTPInputUser; +typedef MTPBoxed MTPInputContact; +typedef MTPBoxed MTPInputFile; +typedef MTPBoxed MTPInputMedia; +typedef MTPBoxed MTPInputChatPhoto; +typedef MTPBoxed MTPInputGeoPoint; +typedef MTPBoxed MTPInputPhoto; +typedef MTPBoxed MTPInputVideo; +typedef MTPBoxed MTPInputFileLocation; +typedef MTPBoxed MTPInputPhotoCrop; +typedef MTPBoxed MTPInputAppEvent; +typedef MTPBoxed MTPPeer; +typedef MTPBoxed MTPstorage_FileType; +typedef MTPBoxed MTPFileLocation; +typedef MTPBoxed MTPUser; +typedef MTPBoxed MTPUserProfilePhoto; +typedef MTPBoxed MTPUserStatus; +typedef MTPBoxed MTPChat; +typedef MTPBoxed MTPChatFull; +typedef MTPBoxed MTPChatParticipant; +typedef MTPBoxed MTPChatParticipants; +typedef MTPBoxed MTPChatPhoto; +typedef MTPBoxed MTPMessage; +typedef MTPBoxed MTPMessageMedia; +typedef MTPBoxed MTPMessageAction; +typedef MTPBoxed MTPDialog; +typedef MTPBoxed MTPPhoto; +typedef MTPBoxed MTPPhotoSize; +typedef MTPBoxed MTPVideo; +typedef MTPBoxed MTPGeoPoint; +typedef MTPBoxed MTPauth_CheckedPhone; +typedef MTPBoxed MTPauth_SentCode; +typedef MTPBoxed MTPauth_Authorization; +typedef MTPBoxed MTPauth_ExportedAuthorization; +typedef MTPBoxed MTPInputNotifyPeer; +typedef MTPBoxed MTPInputPeerNotifyEvents; +typedef MTPBoxed MTPInputPeerNotifySettings; +typedef MTPBoxed MTPPeerNotifyEvents; +typedef MTPBoxed MTPPeerNotifySettings; +typedef MTPBoxed MTPWallPaper; +typedef MTPBoxed MTPUserFull; +typedef MTPBoxed MTPContact; +typedef MTPBoxed MTPImportedContact; +typedef MTPBoxed MTPContactBlocked; +typedef MTPBoxed MTPContactFound; +typedef MTPBoxed MTPContactSuggested; +typedef MTPBoxed MTPContactStatus; +typedef MTPBoxed MTPChatLocated; +typedef MTPBoxed MTPcontacts_ForeignLink; +typedef MTPBoxed MTPcontacts_MyLink; +typedef MTPBoxed MTPcontacts_Link; +typedef MTPBoxed MTPcontacts_Contacts; +typedef MTPBoxed MTPcontacts_ImportedContacts; +typedef MTPBoxed MTPcontacts_Blocked; +typedef MTPBoxed MTPcontacts_Found; +typedef MTPBoxed MTPcontacts_Suggested; +typedef MTPBoxed MTPmessages_Dialogs; +typedef MTPBoxed MTPmessages_Messages; +typedef MTPBoxed MTPmessages_Message; +typedef MTPBoxed MTPmessages_StatedMessages; +typedef MTPBoxed MTPmessages_StatedMessage; +typedef MTPBoxed MTPmessages_SentMessage; +typedef MTPBoxed MTPmessages_Chat; +typedef MTPBoxed MTPmessages_Chats; +typedef MTPBoxed MTPmessages_ChatFull; +typedef MTPBoxed MTPmessages_AffectedHistory; +typedef MTPBoxed MTPMessagesFilter; +typedef MTPBoxed MTPUpdate; +typedef MTPBoxed MTPupdates_State; +typedef MTPBoxed MTPupdates_Difference; +typedef MTPBoxed MTPUpdates; +typedef MTPBoxed MTPphotos_Photos; +typedef MTPBoxed MTPphotos_Photo; +typedef MTPBoxed MTPupload_File; +typedef MTPBoxed MTPDcOption; +typedef MTPBoxed MTPConfig; +typedef MTPBoxed MTPNearestDc; +typedef MTPBoxed MTPhelp_AppUpdate; +typedef MTPBoxed MTPhelp_InviteText; +typedef MTPBoxed MTPInputGeoChat; +typedef MTPBoxed MTPGeoChatMessage; +typedef MTPBoxed MTPgeochats_StatedMessage; +typedef MTPBoxed MTPgeochats_Located; +typedef MTPBoxed MTPgeochats_Messages; +typedef MTPBoxed MTPEncryptedChat; +typedef MTPBoxed MTPInputEncryptedChat; +typedef MTPBoxed MTPEncryptedFile; +typedef MTPBoxed MTPInputEncryptedFile; +typedef MTPBoxed MTPEncryptedMessage; +typedef MTPBoxed MTPDecryptedMessageLayer; +typedef MTPBoxed MTPDecryptedMessage; +typedef MTPBoxed MTPDecryptedMessageMedia; +typedef MTPBoxed MTPDecryptedMessageAction; +typedef MTPBoxed MTPmessages_DhConfig; +typedef MTPBoxed MTPmessages_SentEncryptedMessage; +typedef MTPBoxed MTPInputAudio; +typedef MTPBoxed MTPInputDocument; +typedef MTPBoxed MTPAudio; +typedef MTPBoxed MTPDocument; +typedef MTPBoxed MTPhelp_Support; +typedef MTPBoxed MTPNotifyPeer; + +// Type classes definitions + +class MTPresPQ : private mtpDataOwner { +public: + MTPresPQ(); + MTPresPQ(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_resPQ) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDresPQ &_resPQ() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDresPQ*)data; + } + const MTPDresPQ &c_resPQ() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDresPQ*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_resPQ); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPresPQ(MTPDresPQ *_data); + + friend MTPresPQ MTP_resPQ(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPstring &_pq, const MTPVector &_server_public_key_fingerprints); +}; +typedef MTPBoxed MTPResPQ; + +class MTPp_Q_inner_data : private mtpDataOwner { +public: + MTPp_Q_inner_data(); + MTPp_Q_inner_data(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_p_q_inner_data) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDp_q_inner_data &_p_q_inner_data() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDp_q_inner_data*)data; + } + const MTPDp_q_inner_data &c_p_q_inner_data() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDp_q_inner_data*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_p_q_inner_data); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPp_Q_inner_data(MTPDp_q_inner_data *_data); + + friend MTPp_Q_inner_data MTP_p_q_inner_data(const MTPstring &_pq, const MTPstring &_p, const MTPstring &_q, const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint256 &_new_nonce); +}; +typedef MTPBoxed MTPP_Q_inner_data; + +class MTPserver_DH_Params : private mtpDataOwner { +public: + MTPserver_DH_Params() : mtpDataOwner(0), _type(0) { + } + MTPserver_DH_Params(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDserver_DH_params_fail &_server_DH_params_fail() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_server_DH_params_fail) throw mtpErrorWrongTypeId(_type, mtpc_server_DH_params_fail); + split(); + return *(MTPDserver_DH_params_fail*)data; + } + const MTPDserver_DH_params_fail &c_server_DH_params_fail() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_server_DH_params_fail) throw mtpErrorWrongTypeId(_type, mtpc_server_DH_params_fail); + return *(const MTPDserver_DH_params_fail*)data; + } + + MTPDserver_DH_params_ok &_server_DH_params_ok() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_server_DH_params_ok) throw mtpErrorWrongTypeId(_type, mtpc_server_DH_params_ok); + split(); + return *(MTPDserver_DH_params_ok*)data; + } + const MTPDserver_DH_params_ok &c_server_DH_params_ok() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_server_DH_params_ok) throw mtpErrorWrongTypeId(_type, mtpc_server_DH_params_ok); + return *(const MTPDserver_DH_params_ok*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPserver_DH_Params(mtpTypeId type); + explicit MTPserver_DH_Params(MTPDserver_DH_params_fail *_data); + explicit MTPserver_DH_Params(MTPDserver_DH_params_ok *_data); + + friend MTPserver_DH_Params MTP_server_DH_params_fail(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint128 &_new_nonce_hash); + friend MTPserver_DH_Params MTP_server_DH_params_ok(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPstring &_encrypted_answer); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPServer_DH_Params; + +class MTPserver_DH_inner_data : private mtpDataOwner { +public: + MTPserver_DH_inner_data(); + MTPserver_DH_inner_data(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_server_DH_inner_data) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDserver_DH_inner_data &_server_DH_inner_data() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDserver_DH_inner_data*)data; + } + const MTPDserver_DH_inner_data &c_server_DH_inner_data() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDserver_DH_inner_data*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_server_DH_inner_data); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPserver_DH_inner_data(MTPDserver_DH_inner_data *_data); + + friend MTPserver_DH_inner_data MTP_server_DH_inner_data(const MTPint128 &_nonce, const MTPint128 &_server_nonce, MTPint _g, const MTPstring &_dh_prime, const MTPstring &_g_a, MTPint _server_time); +}; +typedef MTPBoxed MTPServer_DH_inner_data; + +class MTPclient_DH_Inner_Data : private mtpDataOwner { +public: + MTPclient_DH_Inner_Data(); + MTPclient_DH_Inner_Data(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_client_DH_inner_data) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDclient_DH_inner_data &_client_DH_inner_data() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDclient_DH_inner_data*)data; + } + const MTPDclient_DH_inner_data &c_client_DH_inner_data() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDclient_DH_inner_data*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_client_DH_inner_data); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPclient_DH_Inner_Data(MTPDclient_DH_inner_data *_data); + + friend MTPclient_DH_Inner_Data MTP_client_DH_inner_data(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPlong &_retry_id, const MTPstring &_g_b); +}; +typedef MTPBoxed MTPClient_DH_Inner_Data; + +class MTPset_client_DH_params_answer : private mtpDataOwner { +public: + MTPset_client_DH_params_answer() : mtpDataOwner(0), _type(0) { + } + MTPset_client_DH_params_answer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDdh_gen_ok &_dh_gen_ok() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_dh_gen_ok) throw mtpErrorWrongTypeId(_type, mtpc_dh_gen_ok); + split(); + return *(MTPDdh_gen_ok*)data; + } + const MTPDdh_gen_ok &c_dh_gen_ok() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_dh_gen_ok) throw mtpErrorWrongTypeId(_type, mtpc_dh_gen_ok); + return *(const MTPDdh_gen_ok*)data; + } + + MTPDdh_gen_retry &_dh_gen_retry() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_dh_gen_retry) throw mtpErrorWrongTypeId(_type, mtpc_dh_gen_retry); + split(); + return *(MTPDdh_gen_retry*)data; + } + const MTPDdh_gen_retry &c_dh_gen_retry() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_dh_gen_retry) throw mtpErrorWrongTypeId(_type, mtpc_dh_gen_retry); + return *(const MTPDdh_gen_retry*)data; + } + + MTPDdh_gen_fail &_dh_gen_fail() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_dh_gen_fail) throw mtpErrorWrongTypeId(_type, mtpc_dh_gen_fail); + split(); + return *(MTPDdh_gen_fail*)data; + } + const MTPDdh_gen_fail &c_dh_gen_fail() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_dh_gen_fail) throw mtpErrorWrongTypeId(_type, mtpc_dh_gen_fail); + return *(const MTPDdh_gen_fail*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPset_client_DH_params_answer(mtpTypeId type); + explicit MTPset_client_DH_params_answer(MTPDdh_gen_ok *_data); + explicit MTPset_client_DH_params_answer(MTPDdh_gen_retry *_data); + explicit MTPset_client_DH_params_answer(MTPDdh_gen_fail *_data); + + friend MTPset_client_DH_params_answer MTP_dh_gen_ok(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint128 &_new_nonce_hash1); + friend MTPset_client_DH_params_answer MTP_dh_gen_retry(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint128 &_new_nonce_hash2); + friend MTPset_client_DH_params_answer MTP_dh_gen_fail(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint128 &_new_nonce_hash3); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPSet_client_DH_params_answer; + +class MTPmsgsAck : private mtpDataOwner { +public: + MTPmsgsAck(); + MTPmsgsAck(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_msgs_ack) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDmsgs_ack &_msgs_ack() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDmsgs_ack*)data; + } + const MTPDmsgs_ack &c_msgs_ack() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDmsgs_ack*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_msgs_ack); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmsgsAck(MTPDmsgs_ack *_data); + + friend MTPmsgsAck MTP_msgs_ack(const MTPVector &_msg_ids); +}; +typedef MTPBoxed MTPMsgsAck; + +class MTPbadMsgNotification : private mtpDataOwner { +public: + MTPbadMsgNotification() : mtpDataOwner(0), _type(0) { + } + MTPbadMsgNotification(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDbad_msg_notification &_bad_msg_notification() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_bad_msg_notification) throw mtpErrorWrongTypeId(_type, mtpc_bad_msg_notification); + split(); + return *(MTPDbad_msg_notification*)data; + } + const MTPDbad_msg_notification &c_bad_msg_notification() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_bad_msg_notification) throw mtpErrorWrongTypeId(_type, mtpc_bad_msg_notification); + return *(const MTPDbad_msg_notification*)data; + } + + MTPDbad_server_salt &_bad_server_salt() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_bad_server_salt) throw mtpErrorWrongTypeId(_type, mtpc_bad_server_salt); + split(); + return *(MTPDbad_server_salt*)data; + } + const MTPDbad_server_salt &c_bad_server_salt() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_bad_server_salt) throw mtpErrorWrongTypeId(_type, mtpc_bad_server_salt); + return *(const MTPDbad_server_salt*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPbadMsgNotification(mtpTypeId type); + explicit MTPbadMsgNotification(MTPDbad_msg_notification *_data); + explicit MTPbadMsgNotification(MTPDbad_server_salt *_data); + + friend MTPbadMsgNotification MTP_bad_msg_notification(const MTPlong &_bad_msg_id, MTPint _bad_msg_seqno, MTPint _error_code); + friend MTPbadMsgNotification MTP_bad_server_salt(const MTPlong &_bad_msg_id, MTPint _bad_msg_seqno, MTPint _error_code, const MTPlong &_new_server_salt); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPBadMsgNotification; + +class MTPmsgsStateReq : private mtpDataOwner { +public: + MTPmsgsStateReq(); + MTPmsgsStateReq(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_msgs_state_req) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDmsgs_state_req &_msgs_state_req() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDmsgs_state_req*)data; + } + const MTPDmsgs_state_req &c_msgs_state_req() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDmsgs_state_req*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_msgs_state_req); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmsgsStateReq(MTPDmsgs_state_req *_data); + + friend MTPmsgsStateReq MTP_msgs_state_req(const MTPVector &_msg_ids); +}; +typedef MTPBoxed MTPMsgsStateReq; + +class MTPmsgsStateInfo : private mtpDataOwner { +public: + MTPmsgsStateInfo(); + MTPmsgsStateInfo(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_msgs_state_info) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDmsgs_state_info &_msgs_state_info() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDmsgs_state_info*)data; + } + const MTPDmsgs_state_info &c_msgs_state_info() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDmsgs_state_info*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_msgs_state_info); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmsgsStateInfo(MTPDmsgs_state_info *_data); + + friend MTPmsgsStateInfo MTP_msgs_state_info(const MTPlong &_req_msg_id, const MTPstring &_info); +}; +typedef MTPBoxed MTPMsgsStateInfo; + +class MTPmsgsAllInfo : private mtpDataOwner { +public: + MTPmsgsAllInfo(); + MTPmsgsAllInfo(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_msgs_all_info) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDmsgs_all_info &_msgs_all_info() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDmsgs_all_info*)data; + } + const MTPDmsgs_all_info &c_msgs_all_info() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDmsgs_all_info*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_msgs_all_info); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmsgsAllInfo(MTPDmsgs_all_info *_data); + + friend MTPmsgsAllInfo MTP_msgs_all_info(const MTPVector &_msg_ids, const MTPstring &_info); +}; +typedef MTPBoxed MTPMsgsAllInfo; + +class MTPmsgDetailedInfo : private mtpDataOwner { +public: + MTPmsgDetailedInfo() : mtpDataOwner(0), _type(0) { + } + MTPmsgDetailedInfo(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmsg_detailed_info &_msg_detailed_info() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_msg_detailed_info) throw mtpErrorWrongTypeId(_type, mtpc_msg_detailed_info); + split(); + return *(MTPDmsg_detailed_info*)data; + } + const MTPDmsg_detailed_info &c_msg_detailed_info() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_msg_detailed_info) throw mtpErrorWrongTypeId(_type, mtpc_msg_detailed_info); + return *(const MTPDmsg_detailed_info*)data; + } + + MTPDmsg_new_detailed_info &_msg_new_detailed_info() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_msg_new_detailed_info) throw mtpErrorWrongTypeId(_type, mtpc_msg_new_detailed_info); + split(); + return *(MTPDmsg_new_detailed_info*)data; + } + const MTPDmsg_new_detailed_info &c_msg_new_detailed_info() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_msg_new_detailed_info) throw mtpErrorWrongTypeId(_type, mtpc_msg_new_detailed_info); + return *(const MTPDmsg_new_detailed_info*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmsgDetailedInfo(mtpTypeId type); + explicit MTPmsgDetailedInfo(MTPDmsg_detailed_info *_data); + explicit MTPmsgDetailedInfo(MTPDmsg_new_detailed_info *_data); + + friend MTPmsgDetailedInfo MTP_msg_detailed_info(const MTPlong &_msg_id, const MTPlong &_answer_msg_id, MTPint _bytes, MTPint _status); + friend MTPmsgDetailedInfo MTP_msg_new_detailed_info(const MTPlong &_answer_msg_id, MTPint _bytes, MTPint _status); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPMsgDetailedInfo; + +class MTPmsgResendReq : private mtpDataOwner { +public: + MTPmsgResendReq(); + MTPmsgResendReq(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_msg_resend_req) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDmsg_resend_req &_msg_resend_req() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDmsg_resend_req*)data; + } + const MTPDmsg_resend_req &c_msg_resend_req() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDmsg_resend_req*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_msg_resend_req); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmsgResendReq(MTPDmsg_resend_req *_data); + + friend MTPmsgResendReq MTP_msg_resend_req(const MTPVector &_msg_ids); +}; +typedef MTPBoxed MTPMsgResendReq; + +class MTPrpcError : private mtpDataOwner { +public: + MTPrpcError(); + MTPrpcError(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_rpc_error) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDrpc_error &_rpc_error() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDrpc_error*)data; + } + const MTPDrpc_error &c_rpc_error() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDrpc_error*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_rpc_error); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPrpcError(MTPDrpc_error *_data); + + friend MTPrpcError MTP_rpc_error(MTPint _error_code, const MTPstring &_error_message); +}; +typedef MTPBoxed MTPRpcError; + +class MTPrpcDropAnswer : private mtpDataOwner { +public: + MTPrpcDropAnswer() : mtpDataOwner(0), _type(0) { + } + MTPrpcDropAnswer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDrpc_answer_dropped &_rpc_answer_dropped() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_rpc_answer_dropped) throw mtpErrorWrongTypeId(_type, mtpc_rpc_answer_dropped); + split(); + return *(MTPDrpc_answer_dropped*)data; + } + const MTPDrpc_answer_dropped &c_rpc_answer_dropped() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_rpc_answer_dropped) throw mtpErrorWrongTypeId(_type, mtpc_rpc_answer_dropped); + return *(const MTPDrpc_answer_dropped*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPrpcDropAnswer(mtpTypeId type); + explicit MTPrpcDropAnswer(MTPDrpc_answer_dropped *_data); + + friend MTPrpcDropAnswer MTP_rpc_answer_unknown(); + friend MTPrpcDropAnswer MTP_rpc_answer_dropped_running(); + friend MTPrpcDropAnswer MTP_rpc_answer_dropped(const MTPlong &_msg_id, MTPint _seq_no, MTPint _bytes); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPRpcDropAnswer; + +class MTPfutureSalt : private mtpDataOwner { +public: + MTPfutureSalt(); + MTPfutureSalt(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_future_salt) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDfuture_salt &_future_salt() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDfuture_salt*)data; + } + const MTPDfuture_salt &c_future_salt() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDfuture_salt*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_future_salt); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPfutureSalt(MTPDfuture_salt *_data); + + friend MTPfutureSalt MTP_future_salt(MTPint _valid_since, MTPint _valid_until, const MTPlong &_salt); +}; +typedef MTPBoxed MTPFutureSalt; + +class MTPfutureSalts : private mtpDataOwner { +public: + MTPfutureSalts(); + MTPfutureSalts(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_future_salts) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDfuture_salts &_future_salts() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDfuture_salts*)data; + } + const MTPDfuture_salts &c_future_salts() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDfuture_salts*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_future_salts); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPfutureSalts(MTPDfuture_salts *_data); + + friend MTPfutureSalts MTP_future_salts(const MTPlong &_req_msg_id, MTPint _now, const MTPvector &_salts); +}; +typedef MTPBoxed MTPFutureSalts; + +class MTPpong : private mtpDataOwner { +public: + MTPpong(); + MTPpong(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_pong) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDpong &_pong() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDpong*)data; + } + const MTPDpong &c_pong() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDpong*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_pong); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPpong(MTPDpong *_data); + + friend MTPpong MTP_pong(const MTPlong &_msg_id, const MTPlong &_ping_id); +}; +typedef MTPBoxed MTPPong; + +class MTPdestroySessionRes : private mtpDataOwner { +public: + MTPdestroySessionRes() : mtpDataOwner(0), _type(0) { + } + MTPdestroySessionRes(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDdestroy_session_ok &_destroy_session_ok() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_destroy_session_ok) throw mtpErrorWrongTypeId(_type, mtpc_destroy_session_ok); + split(); + return *(MTPDdestroy_session_ok*)data; + } + const MTPDdestroy_session_ok &c_destroy_session_ok() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_destroy_session_ok) throw mtpErrorWrongTypeId(_type, mtpc_destroy_session_ok); + return *(const MTPDdestroy_session_ok*)data; + } + + MTPDdestroy_session_none &_destroy_session_none() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_destroy_session_none) throw mtpErrorWrongTypeId(_type, mtpc_destroy_session_none); + split(); + return *(MTPDdestroy_session_none*)data; + } + const MTPDdestroy_session_none &c_destroy_session_none() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_destroy_session_none) throw mtpErrorWrongTypeId(_type, mtpc_destroy_session_none); + return *(const MTPDdestroy_session_none*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPdestroySessionRes(mtpTypeId type); + explicit MTPdestroySessionRes(MTPDdestroy_session_ok *_data); + explicit MTPdestroySessionRes(MTPDdestroy_session_none *_data); + + friend MTPdestroySessionRes MTP_destroy_session_ok(const MTPlong &_session_id); + friend MTPdestroySessionRes MTP_destroy_session_none(const MTPlong &_session_id); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPDestroySessionRes; + +class MTPnewSession : private mtpDataOwner { +public: + MTPnewSession(); + MTPnewSession(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_new_session_created) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDnew_session_created &_new_session_created() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDnew_session_created*)data; + } + const MTPDnew_session_created &c_new_session_created() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDnew_session_created*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_new_session_created); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPnewSession(MTPDnew_session_created *_data); + + friend MTPnewSession MTP_new_session_created(const MTPlong &_first_msg_id, const MTPlong &_unique_id, const MTPlong &_server_salt); +}; +typedef MTPBoxed MTPNewSession; + +class MTPhttpWait : private mtpDataOwner { +public: + MTPhttpWait(); + MTPhttpWait(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_http_wait) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDhttp_wait &_http_wait() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDhttp_wait*)data; + } + const MTPDhttp_wait &c_http_wait() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDhttp_wait*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_http_wait); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPhttpWait(MTPDhttp_wait *_data); + + friend MTPhttpWait MTP_http_wait(MTPint _max_delay, MTPint _wait_after, MTPint _max_wait); +}; +typedef MTPBoxed MTPHttpWait; + +class MTPinputPeer : private mtpDataOwner { +public: + MTPinputPeer() : mtpDataOwner(0), _type(0) { + } + MTPinputPeer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputPeerContact &_inputPeerContact() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputPeerContact) throw mtpErrorWrongTypeId(_type, mtpc_inputPeerContact); + split(); + return *(MTPDinputPeerContact*)data; + } + const MTPDinputPeerContact &c_inputPeerContact() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputPeerContact) throw mtpErrorWrongTypeId(_type, mtpc_inputPeerContact); + return *(const MTPDinputPeerContact*)data; + } + + MTPDinputPeerForeign &_inputPeerForeign() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputPeerForeign) throw mtpErrorWrongTypeId(_type, mtpc_inputPeerForeign); + split(); + return *(MTPDinputPeerForeign*)data; + } + const MTPDinputPeerForeign &c_inputPeerForeign() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputPeerForeign) throw mtpErrorWrongTypeId(_type, mtpc_inputPeerForeign); + return *(const MTPDinputPeerForeign*)data; + } + + MTPDinputPeerChat &_inputPeerChat() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputPeerChat) throw mtpErrorWrongTypeId(_type, mtpc_inputPeerChat); + split(); + return *(MTPDinputPeerChat*)data; + } + const MTPDinputPeerChat &c_inputPeerChat() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputPeerChat) throw mtpErrorWrongTypeId(_type, mtpc_inputPeerChat); + return *(const MTPDinputPeerChat*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputPeer(mtpTypeId type); + explicit MTPinputPeer(MTPDinputPeerContact *_data); + explicit MTPinputPeer(MTPDinputPeerForeign *_data); + explicit MTPinputPeer(MTPDinputPeerChat *_data); + + friend MTPinputPeer MTP_inputPeerEmpty(); + friend MTPinputPeer MTP_inputPeerSelf(); + friend MTPinputPeer MTP_inputPeerContact(MTPint _user_id); + friend MTPinputPeer MTP_inputPeerForeign(MTPint _user_id, const MTPlong &_access_hash); + friend MTPinputPeer MTP_inputPeerChat(MTPint _chat_id); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputPeer; + +class MTPinputUser : private mtpDataOwner { +public: + MTPinputUser() : mtpDataOwner(0), _type(0) { + } + MTPinputUser(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputUserContact &_inputUserContact() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputUserContact) throw mtpErrorWrongTypeId(_type, mtpc_inputUserContact); + split(); + return *(MTPDinputUserContact*)data; + } + const MTPDinputUserContact &c_inputUserContact() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputUserContact) throw mtpErrorWrongTypeId(_type, mtpc_inputUserContact); + return *(const MTPDinputUserContact*)data; + } + + MTPDinputUserForeign &_inputUserForeign() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputUserForeign) throw mtpErrorWrongTypeId(_type, mtpc_inputUserForeign); + split(); + return *(MTPDinputUserForeign*)data; + } + const MTPDinputUserForeign &c_inputUserForeign() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputUserForeign) throw mtpErrorWrongTypeId(_type, mtpc_inputUserForeign); + return *(const MTPDinputUserForeign*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputUser(mtpTypeId type); + explicit MTPinputUser(MTPDinputUserContact *_data); + explicit MTPinputUser(MTPDinputUserForeign *_data); + + friend MTPinputUser MTP_inputUserEmpty(); + friend MTPinputUser MTP_inputUserSelf(); + friend MTPinputUser MTP_inputUserContact(MTPint _user_id); + friend MTPinputUser MTP_inputUserForeign(MTPint _user_id, const MTPlong &_access_hash); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputUser; + +class MTPinputContact : private mtpDataOwner { +public: + MTPinputContact(); + MTPinputContact(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_inputPhoneContact) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDinputPhoneContact &_inputPhoneContact() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDinputPhoneContact*)data; + } + const MTPDinputPhoneContact &c_inputPhoneContact() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDinputPhoneContact*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_inputPhoneContact); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputContact(MTPDinputPhoneContact *_data); + + friend MTPinputContact MTP_inputPhoneContact(const MTPlong &_client_id, const MTPstring &_phone, const MTPstring &_first_name, const MTPstring &_last_name); +}; +typedef MTPBoxed MTPInputContact; + +class MTPinputFile : private mtpDataOwner { +public: + MTPinputFile() : mtpDataOwner(0), _type(0) { + } + MTPinputFile(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputFile &_inputFile() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputFile) throw mtpErrorWrongTypeId(_type, mtpc_inputFile); + split(); + return *(MTPDinputFile*)data; + } + const MTPDinputFile &c_inputFile() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputFile) throw mtpErrorWrongTypeId(_type, mtpc_inputFile); + return *(const MTPDinputFile*)data; + } + + MTPDinputFileBig &_inputFileBig() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputFileBig) throw mtpErrorWrongTypeId(_type, mtpc_inputFileBig); + split(); + return *(MTPDinputFileBig*)data; + } + const MTPDinputFileBig &c_inputFileBig() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputFileBig) throw mtpErrorWrongTypeId(_type, mtpc_inputFileBig); + return *(const MTPDinputFileBig*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputFile(mtpTypeId type); + explicit MTPinputFile(MTPDinputFile *_data); + explicit MTPinputFile(MTPDinputFileBig *_data); + + friend MTPinputFile MTP_inputFile(const MTPlong &_id, MTPint _parts, const MTPstring &_name, const MTPstring &_md5_checksum); + friend MTPinputFile MTP_inputFileBig(const MTPlong &_id, MTPint _parts, const MTPstring &_name); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputFile; + +class MTPinputMedia : private mtpDataOwner { +public: + MTPinputMedia() : mtpDataOwner(0), _type(0) { + } + MTPinputMedia(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputMediaUploadedPhoto &_inputMediaUploadedPhoto() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaUploadedPhoto) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedPhoto); + split(); + return *(MTPDinputMediaUploadedPhoto*)data; + } + const MTPDinputMediaUploadedPhoto &c_inputMediaUploadedPhoto() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaUploadedPhoto) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedPhoto); + return *(const MTPDinputMediaUploadedPhoto*)data; + } + + MTPDinputMediaPhoto &_inputMediaPhoto() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaPhoto) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaPhoto); + split(); + return *(MTPDinputMediaPhoto*)data; + } + const MTPDinputMediaPhoto &c_inputMediaPhoto() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaPhoto) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaPhoto); + return *(const MTPDinputMediaPhoto*)data; + } + + MTPDinputMediaGeoPoint &_inputMediaGeoPoint() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaGeoPoint) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaGeoPoint); + split(); + return *(MTPDinputMediaGeoPoint*)data; + } + const MTPDinputMediaGeoPoint &c_inputMediaGeoPoint() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaGeoPoint) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaGeoPoint); + return *(const MTPDinputMediaGeoPoint*)data; + } + + MTPDinputMediaContact &_inputMediaContact() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaContact) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaContact); + split(); + return *(MTPDinputMediaContact*)data; + } + const MTPDinputMediaContact &c_inputMediaContact() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaContact) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaContact); + return *(const MTPDinputMediaContact*)data; + } + + MTPDinputMediaUploadedVideo &_inputMediaUploadedVideo() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaUploadedVideo) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedVideo); + split(); + return *(MTPDinputMediaUploadedVideo*)data; + } + const MTPDinputMediaUploadedVideo &c_inputMediaUploadedVideo() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaUploadedVideo) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedVideo); + return *(const MTPDinputMediaUploadedVideo*)data; + } + + MTPDinputMediaUploadedThumbVideo &_inputMediaUploadedThumbVideo() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaUploadedThumbVideo) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedThumbVideo); + split(); + return *(MTPDinputMediaUploadedThumbVideo*)data; + } + const MTPDinputMediaUploadedThumbVideo &c_inputMediaUploadedThumbVideo() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaUploadedThumbVideo) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedThumbVideo); + return *(const MTPDinputMediaUploadedThumbVideo*)data; + } + + MTPDinputMediaVideo &_inputMediaVideo() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaVideo) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaVideo); + split(); + return *(MTPDinputMediaVideo*)data; + } + const MTPDinputMediaVideo &c_inputMediaVideo() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaVideo) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaVideo); + return *(const MTPDinputMediaVideo*)data; + } + + MTPDinputMediaUploadedAudio &_inputMediaUploadedAudio() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaUploadedAudio) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedAudio); + split(); + return *(MTPDinputMediaUploadedAudio*)data; + } + const MTPDinputMediaUploadedAudio &c_inputMediaUploadedAudio() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaUploadedAudio) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedAudio); + return *(const MTPDinputMediaUploadedAudio*)data; + } + + MTPDinputMediaAudio &_inputMediaAudio() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaAudio) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaAudio); + split(); + return *(MTPDinputMediaAudio*)data; + } + const MTPDinputMediaAudio &c_inputMediaAudio() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaAudio) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaAudio); + return *(const MTPDinputMediaAudio*)data; + } + + MTPDinputMediaUploadedDocument &_inputMediaUploadedDocument() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaUploadedDocument) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedDocument); + split(); + return *(MTPDinputMediaUploadedDocument*)data; + } + const MTPDinputMediaUploadedDocument &c_inputMediaUploadedDocument() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaUploadedDocument) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedDocument); + return *(const MTPDinputMediaUploadedDocument*)data; + } + + MTPDinputMediaUploadedThumbDocument &_inputMediaUploadedThumbDocument() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaUploadedThumbDocument) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedThumbDocument); + split(); + return *(MTPDinputMediaUploadedThumbDocument*)data; + } + const MTPDinputMediaUploadedThumbDocument &c_inputMediaUploadedThumbDocument() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaUploadedThumbDocument) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedThumbDocument); + return *(const MTPDinputMediaUploadedThumbDocument*)data; + } + + MTPDinputMediaDocument &_inputMediaDocument() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaDocument) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaDocument); + split(); + return *(MTPDinputMediaDocument*)data; + } + const MTPDinputMediaDocument &c_inputMediaDocument() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaDocument) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaDocument); + return *(const MTPDinputMediaDocument*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputMedia(mtpTypeId type); + explicit MTPinputMedia(MTPDinputMediaUploadedPhoto *_data); + explicit MTPinputMedia(MTPDinputMediaPhoto *_data); + explicit MTPinputMedia(MTPDinputMediaGeoPoint *_data); + explicit MTPinputMedia(MTPDinputMediaContact *_data); + explicit MTPinputMedia(MTPDinputMediaUploadedVideo *_data); + explicit MTPinputMedia(MTPDinputMediaUploadedThumbVideo *_data); + explicit MTPinputMedia(MTPDinputMediaVideo *_data); + explicit MTPinputMedia(MTPDinputMediaUploadedAudio *_data); + explicit MTPinputMedia(MTPDinputMediaAudio *_data); + explicit MTPinputMedia(MTPDinputMediaUploadedDocument *_data); + explicit MTPinputMedia(MTPDinputMediaUploadedThumbDocument *_data); + explicit MTPinputMedia(MTPDinputMediaDocument *_data); + + friend MTPinputMedia MTP_inputMediaEmpty(); + friend MTPinputMedia MTP_inputMediaUploadedPhoto(const MTPInputFile &_file); + friend MTPinputMedia MTP_inputMediaPhoto(const MTPInputPhoto &_id); + friend MTPinputMedia MTP_inputMediaGeoPoint(const MTPInputGeoPoint &_geo_point); + friend MTPinputMedia MTP_inputMediaContact(const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name); + friend MTPinputMedia MTP_inputMediaUploadedVideo(const MTPInputFile &_file, MTPint _duration, MTPint _w, MTPint _h, const MTPstring &_mime_type); + friend MTPinputMedia MTP_inputMediaUploadedThumbVideo(const MTPInputFile &_file, const MTPInputFile &_thumb, MTPint _duration, MTPint _w, MTPint _h, const MTPstring &_mime_type); + friend MTPinputMedia MTP_inputMediaVideo(const MTPInputVideo &_id); + friend MTPinputMedia MTP_inputMediaUploadedAudio(const MTPInputFile &_file, MTPint _duration, const MTPstring &_mime_type); + friend MTPinputMedia MTP_inputMediaAudio(const MTPInputAudio &_id); + friend MTPinputMedia MTP_inputMediaUploadedDocument(const MTPInputFile &_file, const MTPstring &_file_name, const MTPstring &_mime_type); + friend MTPinputMedia MTP_inputMediaUploadedThumbDocument(const MTPInputFile &_file, const MTPInputFile &_thumb, const MTPstring &_file_name, const MTPstring &_mime_type); + friend MTPinputMedia MTP_inputMediaDocument(const MTPInputDocument &_id); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputMedia; + +class MTPinputChatPhoto : private mtpDataOwner { +public: + MTPinputChatPhoto() : mtpDataOwner(0), _type(0) { + } + MTPinputChatPhoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputChatUploadedPhoto &_inputChatUploadedPhoto() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputChatUploadedPhoto) throw mtpErrorWrongTypeId(_type, mtpc_inputChatUploadedPhoto); + split(); + return *(MTPDinputChatUploadedPhoto*)data; + } + const MTPDinputChatUploadedPhoto &c_inputChatUploadedPhoto() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputChatUploadedPhoto) throw mtpErrorWrongTypeId(_type, mtpc_inputChatUploadedPhoto); + return *(const MTPDinputChatUploadedPhoto*)data; + } + + MTPDinputChatPhoto &_inputChatPhoto() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputChatPhoto) throw mtpErrorWrongTypeId(_type, mtpc_inputChatPhoto); + split(); + return *(MTPDinputChatPhoto*)data; + } + const MTPDinputChatPhoto &c_inputChatPhoto() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputChatPhoto) throw mtpErrorWrongTypeId(_type, mtpc_inputChatPhoto); + return *(const MTPDinputChatPhoto*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputChatPhoto(mtpTypeId type); + explicit MTPinputChatPhoto(MTPDinputChatUploadedPhoto *_data); + explicit MTPinputChatPhoto(MTPDinputChatPhoto *_data); + + friend MTPinputChatPhoto MTP_inputChatPhotoEmpty(); + friend MTPinputChatPhoto MTP_inputChatUploadedPhoto(const MTPInputFile &_file, const MTPInputPhotoCrop &_crop); + friend MTPinputChatPhoto MTP_inputChatPhoto(const MTPInputPhoto &_id, const MTPInputPhotoCrop &_crop); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputChatPhoto; + +class MTPinputGeoPoint : private mtpDataOwner { +public: + MTPinputGeoPoint() : mtpDataOwner(0), _type(0) { + } + MTPinputGeoPoint(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputGeoPoint &_inputGeoPoint() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputGeoPoint) throw mtpErrorWrongTypeId(_type, mtpc_inputGeoPoint); + split(); + return *(MTPDinputGeoPoint*)data; + } + const MTPDinputGeoPoint &c_inputGeoPoint() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputGeoPoint) throw mtpErrorWrongTypeId(_type, mtpc_inputGeoPoint); + return *(const MTPDinputGeoPoint*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputGeoPoint(mtpTypeId type); + explicit MTPinputGeoPoint(MTPDinputGeoPoint *_data); + + friend MTPinputGeoPoint MTP_inputGeoPointEmpty(); + friend MTPinputGeoPoint MTP_inputGeoPoint(const MTPdouble &_lat, const MTPdouble &_long); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputGeoPoint; + +class MTPinputPhoto : private mtpDataOwner { +public: + MTPinputPhoto() : mtpDataOwner(0), _type(0) { + } + MTPinputPhoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputPhoto &_inputPhoto() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputPhoto) throw mtpErrorWrongTypeId(_type, mtpc_inputPhoto); + split(); + return *(MTPDinputPhoto*)data; + } + const MTPDinputPhoto &c_inputPhoto() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputPhoto) throw mtpErrorWrongTypeId(_type, mtpc_inputPhoto); + return *(const MTPDinputPhoto*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputPhoto(mtpTypeId type); + explicit MTPinputPhoto(MTPDinputPhoto *_data); + + friend MTPinputPhoto MTP_inputPhotoEmpty(); + friend MTPinputPhoto MTP_inputPhoto(const MTPlong &_id, const MTPlong &_access_hash); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputPhoto; + +class MTPinputVideo : private mtpDataOwner { +public: + MTPinputVideo() : mtpDataOwner(0), _type(0) { + } + MTPinputVideo(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputVideo &_inputVideo() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputVideo) throw mtpErrorWrongTypeId(_type, mtpc_inputVideo); + split(); + return *(MTPDinputVideo*)data; + } + const MTPDinputVideo &c_inputVideo() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputVideo) throw mtpErrorWrongTypeId(_type, mtpc_inputVideo); + return *(const MTPDinputVideo*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputVideo(mtpTypeId type); + explicit MTPinputVideo(MTPDinputVideo *_data); + + friend MTPinputVideo MTP_inputVideoEmpty(); + friend MTPinputVideo MTP_inputVideo(const MTPlong &_id, const MTPlong &_access_hash); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputVideo; + +class MTPinputFileLocation : private mtpDataOwner { +public: + MTPinputFileLocation() : mtpDataOwner(0), _type(0) { + } + MTPinputFileLocation(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputFileLocation &_inputFileLocation() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputFileLocation); + split(); + return *(MTPDinputFileLocation*)data; + } + const MTPDinputFileLocation &c_inputFileLocation() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputFileLocation); + return *(const MTPDinputFileLocation*)data; + } + + MTPDinputVideoFileLocation &_inputVideoFileLocation() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputVideoFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputVideoFileLocation); + split(); + return *(MTPDinputVideoFileLocation*)data; + } + const MTPDinputVideoFileLocation &c_inputVideoFileLocation() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputVideoFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputVideoFileLocation); + return *(const MTPDinputVideoFileLocation*)data; + } + + MTPDinputEncryptedFileLocation &_inputEncryptedFileLocation() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputEncryptedFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputEncryptedFileLocation); + split(); + return *(MTPDinputEncryptedFileLocation*)data; + } + const MTPDinputEncryptedFileLocation &c_inputEncryptedFileLocation() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputEncryptedFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputEncryptedFileLocation); + return *(const MTPDinputEncryptedFileLocation*)data; + } + + MTPDinputAudioFileLocation &_inputAudioFileLocation() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputAudioFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputAudioFileLocation); + split(); + return *(MTPDinputAudioFileLocation*)data; + } + const MTPDinputAudioFileLocation &c_inputAudioFileLocation() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputAudioFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputAudioFileLocation); + return *(const MTPDinputAudioFileLocation*)data; + } + + MTPDinputDocumentFileLocation &_inputDocumentFileLocation() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputDocumentFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputDocumentFileLocation); + split(); + return *(MTPDinputDocumentFileLocation*)data; + } + const MTPDinputDocumentFileLocation &c_inputDocumentFileLocation() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputDocumentFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputDocumentFileLocation); + return *(const MTPDinputDocumentFileLocation*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputFileLocation(mtpTypeId type); + explicit MTPinputFileLocation(MTPDinputFileLocation *_data); + explicit MTPinputFileLocation(MTPDinputVideoFileLocation *_data); + explicit MTPinputFileLocation(MTPDinputEncryptedFileLocation *_data); + explicit MTPinputFileLocation(MTPDinputAudioFileLocation *_data); + explicit MTPinputFileLocation(MTPDinputDocumentFileLocation *_data); + + friend MTPinputFileLocation MTP_inputFileLocation(const MTPlong &_volume_id, MTPint _local_id, const MTPlong &_secret); + friend MTPinputFileLocation MTP_inputVideoFileLocation(const MTPlong &_id, const MTPlong &_access_hash); + friend MTPinputFileLocation MTP_inputEncryptedFileLocation(const MTPlong &_id, const MTPlong &_access_hash); + friend MTPinputFileLocation MTP_inputAudioFileLocation(const MTPlong &_id, const MTPlong &_access_hash); + friend MTPinputFileLocation MTP_inputDocumentFileLocation(const MTPlong &_id, const MTPlong &_access_hash); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputFileLocation; + +class MTPinputPhotoCrop : private mtpDataOwner { +public: + MTPinputPhotoCrop() : mtpDataOwner(0), _type(0) { + } + MTPinputPhotoCrop(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputPhotoCrop &_inputPhotoCrop() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputPhotoCrop) throw mtpErrorWrongTypeId(_type, mtpc_inputPhotoCrop); + split(); + return *(MTPDinputPhotoCrop*)data; + } + const MTPDinputPhotoCrop &c_inputPhotoCrop() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputPhotoCrop) throw mtpErrorWrongTypeId(_type, mtpc_inputPhotoCrop); + return *(const MTPDinputPhotoCrop*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputPhotoCrop(mtpTypeId type); + explicit MTPinputPhotoCrop(MTPDinputPhotoCrop *_data); + + friend MTPinputPhotoCrop MTP_inputPhotoCropAuto(); + friend MTPinputPhotoCrop MTP_inputPhotoCrop(const MTPdouble &_crop_left, const MTPdouble &_crop_top, const MTPdouble &_crop_width); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputPhotoCrop; + +class MTPinputAppEvent : private mtpDataOwner { +public: + MTPinputAppEvent(); + MTPinputAppEvent(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_inputAppEvent) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDinputAppEvent &_inputAppEvent() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDinputAppEvent*)data; + } + const MTPDinputAppEvent &c_inputAppEvent() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDinputAppEvent*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_inputAppEvent); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputAppEvent(MTPDinputAppEvent *_data); + + friend MTPinputAppEvent MTP_inputAppEvent(const MTPdouble &_time, const MTPstring &_type, const MTPlong &_peer, const MTPstring &_data); +}; +typedef MTPBoxed MTPInputAppEvent; + +class MTPpeer : private mtpDataOwner { +public: + MTPpeer() : mtpDataOwner(0), _type(0) { + } + MTPpeer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDpeerUser &_peerUser() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_peerUser) throw mtpErrorWrongTypeId(_type, mtpc_peerUser); + split(); + return *(MTPDpeerUser*)data; + } + const MTPDpeerUser &c_peerUser() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_peerUser) throw mtpErrorWrongTypeId(_type, mtpc_peerUser); + return *(const MTPDpeerUser*)data; + } + + MTPDpeerChat &_peerChat() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_peerChat) throw mtpErrorWrongTypeId(_type, mtpc_peerChat); + split(); + return *(MTPDpeerChat*)data; + } + const MTPDpeerChat &c_peerChat() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_peerChat) throw mtpErrorWrongTypeId(_type, mtpc_peerChat); + return *(const MTPDpeerChat*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPpeer(mtpTypeId type); + explicit MTPpeer(MTPDpeerUser *_data); + explicit MTPpeer(MTPDpeerChat *_data); + + friend MTPpeer MTP_peerUser(MTPint _user_id); + friend MTPpeer MTP_peerChat(MTPint _chat_id); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPPeer; + +class MTPstorage_fileType { +public: + MTPstorage_fileType() : _type(0) { + } + MTPstorage_fileType(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : _type(0) { + read(from, end, cons); + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPstorage_fileType(mtpTypeId type); + + friend MTPstorage_fileType MTP_storage_fileUnknown(); + friend MTPstorage_fileType MTP_storage_fileJpeg(); + friend MTPstorage_fileType MTP_storage_fileGif(); + friend MTPstorage_fileType MTP_storage_filePng(); + friend MTPstorage_fileType MTP_storage_filePdf(); + friend MTPstorage_fileType MTP_storage_fileMp3(); + friend MTPstorage_fileType MTP_storage_fileMov(); + friend MTPstorage_fileType MTP_storage_filePartial(); + friend MTPstorage_fileType MTP_storage_fileMp4(); + friend MTPstorage_fileType MTP_storage_fileWebp(); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPstorage_FileType; + +class MTPfileLocation : private mtpDataOwner { +public: + MTPfileLocation() : mtpDataOwner(0), _type(0) { + } + MTPfileLocation(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDfileLocationUnavailable &_fileLocationUnavailable() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_fileLocationUnavailable) throw mtpErrorWrongTypeId(_type, mtpc_fileLocationUnavailable); + split(); + return *(MTPDfileLocationUnavailable*)data; + } + const MTPDfileLocationUnavailable &c_fileLocationUnavailable() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_fileLocationUnavailable) throw mtpErrorWrongTypeId(_type, mtpc_fileLocationUnavailable); + return *(const MTPDfileLocationUnavailable*)data; + } + + MTPDfileLocation &_fileLocation() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_fileLocation) throw mtpErrorWrongTypeId(_type, mtpc_fileLocation); + split(); + return *(MTPDfileLocation*)data; + } + const MTPDfileLocation &c_fileLocation() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_fileLocation) throw mtpErrorWrongTypeId(_type, mtpc_fileLocation); + return *(const MTPDfileLocation*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPfileLocation(mtpTypeId type); + explicit MTPfileLocation(MTPDfileLocationUnavailable *_data); + explicit MTPfileLocation(MTPDfileLocation *_data); + + friend MTPfileLocation MTP_fileLocationUnavailable(const MTPlong &_volume_id, MTPint _local_id, const MTPlong &_secret); + friend MTPfileLocation MTP_fileLocation(MTPint _dc_id, const MTPlong &_volume_id, MTPint _local_id, const MTPlong &_secret); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPFileLocation; + +class MTPuser : private mtpDataOwner { +public: + MTPuser() : mtpDataOwner(0), _type(0) { + } + MTPuser(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDuserEmpty &_userEmpty() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userEmpty) throw mtpErrorWrongTypeId(_type, mtpc_userEmpty); + split(); + return *(MTPDuserEmpty*)data; + } + const MTPDuserEmpty &c_userEmpty() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userEmpty) throw mtpErrorWrongTypeId(_type, mtpc_userEmpty); + return *(const MTPDuserEmpty*)data; + } + + MTPDuserSelf &_userSelf() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userSelf) throw mtpErrorWrongTypeId(_type, mtpc_userSelf); + split(); + return *(MTPDuserSelf*)data; + } + const MTPDuserSelf &c_userSelf() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userSelf) throw mtpErrorWrongTypeId(_type, mtpc_userSelf); + return *(const MTPDuserSelf*)data; + } + + MTPDuserContact &_userContact() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userContact) throw mtpErrorWrongTypeId(_type, mtpc_userContact); + split(); + return *(MTPDuserContact*)data; + } + const MTPDuserContact &c_userContact() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userContact) throw mtpErrorWrongTypeId(_type, mtpc_userContact); + return *(const MTPDuserContact*)data; + } + + MTPDuserRequest &_userRequest() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userRequest) throw mtpErrorWrongTypeId(_type, mtpc_userRequest); + split(); + return *(MTPDuserRequest*)data; + } + const MTPDuserRequest &c_userRequest() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userRequest) throw mtpErrorWrongTypeId(_type, mtpc_userRequest); + return *(const MTPDuserRequest*)data; + } + + MTPDuserForeign &_userForeign() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userForeign) throw mtpErrorWrongTypeId(_type, mtpc_userForeign); + split(); + return *(MTPDuserForeign*)data; + } + const MTPDuserForeign &c_userForeign() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userForeign) throw mtpErrorWrongTypeId(_type, mtpc_userForeign); + return *(const MTPDuserForeign*)data; + } + + MTPDuserDeleted &_userDeleted() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userDeleted) throw mtpErrorWrongTypeId(_type, mtpc_userDeleted); + split(); + return *(MTPDuserDeleted*)data; + } + const MTPDuserDeleted &c_userDeleted() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userDeleted) throw mtpErrorWrongTypeId(_type, mtpc_userDeleted); + return *(const MTPDuserDeleted*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPuser(mtpTypeId type); + explicit MTPuser(MTPDuserEmpty *_data); + explicit MTPuser(MTPDuserSelf *_data); + explicit MTPuser(MTPDuserContact *_data); + explicit MTPuser(MTPDuserRequest *_data); + explicit MTPuser(MTPDuserForeign *_data); + explicit MTPuser(MTPDuserDeleted *_data); + + friend MTPuser MTP_userEmpty(MTPint _id); + friend MTPuser MTP_userSelf(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name, const MTPstring &_phone, const MTPUserProfilePhoto &_photo, const MTPUserStatus &_status, MTPBool _inactive); + friend MTPuser MTP_userContact(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name, const MTPlong &_access_hash, const MTPstring &_phone, const MTPUserProfilePhoto &_photo, const MTPUserStatus &_status); + friend MTPuser MTP_userRequest(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name, const MTPlong &_access_hash, const MTPstring &_phone, const MTPUserProfilePhoto &_photo, const MTPUserStatus &_status); + friend MTPuser MTP_userForeign(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name, const MTPlong &_access_hash, const MTPUserProfilePhoto &_photo, const MTPUserStatus &_status); + friend MTPuser MTP_userDeleted(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPUser; + +class MTPuserProfilePhoto : private mtpDataOwner { +public: + MTPuserProfilePhoto() : mtpDataOwner(0), _type(0) { + } + MTPuserProfilePhoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDuserProfilePhoto &_userProfilePhoto() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userProfilePhoto) throw mtpErrorWrongTypeId(_type, mtpc_userProfilePhoto); + split(); + return *(MTPDuserProfilePhoto*)data; + } + const MTPDuserProfilePhoto &c_userProfilePhoto() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userProfilePhoto) throw mtpErrorWrongTypeId(_type, mtpc_userProfilePhoto); + return *(const MTPDuserProfilePhoto*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPuserProfilePhoto(mtpTypeId type); + explicit MTPuserProfilePhoto(MTPDuserProfilePhoto *_data); + + friend MTPuserProfilePhoto MTP_userProfilePhotoEmpty(); + friend MTPuserProfilePhoto MTP_userProfilePhoto(const MTPlong &_photo_id, const MTPFileLocation &_photo_small, const MTPFileLocation &_photo_big); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPUserProfilePhoto; + +class MTPuserStatus : private mtpDataOwner { +public: + MTPuserStatus() : mtpDataOwner(0), _type(0) { + } + MTPuserStatus(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDuserStatusOnline &_userStatusOnline() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userStatusOnline) throw mtpErrorWrongTypeId(_type, mtpc_userStatusOnline); + split(); + return *(MTPDuserStatusOnline*)data; + } + const MTPDuserStatusOnline &c_userStatusOnline() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userStatusOnline) throw mtpErrorWrongTypeId(_type, mtpc_userStatusOnline); + return *(const MTPDuserStatusOnline*)data; + } + + MTPDuserStatusOffline &_userStatusOffline() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userStatusOffline) throw mtpErrorWrongTypeId(_type, mtpc_userStatusOffline); + split(); + return *(MTPDuserStatusOffline*)data; + } + const MTPDuserStatusOffline &c_userStatusOffline() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_userStatusOffline) throw mtpErrorWrongTypeId(_type, mtpc_userStatusOffline); + return *(const MTPDuserStatusOffline*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPuserStatus(mtpTypeId type); + explicit MTPuserStatus(MTPDuserStatusOnline *_data); + explicit MTPuserStatus(MTPDuserStatusOffline *_data); + + friend MTPuserStatus MTP_userStatusEmpty(); + friend MTPuserStatus MTP_userStatusOnline(MTPint _expires); + friend MTPuserStatus MTP_userStatusOffline(MTPint _was_online); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPUserStatus; + +class MTPchat : private mtpDataOwner { +public: + MTPchat() : mtpDataOwner(0), _type(0) { + } + MTPchat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDchatEmpty &_chatEmpty() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_chatEmpty) throw mtpErrorWrongTypeId(_type, mtpc_chatEmpty); + split(); + return *(MTPDchatEmpty*)data; + } + const MTPDchatEmpty &c_chatEmpty() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_chatEmpty) throw mtpErrorWrongTypeId(_type, mtpc_chatEmpty); + return *(const MTPDchatEmpty*)data; + } + + MTPDchat &_chat() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_chat) throw mtpErrorWrongTypeId(_type, mtpc_chat); + split(); + return *(MTPDchat*)data; + } + const MTPDchat &c_chat() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_chat) throw mtpErrorWrongTypeId(_type, mtpc_chat); + return *(const MTPDchat*)data; + } + + MTPDchatForbidden &_chatForbidden() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_chatForbidden) throw mtpErrorWrongTypeId(_type, mtpc_chatForbidden); + split(); + return *(MTPDchatForbidden*)data; + } + const MTPDchatForbidden &c_chatForbidden() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_chatForbidden) throw mtpErrorWrongTypeId(_type, mtpc_chatForbidden); + return *(const MTPDchatForbidden*)data; + } + + MTPDgeoChat &_geoChat() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geoChat) throw mtpErrorWrongTypeId(_type, mtpc_geoChat); + split(); + return *(MTPDgeoChat*)data; + } + const MTPDgeoChat &c_geoChat() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geoChat) throw mtpErrorWrongTypeId(_type, mtpc_geoChat); + return *(const MTPDgeoChat*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPchat(mtpTypeId type); + explicit MTPchat(MTPDchatEmpty *_data); + explicit MTPchat(MTPDchat *_data); + explicit MTPchat(MTPDchatForbidden *_data); + explicit MTPchat(MTPDgeoChat *_data); + + friend MTPchat MTP_chatEmpty(MTPint _id); + friend MTPchat MTP_chat(MTPint _id, const MTPstring &_title, const MTPChatPhoto &_photo, MTPint _participants_count, MTPint _date, MTPBool _left, MTPint _version); + friend MTPchat MTP_chatForbidden(MTPint _id, const MTPstring &_title, MTPint _date); + friend MTPchat MTP_geoChat(MTPint _id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_address, const MTPstring &_venue, const MTPGeoPoint &_geo, const MTPChatPhoto &_photo, MTPint _participants_count, MTPint _date, MTPBool _checked_in, MTPint _version); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPChat; + +class MTPchatFull : private mtpDataOwner { +public: + MTPchatFull(); + MTPchatFull(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_chatFull) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDchatFull &_chatFull() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDchatFull*)data; + } + const MTPDchatFull &c_chatFull() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDchatFull*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_chatFull); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPchatFull(MTPDchatFull *_data); + + friend MTPchatFull MTP_chatFull(MTPint _id, const MTPChatParticipants &_participants, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings); +}; +typedef MTPBoxed MTPChatFull; + +class MTPchatParticipant : private mtpDataOwner { +public: + MTPchatParticipant(); + MTPchatParticipant(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_chatParticipant) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDchatParticipant &_chatParticipant() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDchatParticipant*)data; + } + const MTPDchatParticipant &c_chatParticipant() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDchatParticipant*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_chatParticipant); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPchatParticipant(MTPDchatParticipant *_data); + + friend MTPchatParticipant MTP_chatParticipant(MTPint _user_id, MTPint _inviter_id, MTPint _date); +}; +typedef MTPBoxed MTPChatParticipant; + +class MTPchatParticipants : private mtpDataOwner { +public: + MTPchatParticipants() : mtpDataOwner(0), _type(0) { + } + MTPchatParticipants(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDchatParticipantsForbidden &_chatParticipantsForbidden() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_chatParticipantsForbidden) throw mtpErrorWrongTypeId(_type, mtpc_chatParticipantsForbidden); + split(); + return *(MTPDchatParticipantsForbidden*)data; + } + const MTPDchatParticipantsForbidden &c_chatParticipantsForbidden() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_chatParticipantsForbidden) throw mtpErrorWrongTypeId(_type, mtpc_chatParticipantsForbidden); + return *(const MTPDchatParticipantsForbidden*)data; + } + + MTPDchatParticipants &_chatParticipants() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_chatParticipants) throw mtpErrorWrongTypeId(_type, mtpc_chatParticipants); + split(); + return *(MTPDchatParticipants*)data; + } + const MTPDchatParticipants &c_chatParticipants() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_chatParticipants) throw mtpErrorWrongTypeId(_type, mtpc_chatParticipants); + return *(const MTPDchatParticipants*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPchatParticipants(mtpTypeId type); + explicit MTPchatParticipants(MTPDchatParticipantsForbidden *_data); + explicit MTPchatParticipants(MTPDchatParticipants *_data); + + friend MTPchatParticipants MTP_chatParticipantsForbidden(MTPint _chat_id); + friend MTPchatParticipants MTP_chatParticipants(MTPint _chat_id, MTPint _admin_id, const MTPVector &_participants, MTPint _version); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPChatParticipants; + +class MTPchatPhoto : private mtpDataOwner { +public: + MTPchatPhoto() : mtpDataOwner(0), _type(0) { + } + MTPchatPhoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDchatPhoto &_chatPhoto() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_chatPhoto) throw mtpErrorWrongTypeId(_type, mtpc_chatPhoto); + split(); + return *(MTPDchatPhoto*)data; + } + const MTPDchatPhoto &c_chatPhoto() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_chatPhoto) throw mtpErrorWrongTypeId(_type, mtpc_chatPhoto); + return *(const MTPDchatPhoto*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPchatPhoto(mtpTypeId type); + explicit MTPchatPhoto(MTPDchatPhoto *_data); + + friend MTPchatPhoto MTP_chatPhotoEmpty(); + friend MTPchatPhoto MTP_chatPhoto(const MTPFileLocation &_photo_small, const MTPFileLocation &_photo_big); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPChatPhoto; + +class MTPmessage : private mtpDataOwner { +public: + MTPmessage() : mtpDataOwner(0), _type(0) { + } + MTPmessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessageEmpty &_messageEmpty() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageEmpty) throw mtpErrorWrongTypeId(_type, mtpc_messageEmpty); + split(); + return *(MTPDmessageEmpty*)data; + } + const MTPDmessageEmpty &c_messageEmpty() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageEmpty) throw mtpErrorWrongTypeId(_type, mtpc_messageEmpty); + return *(const MTPDmessageEmpty*)data; + } + + MTPDmessage &_message() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_message) throw mtpErrorWrongTypeId(_type, mtpc_message); + split(); + return *(MTPDmessage*)data; + } + const MTPDmessage &c_message() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_message) throw mtpErrorWrongTypeId(_type, mtpc_message); + return *(const MTPDmessage*)data; + } + + MTPDmessageForwarded &_messageForwarded() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageForwarded) throw mtpErrorWrongTypeId(_type, mtpc_messageForwarded); + split(); + return *(MTPDmessageForwarded*)data; + } + const MTPDmessageForwarded &c_messageForwarded() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageForwarded) throw mtpErrorWrongTypeId(_type, mtpc_messageForwarded); + return *(const MTPDmessageForwarded*)data; + } + + MTPDmessageService &_messageService() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageService) throw mtpErrorWrongTypeId(_type, mtpc_messageService); + split(); + return *(MTPDmessageService*)data; + } + const MTPDmessageService &c_messageService() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageService) throw mtpErrorWrongTypeId(_type, mtpc_messageService); + return *(const MTPDmessageService*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessage(mtpTypeId type); + explicit MTPmessage(MTPDmessageEmpty *_data); + explicit MTPmessage(MTPDmessage *_data); + explicit MTPmessage(MTPDmessageForwarded *_data); + explicit MTPmessage(MTPDmessageService *_data); + + friend MTPmessage MTP_messageEmpty(MTPint _id); + friend MTPmessage MTP_message(MTPint _id, MTPint _from_id, const MTPPeer &_to_id, MTPBool _out, MTPBool _unread, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media); + friend MTPmessage MTP_messageForwarded(MTPint _id, MTPint _fwd_from_id, MTPint _fwd_date, MTPint _from_id, const MTPPeer &_to_id, MTPBool _out, MTPBool _unread, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media); + friend MTPmessage MTP_messageService(MTPint _id, MTPint _from_id, const MTPPeer &_to_id, MTPBool _out, MTPBool _unread, MTPint _date, const MTPMessageAction &_action); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPMessage; + +class MTPmessageMedia : private mtpDataOwner { +public: + MTPmessageMedia() : mtpDataOwner(0), _type(0) { + } + MTPmessageMedia(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessageMediaPhoto &_messageMediaPhoto() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaPhoto) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaPhoto); + split(); + return *(MTPDmessageMediaPhoto*)data; + } + const MTPDmessageMediaPhoto &c_messageMediaPhoto() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaPhoto) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaPhoto); + return *(const MTPDmessageMediaPhoto*)data; + } + + MTPDmessageMediaVideo &_messageMediaVideo() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaVideo) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaVideo); + split(); + return *(MTPDmessageMediaVideo*)data; + } + const MTPDmessageMediaVideo &c_messageMediaVideo() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaVideo) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaVideo); + return *(const MTPDmessageMediaVideo*)data; + } + + MTPDmessageMediaGeo &_messageMediaGeo() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaGeo) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaGeo); + split(); + return *(MTPDmessageMediaGeo*)data; + } + const MTPDmessageMediaGeo &c_messageMediaGeo() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaGeo) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaGeo); + return *(const MTPDmessageMediaGeo*)data; + } + + MTPDmessageMediaContact &_messageMediaContact() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaContact) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaContact); + split(); + return *(MTPDmessageMediaContact*)data; + } + const MTPDmessageMediaContact &c_messageMediaContact() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaContact) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaContact); + return *(const MTPDmessageMediaContact*)data; + } + + MTPDmessageMediaUnsupported &_messageMediaUnsupported() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaUnsupported) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaUnsupported); + split(); + return *(MTPDmessageMediaUnsupported*)data; + } + const MTPDmessageMediaUnsupported &c_messageMediaUnsupported() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaUnsupported) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaUnsupported); + return *(const MTPDmessageMediaUnsupported*)data; + } + + MTPDmessageMediaDocument &_messageMediaDocument() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaDocument) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaDocument); + split(); + return *(MTPDmessageMediaDocument*)data; + } + const MTPDmessageMediaDocument &c_messageMediaDocument() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaDocument) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaDocument); + return *(const MTPDmessageMediaDocument*)data; + } + + MTPDmessageMediaAudio &_messageMediaAudio() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaAudio) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaAudio); + split(); + return *(MTPDmessageMediaAudio*)data; + } + const MTPDmessageMediaAudio &c_messageMediaAudio() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaAudio) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaAudio); + return *(const MTPDmessageMediaAudio*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessageMedia(mtpTypeId type); + explicit MTPmessageMedia(MTPDmessageMediaPhoto *_data); + explicit MTPmessageMedia(MTPDmessageMediaVideo *_data); + explicit MTPmessageMedia(MTPDmessageMediaGeo *_data); + explicit MTPmessageMedia(MTPDmessageMediaContact *_data); + explicit MTPmessageMedia(MTPDmessageMediaUnsupported *_data); + explicit MTPmessageMedia(MTPDmessageMediaDocument *_data); + explicit MTPmessageMedia(MTPDmessageMediaAudio *_data); + + friend MTPmessageMedia MTP_messageMediaEmpty(); + friend MTPmessageMedia MTP_messageMediaPhoto(const MTPPhoto &_photo); + friend MTPmessageMedia MTP_messageMediaVideo(const MTPVideo &_video); + friend MTPmessageMedia MTP_messageMediaGeo(const MTPGeoPoint &_geo); + friend MTPmessageMedia MTP_messageMediaContact(const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name, MTPint _user_id); + friend MTPmessageMedia MTP_messageMediaUnsupported(const MTPbytes &_bytes); + friend MTPmessageMedia MTP_messageMediaDocument(const MTPDocument &_document); + friend MTPmessageMedia MTP_messageMediaAudio(const MTPAudio &_audio); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPMessageMedia; + +class MTPmessageAction : private mtpDataOwner { +public: + MTPmessageAction() : mtpDataOwner(0), _type(0) { + } + MTPmessageAction(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessageActionChatCreate &_messageActionChatCreate() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionChatCreate) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChatCreate); + split(); + return *(MTPDmessageActionChatCreate*)data; + } + const MTPDmessageActionChatCreate &c_messageActionChatCreate() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionChatCreate) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChatCreate); + return *(const MTPDmessageActionChatCreate*)data; + } + + MTPDmessageActionChatEditTitle &_messageActionChatEditTitle() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionChatEditTitle) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChatEditTitle); + split(); + return *(MTPDmessageActionChatEditTitle*)data; + } + const MTPDmessageActionChatEditTitle &c_messageActionChatEditTitle() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionChatEditTitle) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChatEditTitle); + return *(const MTPDmessageActionChatEditTitle*)data; + } + + MTPDmessageActionChatEditPhoto &_messageActionChatEditPhoto() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionChatEditPhoto) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChatEditPhoto); + split(); + return *(MTPDmessageActionChatEditPhoto*)data; + } + const MTPDmessageActionChatEditPhoto &c_messageActionChatEditPhoto() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionChatEditPhoto) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChatEditPhoto); + return *(const MTPDmessageActionChatEditPhoto*)data; + } + + MTPDmessageActionChatAddUser &_messageActionChatAddUser() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionChatAddUser) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChatAddUser); + split(); + return *(MTPDmessageActionChatAddUser*)data; + } + const MTPDmessageActionChatAddUser &c_messageActionChatAddUser() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionChatAddUser) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChatAddUser); + return *(const MTPDmessageActionChatAddUser*)data; + } + + MTPDmessageActionChatDeleteUser &_messageActionChatDeleteUser() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionChatDeleteUser) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChatDeleteUser); + split(); + return *(MTPDmessageActionChatDeleteUser*)data; + } + const MTPDmessageActionChatDeleteUser &c_messageActionChatDeleteUser() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionChatDeleteUser) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChatDeleteUser); + return *(const MTPDmessageActionChatDeleteUser*)data; + } + + MTPDmessageActionGeoChatCreate &_messageActionGeoChatCreate() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionGeoChatCreate) throw mtpErrorWrongTypeId(_type, mtpc_messageActionGeoChatCreate); + split(); + return *(MTPDmessageActionGeoChatCreate*)data; + } + const MTPDmessageActionGeoChatCreate &c_messageActionGeoChatCreate() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionGeoChatCreate) throw mtpErrorWrongTypeId(_type, mtpc_messageActionGeoChatCreate); + return *(const MTPDmessageActionGeoChatCreate*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessageAction(mtpTypeId type); + explicit MTPmessageAction(MTPDmessageActionChatCreate *_data); + explicit MTPmessageAction(MTPDmessageActionChatEditTitle *_data); + explicit MTPmessageAction(MTPDmessageActionChatEditPhoto *_data); + explicit MTPmessageAction(MTPDmessageActionChatAddUser *_data); + explicit MTPmessageAction(MTPDmessageActionChatDeleteUser *_data); + explicit MTPmessageAction(MTPDmessageActionGeoChatCreate *_data); + + friend MTPmessageAction MTP_messageActionEmpty(); + friend MTPmessageAction MTP_messageActionChatCreate(const MTPstring &_title, const MTPVector &_users); + friend MTPmessageAction MTP_messageActionChatEditTitle(const MTPstring &_title); + friend MTPmessageAction MTP_messageActionChatEditPhoto(const MTPPhoto &_photo); + friend MTPmessageAction MTP_messageActionChatDeletePhoto(); + friend MTPmessageAction MTP_messageActionChatAddUser(MTPint _user_id); + friend MTPmessageAction MTP_messageActionChatDeleteUser(MTPint _user_id); + friend MTPmessageAction MTP_messageActionGeoChatCreate(const MTPstring &_title, const MTPstring &_address); + friend MTPmessageAction MTP_messageActionGeoChatCheckin(); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPMessageAction; + +class MTPdialog : private mtpDataOwner { +public: + MTPdialog(); + MTPdialog(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_dialog) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDdialog &_dialog() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDdialog*)data; + } + const MTPDdialog &c_dialog() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDdialog*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_dialog); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPdialog(MTPDdialog *_data); + + friend MTPdialog MTP_dialog(const MTPPeer &_peer, MTPint _top_message, MTPint _unread_count, const MTPPeerNotifySettings &_notify_settings); +}; +typedef MTPBoxed MTPDialog; + +class MTPphoto : private mtpDataOwner { +public: + MTPphoto() : mtpDataOwner(0), _type(0) { + } + MTPphoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDphotoEmpty &_photoEmpty() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photoEmpty) throw mtpErrorWrongTypeId(_type, mtpc_photoEmpty); + split(); + return *(MTPDphotoEmpty*)data; + } + const MTPDphotoEmpty &c_photoEmpty() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photoEmpty) throw mtpErrorWrongTypeId(_type, mtpc_photoEmpty); + return *(const MTPDphotoEmpty*)data; + } + + MTPDphoto &_photo() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photo) throw mtpErrorWrongTypeId(_type, mtpc_photo); + split(); + return *(MTPDphoto*)data; + } + const MTPDphoto &c_photo() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photo) throw mtpErrorWrongTypeId(_type, mtpc_photo); + return *(const MTPDphoto*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPphoto(mtpTypeId type); + explicit MTPphoto(MTPDphotoEmpty *_data); + explicit MTPphoto(MTPDphoto *_data); + + friend MTPphoto MTP_photoEmpty(const MTPlong &_id); + friend MTPphoto MTP_photo(const MTPlong &_id, const MTPlong &_access_hash, MTPint _user_id, MTPint _date, const MTPstring &_caption, const MTPGeoPoint &_geo, const MTPVector &_sizes); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPPhoto; + +class MTPphotoSize : private mtpDataOwner { +public: + MTPphotoSize() : mtpDataOwner(0), _type(0) { + } + MTPphotoSize(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDphotoSizeEmpty &_photoSizeEmpty() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photoSizeEmpty) throw mtpErrorWrongTypeId(_type, mtpc_photoSizeEmpty); + split(); + return *(MTPDphotoSizeEmpty*)data; + } + const MTPDphotoSizeEmpty &c_photoSizeEmpty() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photoSizeEmpty) throw mtpErrorWrongTypeId(_type, mtpc_photoSizeEmpty); + return *(const MTPDphotoSizeEmpty*)data; + } + + MTPDphotoSize &_photoSize() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photoSize) throw mtpErrorWrongTypeId(_type, mtpc_photoSize); + split(); + return *(MTPDphotoSize*)data; + } + const MTPDphotoSize &c_photoSize() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photoSize) throw mtpErrorWrongTypeId(_type, mtpc_photoSize); + return *(const MTPDphotoSize*)data; + } + + MTPDphotoCachedSize &_photoCachedSize() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photoCachedSize) throw mtpErrorWrongTypeId(_type, mtpc_photoCachedSize); + split(); + return *(MTPDphotoCachedSize*)data; + } + const MTPDphotoCachedSize &c_photoCachedSize() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photoCachedSize) throw mtpErrorWrongTypeId(_type, mtpc_photoCachedSize); + return *(const MTPDphotoCachedSize*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPphotoSize(mtpTypeId type); + explicit MTPphotoSize(MTPDphotoSizeEmpty *_data); + explicit MTPphotoSize(MTPDphotoSize *_data); + explicit MTPphotoSize(MTPDphotoCachedSize *_data); + + friend MTPphotoSize MTP_photoSizeEmpty(const MTPstring &_type); + friend MTPphotoSize MTP_photoSize(const MTPstring &_type, const MTPFileLocation &_location, MTPint _w, MTPint _h, MTPint _size); + friend MTPphotoSize MTP_photoCachedSize(const MTPstring &_type, const MTPFileLocation &_location, MTPint _w, MTPint _h, const MTPbytes &_bytes); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPPhotoSize; + +class MTPvideo : private mtpDataOwner { +public: + MTPvideo() : mtpDataOwner(0), _type(0) { + } + MTPvideo(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDvideoEmpty &_videoEmpty() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_videoEmpty) throw mtpErrorWrongTypeId(_type, mtpc_videoEmpty); + split(); + return *(MTPDvideoEmpty*)data; + } + const MTPDvideoEmpty &c_videoEmpty() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_videoEmpty) throw mtpErrorWrongTypeId(_type, mtpc_videoEmpty); + return *(const MTPDvideoEmpty*)data; + } + + MTPDvideo &_video() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_video) throw mtpErrorWrongTypeId(_type, mtpc_video); + split(); + return *(MTPDvideo*)data; + } + const MTPDvideo &c_video() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_video) throw mtpErrorWrongTypeId(_type, mtpc_video); + return *(const MTPDvideo*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPvideo(mtpTypeId type); + explicit MTPvideo(MTPDvideoEmpty *_data); + explicit MTPvideo(MTPDvideo *_data); + + friend MTPvideo MTP_videoEmpty(const MTPlong &_id); + friend MTPvideo MTP_video(const MTPlong &_id, const MTPlong &_access_hash, MTPint _user_id, MTPint _date, const MTPstring &_caption, MTPint _duration, const MTPstring &_mime_type, MTPint _size, const MTPPhotoSize &_thumb, MTPint _dc_id, MTPint _w, MTPint _h); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPVideo; + +class MTPgeoPoint : private mtpDataOwner { +public: + MTPgeoPoint() : mtpDataOwner(0), _type(0) { + } + MTPgeoPoint(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDgeoPoint &_geoPoint() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geoPoint) throw mtpErrorWrongTypeId(_type, mtpc_geoPoint); + split(); + return *(MTPDgeoPoint*)data; + } + const MTPDgeoPoint &c_geoPoint() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geoPoint) throw mtpErrorWrongTypeId(_type, mtpc_geoPoint); + return *(const MTPDgeoPoint*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPgeoPoint(mtpTypeId type); + explicit MTPgeoPoint(MTPDgeoPoint *_data); + + friend MTPgeoPoint MTP_geoPointEmpty(); + friend MTPgeoPoint MTP_geoPoint(const MTPdouble &_long, const MTPdouble &_lat); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPGeoPoint; + +class MTPauth_checkedPhone : private mtpDataOwner { +public: + MTPauth_checkedPhone(); + MTPauth_checkedPhone(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_checkedPhone) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDauth_checkedPhone &_auth_checkedPhone() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDauth_checkedPhone*)data; + } + const MTPDauth_checkedPhone &c_auth_checkedPhone() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDauth_checkedPhone*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_checkedPhone); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPauth_checkedPhone(MTPDauth_checkedPhone *_data); + + friend MTPauth_checkedPhone MTP_auth_checkedPhone(MTPBool _phone_registered, MTPBool _phone_invited); +}; +typedef MTPBoxed MTPauth_CheckedPhone; + +class MTPauth_sentCode : private mtpDataOwner { +public: + MTPauth_sentCode(); + MTPauth_sentCode(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_sentCode) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDauth_sentCode &_auth_sentCode() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDauth_sentCode*)data; + } + const MTPDauth_sentCode &c_auth_sentCode() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDauth_sentCode*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_sentCode); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPauth_sentCode(MTPDauth_sentCode *_data); + + friend MTPauth_sentCode MTP_auth_sentCode(MTPBool _phone_registered, const MTPstring &_phone_code_hash, MTPint _send_call_timeout, MTPBool _is_password); +}; +typedef MTPBoxed MTPauth_SentCode; + +class MTPauth_authorization : private mtpDataOwner { +public: + MTPauth_authorization(); + MTPauth_authorization(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_authorization) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDauth_authorization &_auth_authorization() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDauth_authorization*)data; + } + const MTPDauth_authorization &c_auth_authorization() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDauth_authorization*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_authorization); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPauth_authorization(MTPDauth_authorization *_data); + + friend MTPauth_authorization MTP_auth_authorization(MTPint _expires, const MTPUser &_user); +}; +typedef MTPBoxed MTPauth_Authorization; + +class MTPauth_exportedAuthorization : private mtpDataOwner { +public: + MTPauth_exportedAuthorization(); + MTPauth_exportedAuthorization(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_exportedAuthorization) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDauth_exportedAuthorization &_auth_exportedAuthorization() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDauth_exportedAuthorization*)data; + } + const MTPDauth_exportedAuthorization &c_auth_exportedAuthorization() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDauth_exportedAuthorization*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_exportedAuthorization); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPauth_exportedAuthorization(MTPDauth_exportedAuthorization *_data); + + friend MTPauth_exportedAuthorization MTP_auth_exportedAuthorization(MTPint _id, const MTPbytes &_bytes); +}; +typedef MTPBoxed MTPauth_ExportedAuthorization; + +class MTPinputNotifyPeer : private mtpDataOwner { +public: + MTPinputNotifyPeer() : mtpDataOwner(0), _type(0) { + } + MTPinputNotifyPeer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputNotifyPeer &_inputNotifyPeer() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputNotifyPeer) throw mtpErrorWrongTypeId(_type, mtpc_inputNotifyPeer); + split(); + return *(MTPDinputNotifyPeer*)data; + } + const MTPDinputNotifyPeer &c_inputNotifyPeer() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputNotifyPeer) throw mtpErrorWrongTypeId(_type, mtpc_inputNotifyPeer); + return *(const MTPDinputNotifyPeer*)data; + } + + MTPDinputNotifyGeoChatPeer &_inputNotifyGeoChatPeer() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputNotifyGeoChatPeer) throw mtpErrorWrongTypeId(_type, mtpc_inputNotifyGeoChatPeer); + split(); + return *(MTPDinputNotifyGeoChatPeer*)data; + } + const MTPDinputNotifyGeoChatPeer &c_inputNotifyGeoChatPeer() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputNotifyGeoChatPeer) throw mtpErrorWrongTypeId(_type, mtpc_inputNotifyGeoChatPeer); + return *(const MTPDinputNotifyGeoChatPeer*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputNotifyPeer(mtpTypeId type); + explicit MTPinputNotifyPeer(MTPDinputNotifyPeer *_data); + explicit MTPinputNotifyPeer(MTPDinputNotifyGeoChatPeer *_data); + + friend MTPinputNotifyPeer MTP_inputNotifyPeer(const MTPInputPeer &_peer); + friend MTPinputNotifyPeer MTP_inputNotifyUsers(); + friend MTPinputNotifyPeer MTP_inputNotifyChats(); + friend MTPinputNotifyPeer MTP_inputNotifyAll(); + friend MTPinputNotifyPeer MTP_inputNotifyGeoChatPeer(const MTPInputGeoChat &_peer); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputNotifyPeer; + +class MTPinputPeerNotifyEvents { +public: + MTPinputPeerNotifyEvents() : _type(0) { + } + MTPinputPeerNotifyEvents(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : _type(0) { + read(from, end, cons); + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputPeerNotifyEvents(mtpTypeId type); + + friend MTPinputPeerNotifyEvents MTP_inputPeerNotifyEventsEmpty(); + friend MTPinputPeerNotifyEvents MTP_inputPeerNotifyEventsAll(); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputPeerNotifyEvents; + +class MTPinputPeerNotifySettings : private mtpDataOwner { +public: + MTPinputPeerNotifySettings(); + MTPinputPeerNotifySettings(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_inputPeerNotifySettings) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDinputPeerNotifySettings &_inputPeerNotifySettings() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDinputPeerNotifySettings*)data; + } + const MTPDinputPeerNotifySettings &c_inputPeerNotifySettings() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDinputPeerNotifySettings*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_inputPeerNotifySettings); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputPeerNotifySettings(MTPDinputPeerNotifySettings *_data); + + friend MTPinputPeerNotifySettings MTP_inputPeerNotifySettings(MTPint _mute_until, const MTPstring &_sound, MTPBool _show_previews, MTPint _events_mask); +}; +typedef MTPBoxed MTPInputPeerNotifySettings; + +class MTPpeerNotifyEvents { +public: + MTPpeerNotifyEvents() : _type(0) { + } + MTPpeerNotifyEvents(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : _type(0) { + read(from, end, cons); + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPpeerNotifyEvents(mtpTypeId type); + + friend MTPpeerNotifyEvents MTP_peerNotifyEventsEmpty(); + friend MTPpeerNotifyEvents MTP_peerNotifyEventsAll(); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPPeerNotifyEvents; + +class MTPpeerNotifySettings : private mtpDataOwner { +public: + MTPpeerNotifySettings() : mtpDataOwner(0), _type(0) { + } + MTPpeerNotifySettings(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDpeerNotifySettings &_peerNotifySettings() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_peerNotifySettings) throw mtpErrorWrongTypeId(_type, mtpc_peerNotifySettings); + split(); + return *(MTPDpeerNotifySettings*)data; + } + const MTPDpeerNotifySettings &c_peerNotifySettings() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_peerNotifySettings) throw mtpErrorWrongTypeId(_type, mtpc_peerNotifySettings); + return *(const MTPDpeerNotifySettings*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPpeerNotifySettings(mtpTypeId type); + explicit MTPpeerNotifySettings(MTPDpeerNotifySettings *_data); + + friend MTPpeerNotifySettings MTP_peerNotifySettingsEmpty(); + friend MTPpeerNotifySettings MTP_peerNotifySettings(MTPint _mute_until, const MTPstring &_sound, MTPBool _show_previews, MTPint _events_mask); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPPeerNotifySettings; + +class MTPwallPaper : private mtpDataOwner { +public: + MTPwallPaper() : mtpDataOwner(0), _type(0) { + } + MTPwallPaper(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDwallPaper &_wallPaper() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_wallPaper) throw mtpErrorWrongTypeId(_type, mtpc_wallPaper); + split(); + return *(MTPDwallPaper*)data; + } + const MTPDwallPaper &c_wallPaper() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_wallPaper) throw mtpErrorWrongTypeId(_type, mtpc_wallPaper); + return *(const MTPDwallPaper*)data; + } + + MTPDwallPaperSolid &_wallPaperSolid() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_wallPaperSolid) throw mtpErrorWrongTypeId(_type, mtpc_wallPaperSolid); + split(); + return *(MTPDwallPaperSolid*)data; + } + const MTPDwallPaperSolid &c_wallPaperSolid() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_wallPaperSolid) throw mtpErrorWrongTypeId(_type, mtpc_wallPaperSolid); + return *(const MTPDwallPaperSolid*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPwallPaper(mtpTypeId type); + explicit MTPwallPaper(MTPDwallPaper *_data); + explicit MTPwallPaper(MTPDwallPaperSolid *_data); + + friend MTPwallPaper MTP_wallPaper(MTPint _id, const MTPstring &_title, const MTPVector &_sizes, MTPint _color); + friend MTPwallPaper MTP_wallPaperSolid(MTPint _id, const MTPstring &_title, MTPint _bg_color, MTPint _color); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPWallPaper; + +class MTPuserFull : private mtpDataOwner { +public: + MTPuserFull(); + MTPuserFull(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_userFull) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDuserFull &_userFull() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDuserFull*)data; + } + const MTPDuserFull &c_userFull() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDuserFull*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_userFull); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPuserFull(MTPDuserFull *_data); + + friend MTPuserFull MTP_userFull(const MTPUser &_user, const MTPcontacts_Link &_link, const MTPPhoto &_profile_photo, const MTPPeerNotifySettings &_notify_settings, MTPBool _blocked, const MTPstring &_real_first_name, const MTPstring &_real_last_name); +}; +typedef MTPBoxed MTPUserFull; + +class MTPcontact : private mtpDataOwner { +public: + MTPcontact(); + MTPcontact(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contact) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDcontact &_contact() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDcontact*)data; + } + const MTPDcontact &c_contact() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDcontact*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contact); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontact(MTPDcontact *_data); + + friend MTPcontact MTP_contact(MTPint _user_id, MTPBool _mutual); +}; +typedef MTPBoxed MTPContact; + +class MTPimportedContact : private mtpDataOwner { +public: + MTPimportedContact(); + MTPimportedContact(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_importedContact) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDimportedContact &_importedContact() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDimportedContact*)data; + } + const MTPDimportedContact &c_importedContact() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDimportedContact*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_importedContact); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPimportedContact(MTPDimportedContact *_data); + + friend MTPimportedContact MTP_importedContact(MTPint _user_id, const MTPlong &_client_id); +}; +typedef MTPBoxed MTPImportedContact; + +class MTPcontactBlocked : private mtpDataOwner { +public: + MTPcontactBlocked(); + MTPcontactBlocked(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contactBlocked) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDcontactBlocked &_contactBlocked() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDcontactBlocked*)data; + } + const MTPDcontactBlocked &c_contactBlocked() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDcontactBlocked*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contactBlocked); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontactBlocked(MTPDcontactBlocked *_data); + + friend MTPcontactBlocked MTP_contactBlocked(MTPint _user_id, MTPint _date); +}; +typedef MTPBoxed MTPContactBlocked; + +class MTPcontactFound : private mtpDataOwner { +public: + MTPcontactFound(); + MTPcontactFound(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contactFound) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDcontactFound &_contactFound() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDcontactFound*)data; + } + const MTPDcontactFound &c_contactFound() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDcontactFound*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contactFound); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontactFound(MTPDcontactFound *_data); + + friend MTPcontactFound MTP_contactFound(MTPint _user_id); +}; +typedef MTPBoxed MTPContactFound; + +class MTPcontactSuggested : private mtpDataOwner { +public: + MTPcontactSuggested(); + MTPcontactSuggested(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contactSuggested) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDcontactSuggested &_contactSuggested() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDcontactSuggested*)data; + } + const MTPDcontactSuggested &c_contactSuggested() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDcontactSuggested*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contactSuggested); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontactSuggested(MTPDcontactSuggested *_data); + + friend MTPcontactSuggested MTP_contactSuggested(MTPint _user_id, MTPint _mutual_contacts); +}; +typedef MTPBoxed MTPContactSuggested; + +class MTPcontactStatus : private mtpDataOwner { +public: + MTPcontactStatus(); + MTPcontactStatus(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contactStatus) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDcontactStatus &_contactStatus() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDcontactStatus*)data; + } + const MTPDcontactStatus &c_contactStatus() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDcontactStatus*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contactStatus); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontactStatus(MTPDcontactStatus *_data); + + friend MTPcontactStatus MTP_contactStatus(MTPint _user_id, MTPint _expires); +}; +typedef MTPBoxed MTPContactStatus; + +class MTPchatLocated : private mtpDataOwner { +public: + MTPchatLocated(); + MTPchatLocated(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_chatLocated) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDchatLocated &_chatLocated() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDchatLocated*)data; + } + const MTPDchatLocated &c_chatLocated() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDchatLocated*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_chatLocated); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPchatLocated(MTPDchatLocated *_data); + + friend MTPchatLocated MTP_chatLocated(MTPint _chat_id, MTPint _distance); +}; +typedef MTPBoxed MTPChatLocated; + +class MTPcontacts_foreignLink : private mtpDataOwner { +public: + MTPcontacts_foreignLink() : mtpDataOwner(0), _type(0) { + } + MTPcontacts_foreignLink(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDcontacts_foreignLinkRequested &_contacts_foreignLinkRequested() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_contacts_foreignLinkRequested) throw mtpErrorWrongTypeId(_type, mtpc_contacts_foreignLinkRequested); + split(); + return *(MTPDcontacts_foreignLinkRequested*)data; + } + const MTPDcontacts_foreignLinkRequested &c_contacts_foreignLinkRequested() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_contacts_foreignLinkRequested) throw mtpErrorWrongTypeId(_type, mtpc_contacts_foreignLinkRequested); + return *(const MTPDcontacts_foreignLinkRequested*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontacts_foreignLink(mtpTypeId type); + explicit MTPcontacts_foreignLink(MTPDcontacts_foreignLinkRequested *_data); + + friend MTPcontacts_foreignLink MTP_contacts_foreignLinkUnknown(); + friend MTPcontacts_foreignLink MTP_contacts_foreignLinkRequested(MTPBool _has_phone); + friend MTPcontacts_foreignLink MTP_contacts_foreignLinkMutual(); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPcontacts_ForeignLink; + +class MTPcontacts_myLink : private mtpDataOwner { +public: + MTPcontacts_myLink() : mtpDataOwner(0), _type(0) { + } + MTPcontacts_myLink(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDcontacts_myLinkRequested &_contacts_myLinkRequested() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_contacts_myLinkRequested) throw mtpErrorWrongTypeId(_type, mtpc_contacts_myLinkRequested); + split(); + return *(MTPDcontacts_myLinkRequested*)data; + } + const MTPDcontacts_myLinkRequested &c_contacts_myLinkRequested() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_contacts_myLinkRequested) throw mtpErrorWrongTypeId(_type, mtpc_contacts_myLinkRequested); + return *(const MTPDcontacts_myLinkRequested*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontacts_myLink(mtpTypeId type); + explicit MTPcontacts_myLink(MTPDcontacts_myLinkRequested *_data); + + friend MTPcontacts_myLink MTP_contacts_myLinkEmpty(); + friend MTPcontacts_myLink MTP_contacts_myLinkRequested(MTPBool _contact); + friend MTPcontacts_myLink MTP_contacts_myLinkContact(); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPcontacts_MyLink; + +class MTPcontacts_link : private mtpDataOwner { +public: + MTPcontacts_link(); + MTPcontacts_link(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_link) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDcontacts_link &_contacts_link() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDcontacts_link*)data; + } + const MTPDcontacts_link &c_contacts_link() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDcontacts_link*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_link); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontacts_link(MTPDcontacts_link *_data); + + friend MTPcontacts_link MTP_contacts_link(const MTPcontacts_MyLink &_my_link, const MTPcontacts_ForeignLink &_foreign_link, const MTPUser &_user); +}; +typedef MTPBoxed MTPcontacts_Link; + +class MTPcontacts_contacts : private mtpDataOwner { +public: + MTPcontacts_contacts() : mtpDataOwner(0), _type(0) { + } + MTPcontacts_contacts(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDcontacts_contacts &_contacts_contacts() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_contacts_contacts) throw mtpErrorWrongTypeId(_type, mtpc_contacts_contacts); + split(); + return *(MTPDcontacts_contacts*)data; + } + const MTPDcontacts_contacts &c_contacts_contacts() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_contacts_contacts) throw mtpErrorWrongTypeId(_type, mtpc_contacts_contacts); + return *(const MTPDcontacts_contacts*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontacts_contacts(mtpTypeId type); + explicit MTPcontacts_contacts(MTPDcontacts_contacts *_data); + + friend MTPcontacts_contacts MTP_contacts_contacts(const MTPVector &_contacts, const MTPVector &_users); + friend MTPcontacts_contacts MTP_contacts_contactsNotModified(); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPcontacts_Contacts; + +class MTPcontacts_importedContacts : private mtpDataOwner { +public: + MTPcontacts_importedContacts(); + MTPcontacts_importedContacts(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_importedContacts) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDcontacts_importedContacts &_contacts_importedContacts() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDcontacts_importedContacts*)data; + } + const MTPDcontacts_importedContacts &c_contacts_importedContacts() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDcontacts_importedContacts*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_importedContacts); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontacts_importedContacts(MTPDcontacts_importedContacts *_data); + + friend MTPcontacts_importedContacts MTP_contacts_importedContacts(const MTPVector &_imported, const MTPVector &_retry_contacts, const MTPVector &_users); +}; +typedef MTPBoxed MTPcontacts_ImportedContacts; + +class MTPcontacts_blocked : private mtpDataOwner { +public: + MTPcontacts_blocked() : mtpDataOwner(0), _type(0) { + } + MTPcontacts_blocked(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDcontacts_blocked &_contacts_blocked() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_contacts_blocked) throw mtpErrorWrongTypeId(_type, mtpc_contacts_blocked); + split(); + return *(MTPDcontacts_blocked*)data; + } + const MTPDcontacts_blocked &c_contacts_blocked() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_contacts_blocked) throw mtpErrorWrongTypeId(_type, mtpc_contacts_blocked); + return *(const MTPDcontacts_blocked*)data; + } + + MTPDcontacts_blockedSlice &_contacts_blockedSlice() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_contacts_blockedSlice) throw mtpErrorWrongTypeId(_type, mtpc_contacts_blockedSlice); + split(); + return *(MTPDcontacts_blockedSlice*)data; + } + const MTPDcontacts_blockedSlice &c_contacts_blockedSlice() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_contacts_blockedSlice) throw mtpErrorWrongTypeId(_type, mtpc_contacts_blockedSlice); + return *(const MTPDcontacts_blockedSlice*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontacts_blocked(mtpTypeId type); + explicit MTPcontacts_blocked(MTPDcontacts_blocked *_data); + explicit MTPcontacts_blocked(MTPDcontacts_blockedSlice *_data); + + friend MTPcontacts_blocked MTP_contacts_blocked(const MTPVector &_blocked, const MTPVector &_users); + friend MTPcontacts_blocked MTP_contacts_blockedSlice(MTPint _count, const MTPVector &_blocked, const MTPVector &_users); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPcontacts_Blocked; + +class MTPcontacts_found : private mtpDataOwner { +public: + MTPcontacts_found(); + MTPcontacts_found(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_found) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDcontacts_found &_contacts_found() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDcontacts_found*)data; + } + const MTPDcontacts_found &c_contacts_found() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDcontacts_found*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_found); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontacts_found(MTPDcontacts_found *_data); + + friend MTPcontacts_found MTP_contacts_found(const MTPVector &_results, const MTPVector &_users); +}; +typedef MTPBoxed MTPcontacts_Found; + +class MTPcontacts_suggested : private mtpDataOwner { +public: + MTPcontacts_suggested(); + MTPcontacts_suggested(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_suggested) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDcontacts_suggested &_contacts_suggested() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDcontacts_suggested*)data; + } + const MTPDcontacts_suggested &c_contacts_suggested() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDcontacts_suggested*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_suggested); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPcontacts_suggested(MTPDcontacts_suggested *_data); + + friend MTPcontacts_suggested MTP_contacts_suggested(const MTPVector &_results, const MTPVector &_users); +}; +typedef MTPBoxed MTPcontacts_Suggested; + +class MTPmessages_dialogs : private mtpDataOwner { +public: + MTPmessages_dialogs() : mtpDataOwner(0), _type(0) { + } + MTPmessages_dialogs(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessages_dialogs &_messages_dialogs() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_dialogs) throw mtpErrorWrongTypeId(_type, mtpc_messages_dialogs); + split(); + return *(MTPDmessages_dialogs*)data; + } + const MTPDmessages_dialogs &c_messages_dialogs() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_dialogs) throw mtpErrorWrongTypeId(_type, mtpc_messages_dialogs); + return *(const MTPDmessages_dialogs*)data; + } + + MTPDmessages_dialogsSlice &_messages_dialogsSlice() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_dialogsSlice) throw mtpErrorWrongTypeId(_type, mtpc_messages_dialogsSlice); + split(); + return *(MTPDmessages_dialogsSlice*)data; + } + const MTPDmessages_dialogsSlice &c_messages_dialogsSlice() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_dialogsSlice) throw mtpErrorWrongTypeId(_type, mtpc_messages_dialogsSlice); + return *(const MTPDmessages_dialogsSlice*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_dialogs(mtpTypeId type); + explicit MTPmessages_dialogs(MTPDmessages_dialogs *_data); + explicit MTPmessages_dialogs(MTPDmessages_dialogsSlice *_data); + + friend MTPmessages_dialogs MTP_messages_dialogs(const MTPVector &_dialogs, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users); + friend MTPmessages_dialogs MTP_messages_dialogsSlice(MTPint _count, const MTPVector &_dialogs, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPmessages_Dialogs; + +class MTPmessages_messages : private mtpDataOwner { +public: + MTPmessages_messages() : mtpDataOwner(0), _type(0) { + } + MTPmessages_messages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessages_messages &_messages_messages() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_messages) throw mtpErrorWrongTypeId(_type, mtpc_messages_messages); + split(); + return *(MTPDmessages_messages*)data; + } + const MTPDmessages_messages &c_messages_messages() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_messages) throw mtpErrorWrongTypeId(_type, mtpc_messages_messages); + return *(const MTPDmessages_messages*)data; + } + + MTPDmessages_messagesSlice &_messages_messagesSlice() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_messagesSlice) throw mtpErrorWrongTypeId(_type, mtpc_messages_messagesSlice); + split(); + return *(MTPDmessages_messagesSlice*)data; + } + const MTPDmessages_messagesSlice &c_messages_messagesSlice() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_messagesSlice) throw mtpErrorWrongTypeId(_type, mtpc_messages_messagesSlice); + return *(const MTPDmessages_messagesSlice*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_messages(mtpTypeId type); + explicit MTPmessages_messages(MTPDmessages_messages *_data); + explicit MTPmessages_messages(MTPDmessages_messagesSlice *_data); + + friend MTPmessages_messages MTP_messages_messages(const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users); + friend MTPmessages_messages MTP_messages_messagesSlice(MTPint _count, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPmessages_Messages; + +class MTPmessages_message : private mtpDataOwner { +public: + MTPmessages_message() : mtpDataOwner(0), _type(0) { + } + MTPmessages_message(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessages_message &_messages_message() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_message) throw mtpErrorWrongTypeId(_type, mtpc_messages_message); + split(); + return *(MTPDmessages_message*)data; + } + const MTPDmessages_message &c_messages_message() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_message) throw mtpErrorWrongTypeId(_type, mtpc_messages_message); + return *(const MTPDmessages_message*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_message(mtpTypeId type); + explicit MTPmessages_message(MTPDmessages_message *_data); + + friend MTPmessages_message MTP_messages_messageEmpty(); + friend MTPmessages_message MTP_messages_message(const MTPMessage &_message, const MTPVector &_chats, const MTPVector &_users); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPmessages_Message; + +class MTPmessages_statedMessages : private mtpDataOwner { +public: + MTPmessages_statedMessages() : mtpDataOwner(0), _type(0) { + } + MTPmessages_statedMessages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessages_statedMessages &_messages_statedMessages() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_statedMessages) throw mtpErrorWrongTypeId(_type, mtpc_messages_statedMessages); + split(); + return *(MTPDmessages_statedMessages*)data; + } + const MTPDmessages_statedMessages &c_messages_statedMessages() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_statedMessages) throw mtpErrorWrongTypeId(_type, mtpc_messages_statedMessages); + return *(const MTPDmessages_statedMessages*)data; + } + + MTPDmessages_statedMessagesLinks &_messages_statedMessagesLinks() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_statedMessagesLinks) throw mtpErrorWrongTypeId(_type, mtpc_messages_statedMessagesLinks); + split(); + return *(MTPDmessages_statedMessagesLinks*)data; + } + const MTPDmessages_statedMessagesLinks &c_messages_statedMessagesLinks() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_statedMessagesLinks) throw mtpErrorWrongTypeId(_type, mtpc_messages_statedMessagesLinks); + return *(const MTPDmessages_statedMessagesLinks*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_statedMessages(mtpTypeId type); + explicit MTPmessages_statedMessages(MTPDmessages_statedMessages *_data); + explicit MTPmessages_statedMessages(MTPDmessages_statedMessagesLinks *_data); + + friend MTPmessages_statedMessages MTP_messages_statedMessages(const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users, MTPint _pts, MTPint _seq); + friend MTPmessages_statedMessages MTP_messages_statedMessagesLinks(const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users, const MTPVector &_links, MTPint _pts, MTPint _seq); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPmessages_StatedMessages; + +class MTPmessages_statedMessage : private mtpDataOwner { +public: + MTPmessages_statedMessage() : mtpDataOwner(0), _type(0) { + } + MTPmessages_statedMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessages_statedMessage &_messages_statedMessage() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_statedMessage) throw mtpErrorWrongTypeId(_type, mtpc_messages_statedMessage); + split(); + return *(MTPDmessages_statedMessage*)data; + } + const MTPDmessages_statedMessage &c_messages_statedMessage() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_statedMessage) throw mtpErrorWrongTypeId(_type, mtpc_messages_statedMessage); + return *(const MTPDmessages_statedMessage*)data; + } + + MTPDmessages_statedMessageLink &_messages_statedMessageLink() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_statedMessageLink) throw mtpErrorWrongTypeId(_type, mtpc_messages_statedMessageLink); + split(); + return *(MTPDmessages_statedMessageLink*)data; + } + const MTPDmessages_statedMessageLink &c_messages_statedMessageLink() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_statedMessageLink) throw mtpErrorWrongTypeId(_type, mtpc_messages_statedMessageLink); + return *(const MTPDmessages_statedMessageLink*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_statedMessage(mtpTypeId type); + explicit MTPmessages_statedMessage(MTPDmessages_statedMessage *_data); + explicit MTPmessages_statedMessage(MTPDmessages_statedMessageLink *_data); + + friend MTPmessages_statedMessage MTP_messages_statedMessage(const MTPMessage &_message, const MTPVector &_chats, const MTPVector &_users, MTPint _pts, MTPint _seq); + friend MTPmessages_statedMessage MTP_messages_statedMessageLink(const MTPMessage &_message, const MTPVector &_chats, const MTPVector &_users, const MTPVector &_links, MTPint _pts, MTPint _seq); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPmessages_StatedMessage; + +class MTPmessages_sentMessage : private mtpDataOwner { +public: + MTPmessages_sentMessage() : mtpDataOwner(0), _type(0) { + } + MTPmessages_sentMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessages_sentMessage &_messages_sentMessage() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_sentMessage) throw mtpErrorWrongTypeId(_type, mtpc_messages_sentMessage); + split(); + return *(MTPDmessages_sentMessage*)data; + } + const MTPDmessages_sentMessage &c_messages_sentMessage() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_sentMessage) throw mtpErrorWrongTypeId(_type, mtpc_messages_sentMessage); + return *(const MTPDmessages_sentMessage*)data; + } + + MTPDmessages_sentMessageLink &_messages_sentMessageLink() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_sentMessageLink) throw mtpErrorWrongTypeId(_type, mtpc_messages_sentMessageLink); + split(); + return *(MTPDmessages_sentMessageLink*)data; + } + const MTPDmessages_sentMessageLink &c_messages_sentMessageLink() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_sentMessageLink) throw mtpErrorWrongTypeId(_type, mtpc_messages_sentMessageLink); + return *(const MTPDmessages_sentMessageLink*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_sentMessage(mtpTypeId type); + explicit MTPmessages_sentMessage(MTPDmessages_sentMessage *_data); + explicit MTPmessages_sentMessage(MTPDmessages_sentMessageLink *_data); + + friend MTPmessages_sentMessage MTP_messages_sentMessage(MTPint _id, MTPint _date, MTPint _pts, MTPint _seq); + friend MTPmessages_sentMessage MTP_messages_sentMessageLink(MTPint _id, MTPint _date, MTPint _pts, MTPint _seq, const MTPVector &_links); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPmessages_SentMessage; + +class MTPmessages_chat : private mtpDataOwner { +public: + MTPmessages_chat(); + MTPmessages_chat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_chat) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDmessages_chat &_messages_chat() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDmessages_chat*)data; + } + const MTPDmessages_chat &c_messages_chat() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDmessages_chat*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_chat); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_chat(MTPDmessages_chat *_data); + + friend MTPmessages_chat MTP_messages_chat(const MTPChat &_chat, const MTPVector &_users); +}; +typedef MTPBoxed MTPmessages_Chat; + +class MTPmessages_chats : private mtpDataOwner { +public: + MTPmessages_chats(); + MTPmessages_chats(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_chats) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDmessages_chats &_messages_chats() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDmessages_chats*)data; + } + const MTPDmessages_chats &c_messages_chats() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDmessages_chats*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_chats); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_chats(MTPDmessages_chats *_data); + + friend MTPmessages_chats MTP_messages_chats(const MTPVector &_chats, const MTPVector &_users); +}; +typedef MTPBoxed MTPmessages_Chats; + +class MTPmessages_chatFull : private mtpDataOwner { +public: + MTPmessages_chatFull(); + MTPmessages_chatFull(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_chatFull) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDmessages_chatFull &_messages_chatFull() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDmessages_chatFull*)data; + } + const MTPDmessages_chatFull &c_messages_chatFull() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDmessages_chatFull*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_chatFull); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_chatFull(MTPDmessages_chatFull *_data); + + friend MTPmessages_chatFull MTP_messages_chatFull(const MTPChatFull &_full_chat, const MTPVector &_chats, const MTPVector &_users); +}; +typedef MTPBoxed MTPmessages_ChatFull; + +class MTPmessages_affectedHistory : private mtpDataOwner { +public: + MTPmessages_affectedHistory(); + MTPmessages_affectedHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_affectedHistory) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDmessages_affectedHistory &_messages_affectedHistory() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDmessages_affectedHistory*)data; + } + const MTPDmessages_affectedHistory &c_messages_affectedHistory() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDmessages_affectedHistory*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_affectedHistory); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_affectedHistory(MTPDmessages_affectedHistory *_data); + + friend MTPmessages_affectedHistory MTP_messages_affectedHistory(MTPint _pts, MTPint _seq, MTPint _offset); +}; +typedef MTPBoxed MTPmessages_AffectedHistory; + +class MTPmessagesFilter { +public: + MTPmessagesFilter() : _type(0) { + } + MTPmessagesFilter(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : _type(0) { + read(from, end, cons); + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessagesFilter(mtpTypeId type); + + friend MTPmessagesFilter MTP_inputMessagesFilterEmpty(); + friend MTPmessagesFilter MTP_inputMessagesFilterPhotos(); + friend MTPmessagesFilter MTP_inputMessagesFilterVideo(); + friend MTPmessagesFilter MTP_inputMessagesFilterPhotoVideo(); + friend MTPmessagesFilter MTP_inputMessagesFilterDocument(); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPMessagesFilter; + +class MTPupdate : private mtpDataOwner { +public: + MTPupdate() : mtpDataOwner(0), _type(0) { + } + MTPupdate(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDupdateNewMessage &_updateNewMessage() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateNewMessage) throw mtpErrorWrongTypeId(_type, mtpc_updateNewMessage); + split(); + return *(MTPDupdateNewMessage*)data; + } + const MTPDupdateNewMessage &c_updateNewMessage() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateNewMessage) throw mtpErrorWrongTypeId(_type, mtpc_updateNewMessage); + return *(const MTPDupdateNewMessage*)data; + } + + MTPDupdateMessageID &_updateMessageID() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateMessageID) throw mtpErrorWrongTypeId(_type, mtpc_updateMessageID); + split(); + return *(MTPDupdateMessageID*)data; + } + const MTPDupdateMessageID &c_updateMessageID() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateMessageID) throw mtpErrorWrongTypeId(_type, mtpc_updateMessageID); + return *(const MTPDupdateMessageID*)data; + } + + MTPDupdateReadMessages &_updateReadMessages() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateReadMessages) throw mtpErrorWrongTypeId(_type, mtpc_updateReadMessages); + split(); + return *(MTPDupdateReadMessages*)data; + } + const MTPDupdateReadMessages &c_updateReadMessages() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateReadMessages) throw mtpErrorWrongTypeId(_type, mtpc_updateReadMessages); + return *(const MTPDupdateReadMessages*)data; + } + + MTPDupdateDeleteMessages &_updateDeleteMessages() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateDeleteMessages) throw mtpErrorWrongTypeId(_type, mtpc_updateDeleteMessages); + split(); + return *(MTPDupdateDeleteMessages*)data; + } + const MTPDupdateDeleteMessages &c_updateDeleteMessages() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateDeleteMessages) throw mtpErrorWrongTypeId(_type, mtpc_updateDeleteMessages); + return *(const MTPDupdateDeleteMessages*)data; + } + + MTPDupdateRestoreMessages &_updateRestoreMessages() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateRestoreMessages) throw mtpErrorWrongTypeId(_type, mtpc_updateRestoreMessages); + split(); + return *(MTPDupdateRestoreMessages*)data; + } + const MTPDupdateRestoreMessages &c_updateRestoreMessages() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateRestoreMessages) throw mtpErrorWrongTypeId(_type, mtpc_updateRestoreMessages); + return *(const MTPDupdateRestoreMessages*)data; + } + + MTPDupdateUserTyping &_updateUserTyping() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateUserTyping) throw mtpErrorWrongTypeId(_type, mtpc_updateUserTyping); + split(); + return *(MTPDupdateUserTyping*)data; + } + const MTPDupdateUserTyping &c_updateUserTyping() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateUserTyping) throw mtpErrorWrongTypeId(_type, mtpc_updateUserTyping); + return *(const MTPDupdateUserTyping*)data; + } + + MTPDupdateChatUserTyping &_updateChatUserTyping() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateChatUserTyping) throw mtpErrorWrongTypeId(_type, mtpc_updateChatUserTyping); + split(); + return *(MTPDupdateChatUserTyping*)data; + } + const MTPDupdateChatUserTyping &c_updateChatUserTyping() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateChatUserTyping) throw mtpErrorWrongTypeId(_type, mtpc_updateChatUserTyping); + return *(const MTPDupdateChatUserTyping*)data; + } + + MTPDupdateChatParticipants &_updateChatParticipants() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateChatParticipants) throw mtpErrorWrongTypeId(_type, mtpc_updateChatParticipants); + split(); + return *(MTPDupdateChatParticipants*)data; + } + const MTPDupdateChatParticipants &c_updateChatParticipants() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateChatParticipants) throw mtpErrorWrongTypeId(_type, mtpc_updateChatParticipants); + return *(const MTPDupdateChatParticipants*)data; + } + + MTPDupdateUserStatus &_updateUserStatus() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateUserStatus) throw mtpErrorWrongTypeId(_type, mtpc_updateUserStatus); + split(); + return *(MTPDupdateUserStatus*)data; + } + const MTPDupdateUserStatus &c_updateUserStatus() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateUserStatus) throw mtpErrorWrongTypeId(_type, mtpc_updateUserStatus); + return *(const MTPDupdateUserStatus*)data; + } + + MTPDupdateUserName &_updateUserName() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateUserName) throw mtpErrorWrongTypeId(_type, mtpc_updateUserName); + split(); + return *(MTPDupdateUserName*)data; + } + const MTPDupdateUserName &c_updateUserName() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateUserName) throw mtpErrorWrongTypeId(_type, mtpc_updateUserName); + return *(const MTPDupdateUserName*)data; + } + + MTPDupdateUserPhoto &_updateUserPhoto() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateUserPhoto) throw mtpErrorWrongTypeId(_type, mtpc_updateUserPhoto); + split(); + return *(MTPDupdateUserPhoto*)data; + } + const MTPDupdateUserPhoto &c_updateUserPhoto() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateUserPhoto) throw mtpErrorWrongTypeId(_type, mtpc_updateUserPhoto); + return *(const MTPDupdateUserPhoto*)data; + } + + MTPDupdateContactRegistered &_updateContactRegistered() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateContactRegistered) throw mtpErrorWrongTypeId(_type, mtpc_updateContactRegistered); + split(); + return *(MTPDupdateContactRegistered*)data; + } + const MTPDupdateContactRegistered &c_updateContactRegistered() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateContactRegistered) throw mtpErrorWrongTypeId(_type, mtpc_updateContactRegistered); + return *(const MTPDupdateContactRegistered*)data; + } + + MTPDupdateContactLink &_updateContactLink() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateContactLink) throw mtpErrorWrongTypeId(_type, mtpc_updateContactLink); + split(); + return *(MTPDupdateContactLink*)data; + } + const MTPDupdateContactLink &c_updateContactLink() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateContactLink) throw mtpErrorWrongTypeId(_type, mtpc_updateContactLink); + return *(const MTPDupdateContactLink*)data; + } + + MTPDupdateActivation &_updateActivation() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateActivation) throw mtpErrorWrongTypeId(_type, mtpc_updateActivation); + split(); + return *(MTPDupdateActivation*)data; + } + const MTPDupdateActivation &c_updateActivation() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateActivation) throw mtpErrorWrongTypeId(_type, mtpc_updateActivation); + return *(const MTPDupdateActivation*)data; + } + + MTPDupdateNewAuthorization &_updateNewAuthorization() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateNewAuthorization) throw mtpErrorWrongTypeId(_type, mtpc_updateNewAuthorization); + split(); + return *(MTPDupdateNewAuthorization*)data; + } + const MTPDupdateNewAuthorization &c_updateNewAuthorization() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateNewAuthorization) throw mtpErrorWrongTypeId(_type, mtpc_updateNewAuthorization); + return *(const MTPDupdateNewAuthorization*)data; + } + + MTPDupdateNewGeoChatMessage &_updateNewGeoChatMessage() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateNewGeoChatMessage) throw mtpErrorWrongTypeId(_type, mtpc_updateNewGeoChatMessage); + split(); + return *(MTPDupdateNewGeoChatMessage*)data; + } + const MTPDupdateNewGeoChatMessage &c_updateNewGeoChatMessage() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateNewGeoChatMessage) throw mtpErrorWrongTypeId(_type, mtpc_updateNewGeoChatMessage); + return *(const MTPDupdateNewGeoChatMessage*)data; + } + + MTPDupdateNewEncryptedMessage &_updateNewEncryptedMessage() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateNewEncryptedMessage) throw mtpErrorWrongTypeId(_type, mtpc_updateNewEncryptedMessage); + split(); + return *(MTPDupdateNewEncryptedMessage*)data; + } + const MTPDupdateNewEncryptedMessage &c_updateNewEncryptedMessage() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateNewEncryptedMessage) throw mtpErrorWrongTypeId(_type, mtpc_updateNewEncryptedMessage); + return *(const MTPDupdateNewEncryptedMessage*)data; + } + + MTPDupdateEncryptedChatTyping &_updateEncryptedChatTyping() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateEncryptedChatTyping) throw mtpErrorWrongTypeId(_type, mtpc_updateEncryptedChatTyping); + split(); + return *(MTPDupdateEncryptedChatTyping*)data; + } + const MTPDupdateEncryptedChatTyping &c_updateEncryptedChatTyping() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateEncryptedChatTyping) throw mtpErrorWrongTypeId(_type, mtpc_updateEncryptedChatTyping); + return *(const MTPDupdateEncryptedChatTyping*)data; + } + + MTPDupdateEncryption &_updateEncryption() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateEncryption) throw mtpErrorWrongTypeId(_type, mtpc_updateEncryption); + split(); + return *(MTPDupdateEncryption*)data; + } + const MTPDupdateEncryption &c_updateEncryption() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateEncryption) throw mtpErrorWrongTypeId(_type, mtpc_updateEncryption); + return *(const MTPDupdateEncryption*)data; + } + + MTPDupdateEncryptedMessagesRead &_updateEncryptedMessagesRead() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateEncryptedMessagesRead) throw mtpErrorWrongTypeId(_type, mtpc_updateEncryptedMessagesRead); + split(); + return *(MTPDupdateEncryptedMessagesRead*)data; + } + const MTPDupdateEncryptedMessagesRead &c_updateEncryptedMessagesRead() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateEncryptedMessagesRead) throw mtpErrorWrongTypeId(_type, mtpc_updateEncryptedMessagesRead); + return *(const MTPDupdateEncryptedMessagesRead*)data; + } + + MTPDupdateChatParticipantAdd &_updateChatParticipantAdd() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateChatParticipantAdd) throw mtpErrorWrongTypeId(_type, mtpc_updateChatParticipantAdd); + split(); + return *(MTPDupdateChatParticipantAdd*)data; + } + const MTPDupdateChatParticipantAdd &c_updateChatParticipantAdd() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateChatParticipantAdd) throw mtpErrorWrongTypeId(_type, mtpc_updateChatParticipantAdd); + return *(const MTPDupdateChatParticipantAdd*)data; + } + + MTPDupdateChatParticipantDelete &_updateChatParticipantDelete() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateChatParticipantDelete) throw mtpErrorWrongTypeId(_type, mtpc_updateChatParticipantDelete); + split(); + return *(MTPDupdateChatParticipantDelete*)data; + } + const MTPDupdateChatParticipantDelete &c_updateChatParticipantDelete() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateChatParticipantDelete) throw mtpErrorWrongTypeId(_type, mtpc_updateChatParticipantDelete); + return *(const MTPDupdateChatParticipantDelete*)data; + } + + MTPDupdateDcOptions &_updateDcOptions() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateDcOptions) throw mtpErrorWrongTypeId(_type, mtpc_updateDcOptions); + split(); + return *(MTPDupdateDcOptions*)data; + } + const MTPDupdateDcOptions &c_updateDcOptions() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateDcOptions) throw mtpErrorWrongTypeId(_type, mtpc_updateDcOptions); + return *(const MTPDupdateDcOptions*)data; + } + + MTPDupdateUserBlocked &_updateUserBlocked() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateUserBlocked) throw mtpErrorWrongTypeId(_type, mtpc_updateUserBlocked); + split(); + return *(MTPDupdateUserBlocked*)data; + } + const MTPDupdateUserBlocked &c_updateUserBlocked() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateUserBlocked) throw mtpErrorWrongTypeId(_type, mtpc_updateUserBlocked); + return *(const MTPDupdateUserBlocked*)data; + } + + MTPDupdateNotifySettings &_updateNotifySettings() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateNotifySettings) throw mtpErrorWrongTypeId(_type, mtpc_updateNotifySettings); + split(); + return *(MTPDupdateNotifySettings*)data; + } + const MTPDupdateNotifySettings &c_updateNotifySettings() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateNotifySettings) throw mtpErrorWrongTypeId(_type, mtpc_updateNotifySettings); + return *(const MTPDupdateNotifySettings*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPupdate(mtpTypeId type); + explicit MTPupdate(MTPDupdateNewMessage *_data); + explicit MTPupdate(MTPDupdateMessageID *_data); + explicit MTPupdate(MTPDupdateReadMessages *_data); + explicit MTPupdate(MTPDupdateDeleteMessages *_data); + explicit MTPupdate(MTPDupdateRestoreMessages *_data); + explicit MTPupdate(MTPDupdateUserTyping *_data); + explicit MTPupdate(MTPDupdateChatUserTyping *_data); + explicit MTPupdate(MTPDupdateChatParticipants *_data); + explicit MTPupdate(MTPDupdateUserStatus *_data); + explicit MTPupdate(MTPDupdateUserName *_data); + explicit MTPupdate(MTPDupdateUserPhoto *_data); + explicit MTPupdate(MTPDupdateContactRegistered *_data); + explicit MTPupdate(MTPDupdateContactLink *_data); + explicit MTPupdate(MTPDupdateActivation *_data); + explicit MTPupdate(MTPDupdateNewAuthorization *_data); + explicit MTPupdate(MTPDupdateNewGeoChatMessage *_data); + explicit MTPupdate(MTPDupdateNewEncryptedMessage *_data); + explicit MTPupdate(MTPDupdateEncryptedChatTyping *_data); + explicit MTPupdate(MTPDupdateEncryption *_data); + explicit MTPupdate(MTPDupdateEncryptedMessagesRead *_data); + explicit MTPupdate(MTPDupdateChatParticipantAdd *_data); + explicit MTPupdate(MTPDupdateChatParticipantDelete *_data); + explicit MTPupdate(MTPDupdateDcOptions *_data); + explicit MTPupdate(MTPDupdateUserBlocked *_data); + explicit MTPupdate(MTPDupdateNotifySettings *_data); + + friend MTPupdate MTP_updateNewMessage(const MTPMessage &_message, MTPint _pts); + friend MTPupdate MTP_updateMessageID(MTPint _id, const MTPlong &_random_id); + friend MTPupdate MTP_updateReadMessages(const MTPVector &_messages, MTPint _pts); + friend MTPupdate MTP_updateDeleteMessages(const MTPVector &_messages, MTPint _pts); + friend MTPupdate MTP_updateRestoreMessages(const MTPVector &_messages, MTPint _pts); + friend MTPupdate MTP_updateUserTyping(MTPint _user_id); + friend MTPupdate MTP_updateChatUserTyping(MTPint _chat_id, MTPint _user_id); + friend MTPupdate MTP_updateChatParticipants(const MTPChatParticipants &_participants); + friend MTPupdate MTP_updateUserStatus(MTPint _user_id, const MTPUserStatus &_status); + friend MTPupdate MTP_updateUserName(MTPint _user_id, const MTPstring &_first_name, const MTPstring &_last_name); + friend MTPupdate MTP_updateUserPhoto(MTPint _user_id, MTPint _date, const MTPUserProfilePhoto &_photo, MTPBool _previous); + friend MTPupdate MTP_updateContactRegistered(MTPint _user_id, MTPint _date); + friend MTPupdate MTP_updateContactLink(MTPint _user_id, const MTPcontacts_MyLink &_my_link, const MTPcontacts_ForeignLink &_foreign_link); + friend MTPupdate MTP_updateActivation(MTPint _user_id); + friend MTPupdate MTP_updateNewAuthorization(const MTPlong &_auth_key_id, MTPint _date, const MTPstring &_device, const MTPstring &_location); + friend MTPupdate MTP_updateNewGeoChatMessage(const MTPGeoChatMessage &_message); + friend MTPupdate MTP_updateNewEncryptedMessage(const MTPEncryptedMessage &_message, MTPint _qts); + friend MTPupdate MTP_updateEncryptedChatTyping(MTPint _chat_id); + friend MTPupdate MTP_updateEncryption(const MTPEncryptedChat &_chat, MTPint _date); + friend MTPupdate MTP_updateEncryptedMessagesRead(MTPint _chat_id, MTPint _max_date, MTPint _date); + friend MTPupdate MTP_updateChatParticipantAdd(MTPint _chat_id, MTPint _user_id, MTPint _inviter_id, MTPint _version); + friend MTPupdate MTP_updateChatParticipantDelete(MTPint _chat_id, MTPint _user_id, MTPint _version); + friend MTPupdate MTP_updateDcOptions(const MTPVector &_dc_options); + friend MTPupdate MTP_updateUserBlocked(MTPint _user_id, MTPBool _blocked); + friend MTPupdate MTP_updateNotifySettings(const MTPNotifyPeer &_peer, const MTPPeerNotifySettings &_notify_settings); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPUpdate; + +class MTPupdates_state : private mtpDataOwner { +public: + MTPupdates_state(); + MTPupdates_state(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_updates_state) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDupdates_state &_updates_state() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDupdates_state*)data; + } + const MTPDupdates_state &c_updates_state() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDupdates_state*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_updates_state); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPupdates_state(MTPDupdates_state *_data); + + friend MTPupdates_state MTP_updates_state(MTPint _pts, MTPint _qts, MTPint _date, MTPint _seq, MTPint _unread_count); +}; +typedef MTPBoxed MTPupdates_State; + +class MTPupdates_difference : private mtpDataOwner { +public: + MTPupdates_difference() : mtpDataOwner(0), _type(0) { + } + MTPupdates_difference(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDupdates_differenceEmpty &_updates_differenceEmpty() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updates_differenceEmpty) throw mtpErrorWrongTypeId(_type, mtpc_updates_differenceEmpty); + split(); + return *(MTPDupdates_differenceEmpty*)data; + } + const MTPDupdates_differenceEmpty &c_updates_differenceEmpty() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updates_differenceEmpty) throw mtpErrorWrongTypeId(_type, mtpc_updates_differenceEmpty); + return *(const MTPDupdates_differenceEmpty*)data; + } + + MTPDupdates_difference &_updates_difference() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updates_difference) throw mtpErrorWrongTypeId(_type, mtpc_updates_difference); + split(); + return *(MTPDupdates_difference*)data; + } + const MTPDupdates_difference &c_updates_difference() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updates_difference) throw mtpErrorWrongTypeId(_type, mtpc_updates_difference); + return *(const MTPDupdates_difference*)data; + } + + MTPDupdates_differenceSlice &_updates_differenceSlice() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updates_differenceSlice) throw mtpErrorWrongTypeId(_type, mtpc_updates_differenceSlice); + split(); + return *(MTPDupdates_differenceSlice*)data; + } + const MTPDupdates_differenceSlice &c_updates_differenceSlice() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updates_differenceSlice) throw mtpErrorWrongTypeId(_type, mtpc_updates_differenceSlice); + return *(const MTPDupdates_differenceSlice*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPupdates_difference(mtpTypeId type); + explicit MTPupdates_difference(MTPDupdates_differenceEmpty *_data); + explicit MTPupdates_difference(MTPDupdates_difference *_data); + explicit MTPupdates_difference(MTPDupdates_differenceSlice *_data); + + friend MTPupdates_difference MTP_updates_differenceEmpty(MTPint _date, MTPint _seq); + friend MTPupdates_difference MTP_updates_difference(const MTPVector &_new_messages, const MTPVector &_new_encrypted_messages, const MTPVector &_other_updates, const MTPVector &_chats, const MTPVector &_users, const MTPupdates_State &_state); + friend MTPupdates_difference MTP_updates_differenceSlice(const MTPVector &_new_messages, const MTPVector &_new_encrypted_messages, const MTPVector &_other_updates, const MTPVector &_chats, const MTPVector &_users, const MTPupdates_State &_intermediate_state); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPupdates_Difference; + +class MTPupdates : private mtpDataOwner { +public: + MTPupdates() : mtpDataOwner(0), _type(0) { + } + MTPupdates(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDupdateShortMessage &_updateShortMessage() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateShortMessage) throw mtpErrorWrongTypeId(_type, mtpc_updateShortMessage); + split(); + return *(MTPDupdateShortMessage*)data; + } + const MTPDupdateShortMessage &c_updateShortMessage() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateShortMessage) throw mtpErrorWrongTypeId(_type, mtpc_updateShortMessage); + return *(const MTPDupdateShortMessage*)data; + } + + MTPDupdateShortChatMessage &_updateShortChatMessage() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateShortChatMessage) throw mtpErrorWrongTypeId(_type, mtpc_updateShortChatMessage); + split(); + return *(MTPDupdateShortChatMessage*)data; + } + const MTPDupdateShortChatMessage &c_updateShortChatMessage() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateShortChatMessage) throw mtpErrorWrongTypeId(_type, mtpc_updateShortChatMessage); + return *(const MTPDupdateShortChatMessage*)data; + } + + MTPDupdateShort &_updateShort() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateShort) throw mtpErrorWrongTypeId(_type, mtpc_updateShort); + split(); + return *(MTPDupdateShort*)data; + } + const MTPDupdateShort &c_updateShort() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateShort) throw mtpErrorWrongTypeId(_type, mtpc_updateShort); + return *(const MTPDupdateShort*)data; + } + + MTPDupdatesCombined &_updatesCombined() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updatesCombined) throw mtpErrorWrongTypeId(_type, mtpc_updatesCombined); + split(); + return *(MTPDupdatesCombined*)data; + } + const MTPDupdatesCombined &c_updatesCombined() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updatesCombined) throw mtpErrorWrongTypeId(_type, mtpc_updatesCombined); + return *(const MTPDupdatesCombined*)data; + } + + MTPDupdates &_updates() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updates) throw mtpErrorWrongTypeId(_type, mtpc_updates); + split(); + return *(MTPDupdates*)data; + } + const MTPDupdates &c_updates() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updates) throw mtpErrorWrongTypeId(_type, mtpc_updates); + return *(const MTPDupdates*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPupdates(mtpTypeId type); + explicit MTPupdates(MTPDupdateShortMessage *_data); + explicit MTPupdates(MTPDupdateShortChatMessage *_data); + explicit MTPupdates(MTPDupdateShort *_data); + explicit MTPupdates(MTPDupdatesCombined *_data); + explicit MTPupdates(MTPDupdates *_data); + + friend MTPupdates MTP_updatesTooLong(); + friend MTPupdates MTP_updateShortMessage(MTPint _id, MTPint _from_id, const MTPstring &_message, MTPint _pts, MTPint _date, MTPint _seq); + friend MTPupdates MTP_updateShortChatMessage(MTPint _id, MTPint _from_id, MTPint _chat_id, const MTPstring &_message, MTPint _pts, MTPint _date, MTPint _seq); + friend MTPupdates MTP_updateShort(const MTPUpdate &_update, MTPint _date); + friend MTPupdates MTP_updatesCombined(const MTPVector &_updates, const MTPVector &_users, const MTPVector &_chats, MTPint _date, MTPint _seq_start, MTPint _seq); + friend MTPupdates MTP_updates(const MTPVector &_updates, const MTPVector &_users, const MTPVector &_chats, MTPint _date, MTPint _seq); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPUpdates; + +class MTPphotos_photos : private mtpDataOwner { +public: + MTPphotos_photos() : mtpDataOwner(0), _type(0) { + } + MTPphotos_photos(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDphotos_photos &_photos_photos() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photos_photos) throw mtpErrorWrongTypeId(_type, mtpc_photos_photos); + split(); + return *(MTPDphotos_photos*)data; + } + const MTPDphotos_photos &c_photos_photos() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photos_photos) throw mtpErrorWrongTypeId(_type, mtpc_photos_photos); + return *(const MTPDphotos_photos*)data; + } + + MTPDphotos_photosSlice &_photos_photosSlice() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photos_photosSlice) throw mtpErrorWrongTypeId(_type, mtpc_photos_photosSlice); + split(); + return *(MTPDphotos_photosSlice*)data; + } + const MTPDphotos_photosSlice &c_photos_photosSlice() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_photos_photosSlice) throw mtpErrorWrongTypeId(_type, mtpc_photos_photosSlice); + return *(const MTPDphotos_photosSlice*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPphotos_photos(mtpTypeId type); + explicit MTPphotos_photos(MTPDphotos_photos *_data); + explicit MTPphotos_photos(MTPDphotos_photosSlice *_data); + + friend MTPphotos_photos MTP_photos_photos(const MTPVector &_photos, const MTPVector &_users); + friend MTPphotos_photos MTP_photos_photosSlice(MTPint _count, const MTPVector &_photos, const MTPVector &_users); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPphotos_Photos; + +class MTPphotos_photo : private mtpDataOwner { +public: + MTPphotos_photo(); + MTPphotos_photo(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_photos_photo) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDphotos_photo &_photos_photo() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDphotos_photo*)data; + } + const MTPDphotos_photo &c_photos_photo() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDphotos_photo*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_photos_photo); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPphotos_photo(MTPDphotos_photo *_data); + + friend MTPphotos_photo MTP_photos_photo(const MTPPhoto &_photo, const MTPVector &_users); +}; +typedef MTPBoxed MTPphotos_Photo; + +class MTPupload_file : private mtpDataOwner { +public: + MTPupload_file(); + MTPupload_file(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_upload_file) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDupload_file &_upload_file() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDupload_file*)data; + } + const MTPDupload_file &c_upload_file() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDupload_file*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_upload_file); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPupload_file(MTPDupload_file *_data); + + friend MTPupload_file MTP_upload_file(const MTPstorage_FileType &_type, MTPint _mtime, const MTPbytes &_bytes); +}; +typedef MTPBoxed MTPupload_File; + +class MTPdcOption : private mtpDataOwner { +public: + MTPdcOption(); + MTPdcOption(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_dcOption) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDdcOption &_dcOption() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDdcOption*)data; + } + const MTPDdcOption &c_dcOption() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDdcOption*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_dcOption); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPdcOption(MTPDdcOption *_data); + + friend MTPdcOption MTP_dcOption(MTPint _id, const MTPstring &_hostname, const MTPstring &_ip_address, MTPint _port); +}; +typedef MTPBoxed MTPDcOption; + +class MTPconfig : private mtpDataOwner { +public: + MTPconfig(); + MTPconfig(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_config) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDconfig &_config() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDconfig*)data; + } + const MTPDconfig &c_config() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDconfig*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_config); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPconfig(MTPDconfig *_data); + + friend MTPconfig MTP_config(MTPint _date, MTPBool _test_mode, MTPint _this_dc, const MTPVector &_dc_options, MTPint _chat_size_max, MTPint _broadcast_size_max); +}; +typedef MTPBoxed MTPConfig; + +class MTPnearestDc : private mtpDataOwner { +public: + MTPnearestDc(); + MTPnearestDc(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_nearestDc) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDnearestDc &_nearestDc() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDnearestDc*)data; + } + const MTPDnearestDc &c_nearestDc() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDnearestDc*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_nearestDc); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPnearestDc(MTPDnearestDc *_data); + + friend MTPnearestDc MTP_nearestDc(const MTPstring &_country, MTPint _this_dc, MTPint _nearest_dc); +}; +typedef MTPBoxed MTPNearestDc; + +class MTPhelp_appUpdate : private mtpDataOwner { +public: + MTPhelp_appUpdate() : mtpDataOwner(0), _type(0) { + } + MTPhelp_appUpdate(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDhelp_appUpdate &_help_appUpdate() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_help_appUpdate) throw mtpErrorWrongTypeId(_type, mtpc_help_appUpdate); + split(); + return *(MTPDhelp_appUpdate*)data; + } + const MTPDhelp_appUpdate &c_help_appUpdate() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_help_appUpdate) throw mtpErrorWrongTypeId(_type, mtpc_help_appUpdate); + return *(const MTPDhelp_appUpdate*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPhelp_appUpdate(mtpTypeId type); + explicit MTPhelp_appUpdate(MTPDhelp_appUpdate *_data); + + friend MTPhelp_appUpdate MTP_help_appUpdate(MTPint _id, MTPBool _critical, const MTPstring &_url, const MTPstring &_text); + friend MTPhelp_appUpdate MTP_help_noAppUpdate(); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPhelp_AppUpdate; + +class MTPhelp_inviteText : private mtpDataOwner { +public: + MTPhelp_inviteText(); + MTPhelp_inviteText(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_inviteText) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDhelp_inviteText &_help_inviteText() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDhelp_inviteText*)data; + } + const MTPDhelp_inviteText &c_help_inviteText() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDhelp_inviteText*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_inviteText); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPhelp_inviteText(MTPDhelp_inviteText *_data); + + friend MTPhelp_inviteText MTP_help_inviteText(const MTPstring &_message); +}; +typedef MTPBoxed MTPhelp_InviteText; + +class MTPinputGeoChat : private mtpDataOwner { +public: + MTPinputGeoChat(); + MTPinputGeoChat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_inputGeoChat) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDinputGeoChat &_inputGeoChat() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDinputGeoChat*)data; + } + const MTPDinputGeoChat &c_inputGeoChat() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDinputGeoChat*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_inputGeoChat); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputGeoChat(MTPDinputGeoChat *_data); + + friend MTPinputGeoChat MTP_inputGeoChat(MTPint _chat_id, const MTPlong &_access_hash); +}; +typedef MTPBoxed MTPInputGeoChat; + +class MTPgeoChatMessage : private mtpDataOwner { +public: + MTPgeoChatMessage() : mtpDataOwner(0), _type(0) { + } + MTPgeoChatMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDgeoChatMessageEmpty &_geoChatMessageEmpty() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geoChatMessageEmpty) throw mtpErrorWrongTypeId(_type, mtpc_geoChatMessageEmpty); + split(); + return *(MTPDgeoChatMessageEmpty*)data; + } + const MTPDgeoChatMessageEmpty &c_geoChatMessageEmpty() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geoChatMessageEmpty) throw mtpErrorWrongTypeId(_type, mtpc_geoChatMessageEmpty); + return *(const MTPDgeoChatMessageEmpty*)data; + } + + MTPDgeoChatMessage &_geoChatMessage() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geoChatMessage) throw mtpErrorWrongTypeId(_type, mtpc_geoChatMessage); + split(); + return *(MTPDgeoChatMessage*)data; + } + const MTPDgeoChatMessage &c_geoChatMessage() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geoChatMessage) throw mtpErrorWrongTypeId(_type, mtpc_geoChatMessage); + return *(const MTPDgeoChatMessage*)data; + } + + MTPDgeoChatMessageService &_geoChatMessageService() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geoChatMessageService) throw mtpErrorWrongTypeId(_type, mtpc_geoChatMessageService); + split(); + return *(MTPDgeoChatMessageService*)data; + } + const MTPDgeoChatMessageService &c_geoChatMessageService() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geoChatMessageService) throw mtpErrorWrongTypeId(_type, mtpc_geoChatMessageService); + return *(const MTPDgeoChatMessageService*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPgeoChatMessage(mtpTypeId type); + explicit MTPgeoChatMessage(MTPDgeoChatMessageEmpty *_data); + explicit MTPgeoChatMessage(MTPDgeoChatMessage *_data); + explicit MTPgeoChatMessage(MTPDgeoChatMessageService *_data); + + friend MTPgeoChatMessage MTP_geoChatMessageEmpty(MTPint _chat_id, MTPint _id); + friend MTPgeoChatMessage MTP_geoChatMessage(MTPint _chat_id, MTPint _id, MTPint _from_id, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media); + friend MTPgeoChatMessage MTP_geoChatMessageService(MTPint _chat_id, MTPint _id, MTPint _from_id, MTPint _date, const MTPMessageAction &_action); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPGeoChatMessage; + +class MTPgeochats_statedMessage : private mtpDataOwner { +public: + MTPgeochats_statedMessage(); + MTPgeochats_statedMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_statedMessage) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDgeochats_statedMessage &_geochats_statedMessage() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDgeochats_statedMessage*)data; + } + const MTPDgeochats_statedMessage &c_geochats_statedMessage() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDgeochats_statedMessage*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_statedMessage); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPgeochats_statedMessage(MTPDgeochats_statedMessage *_data); + + friend MTPgeochats_statedMessage MTP_geochats_statedMessage(const MTPGeoChatMessage &_message, const MTPVector &_chats, const MTPVector &_users, MTPint _seq); +}; +typedef MTPBoxed MTPgeochats_StatedMessage; + +class MTPgeochats_located : private mtpDataOwner { +public: + MTPgeochats_located(); + MTPgeochats_located(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_located) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDgeochats_located &_geochats_located() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDgeochats_located*)data; + } + const MTPDgeochats_located &c_geochats_located() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDgeochats_located*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_located); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPgeochats_located(MTPDgeochats_located *_data); + + friend MTPgeochats_located MTP_geochats_located(const MTPVector &_results, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users); +}; +typedef MTPBoxed MTPgeochats_Located; + +class MTPgeochats_messages : private mtpDataOwner { +public: + MTPgeochats_messages() : mtpDataOwner(0), _type(0) { + } + MTPgeochats_messages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDgeochats_messages &_geochats_messages() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geochats_messages) throw mtpErrorWrongTypeId(_type, mtpc_geochats_messages); + split(); + return *(MTPDgeochats_messages*)data; + } + const MTPDgeochats_messages &c_geochats_messages() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geochats_messages) throw mtpErrorWrongTypeId(_type, mtpc_geochats_messages); + return *(const MTPDgeochats_messages*)data; + } + + MTPDgeochats_messagesSlice &_geochats_messagesSlice() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geochats_messagesSlice) throw mtpErrorWrongTypeId(_type, mtpc_geochats_messagesSlice); + split(); + return *(MTPDgeochats_messagesSlice*)data; + } + const MTPDgeochats_messagesSlice &c_geochats_messagesSlice() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_geochats_messagesSlice) throw mtpErrorWrongTypeId(_type, mtpc_geochats_messagesSlice); + return *(const MTPDgeochats_messagesSlice*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPgeochats_messages(mtpTypeId type); + explicit MTPgeochats_messages(MTPDgeochats_messages *_data); + explicit MTPgeochats_messages(MTPDgeochats_messagesSlice *_data); + + friend MTPgeochats_messages MTP_geochats_messages(const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users); + friend MTPgeochats_messages MTP_geochats_messagesSlice(MTPint _count, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPgeochats_Messages; + +class MTPencryptedChat : private mtpDataOwner { +public: + MTPencryptedChat() : mtpDataOwner(0), _type(0) { + } + MTPencryptedChat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDencryptedChatEmpty &_encryptedChatEmpty() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedChatEmpty) throw mtpErrorWrongTypeId(_type, mtpc_encryptedChatEmpty); + split(); + return *(MTPDencryptedChatEmpty*)data; + } + const MTPDencryptedChatEmpty &c_encryptedChatEmpty() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedChatEmpty) throw mtpErrorWrongTypeId(_type, mtpc_encryptedChatEmpty); + return *(const MTPDencryptedChatEmpty*)data; + } + + MTPDencryptedChatWaiting &_encryptedChatWaiting() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedChatWaiting) throw mtpErrorWrongTypeId(_type, mtpc_encryptedChatWaiting); + split(); + return *(MTPDencryptedChatWaiting*)data; + } + const MTPDencryptedChatWaiting &c_encryptedChatWaiting() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedChatWaiting) throw mtpErrorWrongTypeId(_type, mtpc_encryptedChatWaiting); + return *(const MTPDencryptedChatWaiting*)data; + } + + MTPDencryptedChatRequested &_encryptedChatRequested() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedChatRequested) throw mtpErrorWrongTypeId(_type, mtpc_encryptedChatRequested); + split(); + return *(MTPDencryptedChatRequested*)data; + } + const MTPDencryptedChatRequested &c_encryptedChatRequested() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedChatRequested) throw mtpErrorWrongTypeId(_type, mtpc_encryptedChatRequested); + return *(const MTPDencryptedChatRequested*)data; + } + + MTPDencryptedChat &_encryptedChat() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedChat) throw mtpErrorWrongTypeId(_type, mtpc_encryptedChat); + split(); + return *(MTPDencryptedChat*)data; + } + const MTPDencryptedChat &c_encryptedChat() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedChat) throw mtpErrorWrongTypeId(_type, mtpc_encryptedChat); + return *(const MTPDencryptedChat*)data; + } + + MTPDencryptedChatDiscarded &_encryptedChatDiscarded() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedChatDiscarded) throw mtpErrorWrongTypeId(_type, mtpc_encryptedChatDiscarded); + split(); + return *(MTPDencryptedChatDiscarded*)data; + } + const MTPDencryptedChatDiscarded &c_encryptedChatDiscarded() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedChatDiscarded) throw mtpErrorWrongTypeId(_type, mtpc_encryptedChatDiscarded); + return *(const MTPDencryptedChatDiscarded*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPencryptedChat(mtpTypeId type); + explicit MTPencryptedChat(MTPDencryptedChatEmpty *_data); + explicit MTPencryptedChat(MTPDencryptedChatWaiting *_data); + explicit MTPencryptedChat(MTPDencryptedChatRequested *_data); + explicit MTPencryptedChat(MTPDencryptedChat *_data); + explicit MTPencryptedChat(MTPDencryptedChatDiscarded *_data); + + friend MTPencryptedChat MTP_encryptedChatEmpty(MTPint _id); + friend MTPencryptedChat MTP_encryptedChatWaiting(MTPint _id, const MTPlong &_access_hash, MTPint _date, MTPint _admin_id, MTPint _participant_id); + friend MTPencryptedChat MTP_encryptedChatRequested(MTPint _id, const MTPlong &_access_hash, MTPint _date, MTPint _admin_id, MTPint _participant_id, const MTPbytes &_g_a); + friend MTPencryptedChat MTP_encryptedChat(MTPint _id, const MTPlong &_access_hash, MTPint _date, MTPint _admin_id, MTPint _participant_id, const MTPbytes &_g_a_or_b, const MTPlong &_key_fingerprint); + friend MTPencryptedChat MTP_encryptedChatDiscarded(MTPint _id); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPEncryptedChat; + +class MTPinputEncryptedChat : private mtpDataOwner { +public: + MTPinputEncryptedChat(); + MTPinputEncryptedChat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_inputEncryptedChat) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDinputEncryptedChat &_inputEncryptedChat() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDinputEncryptedChat*)data; + } + const MTPDinputEncryptedChat &c_inputEncryptedChat() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDinputEncryptedChat*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_inputEncryptedChat); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputEncryptedChat(MTPDinputEncryptedChat *_data); + + friend MTPinputEncryptedChat MTP_inputEncryptedChat(MTPint _chat_id, const MTPlong &_access_hash); +}; +typedef MTPBoxed MTPInputEncryptedChat; + +class MTPencryptedFile : private mtpDataOwner { +public: + MTPencryptedFile() : mtpDataOwner(0), _type(0) { + } + MTPencryptedFile(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDencryptedFile &_encryptedFile() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedFile) throw mtpErrorWrongTypeId(_type, mtpc_encryptedFile); + split(); + return *(MTPDencryptedFile*)data; + } + const MTPDencryptedFile &c_encryptedFile() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedFile) throw mtpErrorWrongTypeId(_type, mtpc_encryptedFile); + return *(const MTPDencryptedFile*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPencryptedFile(mtpTypeId type); + explicit MTPencryptedFile(MTPDencryptedFile *_data); + + friend MTPencryptedFile MTP_encryptedFileEmpty(); + friend MTPencryptedFile MTP_encryptedFile(const MTPlong &_id, const MTPlong &_access_hash, MTPint _size, MTPint _dc_id, MTPint _key_fingerprint); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPEncryptedFile; + +class MTPinputEncryptedFile : private mtpDataOwner { +public: + MTPinputEncryptedFile() : mtpDataOwner(0), _type(0) { + } + MTPinputEncryptedFile(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputEncryptedFileUploaded &_inputEncryptedFileUploaded() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputEncryptedFileUploaded) throw mtpErrorWrongTypeId(_type, mtpc_inputEncryptedFileUploaded); + split(); + return *(MTPDinputEncryptedFileUploaded*)data; + } + const MTPDinputEncryptedFileUploaded &c_inputEncryptedFileUploaded() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputEncryptedFileUploaded) throw mtpErrorWrongTypeId(_type, mtpc_inputEncryptedFileUploaded); + return *(const MTPDinputEncryptedFileUploaded*)data; + } + + MTPDinputEncryptedFile &_inputEncryptedFile() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputEncryptedFile) throw mtpErrorWrongTypeId(_type, mtpc_inputEncryptedFile); + split(); + return *(MTPDinputEncryptedFile*)data; + } + const MTPDinputEncryptedFile &c_inputEncryptedFile() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputEncryptedFile) throw mtpErrorWrongTypeId(_type, mtpc_inputEncryptedFile); + return *(const MTPDinputEncryptedFile*)data; + } + + MTPDinputEncryptedFileBigUploaded &_inputEncryptedFileBigUploaded() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputEncryptedFileBigUploaded) throw mtpErrorWrongTypeId(_type, mtpc_inputEncryptedFileBigUploaded); + split(); + return *(MTPDinputEncryptedFileBigUploaded*)data; + } + const MTPDinputEncryptedFileBigUploaded &c_inputEncryptedFileBigUploaded() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputEncryptedFileBigUploaded) throw mtpErrorWrongTypeId(_type, mtpc_inputEncryptedFileBigUploaded); + return *(const MTPDinputEncryptedFileBigUploaded*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputEncryptedFile(mtpTypeId type); + explicit MTPinputEncryptedFile(MTPDinputEncryptedFileUploaded *_data); + explicit MTPinputEncryptedFile(MTPDinputEncryptedFile *_data); + explicit MTPinputEncryptedFile(MTPDinputEncryptedFileBigUploaded *_data); + + friend MTPinputEncryptedFile MTP_inputEncryptedFileEmpty(); + friend MTPinputEncryptedFile MTP_inputEncryptedFileUploaded(const MTPlong &_id, MTPint _parts, const MTPstring &_md5_checksum, MTPint _key_fingerprint); + friend MTPinputEncryptedFile MTP_inputEncryptedFile(const MTPlong &_id, const MTPlong &_access_hash); + friend MTPinputEncryptedFile MTP_inputEncryptedFileBigUploaded(const MTPlong &_id, MTPint _parts, MTPint _key_fingerprint); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputEncryptedFile; + +class MTPencryptedMessage : private mtpDataOwner { +public: + MTPencryptedMessage() : mtpDataOwner(0), _type(0) { + } + MTPencryptedMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDencryptedMessage &_encryptedMessage() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedMessage) throw mtpErrorWrongTypeId(_type, mtpc_encryptedMessage); + split(); + return *(MTPDencryptedMessage*)data; + } + const MTPDencryptedMessage &c_encryptedMessage() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedMessage) throw mtpErrorWrongTypeId(_type, mtpc_encryptedMessage); + return *(const MTPDencryptedMessage*)data; + } + + MTPDencryptedMessageService &_encryptedMessageService() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedMessageService) throw mtpErrorWrongTypeId(_type, mtpc_encryptedMessageService); + split(); + return *(MTPDencryptedMessageService*)data; + } + const MTPDencryptedMessageService &c_encryptedMessageService() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_encryptedMessageService) throw mtpErrorWrongTypeId(_type, mtpc_encryptedMessageService); + return *(const MTPDencryptedMessageService*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPencryptedMessage(mtpTypeId type); + explicit MTPencryptedMessage(MTPDencryptedMessage *_data); + explicit MTPencryptedMessage(MTPDencryptedMessageService *_data); + + friend MTPencryptedMessage MTP_encryptedMessage(const MTPlong &_random_id, MTPint _chat_id, MTPint _date, const MTPbytes &_bytes, const MTPEncryptedFile &_file); + friend MTPencryptedMessage MTP_encryptedMessageService(const MTPlong &_random_id, MTPint _chat_id, MTPint _date, const MTPbytes &_bytes); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPEncryptedMessage; + +class MTPdecryptedMessageLayer : private mtpDataOwner { +public: + MTPdecryptedMessageLayer(); + MTPdecryptedMessageLayer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_decryptedMessageLayer) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDdecryptedMessageLayer &_decryptedMessageLayer() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDdecryptedMessageLayer*)data; + } + const MTPDdecryptedMessageLayer &c_decryptedMessageLayer() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDdecryptedMessageLayer*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_decryptedMessageLayer); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPdecryptedMessageLayer(MTPDdecryptedMessageLayer *_data); + + friend MTPdecryptedMessageLayer MTP_decryptedMessageLayer(MTPint _layer, const MTPDecryptedMessage &_message); +}; +typedef MTPBoxed MTPDecryptedMessageLayer; + +class MTPdecryptedMessage : private mtpDataOwner { +public: + MTPdecryptedMessage() : mtpDataOwner(0), _type(0) { + } + MTPdecryptedMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDdecryptedMessage &_decryptedMessage() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessage) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessage); + split(); + return *(MTPDdecryptedMessage*)data; + } + const MTPDdecryptedMessage &c_decryptedMessage() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessage) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessage); + return *(const MTPDdecryptedMessage*)data; + } + + MTPDdecryptedMessageService &_decryptedMessageService() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageService) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageService); + split(); + return *(MTPDdecryptedMessageService*)data; + } + const MTPDdecryptedMessageService &c_decryptedMessageService() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageService) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageService); + return *(const MTPDdecryptedMessageService*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPdecryptedMessage(mtpTypeId type); + explicit MTPdecryptedMessage(MTPDdecryptedMessage *_data); + explicit MTPdecryptedMessage(MTPDdecryptedMessageService *_data); + + friend MTPdecryptedMessage MTP_decryptedMessage(const MTPlong &_random_id, const MTPbytes &_random_bytes, const MTPstring &_message, const MTPDecryptedMessageMedia &_media); + friend MTPdecryptedMessage MTP_decryptedMessageService(const MTPlong &_random_id, const MTPbytes &_random_bytes, const MTPDecryptedMessageAction &_action); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPDecryptedMessage; + +class MTPdecryptedMessageMedia : private mtpDataOwner { +public: + MTPdecryptedMessageMedia() : mtpDataOwner(0), _type(0) { + } + MTPdecryptedMessageMedia(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDdecryptedMessageMediaPhoto &_decryptedMessageMediaPhoto() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageMediaPhoto) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageMediaPhoto); + split(); + return *(MTPDdecryptedMessageMediaPhoto*)data; + } + const MTPDdecryptedMessageMediaPhoto &c_decryptedMessageMediaPhoto() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageMediaPhoto) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageMediaPhoto); + return *(const MTPDdecryptedMessageMediaPhoto*)data; + } + + MTPDdecryptedMessageMediaVideo &_decryptedMessageMediaVideo() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageMediaVideo) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageMediaVideo); + split(); + return *(MTPDdecryptedMessageMediaVideo*)data; + } + const MTPDdecryptedMessageMediaVideo &c_decryptedMessageMediaVideo() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageMediaVideo) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageMediaVideo); + return *(const MTPDdecryptedMessageMediaVideo*)data; + } + + MTPDdecryptedMessageMediaGeoPoint &_decryptedMessageMediaGeoPoint() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageMediaGeoPoint) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageMediaGeoPoint); + split(); + return *(MTPDdecryptedMessageMediaGeoPoint*)data; + } + const MTPDdecryptedMessageMediaGeoPoint &c_decryptedMessageMediaGeoPoint() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageMediaGeoPoint) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageMediaGeoPoint); + return *(const MTPDdecryptedMessageMediaGeoPoint*)data; + } + + MTPDdecryptedMessageMediaContact &_decryptedMessageMediaContact() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageMediaContact) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageMediaContact); + split(); + return *(MTPDdecryptedMessageMediaContact*)data; + } + const MTPDdecryptedMessageMediaContact &c_decryptedMessageMediaContact() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageMediaContact) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageMediaContact); + return *(const MTPDdecryptedMessageMediaContact*)data; + } + + MTPDdecryptedMessageMediaDocument &_decryptedMessageMediaDocument() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageMediaDocument) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageMediaDocument); + split(); + return *(MTPDdecryptedMessageMediaDocument*)data; + } + const MTPDdecryptedMessageMediaDocument &c_decryptedMessageMediaDocument() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageMediaDocument) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageMediaDocument); + return *(const MTPDdecryptedMessageMediaDocument*)data; + } + + MTPDdecryptedMessageMediaAudio &_decryptedMessageMediaAudio() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageMediaAudio) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageMediaAudio); + split(); + return *(MTPDdecryptedMessageMediaAudio*)data; + } + const MTPDdecryptedMessageMediaAudio &c_decryptedMessageMediaAudio() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageMediaAudio) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageMediaAudio); + return *(const MTPDdecryptedMessageMediaAudio*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPdecryptedMessageMedia(mtpTypeId type); + explicit MTPdecryptedMessageMedia(MTPDdecryptedMessageMediaPhoto *_data); + explicit MTPdecryptedMessageMedia(MTPDdecryptedMessageMediaVideo *_data); + explicit MTPdecryptedMessageMedia(MTPDdecryptedMessageMediaGeoPoint *_data); + explicit MTPdecryptedMessageMedia(MTPDdecryptedMessageMediaContact *_data); + explicit MTPdecryptedMessageMedia(MTPDdecryptedMessageMediaDocument *_data); + explicit MTPdecryptedMessageMedia(MTPDdecryptedMessageMediaAudio *_data); + + friend MTPdecryptedMessageMedia MTP_decryptedMessageMediaEmpty(); + friend MTPdecryptedMessageMedia MTP_decryptedMessageMediaPhoto(const MTPbytes &_thumb, MTPint _thumb_w, MTPint _thumb_h, MTPint _w, MTPint _h, MTPint _size, const MTPbytes &_key, const MTPbytes &_iv); + friend MTPdecryptedMessageMedia MTP_decryptedMessageMediaVideo(const MTPbytes &_thumb, MTPint _thumb_w, MTPint _thumb_h, MTPint _duration, const MTPstring &_mime_type, MTPint _w, MTPint _h, MTPint _size, const MTPbytes &_key, const MTPbytes &_iv); + friend MTPdecryptedMessageMedia MTP_decryptedMessageMediaGeoPoint(const MTPdouble &_lat, const MTPdouble &_long); + friend MTPdecryptedMessageMedia MTP_decryptedMessageMediaContact(const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name, MTPint _user_id); + friend MTPdecryptedMessageMedia MTP_decryptedMessageMediaDocument(const MTPbytes &_thumb, MTPint _thumb_w, MTPint _thumb_h, const MTPstring &_file_name, const MTPstring &_mime_type, MTPint _size, const MTPbytes &_key, const MTPbytes &_iv); + friend MTPdecryptedMessageMedia MTP_decryptedMessageMediaAudio(MTPint _duration, const MTPstring &_mime_type, MTPint _size, const MTPbytes &_key, const MTPbytes &_iv); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPDecryptedMessageMedia; + +class MTPdecryptedMessageAction : private mtpDataOwner { +public: + MTPdecryptedMessageAction() : mtpDataOwner(0), _type(0) { + } + MTPdecryptedMessageAction(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDdecryptedMessageActionSetMessageTTL &_decryptedMessageActionSetMessageTTL() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageActionSetMessageTTL) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageActionSetMessageTTL); + split(); + return *(MTPDdecryptedMessageActionSetMessageTTL*)data; + } + const MTPDdecryptedMessageActionSetMessageTTL &c_decryptedMessageActionSetMessageTTL() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageActionSetMessageTTL) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageActionSetMessageTTL); + return *(const MTPDdecryptedMessageActionSetMessageTTL*)data; + } + + MTPDdecryptedMessageActionReadMessages &_decryptedMessageActionReadMessages() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageActionReadMessages) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageActionReadMessages); + split(); + return *(MTPDdecryptedMessageActionReadMessages*)data; + } + const MTPDdecryptedMessageActionReadMessages &c_decryptedMessageActionReadMessages() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageActionReadMessages) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageActionReadMessages); + return *(const MTPDdecryptedMessageActionReadMessages*)data; + } + + MTPDdecryptedMessageActionDeleteMessages &_decryptedMessageActionDeleteMessages() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageActionDeleteMessages) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageActionDeleteMessages); + split(); + return *(MTPDdecryptedMessageActionDeleteMessages*)data; + } + const MTPDdecryptedMessageActionDeleteMessages &c_decryptedMessageActionDeleteMessages() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageActionDeleteMessages) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageActionDeleteMessages); + return *(const MTPDdecryptedMessageActionDeleteMessages*)data; + } + + MTPDdecryptedMessageActionScreenshotMessages &_decryptedMessageActionScreenshotMessages() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageActionScreenshotMessages) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageActionScreenshotMessages); + split(); + return *(MTPDdecryptedMessageActionScreenshotMessages*)data; + } + const MTPDdecryptedMessageActionScreenshotMessages &c_decryptedMessageActionScreenshotMessages() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageActionScreenshotMessages) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageActionScreenshotMessages); + return *(const MTPDdecryptedMessageActionScreenshotMessages*)data; + } + + MTPDdecryptedMessageActionNotifyLayer &_decryptedMessageActionNotifyLayer() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageActionNotifyLayer) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageActionNotifyLayer); + split(); + return *(MTPDdecryptedMessageActionNotifyLayer*)data; + } + const MTPDdecryptedMessageActionNotifyLayer &c_decryptedMessageActionNotifyLayer() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_decryptedMessageActionNotifyLayer) throw mtpErrorWrongTypeId(_type, mtpc_decryptedMessageActionNotifyLayer); + return *(const MTPDdecryptedMessageActionNotifyLayer*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPdecryptedMessageAction(mtpTypeId type); + explicit MTPdecryptedMessageAction(MTPDdecryptedMessageActionSetMessageTTL *_data); + explicit MTPdecryptedMessageAction(MTPDdecryptedMessageActionReadMessages *_data); + explicit MTPdecryptedMessageAction(MTPDdecryptedMessageActionDeleteMessages *_data); + explicit MTPdecryptedMessageAction(MTPDdecryptedMessageActionScreenshotMessages *_data); + explicit MTPdecryptedMessageAction(MTPDdecryptedMessageActionNotifyLayer *_data); + + friend MTPdecryptedMessageAction MTP_decryptedMessageActionSetMessageTTL(MTPint _ttl_seconds); + friend MTPdecryptedMessageAction MTP_decryptedMessageActionReadMessages(const MTPVector &_random_ids); + friend MTPdecryptedMessageAction MTP_decryptedMessageActionDeleteMessages(const MTPVector &_random_ids); + friend MTPdecryptedMessageAction MTP_decryptedMessageActionScreenshotMessages(const MTPVector &_random_ids); + friend MTPdecryptedMessageAction MTP_decryptedMessageActionFlushHistory(); + friend MTPdecryptedMessageAction MTP_decryptedMessageActionNotifyLayer(MTPint _layer); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPDecryptedMessageAction; + +class MTPmessages_dhConfig : private mtpDataOwner { +public: + MTPmessages_dhConfig() : mtpDataOwner(0), _type(0) { + } + MTPmessages_dhConfig(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessages_dhConfigNotModified &_messages_dhConfigNotModified() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_dhConfigNotModified) throw mtpErrorWrongTypeId(_type, mtpc_messages_dhConfigNotModified); + split(); + return *(MTPDmessages_dhConfigNotModified*)data; + } + const MTPDmessages_dhConfigNotModified &c_messages_dhConfigNotModified() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_dhConfigNotModified) throw mtpErrorWrongTypeId(_type, mtpc_messages_dhConfigNotModified); + return *(const MTPDmessages_dhConfigNotModified*)data; + } + + MTPDmessages_dhConfig &_messages_dhConfig() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_dhConfig) throw mtpErrorWrongTypeId(_type, mtpc_messages_dhConfig); + split(); + return *(MTPDmessages_dhConfig*)data; + } + const MTPDmessages_dhConfig &c_messages_dhConfig() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_dhConfig) throw mtpErrorWrongTypeId(_type, mtpc_messages_dhConfig); + return *(const MTPDmessages_dhConfig*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_dhConfig(mtpTypeId type); + explicit MTPmessages_dhConfig(MTPDmessages_dhConfigNotModified *_data); + explicit MTPmessages_dhConfig(MTPDmessages_dhConfig *_data); + + friend MTPmessages_dhConfig MTP_messages_dhConfigNotModified(const MTPbytes &_random); + friend MTPmessages_dhConfig MTP_messages_dhConfig(MTPint _g, const MTPbytes &_p, MTPint _version, const MTPbytes &_random); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPmessages_DhConfig; + +class MTPmessages_sentEncryptedMessage : private mtpDataOwner { +public: + MTPmessages_sentEncryptedMessage() : mtpDataOwner(0), _type(0) { + } + MTPmessages_sentEncryptedMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessages_sentEncryptedMessage &_messages_sentEncryptedMessage() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_sentEncryptedMessage) throw mtpErrorWrongTypeId(_type, mtpc_messages_sentEncryptedMessage); + split(); + return *(MTPDmessages_sentEncryptedMessage*)data; + } + const MTPDmessages_sentEncryptedMessage &c_messages_sentEncryptedMessage() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_sentEncryptedMessage) throw mtpErrorWrongTypeId(_type, mtpc_messages_sentEncryptedMessage); + return *(const MTPDmessages_sentEncryptedMessage*)data; + } + + MTPDmessages_sentEncryptedFile &_messages_sentEncryptedFile() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_sentEncryptedFile) throw mtpErrorWrongTypeId(_type, mtpc_messages_sentEncryptedFile); + split(); + return *(MTPDmessages_sentEncryptedFile*)data; + } + const MTPDmessages_sentEncryptedFile &c_messages_sentEncryptedFile() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_sentEncryptedFile) throw mtpErrorWrongTypeId(_type, mtpc_messages_sentEncryptedFile); + return *(const MTPDmessages_sentEncryptedFile*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_sentEncryptedMessage(mtpTypeId type); + explicit MTPmessages_sentEncryptedMessage(MTPDmessages_sentEncryptedMessage *_data); + explicit MTPmessages_sentEncryptedMessage(MTPDmessages_sentEncryptedFile *_data); + + friend MTPmessages_sentEncryptedMessage MTP_messages_sentEncryptedMessage(MTPint _date); + friend MTPmessages_sentEncryptedMessage MTP_messages_sentEncryptedFile(MTPint _date, const MTPEncryptedFile &_file); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPmessages_SentEncryptedMessage; + +class MTPinputAudio : private mtpDataOwner { +public: + MTPinputAudio() : mtpDataOwner(0), _type(0) { + } + MTPinputAudio(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputAudio &_inputAudio() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputAudio) throw mtpErrorWrongTypeId(_type, mtpc_inputAudio); + split(); + return *(MTPDinputAudio*)data; + } + const MTPDinputAudio &c_inputAudio() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputAudio) throw mtpErrorWrongTypeId(_type, mtpc_inputAudio); + return *(const MTPDinputAudio*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputAudio(mtpTypeId type); + explicit MTPinputAudio(MTPDinputAudio *_data); + + friend MTPinputAudio MTP_inputAudioEmpty(); + friend MTPinputAudio MTP_inputAudio(const MTPlong &_id, const MTPlong &_access_hash); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputAudio; + +class MTPinputDocument : private mtpDataOwner { +public: + MTPinputDocument() : mtpDataOwner(0), _type(0) { + } + MTPinputDocument(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputDocument &_inputDocument() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputDocument) throw mtpErrorWrongTypeId(_type, mtpc_inputDocument); + split(); + return *(MTPDinputDocument*)data; + } + const MTPDinputDocument &c_inputDocument() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputDocument) throw mtpErrorWrongTypeId(_type, mtpc_inputDocument); + return *(const MTPDinputDocument*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputDocument(mtpTypeId type); + explicit MTPinputDocument(MTPDinputDocument *_data); + + friend MTPinputDocument MTP_inputDocumentEmpty(); + friend MTPinputDocument MTP_inputDocument(const MTPlong &_id, const MTPlong &_access_hash); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputDocument; + +class MTPaudio : private mtpDataOwner { +public: + MTPaudio() : mtpDataOwner(0), _type(0) { + } + MTPaudio(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDaudioEmpty &_audioEmpty() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_audioEmpty) throw mtpErrorWrongTypeId(_type, mtpc_audioEmpty); + split(); + return *(MTPDaudioEmpty*)data; + } + const MTPDaudioEmpty &c_audioEmpty() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_audioEmpty) throw mtpErrorWrongTypeId(_type, mtpc_audioEmpty); + return *(const MTPDaudioEmpty*)data; + } + + MTPDaudio &_audio() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_audio) throw mtpErrorWrongTypeId(_type, mtpc_audio); + split(); + return *(MTPDaudio*)data; + } + const MTPDaudio &c_audio() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_audio) throw mtpErrorWrongTypeId(_type, mtpc_audio); + return *(const MTPDaudio*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPaudio(mtpTypeId type); + explicit MTPaudio(MTPDaudioEmpty *_data); + explicit MTPaudio(MTPDaudio *_data); + + friend MTPaudio MTP_audioEmpty(const MTPlong &_id); + friend MTPaudio MTP_audio(const MTPlong &_id, const MTPlong &_access_hash, MTPint _user_id, MTPint _date, MTPint _duration, const MTPstring &_mime_type, MTPint _size, MTPint _dc_id); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPAudio; + +class MTPdocument : private mtpDataOwner { +public: + MTPdocument() : mtpDataOwner(0), _type(0) { + } + MTPdocument(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDdocumentEmpty &_documentEmpty() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_documentEmpty) throw mtpErrorWrongTypeId(_type, mtpc_documentEmpty); + split(); + return *(MTPDdocumentEmpty*)data; + } + const MTPDdocumentEmpty &c_documentEmpty() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_documentEmpty) throw mtpErrorWrongTypeId(_type, mtpc_documentEmpty); + return *(const MTPDdocumentEmpty*)data; + } + + MTPDdocument &_document() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_document) throw mtpErrorWrongTypeId(_type, mtpc_document); + split(); + return *(MTPDdocument*)data; + } + const MTPDdocument &c_document() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_document) throw mtpErrorWrongTypeId(_type, mtpc_document); + return *(const MTPDdocument*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPdocument(mtpTypeId type); + explicit MTPdocument(MTPDdocumentEmpty *_data); + explicit MTPdocument(MTPDdocument *_data); + + friend MTPdocument MTP_documentEmpty(const MTPlong &_id); + friend MTPdocument MTP_document(const MTPlong &_id, const MTPlong &_access_hash, MTPint _user_id, MTPint _date, const MTPstring &_file_name, const MTPstring &_mime_type, MTPint _size, const MTPPhotoSize &_thumb, MTPint _dc_id); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPDocument; + +class MTPhelp_support : private mtpDataOwner { +public: + MTPhelp_support(); + MTPhelp_support(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_support) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDhelp_support &_help_support() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDhelp_support*)data; + } + const MTPDhelp_support &c_help_support() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDhelp_support*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_support); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPhelp_support(MTPDhelp_support *_data); + + friend MTPhelp_support MTP_help_support(const MTPstring &_phone_number, const MTPUser &_user); +}; +typedef MTPBoxed MTPhelp_Support; + +class MTPnotifyPeer : private mtpDataOwner { +public: + MTPnotifyPeer() : mtpDataOwner(0), _type(0) { + } + MTPnotifyPeer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDnotifyPeer &_notifyPeer() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_notifyPeer) throw mtpErrorWrongTypeId(_type, mtpc_notifyPeer); + split(); + return *(MTPDnotifyPeer*)data; + } + const MTPDnotifyPeer &c_notifyPeer() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_notifyPeer) throw mtpErrorWrongTypeId(_type, mtpc_notifyPeer); + return *(const MTPDnotifyPeer*)data; + } + + uint32 size() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPnotifyPeer(mtpTypeId type); + explicit MTPnotifyPeer(MTPDnotifyPeer *_data); + + friend MTPnotifyPeer MTP_notifyPeer(const MTPPeer &_peer); + friend MTPnotifyPeer MTP_notifyUsers(); + friend MTPnotifyPeer MTP_notifyChats(); + friend MTPnotifyPeer MTP_notifyAll(); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPNotifyPeer; + +// Type constructors with data + +class MTPDresPQ : public mtpDataImpl { +public: + MTPDresPQ() { + } + MTPDresPQ(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPstring &_pq, const MTPVector &_server_public_key_fingerprints) : vnonce(_nonce), vserver_nonce(_server_nonce), vpq(_pq), vserver_public_key_fingerprints(_server_public_key_fingerprints) { + } + + MTPint128 vnonce; + MTPint128 vserver_nonce; + MTPstring vpq; + MTPVector vserver_public_key_fingerprints; +}; + +class MTPDp_q_inner_data : public mtpDataImpl { +public: + MTPDp_q_inner_data() { + } + MTPDp_q_inner_data(const MTPstring &_pq, const MTPstring &_p, const MTPstring &_q, const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint256 &_new_nonce) : vpq(_pq), vp(_p), vq(_q), vnonce(_nonce), vserver_nonce(_server_nonce), vnew_nonce(_new_nonce) { + } + + MTPstring vpq; + MTPstring vp; + MTPstring vq; + MTPint128 vnonce; + MTPint128 vserver_nonce; + MTPint256 vnew_nonce; +}; + +class MTPDserver_DH_params_fail : public mtpDataImpl { +public: + MTPDserver_DH_params_fail() { + } + MTPDserver_DH_params_fail(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint128 &_new_nonce_hash) : vnonce(_nonce), vserver_nonce(_server_nonce), vnew_nonce_hash(_new_nonce_hash) { + } + + MTPint128 vnonce; + MTPint128 vserver_nonce; + MTPint128 vnew_nonce_hash; +}; + +class MTPDserver_DH_params_ok : public mtpDataImpl { +public: + MTPDserver_DH_params_ok() { + } + MTPDserver_DH_params_ok(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPstring &_encrypted_answer) : vnonce(_nonce), vserver_nonce(_server_nonce), vencrypted_answer(_encrypted_answer) { + } + + MTPint128 vnonce; + MTPint128 vserver_nonce; + MTPstring vencrypted_answer; +}; + +class MTPDserver_DH_inner_data : public mtpDataImpl { +public: + MTPDserver_DH_inner_data() { + } + MTPDserver_DH_inner_data(const MTPint128 &_nonce, const MTPint128 &_server_nonce, MTPint _g, const MTPstring &_dh_prime, const MTPstring &_g_a, MTPint _server_time) : vnonce(_nonce), vserver_nonce(_server_nonce), vg(_g), vdh_prime(_dh_prime), vg_a(_g_a), vserver_time(_server_time) { + } + + MTPint128 vnonce; + MTPint128 vserver_nonce; + MTPint vg; + MTPstring vdh_prime; + MTPstring vg_a; + MTPint vserver_time; +}; + +class MTPDclient_DH_inner_data : public mtpDataImpl { +public: + MTPDclient_DH_inner_data() { + } + MTPDclient_DH_inner_data(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPlong &_retry_id, const MTPstring &_g_b) : vnonce(_nonce), vserver_nonce(_server_nonce), vretry_id(_retry_id), vg_b(_g_b) { + } + + MTPint128 vnonce; + MTPint128 vserver_nonce; + MTPlong vretry_id; + MTPstring vg_b; +}; + +class MTPDdh_gen_ok : public mtpDataImpl { +public: + MTPDdh_gen_ok() { + } + MTPDdh_gen_ok(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint128 &_new_nonce_hash1) : vnonce(_nonce), vserver_nonce(_server_nonce), vnew_nonce_hash1(_new_nonce_hash1) { + } + + MTPint128 vnonce; + MTPint128 vserver_nonce; + MTPint128 vnew_nonce_hash1; +}; + +class MTPDdh_gen_retry : public mtpDataImpl { +public: + MTPDdh_gen_retry() { + } + MTPDdh_gen_retry(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint128 &_new_nonce_hash2) : vnonce(_nonce), vserver_nonce(_server_nonce), vnew_nonce_hash2(_new_nonce_hash2) { + } + + MTPint128 vnonce; + MTPint128 vserver_nonce; + MTPint128 vnew_nonce_hash2; +}; + +class MTPDdh_gen_fail : public mtpDataImpl { +public: + MTPDdh_gen_fail() { + } + MTPDdh_gen_fail(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint128 &_new_nonce_hash3) : vnonce(_nonce), vserver_nonce(_server_nonce), vnew_nonce_hash3(_new_nonce_hash3) { + } + + MTPint128 vnonce; + MTPint128 vserver_nonce; + MTPint128 vnew_nonce_hash3; +}; + +class MTPDmsgs_ack : public mtpDataImpl { +public: + MTPDmsgs_ack() { + } + MTPDmsgs_ack(const MTPVector &_msg_ids) : vmsg_ids(_msg_ids) { + } + + MTPVector vmsg_ids; +}; + +class MTPDbad_msg_notification : public mtpDataImpl { +public: + MTPDbad_msg_notification() { + } + MTPDbad_msg_notification(const MTPlong &_bad_msg_id, MTPint _bad_msg_seqno, MTPint _error_code) : vbad_msg_id(_bad_msg_id), vbad_msg_seqno(_bad_msg_seqno), verror_code(_error_code) { + } + + MTPlong vbad_msg_id; + MTPint vbad_msg_seqno; + MTPint verror_code; +}; + +class MTPDbad_server_salt : public mtpDataImpl { +public: + MTPDbad_server_salt() { + } + MTPDbad_server_salt(const MTPlong &_bad_msg_id, MTPint _bad_msg_seqno, MTPint _error_code, const MTPlong &_new_server_salt) : vbad_msg_id(_bad_msg_id), vbad_msg_seqno(_bad_msg_seqno), verror_code(_error_code), vnew_server_salt(_new_server_salt) { + } + + MTPlong vbad_msg_id; + MTPint vbad_msg_seqno; + MTPint verror_code; + MTPlong vnew_server_salt; +}; + +class MTPDmsgs_state_req : public mtpDataImpl { +public: + MTPDmsgs_state_req() { + } + MTPDmsgs_state_req(const MTPVector &_msg_ids) : vmsg_ids(_msg_ids) { + } + + MTPVector vmsg_ids; +}; + +class MTPDmsgs_state_info : public mtpDataImpl { +public: + MTPDmsgs_state_info() { + } + MTPDmsgs_state_info(const MTPlong &_req_msg_id, const MTPstring &_info) : vreq_msg_id(_req_msg_id), vinfo(_info) { + } + + MTPlong vreq_msg_id; + MTPstring vinfo; +}; + +class MTPDmsgs_all_info : public mtpDataImpl { +public: + MTPDmsgs_all_info() { + } + MTPDmsgs_all_info(const MTPVector &_msg_ids, const MTPstring &_info) : vmsg_ids(_msg_ids), vinfo(_info) { + } + + MTPVector vmsg_ids; + MTPstring vinfo; +}; + +class MTPDmsg_detailed_info : public mtpDataImpl { +public: + MTPDmsg_detailed_info() { + } + MTPDmsg_detailed_info(const MTPlong &_msg_id, const MTPlong &_answer_msg_id, MTPint _bytes, MTPint _status) : vmsg_id(_msg_id), vanswer_msg_id(_answer_msg_id), vbytes(_bytes), vstatus(_status) { + } + + MTPlong vmsg_id; + MTPlong vanswer_msg_id; + MTPint vbytes; + MTPint vstatus; +}; + +class MTPDmsg_new_detailed_info : public mtpDataImpl { +public: + MTPDmsg_new_detailed_info() { + } + MTPDmsg_new_detailed_info(const MTPlong &_answer_msg_id, MTPint _bytes, MTPint _status) : vanswer_msg_id(_answer_msg_id), vbytes(_bytes), vstatus(_status) { + } + + MTPlong vanswer_msg_id; + MTPint vbytes; + MTPint vstatus; +}; + +class MTPDmsg_resend_req : public mtpDataImpl { +public: + MTPDmsg_resend_req() { + } + MTPDmsg_resend_req(const MTPVector &_msg_ids) : vmsg_ids(_msg_ids) { + } + + MTPVector vmsg_ids; +}; + +class MTPDrpc_error : public mtpDataImpl { +public: + MTPDrpc_error() { + } + MTPDrpc_error(MTPint _error_code, const MTPstring &_error_message) : verror_code(_error_code), verror_message(_error_message) { + } + + MTPint verror_code; + MTPstring verror_message; +}; + +class MTPDrpc_answer_dropped : public mtpDataImpl { +public: + MTPDrpc_answer_dropped() { + } + MTPDrpc_answer_dropped(const MTPlong &_msg_id, MTPint _seq_no, MTPint _bytes) : vmsg_id(_msg_id), vseq_no(_seq_no), vbytes(_bytes) { + } + + MTPlong vmsg_id; + MTPint vseq_no; + MTPint vbytes; +}; + +class MTPDfuture_salt : public mtpDataImpl { +public: + MTPDfuture_salt() { + } + MTPDfuture_salt(MTPint _valid_since, MTPint _valid_until, const MTPlong &_salt) : vvalid_since(_valid_since), vvalid_until(_valid_until), vsalt(_salt) { + } + + MTPint vvalid_since; + MTPint vvalid_until; + MTPlong vsalt; +}; + +class MTPDfuture_salts : public mtpDataImpl { +public: + MTPDfuture_salts() { + } + MTPDfuture_salts(const MTPlong &_req_msg_id, MTPint _now, const MTPvector &_salts) : vreq_msg_id(_req_msg_id), vnow(_now), vsalts(_salts) { + } + + MTPlong vreq_msg_id; + MTPint vnow; + MTPvector vsalts; +}; + +class MTPDpong : public mtpDataImpl { +public: + MTPDpong() { + } + MTPDpong(const MTPlong &_msg_id, const MTPlong &_ping_id) : vmsg_id(_msg_id), vping_id(_ping_id) { + } + + MTPlong vmsg_id; + MTPlong vping_id; +}; + +class MTPDdestroy_session_ok : public mtpDataImpl { +public: + MTPDdestroy_session_ok() { + } + MTPDdestroy_session_ok(const MTPlong &_session_id) : vsession_id(_session_id) { + } + + MTPlong vsession_id; +}; + +class MTPDdestroy_session_none : public mtpDataImpl { +public: + MTPDdestroy_session_none() { + } + MTPDdestroy_session_none(const MTPlong &_session_id) : vsession_id(_session_id) { + } + + MTPlong vsession_id; +}; + +class MTPDnew_session_created : public mtpDataImpl { +public: + MTPDnew_session_created() { + } + MTPDnew_session_created(const MTPlong &_first_msg_id, const MTPlong &_unique_id, const MTPlong &_server_salt) : vfirst_msg_id(_first_msg_id), vunique_id(_unique_id), vserver_salt(_server_salt) { + } + + MTPlong vfirst_msg_id; + MTPlong vunique_id; + MTPlong vserver_salt; +}; + +class MTPDhttp_wait : public mtpDataImpl { +public: + MTPDhttp_wait() { + } + MTPDhttp_wait(MTPint _max_delay, MTPint _wait_after, MTPint _max_wait) : vmax_delay(_max_delay), vwait_after(_wait_after), vmax_wait(_max_wait) { + } + + MTPint vmax_delay; + MTPint vwait_after; + MTPint vmax_wait; +}; + +class MTPDinputPeerContact : public mtpDataImpl { +public: + MTPDinputPeerContact() { + } + MTPDinputPeerContact(MTPint _user_id) : vuser_id(_user_id) { + } + + MTPint vuser_id; +}; + +class MTPDinputPeerForeign : public mtpDataImpl { +public: + MTPDinputPeerForeign() { + } + MTPDinputPeerForeign(MTPint _user_id, const MTPlong &_access_hash) : vuser_id(_user_id), vaccess_hash(_access_hash) { + } + + MTPint vuser_id; + MTPlong vaccess_hash; +}; + +class MTPDinputPeerChat : public mtpDataImpl { +public: + MTPDinputPeerChat() { + } + MTPDinputPeerChat(MTPint _chat_id) : vchat_id(_chat_id) { + } + + MTPint vchat_id; +}; + +class MTPDinputUserContact : public mtpDataImpl { +public: + MTPDinputUserContact() { + } + MTPDinputUserContact(MTPint _user_id) : vuser_id(_user_id) { + } + + MTPint vuser_id; +}; + +class MTPDinputUserForeign : public mtpDataImpl { +public: + MTPDinputUserForeign() { + } + MTPDinputUserForeign(MTPint _user_id, const MTPlong &_access_hash) : vuser_id(_user_id), vaccess_hash(_access_hash) { + } + + MTPint vuser_id; + MTPlong vaccess_hash; +}; + +class MTPDinputPhoneContact : public mtpDataImpl { +public: + MTPDinputPhoneContact() { + } + MTPDinputPhoneContact(const MTPlong &_client_id, const MTPstring &_phone, const MTPstring &_first_name, const MTPstring &_last_name) : vclient_id(_client_id), vphone(_phone), vfirst_name(_first_name), vlast_name(_last_name) { + } + + MTPlong vclient_id; + MTPstring vphone; + MTPstring vfirst_name; + MTPstring vlast_name; +}; + +class MTPDinputFile : public mtpDataImpl { +public: + MTPDinputFile() { + } + MTPDinputFile(const MTPlong &_id, MTPint _parts, const MTPstring &_name, const MTPstring &_md5_checksum) : vid(_id), vparts(_parts), vname(_name), vmd5_checksum(_md5_checksum) { + } + + MTPlong vid; + MTPint vparts; + MTPstring vname; + MTPstring vmd5_checksum; +}; + +class MTPDinputFileBig : public mtpDataImpl { +public: + MTPDinputFileBig() { + } + MTPDinputFileBig(const MTPlong &_id, MTPint _parts, const MTPstring &_name) : vid(_id), vparts(_parts), vname(_name) { + } + + MTPlong vid; + MTPint vparts; + MTPstring vname; +}; + +class MTPDinputMediaUploadedPhoto : public mtpDataImpl { +public: + MTPDinputMediaUploadedPhoto() { + } + MTPDinputMediaUploadedPhoto(const MTPInputFile &_file) : vfile(_file) { + } + + MTPInputFile vfile; +}; + +class MTPDinputMediaPhoto : public mtpDataImpl { +public: + MTPDinputMediaPhoto() { + } + MTPDinputMediaPhoto(const MTPInputPhoto &_id) : vid(_id) { + } + + MTPInputPhoto vid; +}; + +class MTPDinputMediaGeoPoint : public mtpDataImpl { +public: + MTPDinputMediaGeoPoint() { + } + MTPDinputMediaGeoPoint(const MTPInputGeoPoint &_geo_point) : vgeo_point(_geo_point) { + } + + MTPInputGeoPoint vgeo_point; +}; + +class MTPDinputMediaContact : public mtpDataImpl { +public: + MTPDinputMediaContact() { + } + MTPDinputMediaContact(const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name) : vphone_number(_phone_number), vfirst_name(_first_name), vlast_name(_last_name) { + } + + MTPstring vphone_number; + MTPstring vfirst_name; + MTPstring vlast_name; +}; + +class MTPDinputMediaUploadedVideo : public mtpDataImpl { +public: + MTPDinputMediaUploadedVideo() { + } + MTPDinputMediaUploadedVideo(const MTPInputFile &_file, MTPint _duration, MTPint _w, MTPint _h, const MTPstring &_mime_type) : vfile(_file), vduration(_duration), vw(_w), vh(_h), vmime_type(_mime_type) { + } + + MTPInputFile vfile; + MTPint vduration; + MTPint vw; + MTPint vh; + MTPstring vmime_type; +}; + +class MTPDinputMediaUploadedThumbVideo : public mtpDataImpl { +public: + MTPDinputMediaUploadedThumbVideo() { + } + MTPDinputMediaUploadedThumbVideo(const MTPInputFile &_file, const MTPInputFile &_thumb, MTPint _duration, MTPint _w, MTPint _h, const MTPstring &_mime_type) : vfile(_file), vthumb(_thumb), vduration(_duration), vw(_w), vh(_h), vmime_type(_mime_type) { + } + + MTPInputFile vfile; + MTPInputFile vthumb; + MTPint vduration; + MTPint vw; + MTPint vh; + MTPstring vmime_type; +}; + +class MTPDinputMediaVideo : public mtpDataImpl { +public: + MTPDinputMediaVideo() { + } + MTPDinputMediaVideo(const MTPInputVideo &_id) : vid(_id) { + } + + MTPInputVideo vid; +}; + +class MTPDinputMediaUploadedAudio : public mtpDataImpl { +public: + MTPDinputMediaUploadedAudio() { + } + MTPDinputMediaUploadedAudio(const MTPInputFile &_file, MTPint _duration, const MTPstring &_mime_type) : vfile(_file), vduration(_duration), vmime_type(_mime_type) { + } + + MTPInputFile vfile; + MTPint vduration; + MTPstring vmime_type; +}; + +class MTPDinputMediaAudio : public mtpDataImpl { +public: + MTPDinputMediaAudio() { + } + MTPDinputMediaAudio(const MTPInputAudio &_id) : vid(_id) { + } + + MTPInputAudio vid; +}; + +class MTPDinputMediaUploadedDocument : public mtpDataImpl { +public: + MTPDinputMediaUploadedDocument() { + } + MTPDinputMediaUploadedDocument(const MTPInputFile &_file, const MTPstring &_file_name, const MTPstring &_mime_type) : vfile(_file), vfile_name(_file_name), vmime_type(_mime_type) { + } + + MTPInputFile vfile; + MTPstring vfile_name; + MTPstring vmime_type; +}; + +class MTPDinputMediaUploadedThumbDocument : public mtpDataImpl { +public: + MTPDinputMediaUploadedThumbDocument() { + } + MTPDinputMediaUploadedThumbDocument(const MTPInputFile &_file, const MTPInputFile &_thumb, const MTPstring &_file_name, const MTPstring &_mime_type) : vfile(_file), vthumb(_thumb), vfile_name(_file_name), vmime_type(_mime_type) { + } + + MTPInputFile vfile; + MTPInputFile vthumb; + MTPstring vfile_name; + MTPstring vmime_type; +}; + +class MTPDinputMediaDocument : public mtpDataImpl { +public: + MTPDinputMediaDocument() { + } + MTPDinputMediaDocument(const MTPInputDocument &_id) : vid(_id) { + } + + MTPInputDocument vid; +}; + +class MTPDinputChatUploadedPhoto : public mtpDataImpl { +public: + MTPDinputChatUploadedPhoto() { + } + MTPDinputChatUploadedPhoto(const MTPInputFile &_file, const MTPInputPhotoCrop &_crop) : vfile(_file), vcrop(_crop) { + } + + MTPInputFile vfile; + MTPInputPhotoCrop vcrop; +}; + +class MTPDinputChatPhoto : public mtpDataImpl { +public: + MTPDinputChatPhoto() { + } + MTPDinputChatPhoto(const MTPInputPhoto &_id, const MTPInputPhotoCrop &_crop) : vid(_id), vcrop(_crop) { + } + + MTPInputPhoto vid; + MTPInputPhotoCrop vcrop; +}; + +class MTPDinputGeoPoint : public mtpDataImpl { +public: + MTPDinputGeoPoint() { + } + MTPDinputGeoPoint(const MTPdouble &_lat, const MTPdouble &_long) : vlat(_lat), vlong(_long) { + } + + MTPdouble vlat; + MTPdouble vlong; +}; + +class MTPDinputPhoto : public mtpDataImpl { +public: + MTPDinputPhoto() { + } + MTPDinputPhoto(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) { + } + + MTPlong vid; + MTPlong vaccess_hash; +}; + +class MTPDinputVideo : public mtpDataImpl { +public: + MTPDinputVideo() { + } + MTPDinputVideo(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) { + } + + MTPlong vid; + MTPlong vaccess_hash; +}; + +class MTPDinputFileLocation : public mtpDataImpl { +public: + MTPDinputFileLocation() { + } + MTPDinputFileLocation(const MTPlong &_volume_id, MTPint _local_id, const MTPlong &_secret) : vvolume_id(_volume_id), vlocal_id(_local_id), vsecret(_secret) { + } + + MTPlong vvolume_id; + MTPint vlocal_id; + MTPlong vsecret; +}; + +class MTPDinputVideoFileLocation : public mtpDataImpl { +public: + MTPDinputVideoFileLocation() { + } + MTPDinputVideoFileLocation(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) { + } + + MTPlong vid; + MTPlong vaccess_hash; +}; + +class MTPDinputEncryptedFileLocation : public mtpDataImpl { +public: + MTPDinputEncryptedFileLocation() { + } + MTPDinputEncryptedFileLocation(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) { + } + + MTPlong vid; + MTPlong vaccess_hash; +}; + +class MTPDinputAudioFileLocation : public mtpDataImpl { +public: + MTPDinputAudioFileLocation() { + } + MTPDinputAudioFileLocation(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) { + } + + MTPlong vid; + MTPlong vaccess_hash; +}; + +class MTPDinputDocumentFileLocation : public mtpDataImpl { +public: + MTPDinputDocumentFileLocation() { + } + MTPDinputDocumentFileLocation(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) { + } + + MTPlong vid; + MTPlong vaccess_hash; +}; + +class MTPDinputPhotoCrop : public mtpDataImpl { +public: + MTPDinputPhotoCrop() { + } + MTPDinputPhotoCrop(const MTPdouble &_crop_left, const MTPdouble &_crop_top, const MTPdouble &_crop_width) : vcrop_left(_crop_left), vcrop_top(_crop_top), vcrop_width(_crop_width) { + } + + MTPdouble vcrop_left; + MTPdouble vcrop_top; + MTPdouble vcrop_width; +}; + +class MTPDinputAppEvent : public mtpDataImpl { +public: + MTPDinputAppEvent() { + } + MTPDinputAppEvent(const MTPdouble &_time, const MTPstring &_type, const MTPlong &_peer, const MTPstring &_data) : vtime(_time), vtype(_type), vpeer(_peer), vdata(_data) { + } + + MTPdouble vtime; + MTPstring vtype; + MTPlong vpeer; + MTPstring vdata; +}; + +class MTPDpeerUser : public mtpDataImpl { +public: + MTPDpeerUser() { + } + MTPDpeerUser(MTPint _user_id) : vuser_id(_user_id) { + } + + MTPint vuser_id; +}; + +class MTPDpeerChat : public mtpDataImpl { +public: + MTPDpeerChat() { + } + MTPDpeerChat(MTPint _chat_id) : vchat_id(_chat_id) { + } + + MTPint vchat_id; +}; + +class MTPDfileLocationUnavailable : public mtpDataImpl { +public: + MTPDfileLocationUnavailable() { + } + MTPDfileLocationUnavailable(const MTPlong &_volume_id, MTPint _local_id, const MTPlong &_secret) : vvolume_id(_volume_id), vlocal_id(_local_id), vsecret(_secret) { + } + + MTPlong vvolume_id; + MTPint vlocal_id; + MTPlong vsecret; +}; + +class MTPDfileLocation : public mtpDataImpl { +public: + MTPDfileLocation() { + } + MTPDfileLocation(MTPint _dc_id, const MTPlong &_volume_id, MTPint _local_id, const MTPlong &_secret) : vdc_id(_dc_id), vvolume_id(_volume_id), vlocal_id(_local_id), vsecret(_secret) { + } + + MTPint vdc_id; + MTPlong vvolume_id; + MTPint vlocal_id; + MTPlong vsecret; +}; + +class MTPDuserEmpty : public mtpDataImpl { +public: + MTPDuserEmpty() { + } + MTPDuserEmpty(MTPint _id) : vid(_id) { + } + + MTPint vid; +}; + +class MTPDuserSelf : public mtpDataImpl { +public: + MTPDuserSelf() { + } + MTPDuserSelf(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name, const MTPstring &_phone, const MTPUserProfilePhoto &_photo, const MTPUserStatus &_status, MTPBool _inactive) : vid(_id), vfirst_name(_first_name), vlast_name(_last_name), vphone(_phone), vphoto(_photo), vstatus(_status), vinactive(_inactive) { + } + + MTPint vid; + MTPstring vfirst_name; + MTPstring vlast_name; + MTPstring vphone; + MTPUserProfilePhoto vphoto; + MTPUserStatus vstatus; + MTPBool vinactive; +}; + +class MTPDuserContact : public mtpDataImpl { +public: + MTPDuserContact() { + } + MTPDuserContact(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name, const MTPlong &_access_hash, const MTPstring &_phone, const MTPUserProfilePhoto &_photo, const MTPUserStatus &_status) : vid(_id), vfirst_name(_first_name), vlast_name(_last_name), vaccess_hash(_access_hash), vphone(_phone), vphoto(_photo), vstatus(_status) { + } + + MTPint vid; + MTPstring vfirst_name; + MTPstring vlast_name; + MTPlong vaccess_hash; + MTPstring vphone; + MTPUserProfilePhoto vphoto; + MTPUserStatus vstatus; +}; + +class MTPDuserRequest : public mtpDataImpl { +public: + MTPDuserRequest() { + } + MTPDuserRequest(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name, const MTPlong &_access_hash, const MTPstring &_phone, const MTPUserProfilePhoto &_photo, const MTPUserStatus &_status) : vid(_id), vfirst_name(_first_name), vlast_name(_last_name), vaccess_hash(_access_hash), vphone(_phone), vphoto(_photo), vstatus(_status) { + } + + MTPint vid; + MTPstring vfirst_name; + MTPstring vlast_name; + MTPlong vaccess_hash; + MTPstring vphone; + MTPUserProfilePhoto vphoto; + MTPUserStatus vstatus; +}; + +class MTPDuserForeign : public mtpDataImpl { +public: + MTPDuserForeign() { + } + MTPDuserForeign(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name, const MTPlong &_access_hash, const MTPUserProfilePhoto &_photo, const MTPUserStatus &_status) : vid(_id), vfirst_name(_first_name), vlast_name(_last_name), vaccess_hash(_access_hash), vphoto(_photo), vstatus(_status) { + } + + MTPint vid; + MTPstring vfirst_name; + MTPstring vlast_name; + MTPlong vaccess_hash; + MTPUserProfilePhoto vphoto; + MTPUserStatus vstatus; +}; + +class MTPDuserDeleted : public mtpDataImpl { +public: + MTPDuserDeleted() { + } + MTPDuserDeleted(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name) : vid(_id), vfirst_name(_first_name), vlast_name(_last_name) { + } + + MTPint vid; + MTPstring vfirst_name; + MTPstring vlast_name; +}; + +class MTPDuserProfilePhoto : public mtpDataImpl { +public: + MTPDuserProfilePhoto() { + } + MTPDuserProfilePhoto(const MTPlong &_photo_id, const MTPFileLocation &_photo_small, const MTPFileLocation &_photo_big) : vphoto_id(_photo_id), vphoto_small(_photo_small), vphoto_big(_photo_big) { + } + + MTPlong vphoto_id; + MTPFileLocation vphoto_small; + MTPFileLocation vphoto_big; +}; + +class MTPDuserStatusOnline : public mtpDataImpl { +public: + MTPDuserStatusOnline() { + } + MTPDuserStatusOnline(MTPint _expires) : vexpires(_expires) { + } + + MTPint vexpires; +}; + +class MTPDuserStatusOffline : public mtpDataImpl { +public: + MTPDuserStatusOffline() { + } + MTPDuserStatusOffline(MTPint _was_online) : vwas_online(_was_online) { + } + + MTPint vwas_online; +}; + +class MTPDchatEmpty : public mtpDataImpl { +public: + MTPDchatEmpty() { + } + MTPDchatEmpty(MTPint _id) : vid(_id) { + } + + MTPint vid; +}; + +class MTPDchat : public mtpDataImpl { +public: + MTPDchat() { + } + MTPDchat(MTPint _id, const MTPstring &_title, const MTPChatPhoto &_photo, MTPint _participants_count, MTPint _date, MTPBool _left, MTPint _version) : vid(_id), vtitle(_title), vphoto(_photo), vparticipants_count(_participants_count), vdate(_date), vleft(_left), vversion(_version) { + } + + MTPint vid; + MTPstring vtitle; + MTPChatPhoto vphoto; + MTPint vparticipants_count; + MTPint vdate; + MTPBool vleft; + MTPint vversion; +}; + +class MTPDchatForbidden : public mtpDataImpl { +public: + MTPDchatForbidden() { + } + MTPDchatForbidden(MTPint _id, const MTPstring &_title, MTPint _date) : vid(_id), vtitle(_title), vdate(_date) { + } + + MTPint vid; + MTPstring vtitle; + MTPint vdate; +}; + +class MTPDgeoChat : public mtpDataImpl { +public: + MTPDgeoChat() { + } + MTPDgeoChat(MTPint _id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_address, const MTPstring &_venue, const MTPGeoPoint &_geo, const MTPChatPhoto &_photo, MTPint _participants_count, MTPint _date, MTPBool _checked_in, MTPint _version) : vid(_id), vaccess_hash(_access_hash), vtitle(_title), vaddress(_address), vvenue(_venue), vgeo(_geo), vphoto(_photo), vparticipants_count(_participants_count), vdate(_date), vchecked_in(_checked_in), vversion(_version) { + } + + MTPint vid; + MTPlong vaccess_hash; + MTPstring vtitle; + MTPstring vaddress; + MTPstring vvenue; + MTPGeoPoint vgeo; + MTPChatPhoto vphoto; + MTPint vparticipants_count; + MTPint vdate; + MTPBool vchecked_in; + MTPint vversion; +}; + +class MTPDchatFull : public mtpDataImpl { +public: + MTPDchatFull() { + } + MTPDchatFull(MTPint _id, const MTPChatParticipants &_participants, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings) : vid(_id), vparticipants(_participants), vchat_photo(_chat_photo), vnotify_settings(_notify_settings) { + } + + MTPint vid; + MTPChatParticipants vparticipants; + MTPPhoto vchat_photo; + MTPPeerNotifySettings vnotify_settings; +}; + +class MTPDchatParticipant : public mtpDataImpl { +public: + MTPDchatParticipant() { + } + MTPDchatParticipant(MTPint _user_id, MTPint _inviter_id, MTPint _date) : vuser_id(_user_id), vinviter_id(_inviter_id), vdate(_date) { + } + + MTPint vuser_id; + MTPint vinviter_id; + MTPint vdate; +}; + +class MTPDchatParticipantsForbidden : public mtpDataImpl { +public: + MTPDchatParticipantsForbidden() { + } + MTPDchatParticipantsForbidden(MTPint _chat_id) : vchat_id(_chat_id) { + } + + MTPint vchat_id; +}; + +class MTPDchatParticipants : public mtpDataImpl { +public: + MTPDchatParticipants() { + } + MTPDchatParticipants(MTPint _chat_id, MTPint _admin_id, const MTPVector &_participants, MTPint _version) : vchat_id(_chat_id), vadmin_id(_admin_id), vparticipants(_participants), vversion(_version) { + } + + MTPint vchat_id; + MTPint vadmin_id; + MTPVector vparticipants; + MTPint vversion; +}; + +class MTPDchatPhoto : public mtpDataImpl { +public: + MTPDchatPhoto() { + } + MTPDchatPhoto(const MTPFileLocation &_photo_small, const MTPFileLocation &_photo_big) : vphoto_small(_photo_small), vphoto_big(_photo_big) { + } + + MTPFileLocation vphoto_small; + MTPFileLocation vphoto_big; +}; + +class MTPDmessageEmpty : public mtpDataImpl { +public: + MTPDmessageEmpty() { + } + MTPDmessageEmpty(MTPint _id) : vid(_id) { + } + + MTPint vid; +}; + +class MTPDmessage : public mtpDataImpl { +public: + MTPDmessage() { + } + MTPDmessage(MTPint _id, MTPint _from_id, const MTPPeer &_to_id, MTPBool _out, MTPBool _unread, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media) : vid(_id), vfrom_id(_from_id), vto_id(_to_id), vout(_out), vunread(_unread), vdate(_date), vmessage(_message), vmedia(_media) { + } + + MTPint vid; + MTPint vfrom_id; + MTPPeer vto_id; + MTPBool vout; + MTPBool vunread; + MTPint vdate; + MTPstring vmessage; + MTPMessageMedia vmedia; +}; + +class MTPDmessageForwarded : public mtpDataImpl { +public: + MTPDmessageForwarded() { + } + MTPDmessageForwarded(MTPint _id, MTPint _fwd_from_id, MTPint _fwd_date, MTPint _from_id, const MTPPeer &_to_id, MTPBool _out, MTPBool _unread, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media) : vid(_id), vfwd_from_id(_fwd_from_id), vfwd_date(_fwd_date), vfrom_id(_from_id), vto_id(_to_id), vout(_out), vunread(_unread), vdate(_date), vmessage(_message), vmedia(_media) { + } + + MTPint vid; + MTPint vfwd_from_id; + MTPint vfwd_date; + MTPint vfrom_id; + MTPPeer vto_id; + MTPBool vout; + MTPBool vunread; + MTPint vdate; + MTPstring vmessage; + MTPMessageMedia vmedia; +}; + +class MTPDmessageService : public mtpDataImpl { +public: + MTPDmessageService() { + } + MTPDmessageService(MTPint _id, MTPint _from_id, const MTPPeer &_to_id, MTPBool _out, MTPBool _unread, MTPint _date, const MTPMessageAction &_action) : vid(_id), vfrom_id(_from_id), vto_id(_to_id), vout(_out), vunread(_unread), vdate(_date), vaction(_action) { + } + + MTPint vid; + MTPint vfrom_id; + MTPPeer vto_id; + MTPBool vout; + MTPBool vunread; + MTPint vdate; + MTPMessageAction vaction; +}; + +class MTPDmessageMediaPhoto : public mtpDataImpl { +public: + MTPDmessageMediaPhoto() { + } + MTPDmessageMediaPhoto(const MTPPhoto &_photo) : vphoto(_photo) { + } + + MTPPhoto vphoto; +}; + +class MTPDmessageMediaVideo : public mtpDataImpl { +public: + MTPDmessageMediaVideo() { + } + MTPDmessageMediaVideo(const MTPVideo &_video) : vvideo(_video) { + } + + MTPVideo vvideo; +}; + +class MTPDmessageMediaGeo : public mtpDataImpl { +public: + MTPDmessageMediaGeo() { + } + MTPDmessageMediaGeo(const MTPGeoPoint &_geo) : vgeo(_geo) { + } + + MTPGeoPoint vgeo; +}; + +class MTPDmessageMediaContact : public mtpDataImpl { +public: + MTPDmessageMediaContact() { + } + MTPDmessageMediaContact(const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name, MTPint _user_id) : vphone_number(_phone_number), vfirst_name(_first_name), vlast_name(_last_name), vuser_id(_user_id) { + } + + MTPstring vphone_number; + MTPstring vfirst_name; + MTPstring vlast_name; + MTPint vuser_id; +}; + +class MTPDmessageMediaUnsupported : public mtpDataImpl { +public: + MTPDmessageMediaUnsupported() { + } + MTPDmessageMediaUnsupported(const MTPbytes &_bytes) : vbytes(_bytes) { + } + + MTPbytes vbytes; +}; + +class MTPDmessageMediaDocument : public mtpDataImpl { +public: + MTPDmessageMediaDocument() { + } + MTPDmessageMediaDocument(const MTPDocument &_document) : vdocument(_document) { + } + + MTPDocument vdocument; +}; + +class MTPDmessageMediaAudio : public mtpDataImpl { +public: + MTPDmessageMediaAudio() { + } + MTPDmessageMediaAudio(const MTPAudio &_audio) : vaudio(_audio) { + } + + MTPAudio vaudio; +}; + +class MTPDmessageActionChatCreate : public mtpDataImpl { +public: + MTPDmessageActionChatCreate() { + } + MTPDmessageActionChatCreate(const MTPstring &_title, const MTPVector &_users) : vtitle(_title), vusers(_users) { + } + + MTPstring vtitle; + MTPVector vusers; +}; + +class MTPDmessageActionChatEditTitle : public mtpDataImpl { +public: + MTPDmessageActionChatEditTitle() { + } + MTPDmessageActionChatEditTitle(const MTPstring &_title) : vtitle(_title) { + } + + MTPstring vtitle; +}; + +class MTPDmessageActionChatEditPhoto : public mtpDataImpl { +public: + MTPDmessageActionChatEditPhoto() { + } + MTPDmessageActionChatEditPhoto(const MTPPhoto &_photo) : vphoto(_photo) { + } + + MTPPhoto vphoto; +}; + +class MTPDmessageActionChatAddUser : public mtpDataImpl { +public: + MTPDmessageActionChatAddUser() { + } + MTPDmessageActionChatAddUser(MTPint _user_id) : vuser_id(_user_id) { + } + + MTPint vuser_id; +}; + +class MTPDmessageActionChatDeleteUser : public mtpDataImpl { +public: + MTPDmessageActionChatDeleteUser() { + } + MTPDmessageActionChatDeleteUser(MTPint _user_id) : vuser_id(_user_id) { + } + + MTPint vuser_id; +}; + +class MTPDmessageActionGeoChatCreate : public mtpDataImpl { +public: + MTPDmessageActionGeoChatCreate() { + } + MTPDmessageActionGeoChatCreate(const MTPstring &_title, const MTPstring &_address) : vtitle(_title), vaddress(_address) { + } + + MTPstring vtitle; + MTPstring vaddress; +}; + +class MTPDdialog : public mtpDataImpl { +public: + MTPDdialog() { + } + MTPDdialog(const MTPPeer &_peer, MTPint _top_message, MTPint _unread_count, const MTPPeerNotifySettings &_notify_settings) : vpeer(_peer), vtop_message(_top_message), vunread_count(_unread_count), vnotify_settings(_notify_settings) { + } + + MTPPeer vpeer; + MTPint vtop_message; + MTPint vunread_count; + MTPPeerNotifySettings vnotify_settings; +}; + +class MTPDphotoEmpty : public mtpDataImpl { +public: + MTPDphotoEmpty() { + } + MTPDphotoEmpty(const MTPlong &_id) : vid(_id) { + } + + MTPlong vid; +}; + +class MTPDphoto : public mtpDataImpl { +public: + MTPDphoto() { + } + MTPDphoto(const MTPlong &_id, const MTPlong &_access_hash, MTPint _user_id, MTPint _date, const MTPstring &_caption, const MTPGeoPoint &_geo, const MTPVector &_sizes) : vid(_id), vaccess_hash(_access_hash), vuser_id(_user_id), vdate(_date), vcaption(_caption), vgeo(_geo), vsizes(_sizes) { + } + + MTPlong vid; + MTPlong vaccess_hash; + MTPint vuser_id; + MTPint vdate; + MTPstring vcaption; + MTPGeoPoint vgeo; + MTPVector vsizes; +}; + +class MTPDphotoSizeEmpty : public mtpDataImpl { +public: + MTPDphotoSizeEmpty() { + } + MTPDphotoSizeEmpty(const MTPstring &_type) : vtype(_type) { + } + + MTPstring vtype; +}; + +class MTPDphotoSize : public mtpDataImpl { +public: + MTPDphotoSize() { + } + MTPDphotoSize(const MTPstring &_type, const MTPFileLocation &_location, MTPint _w, MTPint _h, MTPint _size) : vtype(_type), vlocation(_location), vw(_w), vh(_h), vsize(_size) { + } + + MTPstring vtype; + MTPFileLocation vlocation; + MTPint vw; + MTPint vh; + MTPint vsize; +}; + +class MTPDphotoCachedSize : public mtpDataImpl { +public: + MTPDphotoCachedSize() { + } + MTPDphotoCachedSize(const MTPstring &_type, const MTPFileLocation &_location, MTPint _w, MTPint _h, const MTPbytes &_bytes) : vtype(_type), vlocation(_location), vw(_w), vh(_h), vbytes(_bytes) { + } + + MTPstring vtype; + MTPFileLocation vlocation; + MTPint vw; + MTPint vh; + MTPbytes vbytes; +}; + +class MTPDvideoEmpty : public mtpDataImpl { +public: + MTPDvideoEmpty() { + } + MTPDvideoEmpty(const MTPlong &_id) : vid(_id) { + } + + MTPlong vid; +}; + +class MTPDvideo : public mtpDataImpl { +public: + MTPDvideo() { + } + MTPDvideo(const MTPlong &_id, const MTPlong &_access_hash, MTPint _user_id, MTPint _date, const MTPstring &_caption, MTPint _duration, const MTPstring &_mime_type, MTPint _size, const MTPPhotoSize &_thumb, MTPint _dc_id, MTPint _w, MTPint _h) : vid(_id), vaccess_hash(_access_hash), vuser_id(_user_id), vdate(_date), vcaption(_caption), vduration(_duration), vmime_type(_mime_type), vsize(_size), vthumb(_thumb), vdc_id(_dc_id), vw(_w), vh(_h) { + } + + MTPlong vid; + MTPlong vaccess_hash; + MTPint vuser_id; + MTPint vdate; + MTPstring vcaption; + MTPint vduration; + MTPstring vmime_type; + MTPint vsize; + MTPPhotoSize vthumb; + MTPint vdc_id; + MTPint vw; + MTPint vh; +}; + +class MTPDgeoPoint : public mtpDataImpl { +public: + MTPDgeoPoint() { + } + MTPDgeoPoint(const MTPdouble &_long, const MTPdouble &_lat) : vlong(_long), vlat(_lat) { + } + + MTPdouble vlong; + MTPdouble vlat; +}; + +class MTPDauth_checkedPhone : public mtpDataImpl { +public: + MTPDauth_checkedPhone() { + } + MTPDauth_checkedPhone(MTPBool _phone_registered, MTPBool _phone_invited) : vphone_registered(_phone_registered), vphone_invited(_phone_invited) { + } + + MTPBool vphone_registered; + MTPBool vphone_invited; +}; + +class MTPDauth_sentCode : public mtpDataImpl { +public: + MTPDauth_sentCode() { + } + MTPDauth_sentCode(MTPBool _phone_registered, const MTPstring &_phone_code_hash, MTPint _send_call_timeout, MTPBool _is_password) : vphone_registered(_phone_registered), vphone_code_hash(_phone_code_hash), vsend_call_timeout(_send_call_timeout), vis_password(_is_password) { + } + + MTPBool vphone_registered; + MTPstring vphone_code_hash; + MTPint vsend_call_timeout; + MTPBool vis_password; +}; + +class MTPDauth_authorization : public mtpDataImpl { +public: + MTPDauth_authorization() { + } + MTPDauth_authorization(MTPint _expires, const MTPUser &_user) : vexpires(_expires), vuser(_user) { + } + + MTPint vexpires; + MTPUser vuser; +}; + +class MTPDauth_exportedAuthorization : public mtpDataImpl { +public: + MTPDauth_exportedAuthorization() { + } + MTPDauth_exportedAuthorization(MTPint _id, const MTPbytes &_bytes) : vid(_id), vbytes(_bytes) { + } + + MTPint vid; + MTPbytes vbytes; +}; + +class MTPDinputNotifyPeer : public mtpDataImpl { +public: + MTPDinputNotifyPeer() { + } + MTPDinputNotifyPeer(const MTPInputPeer &_peer) : vpeer(_peer) { + } + + MTPInputPeer vpeer; +}; + +class MTPDinputNotifyGeoChatPeer : public mtpDataImpl { +public: + MTPDinputNotifyGeoChatPeer() { + } + MTPDinputNotifyGeoChatPeer(const MTPInputGeoChat &_peer) : vpeer(_peer) { + } + + MTPInputGeoChat vpeer; +}; + +class MTPDinputPeerNotifySettings : public mtpDataImpl { +public: + MTPDinputPeerNotifySettings() { + } + MTPDinputPeerNotifySettings(MTPint _mute_until, const MTPstring &_sound, MTPBool _show_previews, MTPint _events_mask) : vmute_until(_mute_until), vsound(_sound), vshow_previews(_show_previews), vevents_mask(_events_mask) { + } + + MTPint vmute_until; + MTPstring vsound; + MTPBool vshow_previews; + MTPint vevents_mask; +}; + +class MTPDpeerNotifySettings : public mtpDataImpl { +public: + MTPDpeerNotifySettings() { + } + MTPDpeerNotifySettings(MTPint _mute_until, const MTPstring &_sound, MTPBool _show_previews, MTPint _events_mask) : vmute_until(_mute_until), vsound(_sound), vshow_previews(_show_previews), vevents_mask(_events_mask) { + } + + MTPint vmute_until; + MTPstring vsound; + MTPBool vshow_previews; + MTPint vevents_mask; +}; + +class MTPDwallPaper : public mtpDataImpl { +public: + MTPDwallPaper() { + } + MTPDwallPaper(MTPint _id, const MTPstring &_title, const MTPVector &_sizes, MTPint _color) : vid(_id), vtitle(_title), vsizes(_sizes), vcolor(_color) { + } + + MTPint vid; + MTPstring vtitle; + MTPVector vsizes; + MTPint vcolor; +}; + +class MTPDwallPaperSolid : public mtpDataImpl { +public: + MTPDwallPaperSolid() { + } + MTPDwallPaperSolid(MTPint _id, const MTPstring &_title, MTPint _bg_color, MTPint _color) : vid(_id), vtitle(_title), vbg_color(_bg_color), vcolor(_color) { + } + + MTPint vid; + MTPstring vtitle; + MTPint vbg_color; + MTPint vcolor; +}; + +class MTPDuserFull : public mtpDataImpl { +public: + MTPDuserFull() { + } + MTPDuserFull(const MTPUser &_user, const MTPcontacts_Link &_link, const MTPPhoto &_profile_photo, const MTPPeerNotifySettings &_notify_settings, MTPBool _blocked, const MTPstring &_real_first_name, const MTPstring &_real_last_name) : vuser(_user), vlink(_link), vprofile_photo(_profile_photo), vnotify_settings(_notify_settings), vblocked(_blocked), vreal_first_name(_real_first_name), vreal_last_name(_real_last_name) { + } + + MTPUser vuser; + MTPcontacts_Link vlink; + MTPPhoto vprofile_photo; + MTPPeerNotifySettings vnotify_settings; + MTPBool vblocked; + MTPstring vreal_first_name; + MTPstring vreal_last_name; +}; + +class MTPDcontact : public mtpDataImpl { +public: + MTPDcontact() { + } + MTPDcontact(MTPint _user_id, MTPBool _mutual) : vuser_id(_user_id), vmutual(_mutual) { + } + + MTPint vuser_id; + MTPBool vmutual; +}; + +class MTPDimportedContact : public mtpDataImpl { +public: + MTPDimportedContact() { + } + MTPDimportedContact(MTPint _user_id, const MTPlong &_client_id) : vuser_id(_user_id), vclient_id(_client_id) { + } + + MTPint vuser_id; + MTPlong vclient_id; +}; + +class MTPDcontactBlocked : public mtpDataImpl { +public: + MTPDcontactBlocked() { + } + MTPDcontactBlocked(MTPint _user_id, MTPint _date) : vuser_id(_user_id), vdate(_date) { + } + + MTPint vuser_id; + MTPint vdate; +}; + +class MTPDcontactFound : public mtpDataImpl { +public: + MTPDcontactFound() { + } + MTPDcontactFound(MTPint _user_id) : vuser_id(_user_id) { + } + + MTPint vuser_id; +}; + +class MTPDcontactSuggested : public mtpDataImpl { +public: + MTPDcontactSuggested() { + } + MTPDcontactSuggested(MTPint _user_id, MTPint _mutual_contacts) : vuser_id(_user_id), vmutual_contacts(_mutual_contacts) { + } + + MTPint vuser_id; + MTPint vmutual_contacts; +}; + +class MTPDcontactStatus : public mtpDataImpl { +public: + MTPDcontactStatus() { + } + MTPDcontactStatus(MTPint _user_id, MTPint _expires) : vuser_id(_user_id), vexpires(_expires) { + } + + MTPint vuser_id; + MTPint vexpires; +}; + +class MTPDchatLocated : public mtpDataImpl { +public: + MTPDchatLocated() { + } + MTPDchatLocated(MTPint _chat_id, MTPint _distance) : vchat_id(_chat_id), vdistance(_distance) { + } + + MTPint vchat_id; + MTPint vdistance; +}; + +class MTPDcontacts_foreignLinkRequested : public mtpDataImpl { +public: + MTPDcontacts_foreignLinkRequested() { + } + MTPDcontacts_foreignLinkRequested(MTPBool _has_phone) : vhas_phone(_has_phone) { + } + + MTPBool vhas_phone; +}; + +class MTPDcontacts_myLinkRequested : public mtpDataImpl { +public: + MTPDcontacts_myLinkRequested() { + } + MTPDcontacts_myLinkRequested(MTPBool _contact) : vcontact(_contact) { + } + + MTPBool vcontact; +}; + +class MTPDcontacts_link : public mtpDataImpl { +public: + MTPDcontacts_link() { + } + MTPDcontacts_link(const MTPcontacts_MyLink &_my_link, const MTPcontacts_ForeignLink &_foreign_link, const MTPUser &_user) : vmy_link(_my_link), vforeign_link(_foreign_link), vuser(_user) { + } + + MTPcontacts_MyLink vmy_link; + MTPcontacts_ForeignLink vforeign_link; + MTPUser vuser; +}; + +class MTPDcontacts_contacts : public mtpDataImpl { +public: + MTPDcontacts_contacts() { + } + MTPDcontacts_contacts(const MTPVector &_contacts, const MTPVector &_users) : vcontacts(_contacts), vusers(_users) { + } + + MTPVector vcontacts; + MTPVector vusers; +}; + +class MTPDcontacts_importedContacts : public mtpDataImpl { +public: + MTPDcontacts_importedContacts() { + } + MTPDcontacts_importedContacts(const MTPVector &_imported, const MTPVector &_retry_contacts, const MTPVector &_users) : vimported(_imported), vretry_contacts(_retry_contacts), vusers(_users) { + } + + MTPVector vimported; + MTPVector vretry_contacts; + MTPVector vusers; +}; + +class MTPDcontacts_blocked : public mtpDataImpl { +public: + MTPDcontacts_blocked() { + } + MTPDcontacts_blocked(const MTPVector &_blocked, const MTPVector &_users) : vblocked(_blocked), vusers(_users) { + } + + MTPVector vblocked; + MTPVector vusers; +}; + +class MTPDcontacts_blockedSlice : public mtpDataImpl { +public: + MTPDcontacts_blockedSlice() { + } + MTPDcontacts_blockedSlice(MTPint _count, const MTPVector &_blocked, const MTPVector &_users) : vcount(_count), vblocked(_blocked), vusers(_users) { + } + + MTPint vcount; + MTPVector vblocked; + MTPVector vusers; +}; + +class MTPDcontacts_found : public mtpDataImpl { +public: + MTPDcontacts_found() { + } + MTPDcontacts_found(const MTPVector &_results, const MTPVector &_users) : vresults(_results), vusers(_users) { + } + + MTPVector vresults; + MTPVector vusers; +}; + +class MTPDcontacts_suggested : public mtpDataImpl { +public: + MTPDcontacts_suggested() { + } + MTPDcontacts_suggested(const MTPVector &_results, const MTPVector &_users) : vresults(_results), vusers(_users) { + } + + MTPVector vresults; + MTPVector vusers; +}; + +class MTPDmessages_dialogs : public mtpDataImpl { +public: + MTPDmessages_dialogs() { + } + MTPDmessages_dialogs(const MTPVector &_dialogs, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) : vdialogs(_dialogs), vmessages(_messages), vchats(_chats), vusers(_users) { + } + + MTPVector vdialogs; + MTPVector vmessages; + MTPVector vchats; + MTPVector vusers; +}; + +class MTPDmessages_dialogsSlice : public mtpDataImpl { +public: + MTPDmessages_dialogsSlice() { + } + MTPDmessages_dialogsSlice(MTPint _count, const MTPVector &_dialogs, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) : vcount(_count), vdialogs(_dialogs), vmessages(_messages), vchats(_chats), vusers(_users) { + } + + MTPint vcount; + MTPVector vdialogs; + MTPVector vmessages; + MTPVector vchats; + MTPVector vusers; +}; + +class MTPDmessages_messages : public mtpDataImpl { +public: + MTPDmessages_messages() { + } + MTPDmessages_messages(const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) : vmessages(_messages), vchats(_chats), vusers(_users) { + } + + MTPVector vmessages; + MTPVector vchats; + MTPVector vusers; +}; + +class MTPDmessages_messagesSlice : public mtpDataImpl { +public: + MTPDmessages_messagesSlice() { + } + MTPDmessages_messagesSlice(MTPint _count, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) : vcount(_count), vmessages(_messages), vchats(_chats), vusers(_users) { + } + + MTPint vcount; + MTPVector vmessages; + MTPVector vchats; + MTPVector vusers; +}; + +class MTPDmessages_message : public mtpDataImpl { +public: + MTPDmessages_message() { + } + MTPDmessages_message(const MTPMessage &_message, const MTPVector &_chats, const MTPVector &_users) : vmessage(_message), vchats(_chats), vusers(_users) { + } + + MTPMessage vmessage; + MTPVector vchats; + MTPVector vusers; +}; + +class MTPDmessages_statedMessages : public mtpDataImpl { +public: + MTPDmessages_statedMessages() { + } + MTPDmessages_statedMessages(const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users, MTPint _pts, MTPint _seq) : vmessages(_messages), vchats(_chats), vusers(_users), vpts(_pts), vseq(_seq) { + } + + MTPVector vmessages; + MTPVector vchats; + MTPVector vusers; + MTPint vpts; + MTPint vseq; +}; + +class MTPDmessages_statedMessagesLinks : public mtpDataImpl { +public: + MTPDmessages_statedMessagesLinks() { + } + MTPDmessages_statedMessagesLinks(const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users, const MTPVector &_links, MTPint _pts, MTPint _seq) : vmessages(_messages), vchats(_chats), vusers(_users), vlinks(_links), vpts(_pts), vseq(_seq) { + } + + MTPVector vmessages; + MTPVector vchats; + MTPVector vusers; + MTPVector vlinks; + MTPint vpts; + MTPint vseq; +}; + +class MTPDmessages_statedMessage : public mtpDataImpl { +public: + MTPDmessages_statedMessage() { + } + MTPDmessages_statedMessage(const MTPMessage &_message, const MTPVector &_chats, const MTPVector &_users, MTPint _pts, MTPint _seq) : vmessage(_message), vchats(_chats), vusers(_users), vpts(_pts), vseq(_seq) { + } + + MTPMessage vmessage; + MTPVector vchats; + MTPVector vusers; + MTPint vpts; + MTPint vseq; +}; + +class MTPDmessages_statedMessageLink : public mtpDataImpl { +public: + MTPDmessages_statedMessageLink() { + } + MTPDmessages_statedMessageLink(const MTPMessage &_message, const MTPVector &_chats, const MTPVector &_users, const MTPVector &_links, MTPint _pts, MTPint _seq) : vmessage(_message), vchats(_chats), vusers(_users), vlinks(_links), vpts(_pts), vseq(_seq) { + } + + MTPMessage vmessage; + MTPVector vchats; + MTPVector vusers; + MTPVector vlinks; + MTPint vpts; + MTPint vseq; +}; + +class MTPDmessages_sentMessage : public mtpDataImpl { +public: + MTPDmessages_sentMessage() { + } + MTPDmessages_sentMessage(MTPint _id, MTPint _date, MTPint _pts, MTPint _seq) : vid(_id), vdate(_date), vpts(_pts), vseq(_seq) { + } + + MTPint vid; + MTPint vdate; + MTPint vpts; + MTPint vseq; +}; + +class MTPDmessages_sentMessageLink : public mtpDataImpl { +public: + MTPDmessages_sentMessageLink() { + } + MTPDmessages_sentMessageLink(MTPint _id, MTPint _date, MTPint _pts, MTPint _seq, const MTPVector &_links) : vid(_id), vdate(_date), vpts(_pts), vseq(_seq), vlinks(_links) { + } + + MTPint vid; + MTPint vdate; + MTPint vpts; + MTPint vseq; + MTPVector vlinks; +}; + +class MTPDmessages_chat : public mtpDataImpl { +public: + MTPDmessages_chat() { + } + MTPDmessages_chat(const MTPChat &_chat, const MTPVector &_users) : vchat(_chat), vusers(_users) { + } + + MTPChat vchat; + MTPVector vusers; +}; + +class MTPDmessages_chats : public mtpDataImpl { +public: + MTPDmessages_chats() { + } + MTPDmessages_chats(const MTPVector &_chats, const MTPVector &_users) : vchats(_chats), vusers(_users) { + } + + MTPVector vchats; + MTPVector vusers; +}; + +class MTPDmessages_chatFull : public mtpDataImpl { +public: + MTPDmessages_chatFull() { + } + MTPDmessages_chatFull(const MTPChatFull &_full_chat, const MTPVector &_chats, const MTPVector &_users) : vfull_chat(_full_chat), vchats(_chats), vusers(_users) { + } + + MTPChatFull vfull_chat; + MTPVector vchats; + MTPVector vusers; +}; + +class MTPDmessages_affectedHistory : public mtpDataImpl { +public: + MTPDmessages_affectedHistory() { + } + MTPDmessages_affectedHistory(MTPint _pts, MTPint _seq, MTPint _offset) : vpts(_pts), vseq(_seq), voffset(_offset) { + } + + MTPint vpts; + MTPint vseq; + MTPint voffset; +}; + +class MTPDupdateNewMessage : public mtpDataImpl { +public: + MTPDupdateNewMessage() { + } + MTPDupdateNewMessage(const MTPMessage &_message, MTPint _pts) : vmessage(_message), vpts(_pts) { + } + + MTPMessage vmessage; + MTPint vpts; +}; + +class MTPDupdateMessageID : public mtpDataImpl { +public: + MTPDupdateMessageID() { + } + MTPDupdateMessageID(MTPint _id, const MTPlong &_random_id) : vid(_id), vrandom_id(_random_id) { + } + + MTPint vid; + MTPlong vrandom_id; +}; + +class MTPDupdateReadMessages : public mtpDataImpl { +public: + MTPDupdateReadMessages() { + } + MTPDupdateReadMessages(const MTPVector &_messages, MTPint _pts) : vmessages(_messages), vpts(_pts) { + } + + MTPVector vmessages; + MTPint vpts; +}; + +class MTPDupdateDeleteMessages : public mtpDataImpl { +public: + MTPDupdateDeleteMessages() { + } + MTPDupdateDeleteMessages(const MTPVector &_messages, MTPint _pts) : vmessages(_messages), vpts(_pts) { + } + + MTPVector vmessages; + MTPint vpts; +}; + +class MTPDupdateRestoreMessages : public mtpDataImpl { +public: + MTPDupdateRestoreMessages() { + } + MTPDupdateRestoreMessages(const MTPVector &_messages, MTPint _pts) : vmessages(_messages), vpts(_pts) { + } + + MTPVector vmessages; + MTPint vpts; +}; + +class MTPDupdateUserTyping : public mtpDataImpl { +public: + MTPDupdateUserTyping() { + } + MTPDupdateUserTyping(MTPint _user_id) : vuser_id(_user_id) { + } + + MTPint vuser_id; +}; + +class MTPDupdateChatUserTyping : public mtpDataImpl { +public: + MTPDupdateChatUserTyping() { + } + MTPDupdateChatUserTyping(MTPint _chat_id, MTPint _user_id) : vchat_id(_chat_id), vuser_id(_user_id) { + } + + MTPint vchat_id; + MTPint vuser_id; +}; + +class MTPDupdateChatParticipants : public mtpDataImpl { +public: + MTPDupdateChatParticipants() { + } + MTPDupdateChatParticipants(const MTPChatParticipants &_participants) : vparticipants(_participants) { + } + + MTPChatParticipants vparticipants; +}; + +class MTPDupdateUserStatus : public mtpDataImpl { +public: + MTPDupdateUserStatus() { + } + MTPDupdateUserStatus(MTPint _user_id, const MTPUserStatus &_status) : vuser_id(_user_id), vstatus(_status) { + } + + MTPint vuser_id; + MTPUserStatus vstatus; +}; + +class MTPDupdateUserName : public mtpDataImpl { +public: + MTPDupdateUserName() { + } + MTPDupdateUserName(MTPint _user_id, const MTPstring &_first_name, const MTPstring &_last_name) : vuser_id(_user_id), vfirst_name(_first_name), vlast_name(_last_name) { + } + + MTPint vuser_id; + MTPstring vfirst_name; + MTPstring vlast_name; +}; + +class MTPDupdateUserPhoto : public mtpDataImpl { +public: + MTPDupdateUserPhoto() { + } + MTPDupdateUserPhoto(MTPint _user_id, MTPint _date, const MTPUserProfilePhoto &_photo, MTPBool _previous) : vuser_id(_user_id), vdate(_date), vphoto(_photo), vprevious(_previous) { + } + + MTPint vuser_id; + MTPint vdate; + MTPUserProfilePhoto vphoto; + MTPBool vprevious; +}; + +class MTPDupdateContactRegistered : public mtpDataImpl { +public: + MTPDupdateContactRegistered() { + } + MTPDupdateContactRegistered(MTPint _user_id, MTPint _date) : vuser_id(_user_id), vdate(_date) { + } + + MTPint vuser_id; + MTPint vdate; +}; + +class MTPDupdateContactLink : public mtpDataImpl { +public: + MTPDupdateContactLink() { + } + MTPDupdateContactLink(MTPint _user_id, const MTPcontacts_MyLink &_my_link, const MTPcontacts_ForeignLink &_foreign_link) : vuser_id(_user_id), vmy_link(_my_link), vforeign_link(_foreign_link) { + } + + MTPint vuser_id; + MTPcontacts_MyLink vmy_link; + MTPcontacts_ForeignLink vforeign_link; +}; + +class MTPDupdateActivation : public mtpDataImpl { +public: + MTPDupdateActivation() { + } + MTPDupdateActivation(MTPint _user_id) : vuser_id(_user_id) { + } + + MTPint vuser_id; +}; + +class MTPDupdateNewAuthorization : public mtpDataImpl { +public: + MTPDupdateNewAuthorization() { + } + MTPDupdateNewAuthorization(const MTPlong &_auth_key_id, MTPint _date, const MTPstring &_device, const MTPstring &_location) : vauth_key_id(_auth_key_id), vdate(_date), vdevice(_device), vlocation(_location) { + } + + MTPlong vauth_key_id; + MTPint vdate; + MTPstring vdevice; + MTPstring vlocation; +}; + +class MTPDupdateNewGeoChatMessage : public mtpDataImpl { +public: + MTPDupdateNewGeoChatMessage() { + } + MTPDupdateNewGeoChatMessage(const MTPGeoChatMessage &_message) : vmessage(_message) { + } + + MTPGeoChatMessage vmessage; +}; + +class MTPDupdateNewEncryptedMessage : public mtpDataImpl { +public: + MTPDupdateNewEncryptedMessage() { + } + MTPDupdateNewEncryptedMessage(const MTPEncryptedMessage &_message, MTPint _qts) : vmessage(_message), vqts(_qts) { + } + + MTPEncryptedMessage vmessage; + MTPint vqts; +}; + +class MTPDupdateEncryptedChatTyping : public mtpDataImpl { +public: + MTPDupdateEncryptedChatTyping() { + } + MTPDupdateEncryptedChatTyping(MTPint _chat_id) : vchat_id(_chat_id) { + } + + MTPint vchat_id; +}; + +class MTPDupdateEncryption : public mtpDataImpl { +public: + MTPDupdateEncryption() { + } + MTPDupdateEncryption(const MTPEncryptedChat &_chat, MTPint _date) : vchat(_chat), vdate(_date) { + } + + MTPEncryptedChat vchat; + MTPint vdate; +}; + +class MTPDupdateEncryptedMessagesRead : public mtpDataImpl { +public: + MTPDupdateEncryptedMessagesRead() { + } + MTPDupdateEncryptedMessagesRead(MTPint _chat_id, MTPint _max_date, MTPint _date) : vchat_id(_chat_id), vmax_date(_max_date), vdate(_date) { + } + + MTPint vchat_id; + MTPint vmax_date; + MTPint vdate; +}; + +class MTPDupdateChatParticipantAdd : public mtpDataImpl { +public: + MTPDupdateChatParticipantAdd() { + } + MTPDupdateChatParticipantAdd(MTPint _chat_id, MTPint _user_id, MTPint _inviter_id, MTPint _version) : vchat_id(_chat_id), vuser_id(_user_id), vinviter_id(_inviter_id), vversion(_version) { + } + + MTPint vchat_id; + MTPint vuser_id; + MTPint vinviter_id; + MTPint vversion; +}; + +class MTPDupdateChatParticipantDelete : public mtpDataImpl { +public: + MTPDupdateChatParticipantDelete() { + } + MTPDupdateChatParticipantDelete(MTPint _chat_id, MTPint _user_id, MTPint _version) : vchat_id(_chat_id), vuser_id(_user_id), vversion(_version) { + } + + MTPint vchat_id; + MTPint vuser_id; + MTPint vversion; +}; + +class MTPDupdateDcOptions : public mtpDataImpl { +public: + MTPDupdateDcOptions() { + } + MTPDupdateDcOptions(const MTPVector &_dc_options) : vdc_options(_dc_options) { + } + + MTPVector vdc_options; +}; + +class MTPDupdateUserBlocked : public mtpDataImpl { +public: + MTPDupdateUserBlocked() { + } + MTPDupdateUserBlocked(MTPint _user_id, MTPBool _blocked) : vuser_id(_user_id), vblocked(_blocked) { + } + + MTPint vuser_id; + MTPBool vblocked; +}; + +class MTPDupdateNotifySettings : public mtpDataImpl { +public: + MTPDupdateNotifySettings() { + } + MTPDupdateNotifySettings(const MTPNotifyPeer &_peer, const MTPPeerNotifySettings &_notify_settings) : vpeer(_peer), vnotify_settings(_notify_settings) { + } + + MTPNotifyPeer vpeer; + MTPPeerNotifySettings vnotify_settings; +}; + +class MTPDupdates_state : public mtpDataImpl { +public: + MTPDupdates_state() { + } + MTPDupdates_state(MTPint _pts, MTPint _qts, MTPint _date, MTPint _seq, MTPint _unread_count) : vpts(_pts), vqts(_qts), vdate(_date), vseq(_seq), vunread_count(_unread_count) { + } + + MTPint vpts; + MTPint vqts; + MTPint vdate; + MTPint vseq; + MTPint vunread_count; +}; + +class MTPDupdates_differenceEmpty : public mtpDataImpl { +public: + MTPDupdates_differenceEmpty() { + } + MTPDupdates_differenceEmpty(MTPint _date, MTPint _seq) : vdate(_date), vseq(_seq) { + } + + MTPint vdate; + MTPint vseq; +}; + +class MTPDupdates_difference : public mtpDataImpl { +public: + MTPDupdates_difference() { + } + MTPDupdates_difference(const MTPVector &_new_messages, const MTPVector &_new_encrypted_messages, const MTPVector &_other_updates, const MTPVector &_chats, const MTPVector &_users, const MTPupdates_State &_state) : vnew_messages(_new_messages), vnew_encrypted_messages(_new_encrypted_messages), vother_updates(_other_updates), vchats(_chats), vusers(_users), vstate(_state) { + } + + MTPVector vnew_messages; + MTPVector vnew_encrypted_messages; + MTPVector vother_updates; + MTPVector vchats; + MTPVector vusers; + MTPupdates_State vstate; +}; + +class MTPDupdates_differenceSlice : public mtpDataImpl { +public: + MTPDupdates_differenceSlice() { + } + MTPDupdates_differenceSlice(const MTPVector &_new_messages, const MTPVector &_new_encrypted_messages, const MTPVector &_other_updates, const MTPVector &_chats, const MTPVector &_users, const MTPupdates_State &_intermediate_state) : vnew_messages(_new_messages), vnew_encrypted_messages(_new_encrypted_messages), vother_updates(_other_updates), vchats(_chats), vusers(_users), vintermediate_state(_intermediate_state) { + } + + MTPVector vnew_messages; + MTPVector vnew_encrypted_messages; + MTPVector vother_updates; + MTPVector vchats; + MTPVector vusers; + MTPupdates_State vintermediate_state; +}; + +class MTPDupdateShortMessage : public mtpDataImpl { +public: + MTPDupdateShortMessage() { + } + MTPDupdateShortMessage(MTPint _id, MTPint _from_id, const MTPstring &_message, MTPint _pts, MTPint _date, MTPint _seq) : vid(_id), vfrom_id(_from_id), vmessage(_message), vpts(_pts), vdate(_date), vseq(_seq) { + } + + MTPint vid; + MTPint vfrom_id; + MTPstring vmessage; + MTPint vpts; + MTPint vdate; + MTPint vseq; +}; + +class MTPDupdateShortChatMessage : public mtpDataImpl { +public: + MTPDupdateShortChatMessage() { + } + MTPDupdateShortChatMessage(MTPint _id, MTPint _from_id, MTPint _chat_id, const MTPstring &_message, MTPint _pts, MTPint _date, MTPint _seq) : vid(_id), vfrom_id(_from_id), vchat_id(_chat_id), vmessage(_message), vpts(_pts), vdate(_date), vseq(_seq) { + } + + MTPint vid; + MTPint vfrom_id; + MTPint vchat_id; + MTPstring vmessage; + MTPint vpts; + MTPint vdate; + MTPint vseq; +}; + +class MTPDupdateShort : public mtpDataImpl { +public: + MTPDupdateShort() { + } + MTPDupdateShort(const MTPUpdate &_update, MTPint _date) : vupdate(_update), vdate(_date) { + } + + MTPUpdate vupdate; + MTPint vdate; +}; + +class MTPDupdatesCombined : public mtpDataImpl { +public: + MTPDupdatesCombined() { + } + MTPDupdatesCombined(const MTPVector &_updates, const MTPVector &_users, const MTPVector &_chats, MTPint _date, MTPint _seq_start, MTPint _seq) : vupdates(_updates), vusers(_users), vchats(_chats), vdate(_date), vseq_start(_seq_start), vseq(_seq) { + } + + MTPVector vupdates; + MTPVector vusers; + MTPVector vchats; + MTPint vdate; + MTPint vseq_start; + MTPint vseq; +}; + +class MTPDupdates : public mtpDataImpl { +public: + MTPDupdates() { + } + MTPDupdates(const MTPVector &_updates, const MTPVector &_users, const MTPVector &_chats, MTPint _date, MTPint _seq) : vupdates(_updates), vusers(_users), vchats(_chats), vdate(_date), vseq(_seq) { + } + + MTPVector vupdates; + MTPVector vusers; + MTPVector vchats; + MTPint vdate; + MTPint vseq; +}; + +class MTPDphotos_photos : public mtpDataImpl { +public: + MTPDphotos_photos() { + } + MTPDphotos_photos(const MTPVector &_photos, const MTPVector &_users) : vphotos(_photos), vusers(_users) { + } + + MTPVector vphotos; + MTPVector vusers; +}; + +class MTPDphotos_photosSlice : public mtpDataImpl { +public: + MTPDphotos_photosSlice() { + } + MTPDphotos_photosSlice(MTPint _count, const MTPVector &_photos, const MTPVector &_users) : vcount(_count), vphotos(_photos), vusers(_users) { + } + + MTPint vcount; + MTPVector vphotos; + MTPVector vusers; +}; + +class MTPDphotos_photo : public mtpDataImpl { +public: + MTPDphotos_photo() { + } + MTPDphotos_photo(const MTPPhoto &_photo, const MTPVector &_users) : vphoto(_photo), vusers(_users) { + } + + MTPPhoto vphoto; + MTPVector vusers; +}; + +class MTPDupload_file : public mtpDataImpl { +public: + MTPDupload_file() { + } + MTPDupload_file(const MTPstorage_FileType &_type, MTPint _mtime, const MTPbytes &_bytes) : vtype(_type), vmtime(_mtime), vbytes(_bytes) { + } + + MTPstorage_FileType vtype; + MTPint vmtime; + MTPbytes vbytes; +}; + +class MTPDdcOption : public mtpDataImpl { +public: + MTPDdcOption() { + } + MTPDdcOption(MTPint _id, const MTPstring &_hostname, const MTPstring &_ip_address, MTPint _port) : vid(_id), vhostname(_hostname), vip_address(_ip_address), vport(_port) { + } + + MTPint vid; + MTPstring vhostname; + MTPstring vip_address; + MTPint vport; +}; + +class MTPDconfig : public mtpDataImpl { +public: + MTPDconfig() { + } + MTPDconfig(MTPint _date, MTPBool _test_mode, MTPint _this_dc, const MTPVector &_dc_options, MTPint _chat_size_max, MTPint _broadcast_size_max) : vdate(_date), vtest_mode(_test_mode), vthis_dc(_this_dc), vdc_options(_dc_options), vchat_size_max(_chat_size_max), vbroadcast_size_max(_broadcast_size_max) { + } + + MTPint vdate; + MTPBool vtest_mode; + MTPint vthis_dc; + MTPVector vdc_options; + MTPint vchat_size_max; + MTPint vbroadcast_size_max; +}; + +class MTPDnearestDc : public mtpDataImpl { +public: + MTPDnearestDc() { + } + MTPDnearestDc(const MTPstring &_country, MTPint _this_dc, MTPint _nearest_dc) : vcountry(_country), vthis_dc(_this_dc), vnearest_dc(_nearest_dc) { + } + + MTPstring vcountry; + MTPint vthis_dc; + MTPint vnearest_dc; +}; + +class MTPDhelp_appUpdate : public mtpDataImpl { +public: + MTPDhelp_appUpdate() { + } + MTPDhelp_appUpdate(MTPint _id, MTPBool _critical, const MTPstring &_url, const MTPstring &_text) : vid(_id), vcritical(_critical), vurl(_url), vtext(_text) { + } + + MTPint vid; + MTPBool vcritical; + MTPstring vurl; + MTPstring vtext; +}; + +class MTPDhelp_inviteText : public mtpDataImpl { +public: + MTPDhelp_inviteText() { + } + MTPDhelp_inviteText(const MTPstring &_message) : vmessage(_message) { + } + + MTPstring vmessage; +}; + +class MTPDinputGeoChat : public mtpDataImpl { +public: + MTPDinputGeoChat() { + } + MTPDinputGeoChat(MTPint _chat_id, const MTPlong &_access_hash) : vchat_id(_chat_id), vaccess_hash(_access_hash) { + } + + MTPint vchat_id; + MTPlong vaccess_hash; +}; + +class MTPDgeoChatMessageEmpty : public mtpDataImpl { +public: + MTPDgeoChatMessageEmpty() { + } + MTPDgeoChatMessageEmpty(MTPint _chat_id, MTPint _id) : vchat_id(_chat_id), vid(_id) { + } + + MTPint vchat_id; + MTPint vid; +}; + +class MTPDgeoChatMessage : public mtpDataImpl { +public: + MTPDgeoChatMessage() { + } + MTPDgeoChatMessage(MTPint _chat_id, MTPint _id, MTPint _from_id, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media) : vchat_id(_chat_id), vid(_id), vfrom_id(_from_id), vdate(_date), vmessage(_message), vmedia(_media) { + } + + MTPint vchat_id; + MTPint vid; + MTPint vfrom_id; + MTPint vdate; + MTPstring vmessage; + MTPMessageMedia vmedia; +}; + +class MTPDgeoChatMessageService : public mtpDataImpl { +public: + MTPDgeoChatMessageService() { + } + MTPDgeoChatMessageService(MTPint _chat_id, MTPint _id, MTPint _from_id, MTPint _date, const MTPMessageAction &_action) : vchat_id(_chat_id), vid(_id), vfrom_id(_from_id), vdate(_date), vaction(_action) { + } + + MTPint vchat_id; + MTPint vid; + MTPint vfrom_id; + MTPint vdate; + MTPMessageAction vaction; +}; + +class MTPDgeochats_statedMessage : public mtpDataImpl { +public: + MTPDgeochats_statedMessage() { + } + MTPDgeochats_statedMessage(const MTPGeoChatMessage &_message, const MTPVector &_chats, const MTPVector &_users, MTPint _seq) : vmessage(_message), vchats(_chats), vusers(_users), vseq(_seq) { + } + + MTPGeoChatMessage vmessage; + MTPVector vchats; + MTPVector vusers; + MTPint vseq; +}; + +class MTPDgeochats_located : public mtpDataImpl { +public: + MTPDgeochats_located() { + } + MTPDgeochats_located(const MTPVector &_results, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) : vresults(_results), vmessages(_messages), vchats(_chats), vusers(_users) { + } + + MTPVector vresults; + MTPVector vmessages; + MTPVector vchats; + MTPVector vusers; +}; + +class MTPDgeochats_messages : public mtpDataImpl { +public: + MTPDgeochats_messages() { + } + MTPDgeochats_messages(const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) : vmessages(_messages), vchats(_chats), vusers(_users) { + } + + MTPVector vmessages; + MTPVector vchats; + MTPVector vusers; +}; + +class MTPDgeochats_messagesSlice : public mtpDataImpl { +public: + MTPDgeochats_messagesSlice() { + } + MTPDgeochats_messagesSlice(MTPint _count, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) : vcount(_count), vmessages(_messages), vchats(_chats), vusers(_users) { + } + + MTPint vcount; + MTPVector vmessages; + MTPVector vchats; + MTPVector vusers; +}; + +class MTPDencryptedChatEmpty : public mtpDataImpl { +public: + MTPDencryptedChatEmpty() { + } + MTPDencryptedChatEmpty(MTPint _id) : vid(_id) { + } + + MTPint vid; +}; + +class MTPDencryptedChatWaiting : public mtpDataImpl { +public: + MTPDencryptedChatWaiting() { + } + MTPDencryptedChatWaiting(MTPint _id, const MTPlong &_access_hash, MTPint _date, MTPint _admin_id, MTPint _participant_id) : vid(_id), vaccess_hash(_access_hash), vdate(_date), vadmin_id(_admin_id), vparticipant_id(_participant_id) { + } + + MTPint vid; + MTPlong vaccess_hash; + MTPint vdate; + MTPint vadmin_id; + MTPint vparticipant_id; +}; + +class MTPDencryptedChatRequested : public mtpDataImpl { +public: + MTPDencryptedChatRequested() { + } + MTPDencryptedChatRequested(MTPint _id, const MTPlong &_access_hash, MTPint _date, MTPint _admin_id, MTPint _participant_id, const MTPbytes &_g_a) : vid(_id), vaccess_hash(_access_hash), vdate(_date), vadmin_id(_admin_id), vparticipant_id(_participant_id), vg_a(_g_a) { + } + + MTPint vid; + MTPlong vaccess_hash; + MTPint vdate; + MTPint vadmin_id; + MTPint vparticipant_id; + MTPbytes vg_a; +}; + +class MTPDencryptedChat : public mtpDataImpl { +public: + MTPDencryptedChat() { + } + MTPDencryptedChat(MTPint _id, const MTPlong &_access_hash, MTPint _date, MTPint _admin_id, MTPint _participant_id, const MTPbytes &_g_a_or_b, const MTPlong &_key_fingerprint) : vid(_id), vaccess_hash(_access_hash), vdate(_date), vadmin_id(_admin_id), vparticipant_id(_participant_id), vg_a_or_b(_g_a_or_b), vkey_fingerprint(_key_fingerprint) { + } + + MTPint vid; + MTPlong vaccess_hash; + MTPint vdate; + MTPint vadmin_id; + MTPint vparticipant_id; + MTPbytes vg_a_or_b; + MTPlong vkey_fingerprint; +}; + +class MTPDencryptedChatDiscarded : public mtpDataImpl { +public: + MTPDencryptedChatDiscarded() { + } + MTPDencryptedChatDiscarded(MTPint _id) : vid(_id) { + } + + MTPint vid; +}; + +class MTPDinputEncryptedChat : public mtpDataImpl { +public: + MTPDinputEncryptedChat() { + } + MTPDinputEncryptedChat(MTPint _chat_id, const MTPlong &_access_hash) : vchat_id(_chat_id), vaccess_hash(_access_hash) { + } + + MTPint vchat_id; + MTPlong vaccess_hash; +}; + +class MTPDencryptedFile : public mtpDataImpl { +public: + MTPDencryptedFile() { + } + MTPDencryptedFile(const MTPlong &_id, const MTPlong &_access_hash, MTPint _size, MTPint _dc_id, MTPint _key_fingerprint) : vid(_id), vaccess_hash(_access_hash), vsize(_size), vdc_id(_dc_id), vkey_fingerprint(_key_fingerprint) { + } + + MTPlong vid; + MTPlong vaccess_hash; + MTPint vsize; + MTPint vdc_id; + MTPint vkey_fingerprint; +}; + +class MTPDinputEncryptedFileUploaded : public mtpDataImpl { +public: + MTPDinputEncryptedFileUploaded() { + } + MTPDinputEncryptedFileUploaded(const MTPlong &_id, MTPint _parts, const MTPstring &_md5_checksum, MTPint _key_fingerprint) : vid(_id), vparts(_parts), vmd5_checksum(_md5_checksum), vkey_fingerprint(_key_fingerprint) { + } + + MTPlong vid; + MTPint vparts; + MTPstring vmd5_checksum; + MTPint vkey_fingerprint; +}; + +class MTPDinputEncryptedFile : public mtpDataImpl { +public: + MTPDinputEncryptedFile() { + } + MTPDinputEncryptedFile(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) { + } + + MTPlong vid; + MTPlong vaccess_hash; +}; + +class MTPDinputEncryptedFileBigUploaded : public mtpDataImpl { +public: + MTPDinputEncryptedFileBigUploaded() { + } + MTPDinputEncryptedFileBigUploaded(const MTPlong &_id, MTPint _parts, MTPint _key_fingerprint) : vid(_id), vparts(_parts), vkey_fingerprint(_key_fingerprint) { + } + + MTPlong vid; + MTPint vparts; + MTPint vkey_fingerprint; +}; + +class MTPDencryptedMessage : public mtpDataImpl { +public: + MTPDencryptedMessage() { + } + MTPDencryptedMessage(const MTPlong &_random_id, MTPint _chat_id, MTPint _date, const MTPbytes &_bytes, const MTPEncryptedFile &_file) : vrandom_id(_random_id), vchat_id(_chat_id), vdate(_date), vbytes(_bytes), vfile(_file) { + } + + MTPlong vrandom_id; + MTPint vchat_id; + MTPint vdate; + MTPbytes vbytes; + MTPEncryptedFile vfile; +}; + +class MTPDencryptedMessageService : public mtpDataImpl { +public: + MTPDencryptedMessageService() { + } + MTPDencryptedMessageService(const MTPlong &_random_id, MTPint _chat_id, MTPint _date, const MTPbytes &_bytes) : vrandom_id(_random_id), vchat_id(_chat_id), vdate(_date), vbytes(_bytes) { + } + + MTPlong vrandom_id; + MTPint vchat_id; + MTPint vdate; + MTPbytes vbytes; +}; + +class MTPDdecryptedMessageLayer : public mtpDataImpl { +public: + MTPDdecryptedMessageLayer() { + } + MTPDdecryptedMessageLayer(MTPint _layer, const MTPDecryptedMessage &_message) : vlayer(_layer), vmessage(_message) { + } + + MTPint vlayer; + MTPDecryptedMessage vmessage; +}; + +class MTPDdecryptedMessage : public mtpDataImpl { +public: + MTPDdecryptedMessage() { + } + MTPDdecryptedMessage(const MTPlong &_random_id, const MTPbytes &_random_bytes, const MTPstring &_message, const MTPDecryptedMessageMedia &_media) : vrandom_id(_random_id), vrandom_bytes(_random_bytes), vmessage(_message), vmedia(_media) { + } + + MTPlong vrandom_id; + MTPbytes vrandom_bytes; + MTPstring vmessage; + MTPDecryptedMessageMedia vmedia; +}; + +class MTPDdecryptedMessageService : public mtpDataImpl { +public: + MTPDdecryptedMessageService() { + } + MTPDdecryptedMessageService(const MTPlong &_random_id, const MTPbytes &_random_bytes, const MTPDecryptedMessageAction &_action) : vrandom_id(_random_id), vrandom_bytes(_random_bytes), vaction(_action) { + } + + MTPlong vrandom_id; + MTPbytes vrandom_bytes; + MTPDecryptedMessageAction vaction; +}; + +class MTPDdecryptedMessageMediaPhoto : public mtpDataImpl { +public: + MTPDdecryptedMessageMediaPhoto() { + } + MTPDdecryptedMessageMediaPhoto(const MTPbytes &_thumb, MTPint _thumb_w, MTPint _thumb_h, MTPint _w, MTPint _h, MTPint _size, const MTPbytes &_key, const MTPbytes &_iv) : vthumb(_thumb), vthumb_w(_thumb_w), vthumb_h(_thumb_h), vw(_w), vh(_h), vsize(_size), vkey(_key), viv(_iv) { + } + + MTPbytes vthumb; + MTPint vthumb_w; + MTPint vthumb_h; + MTPint vw; + MTPint vh; + MTPint vsize; + MTPbytes vkey; + MTPbytes viv; +}; + +class MTPDdecryptedMessageMediaVideo : public mtpDataImpl { +public: + MTPDdecryptedMessageMediaVideo() { + } + MTPDdecryptedMessageMediaVideo(const MTPbytes &_thumb, MTPint _thumb_w, MTPint _thumb_h, MTPint _duration, const MTPstring &_mime_type, MTPint _w, MTPint _h, MTPint _size, const MTPbytes &_key, const MTPbytes &_iv) : vthumb(_thumb), vthumb_w(_thumb_w), vthumb_h(_thumb_h), vduration(_duration), vmime_type(_mime_type), vw(_w), vh(_h), vsize(_size), vkey(_key), viv(_iv) { + } + + MTPbytes vthumb; + MTPint vthumb_w; + MTPint vthumb_h; + MTPint vduration; + MTPstring vmime_type; + MTPint vw; + MTPint vh; + MTPint vsize; + MTPbytes vkey; + MTPbytes viv; +}; + +class MTPDdecryptedMessageMediaGeoPoint : public mtpDataImpl { +public: + MTPDdecryptedMessageMediaGeoPoint() { + } + MTPDdecryptedMessageMediaGeoPoint(const MTPdouble &_lat, const MTPdouble &_long) : vlat(_lat), vlong(_long) { + } + + MTPdouble vlat; + MTPdouble vlong; +}; + +class MTPDdecryptedMessageMediaContact : public mtpDataImpl { +public: + MTPDdecryptedMessageMediaContact() { + } + MTPDdecryptedMessageMediaContact(const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name, MTPint _user_id) : vphone_number(_phone_number), vfirst_name(_first_name), vlast_name(_last_name), vuser_id(_user_id) { + } + + MTPstring vphone_number; + MTPstring vfirst_name; + MTPstring vlast_name; + MTPint vuser_id; +}; + +class MTPDdecryptedMessageMediaDocument : public mtpDataImpl { +public: + MTPDdecryptedMessageMediaDocument() { + } + MTPDdecryptedMessageMediaDocument(const MTPbytes &_thumb, MTPint _thumb_w, MTPint _thumb_h, const MTPstring &_file_name, const MTPstring &_mime_type, MTPint _size, const MTPbytes &_key, const MTPbytes &_iv) : vthumb(_thumb), vthumb_w(_thumb_w), vthumb_h(_thumb_h), vfile_name(_file_name), vmime_type(_mime_type), vsize(_size), vkey(_key), viv(_iv) { + } + + MTPbytes vthumb; + MTPint vthumb_w; + MTPint vthumb_h; + MTPstring vfile_name; + MTPstring vmime_type; + MTPint vsize; + MTPbytes vkey; + MTPbytes viv; +}; + +class MTPDdecryptedMessageMediaAudio : public mtpDataImpl { +public: + MTPDdecryptedMessageMediaAudio() { + } + MTPDdecryptedMessageMediaAudio(MTPint _duration, const MTPstring &_mime_type, MTPint _size, const MTPbytes &_key, const MTPbytes &_iv) : vduration(_duration), vmime_type(_mime_type), vsize(_size), vkey(_key), viv(_iv) { + } + + MTPint vduration; + MTPstring vmime_type; + MTPint vsize; + MTPbytes vkey; + MTPbytes viv; +}; + +class MTPDdecryptedMessageActionSetMessageTTL : public mtpDataImpl { +public: + MTPDdecryptedMessageActionSetMessageTTL() { + } + MTPDdecryptedMessageActionSetMessageTTL(MTPint _ttl_seconds) : vttl_seconds(_ttl_seconds) { + } + + MTPint vttl_seconds; +}; + +class MTPDdecryptedMessageActionReadMessages : public mtpDataImpl { +public: + MTPDdecryptedMessageActionReadMessages() { + } + MTPDdecryptedMessageActionReadMessages(const MTPVector &_random_ids) : vrandom_ids(_random_ids) { + } + + MTPVector vrandom_ids; +}; + +class MTPDdecryptedMessageActionDeleteMessages : public mtpDataImpl { +public: + MTPDdecryptedMessageActionDeleteMessages() { + } + MTPDdecryptedMessageActionDeleteMessages(const MTPVector &_random_ids) : vrandom_ids(_random_ids) { + } + + MTPVector vrandom_ids; +}; + +class MTPDdecryptedMessageActionScreenshotMessages : public mtpDataImpl { +public: + MTPDdecryptedMessageActionScreenshotMessages() { + } + MTPDdecryptedMessageActionScreenshotMessages(const MTPVector &_random_ids) : vrandom_ids(_random_ids) { + } + + MTPVector vrandom_ids; +}; + +class MTPDdecryptedMessageActionNotifyLayer : public mtpDataImpl { +public: + MTPDdecryptedMessageActionNotifyLayer() { + } + MTPDdecryptedMessageActionNotifyLayer(MTPint _layer) : vlayer(_layer) { + } + + MTPint vlayer; +}; + +class MTPDmessages_dhConfigNotModified : public mtpDataImpl { +public: + MTPDmessages_dhConfigNotModified() { + } + MTPDmessages_dhConfigNotModified(const MTPbytes &_random) : vrandom(_random) { + } + + MTPbytes vrandom; +}; + +class MTPDmessages_dhConfig : public mtpDataImpl { +public: + MTPDmessages_dhConfig() { + } + MTPDmessages_dhConfig(MTPint _g, const MTPbytes &_p, MTPint _version, const MTPbytes &_random) : vg(_g), vp(_p), vversion(_version), vrandom(_random) { + } + + MTPint vg; + MTPbytes vp; + MTPint vversion; + MTPbytes vrandom; +}; + +class MTPDmessages_sentEncryptedMessage : public mtpDataImpl { +public: + MTPDmessages_sentEncryptedMessage() { + } + MTPDmessages_sentEncryptedMessage(MTPint _date) : vdate(_date) { + } + + MTPint vdate; +}; + +class MTPDmessages_sentEncryptedFile : public mtpDataImpl { +public: + MTPDmessages_sentEncryptedFile() { + } + MTPDmessages_sentEncryptedFile(MTPint _date, const MTPEncryptedFile &_file) : vdate(_date), vfile(_file) { + } + + MTPint vdate; + MTPEncryptedFile vfile; +}; + +class MTPDinputAudio : public mtpDataImpl { +public: + MTPDinputAudio() { + } + MTPDinputAudio(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) { + } + + MTPlong vid; + MTPlong vaccess_hash; +}; + +class MTPDinputDocument : public mtpDataImpl { +public: + MTPDinputDocument() { + } + MTPDinputDocument(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) { + } + + MTPlong vid; + MTPlong vaccess_hash; +}; + +class MTPDaudioEmpty : public mtpDataImpl { +public: + MTPDaudioEmpty() { + } + MTPDaudioEmpty(const MTPlong &_id) : vid(_id) { + } + + MTPlong vid; +}; + +class MTPDaudio : public mtpDataImpl { +public: + MTPDaudio() { + } + MTPDaudio(const MTPlong &_id, const MTPlong &_access_hash, MTPint _user_id, MTPint _date, MTPint _duration, const MTPstring &_mime_type, MTPint _size, MTPint _dc_id) : vid(_id), vaccess_hash(_access_hash), vuser_id(_user_id), vdate(_date), vduration(_duration), vmime_type(_mime_type), vsize(_size), vdc_id(_dc_id) { + } + + MTPlong vid; + MTPlong vaccess_hash; + MTPint vuser_id; + MTPint vdate; + MTPint vduration; + MTPstring vmime_type; + MTPint vsize; + MTPint vdc_id; +}; + +class MTPDdocumentEmpty : public mtpDataImpl { +public: + MTPDdocumentEmpty() { + } + MTPDdocumentEmpty(const MTPlong &_id) : vid(_id) { + } + + MTPlong vid; +}; + +class MTPDdocument : public mtpDataImpl { +public: + MTPDdocument() { + } + MTPDdocument(const MTPlong &_id, const MTPlong &_access_hash, MTPint _user_id, MTPint _date, const MTPstring &_file_name, const MTPstring &_mime_type, MTPint _size, const MTPPhotoSize &_thumb, MTPint _dc_id) : vid(_id), vaccess_hash(_access_hash), vuser_id(_user_id), vdate(_date), vfile_name(_file_name), vmime_type(_mime_type), vsize(_size), vthumb(_thumb), vdc_id(_dc_id) { + } + + MTPlong vid; + MTPlong vaccess_hash; + MTPint vuser_id; + MTPint vdate; + MTPstring vfile_name; + MTPstring vmime_type; + MTPint vsize; + MTPPhotoSize vthumb; + MTPint vdc_id; +}; + +class MTPDhelp_support : public mtpDataImpl { +public: + MTPDhelp_support() { + } + MTPDhelp_support(const MTPstring &_phone_number, const MTPUser &_user) : vphone_number(_phone_number), vuser(_user) { + } + + MTPstring vphone_number; + MTPUser vuser; +}; + +class MTPDnotifyPeer : public mtpDataImpl { +public: + MTPDnotifyPeer() { + } + MTPDnotifyPeer(const MTPPeer &_peer) : vpeer(_peer) { + } + + MTPPeer vpeer; +}; + +// RPC methods + +class MTPreq_pq { // RPC method 'req_pq' +public: + MTPint128 vnonce; + + MTPreq_pq() { + } + MTPreq_pq(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_req_pq) { + read(from, end, cons); + } + MTPreq_pq(const MTPint128 &_nonce) : vnonce(_nonce) { + } + + uint32 size() const { + return vnonce.size(); + } + mtpTypeId type() const { + return mtpc_req_pq; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_req_pq) { + vnonce.read(from, end); + } + void write(mtpBuffer &to) const { + vnonce.write(to); + } + + typedef MTPResPQ ResponseType; +}; +class MTPReq_pq : public MTPBoxed { +public: + MTPReq_pq() { + } + MTPReq_pq(const MTPreq_pq &v) : MTPBoxed(v) { + } + MTPReq_pq(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPReq_pq(const MTPint128 &_nonce) : MTPBoxed(MTPreq_pq(_nonce)) { + } +}; + +class MTPreq_DH_params { // RPC method 'req_DH_params' +public: + MTPint128 vnonce; + MTPint128 vserver_nonce; + MTPstring vp; + MTPstring vq; + MTPlong vpublic_key_fingerprint; + MTPstring vencrypted_data; + + MTPreq_DH_params() { + } + MTPreq_DH_params(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_req_DH_params) { + read(from, end, cons); + } + MTPreq_DH_params(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPstring &_p, const MTPstring &_q, const MTPlong &_public_key_fingerprint, const MTPstring &_encrypted_data) : vnonce(_nonce), vserver_nonce(_server_nonce), vp(_p), vq(_q), vpublic_key_fingerprint(_public_key_fingerprint), vencrypted_data(_encrypted_data) { + } + + uint32 size() const { + return vnonce.size() + vserver_nonce.size() + vp.size() + vq.size() + vpublic_key_fingerprint.size() + vencrypted_data.size(); + } + mtpTypeId type() const { + return mtpc_req_DH_params; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_req_DH_params) { + vnonce.read(from, end); + vserver_nonce.read(from, end); + vp.read(from, end); + vq.read(from, end); + vpublic_key_fingerprint.read(from, end); + vencrypted_data.read(from, end); + } + void write(mtpBuffer &to) const { + vnonce.write(to); + vserver_nonce.write(to); + vp.write(to); + vq.write(to); + vpublic_key_fingerprint.write(to); + vencrypted_data.write(to); + } + + typedef MTPServer_DH_Params ResponseType; +}; +class MTPReq_DH_params : public MTPBoxed { +public: + MTPReq_DH_params() { + } + MTPReq_DH_params(const MTPreq_DH_params &v) : MTPBoxed(v) { + } + MTPReq_DH_params(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPReq_DH_params(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPstring &_p, const MTPstring &_q, const MTPlong &_public_key_fingerprint, const MTPstring &_encrypted_data) : MTPBoxed(MTPreq_DH_params(_nonce, _server_nonce, _p, _q, _public_key_fingerprint, _encrypted_data)) { + } +}; + +class MTPset_client_DH_params { // RPC method 'set_client_DH_params' +public: + MTPint128 vnonce; + MTPint128 vserver_nonce; + MTPstring vencrypted_data; + + MTPset_client_DH_params() { + } + MTPset_client_DH_params(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_set_client_DH_params) { + read(from, end, cons); + } + MTPset_client_DH_params(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPstring &_encrypted_data) : vnonce(_nonce), vserver_nonce(_server_nonce), vencrypted_data(_encrypted_data) { + } + + uint32 size() const { + return vnonce.size() + vserver_nonce.size() + vencrypted_data.size(); + } + mtpTypeId type() const { + return mtpc_set_client_DH_params; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_set_client_DH_params) { + vnonce.read(from, end); + vserver_nonce.read(from, end); + vencrypted_data.read(from, end); + } + void write(mtpBuffer &to) const { + vnonce.write(to); + vserver_nonce.write(to); + vencrypted_data.write(to); + } + + typedef MTPSet_client_DH_params_answer ResponseType; +}; +class MTPSet_client_DH_params : public MTPBoxed { +public: + MTPSet_client_DH_params() { + } + MTPSet_client_DH_params(const MTPset_client_DH_params &v) : MTPBoxed(v) { + } + MTPSet_client_DH_params(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPSet_client_DH_params(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPstring &_encrypted_data) : MTPBoxed(MTPset_client_DH_params(_nonce, _server_nonce, _encrypted_data)) { + } +}; + +class MTPrpc_drop_answer { // RPC method 'rpc_drop_answer' +public: + MTPlong vreq_msg_id; + + MTPrpc_drop_answer() { + } + MTPrpc_drop_answer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_rpc_drop_answer) { + read(from, end, cons); + } + MTPrpc_drop_answer(const MTPlong &_req_msg_id) : vreq_msg_id(_req_msg_id) { + } + + uint32 size() const { + return vreq_msg_id.size(); + } + mtpTypeId type() const { + return mtpc_rpc_drop_answer; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_rpc_drop_answer) { + vreq_msg_id.read(from, end); + } + void write(mtpBuffer &to) const { + vreq_msg_id.write(to); + } + + typedef MTPRpcDropAnswer ResponseType; +}; +class MTPRpc_drop_answer : public MTPBoxed { +public: + MTPRpc_drop_answer() { + } + MTPRpc_drop_answer(const MTPrpc_drop_answer &v) : MTPBoxed(v) { + } + MTPRpc_drop_answer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPRpc_drop_answer(const MTPlong &_req_msg_id) : MTPBoxed(MTPrpc_drop_answer(_req_msg_id)) { + } +}; + +class MTPget_future_salts { // RPC method 'get_future_salts' +public: + MTPint vnum; + + MTPget_future_salts() { + } + MTPget_future_salts(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_get_future_salts) { + read(from, end, cons); + } + MTPget_future_salts(MTPint _num) : vnum(_num) { + } + + uint32 size() const { + return vnum.size(); + } + mtpTypeId type() const { + return mtpc_get_future_salts; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_get_future_salts) { + vnum.read(from, end); + } + void write(mtpBuffer &to) const { + vnum.write(to); + } + + typedef MTPFutureSalts ResponseType; +}; +class MTPGet_future_salts : public MTPBoxed { +public: + MTPGet_future_salts() { + } + MTPGet_future_salts(const MTPget_future_salts &v) : MTPBoxed(v) { + } + MTPGet_future_salts(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPGet_future_salts(MTPint _num) : MTPBoxed(MTPget_future_salts(_num)) { + } +}; + +class MTPping { // RPC method 'ping' +public: + MTPlong vping_id; + + MTPping() { + } + MTPping(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_ping) { + read(from, end, cons); + } + MTPping(const MTPlong &_ping_id) : vping_id(_ping_id) { + } + + uint32 size() const { + return vping_id.size(); + } + mtpTypeId type() const { + return mtpc_ping; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_ping) { + vping_id.read(from, end); + } + void write(mtpBuffer &to) const { + vping_id.write(to); + } + + typedef MTPPong ResponseType; +}; +class MTPPing : public MTPBoxed { +public: + MTPPing() { + } + MTPPing(const MTPping &v) : MTPBoxed(v) { + } + MTPPing(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPPing(const MTPlong &_ping_id) : MTPBoxed(MTPping(_ping_id)) { + } +}; + +class MTPping_delay_disconnect { // RPC method 'ping_delay_disconnect' +public: + MTPlong vping_id; + MTPint vdisconnect_delay; + + MTPping_delay_disconnect() { + } + MTPping_delay_disconnect(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_ping_delay_disconnect) { + read(from, end, cons); + } + MTPping_delay_disconnect(const MTPlong &_ping_id, MTPint _disconnect_delay) : vping_id(_ping_id), vdisconnect_delay(_disconnect_delay) { + } + + uint32 size() const { + return vping_id.size() + vdisconnect_delay.size(); + } + mtpTypeId type() const { + return mtpc_ping_delay_disconnect; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_ping_delay_disconnect) { + vping_id.read(from, end); + vdisconnect_delay.read(from, end); + } + void write(mtpBuffer &to) const { + vping_id.write(to); + vdisconnect_delay.write(to); + } + + typedef MTPPong ResponseType; +}; +class MTPPing_delay_disconnect : public MTPBoxed { +public: + MTPPing_delay_disconnect() { + } + MTPPing_delay_disconnect(const MTPping_delay_disconnect &v) : MTPBoxed(v) { + } + MTPPing_delay_disconnect(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPPing_delay_disconnect(const MTPlong &_ping_id, MTPint _disconnect_delay) : MTPBoxed(MTPping_delay_disconnect(_ping_id, _disconnect_delay)) { + } +}; + +class MTPdestroy_session { // RPC method 'destroy_session' +public: + MTPlong vsession_id; + + MTPdestroy_session() { + } + MTPdestroy_session(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_destroy_session) { + read(from, end, cons); + } + MTPdestroy_session(const MTPlong &_session_id) : vsession_id(_session_id) { + } + + uint32 size() const { + return vsession_id.size(); + } + mtpTypeId type() const { + return mtpc_destroy_session; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_destroy_session) { + vsession_id.read(from, end); + } + void write(mtpBuffer &to) const { + vsession_id.write(to); + } + + typedef MTPDestroySessionRes ResponseType; +}; +class MTPDestroy_session : public MTPBoxed { +public: + MTPDestroy_session() { + } + MTPDestroy_session(const MTPdestroy_session &v) : MTPBoxed(v) { + } + MTPDestroy_session(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPDestroy_session(const MTPlong &_session_id) : MTPBoxed(MTPdestroy_session(_session_id)) { + } +}; + +class MTPregister_saveDeveloperInfo { // RPC method 'register.saveDeveloperInfo' +public: + MTPstring vname; + MTPstring vemail; + MTPstring vphone_number; + MTPint vage; + MTPstring vcity; + + MTPregister_saveDeveloperInfo() { + } + MTPregister_saveDeveloperInfo(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_register_saveDeveloperInfo) { + read(from, end, cons); + } + MTPregister_saveDeveloperInfo(const MTPstring &_name, const MTPstring &_email, const MTPstring &_phone_number, MTPint _age, const MTPstring &_city) : vname(_name), vemail(_email), vphone_number(_phone_number), vage(_age), vcity(_city) { + } + + uint32 size() const { + return vname.size() + vemail.size() + vphone_number.size() + vage.size() + vcity.size(); + } + mtpTypeId type() const { + return mtpc_register_saveDeveloperInfo; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_register_saveDeveloperInfo) { + vname.read(from, end); + vemail.read(from, end); + vphone_number.read(from, end); + vage.read(from, end); + vcity.read(from, end); + } + void write(mtpBuffer &to) const { + vname.write(to); + vemail.write(to); + vphone_number.write(to); + vage.write(to); + vcity.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPregister_SaveDeveloperInfo : public MTPBoxed { +public: + MTPregister_SaveDeveloperInfo() { + } + MTPregister_SaveDeveloperInfo(const MTPregister_saveDeveloperInfo &v) : MTPBoxed(v) { + } + MTPregister_SaveDeveloperInfo(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPregister_SaveDeveloperInfo(const MTPstring &_name, const MTPstring &_email, const MTPstring &_phone_number, MTPint _age, const MTPstring &_city) : MTPBoxed(MTPregister_saveDeveloperInfo(_name, _email, _phone_number, _age, _city)) { + } +}; + +template +class MTPinvokeAfterMsg { // RPC method 'invokeAfterMsg' +public: + MTPlong vmsg_id; + TQueryType vquery; + + MTPinvokeAfterMsg() { + } + MTPinvokeAfterMsg(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_invokeAfterMsg) { + read(from, end, cons); + } + MTPinvokeAfterMsg(const MTPlong &_msg_id, const TQueryType &_query) : vmsg_id(_msg_id), vquery(_query) { + } + + uint32 size() const { + return vmsg_id.size() + vquery.size(); + } + mtpTypeId type() const { + return mtpc_invokeAfterMsg; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_invokeAfterMsg) { + vmsg_id.read(from, end); + vquery.read(from, end); + } + void write(mtpBuffer &to) const { + vmsg_id.write(to); + vquery.write(to); + } + + typedef typename TQueryType::ResponseType ResponseType; +}; +template +class MTPInvokeAfterMsg : public MTPBoxed > { +public: + MTPInvokeAfterMsg() { + } + MTPInvokeAfterMsg(const MTPinvokeAfterMsg &v) : MTPBoxed >(v) { + } + MTPInvokeAfterMsg(const MTPlong &_msg_id, const TQueryType &_query) : MTPBoxed >(MTPinvokeAfterMsg(_msg_id, _query)) { + } +}; + +template +class MTPinvokeAfterMsgs { // RPC method 'invokeAfterMsgs' +public: + MTPVector vmsg_ids; + TQueryType vquery; + + MTPinvokeAfterMsgs() { + } + MTPinvokeAfterMsgs(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_invokeAfterMsgs) { + read(from, end, cons); + } + MTPinvokeAfterMsgs(const MTPVector &_msg_ids, const TQueryType &_query) : vmsg_ids(_msg_ids), vquery(_query) { + } + + uint32 size() const { + return vmsg_ids.size() + vquery.size(); + } + mtpTypeId type() const { + return mtpc_invokeAfterMsgs; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_invokeAfterMsgs) { + vmsg_ids.read(from, end); + vquery.read(from, end); + } + void write(mtpBuffer &to) const { + vmsg_ids.write(to); + vquery.write(to); + } + + typedef typename TQueryType::ResponseType ResponseType; +}; +template +class MTPInvokeAfterMsgs : public MTPBoxed > { +public: + MTPInvokeAfterMsgs() { + } + MTPInvokeAfterMsgs(const MTPinvokeAfterMsgs &v) : MTPBoxed >(v) { + } + MTPInvokeAfterMsgs(const MTPVector &_msg_ids, const TQueryType &_query) : MTPBoxed >(MTPinvokeAfterMsgs(_msg_ids, _query)) { + } +}; + +class MTPauth_checkPhone { // RPC method 'auth.checkPhone' +public: + MTPstring vphone_number; + + MTPauth_checkPhone() { + } + MTPauth_checkPhone(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_checkPhone) { + read(from, end, cons); + } + MTPauth_checkPhone(const MTPstring &_phone_number) : vphone_number(_phone_number) { + } + + uint32 size() const { + return vphone_number.size(); + } + mtpTypeId type() const { + return mtpc_auth_checkPhone; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_checkPhone) { + vphone_number.read(from, end); + } + void write(mtpBuffer &to) const { + vphone_number.write(to); + } + + typedef MTPauth_CheckedPhone ResponseType; +}; +class MTPauth_CheckPhone : public MTPBoxed { +public: + MTPauth_CheckPhone() { + } + MTPauth_CheckPhone(const MTPauth_checkPhone &v) : MTPBoxed(v) { + } + MTPauth_CheckPhone(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPauth_CheckPhone(const MTPstring &_phone_number) : MTPBoxed(MTPauth_checkPhone(_phone_number)) { + } +}; + +class MTPauth_sendCode { // RPC method 'auth.sendCode' +public: + MTPstring vphone_number; + MTPint vsms_type; + MTPint vapi_id; + MTPstring vapi_hash; + MTPstring vlang_code; + + MTPauth_sendCode() { + } + MTPauth_sendCode(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_sendCode) { + read(from, end, cons); + } + MTPauth_sendCode(const MTPstring &_phone_number, MTPint _sms_type, MTPint _api_id, const MTPstring &_api_hash, const MTPstring &_lang_code) : vphone_number(_phone_number), vsms_type(_sms_type), vapi_id(_api_id), vapi_hash(_api_hash), vlang_code(_lang_code) { + } + + uint32 size() const { + return vphone_number.size() + vsms_type.size() + vapi_id.size() + vapi_hash.size() + vlang_code.size(); + } + mtpTypeId type() const { + return mtpc_auth_sendCode; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_sendCode) { + vphone_number.read(from, end); + vsms_type.read(from, end); + vapi_id.read(from, end); + vapi_hash.read(from, end); + vlang_code.read(from, end); + } + void write(mtpBuffer &to) const { + vphone_number.write(to); + vsms_type.write(to); + vapi_id.write(to); + vapi_hash.write(to); + vlang_code.write(to); + } + + typedef MTPauth_SentCode ResponseType; +}; +class MTPauth_SendCode : public MTPBoxed { +public: + MTPauth_SendCode() { + } + MTPauth_SendCode(const MTPauth_sendCode &v) : MTPBoxed(v) { + } + MTPauth_SendCode(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPauth_SendCode(const MTPstring &_phone_number, MTPint _sms_type, MTPint _api_id, const MTPstring &_api_hash, const MTPstring &_lang_code) : MTPBoxed(MTPauth_sendCode(_phone_number, _sms_type, _api_id, _api_hash, _lang_code)) { + } +}; + +class MTPauth_sendCall { // RPC method 'auth.sendCall' +public: + MTPstring vphone_number; + MTPstring vphone_code_hash; + + MTPauth_sendCall() { + } + MTPauth_sendCall(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_sendCall) { + read(from, end, cons); + } + MTPauth_sendCall(const MTPstring &_phone_number, const MTPstring &_phone_code_hash) : vphone_number(_phone_number), vphone_code_hash(_phone_code_hash) { + } + + uint32 size() const { + return vphone_number.size() + vphone_code_hash.size(); + } + mtpTypeId type() const { + return mtpc_auth_sendCall; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_sendCall) { + vphone_number.read(from, end); + vphone_code_hash.read(from, end); + } + void write(mtpBuffer &to) const { + vphone_number.write(to); + vphone_code_hash.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPauth_SendCall : public MTPBoxed { +public: + MTPauth_SendCall() { + } + MTPauth_SendCall(const MTPauth_sendCall &v) : MTPBoxed(v) { + } + MTPauth_SendCall(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPauth_SendCall(const MTPstring &_phone_number, const MTPstring &_phone_code_hash) : MTPBoxed(MTPauth_sendCall(_phone_number, _phone_code_hash)) { + } +}; + +class MTPauth_signUp { // RPC method 'auth.signUp' +public: + MTPstring vphone_number; + MTPstring vphone_code_hash; + MTPstring vphone_code; + MTPstring vfirst_name; + MTPstring vlast_name; + + MTPauth_signUp() { + } + MTPauth_signUp(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_signUp) { + read(from, end, cons); + } + MTPauth_signUp(const MTPstring &_phone_number, const MTPstring &_phone_code_hash, const MTPstring &_phone_code, const MTPstring &_first_name, const MTPstring &_last_name) : vphone_number(_phone_number), vphone_code_hash(_phone_code_hash), vphone_code(_phone_code), vfirst_name(_first_name), vlast_name(_last_name) { + } + + uint32 size() const { + return vphone_number.size() + vphone_code_hash.size() + vphone_code.size() + vfirst_name.size() + vlast_name.size(); + } + mtpTypeId type() const { + return mtpc_auth_signUp; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_signUp) { + vphone_number.read(from, end); + vphone_code_hash.read(from, end); + vphone_code.read(from, end); + vfirst_name.read(from, end); + vlast_name.read(from, end); + } + void write(mtpBuffer &to) const { + vphone_number.write(to); + vphone_code_hash.write(to); + vphone_code.write(to); + vfirst_name.write(to); + vlast_name.write(to); + } + + typedef MTPauth_Authorization ResponseType; +}; +class MTPauth_SignUp : public MTPBoxed { +public: + MTPauth_SignUp() { + } + MTPauth_SignUp(const MTPauth_signUp &v) : MTPBoxed(v) { + } + MTPauth_SignUp(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPauth_SignUp(const MTPstring &_phone_number, const MTPstring &_phone_code_hash, const MTPstring &_phone_code, const MTPstring &_first_name, const MTPstring &_last_name) : MTPBoxed(MTPauth_signUp(_phone_number, _phone_code_hash, _phone_code, _first_name, _last_name)) { + } +}; + +class MTPauth_signIn { // RPC method 'auth.signIn' +public: + MTPstring vphone_number; + MTPstring vphone_code_hash; + MTPstring vphone_code; + + MTPauth_signIn() { + } + MTPauth_signIn(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_signIn) { + read(from, end, cons); + } + MTPauth_signIn(const MTPstring &_phone_number, const MTPstring &_phone_code_hash, const MTPstring &_phone_code) : vphone_number(_phone_number), vphone_code_hash(_phone_code_hash), vphone_code(_phone_code) { + } + + uint32 size() const { + return vphone_number.size() + vphone_code_hash.size() + vphone_code.size(); + } + mtpTypeId type() const { + return mtpc_auth_signIn; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_signIn) { + vphone_number.read(from, end); + vphone_code_hash.read(from, end); + vphone_code.read(from, end); + } + void write(mtpBuffer &to) const { + vphone_number.write(to); + vphone_code_hash.write(to); + vphone_code.write(to); + } + + typedef MTPauth_Authorization ResponseType; +}; +class MTPauth_SignIn : public MTPBoxed { +public: + MTPauth_SignIn() { + } + MTPauth_SignIn(const MTPauth_signIn &v) : MTPBoxed(v) { + } + MTPauth_SignIn(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPauth_SignIn(const MTPstring &_phone_number, const MTPstring &_phone_code_hash, const MTPstring &_phone_code) : MTPBoxed(MTPauth_signIn(_phone_number, _phone_code_hash, _phone_code)) { + } +}; + +class MTPauth_logOut { // RPC method 'auth.logOut' +public: + MTPauth_logOut() { + } + MTPauth_logOut(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_logOut) { + read(from, end, cons); + } + + uint32 size() const { + return 0; + } + mtpTypeId type() const { + return mtpc_auth_logOut; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_logOut) { + } + void write(mtpBuffer &to) const { + } + + typedef MTPBool ResponseType; +}; +class MTPauth_LogOut : public MTPBoxed { +public: + MTPauth_LogOut() { + } + MTPauth_LogOut(const MTPauth_logOut &v) : MTPBoxed(v) { + } + MTPauth_LogOut(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } +}; + +class MTPauth_resetAuthorizations { // RPC method 'auth.resetAuthorizations' +public: + MTPauth_resetAuthorizations() { + } + MTPauth_resetAuthorizations(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_resetAuthorizations) { + read(from, end, cons); + } + + uint32 size() const { + return 0; + } + mtpTypeId type() const { + return mtpc_auth_resetAuthorizations; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_resetAuthorizations) { + } + void write(mtpBuffer &to) const { + } + + typedef MTPBool ResponseType; +}; +class MTPauth_ResetAuthorizations : public MTPBoxed { +public: + MTPauth_ResetAuthorizations() { + } + MTPauth_ResetAuthorizations(const MTPauth_resetAuthorizations &v) : MTPBoxed(v) { + } + MTPauth_ResetAuthorizations(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } +}; + +class MTPauth_sendInvites { // RPC method 'auth.sendInvites' +public: + MTPVector vphone_numbers; + MTPstring vmessage; + + MTPauth_sendInvites() { + } + MTPauth_sendInvites(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_sendInvites) { + read(from, end, cons); + } + MTPauth_sendInvites(const MTPVector &_phone_numbers, const MTPstring &_message) : vphone_numbers(_phone_numbers), vmessage(_message) { + } + + uint32 size() const { + return vphone_numbers.size() + vmessage.size(); + } + mtpTypeId type() const { + return mtpc_auth_sendInvites; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_sendInvites) { + vphone_numbers.read(from, end); + vmessage.read(from, end); + } + void write(mtpBuffer &to) const { + vphone_numbers.write(to); + vmessage.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPauth_SendInvites : public MTPBoxed { +public: + MTPauth_SendInvites() { + } + MTPauth_SendInvites(const MTPauth_sendInvites &v) : MTPBoxed(v) { + } + MTPauth_SendInvites(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPauth_SendInvites(const MTPVector &_phone_numbers, const MTPstring &_message) : MTPBoxed(MTPauth_sendInvites(_phone_numbers, _message)) { + } +}; + +class MTPauth_exportAuthorization { // RPC method 'auth.exportAuthorization' +public: + MTPint vdc_id; + + MTPauth_exportAuthorization() { + } + MTPauth_exportAuthorization(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_exportAuthorization) { + read(from, end, cons); + } + MTPauth_exportAuthorization(MTPint _dc_id) : vdc_id(_dc_id) { + } + + uint32 size() const { + return vdc_id.size(); + } + mtpTypeId type() const { + return mtpc_auth_exportAuthorization; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_exportAuthorization) { + vdc_id.read(from, end); + } + void write(mtpBuffer &to) const { + vdc_id.write(to); + } + + typedef MTPauth_ExportedAuthorization ResponseType; +}; +class MTPauth_ExportAuthorization : public MTPBoxed { +public: + MTPauth_ExportAuthorization() { + } + MTPauth_ExportAuthorization(const MTPauth_exportAuthorization &v) : MTPBoxed(v) { + } + MTPauth_ExportAuthorization(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPauth_ExportAuthorization(MTPint _dc_id) : MTPBoxed(MTPauth_exportAuthorization(_dc_id)) { + } +}; + +class MTPauth_importAuthorization { // RPC method 'auth.importAuthorization' +public: + MTPint vid; + MTPbytes vbytes; + + MTPauth_importAuthorization() { + } + MTPauth_importAuthorization(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_importAuthorization) { + read(from, end, cons); + } + MTPauth_importAuthorization(MTPint _id, const MTPbytes &_bytes) : vid(_id), vbytes(_bytes) { + } + + uint32 size() const { + return vid.size() + vbytes.size(); + } + mtpTypeId type() const { + return mtpc_auth_importAuthorization; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_auth_importAuthorization) { + vid.read(from, end); + vbytes.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + vbytes.write(to); + } + + typedef MTPauth_Authorization ResponseType; +}; +class MTPauth_ImportAuthorization : public MTPBoxed { +public: + MTPauth_ImportAuthorization() { + } + MTPauth_ImportAuthorization(const MTPauth_importAuthorization &v) : MTPBoxed(v) { + } + MTPauth_ImportAuthorization(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPauth_ImportAuthorization(MTPint _id, const MTPbytes &_bytes) : MTPBoxed(MTPauth_importAuthorization(_id, _bytes)) { + } +}; + +class MTPaccount_registerDevice { // RPC method 'account.registerDevice' +public: + MTPint vtoken_type; + MTPstring vtoken; + MTPstring vdevice_model; + MTPstring vsystem_version; + MTPstring vapp_version; + MTPBool vapp_sandbox; + MTPstring vlang_code; + + MTPaccount_registerDevice() { + } + MTPaccount_registerDevice(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_registerDevice) { + read(from, end, cons); + } + MTPaccount_registerDevice(MTPint _token_type, const MTPstring &_token, const MTPstring &_device_model, const MTPstring &_system_version, const MTPstring &_app_version, MTPBool _app_sandbox, const MTPstring &_lang_code) : vtoken_type(_token_type), vtoken(_token), vdevice_model(_device_model), vsystem_version(_system_version), vapp_version(_app_version), vapp_sandbox(_app_sandbox), vlang_code(_lang_code) { + } + + uint32 size() const { + return vtoken_type.size() + vtoken.size() + vdevice_model.size() + vsystem_version.size() + vapp_version.size() + vapp_sandbox.size() + vlang_code.size(); + } + mtpTypeId type() const { + return mtpc_account_registerDevice; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_registerDevice) { + vtoken_type.read(from, end); + vtoken.read(from, end); + vdevice_model.read(from, end); + vsystem_version.read(from, end); + vapp_version.read(from, end); + vapp_sandbox.read(from, end); + vlang_code.read(from, end); + } + void write(mtpBuffer &to) const { + vtoken_type.write(to); + vtoken.write(to); + vdevice_model.write(to); + vsystem_version.write(to); + vapp_version.write(to); + vapp_sandbox.write(to); + vlang_code.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPaccount_RegisterDevice : public MTPBoxed { +public: + MTPaccount_RegisterDevice() { + } + MTPaccount_RegisterDevice(const MTPaccount_registerDevice &v) : MTPBoxed(v) { + } + MTPaccount_RegisterDevice(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPaccount_RegisterDevice(MTPint _token_type, const MTPstring &_token, const MTPstring &_device_model, const MTPstring &_system_version, const MTPstring &_app_version, MTPBool _app_sandbox, const MTPstring &_lang_code) : MTPBoxed(MTPaccount_registerDevice(_token_type, _token, _device_model, _system_version, _app_version, _app_sandbox, _lang_code)) { + } +}; + +class MTPaccount_unregisterDevice { // RPC method 'account.unregisterDevice' +public: + MTPint vtoken_type; + MTPstring vtoken; + + MTPaccount_unregisterDevice() { + } + MTPaccount_unregisterDevice(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_unregisterDevice) { + read(from, end, cons); + } + MTPaccount_unregisterDevice(MTPint _token_type, const MTPstring &_token) : vtoken_type(_token_type), vtoken(_token) { + } + + uint32 size() const { + return vtoken_type.size() + vtoken.size(); + } + mtpTypeId type() const { + return mtpc_account_unregisterDevice; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_unregisterDevice) { + vtoken_type.read(from, end); + vtoken.read(from, end); + } + void write(mtpBuffer &to) const { + vtoken_type.write(to); + vtoken.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPaccount_UnregisterDevice : public MTPBoxed { +public: + MTPaccount_UnregisterDevice() { + } + MTPaccount_UnregisterDevice(const MTPaccount_unregisterDevice &v) : MTPBoxed(v) { + } + MTPaccount_UnregisterDevice(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPaccount_UnregisterDevice(MTPint _token_type, const MTPstring &_token) : MTPBoxed(MTPaccount_unregisterDevice(_token_type, _token)) { + } +}; + +class MTPaccount_updateNotifySettings { // RPC method 'account.updateNotifySettings' +public: + MTPInputNotifyPeer vpeer; + MTPInputPeerNotifySettings vsettings; + + MTPaccount_updateNotifySettings() { + } + MTPaccount_updateNotifySettings(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_updateNotifySettings) { + read(from, end, cons); + } + MTPaccount_updateNotifySettings(const MTPInputNotifyPeer &_peer, const MTPInputPeerNotifySettings &_settings) : vpeer(_peer), vsettings(_settings) { + } + + uint32 size() const { + return vpeer.size() + vsettings.size(); + } + mtpTypeId type() const { + return mtpc_account_updateNotifySettings; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_updateNotifySettings) { + vpeer.read(from, end); + vsettings.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vsettings.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPaccount_UpdateNotifySettings : public MTPBoxed { +public: + MTPaccount_UpdateNotifySettings() { + } + MTPaccount_UpdateNotifySettings(const MTPaccount_updateNotifySettings &v) : MTPBoxed(v) { + } + MTPaccount_UpdateNotifySettings(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPaccount_UpdateNotifySettings(const MTPInputNotifyPeer &_peer, const MTPInputPeerNotifySettings &_settings) : MTPBoxed(MTPaccount_updateNotifySettings(_peer, _settings)) { + } +}; + +class MTPaccount_getNotifySettings { // RPC method 'account.getNotifySettings' +public: + MTPInputNotifyPeer vpeer; + + MTPaccount_getNotifySettings() { + } + MTPaccount_getNotifySettings(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_getNotifySettings) { + read(from, end, cons); + } + MTPaccount_getNotifySettings(const MTPInputNotifyPeer &_peer) : vpeer(_peer) { + } + + uint32 size() const { + return vpeer.size(); + } + mtpTypeId type() const { + return mtpc_account_getNotifySettings; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_getNotifySettings) { + vpeer.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + } + + typedef MTPPeerNotifySettings ResponseType; +}; +class MTPaccount_GetNotifySettings : public MTPBoxed { +public: + MTPaccount_GetNotifySettings() { + } + MTPaccount_GetNotifySettings(const MTPaccount_getNotifySettings &v) : MTPBoxed(v) { + } + MTPaccount_GetNotifySettings(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPaccount_GetNotifySettings(const MTPInputNotifyPeer &_peer) : MTPBoxed(MTPaccount_getNotifySettings(_peer)) { + } +}; + +class MTPaccount_resetNotifySettings { // RPC method 'account.resetNotifySettings' +public: + MTPaccount_resetNotifySettings() { + } + MTPaccount_resetNotifySettings(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_resetNotifySettings) { + read(from, end, cons); + } + + uint32 size() const { + return 0; + } + mtpTypeId type() const { + return mtpc_account_resetNotifySettings; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_resetNotifySettings) { + } + void write(mtpBuffer &to) const { + } + + typedef MTPBool ResponseType; +}; +class MTPaccount_ResetNotifySettings : public MTPBoxed { +public: + MTPaccount_ResetNotifySettings() { + } + MTPaccount_ResetNotifySettings(const MTPaccount_resetNotifySettings &v) : MTPBoxed(v) { + } + MTPaccount_ResetNotifySettings(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } +}; + +class MTPaccount_updateProfile { // RPC method 'account.updateProfile' +public: + MTPstring vfirst_name; + MTPstring vlast_name; + + MTPaccount_updateProfile() { + } + MTPaccount_updateProfile(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_updateProfile) { + read(from, end, cons); + } + MTPaccount_updateProfile(const MTPstring &_first_name, const MTPstring &_last_name) : vfirst_name(_first_name), vlast_name(_last_name) { + } + + uint32 size() const { + return vfirst_name.size() + vlast_name.size(); + } + mtpTypeId type() const { + return mtpc_account_updateProfile; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_updateProfile) { + vfirst_name.read(from, end); + vlast_name.read(from, end); + } + void write(mtpBuffer &to) const { + vfirst_name.write(to); + vlast_name.write(to); + } + + typedef MTPUser ResponseType; +}; +class MTPaccount_UpdateProfile : public MTPBoxed { +public: + MTPaccount_UpdateProfile() { + } + MTPaccount_UpdateProfile(const MTPaccount_updateProfile &v) : MTPBoxed(v) { + } + MTPaccount_UpdateProfile(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPaccount_UpdateProfile(const MTPstring &_first_name, const MTPstring &_last_name) : MTPBoxed(MTPaccount_updateProfile(_first_name, _last_name)) { + } +}; + +class MTPaccount_updateStatus { // RPC method 'account.updateStatus' +public: + MTPBool voffline; + + MTPaccount_updateStatus() { + } + MTPaccount_updateStatus(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_updateStatus) { + read(from, end, cons); + } + MTPaccount_updateStatus(MTPBool _offline) : voffline(_offline) { + } + + uint32 size() const { + return voffline.size(); + } + mtpTypeId type() const { + return mtpc_account_updateStatus; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_updateStatus) { + voffline.read(from, end); + } + void write(mtpBuffer &to) const { + voffline.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPaccount_UpdateStatus : public MTPBoxed { +public: + MTPaccount_UpdateStatus() { + } + MTPaccount_UpdateStatus(const MTPaccount_updateStatus &v) : MTPBoxed(v) { + } + MTPaccount_UpdateStatus(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPaccount_UpdateStatus(MTPBool _offline) : MTPBoxed(MTPaccount_updateStatus(_offline)) { + } +}; + +class MTPaccount_getWallPapers { // RPC method 'account.getWallPapers' +public: + MTPaccount_getWallPapers() { + } + MTPaccount_getWallPapers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_getWallPapers) { + read(from, end, cons); + } + + uint32 size() const { + return 0; + } + mtpTypeId type() const { + return mtpc_account_getWallPapers; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_account_getWallPapers) { + } + void write(mtpBuffer &to) const { + } + + typedef MTPVector ResponseType; +}; +class MTPaccount_GetWallPapers : public MTPBoxed { +public: + MTPaccount_GetWallPapers() { + } + MTPaccount_GetWallPapers(const MTPaccount_getWallPapers &v) : MTPBoxed(v) { + } + MTPaccount_GetWallPapers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } +}; + +class MTPusers_getUsers { // RPC method 'users.getUsers' +public: + MTPVector vid; + + MTPusers_getUsers() { + } + MTPusers_getUsers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_users_getUsers) { + read(from, end, cons); + } + MTPusers_getUsers(const MTPVector &_id) : vid(_id) { + } + + uint32 size() const { + return vid.size(); + } + mtpTypeId type() const { + return mtpc_users_getUsers; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_users_getUsers) { + vid.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + } + + typedef MTPVector ResponseType; +}; +class MTPusers_GetUsers : public MTPBoxed { +public: + MTPusers_GetUsers() { + } + MTPusers_GetUsers(const MTPusers_getUsers &v) : MTPBoxed(v) { + } + MTPusers_GetUsers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPusers_GetUsers(const MTPVector &_id) : MTPBoxed(MTPusers_getUsers(_id)) { + } +}; + +class MTPusers_getFullUser { // RPC method 'users.getFullUser' +public: + MTPInputUser vid; + + MTPusers_getFullUser() { + } + MTPusers_getFullUser(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_users_getFullUser) { + read(from, end, cons); + } + MTPusers_getFullUser(const MTPInputUser &_id) : vid(_id) { + } + + uint32 size() const { + return vid.size(); + } + mtpTypeId type() const { + return mtpc_users_getFullUser; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_users_getFullUser) { + vid.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + } + + typedef MTPUserFull ResponseType; +}; +class MTPusers_GetFullUser : public MTPBoxed { +public: + MTPusers_GetFullUser() { + } + MTPusers_GetFullUser(const MTPusers_getFullUser &v) : MTPBoxed(v) { + } + MTPusers_GetFullUser(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPusers_GetFullUser(const MTPInputUser &_id) : MTPBoxed(MTPusers_getFullUser(_id)) { + } +}; + +class MTPcontacts_getStatuses { // RPC method 'contacts.getStatuses' +public: + MTPcontacts_getStatuses() { + } + MTPcontacts_getStatuses(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_getStatuses) { + read(from, end, cons); + } + + uint32 size() const { + return 0; + } + mtpTypeId type() const { + return mtpc_contacts_getStatuses; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_getStatuses) { + } + void write(mtpBuffer &to) const { + } + + typedef MTPVector ResponseType; +}; +class MTPcontacts_GetStatuses : public MTPBoxed { +public: + MTPcontacts_GetStatuses() { + } + MTPcontacts_GetStatuses(const MTPcontacts_getStatuses &v) : MTPBoxed(v) { + } + MTPcontacts_GetStatuses(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } +}; + +class MTPcontacts_getContacts { // RPC method 'contacts.getContacts' +public: + MTPstring vhash; + + MTPcontacts_getContacts() { + } + MTPcontacts_getContacts(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_getContacts) { + read(from, end, cons); + } + MTPcontacts_getContacts(const MTPstring &_hash) : vhash(_hash) { + } + + uint32 size() const { + return vhash.size(); + } + mtpTypeId type() const { + return mtpc_contacts_getContacts; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_getContacts) { + vhash.read(from, end); + } + void write(mtpBuffer &to) const { + vhash.write(to); + } + + typedef MTPcontacts_Contacts ResponseType; +}; +class MTPcontacts_GetContacts : public MTPBoxed { +public: + MTPcontacts_GetContacts() { + } + MTPcontacts_GetContacts(const MTPcontacts_getContacts &v) : MTPBoxed(v) { + } + MTPcontacts_GetContacts(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPcontacts_GetContacts(const MTPstring &_hash) : MTPBoxed(MTPcontacts_getContacts(_hash)) { + } +}; + +class MTPcontacts_importContacts { // RPC method 'contacts.importContacts' +public: + MTPVector vcontacts; + MTPBool vreplace; + + MTPcontacts_importContacts() { + } + MTPcontacts_importContacts(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_importContacts) { + read(from, end, cons); + } + MTPcontacts_importContacts(const MTPVector &_contacts, MTPBool _replace) : vcontacts(_contacts), vreplace(_replace) { + } + + uint32 size() const { + return vcontacts.size() + vreplace.size(); + } + mtpTypeId type() const { + return mtpc_contacts_importContacts; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_importContacts) { + vcontacts.read(from, end); + vreplace.read(from, end); + } + void write(mtpBuffer &to) const { + vcontacts.write(to); + vreplace.write(to); + } + + typedef MTPcontacts_ImportedContacts ResponseType; +}; +class MTPcontacts_ImportContacts : public MTPBoxed { +public: + MTPcontacts_ImportContacts() { + } + MTPcontacts_ImportContacts(const MTPcontacts_importContacts &v) : MTPBoxed(v) { + } + MTPcontacts_ImportContacts(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPcontacts_ImportContacts(const MTPVector &_contacts, MTPBool _replace) : MTPBoxed(MTPcontacts_importContacts(_contacts, _replace)) { + } +}; + +class MTPcontacts_search { // RPC method 'contacts.search' +public: + MTPstring vq; + MTPint vlimit; + + MTPcontacts_search() { + } + MTPcontacts_search(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_search) { + read(from, end, cons); + } + MTPcontacts_search(const MTPstring &_q, MTPint _limit) : vq(_q), vlimit(_limit) { + } + + uint32 size() const { + return vq.size() + vlimit.size(); + } + mtpTypeId type() const { + return mtpc_contacts_search; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_search) { + vq.read(from, end); + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + vq.write(to); + vlimit.write(to); + } + + typedef MTPcontacts_Found ResponseType; +}; +class MTPcontacts_Search : public MTPBoxed { +public: + MTPcontacts_Search() { + } + MTPcontacts_Search(const MTPcontacts_search &v) : MTPBoxed(v) { + } + MTPcontacts_Search(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPcontacts_Search(const MTPstring &_q, MTPint _limit) : MTPBoxed(MTPcontacts_search(_q, _limit)) { + } +}; + +class MTPcontacts_getSuggested { // RPC method 'contacts.getSuggested' +public: + MTPint vlimit; + + MTPcontacts_getSuggested() { + } + MTPcontacts_getSuggested(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_getSuggested) { + read(from, end, cons); + } + MTPcontacts_getSuggested(MTPint _limit) : vlimit(_limit) { + } + + uint32 size() const { + return vlimit.size(); + } + mtpTypeId type() const { + return mtpc_contacts_getSuggested; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_getSuggested) { + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + vlimit.write(to); + } + + typedef MTPcontacts_Suggested ResponseType; +}; +class MTPcontacts_GetSuggested : public MTPBoxed { +public: + MTPcontacts_GetSuggested() { + } + MTPcontacts_GetSuggested(const MTPcontacts_getSuggested &v) : MTPBoxed(v) { + } + MTPcontacts_GetSuggested(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPcontacts_GetSuggested(MTPint _limit) : MTPBoxed(MTPcontacts_getSuggested(_limit)) { + } +}; + +class MTPcontacts_deleteContact { // RPC method 'contacts.deleteContact' +public: + MTPInputUser vid; + + MTPcontacts_deleteContact() { + } + MTPcontacts_deleteContact(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_deleteContact) { + read(from, end, cons); + } + MTPcontacts_deleteContact(const MTPInputUser &_id) : vid(_id) { + } + + uint32 size() const { + return vid.size(); + } + mtpTypeId type() const { + return mtpc_contacts_deleteContact; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_deleteContact) { + vid.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + } + + typedef MTPcontacts_Link ResponseType; +}; +class MTPcontacts_DeleteContact : public MTPBoxed { +public: + MTPcontacts_DeleteContact() { + } + MTPcontacts_DeleteContact(const MTPcontacts_deleteContact &v) : MTPBoxed(v) { + } + MTPcontacts_DeleteContact(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPcontacts_DeleteContact(const MTPInputUser &_id) : MTPBoxed(MTPcontacts_deleteContact(_id)) { + } +}; + +class MTPcontacts_deleteContacts { // RPC method 'contacts.deleteContacts' +public: + MTPVector vid; + + MTPcontacts_deleteContacts() { + } + MTPcontacts_deleteContacts(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_deleteContacts) { + read(from, end, cons); + } + MTPcontacts_deleteContacts(const MTPVector &_id) : vid(_id) { + } + + uint32 size() const { + return vid.size(); + } + mtpTypeId type() const { + return mtpc_contacts_deleteContacts; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_deleteContacts) { + vid.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPcontacts_DeleteContacts : public MTPBoxed { +public: + MTPcontacts_DeleteContacts() { + } + MTPcontacts_DeleteContacts(const MTPcontacts_deleteContacts &v) : MTPBoxed(v) { + } + MTPcontacts_DeleteContacts(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPcontacts_DeleteContacts(const MTPVector &_id) : MTPBoxed(MTPcontacts_deleteContacts(_id)) { + } +}; + +class MTPcontacts_block { // RPC method 'contacts.block' +public: + MTPInputUser vid; + + MTPcontacts_block() { + } + MTPcontacts_block(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_block) { + read(from, end, cons); + } + MTPcontacts_block(const MTPInputUser &_id) : vid(_id) { + } + + uint32 size() const { + return vid.size(); + } + mtpTypeId type() const { + return mtpc_contacts_block; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_block) { + vid.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPcontacts_Block : public MTPBoxed { +public: + MTPcontacts_Block() { + } + MTPcontacts_Block(const MTPcontacts_block &v) : MTPBoxed(v) { + } + MTPcontacts_Block(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPcontacts_Block(const MTPInputUser &_id) : MTPBoxed(MTPcontacts_block(_id)) { + } +}; + +class MTPcontacts_unblock { // RPC method 'contacts.unblock' +public: + MTPInputUser vid; + + MTPcontacts_unblock() { + } + MTPcontacts_unblock(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_unblock) { + read(from, end, cons); + } + MTPcontacts_unblock(const MTPInputUser &_id) : vid(_id) { + } + + uint32 size() const { + return vid.size(); + } + mtpTypeId type() const { + return mtpc_contacts_unblock; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_unblock) { + vid.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPcontacts_Unblock : public MTPBoxed { +public: + MTPcontacts_Unblock() { + } + MTPcontacts_Unblock(const MTPcontacts_unblock &v) : MTPBoxed(v) { + } + MTPcontacts_Unblock(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPcontacts_Unblock(const MTPInputUser &_id) : MTPBoxed(MTPcontacts_unblock(_id)) { + } +}; + +class MTPcontacts_getBlocked { // RPC method 'contacts.getBlocked' +public: + MTPint voffset; + MTPint vlimit; + + MTPcontacts_getBlocked() { + } + MTPcontacts_getBlocked(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_getBlocked) { + read(from, end, cons); + } + MTPcontacts_getBlocked(MTPint _offset, MTPint _limit) : voffset(_offset), vlimit(_limit) { + } + + uint32 size() const { + return voffset.size() + vlimit.size(); + } + mtpTypeId type() const { + return mtpc_contacts_getBlocked; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_getBlocked) { + voffset.read(from, end); + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + voffset.write(to); + vlimit.write(to); + } + + typedef MTPcontacts_Blocked ResponseType; +}; +class MTPcontacts_GetBlocked : public MTPBoxed { +public: + MTPcontacts_GetBlocked() { + } + MTPcontacts_GetBlocked(const MTPcontacts_getBlocked &v) : MTPBoxed(v) { + } + MTPcontacts_GetBlocked(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPcontacts_GetBlocked(MTPint _offset, MTPint _limit) : MTPBoxed(MTPcontacts_getBlocked(_offset, _limit)) { + } +}; + +class MTPmessages_getMessages { // RPC method 'messages.getMessages' +public: + MTPVector vid; + + MTPmessages_getMessages() { + } + MTPmessages_getMessages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getMessages) { + read(from, end, cons); + } + MTPmessages_getMessages(const MTPVector &_id) : vid(_id) { + } + + uint32 size() const { + return vid.size(); + } + mtpTypeId type() const { + return mtpc_messages_getMessages; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getMessages) { + vid.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + } + + typedef MTPmessages_Messages ResponseType; +}; +class MTPmessages_GetMessages : public MTPBoxed { +public: + MTPmessages_GetMessages() { + } + MTPmessages_GetMessages(const MTPmessages_getMessages &v) : MTPBoxed(v) { + } + MTPmessages_GetMessages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_GetMessages(const MTPVector &_id) : MTPBoxed(MTPmessages_getMessages(_id)) { + } +}; + +class MTPmessages_getDialogs { // RPC method 'messages.getDialogs' +public: + MTPint voffset; + MTPint vmax_id; + MTPint vlimit; + + MTPmessages_getDialogs() { + } + MTPmessages_getDialogs(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getDialogs) { + read(from, end, cons); + } + MTPmessages_getDialogs(MTPint _offset, MTPint _max_id, MTPint _limit) : voffset(_offset), vmax_id(_max_id), vlimit(_limit) { + } + + uint32 size() const { + return voffset.size() + vmax_id.size() + vlimit.size(); + } + mtpTypeId type() const { + return mtpc_messages_getDialogs; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getDialogs) { + voffset.read(from, end); + vmax_id.read(from, end); + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + voffset.write(to); + vmax_id.write(to); + vlimit.write(to); + } + + typedef MTPmessages_Dialogs ResponseType; +}; +class MTPmessages_GetDialogs : public MTPBoxed { +public: + MTPmessages_GetDialogs() { + } + MTPmessages_GetDialogs(const MTPmessages_getDialogs &v) : MTPBoxed(v) { + } + MTPmessages_GetDialogs(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_GetDialogs(MTPint _offset, MTPint _max_id, MTPint _limit) : MTPBoxed(MTPmessages_getDialogs(_offset, _max_id, _limit)) { + } +}; + +class MTPmessages_getHistory { // RPC method 'messages.getHistory' +public: + MTPInputPeer vpeer; + MTPint voffset; + MTPint vmax_id; + MTPint vlimit; + + MTPmessages_getHistory() { + } + MTPmessages_getHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getHistory) { + read(from, end, cons); + } + MTPmessages_getHistory(const MTPInputPeer &_peer, MTPint _offset, MTPint _max_id, MTPint _limit) : vpeer(_peer), voffset(_offset), vmax_id(_max_id), vlimit(_limit) { + } + + uint32 size() const { + return vpeer.size() + voffset.size() + vmax_id.size() + vlimit.size(); + } + mtpTypeId type() const { + return mtpc_messages_getHistory; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getHistory) { + vpeer.read(from, end); + voffset.read(from, end); + vmax_id.read(from, end); + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + voffset.write(to); + vmax_id.write(to); + vlimit.write(to); + } + + typedef MTPmessages_Messages ResponseType; +}; +class MTPmessages_GetHistory : public MTPBoxed { +public: + MTPmessages_GetHistory() { + } + MTPmessages_GetHistory(const MTPmessages_getHistory &v) : MTPBoxed(v) { + } + MTPmessages_GetHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_GetHistory(const MTPInputPeer &_peer, MTPint _offset, MTPint _max_id, MTPint _limit) : MTPBoxed(MTPmessages_getHistory(_peer, _offset, _max_id, _limit)) { + } +}; + +class MTPmessages_search { // RPC method 'messages.search' +public: + MTPInputPeer vpeer; + MTPstring vq; + MTPMessagesFilter vfilter; + MTPint vmin_date; + MTPint vmax_date; + MTPint voffset; + MTPint vmax_id; + MTPint vlimit; + + MTPmessages_search() { + } + MTPmessages_search(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_search) { + read(from, end, cons); + } + MTPmessages_search(const MTPInputPeer &_peer, const MTPstring &_q, const MTPMessagesFilter &_filter, MTPint _min_date, MTPint _max_date, MTPint _offset, MTPint _max_id, MTPint _limit) : vpeer(_peer), vq(_q), vfilter(_filter), vmin_date(_min_date), vmax_date(_max_date), voffset(_offset), vmax_id(_max_id), vlimit(_limit) { + } + + uint32 size() const { + return vpeer.size() + vq.size() + vfilter.size() + vmin_date.size() + vmax_date.size() + voffset.size() + vmax_id.size() + vlimit.size(); + } + mtpTypeId type() const { + return mtpc_messages_search; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_search) { + vpeer.read(from, end); + vq.read(from, end); + vfilter.read(from, end); + vmin_date.read(from, end); + vmax_date.read(from, end); + voffset.read(from, end); + vmax_id.read(from, end); + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vq.write(to); + vfilter.write(to); + vmin_date.write(to); + vmax_date.write(to); + voffset.write(to); + vmax_id.write(to); + vlimit.write(to); + } + + typedef MTPmessages_Messages ResponseType; +}; +class MTPmessages_Search : public MTPBoxed { +public: + MTPmessages_Search() { + } + MTPmessages_Search(const MTPmessages_search &v) : MTPBoxed(v) { + } + MTPmessages_Search(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_Search(const MTPInputPeer &_peer, const MTPstring &_q, const MTPMessagesFilter &_filter, MTPint _min_date, MTPint _max_date, MTPint _offset, MTPint _max_id, MTPint _limit) : MTPBoxed(MTPmessages_search(_peer, _q, _filter, _min_date, _max_date, _offset, _max_id, _limit)) { + } +}; + +class MTPmessages_readHistory { // RPC method 'messages.readHistory' +public: + MTPInputPeer vpeer; + MTPint vmax_id; + MTPint voffset; + + MTPmessages_readHistory() { + } + MTPmessages_readHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_readHistory) { + read(from, end, cons); + } + MTPmessages_readHistory(const MTPInputPeer &_peer, MTPint _max_id, MTPint _offset) : vpeer(_peer), vmax_id(_max_id), voffset(_offset) { + } + + uint32 size() const { + return vpeer.size() + vmax_id.size() + voffset.size(); + } + mtpTypeId type() const { + return mtpc_messages_readHistory; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_readHistory) { + vpeer.read(from, end); + vmax_id.read(from, end); + voffset.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vmax_id.write(to); + voffset.write(to); + } + + typedef MTPmessages_AffectedHistory ResponseType; +}; +class MTPmessages_ReadHistory : public MTPBoxed { +public: + MTPmessages_ReadHistory() { + } + MTPmessages_ReadHistory(const MTPmessages_readHistory &v) : MTPBoxed(v) { + } + MTPmessages_ReadHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_ReadHistory(const MTPInputPeer &_peer, MTPint _max_id, MTPint _offset) : MTPBoxed(MTPmessages_readHistory(_peer, _max_id, _offset)) { + } +}; + +class MTPmessages_deleteHistory { // RPC method 'messages.deleteHistory' +public: + MTPInputPeer vpeer; + MTPint voffset; + + MTPmessages_deleteHistory() { + } + MTPmessages_deleteHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_deleteHistory) { + read(from, end, cons); + } + MTPmessages_deleteHistory(const MTPInputPeer &_peer, MTPint _offset) : vpeer(_peer), voffset(_offset) { + } + + uint32 size() const { + return vpeer.size() + voffset.size(); + } + mtpTypeId type() const { + return mtpc_messages_deleteHistory; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_deleteHistory) { + vpeer.read(from, end); + voffset.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + voffset.write(to); + } + + typedef MTPmessages_AffectedHistory ResponseType; +}; +class MTPmessages_DeleteHistory : public MTPBoxed { +public: + MTPmessages_DeleteHistory() { + } + MTPmessages_DeleteHistory(const MTPmessages_deleteHistory &v) : MTPBoxed(v) { + } + MTPmessages_DeleteHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_DeleteHistory(const MTPInputPeer &_peer, MTPint _offset) : MTPBoxed(MTPmessages_deleteHistory(_peer, _offset)) { + } +}; + +class MTPmessages_deleteMessages { // RPC method 'messages.deleteMessages' +public: + MTPVector vid; + + MTPmessages_deleteMessages() { + } + MTPmessages_deleteMessages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_deleteMessages) { + read(from, end, cons); + } + MTPmessages_deleteMessages(const MTPVector &_id) : vid(_id) { + } + + uint32 size() const { + return vid.size(); + } + mtpTypeId type() const { + return mtpc_messages_deleteMessages; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_deleteMessages) { + vid.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + } + + typedef MTPVector ResponseType; +}; +class MTPmessages_DeleteMessages : public MTPBoxed { +public: + MTPmessages_DeleteMessages() { + } + MTPmessages_DeleteMessages(const MTPmessages_deleteMessages &v) : MTPBoxed(v) { + } + MTPmessages_DeleteMessages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_DeleteMessages(const MTPVector &_id) : MTPBoxed(MTPmessages_deleteMessages(_id)) { + } +}; + +class MTPmessages_restoreMessages { // RPC method 'messages.restoreMessages' +public: + MTPVector vid; + + MTPmessages_restoreMessages() { + } + MTPmessages_restoreMessages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_restoreMessages) { + read(from, end, cons); + } + MTPmessages_restoreMessages(const MTPVector &_id) : vid(_id) { + } + + uint32 size() const { + return vid.size(); + } + mtpTypeId type() const { + return mtpc_messages_restoreMessages; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_restoreMessages) { + vid.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + } + + typedef MTPVector ResponseType; +}; +class MTPmessages_RestoreMessages : public MTPBoxed { +public: + MTPmessages_RestoreMessages() { + } + MTPmessages_RestoreMessages(const MTPmessages_restoreMessages &v) : MTPBoxed(v) { + } + MTPmessages_RestoreMessages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_RestoreMessages(const MTPVector &_id) : MTPBoxed(MTPmessages_restoreMessages(_id)) { + } +}; + +class MTPmessages_receivedMessages { // RPC method 'messages.receivedMessages' +public: + MTPint vmax_id; + + MTPmessages_receivedMessages() { + } + MTPmessages_receivedMessages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_receivedMessages) { + read(from, end, cons); + } + MTPmessages_receivedMessages(MTPint _max_id) : vmax_id(_max_id) { + } + + uint32 size() const { + return vmax_id.size(); + } + mtpTypeId type() const { + return mtpc_messages_receivedMessages; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_receivedMessages) { + vmax_id.read(from, end); + } + void write(mtpBuffer &to) const { + vmax_id.write(to); + } + + typedef MTPVector ResponseType; +}; +class MTPmessages_ReceivedMessages : public MTPBoxed { +public: + MTPmessages_ReceivedMessages() { + } + MTPmessages_ReceivedMessages(const MTPmessages_receivedMessages &v) : MTPBoxed(v) { + } + MTPmessages_ReceivedMessages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_ReceivedMessages(MTPint _max_id) : MTPBoxed(MTPmessages_receivedMessages(_max_id)) { + } +}; + +class MTPmessages_setTyping { // RPC method 'messages.setTyping' +public: + MTPInputPeer vpeer; + MTPBool vtyping; + + MTPmessages_setTyping() { + } + MTPmessages_setTyping(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setTyping) { + read(from, end, cons); + } + MTPmessages_setTyping(const MTPInputPeer &_peer, MTPBool _typing) : vpeer(_peer), vtyping(_typing) { + } + + uint32 size() const { + return vpeer.size() + vtyping.size(); + } + mtpTypeId type() const { + return mtpc_messages_setTyping; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setTyping) { + vpeer.read(from, end); + vtyping.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vtyping.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPmessages_SetTyping : public MTPBoxed { +public: + MTPmessages_SetTyping() { + } + MTPmessages_SetTyping(const MTPmessages_setTyping &v) : MTPBoxed(v) { + } + MTPmessages_SetTyping(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_SetTyping(const MTPInputPeer &_peer, MTPBool _typing) : MTPBoxed(MTPmessages_setTyping(_peer, _typing)) { + } +}; + +class MTPmessages_sendMessage { // RPC method 'messages.sendMessage' +public: + MTPInputPeer vpeer; + MTPstring vmessage; + MTPlong vrandom_id; + + MTPmessages_sendMessage() { + } + MTPmessages_sendMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_sendMessage) { + read(from, end, cons); + } + MTPmessages_sendMessage(const MTPInputPeer &_peer, const MTPstring &_message, const MTPlong &_random_id) : vpeer(_peer), vmessage(_message), vrandom_id(_random_id) { + } + + uint32 size() const { + return vpeer.size() + vmessage.size() + vrandom_id.size(); + } + mtpTypeId type() const { + return mtpc_messages_sendMessage; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_sendMessage) { + vpeer.read(from, end); + vmessage.read(from, end); + vrandom_id.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vmessage.write(to); + vrandom_id.write(to); + } + + typedef MTPmessages_SentMessage ResponseType; +}; +class MTPmessages_SendMessage : public MTPBoxed { +public: + MTPmessages_SendMessage() { + } + MTPmessages_SendMessage(const MTPmessages_sendMessage &v) : MTPBoxed(v) { + } + MTPmessages_SendMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_SendMessage(const MTPInputPeer &_peer, const MTPstring &_message, const MTPlong &_random_id) : MTPBoxed(MTPmessages_sendMessage(_peer, _message, _random_id)) { + } +}; + +class MTPmessages_sendMedia { // RPC method 'messages.sendMedia' +public: + MTPInputPeer vpeer; + MTPInputMedia vmedia; + MTPlong vrandom_id; + + MTPmessages_sendMedia() { + } + MTPmessages_sendMedia(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_sendMedia) { + read(from, end, cons); + } + MTPmessages_sendMedia(const MTPInputPeer &_peer, const MTPInputMedia &_media, const MTPlong &_random_id) : vpeer(_peer), vmedia(_media), vrandom_id(_random_id) { + } + + uint32 size() const { + return vpeer.size() + vmedia.size() + vrandom_id.size(); + } + mtpTypeId type() const { + return mtpc_messages_sendMedia; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_sendMedia) { + vpeer.read(from, end); + vmedia.read(from, end); + vrandom_id.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vmedia.write(to); + vrandom_id.write(to); + } + + typedef MTPmessages_StatedMessage ResponseType; +}; +class MTPmessages_SendMedia : public MTPBoxed { +public: + MTPmessages_SendMedia() { + } + MTPmessages_SendMedia(const MTPmessages_sendMedia &v) : MTPBoxed(v) { + } + MTPmessages_SendMedia(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_SendMedia(const MTPInputPeer &_peer, const MTPInputMedia &_media, const MTPlong &_random_id) : MTPBoxed(MTPmessages_sendMedia(_peer, _media, _random_id)) { + } +}; + +class MTPmessages_forwardMessages { // RPC method 'messages.forwardMessages' +public: + MTPInputPeer vpeer; + MTPVector vid; + + MTPmessages_forwardMessages() { + } + MTPmessages_forwardMessages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_forwardMessages) { + read(from, end, cons); + } + MTPmessages_forwardMessages(const MTPInputPeer &_peer, const MTPVector &_id) : vpeer(_peer), vid(_id) { + } + + uint32 size() const { + return vpeer.size() + vid.size(); + } + mtpTypeId type() const { + return mtpc_messages_forwardMessages; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_forwardMessages) { + vpeer.read(from, end); + vid.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vid.write(to); + } + + typedef MTPmessages_StatedMessages ResponseType; +}; +class MTPmessages_ForwardMessages : public MTPBoxed { +public: + MTPmessages_ForwardMessages() { + } + MTPmessages_ForwardMessages(const MTPmessages_forwardMessages &v) : MTPBoxed(v) { + } + MTPmessages_ForwardMessages(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_ForwardMessages(const MTPInputPeer &_peer, const MTPVector &_id) : MTPBoxed(MTPmessages_forwardMessages(_peer, _id)) { + } +}; + +class MTPmessages_getChats { // RPC method 'messages.getChats' +public: + MTPVector vid; + + MTPmessages_getChats() { + } + MTPmessages_getChats(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getChats) { + read(from, end, cons); + } + MTPmessages_getChats(const MTPVector &_id) : vid(_id) { + } + + uint32 size() const { + return vid.size(); + } + mtpTypeId type() const { + return mtpc_messages_getChats; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getChats) { + vid.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + } + + typedef MTPmessages_Chats ResponseType; +}; +class MTPmessages_GetChats : public MTPBoxed { +public: + MTPmessages_GetChats() { + } + MTPmessages_GetChats(const MTPmessages_getChats &v) : MTPBoxed(v) { + } + MTPmessages_GetChats(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_GetChats(const MTPVector &_id) : MTPBoxed(MTPmessages_getChats(_id)) { + } +}; + +class MTPmessages_getFullChat { // RPC method 'messages.getFullChat' +public: + MTPint vchat_id; + + MTPmessages_getFullChat() { + } + MTPmessages_getFullChat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getFullChat) { + read(from, end, cons); + } + MTPmessages_getFullChat(MTPint _chat_id) : vchat_id(_chat_id) { + } + + uint32 size() const { + return vchat_id.size(); + } + mtpTypeId type() const { + return mtpc_messages_getFullChat; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getFullChat) { + vchat_id.read(from, end); + } + void write(mtpBuffer &to) const { + vchat_id.write(to); + } + + typedef MTPmessages_ChatFull ResponseType; +}; +class MTPmessages_GetFullChat : public MTPBoxed { +public: + MTPmessages_GetFullChat() { + } + MTPmessages_GetFullChat(const MTPmessages_getFullChat &v) : MTPBoxed(v) { + } + MTPmessages_GetFullChat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_GetFullChat(MTPint _chat_id) : MTPBoxed(MTPmessages_getFullChat(_chat_id)) { + } +}; + +class MTPmessages_editChatTitle { // RPC method 'messages.editChatTitle' +public: + MTPint vchat_id; + MTPstring vtitle; + + MTPmessages_editChatTitle() { + } + MTPmessages_editChatTitle(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_editChatTitle) { + read(from, end, cons); + } + MTPmessages_editChatTitle(MTPint _chat_id, const MTPstring &_title) : vchat_id(_chat_id), vtitle(_title) { + } + + uint32 size() const { + return vchat_id.size() + vtitle.size(); + } + mtpTypeId type() const { + return mtpc_messages_editChatTitle; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_editChatTitle) { + vchat_id.read(from, end); + vtitle.read(from, end); + } + void write(mtpBuffer &to) const { + vchat_id.write(to); + vtitle.write(to); + } + + typedef MTPmessages_StatedMessage ResponseType; +}; +class MTPmessages_EditChatTitle : public MTPBoxed { +public: + MTPmessages_EditChatTitle() { + } + MTPmessages_EditChatTitle(const MTPmessages_editChatTitle &v) : MTPBoxed(v) { + } + MTPmessages_EditChatTitle(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_EditChatTitle(MTPint _chat_id, const MTPstring &_title) : MTPBoxed(MTPmessages_editChatTitle(_chat_id, _title)) { + } +}; + +class MTPmessages_editChatPhoto { // RPC method 'messages.editChatPhoto' +public: + MTPint vchat_id; + MTPInputChatPhoto vphoto; + + MTPmessages_editChatPhoto() { + } + MTPmessages_editChatPhoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_editChatPhoto) { + read(from, end, cons); + } + MTPmessages_editChatPhoto(MTPint _chat_id, const MTPInputChatPhoto &_photo) : vchat_id(_chat_id), vphoto(_photo) { + } + + uint32 size() const { + return vchat_id.size() + vphoto.size(); + } + mtpTypeId type() const { + return mtpc_messages_editChatPhoto; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_editChatPhoto) { + vchat_id.read(from, end); + vphoto.read(from, end); + } + void write(mtpBuffer &to) const { + vchat_id.write(to); + vphoto.write(to); + } + + typedef MTPmessages_StatedMessage ResponseType; +}; +class MTPmessages_EditChatPhoto : public MTPBoxed { +public: + MTPmessages_EditChatPhoto() { + } + MTPmessages_EditChatPhoto(const MTPmessages_editChatPhoto &v) : MTPBoxed(v) { + } + MTPmessages_EditChatPhoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_EditChatPhoto(MTPint _chat_id, const MTPInputChatPhoto &_photo) : MTPBoxed(MTPmessages_editChatPhoto(_chat_id, _photo)) { + } +}; + +class MTPmessages_addChatUser { // RPC method 'messages.addChatUser' +public: + MTPint vchat_id; + MTPInputUser vuser_id; + MTPint vfwd_limit; + + MTPmessages_addChatUser() { + } + MTPmessages_addChatUser(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_addChatUser) { + read(from, end, cons); + } + MTPmessages_addChatUser(MTPint _chat_id, const MTPInputUser &_user_id, MTPint _fwd_limit) : vchat_id(_chat_id), vuser_id(_user_id), vfwd_limit(_fwd_limit) { + } + + uint32 size() const { + return vchat_id.size() + vuser_id.size() + vfwd_limit.size(); + } + mtpTypeId type() const { + return mtpc_messages_addChatUser; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_addChatUser) { + vchat_id.read(from, end); + vuser_id.read(from, end); + vfwd_limit.read(from, end); + } + void write(mtpBuffer &to) const { + vchat_id.write(to); + vuser_id.write(to); + vfwd_limit.write(to); + } + + typedef MTPmessages_StatedMessage ResponseType; +}; +class MTPmessages_AddChatUser : public MTPBoxed { +public: + MTPmessages_AddChatUser() { + } + MTPmessages_AddChatUser(const MTPmessages_addChatUser &v) : MTPBoxed(v) { + } + MTPmessages_AddChatUser(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_AddChatUser(MTPint _chat_id, const MTPInputUser &_user_id, MTPint _fwd_limit) : MTPBoxed(MTPmessages_addChatUser(_chat_id, _user_id, _fwd_limit)) { + } +}; + +class MTPmessages_deleteChatUser { // RPC method 'messages.deleteChatUser' +public: + MTPint vchat_id; + MTPInputUser vuser_id; + + MTPmessages_deleteChatUser() { + } + MTPmessages_deleteChatUser(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_deleteChatUser) { + read(from, end, cons); + } + MTPmessages_deleteChatUser(MTPint _chat_id, const MTPInputUser &_user_id) : vchat_id(_chat_id), vuser_id(_user_id) { + } + + uint32 size() const { + return vchat_id.size() + vuser_id.size(); + } + mtpTypeId type() const { + return mtpc_messages_deleteChatUser; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_deleteChatUser) { + vchat_id.read(from, end); + vuser_id.read(from, end); + } + void write(mtpBuffer &to) const { + vchat_id.write(to); + vuser_id.write(to); + } + + typedef MTPmessages_StatedMessage ResponseType; +}; +class MTPmessages_DeleteChatUser : public MTPBoxed { +public: + MTPmessages_DeleteChatUser() { + } + MTPmessages_DeleteChatUser(const MTPmessages_deleteChatUser &v) : MTPBoxed(v) { + } + MTPmessages_DeleteChatUser(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_DeleteChatUser(MTPint _chat_id, const MTPInputUser &_user_id) : MTPBoxed(MTPmessages_deleteChatUser(_chat_id, _user_id)) { + } +}; + +class MTPmessages_createChat { // RPC method 'messages.createChat' +public: + MTPVector vusers; + MTPstring vtitle; + + MTPmessages_createChat() { + } + MTPmessages_createChat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_createChat) { + read(from, end, cons); + } + MTPmessages_createChat(const MTPVector &_users, const MTPstring &_title) : vusers(_users), vtitle(_title) { + } + + uint32 size() const { + return vusers.size() + vtitle.size(); + } + mtpTypeId type() const { + return mtpc_messages_createChat; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_createChat) { + vusers.read(from, end); + vtitle.read(from, end); + } + void write(mtpBuffer &to) const { + vusers.write(to); + vtitle.write(to); + } + + typedef MTPmessages_StatedMessage ResponseType; +}; +class MTPmessages_CreateChat : public MTPBoxed { +public: + MTPmessages_CreateChat() { + } + MTPmessages_CreateChat(const MTPmessages_createChat &v) : MTPBoxed(v) { + } + MTPmessages_CreateChat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_CreateChat(const MTPVector &_users, const MTPstring &_title) : MTPBoxed(MTPmessages_createChat(_users, _title)) { + } +}; + +class MTPupdates_getState { // RPC method 'updates.getState' +public: + MTPupdates_getState() { + } + MTPupdates_getState(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_updates_getState) { + read(from, end, cons); + } + + uint32 size() const { + return 0; + } + mtpTypeId type() const { + return mtpc_updates_getState; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_updates_getState) { + } + void write(mtpBuffer &to) const { + } + + typedef MTPupdates_State ResponseType; +}; +class MTPupdates_GetState : public MTPBoxed { +public: + MTPupdates_GetState() { + } + MTPupdates_GetState(const MTPupdates_getState &v) : MTPBoxed(v) { + } + MTPupdates_GetState(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } +}; + +class MTPupdates_getDifference { // RPC method 'updates.getDifference' +public: + MTPint vpts; + MTPint vdate; + MTPint vqts; + + MTPupdates_getDifference() { + } + MTPupdates_getDifference(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_updates_getDifference) { + read(from, end, cons); + } + MTPupdates_getDifference(MTPint _pts, MTPint _date, MTPint _qts) : vpts(_pts), vdate(_date), vqts(_qts) { + } + + uint32 size() const { + return vpts.size() + vdate.size() + vqts.size(); + } + mtpTypeId type() const { + return mtpc_updates_getDifference; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_updates_getDifference) { + vpts.read(from, end); + vdate.read(from, end); + vqts.read(from, end); + } + void write(mtpBuffer &to) const { + vpts.write(to); + vdate.write(to); + vqts.write(to); + } + + typedef MTPupdates_Difference ResponseType; +}; +class MTPupdates_GetDifference : public MTPBoxed { +public: + MTPupdates_GetDifference() { + } + MTPupdates_GetDifference(const MTPupdates_getDifference &v) : MTPBoxed(v) { + } + MTPupdates_GetDifference(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPupdates_GetDifference(MTPint _pts, MTPint _date, MTPint _qts) : MTPBoxed(MTPupdates_getDifference(_pts, _date, _qts)) { + } +}; + +class MTPphotos_updateProfilePhoto { // RPC method 'photos.updateProfilePhoto' +public: + MTPInputPhoto vid; + MTPInputPhotoCrop vcrop; + + MTPphotos_updateProfilePhoto() { + } + MTPphotos_updateProfilePhoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_photos_updateProfilePhoto) { + read(from, end, cons); + } + MTPphotos_updateProfilePhoto(const MTPInputPhoto &_id, const MTPInputPhotoCrop &_crop) : vid(_id), vcrop(_crop) { + } + + uint32 size() const { + return vid.size() + vcrop.size(); + } + mtpTypeId type() const { + return mtpc_photos_updateProfilePhoto; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_photos_updateProfilePhoto) { + vid.read(from, end); + vcrop.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + vcrop.write(to); + } + + typedef MTPUserProfilePhoto ResponseType; +}; +class MTPphotos_UpdateProfilePhoto : public MTPBoxed { +public: + MTPphotos_UpdateProfilePhoto() { + } + MTPphotos_UpdateProfilePhoto(const MTPphotos_updateProfilePhoto &v) : MTPBoxed(v) { + } + MTPphotos_UpdateProfilePhoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPphotos_UpdateProfilePhoto(const MTPInputPhoto &_id, const MTPInputPhotoCrop &_crop) : MTPBoxed(MTPphotos_updateProfilePhoto(_id, _crop)) { + } +}; + +class MTPphotos_uploadProfilePhoto { // RPC method 'photos.uploadProfilePhoto' +public: + MTPInputFile vfile; + MTPstring vcaption; + MTPInputGeoPoint vgeo_point; + MTPInputPhotoCrop vcrop; + + MTPphotos_uploadProfilePhoto() { + } + MTPphotos_uploadProfilePhoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_photos_uploadProfilePhoto) { + read(from, end, cons); + } + MTPphotos_uploadProfilePhoto(const MTPInputFile &_file, const MTPstring &_caption, const MTPInputGeoPoint &_geo_point, const MTPInputPhotoCrop &_crop) : vfile(_file), vcaption(_caption), vgeo_point(_geo_point), vcrop(_crop) { + } + + uint32 size() const { + return vfile.size() + vcaption.size() + vgeo_point.size() + vcrop.size(); + } + mtpTypeId type() const { + return mtpc_photos_uploadProfilePhoto; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_photos_uploadProfilePhoto) { + vfile.read(from, end); + vcaption.read(from, end); + vgeo_point.read(from, end); + vcrop.read(from, end); + } + void write(mtpBuffer &to) const { + vfile.write(to); + vcaption.write(to); + vgeo_point.write(to); + vcrop.write(to); + } + + typedef MTPphotos_Photo ResponseType; +}; +class MTPphotos_UploadProfilePhoto : public MTPBoxed { +public: + MTPphotos_UploadProfilePhoto() { + } + MTPphotos_UploadProfilePhoto(const MTPphotos_uploadProfilePhoto &v) : MTPBoxed(v) { + } + MTPphotos_UploadProfilePhoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPphotos_UploadProfilePhoto(const MTPInputFile &_file, const MTPstring &_caption, const MTPInputGeoPoint &_geo_point, const MTPInputPhotoCrop &_crop) : MTPBoxed(MTPphotos_uploadProfilePhoto(_file, _caption, _geo_point, _crop)) { + } +}; + +class MTPupload_saveFilePart { // RPC method 'upload.saveFilePart' +public: + MTPlong vfile_id; + MTPint vfile_part; + MTPbytes vbytes; + + MTPupload_saveFilePart() { + } + MTPupload_saveFilePart(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_upload_saveFilePart) { + read(from, end, cons); + } + MTPupload_saveFilePart(const MTPlong &_file_id, MTPint _file_part, const MTPbytes &_bytes) : vfile_id(_file_id), vfile_part(_file_part), vbytes(_bytes) { + } + + uint32 size() const { + return vfile_id.size() + vfile_part.size() + vbytes.size(); + } + mtpTypeId type() const { + return mtpc_upload_saveFilePart; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_upload_saveFilePart) { + vfile_id.read(from, end); + vfile_part.read(from, end); + vbytes.read(from, end); + } + void write(mtpBuffer &to) const { + vfile_id.write(to); + vfile_part.write(to); + vbytes.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPupload_SaveFilePart : public MTPBoxed { +public: + MTPupload_SaveFilePart() { + } + MTPupload_SaveFilePart(const MTPupload_saveFilePart &v) : MTPBoxed(v) { + } + MTPupload_SaveFilePart(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPupload_SaveFilePart(const MTPlong &_file_id, MTPint _file_part, const MTPbytes &_bytes) : MTPBoxed(MTPupload_saveFilePart(_file_id, _file_part, _bytes)) { + } +}; + +class MTPupload_getFile { // RPC method 'upload.getFile' +public: + MTPInputFileLocation vlocation; + MTPint voffset; + MTPint vlimit; + + MTPupload_getFile() { + } + MTPupload_getFile(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_upload_getFile) { + read(from, end, cons); + } + MTPupload_getFile(const MTPInputFileLocation &_location, MTPint _offset, MTPint _limit) : vlocation(_location), voffset(_offset), vlimit(_limit) { + } + + uint32 size() const { + return vlocation.size() + voffset.size() + vlimit.size(); + } + mtpTypeId type() const { + return mtpc_upload_getFile; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_upload_getFile) { + vlocation.read(from, end); + voffset.read(from, end); + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + vlocation.write(to); + voffset.write(to); + vlimit.write(to); + } + + typedef MTPupload_File ResponseType; +}; +class MTPupload_GetFile : public MTPBoxed { +public: + MTPupload_GetFile() { + } + MTPupload_GetFile(const MTPupload_getFile &v) : MTPBoxed(v) { + } + MTPupload_GetFile(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPupload_GetFile(const MTPInputFileLocation &_location, MTPint _offset, MTPint _limit) : MTPBoxed(MTPupload_getFile(_location, _offset, _limit)) { + } +}; + +class MTPhelp_getConfig { // RPC method 'help.getConfig' +public: + MTPhelp_getConfig() { + } + MTPhelp_getConfig(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_getConfig) { + read(from, end, cons); + } + + uint32 size() const { + return 0; + } + mtpTypeId type() const { + return mtpc_help_getConfig; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_getConfig) { + } + void write(mtpBuffer &to) const { + } + + typedef MTPConfig ResponseType; +}; +class MTPhelp_GetConfig : public MTPBoxed { +public: + MTPhelp_GetConfig() { + } + MTPhelp_GetConfig(const MTPhelp_getConfig &v) : MTPBoxed(v) { + } + MTPhelp_GetConfig(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } +}; + +class MTPhelp_getNearestDc { // RPC method 'help.getNearestDc' +public: + MTPhelp_getNearestDc() { + } + MTPhelp_getNearestDc(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_getNearestDc) { + read(from, end, cons); + } + + uint32 size() const { + return 0; + } + mtpTypeId type() const { + return mtpc_help_getNearestDc; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_getNearestDc) { + } + void write(mtpBuffer &to) const { + } + + typedef MTPNearestDc ResponseType; +}; +class MTPhelp_GetNearestDc : public MTPBoxed { +public: + MTPhelp_GetNearestDc() { + } + MTPhelp_GetNearestDc(const MTPhelp_getNearestDc &v) : MTPBoxed(v) { + } + MTPhelp_GetNearestDc(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } +}; + +class MTPhelp_getAppUpdate { // RPC method 'help.getAppUpdate' +public: + MTPstring vdevice_model; + MTPstring vsystem_version; + MTPstring vapp_version; + MTPstring vlang_code; + + MTPhelp_getAppUpdate() { + } + MTPhelp_getAppUpdate(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_getAppUpdate) { + read(from, end, cons); + } + MTPhelp_getAppUpdate(const MTPstring &_device_model, const MTPstring &_system_version, const MTPstring &_app_version, const MTPstring &_lang_code) : vdevice_model(_device_model), vsystem_version(_system_version), vapp_version(_app_version), vlang_code(_lang_code) { + } + + uint32 size() const { + return vdevice_model.size() + vsystem_version.size() + vapp_version.size() + vlang_code.size(); + } + mtpTypeId type() const { + return mtpc_help_getAppUpdate; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_getAppUpdate) { + vdevice_model.read(from, end); + vsystem_version.read(from, end); + vapp_version.read(from, end); + vlang_code.read(from, end); + } + void write(mtpBuffer &to) const { + vdevice_model.write(to); + vsystem_version.write(to); + vapp_version.write(to); + vlang_code.write(to); + } + + typedef MTPhelp_AppUpdate ResponseType; +}; +class MTPhelp_GetAppUpdate : public MTPBoxed { +public: + MTPhelp_GetAppUpdate() { + } + MTPhelp_GetAppUpdate(const MTPhelp_getAppUpdate &v) : MTPBoxed(v) { + } + MTPhelp_GetAppUpdate(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPhelp_GetAppUpdate(const MTPstring &_device_model, const MTPstring &_system_version, const MTPstring &_app_version, const MTPstring &_lang_code) : MTPBoxed(MTPhelp_getAppUpdate(_device_model, _system_version, _app_version, _lang_code)) { + } +}; + +class MTPhelp_saveAppLog { // RPC method 'help.saveAppLog' +public: + MTPVector vevents; + + MTPhelp_saveAppLog() { + } + MTPhelp_saveAppLog(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_saveAppLog) { + read(from, end, cons); + } + MTPhelp_saveAppLog(const MTPVector &_events) : vevents(_events) { + } + + uint32 size() const { + return vevents.size(); + } + mtpTypeId type() const { + return mtpc_help_saveAppLog; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_saveAppLog) { + vevents.read(from, end); + } + void write(mtpBuffer &to) const { + vevents.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPhelp_SaveAppLog : public MTPBoxed { +public: + MTPhelp_SaveAppLog() { + } + MTPhelp_SaveAppLog(const MTPhelp_saveAppLog &v) : MTPBoxed(v) { + } + MTPhelp_SaveAppLog(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPhelp_SaveAppLog(const MTPVector &_events) : MTPBoxed(MTPhelp_saveAppLog(_events)) { + } +}; + +class MTPhelp_getInviteText { // RPC method 'help.getInviteText' +public: + MTPstring vlang_code; + + MTPhelp_getInviteText() { + } + MTPhelp_getInviteText(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_getInviteText) { + read(from, end, cons); + } + MTPhelp_getInviteText(const MTPstring &_lang_code) : vlang_code(_lang_code) { + } + + uint32 size() const { + return vlang_code.size(); + } + mtpTypeId type() const { + return mtpc_help_getInviteText; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_getInviteText) { + vlang_code.read(from, end); + } + void write(mtpBuffer &to) const { + vlang_code.write(to); + } + + typedef MTPhelp_InviteText ResponseType; +}; +class MTPhelp_GetInviteText : public MTPBoxed { +public: + MTPhelp_GetInviteText() { + } + MTPhelp_GetInviteText(const MTPhelp_getInviteText &v) : MTPBoxed(v) { + } + MTPhelp_GetInviteText(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPhelp_GetInviteText(const MTPstring &_lang_code) : MTPBoxed(MTPhelp_getInviteText(_lang_code)) { + } +}; + +class MTPphotos_getUserPhotos { // RPC method 'photos.getUserPhotos' +public: + MTPInputUser vuser_id; + MTPint voffset; + MTPint vmax_id; + MTPint vlimit; + + MTPphotos_getUserPhotos() { + } + MTPphotos_getUserPhotos(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_photos_getUserPhotos) { + read(from, end, cons); + } + MTPphotos_getUserPhotos(const MTPInputUser &_user_id, MTPint _offset, MTPint _max_id, MTPint _limit) : vuser_id(_user_id), voffset(_offset), vmax_id(_max_id), vlimit(_limit) { + } + + uint32 size() const { + return vuser_id.size() + voffset.size() + vmax_id.size() + vlimit.size(); + } + mtpTypeId type() const { + return mtpc_photos_getUserPhotos; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_photos_getUserPhotos) { + vuser_id.read(from, end); + voffset.read(from, end); + vmax_id.read(from, end); + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + vuser_id.write(to); + voffset.write(to); + vmax_id.write(to); + vlimit.write(to); + } + + typedef MTPphotos_Photos ResponseType; +}; +class MTPphotos_GetUserPhotos : public MTPBoxed { +public: + MTPphotos_GetUserPhotos() { + } + MTPphotos_GetUserPhotos(const MTPphotos_getUserPhotos &v) : MTPBoxed(v) { + } + MTPphotos_GetUserPhotos(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPphotos_GetUserPhotos(const MTPInputUser &_user_id, MTPint _offset, MTPint _max_id, MTPint _limit) : MTPBoxed(MTPphotos_getUserPhotos(_user_id, _offset, _max_id, _limit)) { + } +}; + +class MTPmessages_forwardMessage { // RPC method 'messages.forwardMessage' +public: + MTPInputPeer vpeer; + MTPint vid; + MTPlong vrandom_id; + + MTPmessages_forwardMessage() { + } + MTPmessages_forwardMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_forwardMessage) { + read(from, end, cons); + } + MTPmessages_forwardMessage(const MTPInputPeer &_peer, MTPint _id, const MTPlong &_random_id) : vpeer(_peer), vid(_id), vrandom_id(_random_id) { + } + + uint32 size() const { + return vpeer.size() + vid.size() + vrandom_id.size(); + } + mtpTypeId type() const { + return mtpc_messages_forwardMessage; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_forwardMessage) { + vpeer.read(from, end); + vid.read(from, end); + vrandom_id.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vid.write(to); + vrandom_id.write(to); + } + + typedef MTPmessages_StatedMessage ResponseType; +}; +class MTPmessages_ForwardMessage : public MTPBoxed { +public: + MTPmessages_ForwardMessage() { + } + MTPmessages_ForwardMessage(const MTPmessages_forwardMessage &v) : MTPBoxed(v) { + } + MTPmessages_ForwardMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_ForwardMessage(const MTPInputPeer &_peer, MTPint _id, const MTPlong &_random_id) : MTPBoxed(MTPmessages_forwardMessage(_peer, _id, _random_id)) { + } +}; + +class MTPmessages_sendBroadcast { // RPC method 'messages.sendBroadcast' +public: + MTPVector vcontacts; + MTPstring vmessage; + MTPInputMedia vmedia; + + MTPmessages_sendBroadcast() { + } + MTPmessages_sendBroadcast(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_sendBroadcast) { + read(from, end, cons); + } + MTPmessages_sendBroadcast(const MTPVector &_contacts, const MTPstring &_message, const MTPInputMedia &_media) : vcontacts(_contacts), vmessage(_message), vmedia(_media) { + } + + uint32 size() const { + return vcontacts.size() + vmessage.size() + vmedia.size(); + } + mtpTypeId type() const { + return mtpc_messages_sendBroadcast; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_sendBroadcast) { + vcontacts.read(from, end); + vmessage.read(from, end); + vmedia.read(from, end); + } + void write(mtpBuffer &to) const { + vcontacts.write(to); + vmessage.write(to); + vmedia.write(to); + } + + typedef MTPmessages_StatedMessages ResponseType; +}; +class MTPmessages_SendBroadcast : public MTPBoxed { +public: + MTPmessages_SendBroadcast() { + } + MTPmessages_SendBroadcast(const MTPmessages_sendBroadcast &v) : MTPBoxed(v) { + } + MTPmessages_SendBroadcast(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_SendBroadcast(const MTPVector &_contacts, const MTPstring &_message, const MTPInputMedia &_media) : MTPBoxed(MTPmessages_sendBroadcast(_contacts, _message, _media)) { + } +}; + +class MTPgeochats_getLocated { // RPC method 'geochats.getLocated' +public: + MTPInputGeoPoint vgeo_point; + MTPint vradius; + MTPint vlimit; + + MTPgeochats_getLocated() { + } + MTPgeochats_getLocated(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_getLocated) { + read(from, end, cons); + } + MTPgeochats_getLocated(const MTPInputGeoPoint &_geo_point, MTPint _radius, MTPint _limit) : vgeo_point(_geo_point), vradius(_radius), vlimit(_limit) { + } + + uint32 size() const { + return vgeo_point.size() + vradius.size() + vlimit.size(); + } + mtpTypeId type() const { + return mtpc_geochats_getLocated; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_getLocated) { + vgeo_point.read(from, end); + vradius.read(from, end); + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + vgeo_point.write(to); + vradius.write(to); + vlimit.write(to); + } + + typedef MTPgeochats_Located ResponseType; +}; +class MTPgeochats_GetLocated : public MTPBoxed { +public: + MTPgeochats_GetLocated() { + } + MTPgeochats_GetLocated(const MTPgeochats_getLocated &v) : MTPBoxed(v) { + } + MTPgeochats_GetLocated(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPgeochats_GetLocated(const MTPInputGeoPoint &_geo_point, MTPint _radius, MTPint _limit) : MTPBoxed(MTPgeochats_getLocated(_geo_point, _radius, _limit)) { + } +}; + +class MTPgeochats_getRecents { // RPC method 'geochats.getRecents' +public: + MTPint voffset; + MTPint vlimit; + + MTPgeochats_getRecents() { + } + MTPgeochats_getRecents(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_getRecents) { + read(from, end, cons); + } + MTPgeochats_getRecents(MTPint _offset, MTPint _limit) : voffset(_offset), vlimit(_limit) { + } + + uint32 size() const { + return voffset.size() + vlimit.size(); + } + mtpTypeId type() const { + return mtpc_geochats_getRecents; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_getRecents) { + voffset.read(from, end); + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + voffset.write(to); + vlimit.write(to); + } + + typedef MTPgeochats_Messages ResponseType; +}; +class MTPgeochats_GetRecents : public MTPBoxed { +public: + MTPgeochats_GetRecents() { + } + MTPgeochats_GetRecents(const MTPgeochats_getRecents &v) : MTPBoxed(v) { + } + MTPgeochats_GetRecents(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPgeochats_GetRecents(MTPint _offset, MTPint _limit) : MTPBoxed(MTPgeochats_getRecents(_offset, _limit)) { + } +}; + +class MTPgeochats_checkin { // RPC method 'geochats.checkin' +public: + MTPInputGeoChat vpeer; + + MTPgeochats_checkin() { + } + MTPgeochats_checkin(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_checkin) { + read(from, end, cons); + } + MTPgeochats_checkin(const MTPInputGeoChat &_peer) : vpeer(_peer) { + } + + uint32 size() const { + return vpeer.size(); + } + mtpTypeId type() const { + return mtpc_geochats_checkin; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_checkin) { + vpeer.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + } + + typedef MTPgeochats_StatedMessage ResponseType; +}; +class MTPgeochats_Checkin : public MTPBoxed { +public: + MTPgeochats_Checkin() { + } + MTPgeochats_Checkin(const MTPgeochats_checkin &v) : MTPBoxed(v) { + } + MTPgeochats_Checkin(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPgeochats_Checkin(const MTPInputGeoChat &_peer) : MTPBoxed(MTPgeochats_checkin(_peer)) { + } +}; + +class MTPgeochats_getFullChat { // RPC method 'geochats.getFullChat' +public: + MTPInputGeoChat vpeer; + + MTPgeochats_getFullChat() { + } + MTPgeochats_getFullChat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_getFullChat) { + read(from, end, cons); + } + MTPgeochats_getFullChat(const MTPInputGeoChat &_peer) : vpeer(_peer) { + } + + uint32 size() const { + return vpeer.size(); + } + mtpTypeId type() const { + return mtpc_geochats_getFullChat; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_getFullChat) { + vpeer.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + } + + typedef MTPmessages_ChatFull ResponseType; +}; +class MTPgeochats_GetFullChat : public MTPBoxed { +public: + MTPgeochats_GetFullChat() { + } + MTPgeochats_GetFullChat(const MTPgeochats_getFullChat &v) : MTPBoxed(v) { + } + MTPgeochats_GetFullChat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPgeochats_GetFullChat(const MTPInputGeoChat &_peer) : MTPBoxed(MTPgeochats_getFullChat(_peer)) { + } +}; + +class MTPgeochats_editChatTitle { // RPC method 'geochats.editChatTitle' +public: + MTPInputGeoChat vpeer; + MTPstring vtitle; + MTPstring vaddress; + + MTPgeochats_editChatTitle() { + } + MTPgeochats_editChatTitle(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_editChatTitle) { + read(from, end, cons); + } + MTPgeochats_editChatTitle(const MTPInputGeoChat &_peer, const MTPstring &_title, const MTPstring &_address) : vpeer(_peer), vtitle(_title), vaddress(_address) { + } + + uint32 size() const { + return vpeer.size() + vtitle.size() + vaddress.size(); + } + mtpTypeId type() const { + return mtpc_geochats_editChatTitle; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_editChatTitle) { + vpeer.read(from, end); + vtitle.read(from, end); + vaddress.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vtitle.write(to); + vaddress.write(to); + } + + typedef MTPgeochats_StatedMessage ResponseType; +}; +class MTPgeochats_EditChatTitle : public MTPBoxed { +public: + MTPgeochats_EditChatTitle() { + } + MTPgeochats_EditChatTitle(const MTPgeochats_editChatTitle &v) : MTPBoxed(v) { + } + MTPgeochats_EditChatTitle(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPgeochats_EditChatTitle(const MTPInputGeoChat &_peer, const MTPstring &_title, const MTPstring &_address) : MTPBoxed(MTPgeochats_editChatTitle(_peer, _title, _address)) { + } +}; + +class MTPgeochats_editChatPhoto { // RPC method 'geochats.editChatPhoto' +public: + MTPInputGeoChat vpeer; + MTPInputChatPhoto vphoto; + + MTPgeochats_editChatPhoto() { + } + MTPgeochats_editChatPhoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_editChatPhoto) { + read(from, end, cons); + } + MTPgeochats_editChatPhoto(const MTPInputGeoChat &_peer, const MTPInputChatPhoto &_photo) : vpeer(_peer), vphoto(_photo) { + } + + uint32 size() const { + return vpeer.size() + vphoto.size(); + } + mtpTypeId type() const { + return mtpc_geochats_editChatPhoto; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_editChatPhoto) { + vpeer.read(from, end); + vphoto.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vphoto.write(to); + } + + typedef MTPgeochats_StatedMessage ResponseType; +}; +class MTPgeochats_EditChatPhoto : public MTPBoxed { +public: + MTPgeochats_EditChatPhoto() { + } + MTPgeochats_EditChatPhoto(const MTPgeochats_editChatPhoto &v) : MTPBoxed(v) { + } + MTPgeochats_EditChatPhoto(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPgeochats_EditChatPhoto(const MTPInputGeoChat &_peer, const MTPInputChatPhoto &_photo) : MTPBoxed(MTPgeochats_editChatPhoto(_peer, _photo)) { + } +}; + +class MTPgeochats_search { // RPC method 'geochats.search' +public: + MTPInputGeoChat vpeer; + MTPstring vq; + MTPMessagesFilter vfilter; + MTPint vmin_date; + MTPint vmax_date; + MTPint voffset; + MTPint vmax_id; + MTPint vlimit; + + MTPgeochats_search() { + } + MTPgeochats_search(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_search) { + read(from, end, cons); + } + MTPgeochats_search(const MTPInputGeoChat &_peer, const MTPstring &_q, const MTPMessagesFilter &_filter, MTPint _min_date, MTPint _max_date, MTPint _offset, MTPint _max_id, MTPint _limit) : vpeer(_peer), vq(_q), vfilter(_filter), vmin_date(_min_date), vmax_date(_max_date), voffset(_offset), vmax_id(_max_id), vlimit(_limit) { + } + + uint32 size() const { + return vpeer.size() + vq.size() + vfilter.size() + vmin_date.size() + vmax_date.size() + voffset.size() + vmax_id.size() + vlimit.size(); + } + mtpTypeId type() const { + return mtpc_geochats_search; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_search) { + vpeer.read(from, end); + vq.read(from, end); + vfilter.read(from, end); + vmin_date.read(from, end); + vmax_date.read(from, end); + voffset.read(from, end); + vmax_id.read(from, end); + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vq.write(to); + vfilter.write(to); + vmin_date.write(to); + vmax_date.write(to); + voffset.write(to); + vmax_id.write(to); + vlimit.write(to); + } + + typedef MTPgeochats_Messages ResponseType; +}; +class MTPgeochats_Search : public MTPBoxed { +public: + MTPgeochats_Search() { + } + MTPgeochats_Search(const MTPgeochats_search &v) : MTPBoxed(v) { + } + MTPgeochats_Search(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPgeochats_Search(const MTPInputGeoChat &_peer, const MTPstring &_q, const MTPMessagesFilter &_filter, MTPint _min_date, MTPint _max_date, MTPint _offset, MTPint _max_id, MTPint _limit) : MTPBoxed(MTPgeochats_search(_peer, _q, _filter, _min_date, _max_date, _offset, _max_id, _limit)) { + } +}; + +class MTPgeochats_getHistory { // RPC method 'geochats.getHistory' +public: + MTPInputGeoChat vpeer; + MTPint voffset; + MTPint vmax_id; + MTPint vlimit; + + MTPgeochats_getHistory() { + } + MTPgeochats_getHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_getHistory) { + read(from, end, cons); + } + MTPgeochats_getHistory(const MTPInputGeoChat &_peer, MTPint _offset, MTPint _max_id, MTPint _limit) : vpeer(_peer), voffset(_offset), vmax_id(_max_id), vlimit(_limit) { + } + + uint32 size() const { + return vpeer.size() + voffset.size() + vmax_id.size() + vlimit.size(); + } + mtpTypeId type() const { + return mtpc_geochats_getHistory; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_getHistory) { + vpeer.read(from, end); + voffset.read(from, end); + vmax_id.read(from, end); + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + voffset.write(to); + vmax_id.write(to); + vlimit.write(to); + } + + typedef MTPgeochats_Messages ResponseType; +}; +class MTPgeochats_GetHistory : public MTPBoxed { +public: + MTPgeochats_GetHistory() { + } + MTPgeochats_GetHistory(const MTPgeochats_getHistory &v) : MTPBoxed(v) { + } + MTPgeochats_GetHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPgeochats_GetHistory(const MTPInputGeoChat &_peer, MTPint _offset, MTPint _max_id, MTPint _limit) : MTPBoxed(MTPgeochats_getHistory(_peer, _offset, _max_id, _limit)) { + } +}; + +class MTPgeochats_setTyping { // RPC method 'geochats.setTyping' +public: + MTPInputGeoChat vpeer; + MTPBool vtyping; + + MTPgeochats_setTyping() { + } + MTPgeochats_setTyping(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_setTyping) { + read(from, end, cons); + } + MTPgeochats_setTyping(const MTPInputGeoChat &_peer, MTPBool _typing) : vpeer(_peer), vtyping(_typing) { + } + + uint32 size() const { + return vpeer.size() + vtyping.size(); + } + mtpTypeId type() const { + return mtpc_geochats_setTyping; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_setTyping) { + vpeer.read(from, end); + vtyping.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vtyping.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPgeochats_SetTyping : public MTPBoxed { +public: + MTPgeochats_SetTyping() { + } + MTPgeochats_SetTyping(const MTPgeochats_setTyping &v) : MTPBoxed(v) { + } + MTPgeochats_SetTyping(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPgeochats_SetTyping(const MTPInputGeoChat &_peer, MTPBool _typing) : MTPBoxed(MTPgeochats_setTyping(_peer, _typing)) { + } +}; + +class MTPgeochats_sendMessage { // RPC method 'geochats.sendMessage' +public: + MTPInputGeoChat vpeer; + MTPstring vmessage; + MTPlong vrandom_id; + + MTPgeochats_sendMessage() { + } + MTPgeochats_sendMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_sendMessage) { + read(from, end, cons); + } + MTPgeochats_sendMessage(const MTPInputGeoChat &_peer, const MTPstring &_message, const MTPlong &_random_id) : vpeer(_peer), vmessage(_message), vrandom_id(_random_id) { + } + + uint32 size() const { + return vpeer.size() + vmessage.size() + vrandom_id.size(); + } + mtpTypeId type() const { + return mtpc_geochats_sendMessage; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_sendMessage) { + vpeer.read(from, end); + vmessage.read(from, end); + vrandom_id.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vmessage.write(to); + vrandom_id.write(to); + } + + typedef MTPgeochats_StatedMessage ResponseType; +}; +class MTPgeochats_SendMessage : public MTPBoxed { +public: + MTPgeochats_SendMessage() { + } + MTPgeochats_SendMessage(const MTPgeochats_sendMessage &v) : MTPBoxed(v) { + } + MTPgeochats_SendMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPgeochats_SendMessage(const MTPInputGeoChat &_peer, const MTPstring &_message, const MTPlong &_random_id) : MTPBoxed(MTPgeochats_sendMessage(_peer, _message, _random_id)) { + } +}; + +class MTPgeochats_sendMedia { // RPC method 'geochats.sendMedia' +public: + MTPInputGeoChat vpeer; + MTPInputMedia vmedia; + MTPlong vrandom_id; + + MTPgeochats_sendMedia() { + } + MTPgeochats_sendMedia(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_sendMedia) { + read(from, end, cons); + } + MTPgeochats_sendMedia(const MTPInputGeoChat &_peer, const MTPInputMedia &_media, const MTPlong &_random_id) : vpeer(_peer), vmedia(_media), vrandom_id(_random_id) { + } + + uint32 size() const { + return vpeer.size() + vmedia.size() + vrandom_id.size(); + } + mtpTypeId type() const { + return mtpc_geochats_sendMedia; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_sendMedia) { + vpeer.read(from, end); + vmedia.read(from, end); + vrandom_id.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vmedia.write(to); + vrandom_id.write(to); + } + + typedef MTPgeochats_StatedMessage ResponseType; +}; +class MTPgeochats_SendMedia : public MTPBoxed { +public: + MTPgeochats_SendMedia() { + } + MTPgeochats_SendMedia(const MTPgeochats_sendMedia &v) : MTPBoxed(v) { + } + MTPgeochats_SendMedia(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPgeochats_SendMedia(const MTPInputGeoChat &_peer, const MTPInputMedia &_media, const MTPlong &_random_id) : MTPBoxed(MTPgeochats_sendMedia(_peer, _media, _random_id)) { + } +}; + +class MTPgeochats_createGeoChat { // RPC method 'geochats.createGeoChat' +public: + MTPstring vtitle; + MTPInputGeoPoint vgeo_point; + MTPstring vaddress; + MTPstring vvenue; + + MTPgeochats_createGeoChat() { + } + MTPgeochats_createGeoChat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_createGeoChat) { + read(from, end, cons); + } + MTPgeochats_createGeoChat(const MTPstring &_title, const MTPInputGeoPoint &_geo_point, const MTPstring &_address, const MTPstring &_venue) : vtitle(_title), vgeo_point(_geo_point), vaddress(_address), vvenue(_venue) { + } + + uint32 size() const { + return vtitle.size() + vgeo_point.size() + vaddress.size() + vvenue.size(); + } + mtpTypeId type() const { + return mtpc_geochats_createGeoChat; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_geochats_createGeoChat) { + vtitle.read(from, end); + vgeo_point.read(from, end); + vaddress.read(from, end); + vvenue.read(from, end); + } + void write(mtpBuffer &to) const { + vtitle.write(to); + vgeo_point.write(to); + vaddress.write(to); + vvenue.write(to); + } + + typedef MTPgeochats_StatedMessage ResponseType; +}; +class MTPgeochats_CreateGeoChat : public MTPBoxed { +public: + MTPgeochats_CreateGeoChat() { + } + MTPgeochats_CreateGeoChat(const MTPgeochats_createGeoChat &v) : MTPBoxed(v) { + } + MTPgeochats_CreateGeoChat(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPgeochats_CreateGeoChat(const MTPstring &_title, const MTPInputGeoPoint &_geo_point, const MTPstring &_address, const MTPstring &_venue) : MTPBoxed(MTPgeochats_createGeoChat(_title, _geo_point, _address, _venue)) { + } +}; + +class MTPmessages_getDhConfig { // RPC method 'messages.getDhConfig' +public: + MTPint vversion; + MTPint vrandom_length; + + MTPmessages_getDhConfig() { + } + MTPmessages_getDhConfig(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getDhConfig) { + read(from, end, cons); + } + MTPmessages_getDhConfig(MTPint _version, MTPint _random_length) : vversion(_version), vrandom_length(_random_length) { + } + + uint32 size() const { + return vversion.size() + vrandom_length.size(); + } + mtpTypeId type() const { + return mtpc_messages_getDhConfig; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getDhConfig) { + vversion.read(from, end); + vrandom_length.read(from, end); + } + void write(mtpBuffer &to) const { + vversion.write(to); + vrandom_length.write(to); + } + + typedef MTPmessages_DhConfig ResponseType; +}; +class MTPmessages_GetDhConfig : public MTPBoxed { +public: + MTPmessages_GetDhConfig() { + } + MTPmessages_GetDhConfig(const MTPmessages_getDhConfig &v) : MTPBoxed(v) { + } + MTPmessages_GetDhConfig(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_GetDhConfig(MTPint _version, MTPint _random_length) : MTPBoxed(MTPmessages_getDhConfig(_version, _random_length)) { + } +}; + +class MTPmessages_requestEncryption { // RPC method 'messages.requestEncryption' +public: + MTPInputUser vuser_id; + MTPint vrandom_id; + MTPbytes vg_a; + + MTPmessages_requestEncryption() { + } + MTPmessages_requestEncryption(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_requestEncryption) { + read(from, end, cons); + } + MTPmessages_requestEncryption(const MTPInputUser &_user_id, MTPint _random_id, const MTPbytes &_g_a) : vuser_id(_user_id), vrandom_id(_random_id), vg_a(_g_a) { + } + + uint32 size() const { + return vuser_id.size() + vrandom_id.size() + vg_a.size(); + } + mtpTypeId type() const { + return mtpc_messages_requestEncryption; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_requestEncryption) { + vuser_id.read(from, end); + vrandom_id.read(from, end); + vg_a.read(from, end); + } + void write(mtpBuffer &to) const { + vuser_id.write(to); + vrandom_id.write(to); + vg_a.write(to); + } + + typedef MTPEncryptedChat ResponseType; +}; +class MTPmessages_RequestEncryption : public MTPBoxed { +public: + MTPmessages_RequestEncryption() { + } + MTPmessages_RequestEncryption(const MTPmessages_requestEncryption &v) : MTPBoxed(v) { + } + MTPmessages_RequestEncryption(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_RequestEncryption(const MTPInputUser &_user_id, MTPint _random_id, const MTPbytes &_g_a) : MTPBoxed(MTPmessages_requestEncryption(_user_id, _random_id, _g_a)) { + } +}; + +class MTPmessages_acceptEncryption { // RPC method 'messages.acceptEncryption' +public: + MTPInputEncryptedChat vpeer; + MTPbytes vg_b; + MTPlong vkey_fingerprint; + + MTPmessages_acceptEncryption() { + } + MTPmessages_acceptEncryption(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_acceptEncryption) { + read(from, end, cons); + } + MTPmessages_acceptEncryption(const MTPInputEncryptedChat &_peer, const MTPbytes &_g_b, const MTPlong &_key_fingerprint) : vpeer(_peer), vg_b(_g_b), vkey_fingerprint(_key_fingerprint) { + } + + uint32 size() const { + return vpeer.size() + vg_b.size() + vkey_fingerprint.size(); + } + mtpTypeId type() const { + return mtpc_messages_acceptEncryption; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_acceptEncryption) { + vpeer.read(from, end); + vg_b.read(from, end); + vkey_fingerprint.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vg_b.write(to); + vkey_fingerprint.write(to); + } + + typedef MTPEncryptedChat ResponseType; +}; +class MTPmessages_AcceptEncryption : public MTPBoxed { +public: + MTPmessages_AcceptEncryption() { + } + MTPmessages_AcceptEncryption(const MTPmessages_acceptEncryption &v) : MTPBoxed(v) { + } + MTPmessages_AcceptEncryption(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_AcceptEncryption(const MTPInputEncryptedChat &_peer, const MTPbytes &_g_b, const MTPlong &_key_fingerprint) : MTPBoxed(MTPmessages_acceptEncryption(_peer, _g_b, _key_fingerprint)) { + } +}; + +class MTPmessages_discardEncryption { // RPC method 'messages.discardEncryption' +public: + MTPint vchat_id; + + MTPmessages_discardEncryption() { + } + MTPmessages_discardEncryption(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_discardEncryption) { + read(from, end, cons); + } + MTPmessages_discardEncryption(MTPint _chat_id) : vchat_id(_chat_id) { + } + + uint32 size() const { + return vchat_id.size(); + } + mtpTypeId type() const { + return mtpc_messages_discardEncryption; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_discardEncryption) { + vchat_id.read(from, end); + } + void write(mtpBuffer &to) const { + vchat_id.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPmessages_DiscardEncryption : public MTPBoxed { +public: + MTPmessages_DiscardEncryption() { + } + MTPmessages_DiscardEncryption(const MTPmessages_discardEncryption &v) : MTPBoxed(v) { + } + MTPmessages_DiscardEncryption(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_DiscardEncryption(MTPint _chat_id) : MTPBoxed(MTPmessages_discardEncryption(_chat_id)) { + } +}; + +class MTPmessages_setEncryptedTyping { // RPC method 'messages.setEncryptedTyping' +public: + MTPInputEncryptedChat vpeer; + MTPBool vtyping; + + MTPmessages_setEncryptedTyping() { + } + MTPmessages_setEncryptedTyping(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setEncryptedTyping) { + read(from, end, cons); + } + MTPmessages_setEncryptedTyping(const MTPInputEncryptedChat &_peer, MTPBool _typing) : vpeer(_peer), vtyping(_typing) { + } + + uint32 size() const { + return vpeer.size() + vtyping.size(); + } + mtpTypeId type() const { + return mtpc_messages_setEncryptedTyping; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setEncryptedTyping) { + vpeer.read(from, end); + vtyping.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vtyping.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPmessages_SetEncryptedTyping : public MTPBoxed { +public: + MTPmessages_SetEncryptedTyping() { + } + MTPmessages_SetEncryptedTyping(const MTPmessages_setEncryptedTyping &v) : MTPBoxed(v) { + } + MTPmessages_SetEncryptedTyping(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_SetEncryptedTyping(const MTPInputEncryptedChat &_peer, MTPBool _typing) : MTPBoxed(MTPmessages_setEncryptedTyping(_peer, _typing)) { + } +}; + +class MTPmessages_readEncryptedHistory { // RPC method 'messages.readEncryptedHistory' +public: + MTPInputEncryptedChat vpeer; + MTPint vmax_date; + + MTPmessages_readEncryptedHistory() { + } + MTPmessages_readEncryptedHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_readEncryptedHistory) { + read(from, end, cons); + } + MTPmessages_readEncryptedHistory(const MTPInputEncryptedChat &_peer, MTPint _max_date) : vpeer(_peer), vmax_date(_max_date) { + } + + uint32 size() const { + return vpeer.size() + vmax_date.size(); + } + mtpTypeId type() const { + return mtpc_messages_readEncryptedHistory; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_readEncryptedHistory) { + vpeer.read(from, end); + vmax_date.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vmax_date.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPmessages_ReadEncryptedHistory : public MTPBoxed { +public: + MTPmessages_ReadEncryptedHistory() { + } + MTPmessages_ReadEncryptedHistory(const MTPmessages_readEncryptedHistory &v) : MTPBoxed(v) { + } + MTPmessages_ReadEncryptedHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_ReadEncryptedHistory(const MTPInputEncryptedChat &_peer, MTPint _max_date) : MTPBoxed(MTPmessages_readEncryptedHistory(_peer, _max_date)) { + } +}; + +class MTPmessages_sendEncrypted { // RPC method 'messages.sendEncrypted' +public: + MTPInputEncryptedChat vpeer; + MTPlong vrandom_id; + MTPbytes vdata; + + MTPmessages_sendEncrypted() { + } + MTPmessages_sendEncrypted(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_sendEncrypted) { + read(from, end, cons); + } + MTPmessages_sendEncrypted(const MTPInputEncryptedChat &_peer, const MTPlong &_random_id, const MTPbytes &_data) : vpeer(_peer), vrandom_id(_random_id), vdata(_data) { + } + + uint32 size() const { + return vpeer.size() + vrandom_id.size() + vdata.size(); + } + mtpTypeId type() const { + return mtpc_messages_sendEncrypted; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_sendEncrypted) { + vpeer.read(from, end); + vrandom_id.read(from, end); + vdata.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vrandom_id.write(to); + vdata.write(to); + } + + typedef MTPmessages_SentEncryptedMessage ResponseType; +}; +class MTPmessages_SendEncrypted : public MTPBoxed { +public: + MTPmessages_SendEncrypted() { + } + MTPmessages_SendEncrypted(const MTPmessages_sendEncrypted &v) : MTPBoxed(v) { + } + MTPmessages_SendEncrypted(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_SendEncrypted(const MTPInputEncryptedChat &_peer, const MTPlong &_random_id, const MTPbytes &_data) : MTPBoxed(MTPmessages_sendEncrypted(_peer, _random_id, _data)) { + } +}; + +class MTPmessages_sendEncryptedFile { // RPC method 'messages.sendEncryptedFile' +public: + MTPInputEncryptedChat vpeer; + MTPlong vrandom_id; + MTPbytes vdata; + MTPInputEncryptedFile vfile; + + MTPmessages_sendEncryptedFile() { + } + MTPmessages_sendEncryptedFile(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_sendEncryptedFile) { + read(from, end, cons); + } + MTPmessages_sendEncryptedFile(const MTPInputEncryptedChat &_peer, const MTPlong &_random_id, const MTPbytes &_data, const MTPInputEncryptedFile &_file) : vpeer(_peer), vrandom_id(_random_id), vdata(_data), vfile(_file) { + } + + uint32 size() const { + return vpeer.size() + vrandom_id.size() + vdata.size() + vfile.size(); + } + mtpTypeId type() const { + return mtpc_messages_sendEncryptedFile; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_sendEncryptedFile) { + vpeer.read(from, end); + vrandom_id.read(from, end); + vdata.read(from, end); + vfile.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vrandom_id.write(to); + vdata.write(to); + vfile.write(to); + } + + typedef MTPmessages_SentEncryptedMessage ResponseType; +}; +class MTPmessages_SendEncryptedFile : public MTPBoxed { +public: + MTPmessages_SendEncryptedFile() { + } + MTPmessages_SendEncryptedFile(const MTPmessages_sendEncryptedFile &v) : MTPBoxed(v) { + } + MTPmessages_SendEncryptedFile(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_SendEncryptedFile(const MTPInputEncryptedChat &_peer, const MTPlong &_random_id, const MTPbytes &_data, const MTPInputEncryptedFile &_file) : MTPBoxed(MTPmessages_sendEncryptedFile(_peer, _random_id, _data, _file)) { + } +}; + +class MTPmessages_sendEncryptedService { // RPC method 'messages.sendEncryptedService' +public: + MTPInputEncryptedChat vpeer; + MTPlong vrandom_id; + MTPbytes vdata; + + MTPmessages_sendEncryptedService() { + } + MTPmessages_sendEncryptedService(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_sendEncryptedService) { + read(from, end, cons); + } + MTPmessages_sendEncryptedService(const MTPInputEncryptedChat &_peer, const MTPlong &_random_id, const MTPbytes &_data) : vpeer(_peer), vrandom_id(_random_id), vdata(_data) { + } + + uint32 size() const { + return vpeer.size() + vrandom_id.size() + vdata.size(); + } + mtpTypeId type() const { + return mtpc_messages_sendEncryptedService; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_sendEncryptedService) { + vpeer.read(from, end); + vrandom_id.read(from, end); + vdata.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vrandom_id.write(to); + vdata.write(to); + } + + typedef MTPmessages_SentEncryptedMessage ResponseType; +}; +class MTPmessages_SendEncryptedService : public MTPBoxed { +public: + MTPmessages_SendEncryptedService() { + } + MTPmessages_SendEncryptedService(const MTPmessages_sendEncryptedService &v) : MTPBoxed(v) { + } + MTPmessages_SendEncryptedService(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_SendEncryptedService(const MTPInputEncryptedChat &_peer, const MTPlong &_random_id, const MTPbytes &_data) : MTPBoxed(MTPmessages_sendEncryptedService(_peer, _random_id, _data)) { + } +}; + +class MTPmessages_receivedQueue { // RPC method 'messages.receivedQueue' +public: + MTPint vmax_qts; + + MTPmessages_receivedQueue() { + } + MTPmessages_receivedQueue(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_receivedQueue) { + read(from, end, cons); + } + MTPmessages_receivedQueue(MTPint _max_qts) : vmax_qts(_max_qts) { + } + + uint32 size() const { + return vmax_qts.size(); + } + mtpTypeId type() const { + return mtpc_messages_receivedQueue; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_receivedQueue) { + vmax_qts.read(from, end); + } + void write(mtpBuffer &to) const { + vmax_qts.write(to); + } + + typedef MTPVector ResponseType; +}; +class MTPmessages_ReceivedQueue : public MTPBoxed { +public: + MTPmessages_ReceivedQueue() { + } + MTPmessages_ReceivedQueue(const MTPmessages_receivedQueue &v) : MTPBoxed(v) { + } + MTPmessages_ReceivedQueue(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_ReceivedQueue(MTPint _max_qts) : MTPBoxed(MTPmessages_receivedQueue(_max_qts)) { + } +}; + +class MTPupload_saveBigFilePart { // RPC method 'upload.saveBigFilePart' +public: + MTPlong vfile_id; + MTPint vfile_part; + MTPint vfile_total_parts; + MTPbytes vbytes; + + MTPupload_saveBigFilePart() { + } + MTPupload_saveBigFilePart(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_upload_saveBigFilePart) { + read(from, end, cons); + } + MTPupload_saveBigFilePart(const MTPlong &_file_id, MTPint _file_part, MTPint _file_total_parts, const MTPbytes &_bytes) : vfile_id(_file_id), vfile_part(_file_part), vfile_total_parts(_file_total_parts), vbytes(_bytes) { + } + + uint32 size() const { + return vfile_id.size() + vfile_part.size() + vfile_total_parts.size() + vbytes.size(); + } + mtpTypeId type() const { + return mtpc_upload_saveBigFilePart; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_upload_saveBigFilePart) { + vfile_id.read(from, end); + vfile_part.read(from, end); + vfile_total_parts.read(from, end); + vbytes.read(from, end); + } + void write(mtpBuffer &to) const { + vfile_id.write(to); + vfile_part.write(to); + vfile_total_parts.write(to); + vbytes.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPupload_SaveBigFilePart : public MTPBoxed { +public: + MTPupload_SaveBigFilePart() { + } + MTPupload_SaveBigFilePart(const MTPupload_saveBigFilePart &v) : MTPBoxed(v) { + } + MTPupload_SaveBigFilePart(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPupload_SaveBigFilePart(const MTPlong &_file_id, MTPint _file_part, MTPint _file_total_parts, const MTPbytes &_bytes) : MTPBoxed(MTPupload_saveBigFilePart(_file_id, _file_part, _file_total_parts, _bytes)) { + } +}; + +template +class MTPinitConnection { // RPC method 'initConnection' +public: + MTPint vapi_id; + MTPstring vdevice_model; + MTPstring vsystem_version; + MTPstring vapp_version; + MTPstring vlang_code; + TQueryType vquery; + + MTPinitConnection() { + } + MTPinitConnection(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_initConnection) { + read(from, end, cons); + } + MTPinitConnection(MTPint _api_id, const MTPstring &_device_model, const MTPstring &_system_version, const MTPstring &_app_version, const MTPstring &_lang_code, const TQueryType &_query) : vapi_id(_api_id), vdevice_model(_device_model), vsystem_version(_system_version), vapp_version(_app_version), vlang_code(_lang_code), vquery(_query) { + } + + uint32 size() const { + return vapi_id.size() + vdevice_model.size() + vsystem_version.size() + vapp_version.size() + vlang_code.size() + vquery.size(); + } + mtpTypeId type() const { + return mtpc_initConnection; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_initConnection) { + vapi_id.read(from, end); + vdevice_model.read(from, end); + vsystem_version.read(from, end); + vapp_version.read(from, end); + vlang_code.read(from, end); + vquery.read(from, end); + } + void write(mtpBuffer &to) const { + vapi_id.write(to); + vdevice_model.write(to); + vsystem_version.write(to); + vapp_version.write(to); + vlang_code.write(to); + vquery.write(to); + } + + typedef typename TQueryType::ResponseType ResponseType; +}; +template +class MTPInitConnection : public MTPBoxed > { +public: + MTPInitConnection() { + } + MTPInitConnection(const MTPinitConnection &v) : MTPBoxed >(v) { + } + MTPInitConnection(MTPint _api_id, const MTPstring &_device_model, const MTPstring &_system_version, const MTPstring &_app_version, const MTPstring &_lang_code, const TQueryType &_query) : MTPBoxed >(MTPinitConnection(_api_id, _device_model, _system_version, _app_version, _lang_code, _query)) { + } +}; + +class MTPhelp_getSupport { // RPC method 'help.getSupport' +public: + MTPhelp_getSupport() { + } + MTPhelp_getSupport(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_getSupport) { + read(from, end, cons); + } + + uint32 size() const { + return 0; + } + mtpTypeId type() const { + return mtpc_help_getSupport; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_help_getSupport) { + } + void write(mtpBuffer &to) const { + } + + typedef MTPhelp_Support ResponseType; +}; +class MTPhelp_GetSupport : public MTPBoxed { +public: + MTPhelp_GetSupport() { + } + MTPhelp_GetSupport(const MTPhelp_getSupport &v) : MTPBoxed(v) { + } + MTPhelp_GetSupport(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } +}; + +// Inline methods definition + +inline MTPresPQ::MTPresPQ() : mtpDataOwner(new MTPDresPQ()) { +} + +inline uint32 MTPresPQ::size() const { + const MTPDresPQ &v(c_resPQ()); + return v.vnonce.size() + v.vserver_nonce.size() + v.vpq.size() + v.vserver_public_key_fingerprints.size(); +} +inline mtpTypeId MTPresPQ::type() const { + return mtpc_resPQ; +} +inline void MTPresPQ::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_resPQ) throw mtpErrorUnexpected(cons, "MTPresPQ"); + + if (!data) setData(new MTPDresPQ()); + MTPDresPQ &v(_resPQ()); + v.vnonce.read(from, end); + v.vserver_nonce.read(from, end); + v.vpq.read(from, end); + v.vserver_public_key_fingerprints.read(from, end); +} +inline void MTPresPQ::write(mtpBuffer &to) const { + const MTPDresPQ &v(c_resPQ()); + v.vnonce.write(to); + v.vserver_nonce.write(to); + v.vpq.write(to); + v.vserver_public_key_fingerprints.write(to); +} +inline MTPresPQ::MTPresPQ(MTPDresPQ *_data) : mtpDataOwner(_data) { +} +inline MTPresPQ MTP_resPQ(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPstring &_pq, const MTPVector &_server_public_key_fingerprints) { + return MTPresPQ(new MTPDresPQ(_nonce, _server_nonce, _pq, _server_public_key_fingerprints)); +} + +inline MTPp_Q_inner_data::MTPp_Q_inner_data() : mtpDataOwner(new MTPDp_q_inner_data()) { +} + +inline uint32 MTPp_Q_inner_data::size() const { + const MTPDp_q_inner_data &v(c_p_q_inner_data()); + return v.vpq.size() + v.vp.size() + v.vq.size() + v.vnonce.size() + v.vserver_nonce.size() + v.vnew_nonce.size(); +} +inline mtpTypeId MTPp_Q_inner_data::type() const { + return mtpc_p_q_inner_data; +} +inline void MTPp_Q_inner_data::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_p_q_inner_data) throw mtpErrorUnexpected(cons, "MTPp_Q_inner_data"); + + if (!data) setData(new MTPDp_q_inner_data()); + MTPDp_q_inner_data &v(_p_q_inner_data()); + v.vpq.read(from, end); + v.vp.read(from, end); + v.vq.read(from, end); + v.vnonce.read(from, end); + v.vserver_nonce.read(from, end); + v.vnew_nonce.read(from, end); +} +inline void MTPp_Q_inner_data::write(mtpBuffer &to) const { + const MTPDp_q_inner_data &v(c_p_q_inner_data()); + v.vpq.write(to); + v.vp.write(to); + v.vq.write(to); + v.vnonce.write(to); + v.vserver_nonce.write(to); + v.vnew_nonce.write(to); +} +inline MTPp_Q_inner_data::MTPp_Q_inner_data(MTPDp_q_inner_data *_data) : mtpDataOwner(_data) { +} +inline MTPp_Q_inner_data MTP_p_q_inner_data(const MTPstring &_pq, const MTPstring &_p, const MTPstring &_q, const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint256 &_new_nonce) { + return MTPp_Q_inner_data(new MTPDp_q_inner_data(_pq, _p, _q, _nonce, _server_nonce, _new_nonce)); +} + +inline uint32 MTPserver_DH_Params::size() const { + switch (_type) { + case mtpc_server_DH_params_fail: { + const MTPDserver_DH_params_fail &v(c_server_DH_params_fail()); + return v.vnonce.size() + v.vserver_nonce.size() + v.vnew_nonce_hash.size(); + } + case mtpc_server_DH_params_ok: { + const MTPDserver_DH_params_ok &v(c_server_DH_params_ok()); + return v.vnonce.size() + v.vserver_nonce.size() + v.vencrypted_answer.size(); + } + } + return 0; +} +inline mtpTypeId MTPserver_DH_Params::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPserver_DH_Params::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_server_DH_params_fail: _type = cons; { + if (!data) setData(new MTPDserver_DH_params_fail()); + MTPDserver_DH_params_fail &v(_server_DH_params_fail()); + v.vnonce.read(from, end); + v.vserver_nonce.read(from, end); + v.vnew_nonce_hash.read(from, end); + } break; + case mtpc_server_DH_params_ok: _type = cons; { + if (!data) setData(new MTPDserver_DH_params_ok()); + MTPDserver_DH_params_ok &v(_server_DH_params_ok()); + v.vnonce.read(from, end); + v.vserver_nonce.read(from, end); + v.vencrypted_answer.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPserver_DH_Params"); + } +} +inline void MTPserver_DH_Params::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_server_DH_params_fail: { + const MTPDserver_DH_params_fail &v(c_server_DH_params_fail()); + v.vnonce.write(to); + v.vserver_nonce.write(to); + v.vnew_nonce_hash.write(to); + } break; + case mtpc_server_DH_params_ok: { + const MTPDserver_DH_params_ok &v(c_server_DH_params_ok()); + v.vnonce.write(to); + v.vserver_nonce.write(to); + v.vencrypted_answer.write(to); + } break; + } +} +inline MTPserver_DH_Params::MTPserver_DH_Params(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_server_DH_params_fail: setData(new MTPDserver_DH_params_fail()); break; + case mtpc_server_DH_params_ok: setData(new MTPDserver_DH_params_ok()); break; + default: throw mtpErrorBadTypeId(type, "MTPserver_DH_Params"); + } +} +inline MTPserver_DH_Params::MTPserver_DH_Params(MTPDserver_DH_params_fail *_data) : _type(mtpc_server_DH_params_fail), mtpDataOwner(_data) { +} +inline MTPserver_DH_Params::MTPserver_DH_Params(MTPDserver_DH_params_ok *_data) : _type(mtpc_server_DH_params_ok), mtpDataOwner(_data) { +} +inline MTPserver_DH_Params MTP_server_DH_params_fail(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint128 &_new_nonce_hash) { + return MTPserver_DH_Params(new MTPDserver_DH_params_fail(_nonce, _server_nonce, _new_nonce_hash)); +} +inline MTPserver_DH_Params MTP_server_DH_params_ok(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPstring &_encrypted_answer) { + return MTPserver_DH_Params(new MTPDserver_DH_params_ok(_nonce, _server_nonce, _encrypted_answer)); +} + +inline MTPserver_DH_inner_data::MTPserver_DH_inner_data() : mtpDataOwner(new MTPDserver_DH_inner_data()) { +} + +inline uint32 MTPserver_DH_inner_data::size() const { + const MTPDserver_DH_inner_data &v(c_server_DH_inner_data()); + return v.vnonce.size() + v.vserver_nonce.size() + v.vg.size() + v.vdh_prime.size() + v.vg_a.size() + v.vserver_time.size(); +} +inline mtpTypeId MTPserver_DH_inner_data::type() const { + return mtpc_server_DH_inner_data; +} +inline void MTPserver_DH_inner_data::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_server_DH_inner_data) throw mtpErrorUnexpected(cons, "MTPserver_DH_inner_data"); + + if (!data) setData(new MTPDserver_DH_inner_data()); + MTPDserver_DH_inner_data &v(_server_DH_inner_data()); + v.vnonce.read(from, end); + v.vserver_nonce.read(from, end); + v.vg.read(from, end); + v.vdh_prime.read(from, end); + v.vg_a.read(from, end); + v.vserver_time.read(from, end); +} +inline void MTPserver_DH_inner_data::write(mtpBuffer &to) const { + const MTPDserver_DH_inner_data &v(c_server_DH_inner_data()); + v.vnonce.write(to); + v.vserver_nonce.write(to); + v.vg.write(to); + v.vdh_prime.write(to); + v.vg_a.write(to); + v.vserver_time.write(to); +} +inline MTPserver_DH_inner_data::MTPserver_DH_inner_data(MTPDserver_DH_inner_data *_data) : mtpDataOwner(_data) { +} +inline MTPserver_DH_inner_data MTP_server_DH_inner_data(const MTPint128 &_nonce, const MTPint128 &_server_nonce, MTPint _g, const MTPstring &_dh_prime, const MTPstring &_g_a, MTPint _server_time) { + return MTPserver_DH_inner_data(new MTPDserver_DH_inner_data(_nonce, _server_nonce, _g, _dh_prime, _g_a, _server_time)); +} + +inline MTPclient_DH_Inner_Data::MTPclient_DH_Inner_Data() : mtpDataOwner(new MTPDclient_DH_inner_data()) { +} + +inline uint32 MTPclient_DH_Inner_Data::size() const { + const MTPDclient_DH_inner_data &v(c_client_DH_inner_data()); + return v.vnonce.size() + v.vserver_nonce.size() + v.vretry_id.size() + v.vg_b.size(); +} +inline mtpTypeId MTPclient_DH_Inner_Data::type() const { + return mtpc_client_DH_inner_data; +} +inline void MTPclient_DH_Inner_Data::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_client_DH_inner_data) throw mtpErrorUnexpected(cons, "MTPclient_DH_Inner_Data"); + + if (!data) setData(new MTPDclient_DH_inner_data()); + MTPDclient_DH_inner_data &v(_client_DH_inner_data()); + v.vnonce.read(from, end); + v.vserver_nonce.read(from, end); + v.vretry_id.read(from, end); + v.vg_b.read(from, end); +} +inline void MTPclient_DH_Inner_Data::write(mtpBuffer &to) const { + const MTPDclient_DH_inner_data &v(c_client_DH_inner_data()); + v.vnonce.write(to); + v.vserver_nonce.write(to); + v.vretry_id.write(to); + v.vg_b.write(to); +} +inline MTPclient_DH_Inner_Data::MTPclient_DH_Inner_Data(MTPDclient_DH_inner_data *_data) : mtpDataOwner(_data) { +} +inline MTPclient_DH_Inner_Data MTP_client_DH_inner_data(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPlong &_retry_id, const MTPstring &_g_b) { + return MTPclient_DH_Inner_Data(new MTPDclient_DH_inner_data(_nonce, _server_nonce, _retry_id, _g_b)); +} + +inline uint32 MTPset_client_DH_params_answer::size() const { + switch (_type) { + case mtpc_dh_gen_ok: { + const MTPDdh_gen_ok &v(c_dh_gen_ok()); + return v.vnonce.size() + v.vserver_nonce.size() + v.vnew_nonce_hash1.size(); + } + case mtpc_dh_gen_retry: { + const MTPDdh_gen_retry &v(c_dh_gen_retry()); + return v.vnonce.size() + v.vserver_nonce.size() + v.vnew_nonce_hash2.size(); + } + case mtpc_dh_gen_fail: { + const MTPDdh_gen_fail &v(c_dh_gen_fail()); + return v.vnonce.size() + v.vserver_nonce.size() + v.vnew_nonce_hash3.size(); + } + } + return 0; +} +inline mtpTypeId MTPset_client_DH_params_answer::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPset_client_DH_params_answer::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_dh_gen_ok: _type = cons; { + if (!data) setData(new MTPDdh_gen_ok()); + MTPDdh_gen_ok &v(_dh_gen_ok()); + v.vnonce.read(from, end); + v.vserver_nonce.read(from, end); + v.vnew_nonce_hash1.read(from, end); + } break; + case mtpc_dh_gen_retry: _type = cons; { + if (!data) setData(new MTPDdh_gen_retry()); + MTPDdh_gen_retry &v(_dh_gen_retry()); + v.vnonce.read(from, end); + v.vserver_nonce.read(from, end); + v.vnew_nonce_hash2.read(from, end); + } break; + case mtpc_dh_gen_fail: _type = cons; { + if (!data) setData(new MTPDdh_gen_fail()); + MTPDdh_gen_fail &v(_dh_gen_fail()); + v.vnonce.read(from, end); + v.vserver_nonce.read(from, end); + v.vnew_nonce_hash3.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPset_client_DH_params_answer"); + } +} +inline void MTPset_client_DH_params_answer::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_dh_gen_ok: { + const MTPDdh_gen_ok &v(c_dh_gen_ok()); + v.vnonce.write(to); + v.vserver_nonce.write(to); + v.vnew_nonce_hash1.write(to); + } break; + case mtpc_dh_gen_retry: { + const MTPDdh_gen_retry &v(c_dh_gen_retry()); + v.vnonce.write(to); + v.vserver_nonce.write(to); + v.vnew_nonce_hash2.write(to); + } break; + case mtpc_dh_gen_fail: { + const MTPDdh_gen_fail &v(c_dh_gen_fail()); + v.vnonce.write(to); + v.vserver_nonce.write(to); + v.vnew_nonce_hash3.write(to); + } break; + } +} +inline MTPset_client_DH_params_answer::MTPset_client_DH_params_answer(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_dh_gen_ok: setData(new MTPDdh_gen_ok()); break; + case mtpc_dh_gen_retry: setData(new MTPDdh_gen_retry()); break; + case mtpc_dh_gen_fail: setData(new MTPDdh_gen_fail()); break; + default: throw mtpErrorBadTypeId(type, "MTPset_client_DH_params_answer"); + } +} +inline MTPset_client_DH_params_answer::MTPset_client_DH_params_answer(MTPDdh_gen_ok *_data) : _type(mtpc_dh_gen_ok), mtpDataOwner(_data) { +} +inline MTPset_client_DH_params_answer::MTPset_client_DH_params_answer(MTPDdh_gen_retry *_data) : _type(mtpc_dh_gen_retry), mtpDataOwner(_data) { +} +inline MTPset_client_DH_params_answer::MTPset_client_DH_params_answer(MTPDdh_gen_fail *_data) : _type(mtpc_dh_gen_fail), mtpDataOwner(_data) { +} +inline MTPset_client_DH_params_answer MTP_dh_gen_ok(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint128 &_new_nonce_hash1) { + return MTPset_client_DH_params_answer(new MTPDdh_gen_ok(_nonce, _server_nonce, _new_nonce_hash1)); +} +inline MTPset_client_DH_params_answer MTP_dh_gen_retry(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint128 &_new_nonce_hash2) { + return MTPset_client_DH_params_answer(new MTPDdh_gen_retry(_nonce, _server_nonce, _new_nonce_hash2)); +} +inline MTPset_client_DH_params_answer MTP_dh_gen_fail(const MTPint128 &_nonce, const MTPint128 &_server_nonce, const MTPint128 &_new_nonce_hash3) { + return MTPset_client_DH_params_answer(new MTPDdh_gen_fail(_nonce, _server_nonce, _new_nonce_hash3)); +} + +inline MTPmsgsAck::MTPmsgsAck() : mtpDataOwner(new MTPDmsgs_ack()) { +} + +inline uint32 MTPmsgsAck::size() const { + const MTPDmsgs_ack &v(c_msgs_ack()); + return v.vmsg_ids.size(); +} +inline mtpTypeId MTPmsgsAck::type() const { + return mtpc_msgs_ack; +} +inline void MTPmsgsAck::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_msgs_ack) throw mtpErrorUnexpected(cons, "MTPmsgsAck"); + + if (!data) setData(new MTPDmsgs_ack()); + MTPDmsgs_ack &v(_msgs_ack()); + v.vmsg_ids.read(from, end); +} +inline void MTPmsgsAck::write(mtpBuffer &to) const { + const MTPDmsgs_ack &v(c_msgs_ack()); + v.vmsg_ids.write(to); +} +inline MTPmsgsAck::MTPmsgsAck(MTPDmsgs_ack *_data) : mtpDataOwner(_data) { +} +inline MTPmsgsAck MTP_msgs_ack(const MTPVector &_msg_ids) { + return MTPmsgsAck(new MTPDmsgs_ack(_msg_ids)); +} + +inline uint32 MTPbadMsgNotification::size() const { + switch (_type) { + case mtpc_bad_msg_notification: { + const MTPDbad_msg_notification &v(c_bad_msg_notification()); + return v.vbad_msg_id.size() + v.vbad_msg_seqno.size() + v.verror_code.size(); + } + case mtpc_bad_server_salt: { + const MTPDbad_server_salt &v(c_bad_server_salt()); + return v.vbad_msg_id.size() + v.vbad_msg_seqno.size() + v.verror_code.size() + v.vnew_server_salt.size(); + } + } + return 0; +} +inline mtpTypeId MTPbadMsgNotification::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPbadMsgNotification::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_bad_msg_notification: _type = cons; { + if (!data) setData(new MTPDbad_msg_notification()); + MTPDbad_msg_notification &v(_bad_msg_notification()); + v.vbad_msg_id.read(from, end); + v.vbad_msg_seqno.read(from, end); + v.verror_code.read(from, end); + } break; + case mtpc_bad_server_salt: _type = cons; { + if (!data) setData(new MTPDbad_server_salt()); + MTPDbad_server_salt &v(_bad_server_salt()); + v.vbad_msg_id.read(from, end); + v.vbad_msg_seqno.read(from, end); + v.verror_code.read(from, end); + v.vnew_server_salt.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPbadMsgNotification"); + } +} +inline void MTPbadMsgNotification::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_bad_msg_notification: { + const MTPDbad_msg_notification &v(c_bad_msg_notification()); + v.vbad_msg_id.write(to); + v.vbad_msg_seqno.write(to); + v.verror_code.write(to); + } break; + case mtpc_bad_server_salt: { + const MTPDbad_server_salt &v(c_bad_server_salt()); + v.vbad_msg_id.write(to); + v.vbad_msg_seqno.write(to); + v.verror_code.write(to); + v.vnew_server_salt.write(to); + } break; + } +} +inline MTPbadMsgNotification::MTPbadMsgNotification(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_bad_msg_notification: setData(new MTPDbad_msg_notification()); break; + case mtpc_bad_server_salt: setData(new MTPDbad_server_salt()); break; + default: throw mtpErrorBadTypeId(type, "MTPbadMsgNotification"); + } +} +inline MTPbadMsgNotification::MTPbadMsgNotification(MTPDbad_msg_notification *_data) : _type(mtpc_bad_msg_notification), mtpDataOwner(_data) { +} +inline MTPbadMsgNotification::MTPbadMsgNotification(MTPDbad_server_salt *_data) : _type(mtpc_bad_server_salt), mtpDataOwner(_data) { +} +inline MTPbadMsgNotification MTP_bad_msg_notification(const MTPlong &_bad_msg_id, MTPint _bad_msg_seqno, MTPint _error_code) { + return MTPbadMsgNotification(new MTPDbad_msg_notification(_bad_msg_id, _bad_msg_seqno, _error_code)); +} +inline MTPbadMsgNotification MTP_bad_server_salt(const MTPlong &_bad_msg_id, MTPint _bad_msg_seqno, MTPint _error_code, const MTPlong &_new_server_salt) { + return MTPbadMsgNotification(new MTPDbad_server_salt(_bad_msg_id, _bad_msg_seqno, _error_code, _new_server_salt)); +} + +inline MTPmsgsStateReq::MTPmsgsStateReq() : mtpDataOwner(new MTPDmsgs_state_req()) { +} + +inline uint32 MTPmsgsStateReq::size() const { + const MTPDmsgs_state_req &v(c_msgs_state_req()); + return v.vmsg_ids.size(); +} +inline mtpTypeId MTPmsgsStateReq::type() const { + return mtpc_msgs_state_req; +} +inline void MTPmsgsStateReq::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_msgs_state_req) throw mtpErrorUnexpected(cons, "MTPmsgsStateReq"); + + if (!data) setData(new MTPDmsgs_state_req()); + MTPDmsgs_state_req &v(_msgs_state_req()); + v.vmsg_ids.read(from, end); +} +inline void MTPmsgsStateReq::write(mtpBuffer &to) const { + const MTPDmsgs_state_req &v(c_msgs_state_req()); + v.vmsg_ids.write(to); +} +inline MTPmsgsStateReq::MTPmsgsStateReq(MTPDmsgs_state_req *_data) : mtpDataOwner(_data) { +} +inline MTPmsgsStateReq MTP_msgs_state_req(const MTPVector &_msg_ids) { + return MTPmsgsStateReq(new MTPDmsgs_state_req(_msg_ids)); +} + +inline MTPmsgsStateInfo::MTPmsgsStateInfo() : mtpDataOwner(new MTPDmsgs_state_info()) { +} + +inline uint32 MTPmsgsStateInfo::size() const { + const MTPDmsgs_state_info &v(c_msgs_state_info()); + return v.vreq_msg_id.size() + v.vinfo.size(); +} +inline mtpTypeId MTPmsgsStateInfo::type() const { + return mtpc_msgs_state_info; +} +inline void MTPmsgsStateInfo::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_msgs_state_info) throw mtpErrorUnexpected(cons, "MTPmsgsStateInfo"); + + if (!data) setData(new MTPDmsgs_state_info()); + MTPDmsgs_state_info &v(_msgs_state_info()); + v.vreq_msg_id.read(from, end); + v.vinfo.read(from, end); +} +inline void MTPmsgsStateInfo::write(mtpBuffer &to) const { + const MTPDmsgs_state_info &v(c_msgs_state_info()); + v.vreq_msg_id.write(to); + v.vinfo.write(to); +} +inline MTPmsgsStateInfo::MTPmsgsStateInfo(MTPDmsgs_state_info *_data) : mtpDataOwner(_data) { +} +inline MTPmsgsStateInfo MTP_msgs_state_info(const MTPlong &_req_msg_id, const MTPstring &_info) { + return MTPmsgsStateInfo(new MTPDmsgs_state_info(_req_msg_id, _info)); +} + +inline MTPmsgsAllInfo::MTPmsgsAllInfo() : mtpDataOwner(new MTPDmsgs_all_info()) { +} + +inline uint32 MTPmsgsAllInfo::size() const { + const MTPDmsgs_all_info &v(c_msgs_all_info()); + return v.vmsg_ids.size() + v.vinfo.size(); +} +inline mtpTypeId MTPmsgsAllInfo::type() const { + return mtpc_msgs_all_info; +} +inline void MTPmsgsAllInfo::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_msgs_all_info) throw mtpErrorUnexpected(cons, "MTPmsgsAllInfo"); + + if (!data) setData(new MTPDmsgs_all_info()); + MTPDmsgs_all_info &v(_msgs_all_info()); + v.vmsg_ids.read(from, end); + v.vinfo.read(from, end); +} +inline void MTPmsgsAllInfo::write(mtpBuffer &to) const { + const MTPDmsgs_all_info &v(c_msgs_all_info()); + v.vmsg_ids.write(to); + v.vinfo.write(to); +} +inline MTPmsgsAllInfo::MTPmsgsAllInfo(MTPDmsgs_all_info *_data) : mtpDataOwner(_data) { +} +inline MTPmsgsAllInfo MTP_msgs_all_info(const MTPVector &_msg_ids, const MTPstring &_info) { + return MTPmsgsAllInfo(new MTPDmsgs_all_info(_msg_ids, _info)); +} + +inline uint32 MTPmsgDetailedInfo::size() const { + switch (_type) { + case mtpc_msg_detailed_info: { + const MTPDmsg_detailed_info &v(c_msg_detailed_info()); + return v.vmsg_id.size() + v.vanswer_msg_id.size() + v.vbytes.size() + v.vstatus.size(); + } + case mtpc_msg_new_detailed_info: { + const MTPDmsg_new_detailed_info &v(c_msg_new_detailed_info()); + return v.vanswer_msg_id.size() + v.vbytes.size() + v.vstatus.size(); + } + } + return 0; +} +inline mtpTypeId MTPmsgDetailedInfo::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmsgDetailedInfo::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_msg_detailed_info: _type = cons; { + if (!data) setData(new MTPDmsg_detailed_info()); + MTPDmsg_detailed_info &v(_msg_detailed_info()); + v.vmsg_id.read(from, end); + v.vanswer_msg_id.read(from, end); + v.vbytes.read(from, end); + v.vstatus.read(from, end); + } break; + case mtpc_msg_new_detailed_info: _type = cons; { + if (!data) setData(new MTPDmsg_new_detailed_info()); + MTPDmsg_new_detailed_info &v(_msg_new_detailed_info()); + v.vanswer_msg_id.read(from, end); + v.vbytes.read(from, end); + v.vstatus.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmsgDetailedInfo"); + } +} +inline void MTPmsgDetailedInfo::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_msg_detailed_info: { + const MTPDmsg_detailed_info &v(c_msg_detailed_info()); + v.vmsg_id.write(to); + v.vanswer_msg_id.write(to); + v.vbytes.write(to); + v.vstatus.write(to); + } break; + case mtpc_msg_new_detailed_info: { + const MTPDmsg_new_detailed_info &v(c_msg_new_detailed_info()); + v.vanswer_msg_id.write(to); + v.vbytes.write(to); + v.vstatus.write(to); + } break; + } +} +inline MTPmsgDetailedInfo::MTPmsgDetailedInfo(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_msg_detailed_info: setData(new MTPDmsg_detailed_info()); break; + case mtpc_msg_new_detailed_info: setData(new MTPDmsg_new_detailed_info()); break; + default: throw mtpErrorBadTypeId(type, "MTPmsgDetailedInfo"); + } +} +inline MTPmsgDetailedInfo::MTPmsgDetailedInfo(MTPDmsg_detailed_info *_data) : _type(mtpc_msg_detailed_info), mtpDataOwner(_data) { +} +inline MTPmsgDetailedInfo::MTPmsgDetailedInfo(MTPDmsg_new_detailed_info *_data) : _type(mtpc_msg_new_detailed_info), mtpDataOwner(_data) { +} +inline MTPmsgDetailedInfo MTP_msg_detailed_info(const MTPlong &_msg_id, const MTPlong &_answer_msg_id, MTPint _bytes, MTPint _status) { + return MTPmsgDetailedInfo(new MTPDmsg_detailed_info(_msg_id, _answer_msg_id, _bytes, _status)); +} +inline MTPmsgDetailedInfo MTP_msg_new_detailed_info(const MTPlong &_answer_msg_id, MTPint _bytes, MTPint _status) { + return MTPmsgDetailedInfo(new MTPDmsg_new_detailed_info(_answer_msg_id, _bytes, _status)); +} + +inline MTPmsgResendReq::MTPmsgResendReq() : mtpDataOwner(new MTPDmsg_resend_req()) { +} + +inline uint32 MTPmsgResendReq::size() const { + const MTPDmsg_resend_req &v(c_msg_resend_req()); + return v.vmsg_ids.size(); +} +inline mtpTypeId MTPmsgResendReq::type() const { + return mtpc_msg_resend_req; +} +inline void MTPmsgResendReq::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_msg_resend_req) throw mtpErrorUnexpected(cons, "MTPmsgResendReq"); + + if (!data) setData(new MTPDmsg_resend_req()); + MTPDmsg_resend_req &v(_msg_resend_req()); + v.vmsg_ids.read(from, end); +} +inline void MTPmsgResendReq::write(mtpBuffer &to) const { + const MTPDmsg_resend_req &v(c_msg_resend_req()); + v.vmsg_ids.write(to); +} +inline MTPmsgResendReq::MTPmsgResendReq(MTPDmsg_resend_req *_data) : mtpDataOwner(_data) { +} +inline MTPmsgResendReq MTP_msg_resend_req(const MTPVector &_msg_ids) { + return MTPmsgResendReq(new MTPDmsg_resend_req(_msg_ids)); +} + +inline MTPrpcError::MTPrpcError() : mtpDataOwner(new MTPDrpc_error()) { +} + +inline uint32 MTPrpcError::size() const { + const MTPDrpc_error &v(c_rpc_error()); + return v.verror_code.size() + v.verror_message.size(); +} +inline mtpTypeId MTPrpcError::type() const { + return mtpc_rpc_error; +} +inline void MTPrpcError::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_rpc_error) throw mtpErrorUnexpected(cons, "MTPrpcError"); + + if (!data) setData(new MTPDrpc_error()); + MTPDrpc_error &v(_rpc_error()); + v.verror_code.read(from, end); + v.verror_message.read(from, end); +} +inline void MTPrpcError::write(mtpBuffer &to) const { + const MTPDrpc_error &v(c_rpc_error()); + v.verror_code.write(to); + v.verror_message.write(to); +} +inline MTPrpcError::MTPrpcError(MTPDrpc_error *_data) : mtpDataOwner(_data) { +} +inline MTPrpcError MTP_rpc_error(MTPint _error_code, const MTPstring &_error_message) { + return MTPrpcError(new MTPDrpc_error(_error_code, _error_message)); +} + +inline uint32 MTPrpcDropAnswer::size() const { + switch (_type) { + case mtpc_rpc_answer_dropped: { + const MTPDrpc_answer_dropped &v(c_rpc_answer_dropped()); + return v.vmsg_id.size() + v.vseq_no.size() + v.vbytes.size(); + } + } + return 0; +} +inline mtpTypeId MTPrpcDropAnswer::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPrpcDropAnswer::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_rpc_answer_unknown: _type = cons; break; + case mtpc_rpc_answer_dropped_running: _type = cons; break; + case mtpc_rpc_answer_dropped: _type = cons; { + if (!data) setData(new MTPDrpc_answer_dropped()); + MTPDrpc_answer_dropped &v(_rpc_answer_dropped()); + v.vmsg_id.read(from, end); + v.vseq_no.read(from, end); + v.vbytes.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPrpcDropAnswer"); + } +} +inline void MTPrpcDropAnswer::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_rpc_answer_dropped: { + const MTPDrpc_answer_dropped &v(c_rpc_answer_dropped()); + v.vmsg_id.write(to); + v.vseq_no.write(to); + v.vbytes.write(to); + } break; + } +} +inline MTPrpcDropAnswer::MTPrpcDropAnswer(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_rpc_answer_unknown: break; + case mtpc_rpc_answer_dropped_running: break; + case mtpc_rpc_answer_dropped: setData(new MTPDrpc_answer_dropped()); break; + default: throw mtpErrorBadTypeId(type, "MTPrpcDropAnswer"); + } +} +inline MTPrpcDropAnswer::MTPrpcDropAnswer(MTPDrpc_answer_dropped *_data) : _type(mtpc_rpc_answer_dropped), mtpDataOwner(_data) { +} +inline MTPrpcDropAnswer MTP_rpc_answer_unknown() { + return MTPrpcDropAnswer(mtpc_rpc_answer_unknown); +} +inline MTPrpcDropAnswer MTP_rpc_answer_dropped_running() { + return MTPrpcDropAnswer(mtpc_rpc_answer_dropped_running); +} +inline MTPrpcDropAnswer MTP_rpc_answer_dropped(const MTPlong &_msg_id, MTPint _seq_no, MTPint _bytes) { + return MTPrpcDropAnswer(new MTPDrpc_answer_dropped(_msg_id, _seq_no, _bytes)); +} + +inline MTPfutureSalt::MTPfutureSalt() : mtpDataOwner(new MTPDfuture_salt()) { +} + +inline uint32 MTPfutureSalt::size() const { + const MTPDfuture_salt &v(c_future_salt()); + return v.vvalid_since.size() + v.vvalid_until.size() + v.vsalt.size(); +} +inline mtpTypeId MTPfutureSalt::type() const { + return mtpc_future_salt; +} +inline void MTPfutureSalt::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_future_salt) throw mtpErrorUnexpected(cons, "MTPfutureSalt"); + + if (!data) setData(new MTPDfuture_salt()); + MTPDfuture_salt &v(_future_salt()); + v.vvalid_since.read(from, end); + v.vvalid_until.read(from, end); + v.vsalt.read(from, end); +} +inline void MTPfutureSalt::write(mtpBuffer &to) const { + const MTPDfuture_salt &v(c_future_salt()); + v.vvalid_since.write(to); + v.vvalid_until.write(to); + v.vsalt.write(to); +} +inline MTPfutureSalt::MTPfutureSalt(MTPDfuture_salt *_data) : mtpDataOwner(_data) { +} +inline MTPfutureSalt MTP_future_salt(MTPint _valid_since, MTPint _valid_until, const MTPlong &_salt) { + return MTPfutureSalt(new MTPDfuture_salt(_valid_since, _valid_until, _salt)); +} + +inline MTPfutureSalts::MTPfutureSalts() : mtpDataOwner(new MTPDfuture_salts()) { +} + +inline uint32 MTPfutureSalts::size() const { + const MTPDfuture_salts &v(c_future_salts()); + return v.vreq_msg_id.size() + v.vnow.size() + v.vsalts.size(); +} +inline mtpTypeId MTPfutureSalts::type() const { + return mtpc_future_salts; +} +inline void MTPfutureSalts::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_future_salts) throw mtpErrorUnexpected(cons, "MTPfutureSalts"); + + if (!data) setData(new MTPDfuture_salts()); + MTPDfuture_salts &v(_future_salts()); + v.vreq_msg_id.read(from, end); + v.vnow.read(from, end); + v.vsalts.read(from, end); +} +inline void MTPfutureSalts::write(mtpBuffer &to) const { + const MTPDfuture_salts &v(c_future_salts()); + v.vreq_msg_id.write(to); + v.vnow.write(to); + v.vsalts.write(to); +} +inline MTPfutureSalts::MTPfutureSalts(MTPDfuture_salts *_data) : mtpDataOwner(_data) { +} +inline MTPfutureSalts MTP_future_salts(const MTPlong &_req_msg_id, MTPint _now, const MTPvector &_salts) { + return MTPfutureSalts(new MTPDfuture_salts(_req_msg_id, _now, _salts)); +} + +inline MTPpong::MTPpong() : mtpDataOwner(new MTPDpong()) { +} + +inline uint32 MTPpong::size() const { + const MTPDpong &v(c_pong()); + return v.vmsg_id.size() + v.vping_id.size(); +} +inline mtpTypeId MTPpong::type() const { + return mtpc_pong; +} +inline void MTPpong::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_pong) throw mtpErrorUnexpected(cons, "MTPpong"); + + if (!data) setData(new MTPDpong()); + MTPDpong &v(_pong()); + v.vmsg_id.read(from, end); + v.vping_id.read(from, end); +} +inline void MTPpong::write(mtpBuffer &to) const { + const MTPDpong &v(c_pong()); + v.vmsg_id.write(to); + v.vping_id.write(to); +} +inline MTPpong::MTPpong(MTPDpong *_data) : mtpDataOwner(_data) { +} +inline MTPpong MTP_pong(const MTPlong &_msg_id, const MTPlong &_ping_id) { + return MTPpong(new MTPDpong(_msg_id, _ping_id)); +} + +inline uint32 MTPdestroySessionRes::size() const { + switch (_type) { + case mtpc_destroy_session_ok: { + const MTPDdestroy_session_ok &v(c_destroy_session_ok()); + return v.vsession_id.size(); + } + case mtpc_destroy_session_none: { + const MTPDdestroy_session_none &v(c_destroy_session_none()); + return v.vsession_id.size(); + } + } + return 0; +} +inline mtpTypeId MTPdestroySessionRes::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPdestroySessionRes::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_destroy_session_ok: _type = cons; { + if (!data) setData(new MTPDdestroy_session_ok()); + MTPDdestroy_session_ok &v(_destroy_session_ok()); + v.vsession_id.read(from, end); + } break; + case mtpc_destroy_session_none: _type = cons; { + if (!data) setData(new MTPDdestroy_session_none()); + MTPDdestroy_session_none &v(_destroy_session_none()); + v.vsession_id.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPdestroySessionRes"); + } +} +inline void MTPdestroySessionRes::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_destroy_session_ok: { + const MTPDdestroy_session_ok &v(c_destroy_session_ok()); + v.vsession_id.write(to); + } break; + case mtpc_destroy_session_none: { + const MTPDdestroy_session_none &v(c_destroy_session_none()); + v.vsession_id.write(to); + } break; + } +} +inline MTPdestroySessionRes::MTPdestroySessionRes(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_destroy_session_ok: setData(new MTPDdestroy_session_ok()); break; + case mtpc_destroy_session_none: setData(new MTPDdestroy_session_none()); break; + default: throw mtpErrorBadTypeId(type, "MTPdestroySessionRes"); + } +} +inline MTPdestroySessionRes::MTPdestroySessionRes(MTPDdestroy_session_ok *_data) : _type(mtpc_destroy_session_ok), mtpDataOwner(_data) { +} +inline MTPdestroySessionRes::MTPdestroySessionRes(MTPDdestroy_session_none *_data) : _type(mtpc_destroy_session_none), mtpDataOwner(_data) { +} +inline MTPdestroySessionRes MTP_destroy_session_ok(const MTPlong &_session_id) { + return MTPdestroySessionRes(new MTPDdestroy_session_ok(_session_id)); +} +inline MTPdestroySessionRes MTP_destroy_session_none(const MTPlong &_session_id) { + return MTPdestroySessionRes(new MTPDdestroy_session_none(_session_id)); +} + +inline MTPnewSession::MTPnewSession() : mtpDataOwner(new MTPDnew_session_created()) { +} + +inline uint32 MTPnewSession::size() const { + const MTPDnew_session_created &v(c_new_session_created()); + return v.vfirst_msg_id.size() + v.vunique_id.size() + v.vserver_salt.size(); +} +inline mtpTypeId MTPnewSession::type() const { + return mtpc_new_session_created; +} +inline void MTPnewSession::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_new_session_created) throw mtpErrorUnexpected(cons, "MTPnewSession"); + + if (!data) setData(new MTPDnew_session_created()); + MTPDnew_session_created &v(_new_session_created()); + v.vfirst_msg_id.read(from, end); + v.vunique_id.read(from, end); + v.vserver_salt.read(from, end); +} +inline void MTPnewSession::write(mtpBuffer &to) const { + const MTPDnew_session_created &v(c_new_session_created()); + v.vfirst_msg_id.write(to); + v.vunique_id.write(to); + v.vserver_salt.write(to); +} +inline MTPnewSession::MTPnewSession(MTPDnew_session_created *_data) : mtpDataOwner(_data) { +} +inline MTPnewSession MTP_new_session_created(const MTPlong &_first_msg_id, const MTPlong &_unique_id, const MTPlong &_server_salt) { + return MTPnewSession(new MTPDnew_session_created(_first_msg_id, _unique_id, _server_salt)); +} + +inline MTPhttpWait::MTPhttpWait() : mtpDataOwner(new MTPDhttp_wait()) { +} + +inline uint32 MTPhttpWait::size() const { + const MTPDhttp_wait &v(c_http_wait()); + return v.vmax_delay.size() + v.vwait_after.size() + v.vmax_wait.size(); +} +inline mtpTypeId MTPhttpWait::type() const { + return mtpc_http_wait; +} +inline void MTPhttpWait::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_http_wait) throw mtpErrorUnexpected(cons, "MTPhttpWait"); + + if (!data) setData(new MTPDhttp_wait()); + MTPDhttp_wait &v(_http_wait()); + v.vmax_delay.read(from, end); + v.vwait_after.read(from, end); + v.vmax_wait.read(from, end); +} +inline void MTPhttpWait::write(mtpBuffer &to) const { + const MTPDhttp_wait &v(c_http_wait()); + v.vmax_delay.write(to); + v.vwait_after.write(to); + v.vmax_wait.write(to); +} +inline MTPhttpWait::MTPhttpWait(MTPDhttp_wait *_data) : mtpDataOwner(_data) { +} +inline MTPhttpWait MTP_http_wait(MTPint _max_delay, MTPint _wait_after, MTPint _max_wait) { + return MTPhttpWait(new MTPDhttp_wait(_max_delay, _wait_after, _max_wait)); +} + +inline uint32 MTPinputPeer::size() const { + switch (_type) { + case mtpc_inputPeerContact: { + const MTPDinputPeerContact &v(c_inputPeerContact()); + return v.vuser_id.size(); + } + case mtpc_inputPeerForeign: { + const MTPDinputPeerForeign &v(c_inputPeerForeign()); + return v.vuser_id.size() + v.vaccess_hash.size(); + } + case mtpc_inputPeerChat: { + const MTPDinputPeerChat &v(c_inputPeerChat()); + return v.vchat_id.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputPeer::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputPeer::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputPeerEmpty: _type = cons; break; + case mtpc_inputPeerSelf: _type = cons; break; + case mtpc_inputPeerContact: _type = cons; { + if (!data) setData(new MTPDinputPeerContact()); + MTPDinputPeerContact &v(_inputPeerContact()); + v.vuser_id.read(from, end); + } break; + case mtpc_inputPeerForeign: _type = cons; { + if (!data) setData(new MTPDinputPeerForeign()); + MTPDinputPeerForeign &v(_inputPeerForeign()); + v.vuser_id.read(from, end); + v.vaccess_hash.read(from, end); + } break; + case mtpc_inputPeerChat: _type = cons; { + if (!data) setData(new MTPDinputPeerChat()); + MTPDinputPeerChat &v(_inputPeerChat()); + v.vchat_id.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputPeer"); + } +} +inline void MTPinputPeer::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputPeerContact: { + const MTPDinputPeerContact &v(c_inputPeerContact()); + v.vuser_id.write(to); + } break; + case mtpc_inputPeerForeign: { + const MTPDinputPeerForeign &v(c_inputPeerForeign()); + v.vuser_id.write(to); + v.vaccess_hash.write(to); + } break; + case mtpc_inputPeerChat: { + const MTPDinputPeerChat &v(c_inputPeerChat()); + v.vchat_id.write(to); + } break; + } +} +inline MTPinputPeer::MTPinputPeer(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputPeerEmpty: break; + case mtpc_inputPeerSelf: break; + case mtpc_inputPeerContact: setData(new MTPDinputPeerContact()); break; + case mtpc_inputPeerForeign: setData(new MTPDinputPeerForeign()); break; + case mtpc_inputPeerChat: setData(new MTPDinputPeerChat()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputPeer"); + } +} +inline MTPinputPeer::MTPinputPeer(MTPDinputPeerContact *_data) : _type(mtpc_inputPeerContact), mtpDataOwner(_data) { +} +inline MTPinputPeer::MTPinputPeer(MTPDinputPeerForeign *_data) : _type(mtpc_inputPeerForeign), mtpDataOwner(_data) { +} +inline MTPinputPeer::MTPinputPeer(MTPDinputPeerChat *_data) : _type(mtpc_inputPeerChat), mtpDataOwner(_data) { +} +inline MTPinputPeer MTP_inputPeerEmpty() { + return MTPinputPeer(mtpc_inputPeerEmpty); +} +inline MTPinputPeer MTP_inputPeerSelf() { + return MTPinputPeer(mtpc_inputPeerSelf); +} +inline MTPinputPeer MTP_inputPeerContact(MTPint _user_id) { + return MTPinputPeer(new MTPDinputPeerContact(_user_id)); +} +inline MTPinputPeer MTP_inputPeerForeign(MTPint _user_id, const MTPlong &_access_hash) { + return MTPinputPeer(new MTPDinputPeerForeign(_user_id, _access_hash)); +} +inline MTPinputPeer MTP_inputPeerChat(MTPint _chat_id) { + return MTPinputPeer(new MTPDinputPeerChat(_chat_id)); +} + +inline uint32 MTPinputUser::size() const { + switch (_type) { + case mtpc_inputUserContact: { + const MTPDinputUserContact &v(c_inputUserContact()); + return v.vuser_id.size(); + } + case mtpc_inputUserForeign: { + const MTPDinputUserForeign &v(c_inputUserForeign()); + return v.vuser_id.size() + v.vaccess_hash.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputUser::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputUser::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputUserEmpty: _type = cons; break; + case mtpc_inputUserSelf: _type = cons; break; + case mtpc_inputUserContact: _type = cons; { + if (!data) setData(new MTPDinputUserContact()); + MTPDinputUserContact &v(_inputUserContact()); + v.vuser_id.read(from, end); + } break; + case mtpc_inputUserForeign: _type = cons; { + if (!data) setData(new MTPDinputUserForeign()); + MTPDinputUserForeign &v(_inputUserForeign()); + v.vuser_id.read(from, end); + v.vaccess_hash.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputUser"); + } +} +inline void MTPinputUser::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputUserContact: { + const MTPDinputUserContact &v(c_inputUserContact()); + v.vuser_id.write(to); + } break; + case mtpc_inputUserForeign: { + const MTPDinputUserForeign &v(c_inputUserForeign()); + v.vuser_id.write(to); + v.vaccess_hash.write(to); + } break; + } +} +inline MTPinputUser::MTPinputUser(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputUserEmpty: break; + case mtpc_inputUserSelf: break; + case mtpc_inputUserContact: setData(new MTPDinputUserContact()); break; + case mtpc_inputUserForeign: setData(new MTPDinputUserForeign()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputUser"); + } +} +inline MTPinputUser::MTPinputUser(MTPDinputUserContact *_data) : _type(mtpc_inputUserContact), mtpDataOwner(_data) { +} +inline MTPinputUser::MTPinputUser(MTPDinputUserForeign *_data) : _type(mtpc_inputUserForeign), mtpDataOwner(_data) { +} +inline MTPinputUser MTP_inputUserEmpty() { + return MTPinputUser(mtpc_inputUserEmpty); +} +inline MTPinputUser MTP_inputUserSelf() { + return MTPinputUser(mtpc_inputUserSelf); +} +inline MTPinputUser MTP_inputUserContact(MTPint _user_id) { + return MTPinputUser(new MTPDinputUserContact(_user_id)); +} +inline MTPinputUser MTP_inputUserForeign(MTPint _user_id, const MTPlong &_access_hash) { + return MTPinputUser(new MTPDinputUserForeign(_user_id, _access_hash)); +} + +inline MTPinputContact::MTPinputContact() : mtpDataOwner(new MTPDinputPhoneContact()) { +} + +inline uint32 MTPinputContact::size() const { + const MTPDinputPhoneContact &v(c_inputPhoneContact()); + return v.vclient_id.size() + v.vphone.size() + v.vfirst_name.size() + v.vlast_name.size(); +} +inline mtpTypeId MTPinputContact::type() const { + return mtpc_inputPhoneContact; +} +inline void MTPinputContact::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_inputPhoneContact) throw mtpErrorUnexpected(cons, "MTPinputContact"); + + if (!data) setData(new MTPDinputPhoneContact()); + MTPDinputPhoneContact &v(_inputPhoneContact()); + v.vclient_id.read(from, end); + v.vphone.read(from, end); + v.vfirst_name.read(from, end); + v.vlast_name.read(from, end); +} +inline void MTPinputContact::write(mtpBuffer &to) const { + const MTPDinputPhoneContact &v(c_inputPhoneContact()); + v.vclient_id.write(to); + v.vphone.write(to); + v.vfirst_name.write(to); + v.vlast_name.write(to); +} +inline MTPinputContact::MTPinputContact(MTPDinputPhoneContact *_data) : mtpDataOwner(_data) { +} +inline MTPinputContact MTP_inputPhoneContact(const MTPlong &_client_id, const MTPstring &_phone, const MTPstring &_first_name, const MTPstring &_last_name) { + return MTPinputContact(new MTPDinputPhoneContact(_client_id, _phone, _first_name, _last_name)); +} + +inline uint32 MTPinputFile::size() const { + switch (_type) { + case mtpc_inputFile: { + const MTPDinputFile &v(c_inputFile()); + return v.vid.size() + v.vparts.size() + v.vname.size() + v.vmd5_checksum.size(); + } + case mtpc_inputFileBig: { + const MTPDinputFileBig &v(c_inputFileBig()); + return v.vid.size() + v.vparts.size() + v.vname.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputFile::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputFile::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputFile: _type = cons; { + if (!data) setData(new MTPDinputFile()); + MTPDinputFile &v(_inputFile()); + v.vid.read(from, end); + v.vparts.read(from, end); + v.vname.read(from, end); + v.vmd5_checksum.read(from, end); + } break; + case mtpc_inputFileBig: _type = cons; { + if (!data) setData(new MTPDinputFileBig()); + MTPDinputFileBig &v(_inputFileBig()); + v.vid.read(from, end); + v.vparts.read(from, end); + v.vname.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputFile"); + } +} +inline void MTPinputFile::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputFile: { + const MTPDinputFile &v(c_inputFile()); + v.vid.write(to); + v.vparts.write(to); + v.vname.write(to); + v.vmd5_checksum.write(to); + } break; + case mtpc_inputFileBig: { + const MTPDinputFileBig &v(c_inputFileBig()); + v.vid.write(to); + v.vparts.write(to); + v.vname.write(to); + } break; + } +} +inline MTPinputFile::MTPinputFile(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputFile: setData(new MTPDinputFile()); break; + case mtpc_inputFileBig: setData(new MTPDinputFileBig()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputFile"); + } +} +inline MTPinputFile::MTPinputFile(MTPDinputFile *_data) : _type(mtpc_inputFile), mtpDataOwner(_data) { +} +inline MTPinputFile::MTPinputFile(MTPDinputFileBig *_data) : _type(mtpc_inputFileBig), mtpDataOwner(_data) { +} +inline MTPinputFile MTP_inputFile(const MTPlong &_id, MTPint _parts, const MTPstring &_name, const MTPstring &_md5_checksum) { + return MTPinputFile(new MTPDinputFile(_id, _parts, _name, _md5_checksum)); +} +inline MTPinputFile MTP_inputFileBig(const MTPlong &_id, MTPint _parts, const MTPstring &_name) { + return MTPinputFile(new MTPDinputFileBig(_id, _parts, _name)); +} + +inline uint32 MTPinputMedia::size() const { + switch (_type) { + case mtpc_inputMediaUploadedPhoto: { + const MTPDinputMediaUploadedPhoto &v(c_inputMediaUploadedPhoto()); + return v.vfile.size(); + } + case mtpc_inputMediaPhoto: { + const MTPDinputMediaPhoto &v(c_inputMediaPhoto()); + return v.vid.size(); + } + case mtpc_inputMediaGeoPoint: { + const MTPDinputMediaGeoPoint &v(c_inputMediaGeoPoint()); + return v.vgeo_point.size(); + } + case mtpc_inputMediaContact: { + const MTPDinputMediaContact &v(c_inputMediaContact()); + return v.vphone_number.size() + v.vfirst_name.size() + v.vlast_name.size(); + } + case mtpc_inputMediaUploadedVideo: { + const MTPDinputMediaUploadedVideo &v(c_inputMediaUploadedVideo()); + return v.vfile.size() + v.vduration.size() + v.vw.size() + v.vh.size() + v.vmime_type.size(); + } + case mtpc_inputMediaUploadedThumbVideo: { + const MTPDinputMediaUploadedThumbVideo &v(c_inputMediaUploadedThumbVideo()); + return v.vfile.size() + v.vthumb.size() + v.vduration.size() + v.vw.size() + v.vh.size() + v.vmime_type.size(); + } + case mtpc_inputMediaVideo: { + const MTPDinputMediaVideo &v(c_inputMediaVideo()); + return v.vid.size(); + } + case mtpc_inputMediaUploadedAudio: { + const MTPDinputMediaUploadedAudio &v(c_inputMediaUploadedAudio()); + return v.vfile.size() + v.vduration.size() + v.vmime_type.size(); + } + case mtpc_inputMediaAudio: { + const MTPDinputMediaAudio &v(c_inputMediaAudio()); + return v.vid.size(); + } + case mtpc_inputMediaUploadedDocument: { + const MTPDinputMediaUploadedDocument &v(c_inputMediaUploadedDocument()); + return v.vfile.size() + v.vfile_name.size() + v.vmime_type.size(); + } + case mtpc_inputMediaUploadedThumbDocument: { + const MTPDinputMediaUploadedThumbDocument &v(c_inputMediaUploadedThumbDocument()); + return v.vfile.size() + v.vthumb.size() + v.vfile_name.size() + v.vmime_type.size(); + } + case mtpc_inputMediaDocument: { + const MTPDinputMediaDocument &v(c_inputMediaDocument()); + return v.vid.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputMedia::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputMedia::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputMediaEmpty: _type = cons; break; + case mtpc_inputMediaUploadedPhoto: _type = cons; { + if (!data) setData(new MTPDinputMediaUploadedPhoto()); + MTPDinputMediaUploadedPhoto &v(_inputMediaUploadedPhoto()); + v.vfile.read(from, end); + } break; + case mtpc_inputMediaPhoto: _type = cons; { + if (!data) setData(new MTPDinputMediaPhoto()); + MTPDinputMediaPhoto &v(_inputMediaPhoto()); + v.vid.read(from, end); + } break; + case mtpc_inputMediaGeoPoint: _type = cons; { + if (!data) setData(new MTPDinputMediaGeoPoint()); + MTPDinputMediaGeoPoint &v(_inputMediaGeoPoint()); + v.vgeo_point.read(from, end); + } break; + case mtpc_inputMediaContact: _type = cons; { + if (!data) setData(new MTPDinputMediaContact()); + MTPDinputMediaContact &v(_inputMediaContact()); + v.vphone_number.read(from, end); + v.vfirst_name.read(from, end); + v.vlast_name.read(from, end); + } break; + case mtpc_inputMediaUploadedVideo: _type = cons; { + if (!data) setData(new MTPDinputMediaUploadedVideo()); + MTPDinputMediaUploadedVideo &v(_inputMediaUploadedVideo()); + v.vfile.read(from, end); + v.vduration.read(from, end); + v.vw.read(from, end); + v.vh.read(from, end); + v.vmime_type.read(from, end); + } break; + case mtpc_inputMediaUploadedThumbVideo: _type = cons; { + if (!data) setData(new MTPDinputMediaUploadedThumbVideo()); + MTPDinputMediaUploadedThumbVideo &v(_inputMediaUploadedThumbVideo()); + v.vfile.read(from, end); + v.vthumb.read(from, end); + v.vduration.read(from, end); + v.vw.read(from, end); + v.vh.read(from, end); + v.vmime_type.read(from, end); + } break; + case mtpc_inputMediaVideo: _type = cons; { + if (!data) setData(new MTPDinputMediaVideo()); + MTPDinputMediaVideo &v(_inputMediaVideo()); + v.vid.read(from, end); + } break; + case mtpc_inputMediaUploadedAudio: _type = cons; { + if (!data) setData(new MTPDinputMediaUploadedAudio()); + MTPDinputMediaUploadedAudio &v(_inputMediaUploadedAudio()); + v.vfile.read(from, end); + v.vduration.read(from, end); + v.vmime_type.read(from, end); + } break; + case mtpc_inputMediaAudio: _type = cons; { + if (!data) setData(new MTPDinputMediaAudio()); + MTPDinputMediaAudio &v(_inputMediaAudio()); + v.vid.read(from, end); + } break; + case mtpc_inputMediaUploadedDocument: _type = cons; { + if (!data) setData(new MTPDinputMediaUploadedDocument()); + MTPDinputMediaUploadedDocument &v(_inputMediaUploadedDocument()); + v.vfile.read(from, end); + v.vfile_name.read(from, end); + v.vmime_type.read(from, end); + } break; + case mtpc_inputMediaUploadedThumbDocument: _type = cons; { + if (!data) setData(new MTPDinputMediaUploadedThumbDocument()); + MTPDinputMediaUploadedThumbDocument &v(_inputMediaUploadedThumbDocument()); + v.vfile.read(from, end); + v.vthumb.read(from, end); + v.vfile_name.read(from, end); + v.vmime_type.read(from, end); + } break; + case mtpc_inputMediaDocument: _type = cons; { + if (!data) setData(new MTPDinputMediaDocument()); + MTPDinputMediaDocument &v(_inputMediaDocument()); + v.vid.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputMedia"); + } +} +inline void MTPinputMedia::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputMediaUploadedPhoto: { + const MTPDinputMediaUploadedPhoto &v(c_inputMediaUploadedPhoto()); + v.vfile.write(to); + } break; + case mtpc_inputMediaPhoto: { + const MTPDinputMediaPhoto &v(c_inputMediaPhoto()); + v.vid.write(to); + } break; + case mtpc_inputMediaGeoPoint: { + const MTPDinputMediaGeoPoint &v(c_inputMediaGeoPoint()); + v.vgeo_point.write(to); + } break; + case mtpc_inputMediaContact: { + const MTPDinputMediaContact &v(c_inputMediaContact()); + v.vphone_number.write(to); + v.vfirst_name.write(to); + v.vlast_name.write(to); + } break; + case mtpc_inputMediaUploadedVideo: { + const MTPDinputMediaUploadedVideo &v(c_inputMediaUploadedVideo()); + v.vfile.write(to); + v.vduration.write(to); + v.vw.write(to); + v.vh.write(to); + v.vmime_type.write(to); + } break; + case mtpc_inputMediaUploadedThumbVideo: { + const MTPDinputMediaUploadedThumbVideo &v(c_inputMediaUploadedThumbVideo()); + v.vfile.write(to); + v.vthumb.write(to); + v.vduration.write(to); + v.vw.write(to); + v.vh.write(to); + v.vmime_type.write(to); + } break; + case mtpc_inputMediaVideo: { + const MTPDinputMediaVideo &v(c_inputMediaVideo()); + v.vid.write(to); + } break; + case mtpc_inputMediaUploadedAudio: { + const MTPDinputMediaUploadedAudio &v(c_inputMediaUploadedAudio()); + v.vfile.write(to); + v.vduration.write(to); + v.vmime_type.write(to); + } break; + case mtpc_inputMediaAudio: { + const MTPDinputMediaAudio &v(c_inputMediaAudio()); + v.vid.write(to); + } break; + case mtpc_inputMediaUploadedDocument: { + const MTPDinputMediaUploadedDocument &v(c_inputMediaUploadedDocument()); + v.vfile.write(to); + v.vfile_name.write(to); + v.vmime_type.write(to); + } break; + case mtpc_inputMediaUploadedThumbDocument: { + const MTPDinputMediaUploadedThumbDocument &v(c_inputMediaUploadedThumbDocument()); + v.vfile.write(to); + v.vthumb.write(to); + v.vfile_name.write(to); + v.vmime_type.write(to); + } break; + case mtpc_inputMediaDocument: { + const MTPDinputMediaDocument &v(c_inputMediaDocument()); + v.vid.write(to); + } break; + } +} +inline MTPinputMedia::MTPinputMedia(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputMediaEmpty: break; + case mtpc_inputMediaUploadedPhoto: setData(new MTPDinputMediaUploadedPhoto()); break; + case mtpc_inputMediaPhoto: setData(new MTPDinputMediaPhoto()); break; + case mtpc_inputMediaGeoPoint: setData(new MTPDinputMediaGeoPoint()); break; + case mtpc_inputMediaContact: setData(new MTPDinputMediaContact()); break; + case mtpc_inputMediaUploadedVideo: setData(new MTPDinputMediaUploadedVideo()); break; + case mtpc_inputMediaUploadedThumbVideo: setData(new MTPDinputMediaUploadedThumbVideo()); break; + case mtpc_inputMediaVideo: setData(new MTPDinputMediaVideo()); break; + case mtpc_inputMediaUploadedAudio: setData(new MTPDinputMediaUploadedAudio()); break; + case mtpc_inputMediaAudio: setData(new MTPDinputMediaAudio()); break; + case mtpc_inputMediaUploadedDocument: setData(new MTPDinputMediaUploadedDocument()); break; + case mtpc_inputMediaUploadedThumbDocument: setData(new MTPDinputMediaUploadedThumbDocument()); break; + case mtpc_inputMediaDocument: setData(new MTPDinputMediaDocument()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputMedia"); + } +} +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaUploadedPhoto *_data) : _type(mtpc_inputMediaUploadedPhoto), mtpDataOwner(_data) { +} +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaPhoto *_data) : _type(mtpc_inputMediaPhoto), mtpDataOwner(_data) { +} +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaGeoPoint *_data) : _type(mtpc_inputMediaGeoPoint), mtpDataOwner(_data) { +} +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaContact *_data) : _type(mtpc_inputMediaContact), mtpDataOwner(_data) { +} +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaUploadedVideo *_data) : _type(mtpc_inputMediaUploadedVideo), mtpDataOwner(_data) { +} +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaUploadedThumbVideo *_data) : _type(mtpc_inputMediaUploadedThumbVideo), mtpDataOwner(_data) { +} +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaVideo *_data) : _type(mtpc_inputMediaVideo), mtpDataOwner(_data) { +} +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaUploadedAudio *_data) : _type(mtpc_inputMediaUploadedAudio), mtpDataOwner(_data) { +} +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaAudio *_data) : _type(mtpc_inputMediaAudio), mtpDataOwner(_data) { +} +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaUploadedDocument *_data) : _type(mtpc_inputMediaUploadedDocument), mtpDataOwner(_data) { +} +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaUploadedThumbDocument *_data) : _type(mtpc_inputMediaUploadedThumbDocument), mtpDataOwner(_data) { +} +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaDocument *_data) : _type(mtpc_inputMediaDocument), mtpDataOwner(_data) { +} +inline MTPinputMedia MTP_inputMediaEmpty() { + return MTPinputMedia(mtpc_inputMediaEmpty); +} +inline MTPinputMedia MTP_inputMediaUploadedPhoto(const MTPInputFile &_file) { + return MTPinputMedia(new MTPDinputMediaUploadedPhoto(_file)); +} +inline MTPinputMedia MTP_inputMediaPhoto(const MTPInputPhoto &_id) { + return MTPinputMedia(new MTPDinputMediaPhoto(_id)); +} +inline MTPinputMedia MTP_inputMediaGeoPoint(const MTPInputGeoPoint &_geo_point) { + return MTPinputMedia(new MTPDinputMediaGeoPoint(_geo_point)); +} +inline MTPinputMedia MTP_inputMediaContact(const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name) { + return MTPinputMedia(new MTPDinputMediaContact(_phone_number, _first_name, _last_name)); +} +inline MTPinputMedia MTP_inputMediaUploadedVideo(const MTPInputFile &_file, MTPint _duration, MTPint _w, MTPint _h, const MTPstring &_mime_type) { + return MTPinputMedia(new MTPDinputMediaUploadedVideo(_file, _duration, _w, _h, _mime_type)); +} +inline MTPinputMedia MTP_inputMediaUploadedThumbVideo(const MTPInputFile &_file, const MTPInputFile &_thumb, MTPint _duration, MTPint _w, MTPint _h, const MTPstring &_mime_type) { + return MTPinputMedia(new MTPDinputMediaUploadedThumbVideo(_file, _thumb, _duration, _w, _h, _mime_type)); +} +inline MTPinputMedia MTP_inputMediaVideo(const MTPInputVideo &_id) { + return MTPinputMedia(new MTPDinputMediaVideo(_id)); +} +inline MTPinputMedia MTP_inputMediaUploadedAudio(const MTPInputFile &_file, MTPint _duration, const MTPstring &_mime_type) { + return MTPinputMedia(new MTPDinputMediaUploadedAudio(_file, _duration, _mime_type)); +} +inline MTPinputMedia MTP_inputMediaAudio(const MTPInputAudio &_id) { + return MTPinputMedia(new MTPDinputMediaAudio(_id)); +} +inline MTPinputMedia MTP_inputMediaUploadedDocument(const MTPInputFile &_file, const MTPstring &_file_name, const MTPstring &_mime_type) { + return MTPinputMedia(new MTPDinputMediaUploadedDocument(_file, _file_name, _mime_type)); +} +inline MTPinputMedia MTP_inputMediaUploadedThumbDocument(const MTPInputFile &_file, const MTPInputFile &_thumb, const MTPstring &_file_name, const MTPstring &_mime_type) { + return MTPinputMedia(new MTPDinputMediaUploadedThumbDocument(_file, _thumb, _file_name, _mime_type)); +} +inline MTPinputMedia MTP_inputMediaDocument(const MTPInputDocument &_id) { + return MTPinputMedia(new MTPDinputMediaDocument(_id)); +} + +inline uint32 MTPinputChatPhoto::size() const { + switch (_type) { + case mtpc_inputChatUploadedPhoto: { + const MTPDinputChatUploadedPhoto &v(c_inputChatUploadedPhoto()); + return v.vfile.size() + v.vcrop.size(); + } + case mtpc_inputChatPhoto: { + const MTPDinputChatPhoto &v(c_inputChatPhoto()); + return v.vid.size() + v.vcrop.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputChatPhoto::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputChatPhoto::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputChatPhotoEmpty: _type = cons; break; + case mtpc_inputChatUploadedPhoto: _type = cons; { + if (!data) setData(new MTPDinputChatUploadedPhoto()); + MTPDinputChatUploadedPhoto &v(_inputChatUploadedPhoto()); + v.vfile.read(from, end); + v.vcrop.read(from, end); + } break; + case mtpc_inputChatPhoto: _type = cons; { + if (!data) setData(new MTPDinputChatPhoto()); + MTPDinputChatPhoto &v(_inputChatPhoto()); + v.vid.read(from, end); + v.vcrop.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputChatPhoto"); + } +} +inline void MTPinputChatPhoto::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputChatUploadedPhoto: { + const MTPDinputChatUploadedPhoto &v(c_inputChatUploadedPhoto()); + v.vfile.write(to); + v.vcrop.write(to); + } break; + case mtpc_inputChatPhoto: { + const MTPDinputChatPhoto &v(c_inputChatPhoto()); + v.vid.write(to); + v.vcrop.write(to); + } break; + } +} +inline MTPinputChatPhoto::MTPinputChatPhoto(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputChatPhotoEmpty: break; + case mtpc_inputChatUploadedPhoto: setData(new MTPDinputChatUploadedPhoto()); break; + case mtpc_inputChatPhoto: setData(new MTPDinputChatPhoto()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputChatPhoto"); + } +} +inline MTPinputChatPhoto::MTPinputChatPhoto(MTPDinputChatUploadedPhoto *_data) : _type(mtpc_inputChatUploadedPhoto), mtpDataOwner(_data) { +} +inline MTPinputChatPhoto::MTPinputChatPhoto(MTPDinputChatPhoto *_data) : _type(mtpc_inputChatPhoto), mtpDataOwner(_data) { +} +inline MTPinputChatPhoto MTP_inputChatPhotoEmpty() { + return MTPinputChatPhoto(mtpc_inputChatPhotoEmpty); +} +inline MTPinputChatPhoto MTP_inputChatUploadedPhoto(const MTPInputFile &_file, const MTPInputPhotoCrop &_crop) { + return MTPinputChatPhoto(new MTPDinputChatUploadedPhoto(_file, _crop)); +} +inline MTPinputChatPhoto MTP_inputChatPhoto(const MTPInputPhoto &_id, const MTPInputPhotoCrop &_crop) { + return MTPinputChatPhoto(new MTPDinputChatPhoto(_id, _crop)); +} + +inline uint32 MTPinputGeoPoint::size() const { + switch (_type) { + case mtpc_inputGeoPoint: { + const MTPDinputGeoPoint &v(c_inputGeoPoint()); + return v.vlat.size() + v.vlong.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputGeoPoint::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputGeoPoint::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputGeoPointEmpty: _type = cons; break; + case mtpc_inputGeoPoint: _type = cons; { + if (!data) setData(new MTPDinputGeoPoint()); + MTPDinputGeoPoint &v(_inputGeoPoint()); + v.vlat.read(from, end); + v.vlong.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputGeoPoint"); + } +} +inline void MTPinputGeoPoint::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputGeoPoint: { + const MTPDinputGeoPoint &v(c_inputGeoPoint()); + v.vlat.write(to); + v.vlong.write(to); + } break; + } +} +inline MTPinputGeoPoint::MTPinputGeoPoint(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputGeoPointEmpty: break; + case mtpc_inputGeoPoint: setData(new MTPDinputGeoPoint()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputGeoPoint"); + } +} +inline MTPinputGeoPoint::MTPinputGeoPoint(MTPDinputGeoPoint *_data) : _type(mtpc_inputGeoPoint), mtpDataOwner(_data) { +} +inline MTPinputGeoPoint MTP_inputGeoPointEmpty() { + return MTPinputGeoPoint(mtpc_inputGeoPointEmpty); +} +inline MTPinputGeoPoint MTP_inputGeoPoint(const MTPdouble &_lat, const MTPdouble &_long) { + return MTPinputGeoPoint(new MTPDinputGeoPoint(_lat, _long)); +} + +inline uint32 MTPinputPhoto::size() const { + switch (_type) { + case mtpc_inputPhoto: { + const MTPDinputPhoto &v(c_inputPhoto()); + return v.vid.size() + v.vaccess_hash.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputPhoto::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputPhoto::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputPhotoEmpty: _type = cons; break; + case mtpc_inputPhoto: _type = cons; { + if (!data) setData(new MTPDinputPhoto()); + MTPDinputPhoto &v(_inputPhoto()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputPhoto"); + } +} +inline void MTPinputPhoto::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputPhoto: { + const MTPDinputPhoto &v(c_inputPhoto()); + v.vid.write(to); + v.vaccess_hash.write(to); + } break; + } +} +inline MTPinputPhoto::MTPinputPhoto(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputPhotoEmpty: break; + case mtpc_inputPhoto: setData(new MTPDinputPhoto()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputPhoto"); + } +} +inline MTPinputPhoto::MTPinputPhoto(MTPDinputPhoto *_data) : _type(mtpc_inputPhoto), mtpDataOwner(_data) { +} +inline MTPinputPhoto MTP_inputPhotoEmpty() { + return MTPinputPhoto(mtpc_inputPhotoEmpty); +} +inline MTPinputPhoto MTP_inputPhoto(const MTPlong &_id, const MTPlong &_access_hash) { + return MTPinputPhoto(new MTPDinputPhoto(_id, _access_hash)); +} + +inline uint32 MTPinputVideo::size() const { + switch (_type) { + case mtpc_inputVideo: { + const MTPDinputVideo &v(c_inputVideo()); + return v.vid.size() + v.vaccess_hash.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputVideo::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputVideo::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputVideoEmpty: _type = cons; break; + case mtpc_inputVideo: _type = cons; { + if (!data) setData(new MTPDinputVideo()); + MTPDinputVideo &v(_inputVideo()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputVideo"); + } +} +inline void MTPinputVideo::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputVideo: { + const MTPDinputVideo &v(c_inputVideo()); + v.vid.write(to); + v.vaccess_hash.write(to); + } break; + } +} +inline MTPinputVideo::MTPinputVideo(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputVideoEmpty: break; + case mtpc_inputVideo: setData(new MTPDinputVideo()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputVideo"); + } +} +inline MTPinputVideo::MTPinputVideo(MTPDinputVideo *_data) : _type(mtpc_inputVideo), mtpDataOwner(_data) { +} +inline MTPinputVideo MTP_inputVideoEmpty() { + return MTPinputVideo(mtpc_inputVideoEmpty); +} +inline MTPinputVideo MTP_inputVideo(const MTPlong &_id, const MTPlong &_access_hash) { + return MTPinputVideo(new MTPDinputVideo(_id, _access_hash)); +} + +inline uint32 MTPinputFileLocation::size() const { + switch (_type) { + case mtpc_inputFileLocation: { + const MTPDinputFileLocation &v(c_inputFileLocation()); + return v.vvolume_id.size() + v.vlocal_id.size() + v.vsecret.size(); + } + case mtpc_inputVideoFileLocation: { + const MTPDinputVideoFileLocation &v(c_inputVideoFileLocation()); + return v.vid.size() + v.vaccess_hash.size(); + } + case mtpc_inputEncryptedFileLocation: { + const MTPDinputEncryptedFileLocation &v(c_inputEncryptedFileLocation()); + return v.vid.size() + v.vaccess_hash.size(); + } + case mtpc_inputAudioFileLocation: { + const MTPDinputAudioFileLocation &v(c_inputAudioFileLocation()); + return v.vid.size() + v.vaccess_hash.size(); + } + case mtpc_inputDocumentFileLocation: { + const MTPDinputDocumentFileLocation &v(c_inputDocumentFileLocation()); + return v.vid.size() + v.vaccess_hash.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputFileLocation::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputFileLocation::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputFileLocation: _type = cons; { + if (!data) setData(new MTPDinputFileLocation()); + MTPDinputFileLocation &v(_inputFileLocation()); + v.vvolume_id.read(from, end); + v.vlocal_id.read(from, end); + v.vsecret.read(from, end); + } break; + case mtpc_inputVideoFileLocation: _type = cons; { + if (!data) setData(new MTPDinputVideoFileLocation()); + MTPDinputVideoFileLocation &v(_inputVideoFileLocation()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + } break; + case mtpc_inputEncryptedFileLocation: _type = cons; { + if (!data) setData(new MTPDinputEncryptedFileLocation()); + MTPDinputEncryptedFileLocation &v(_inputEncryptedFileLocation()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + } break; + case mtpc_inputAudioFileLocation: _type = cons; { + if (!data) setData(new MTPDinputAudioFileLocation()); + MTPDinputAudioFileLocation &v(_inputAudioFileLocation()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + } break; + case mtpc_inputDocumentFileLocation: _type = cons; { + if (!data) setData(new MTPDinputDocumentFileLocation()); + MTPDinputDocumentFileLocation &v(_inputDocumentFileLocation()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputFileLocation"); + } +} +inline void MTPinputFileLocation::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputFileLocation: { + const MTPDinputFileLocation &v(c_inputFileLocation()); + v.vvolume_id.write(to); + v.vlocal_id.write(to); + v.vsecret.write(to); + } break; + case mtpc_inputVideoFileLocation: { + const MTPDinputVideoFileLocation &v(c_inputVideoFileLocation()); + v.vid.write(to); + v.vaccess_hash.write(to); + } break; + case mtpc_inputEncryptedFileLocation: { + const MTPDinputEncryptedFileLocation &v(c_inputEncryptedFileLocation()); + v.vid.write(to); + v.vaccess_hash.write(to); + } break; + case mtpc_inputAudioFileLocation: { + const MTPDinputAudioFileLocation &v(c_inputAudioFileLocation()); + v.vid.write(to); + v.vaccess_hash.write(to); + } break; + case mtpc_inputDocumentFileLocation: { + const MTPDinputDocumentFileLocation &v(c_inputDocumentFileLocation()); + v.vid.write(to); + v.vaccess_hash.write(to); + } break; + } +} +inline MTPinputFileLocation::MTPinputFileLocation(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputFileLocation: setData(new MTPDinputFileLocation()); break; + case mtpc_inputVideoFileLocation: setData(new MTPDinputVideoFileLocation()); break; + case mtpc_inputEncryptedFileLocation: setData(new MTPDinputEncryptedFileLocation()); break; + case mtpc_inputAudioFileLocation: setData(new MTPDinputAudioFileLocation()); break; + case mtpc_inputDocumentFileLocation: setData(new MTPDinputDocumentFileLocation()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputFileLocation"); + } +} +inline MTPinputFileLocation::MTPinputFileLocation(MTPDinputFileLocation *_data) : _type(mtpc_inputFileLocation), mtpDataOwner(_data) { +} +inline MTPinputFileLocation::MTPinputFileLocation(MTPDinputVideoFileLocation *_data) : _type(mtpc_inputVideoFileLocation), mtpDataOwner(_data) { +} +inline MTPinputFileLocation::MTPinputFileLocation(MTPDinputEncryptedFileLocation *_data) : _type(mtpc_inputEncryptedFileLocation), mtpDataOwner(_data) { +} +inline MTPinputFileLocation::MTPinputFileLocation(MTPDinputAudioFileLocation *_data) : _type(mtpc_inputAudioFileLocation), mtpDataOwner(_data) { +} +inline MTPinputFileLocation::MTPinputFileLocation(MTPDinputDocumentFileLocation *_data) : _type(mtpc_inputDocumentFileLocation), mtpDataOwner(_data) { +} +inline MTPinputFileLocation MTP_inputFileLocation(const MTPlong &_volume_id, MTPint _local_id, const MTPlong &_secret) { + return MTPinputFileLocation(new MTPDinputFileLocation(_volume_id, _local_id, _secret)); +} +inline MTPinputFileLocation MTP_inputVideoFileLocation(const MTPlong &_id, const MTPlong &_access_hash) { + return MTPinputFileLocation(new MTPDinputVideoFileLocation(_id, _access_hash)); +} +inline MTPinputFileLocation MTP_inputEncryptedFileLocation(const MTPlong &_id, const MTPlong &_access_hash) { + return MTPinputFileLocation(new MTPDinputEncryptedFileLocation(_id, _access_hash)); +} +inline MTPinputFileLocation MTP_inputAudioFileLocation(const MTPlong &_id, const MTPlong &_access_hash) { + return MTPinputFileLocation(new MTPDinputAudioFileLocation(_id, _access_hash)); +} +inline MTPinputFileLocation MTP_inputDocumentFileLocation(const MTPlong &_id, const MTPlong &_access_hash) { + return MTPinputFileLocation(new MTPDinputDocumentFileLocation(_id, _access_hash)); +} + +inline uint32 MTPinputPhotoCrop::size() const { + switch (_type) { + case mtpc_inputPhotoCrop: { + const MTPDinputPhotoCrop &v(c_inputPhotoCrop()); + return v.vcrop_left.size() + v.vcrop_top.size() + v.vcrop_width.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputPhotoCrop::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputPhotoCrop::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputPhotoCropAuto: _type = cons; break; + case mtpc_inputPhotoCrop: _type = cons; { + if (!data) setData(new MTPDinputPhotoCrop()); + MTPDinputPhotoCrop &v(_inputPhotoCrop()); + v.vcrop_left.read(from, end); + v.vcrop_top.read(from, end); + v.vcrop_width.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputPhotoCrop"); + } +} +inline void MTPinputPhotoCrop::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputPhotoCrop: { + const MTPDinputPhotoCrop &v(c_inputPhotoCrop()); + v.vcrop_left.write(to); + v.vcrop_top.write(to); + v.vcrop_width.write(to); + } break; + } +} +inline MTPinputPhotoCrop::MTPinputPhotoCrop(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputPhotoCropAuto: break; + case mtpc_inputPhotoCrop: setData(new MTPDinputPhotoCrop()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputPhotoCrop"); + } +} +inline MTPinputPhotoCrop::MTPinputPhotoCrop(MTPDinputPhotoCrop *_data) : _type(mtpc_inputPhotoCrop), mtpDataOwner(_data) { +} +inline MTPinputPhotoCrop MTP_inputPhotoCropAuto() { + return MTPinputPhotoCrop(mtpc_inputPhotoCropAuto); +} +inline MTPinputPhotoCrop MTP_inputPhotoCrop(const MTPdouble &_crop_left, const MTPdouble &_crop_top, const MTPdouble &_crop_width) { + return MTPinputPhotoCrop(new MTPDinputPhotoCrop(_crop_left, _crop_top, _crop_width)); +} + +inline MTPinputAppEvent::MTPinputAppEvent() : mtpDataOwner(new MTPDinputAppEvent()) { +} + +inline uint32 MTPinputAppEvent::size() const { + const MTPDinputAppEvent &v(c_inputAppEvent()); + return v.vtime.size() + v.vtype.size() + v.vpeer.size() + v.vdata.size(); +} +inline mtpTypeId MTPinputAppEvent::type() const { + return mtpc_inputAppEvent; +} +inline void MTPinputAppEvent::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_inputAppEvent) throw mtpErrorUnexpected(cons, "MTPinputAppEvent"); + + if (!data) setData(new MTPDinputAppEvent()); + MTPDinputAppEvent &v(_inputAppEvent()); + v.vtime.read(from, end); + v.vtype.read(from, end); + v.vpeer.read(from, end); + v.vdata.read(from, end); +} +inline void MTPinputAppEvent::write(mtpBuffer &to) const { + const MTPDinputAppEvent &v(c_inputAppEvent()); + v.vtime.write(to); + v.vtype.write(to); + v.vpeer.write(to); + v.vdata.write(to); +} +inline MTPinputAppEvent::MTPinputAppEvent(MTPDinputAppEvent *_data) : mtpDataOwner(_data) { +} +inline MTPinputAppEvent MTP_inputAppEvent(const MTPdouble &_time, const MTPstring &_type, const MTPlong &_peer, const MTPstring &_data) { + return MTPinputAppEvent(new MTPDinputAppEvent(_time, _type, _peer, _data)); +} + +inline uint32 MTPpeer::size() const { + switch (_type) { + case mtpc_peerUser: { + const MTPDpeerUser &v(c_peerUser()); + return v.vuser_id.size(); + } + case mtpc_peerChat: { + const MTPDpeerChat &v(c_peerChat()); + return v.vchat_id.size(); + } + } + return 0; +} +inline mtpTypeId MTPpeer::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPpeer::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_peerUser: _type = cons; { + if (!data) setData(new MTPDpeerUser()); + MTPDpeerUser &v(_peerUser()); + v.vuser_id.read(from, end); + } break; + case mtpc_peerChat: _type = cons; { + if (!data) setData(new MTPDpeerChat()); + MTPDpeerChat &v(_peerChat()); + v.vchat_id.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPpeer"); + } +} +inline void MTPpeer::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_peerUser: { + const MTPDpeerUser &v(c_peerUser()); + v.vuser_id.write(to); + } break; + case mtpc_peerChat: { + const MTPDpeerChat &v(c_peerChat()); + v.vchat_id.write(to); + } break; + } +} +inline MTPpeer::MTPpeer(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_peerUser: setData(new MTPDpeerUser()); break; + case mtpc_peerChat: setData(new MTPDpeerChat()); break; + default: throw mtpErrorBadTypeId(type, "MTPpeer"); + } +} +inline MTPpeer::MTPpeer(MTPDpeerUser *_data) : _type(mtpc_peerUser), mtpDataOwner(_data) { +} +inline MTPpeer::MTPpeer(MTPDpeerChat *_data) : _type(mtpc_peerChat), mtpDataOwner(_data) { +} +inline MTPpeer MTP_peerUser(MTPint _user_id) { + return MTPpeer(new MTPDpeerUser(_user_id)); +} +inline MTPpeer MTP_peerChat(MTPint _chat_id) { + return MTPpeer(new MTPDpeerChat(_chat_id)); +} + +inline uint32 MTPstorage_fileType::size() const { + return 0; +} +inline mtpTypeId MTPstorage_fileType::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPstorage_fileType::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + switch (cons) { + case mtpc_storage_fileUnknown: _type = cons; break; + case mtpc_storage_fileJpeg: _type = cons; break; + case mtpc_storage_fileGif: _type = cons; break; + case mtpc_storage_filePng: _type = cons; break; + case mtpc_storage_filePdf: _type = cons; break; + case mtpc_storage_fileMp3: _type = cons; break; + case mtpc_storage_fileMov: _type = cons; break; + case mtpc_storage_filePartial: _type = cons; break; + case mtpc_storage_fileMp4: _type = cons; break; + case mtpc_storage_fileWebp: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPstorage_fileType"); + } +} +inline void MTPstorage_fileType::write(mtpBuffer &to) const { + switch (_type) { + } +} +inline MTPstorage_fileType::MTPstorage_fileType(mtpTypeId type) : _type(type) { + switch (type) { + case mtpc_storage_fileUnknown: break; + case mtpc_storage_fileJpeg: break; + case mtpc_storage_fileGif: break; + case mtpc_storage_filePng: break; + case mtpc_storage_filePdf: break; + case mtpc_storage_fileMp3: break; + case mtpc_storage_fileMov: break; + case mtpc_storage_filePartial: break; + case mtpc_storage_fileMp4: break; + case mtpc_storage_fileWebp: break; + default: throw mtpErrorBadTypeId(type, "MTPstorage_fileType"); + } +} +inline MTPstorage_fileType MTP_storage_fileUnknown() { + return MTPstorage_fileType(mtpc_storage_fileUnknown); +} +inline MTPstorage_fileType MTP_storage_fileJpeg() { + return MTPstorage_fileType(mtpc_storage_fileJpeg); +} +inline MTPstorage_fileType MTP_storage_fileGif() { + return MTPstorage_fileType(mtpc_storage_fileGif); +} +inline MTPstorage_fileType MTP_storage_filePng() { + return MTPstorage_fileType(mtpc_storage_filePng); +} +inline MTPstorage_fileType MTP_storage_filePdf() { + return MTPstorage_fileType(mtpc_storage_filePdf); +} +inline MTPstorage_fileType MTP_storage_fileMp3() { + return MTPstorage_fileType(mtpc_storage_fileMp3); +} +inline MTPstorage_fileType MTP_storage_fileMov() { + return MTPstorage_fileType(mtpc_storage_fileMov); +} +inline MTPstorage_fileType MTP_storage_filePartial() { + return MTPstorage_fileType(mtpc_storage_filePartial); +} +inline MTPstorage_fileType MTP_storage_fileMp4() { + return MTPstorage_fileType(mtpc_storage_fileMp4); +} +inline MTPstorage_fileType MTP_storage_fileWebp() { + return MTPstorage_fileType(mtpc_storage_fileWebp); +} + +inline uint32 MTPfileLocation::size() const { + switch (_type) { + case mtpc_fileLocationUnavailable: { + const MTPDfileLocationUnavailable &v(c_fileLocationUnavailable()); + return v.vvolume_id.size() + v.vlocal_id.size() + v.vsecret.size(); + } + case mtpc_fileLocation: { + const MTPDfileLocation &v(c_fileLocation()); + return v.vdc_id.size() + v.vvolume_id.size() + v.vlocal_id.size() + v.vsecret.size(); + } + } + return 0; +} +inline mtpTypeId MTPfileLocation::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPfileLocation::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_fileLocationUnavailable: _type = cons; { + if (!data) setData(new MTPDfileLocationUnavailable()); + MTPDfileLocationUnavailable &v(_fileLocationUnavailable()); + v.vvolume_id.read(from, end); + v.vlocal_id.read(from, end); + v.vsecret.read(from, end); + } break; + case mtpc_fileLocation: _type = cons; { + if (!data) setData(new MTPDfileLocation()); + MTPDfileLocation &v(_fileLocation()); + v.vdc_id.read(from, end); + v.vvolume_id.read(from, end); + v.vlocal_id.read(from, end); + v.vsecret.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPfileLocation"); + } +} +inline void MTPfileLocation::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_fileLocationUnavailable: { + const MTPDfileLocationUnavailable &v(c_fileLocationUnavailable()); + v.vvolume_id.write(to); + v.vlocal_id.write(to); + v.vsecret.write(to); + } break; + case mtpc_fileLocation: { + const MTPDfileLocation &v(c_fileLocation()); + v.vdc_id.write(to); + v.vvolume_id.write(to); + v.vlocal_id.write(to); + v.vsecret.write(to); + } break; + } +} +inline MTPfileLocation::MTPfileLocation(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_fileLocationUnavailable: setData(new MTPDfileLocationUnavailable()); break; + case mtpc_fileLocation: setData(new MTPDfileLocation()); break; + default: throw mtpErrorBadTypeId(type, "MTPfileLocation"); + } +} +inline MTPfileLocation::MTPfileLocation(MTPDfileLocationUnavailable *_data) : _type(mtpc_fileLocationUnavailable), mtpDataOwner(_data) { +} +inline MTPfileLocation::MTPfileLocation(MTPDfileLocation *_data) : _type(mtpc_fileLocation), mtpDataOwner(_data) { +} +inline MTPfileLocation MTP_fileLocationUnavailable(const MTPlong &_volume_id, MTPint _local_id, const MTPlong &_secret) { + return MTPfileLocation(new MTPDfileLocationUnavailable(_volume_id, _local_id, _secret)); +} +inline MTPfileLocation MTP_fileLocation(MTPint _dc_id, const MTPlong &_volume_id, MTPint _local_id, const MTPlong &_secret) { + return MTPfileLocation(new MTPDfileLocation(_dc_id, _volume_id, _local_id, _secret)); +} + +inline uint32 MTPuser::size() const { + switch (_type) { + case mtpc_userEmpty: { + const MTPDuserEmpty &v(c_userEmpty()); + return v.vid.size(); + } + case mtpc_userSelf: { + const MTPDuserSelf &v(c_userSelf()); + return v.vid.size() + v.vfirst_name.size() + v.vlast_name.size() + v.vphone.size() + v.vphoto.size() + v.vstatus.size() + v.vinactive.size(); + } + case mtpc_userContact: { + const MTPDuserContact &v(c_userContact()); + return v.vid.size() + v.vfirst_name.size() + v.vlast_name.size() + v.vaccess_hash.size() + v.vphone.size() + v.vphoto.size() + v.vstatus.size(); + } + case mtpc_userRequest: { + const MTPDuserRequest &v(c_userRequest()); + return v.vid.size() + v.vfirst_name.size() + v.vlast_name.size() + v.vaccess_hash.size() + v.vphone.size() + v.vphoto.size() + v.vstatus.size(); + } + case mtpc_userForeign: { + const MTPDuserForeign &v(c_userForeign()); + return v.vid.size() + v.vfirst_name.size() + v.vlast_name.size() + v.vaccess_hash.size() + v.vphoto.size() + v.vstatus.size(); + } + case mtpc_userDeleted: { + const MTPDuserDeleted &v(c_userDeleted()); + return v.vid.size() + v.vfirst_name.size() + v.vlast_name.size(); + } + } + return 0; +} +inline mtpTypeId MTPuser::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPuser::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_userEmpty: _type = cons; { + if (!data) setData(new MTPDuserEmpty()); + MTPDuserEmpty &v(_userEmpty()); + v.vid.read(from, end); + } break; + case mtpc_userSelf: _type = cons; { + if (!data) setData(new MTPDuserSelf()); + MTPDuserSelf &v(_userSelf()); + v.vid.read(from, end); + v.vfirst_name.read(from, end); + v.vlast_name.read(from, end); + v.vphone.read(from, end); + v.vphoto.read(from, end); + v.vstatus.read(from, end); + v.vinactive.read(from, end); + } break; + case mtpc_userContact: _type = cons; { + if (!data) setData(new MTPDuserContact()); + MTPDuserContact &v(_userContact()); + v.vid.read(from, end); + v.vfirst_name.read(from, end); + v.vlast_name.read(from, end); + v.vaccess_hash.read(from, end); + v.vphone.read(from, end); + v.vphoto.read(from, end); + v.vstatus.read(from, end); + } break; + case mtpc_userRequest: _type = cons; { + if (!data) setData(new MTPDuserRequest()); + MTPDuserRequest &v(_userRequest()); + v.vid.read(from, end); + v.vfirst_name.read(from, end); + v.vlast_name.read(from, end); + v.vaccess_hash.read(from, end); + v.vphone.read(from, end); + v.vphoto.read(from, end); + v.vstatus.read(from, end); + } break; + case mtpc_userForeign: _type = cons; { + if (!data) setData(new MTPDuserForeign()); + MTPDuserForeign &v(_userForeign()); + v.vid.read(from, end); + v.vfirst_name.read(from, end); + v.vlast_name.read(from, end); + v.vaccess_hash.read(from, end); + v.vphoto.read(from, end); + v.vstatus.read(from, end); + } break; + case mtpc_userDeleted: _type = cons; { + if (!data) setData(new MTPDuserDeleted()); + MTPDuserDeleted &v(_userDeleted()); + v.vid.read(from, end); + v.vfirst_name.read(from, end); + v.vlast_name.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPuser"); + } +} +inline void MTPuser::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_userEmpty: { + const MTPDuserEmpty &v(c_userEmpty()); + v.vid.write(to); + } break; + case mtpc_userSelf: { + const MTPDuserSelf &v(c_userSelf()); + v.vid.write(to); + v.vfirst_name.write(to); + v.vlast_name.write(to); + v.vphone.write(to); + v.vphoto.write(to); + v.vstatus.write(to); + v.vinactive.write(to); + } break; + case mtpc_userContact: { + const MTPDuserContact &v(c_userContact()); + v.vid.write(to); + v.vfirst_name.write(to); + v.vlast_name.write(to); + v.vaccess_hash.write(to); + v.vphone.write(to); + v.vphoto.write(to); + v.vstatus.write(to); + } break; + case mtpc_userRequest: { + const MTPDuserRequest &v(c_userRequest()); + v.vid.write(to); + v.vfirst_name.write(to); + v.vlast_name.write(to); + v.vaccess_hash.write(to); + v.vphone.write(to); + v.vphoto.write(to); + v.vstatus.write(to); + } break; + case mtpc_userForeign: { + const MTPDuserForeign &v(c_userForeign()); + v.vid.write(to); + v.vfirst_name.write(to); + v.vlast_name.write(to); + v.vaccess_hash.write(to); + v.vphoto.write(to); + v.vstatus.write(to); + } break; + case mtpc_userDeleted: { + const MTPDuserDeleted &v(c_userDeleted()); + v.vid.write(to); + v.vfirst_name.write(to); + v.vlast_name.write(to); + } break; + } +} +inline MTPuser::MTPuser(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_userEmpty: setData(new MTPDuserEmpty()); break; + case mtpc_userSelf: setData(new MTPDuserSelf()); break; + case mtpc_userContact: setData(new MTPDuserContact()); break; + case mtpc_userRequest: setData(new MTPDuserRequest()); break; + case mtpc_userForeign: setData(new MTPDuserForeign()); break; + case mtpc_userDeleted: setData(new MTPDuserDeleted()); break; + default: throw mtpErrorBadTypeId(type, "MTPuser"); + } +} +inline MTPuser::MTPuser(MTPDuserEmpty *_data) : _type(mtpc_userEmpty), mtpDataOwner(_data) { +} +inline MTPuser::MTPuser(MTPDuserSelf *_data) : _type(mtpc_userSelf), mtpDataOwner(_data) { +} +inline MTPuser::MTPuser(MTPDuserContact *_data) : _type(mtpc_userContact), mtpDataOwner(_data) { +} +inline MTPuser::MTPuser(MTPDuserRequest *_data) : _type(mtpc_userRequest), mtpDataOwner(_data) { +} +inline MTPuser::MTPuser(MTPDuserForeign *_data) : _type(mtpc_userForeign), mtpDataOwner(_data) { +} +inline MTPuser::MTPuser(MTPDuserDeleted *_data) : _type(mtpc_userDeleted), mtpDataOwner(_data) { +} +inline MTPuser MTP_userEmpty(MTPint _id) { + return MTPuser(new MTPDuserEmpty(_id)); +} +inline MTPuser MTP_userSelf(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name, const MTPstring &_phone, const MTPUserProfilePhoto &_photo, const MTPUserStatus &_status, MTPBool _inactive) { + return MTPuser(new MTPDuserSelf(_id, _first_name, _last_name, _phone, _photo, _status, _inactive)); +} +inline MTPuser MTP_userContact(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name, const MTPlong &_access_hash, const MTPstring &_phone, const MTPUserProfilePhoto &_photo, const MTPUserStatus &_status) { + return MTPuser(new MTPDuserContact(_id, _first_name, _last_name, _access_hash, _phone, _photo, _status)); +} +inline MTPuser MTP_userRequest(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name, const MTPlong &_access_hash, const MTPstring &_phone, const MTPUserProfilePhoto &_photo, const MTPUserStatus &_status) { + return MTPuser(new MTPDuserRequest(_id, _first_name, _last_name, _access_hash, _phone, _photo, _status)); +} +inline MTPuser MTP_userForeign(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name, const MTPlong &_access_hash, const MTPUserProfilePhoto &_photo, const MTPUserStatus &_status) { + return MTPuser(new MTPDuserForeign(_id, _first_name, _last_name, _access_hash, _photo, _status)); +} +inline MTPuser MTP_userDeleted(MTPint _id, const MTPstring &_first_name, const MTPstring &_last_name) { + return MTPuser(new MTPDuserDeleted(_id, _first_name, _last_name)); +} + +inline uint32 MTPuserProfilePhoto::size() const { + switch (_type) { + case mtpc_userProfilePhoto: { + const MTPDuserProfilePhoto &v(c_userProfilePhoto()); + return v.vphoto_id.size() + v.vphoto_small.size() + v.vphoto_big.size(); + } + } + return 0; +} +inline mtpTypeId MTPuserProfilePhoto::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPuserProfilePhoto::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_userProfilePhotoEmpty: _type = cons; break; + case mtpc_userProfilePhoto: _type = cons; { + if (!data) setData(new MTPDuserProfilePhoto()); + MTPDuserProfilePhoto &v(_userProfilePhoto()); + v.vphoto_id.read(from, end); + v.vphoto_small.read(from, end); + v.vphoto_big.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPuserProfilePhoto"); + } +} +inline void MTPuserProfilePhoto::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_userProfilePhoto: { + const MTPDuserProfilePhoto &v(c_userProfilePhoto()); + v.vphoto_id.write(to); + v.vphoto_small.write(to); + v.vphoto_big.write(to); + } break; + } +} +inline MTPuserProfilePhoto::MTPuserProfilePhoto(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_userProfilePhotoEmpty: break; + case mtpc_userProfilePhoto: setData(new MTPDuserProfilePhoto()); break; + default: throw mtpErrorBadTypeId(type, "MTPuserProfilePhoto"); + } +} +inline MTPuserProfilePhoto::MTPuserProfilePhoto(MTPDuserProfilePhoto *_data) : _type(mtpc_userProfilePhoto), mtpDataOwner(_data) { +} +inline MTPuserProfilePhoto MTP_userProfilePhotoEmpty() { + return MTPuserProfilePhoto(mtpc_userProfilePhotoEmpty); +} +inline MTPuserProfilePhoto MTP_userProfilePhoto(const MTPlong &_photo_id, const MTPFileLocation &_photo_small, const MTPFileLocation &_photo_big) { + return MTPuserProfilePhoto(new MTPDuserProfilePhoto(_photo_id, _photo_small, _photo_big)); +} + +inline uint32 MTPuserStatus::size() const { + switch (_type) { + case mtpc_userStatusOnline: { + const MTPDuserStatusOnline &v(c_userStatusOnline()); + return v.vexpires.size(); + } + case mtpc_userStatusOffline: { + const MTPDuserStatusOffline &v(c_userStatusOffline()); + return v.vwas_online.size(); + } + } + return 0; +} +inline mtpTypeId MTPuserStatus::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPuserStatus::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_userStatusEmpty: _type = cons; break; + case mtpc_userStatusOnline: _type = cons; { + if (!data) setData(new MTPDuserStatusOnline()); + MTPDuserStatusOnline &v(_userStatusOnline()); + v.vexpires.read(from, end); + } break; + case mtpc_userStatusOffline: _type = cons; { + if (!data) setData(new MTPDuserStatusOffline()); + MTPDuserStatusOffline &v(_userStatusOffline()); + v.vwas_online.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPuserStatus"); + } +} +inline void MTPuserStatus::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_userStatusOnline: { + const MTPDuserStatusOnline &v(c_userStatusOnline()); + v.vexpires.write(to); + } break; + case mtpc_userStatusOffline: { + const MTPDuserStatusOffline &v(c_userStatusOffline()); + v.vwas_online.write(to); + } break; + } +} +inline MTPuserStatus::MTPuserStatus(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_userStatusEmpty: break; + case mtpc_userStatusOnline: setData(new MTPDuserStatusOnline()); break; + case mtpc_userStatusOffline: setData(new MTPDuserStatusOffline()); break; + default: throw mtpErrorBadTypeId(type, "MTPuserStatus"); + } +} +inline MTPuserStatus::MTPuserStatus(MTPDuserStatusOnline *_data) : _type(mtpc_userStatusOnline), mtpDataOwner(_data) { +} +inline MTPuserStatus::MTPuserStatus(MTPDuserStatusOffline *_data) : _type(mtpc_userStatusOffline), mtpDataOwner(_data) { +} +inline MTPuserStatus MTP_userStatusEmpty() { + return MTPuserStatus(mtpc_userStatusEmpty); +} +inline MTPuserStatus MTP_userStatusOnline(MTPint _expires) { + return MTPuserStatus(new MTPDuserStatusOnline(_expires)); +} +inline MTPuserStatus MTP_userStatusOffline(MTPint _was_online) { + return MTPuserStatus(new MTPDuserStatusOffline(_was_online)); +} + +inline uint32 MTPchat::size() const { + switch (_type) { + case mtpc_chatEmpty: { + const MTPDchatEmpty &v(c_chatEmpty()); + return v.vid.size(); + } + case mtpc_chat: { + const MTPDchat &v(c_chat()); + return v.vid.size() + v.vtitle.size() + v.vphoto.size() + v.vparticipants_count.size() + v.vdate.size() + v.vleft.size() + v.vversion.size(); + } + case mtpc_chatForbidden: { + const MTPDchatForbidden &v(c_chatForbidden()); + return v.vid.size() + v.vtitle.size() + v.vdate.size(); + } + case mtpc_geoChat: { + const MTPDgeoChat &v(c_geoChat()); + return v.vid.size() + v.vaccess_hash.size() + v.vtitle.size() + v.vaddress.size() + v.vvenue.size() + v.vgeo.size() + v.vphoto.size() + v.vparticipants_count.size() + v.vdate.size() + v.vchecked_in.size() + v.vversion.size(); + } + } + return 0; +} +inline mtpTypeId MTPchat::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPchat::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_chatEmpty: _type = cons; { + if (!data) setData(new MTPDchatEmpty()); + MTPDchatEmpty &v(_chatEmpty()); + v.vid.read(from, end); + } break; + case mtpc_chat: _type = cons; { + if (!data) setData(new MTPDchat()); + MTPDchat &v(_chat()); + v.vid.read(from, end); + v.vtitle.read(from, end); + v.vphoto.read(from, end); + v.vparticipants_count.read(from, end); + v.vdate.read(from, end); + v.vleft.read(from, end); + v.vversion.read(from, end); + } break; + case mtpc_chatForbidden: _type = cons; { + if (!data) setData(new MTPDchatForbidden()); + MTPDchatForbidden &v(_chatForbidden()); + v.vid.read(from, end); + v.vtitle.read(from, end); + v.vdate.read(from, end); + } break; + case mtpc_geoChat: _type = cons; { + if (!data) setData(new MTPDgeoChat()); + MTPDgeoChat &v(_geoChat()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + v.vtitle.read(from, end); + v.vaddress.read(from, end); + v.vvenue.read(from, end); + v.vgeo.read(from, end); + v.vphoto.read(from, end); + v.vparticipants_count.read(from, end); + v.vdate.read(from, end); + v.vchecked_in.read(from, end); + v.vversion.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPchat"); + } +} +inline void MTPchat::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_chatEmpty: { + const MTPDchatEmpty &v(c_chatEmpty()); + v.vid.write(to); + } break; + case mtpc_chat: { + const MTPDchat &v(c_chat()); + v.vid.write(to); + v.vtitle.write(to); + v.vphoto.write(to); + v.vparticipants_count.write(to); + v.vdate.write(to); + v.vleft.write(to); + v.vversion.write(to); + } break; + case mtpc_chatForbidden: { + const MTPDchatForbidden &v(c_chatForbidden()); + v.vid.write(to); + v.vtitle.write(to); + v.vdate.write(to); + } break; + case mtpc_geoChat: { + const MTPDgeoChat &v(c_geoChat()); + v.vid.write(to); + v.vaccess_hash.write(to); + v.vtitle.write(to); + v.vaddress.write(to); + v.vvenue.write(to); + v.vgeo.write(to); + v.vphoto.write(to); + v.vparticipants_count.write(to); + v.vdate.write(to); + v.vchecked_in.write(to); + v.vversion.write(to); + } break; + } +} +inline MTPchat::MTPchat(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_chatEmpty: setData(new MTPDchatEmpty()); break; + case mtpc_chat: setData(new MTPDchat()); break; + case mtpc_chatForbidden: setData(new MTPDchatForbidden()); break; + case mtpc_geoChat: setData(new MTPDgeoChat()); break; + default: throw mtpErrorBadTypeId(type, "MTPchat"); + } +} +inline MTPchat::MTPchat(MTPDchatEmpty *_data) : _type(mtpc_chatEmpty), mtpDataOwner(_data) { +} +inline MTPchat::MTPchat(MTPDchat *_data) : _type(mtpc_chat), mtpDataOwner(_data) { +} +inline MTPchat::MTPchat(MTPDchatForbidden *_data) : _type(mtpc_chatForbidden), mtpDataOwner(_data) { +} +inline MTPchat::MTPchat(MTPDgeoChat *_data) : _type(mtpc_geoChat), mtpDataOwner(_data) { +} +inline MTPchat MTP_chatEmpty(MTPint _id) { + return MTPchat(new MTPDchatEmpty(_id)); +} +inline MTPchat MTP_chat(MTPint _id, const MTPstring &_title, const MTPChatPhoto &_photo, MTPint _participants_count, MTPint _date, MTPBool _left, MTPint _version) { + return MTPchat(new MTPDchat(_id, _title, _photo, _participants_count, _date, _left, _version)); +} +inline MTPchat MTP_chatForbidden(MTPint _id, const MTPstring &_title, MTPint _date) { + return MTPchat(new MTPDchatForbidden(_id, _title, _date)); +} +inline MTPchat MTP_geoChat(MTPint _id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_address, const MTPstring &_venue, const MTPGeoPoint &_geo, const MTPChatPhoto &_photo, MTPint _participants_count, MTPint _date, MTPBool _checked_in, MTPint _version) { + return MTPchat(new MTPDgeoChat(_id, _access_hash, _title, _address, _venue, _geo, _photo, _participants_count, _date, _checked_in, _version)); +} + +inline MTPchatFull::MTPchatFull() : mtpDataOwner(new MTPDchatFull()) { +} + +inline uint32 MTPchatFull::size() const { + const MTPDchatFull &v(c_chatFull()); + return v.vid.size() + v.vparticipants.size() + v.vchat_photo.size() + v.vnotify_settings.size(); +} +inline mtpTypeId MTPchatFull::type() const { + return mtpc_chatFull; +} +inline void MTPchatFull::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_chatFull) throw mtpErrorUnexpected(cons, "MTPchatFull"); + + if (!data) setData(new MTPDchatFull()); + MTPDchatFull &v(_chatFull()); + v.vid.read(from, end); + v.vparticipants.read(from, end); + v.vchat_photo.read(from, end); + v.vnotify_settings.read(from, end); +} +inline void MTPchatFull::write(mtpBuffer &to) const { + const MTPDchatFull &v(c_chatFull()); + v.vid.write(to); + v.vparticipants.write(to); + v.vchat_photo.write(to); + v.vnotify_settings.write(to); +} +inline MTPchatFull::MTPchatFull(MTPDchatFull *_data) : mtpDataOwner(_data) { +} +inline MTPchatFull MTP_chatFull(MTPint _id, const MTPChatParticipants &_participants, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings) { + return MTPchatFull(new MTPDchatFull(_id, _participants, _chat_photo, _notify_settings)); +} + +inline MTPchatParticipant::MTPchatParticipant() : mtpDataOwner(new MTPDchatParticipant()) { +} + +inline uint32 MTPchatParticipant::size() const { + const MTPDchatParticipant &v(c_chatParticipant()); + return v.vuser_id.size() + v.vinviter_id.size() + v.vdate.size(); +} +inline mtpTypeId MTPchatParticipant::type() const { + return mtpc_chatParticipant; +} +inline void MTPchatParticipant::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_chatParticipant) throw mtpErrorUnexpected(cons, "MTPchatParticipant"); + + if (!data) setData(new MTPDchatParticipant()); + MTPDchatParticipant &v(_chatParticipant()); + v.vuser_id.read(from, end); + v.vinviter_id.read(from, end); + v.vdate.read(from, end); +} +inline void MTPchatParticipant::write(mtpBuffer &to) const { + const MTPDchatParticipant &v(c_chatParticipant()); + v.vuser_id.write(to); + v.vinviter_id.write(to); + v.vdate.write(to); +} +inline MTPchatParticipant::MTPchatParticipant(MTPDchatParticipant *_data) : mtpDataOwner(_data) { +} +inline MTPchatParticipant MTP_chatParticipant(MTPint _user_id, MTPint _inviter_id, MTPint _date) { + return MTPchatParticipant(new MTPDchatParticipant(_user_id, _inviter_id, _date)); +} + +inline uint32 MTPchatParticipants::size() const { + switch (_type) { + case mtpc_chatParticipantsForbidden: { + const MTPDchatParticipantsForbidden &v(c_chatParticipantsForbidden()); + return v.vchat_id.size(); + } + case mtpc_chatParticipants: { + const MTPDchatParticipants &v(c_chatParticipants()); + return v.vchat_id.size() + v.vadmin_id.size() + v.vparticipants.size() + v.vversion.size(); + } + } + return 0; +} +inline mtpTypeId MTPchatParticipants::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPchatParticipants::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_chatParticipantsForbidden: _type = cons; { + if (!data) setData(new MTPDchatParticipantsForbidden()); + MTPDchatParticipantsForbidden &v(_chatParticipantsForbidden()); + v.vchat_id.read(from, end); + } break; + case mtpc_chatParticipants: _type = cons; { + if (!data) setData(new MTPDchatParticipants()); + MTPDchatParticipants &v(_chatParticipants()); + v.vchat_id.read(from, end); + v.vadmin_id.read(from, end); + v.vparticipants.read(from, end); + v.vversion.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPchatParticipants"); + } +} +inline void MTPchatParticipants::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_chatParticipantsForbidden: { + const MTPDchatParticipantsForbidden &v(c_chatParticipantsForbidden()); + v.vchat_id.write(to); + } break; + case mtpc_chatParticipants: { + const MTPDchatParticipants &v(c_chatParticipants()); + v.vchat_id.write(to); + v.vadmin_id.write(to); + v.vparticipants.write(to); + v.vversion.write(to); + } break; + } +} +inline MTPchatParticipants::MTPchatParticipants(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_chatParticipantsForbidden: setData(new MTPDchatParticipantsForbidden()); break; + case mtpc_chatParticipants: setData(new MTPDchatParticipants()); break; + default: throw mtpErrorBadTypeId(type, "MTPchatParticipants"); + } +} +inline MTPchatParticipants::MTPchatParticipants(MTPDchatParticipantsForbidden *_data) : _type(mtpc_chatParticipantsForbidden), mtpDataOwner(_data) { +} +inline MTPchatParticipants::MTPchatParticipants(MTPDchatParticipants *_data) : _type(mtpc_chatParticipants), mtpDataOwner(_data) { +} +inline MTPchatParticipants MTP_chatParticipantsForbidden(MTPint _chat_id) { + return MTPchatParticipants(new MTPDchatParticipantsForbidden(_chat_id)); +} +inline MTPchatParticipants MTP_chatParticipants(MTPint _chat_id, MTPint _admin_id, const MTPVector &_participants, MTPint _version) { + return MTPchatParticipants(new MTPDchatParticipants(_chat_id, _admin_id, _participants, _version)); +} + +inline uint32 MTPchatPhoto::size() const { + switch (_type) { + case mtpc_chatPhoto: { + const MTPDchatPhoto &v(c_chatPhoto()); + return v.vphoto_small.size() + v.vphoto_big.size(); + } + } + return 0; +} +inline mtpTypeId MTPchatPhoto::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPchatPhoto::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_chatPhotoEmpty: _type = cons; break; + case mtpc_chatPhoto: _type = cons; { + if (!data) setData(new MTPDchatPhoto()); + MTPDchatPhoto &v(_chatPhoto()); + v.vphoto_small.read(from, end); + v.vphoto_big.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPchatPhoto"); + } +} +inline void MTPchatPhoto::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_chatPhoto: { + const MTPDchatPhoto &v(c_chatPhoto()); + v.vphoto_small.write(to); + v.vphoto_big.write(to); + } break; + } +} +inline MTPchatPhoto::MTPchatPhoto(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_chatPhotoEmpty: break; + case mtpc_chatPhoto: setData(new MTPDchatPhoto()); break; + default: throw mtpErrorBadTypeId(type, "MTPchatPhoto"); + } +} +inline MTPchatPhoto::MTPchatPhoto(MTPDchatPhoto *_data) : _type(mtpc_chatPhoto), mtpDataOwner(_data) { +} +inline MTPchatPhoto MTP_chatPhotoEmpty() { + return MTPchatPhoto(mtpc_chatPhotoEmpty); +} +inline MTPchatPhoto MTP_chatPhoto(const MTPFileLocation &_photo_small, const MTPFileLocation &_photo_big) { + return MTPchatPhoto(new MTPDchatPhoto(_photo_small, _photo_big)); +} + +inline uint32 MTPmessage::size() const { + switch (_type) { + case mtpc_messageEmpty: { + const MTPDmessageEmpty &v(c_messageEmpty()); + return v.vid.size(); + } + case mtpc_message: { + const MTPDmessage &v(c_message()); + return v.vid.size() + v.vfrom_id.size() + v.vto_id.size() + v.vout.size() + v.vunread.size() + v.vdate.size() + v.vmessage.size() + v.vmedia.size(); + } + case mtpc_messageForwarded: { + const MTPDmessageForwarded &v(c_messageForwarded()); + return v.vid.size() + v.vfwd_from_id.size() + v.vfwd_date.size() + v.vfrom_id.size() + v.vto_id.size() + v.vout.size() + v.vunread.size() + v.vdate.size() + v.vmessage.size() + v.vmedia.size(); + } + case mtpc_messageService: { + const MTPDmessageService &v(c_messageService()); + return v.vid.size() + v.vfrom_id.size() + v.vto_id.size() + v.vout.size() + v.vunread.size() + v.vdate.size() + v.vaction.size(); + } + } + return 0; +} +inline mtpTypeId MTPmessage::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessage::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messageEmpty: _type = cons; { + if (!data) setData(new MTPDmessageEmpty()); + MTPDmessageEmpty &v(_messageEmpty()); + v.vid.read(from, end); + } break; + case mtpc_message: _type = cons; { + if (!data) setData(new MTPDmessage()); + MTPDmessage &v(_message()); + v.vid.read(from, end); + v.vfrom_id.read(from, end); + v.vto_id.read(from, end); + v.vout.read(from, end); + v.vunread.read(from, end); + v.vdate.read(from, end); + v.vmessage.read(from, end); + v.vmedia.read(from, end); + } break; + case mtpc_messageForwarded: _type = cons; { + if (!data) setData(new MTPDmessageForwarded()); + MTPDmessageForwarded &v(_messageForwarded()); + v.vid.read(from, end); + v.vfwd_from_id.read(from, end); + v.vfwd_date.read(from, end); + v.vfrom_id.read(from, end); + v.vto_id.read(from, end); + v.vout.read(from, end); + v.vunread.read(from, end); + v.vdate.read(from, end); + v.vmessage.read(from, end); + v.vmedia.read(from, end); + } break; + case mtpc_messageService: _type = cons; { + if (!data) setData(new MTPDmessageService()); + MTPDmessageService &v(_messageService()); + v.vid.read(from, end); + v.vfrom_id.read(from, end); + v.vto_id.read(from, end); + v.vout.read(from, end); + v.vunread.read(from, end); + v.vdate.read(from, end); + v.vaction.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessage"); + } +} +inline void MTPmessage::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messageEmpty: { + const MTPDmessageEmpty &v(c_messageEmpty()); + v.vid.write(to); + } break; + case mtpc_message: { + const MTPDmessage &v(c_message()); + v.vid.write(to); + v.vfrom_id.write(to); + v.vto_id.write(to); + v.vout.write(to); + v.vunread.write(to); + v.vdate.write(to); + v.vmessage.write(to); + v.vmedia.write(to); + } break; + case mtpc_messageForwarded: { + const MTPDmessageForwarded &v(c_messageForwarded()); + v.vid.write(to); + v.vfwd_from_id.write(to); + v.vfwd_date.write(to); + v.vfrom_id.write(to); + v.vto_id.write(to); + v.vout.write(to); + v.vunread.write(to); + v.vdate.write(to); + v.vmessage.write(to); + v.vmedia.write(to); + } break; + case mtpc_messageService: { + const MTPDmessageService &v(c_messageService()); + v.vid.write(to); + v.vfrom_id.write(to); + v.vto_id.write(to); + v.vout.write(to); + v.vunread.write(to); + v.vdate.write(to); + v.vaction.write(to); + } break; + } +} +inline MTPmessage::MTPmessage(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_messageEmpty: setData(new MTPDmessageEmpty()); break; + case mtpc_message: setData(new MTPDmessage()); break; + case mtpc_messageForwarded: setData(new MTPDmessageForwarded()); break; + case mtpc_messageService: setData(new MTPDmessageService()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessage"); + } +} +inline MTPmessage::MTPmessage(MTPDmessageEmpty *_data) : _type(mtpc_messageEmpty), mtpDataOwner(_data) { +} +inline MTPmessage::MTPmessage(MTPDmessage *_data) : _type(mtpc_message), mtpDataOwner(_data) { +} +inline MTPmessage::MTPmessage(MTPDmessageForwarded *_data) : _type(mtpc_messageForwarded), mtpDataOwner(_data) { +} +inline MTPmessage::MTPmessage(MTPDmessageService *_data) : _type(mtpc_messageService), mtpDataOwner(_data) { +} +inline MTPmessage MTP_messageEmpty(MTPint _id) { + return MTPmessage(new MTPDmessageEmpty(_id)); +} +inline MTPmessage MTP_message(MTPint _id, MTPint _from_id, const MTPPeer &_to_id, MTPBool _out, MTPBool _unread, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media) { + return MTPmessage(new MTPDmessage(_id, _from_id, _to_id, _out, _unread, _date, _message, _media)); +} +inline MTPmessage MTP_messageForwarded(MTPint _id, MTPint _fwd_from_id, MTPint _fwd_date, MTPint _from_id, const MTPPeer &_to_id, MTPBool _out, MTPBool _unread, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media) { + return MTPmessage(new MTPDmessageForwarded(_id, _fwd_from_id, _fwd_date, _from_id, _to_id, _out, _unread, _date, _message, _media)); +} +inline MTPmessage MTP_messageService(MTPint _id, MTPint _from_id, const MTPPeer &_to_id, MTPBool _out, MTPBool _unread, MTPint _date, const MTPMessageAction &_action) { + return MTPmessage(new MTPDmessageService(_id, _from_id, _to_id, _out, _unread, _date, _action)); +} + +inline uint32 MTPmessageMedia::size() const { + switch (_type) { + case mtpc_messageMediaPhoto: { + const MTPDmessageMediaPhoto &v(c_messageMediaPhoto()); + return v.vphoto.size(); + } + case mtpc_messageMediaVideo: { + const MTPDmessageMediaVideo &v(c_messageMediaVideo()); + return v.vvideo.size(); + } + case mtpc_messageMediaGeo: { + const MTPDmessageMediaGeo &v(c_messageMediaGeo()); + return v.vgeo.size(); + } + case mtpc_messageMediaContact: { + const MTPDmessageMediaContact &v(c_messageMediaContact()); + return v.vphone_number.size() + v.vfirst_name.size() + v.vlast_name.size() + v.vuser_id.size(); + } + case mtpc_messageMediaUnsupported: { + const MTPDmessageMediaUnsupported &v(c_messageMediaUnsupported()); + return v.vbytes.size(); + } + case mtpc_messageMediaDocument: { + const MTPDmessageMediaDocument &v(c_messageMediaDocument()); + return v.vdocument.size(); + } + case mtpc_messageMediaAudio: { + const MTPDmessageMediaAudio &v(c_messageMediaAudio()); + return v.vaudio.size(); + } + } + return 0; +} +inline mtpTypeId MTPmessageMedia::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessageMedia::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messageMediaEmpty: _type = cons; break; + case mtpc_messageMediaPhoto: _type = cons; { + if (!data) setData(new MTPDmessageMediaPhoto()); + MTPDmessageMediaPhoto &v(_messageMediaPhoto()); + v.vphoto.read(from, end); + } break; + case mtpc_messageMediaVideo: _type = cons; { + if (!data) setData(new MTPDmessageMediaVideo()); + MTPDmessageMediaVideo &v(_messageMediaVideo()); + v.vvideo.read(from, end); + } break; + case mtpc_messageMediaGeo: _type = cons; { + if (!data) setData(new MTPDmessageMediaGeo()); + MTPDmessageMediaGeo &v(_messageMediaGeo()); + v.vgeo.read(from, end); + } break; + case mtpc_messageMediaContact: _type = cons; { + if (!data) setData(new MTPDmessageMediaContact()); + MTPDmessageMediaContact &v(_messageMediaContact()); + v.vphone_number.read(from, end); + v.vfirst_name.read(from, end); + v.vlast_name.read(from, end); + v.vuser_id.read(from, end); + } break; + case mtpc_messageMediaUnsupported: _type = cons; { + if (!data) setData(new MTPDmessageMediaUnsupported()); + MTPDmessageMediaUnsupported &v(_messageMediaUnsupported()); + v.vbytes.read(from, end); + } break; + case mtpc_messageMediaDocument: _type = cons; { + if (!data) setData(new MTPDmessageMediaDocument()); + MTPDmessageMediaDocument &v(_messageMediaDocument()); + v.vdocument.read(from, end); + } break; + case mtpc_messageMediaAudio: _type = cons; { + if (!data) setData(new MTPDmessageMediaAudio()); + MTPDmessageMediaAudio &v(_messageMediaAudio()); + v.vaudio.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessageMedia"); + } +} +inline void MTPmessageMedia::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messageMediaPhoto: { + const MTPDmessageMediaPhoto &v(c_messageMediaPhoto()); + v.vphoto.write(to); + } break; + case mtpc_messageMediaVideo: { + const MTPDmessageMediaVideo &v(c_messageMediaVideo()); + v.vvideo.write(to); + } break; + case mtpc_messageMediaGeo: { + const MTPDmessageMediaGeo &v(c_messageMediaGeo()); + v.vgeo.write(to); + } break; + case mtpc_messageMediaContact: { + const MTPDmessageMediaContact &v(c_messageMediaContact()); + v.vphone_number.write(to); + v.vfirst_name.write(to); + v.vlast_name.write(to); + v.vuser_id.write(to); + } break; + case mtpc_messageMediaUnsupported: { + const MTPDmessageMediaUnsupported &v(c_messageMediaUnsupported()); + v.vbytes.write(to); + } break; + case mtpc_messageMediaDocument: { + const MTPDmessageMediaDocument &v(c_messageMediaDocument()); + v.vdocument.write(to); + } break; + case mtpc_messageMediaAudio: { + const MTPDmessageMediaAudio &v(c_messageMediaAudio()); + v.vaudio.write(to); + } break; + } +} +inline MTPmessageMedia::MTPmessageMedia(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_messageMediaEmpty: break; + case mtpc_messageMediaPhoto: setData(new MTPDmessageMediaPhoto()); break; + case mtpc_messageMediaVideo: setData(new MTPDmessageMediaVideo()); break; + case mtpc_messageMediaGeo: setData(new MTPDmessageMediaGeo()); break; + case mtpc_messageMediaContact: setData(new MTPDmessageMediaContact()); break; + case mtpc_messageMediaUnsupported: setData(new MTPDmessageMediaUnsupported()); break; + case mtpc_messageMediaDocument: setData(new MTPDmessageMediaDocument()); break; + case mtpc_messageMediaAudio: setData(new MTPDmessageMediaAudio()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessageMedia"); + } +} +inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaPhoto *_data) : _type(mtpc_messageMediaPhoto), mtpDataOwner(_data) { +} +inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaVideo *_data) : _type(mtpc_messageMediaVideo), mtpDataOwner(_data) { +} +inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaGeo *_data) : _type(mtpc_messageMediaGeo), mtpDataOwner(_data) { +} +inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaContact *_data) : _type(mtpc_messageMediaContact), mtpDataOwner(_data) { +} +inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaUnsupported *_data) : _type(mtpc_messageMediaUnsupported), mtpDataOwner(_data) { +} +inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaDocument *_data) : _type(mtpc_messageMediaDocument), mtpDataOwner(_data) { +} +inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaAudio *_data) : _type(mtpc_messageMediaAudio), mtpDataOwner(_data) { +} +inline MTPmessageMedia MTP_messageMediaEmpty() { + return MTPmessageMedia(mtpc_messageMediaEmpty); +} +inline MTPmessageMedia MTP_messageMediaPhoto(const MTPPhoto &_photo) { + return MTPmessageMedia(new MTPDmessageMediaPhoto(_photo)); +} +inline MTPmessageMedia MTP_messageMediaVideo(const MTPVideo &_video) { + return MTPmessageMedia(new MTPDmessageMediaVideo(_video)); +} +inline MTPmessageMedia MTP_messageMediaGeo(const MTPGeoPoint &_geo) { + return MTPmessageMedia(new MTPDmessageMediaGeo(_geo)); +} +inline MTPmessageMedia MTP_messageMediaContact(const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name, MTPint _user_id) { + return MTPmessageMedia(new MTPDmessageMediaContact(_phone_number, _first_name, _last_name, _user_id)); +} +inline MTPmessageMedia MTP_messageMediaUnsupported(const MTPbytes &_bytes) { + return MTPmessageMedia(new MTPDmessageMediaUnsupported(_bytes)); +} +inline MTPmessageMedia MTP_messageMediaDocument(const MTPDocument &_document) { + return MTPmessageMedia(new MTPDmessageMediaDocument(_document)); +} +inline MTPmessageMedia MTP_messageMediaAudio(const MTPAudio &_audio) { + return MTPmessageMedia(new MTPDmessageMediaAudio(_audio)); +} + +inline uint32 MTPmessageAction::size() const { + switch (_type) { + case mtpc_messageActionChatCreate: { + const MTPDmessageActionChatCreate &v(c_messageActionChatCreate()); + return v.vtitle.size() + v.vusers.size(); + } + case mtpc_messageActionChatEditTitle: { + const MTPDmessageActionChatEditTitle &v(c_messageActionChatEditTitle()); + return v.vtitle.size(); + } + case mtpc_messageActionChatEditPhoto: { + const MTPDmessageActionChatEditPhoto &v(c_messageActionChatEditPhoto()); + return v.vphoto.size(); + } + case mtpc_messageActionChatAddUser: { + const MTPDmessageActionChatAddUser &v(c_messageActionChatAddUser()); + return v.vuser_id.size(); + } + case mtpc_messageActionChatDeleteUser: { + const MTPDmessageActionChatDeleteUser &v(c_messageActionChatDeleteUser()); + return v.vuser_id.size(); + } + case mtpc_messageActionGeoChatCreate: { + const MTPDmessageActionGeoChatCreate &v(c_messageActionGeoChatCreate()); + return v.vtitle.size() + v.vaddress.size(); + } + } + return 0; +} +inline mtpTypeId MTPmessageAction::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessageAction::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messageActionEmpty: _type = cons; break; + case mtpc_messageActionChatCreate: _type = cons; { + if (!data) setData(new MTPDmessageActionChatCreate()); + MTPDmessageActionChatCreate &v(_messageActionChatCreate()); + v.vtitle.read(from, end); + v.vusers.read(from, end); + } break; + case mtpc_messageActionChatEditTitle: _type = cons; { + if (!data) setData(new MTPDmessageActionChatEditTitle()); + MTPDmessageActionChatEditTitle &v(_messageActionChatEditTitle()); + v.vtitle.read(from, end); + } break; + case mtpc_messageActionChatEditPhoto: _type = cons; { + if (!data) setData(new MTPDmessageActionChatEditPhoto()); + MTPDmessageActionChatEditPhoto &v(_messageActionChatEditPhoto()); + v.vphoto.read(from, end); + } break; + case mtpc_messageActionChatDeletePhoto: _type = cons; break; + case mtpc_messageActionChatAddUser: _type = cons; { + if (!data) setData(new MTPDmessageActionChatAddUser()); + MTPDmessageActionChatAddUser &v(_messageActionChatAddUser()); + v.vuser_id.read(from, end); + } break; + case mtpc_messageActionChatDeleteUser: _type = cons; { + if (!data) setData(new MTPDmessageActionChatDeleteUser()); + MTPDmessageActionChatDeleteUser &v(_messageActionChatDeleteUser()); + v.vuser_id.read(from, end); + } break; + case mtpc_messageActionGeoChatCreate: _type = cons; { + if (!data) setData(new MTPDmessageActionGeoChatCreate()); + MTPDmessageActionGeoChatCreate &v(_messageActionGeoChatCreate()); + v.vtitle.read(from, end); + v.vaddress.read(from, end); + } break; + case mtpc_messageActionGeoChatCheckin: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPmessageAction"); + } +} +inline void MTPmessageAction::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messageActionChatCreate: { + const MTPDmessageActionChatCreate &v(c_messageActionChatCreate()); + v.vtitle.write(to); + v.vusers.write(to); + } break; + case mtpc_messageActionChatEditTitle: { + const MTPDmessageActionChatEditTitle &v(c_messageActionChatEditTitle()); + v.vtitle.write(to); + } break; + case mtpc_messageActionChatEditPhoto: { + const MTPDmessageActionChatEditPhoto &v(c_messageActionChatEditPhoto()); + v.vphoto.write(to); + } break; + case mtpc_messageActionChatAddUser: { + const MTPDmessageActionChatAddUser &v(c_messageActionChatAddUser()); + v.vuser_id.write(to); + } break; + case mtpc_messageActionChatDeleteUser: { + const MTPDmessageActionChatDeleteUser &v(c_messageActionChatDeleteUser()); + v.vuser_id.write(to); + } break; + case mtpc_messageActionGeoChatCreate: { + const MTPDmessageActionGeoChatCreate &v(c_messageActionGeoChatCreate()); + v.vtitle.write(to); + v.vaddress.write(to); + } break; + } +} +inline MTPmessageAction::MTPmessageAction(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_messageActionEmpty: break; + case mtpc_messageActionChatCreate: setData(new MTPDmessageActionChatCreate()); break; + case mtpc_messageActionChatEditTitle: setData(new MTPDmessageActionChatEditTitle()); break; + case mtpc_messageActionChatEditPhoto: setData(new MTPDmessageActionChatEditPhoto()); break; + case mtpc_messageActionChatDeletePhoto: break; + case mtpc_messageActionChatAddUser: setData(new MTPDmessageActionChatAddUser()); break; + case mtpc_messageActionChatDeleteUser: setData(new MTPDmessageActionChatDeleteUser()); break; + case mtpc_messageActionGeoChatCreate: setData(new MTPDmessageActionGeoChatCreate()); break; + case mtpc_messageActionGeoChatCheckin: break; + default: throw mtpErrorBadTypeId(type, "MTPmessageAction"); + } +} +inline MTPmessageAction::MTPmessageAction(MTPDmessageActionChatCreate *_data) : _type(mtpc_messageActionChatCreate), mtpDataOwner(_data) { +} +inline MTPmessageAction::MTPmessageAction(MTPDmessageActionChatEditTitle *_data) : _type(mtpc_messageActionChatEditTitle), mtpDataOwner(_data) { +} +inline MTPmessageAction::MTPmessageAction(MTPDmessageActionChatEditPhoto *_data) : _type(mtpc_messageActionChatEditPhoto), mtpDataOwner(_data) { +} +inline MTPmessageAction::MTPmessageAction(MTPDmessageActionChatAddUser *_data) : _type(mtpc_messageActionChatAddUser), mtpDataOwner(_data) { +} +inline MTPmessageAction::MTPmessageAction(MTPDmessageActionChatDeleteUser *_data) : _type(mtpc_messageActionChatDeleteUser), mtpDataOwner(_data) { +} +inline MTPmessageAction::MTPmessageAction(MTPDmessageActionGeoChatCreate *_data) : _type(mtpc_messageActionGeoChatCreate), mtpDataOwner(_data) { +} +inline MTPmessageAction MTP_messageActionEmpty() { + return MTPmessageAction(mtpc_messageActionEmpty); +} +inline MTPmessageAction MTP_messageActionChatCreate(const MTPstring &_title, const MTPVector &_users) { + return MTPmessageAction(new MTPDmessageActionChatCreate(_title, _users)); +} +inline MTPmessageAction MTP_messageActionChatEditTitle(const MTPstring &_title) { + return MTPmessageAction(new MTPDmessageActionChatEditTitle(_title)); +} +inline MTPmessageAction MTP_messageActionChatEditPhoto(const MTPPhoto &_photo) { + return MTPmessageAction(new MTPDmessageActionChatEditPhoto(_photo)); +} +inline MTPmessageAction MTP_messageActionChatDeletePhoto() { + return MTPmessageAction(mtpc_messageActionChatDeletePhoto); +} +inline MTPmessageAction MTP_messageActionChatAddUser(MTPint _user_id) { + return MTPmessageAction(new MTPDmessageActionChatAddUser(_user_id)); +} +inline MTPmessageAction MTP_messageActionChatDeleteUser(MTPint _user_id) { + return MTPmessageAction(new MTPDmessageActionChatDeleteUser(_user_id)); +} +inline MTPmessageAction MTP_messageActionGeoChatCreate(const MTPstring &_title, const MTPstring &_address) { + return MTPmessageAction(new MTPDmessageActionGeoChatCreate(_title, _address)); +} +inline MTPmessageAction MTP_messageActionGeoChatCheckin() { + return MTPmessageAction(mtpc_messageActionGeoChatCheckin); +} + +inline MTPdialog::MTPdialog() : mtpDataOwner(new MTPDdialog()) { +} + +inline uint32 MTPdialog::size() const { + const MTPDdialog &v(c_dialog()); + return v.vpeer.size() + v.vtop_message.size() + v.vunread_count.size() + v.vnotify_settings.size(); +} +inline mtpTypeId MTPdialog::type() const { + return mtpc_dialog; +} +inline void MTPdialog::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_dialog) throw mtpErrorUnexpected(cons, "MTPdialog"); + + if (!data) setData(new MTPDdialog()); + MTPDdialog &v(_dialog()); + v.vpeer.read(from, end); + v.vtop_message.read(from, end); + v.vunread_count.read(from, end); + v.vnotify_settings.read(from, end); +} +inline void MTPdialog::write(mtpBuffer &to) const { + const MTPDdialog &v(c_dialog()); + v.vpeer.write(to); + v.vtop_message.write(to); + v.vunread_count.write(to); + v.vnotify_settings.write(to); +} +inline MTPdialog::MTPdialog(MTPDdialog *_data) : mtpDataOwner(_data) { +} +inline MTPdialog MTP_dialog(const MTPPeer &_peer, MTPint _top_message, MTPint _unread_count, const MTPPeerNotifySettings &_notify_settings) { + return MTPdialog(new MTPDdialog(_peer, _top_message, _unread_count, _notify_settings)); +} + +inline uint32 MTPphoto::size() const { + switch (_type) { + case mtpc_photoEmpty: { + const MTPDphotoEmpty &v(c_photoEmpty()); + return v.vid.size(); + } + case mtpc_photo: { + const MTPDphoto &v(c_photo()); + return v.vid.size() + v.vaccess_hash.size() + v.vuser_id.size() + v.vdate.size() + v.vcaption.size() + v.vgeo.size() + v.vsizes.size(); + } + } + return 0; +} +inline mtpTypeId MTPphoto::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPphoto::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_photoEmpty: _type = cons; { + if (!data) setData(new MTPDphotoEmpty()); + MTPDphotoEmpty &v(_photoEmpty()); + v.vid.read(from, end); + } break; + case mtpc_photo: _type = cons; { + if (!data) setData(new MTPDphoto()); + MTPDphoto &v(_photo()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + v.vuser_id.read(from, end); + v.vdate.read(from, end); + v.vcaption.read(from, end); + v.vgeo.read(from, end); + v.vsizes.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPphoto"); + } +} +inline void MTPphoto::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_photoEmpty: { + const MTPDphotoEmpty &v(c_photoEmpty()); + v.vid.write(to); + } break; + case mtpc_photo: { + const MTPDphoto &v(c_photo()); + v.vid.write(to); + v.vaccess_hash.write(to); + v.vuser_id.write(to); + v.vdate.write(to); + v.vcaption.write(to); + v.vgeo.write(to); + v.vsizes.write(to); + } break; + } +} +inline MTPphoto::MTPphoto(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_photoEmpty: setData(new MTPDphotoEmpty()); break; + case mtpc_photo: setData(new MTPDphoto()); break; + default: throw mtpErrorBadTypeId(type, "MTPphoto"); + } +} +inline MTPphoto::MTPphoto(MTPDphotoEmpty *_data) : _type(mtpc_photoEmpty), mtpDataOwner(_data) { +} +inline MTPphoto::MTPphoto(MTPDphoto *_data) : _type(mtpc_photo), mtpDataOwner(_data) { +} +inline MTPphoto MTP_photoEmpty(const MTPlong &_id) { + return MTPphoto(new MTPDphotoEmpty(_id)); +} +inline MTPphoto MTP_photo(const MTPlong &_id, const MTPlong &_access_hash, MTPint _user_id, MTPint _date, const MTPstring &_caption, const MTPGeoPoint &_geo, const MTPVector &_sizes) { + return MTPphoto(new MTPDphoto(_id, _access_hash, _user_id, _date, _caption, _geo, _sizes)); +} + +inline uint32 MTPphotoSize::size() const { + switch (_type) { + case mtpc_photoSizeEmpty: { + const MTPDphotoSizeEmpty &v(c_photoSizeEmpty()); + return v.vtype.size(); + } + case mtpc_photoSize: { + const MTPDphotoSize &v(c_photoSize()); + return v.vtype.size() + v.vlocation.size() + v.vw.size() + v.vh.size() + v.vsize.size(); + } + case mtpc_photoCachedSize: { + const MTPDphotoCachedSize &v(c_photoCachedSize()); + return v.vtype.size() + v.vlocation.size() + v.vw.size() + v.vh.size() + v.vbytes.size(); + } + } + return 0; +} +inline mtpTypeId MTPphotoSize::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPphotoSize::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_photoSizeEmpty: _type = cons; { + if (!data) setData(new MTPDphotoSizeEmpty()); + MTPDphotoSizeEmpty &v(_photoSizeEmpty()); + v.vtype.read(from, end); + } break; + case mtpc_photoSize: _type = cons; { + if (!data) setData(new MTPDphotoSize()); + MTPDphotoSize &v(_photoSize()); + v.vtype.read(from, end); + v.vlocation.read(from, end); + v.vw.read(from, end); + v.vh.read(from, end); + v.vsize.read(from, end); + } break; + case mtpc_photoCachedSize: _type = cons; { + if (!data) setData(new MTPDphotoCachedSize()); + MTPDphotoCachedSize &v(_photoCachedSize()); + v.vtype.read(from, end); + v.vlocation.read(from, end); + v.vw.read(from, end); + v.vh.read(from, end); + v.vbytes.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPphotoSize"); + } +} +inline void MTPphotoSize::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_photoSizeEmpty: { + const MTPDphotoSizeEmpty &v(c_photoSizeEmpty()); + v.vtype.write(to); + } break; + case mtpc_photoSize: { + const MTPDphotoSize &v(c_photoSize()); + v.vtype.write(to); + v.vlocation.write(to); + v.vw.write(to); + v.vh.write(to); + v.vsize.write(to); + } break; + case mtpc_photoCachedSize: { + const MTPDphotoCachedSize &v(c_photoCachedSize()); + v.vtype.write(to); + v.vlocation.write(to); + v.vw.write(to); + v.vh.write(to); + v.vbytes.write(to); + } break; + } +} +inline MTPphotoSize::MTPphotoSize(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_photoSizeEmpty: setData(new MTPDphotoSizeEmpty()); break; + case mtpc_photoSize: setData(new MTPDphotoSize()); break; + case mtpc_photoCachedSize: setData(new MTPDphotoCachedSize()); break; + default: throw mtpErrorBadTypeId(type, "MTPphotoSize"); + } +} +inline MTPphotoSize::MTPphotoSize(MTPDphotoSizeEmpty *_data) : _type(mtpc_photoSizeEmpty), mtpDataOwner(_data) { +} +inline MTPphotoSize::MTPphotoSize(MTPDphotoSize *_data) : _type(mtpc_photoSize), mtpDataOwner(_data) { +} +inline MTPphotoSize::MTPphotoSize(MTPDphotoCachedSize *_data) : _type(mtpc_photoCachedSize), mtpDataOwner(_data) { +} +inline MTPphotoSize MTP_photoSizeEmpty(const MTPstring &_type) { + return MTPphotoSize(new MTPDphotoSizeEmpty(_type)); +} +inline MTPphotoSize MTP_photoSize(const MTPstring &_type, const MTPFileLocation &_location, MTPint _w, MTPint _h, MTPint _size) { + return MTPphotoSize(new MTPDphotoSize(_type, _location, _w, _h, _size)); +} +inline MTPphotoSize MTP_photoCachedSize(const MTPstring &_type, const MTPFileLocation &_location, MTPint _w, MTPint _h, const MTPbytes &_bytes) { + return MTPphotoSize(new MTPDphotoCachedSize(_type, _location, _w, _h, _bytes)); +} + +inline uint32 MTPvideo::size() const { + switch (_type) { + case mtpc_videoEmpty: { + const MTPDvideoEmpty &v(c_videoEmpty()); + return v.vid.size(); + } + case mtpc_video: { + const MTPDvideo &v(c_video()); + return v.vid.size() + v.vaccess_hash.size() + v.vuser_id.size() + v.vdate.size() + v.vcaption.size() + v.vduration.size() + v.vmime_type.size() + v.vsize.size() + v.vthumb.size() + v.vdc_id.size() + v.vw.size() + v.vh.size(); + } + } + return 0; +} +inline mtpTypeId MTPvideo::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPvideo::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_videoEmpty: _type = cons; { + if (!data) setData(new MTPDvideoEmpty()); + MTPDvideoEmpty &v(_videoEmpty()); + v.vid.read(from, end); + } break; + case mtpc_video: _type = cons; { + if (!data) setData(new MTPDvideo()); + MTPDvideo &v(_video()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + v.vuser_id.read(from, end); + v.vdate.read(from, end); + v.vcaption.read(from, end); + v.vduration.read(from, end); + v.vmime_type.read(from, end); + v.vsize.read(from, end); + v.vthumb.read(from, end); + v.vdc_id.read(from, end); + v.vw.read(from, end); + v.vh.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPvideo"); + } +} +inline void MTPvideo::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_videoEmpty: { + const MTPDvideoEmpty &v(c_videoEmpty()); + v.vid.write(to); + } break; + case mtpc_video: { + const MTPDvideo &v(c_video()); + v.vid.write(to); + v.vaccess_hash.write(to); + v.vuser_id.write(to); + v.vdate.write(to); + v.vcaption.write(to); + v.vduration.write(to); + v.vmime_type.write(to); + v.vsize.write(to); + v.vthumb.write(to); + v.vdc_id.write(to); + v.vw.write(to); + v.vh.write(to); + } break; + } +} +inline MTPvideo::MTPvideo(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_videoEmpty: setData(new MTPDvideoEmpty()); break; + case mtpc_video: setData(new MTPDvideo()); break; + default: throw mtpErrorBadTypeId(type, "MTPvideo"); + } +} +inline MTPvideo::MTPvideo(MTPDvideoEmpty *_data) : _type(mtpc_videoEmpty), mtpDataOwner(_data) { +} +inline MTPvideo::MTPvideo(MTPDvideo *_data) : _type(mtpc_video), mtpDataOwner(_data) { +} +inline MTPvideo MTP_videoEmpty(const MTPlong &_id) { + return MTPvideo(new MTPDvideoEmpty(_id)); +} +inline MTPvideo MTP_video(const MTPlong &_id, const MTPlong &_access_hash, MTPint _user_id, MTPint _date, const MTPstring &_caption, MTPint _duration, const MTPstring &_mime_type, MTPint _size, const MTPPhotoSize &_thumb, MTPint _dc_id, MTPint _w, MTPint _h) { + return MTPvideo(new MTPDvideo(_id, _access_hash, _user_id, _date, _caption, _duration, _mime_type, _size, _thumb, _dc_id, _w, _h)); +} + +inline uint32 MTPgeoPoint::size() const { + switch (_type) { + case mtpc_geoPoint: { + const MTPDgeoPoint &v(c_geoPoint()); + return v.vlong.size() + v.vlat.size(); + } + } + return 0; +} +inline mtpTypeId MTPgeoPoint::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPgeoPoint::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_geoPointEmpty: _type = cons; break; + case mtpc_geoPoint: _type = cons; { + if (!data) setData(new MTPDgeoPoint()); + MTPDgeoPoint &v(_geoPoint()); + v.vlong.read(from, end); + v.vlat.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPgeoPoint"); + } +} +inline void MTPgeoPoint::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_geoPoint: { + const MTPDgeoPoint &v(c_geoPoint()); + v.vlong.write(to); + v.vlat.write(to); + } break; + } +} +inline MTPgeoPoint::MTPgeoPoint(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_geoPointEmpty: break; + case mtpc_geoPoint: setData(new MTPDgeoPoint()); break; + default: throw mtpErrorBadTypeId(type, "MTPgeoPoint"); + } +} +inline MTPgeoPoint::MTPgeoPoint(MTPDgeoPoint *_data) : _type(mtpc_geoPoint), mtpDataOwner(_data) { +} +inline MTPgeoPoint MTP_geoPointEmpty() { + return MTPgeoPoint(mtpc_geoPointEmpty); +} +inline MTPgeoPoint MTP_geoPoint(const MTPdouble &_long, const MTPdouble &_lat) { + return MTPgeoPoint(new MTPDgeoPoint(_long, _lat)); +} + +inline MTPauth_checkedPhone::MTPauth_checkedPhone() : mtpDataOwner(new MTPDauth_checkedPhone()) { +} + +inline uint32 MTPauth_checkedPhone::size() const { + const MTPDauth_checkedPhone &v(c_auth_checkedPhone()); + return v.vphone_registered.size() + v.vphone_invited.size(); +} +inline mtpTypeId MTPauth_checkedPhone::type() const { + return mtpc_auth_checkedPhone; +} +inline void MTPauth_checkedPhone::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_auth_checkedPhone) throw mtpErrorUnexpected(cons, "MTPauth_checkedPhone"); + + if (!data) setData(new MTPDauth_checkedPhone()); + MTPDauth_checkedPhone &v(_auth_checkedPhone()); + v.vphone_registered.read(from, end); + v.vphone_invited.read(from, end); +} +inline void MTPauth_checkedPhone::write(mtpBuffer &to) const { + const MTPDauth_checkedPhone &v(c_auth_checkedPhone()); + v.vphone_registered.write(to); + v.vphone_invited.write(to); +} +inline MTPauth_checkedPhone::MTPauth_checkedPhone(MTPDauth_checkedPhone *_data) : mtpDataOwner(_data) { +} +inline MTPauth_checkedPhone MTP_auth_checkedPhone(MTPBool _phone_registered, MTPBool _phone_invited) { + return MTPauth_checkedPhone(new MTPDauth_checkedPhone(_phone_registered, _phone_invited)); +} + +inline MTPauth_sentCode::MTPauth_sentCode() : mtpDataOwner(new MTPDauth_sentCode()) { +} + +inline uint32 MTPauth_sentCode::size() const { + const MTPDauth_sentCode &v(c_auth_sentCode()); + return v.vphone_registered.size() + v.vphone_code_hash.size() + v.vsend_call_timeout.size() + v.vis_password.size(); +} +inline mtpTypeId MTPauth_sentCode::type() const { + return mtpc_auth_sentCode; +} +inline void MTPauth_sentCode::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_auth_sentCode) throw mtpErrorUnexpected(cons, "MTPauth_sentCode"); + + if (!data) setData(new MTPDauth_sentCode()); + MTPDauth_sentCode &v(_auth_sentCode()); + v.vphone_registered.read(from, end); + v.vphone_code_hash.read(from, end); + v.vsend_call_timeout.read(from, end); + v.vis_password.read(from, end); +} +inline void MTPauth_sentCode::write(mtpBuffer &to) const { + const MTPDauth_sentCode &v(c_auth_sentCode()); + v.vphone_registered.write(to); + v.vphone_code_hash.write(to); + v.vsend_call_timeout.write(to); + v.vis_password.write(to); +} +inline MTPauth_sentCode::MTPauth_sentCode(MTPDauth_sentCode *_data) : mtpDataOwner(_data) { +} +inline MTPauth_sentCode MTP_auth_sentCode(MTPBool _phone_registered, const MTPstring &_phone_code_hash, MTPint _send_call_timeout, MTPBool _is_password) { + return MTPauth_sentCode(new MTPDauth_sentCode(_phone_registered, _phone_code_hash, _send_call_timeout, _is_password)); +} + +inline MTPauth_authorization::MTPauth_authorization() : mtpDataOwner(new MTPDauth_authorization()) { +} + +inline uint32 MTPauth_authorization::size() const { + const MTPDauth_authorization &v(c_auth_authorization()); + return v.vexpires.size() + v.vuser.size(); +} +inline mtpTypeId MTPauth_authorization::type() const { + return mtpc_auth_authorization; +} +inline void MTPauth_authorization::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_auth_authorization) throw mtpErrorUnexpected(cons, "MTPauth_authorization"); + + if (!data) setData(new MTPDauth_authorization()); + MTPDauth_authorization &v(_auth_authorization()); + v.vexpires.read(from, end); + v.vuser.read(from, end); +} +inline void MTPauth_authorization::write(mtpBuffer &to) const { + const MTPDauth_authorization &v(c_auth_authorization()); + v.vexpires.write(to); + v.vuser.write(to); +} +inline MTPauth_authorization::MTPauth_authorization(MTPDauth_authorization *_data) : mtpDataOwner(_data) { +} +inline MTPauth_authorization MTP_auth_authorization(MTPint _expires, const MTPUser &_user) { + return MTPauth_authorization(new MTPDauth_authorization(_expires, _user)); +} + +inline MTPauth_exportedAuthorization::MTPauth_exportedAuthorization() : mtpDataOwner(new MTPDauth_exportedAuthorization()) { +} + +inline uint32 MTPauth_exportedAuthorization::size() const { + const MTPDauth_exportedAuthorization &v(c_auth_exportedAuthorization()); + return v.vid.size() + v.vbytes.size(); +} +inline mtpTypeId MTPauth_exportedAuthorization::type() const { + return mtpc_auth_exportedAuthorization; +} +inline void MTPauth_exportedAuthorization::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_auth_exportedAuthorization) throw mtpErrorUnexpected(cons, "MTPauth_exportedAuthorization"); + + if (!data) setData(new MTPDauth_exportedAuthorization()); + MTPDauth_exportedAuthorization &v(_auth_exportedAuthorization()); + v.vid.read(from, end); + v.vbytes.read(from, end); +} +inline void MTPauth_exportedAuthorization::write(mtpBuffer &to) const { + const MTPDauth_exportedAuthorization &v(c_auth_exportedAuthorization()); + v.vid.write(to); + v.vbytes.write(to); +} +inline MTPauth_exportedAuthorization::MTPauth_exportedAuthorization(MTPDauth_exportedAuthorization *_data) : mtpDataOwner(_data) { +} +inline MTPauth_exportedAuthorization MTP_auth_exportedAuthorization(MTPint _id, const MTPbytes &_bytes) { + return MTPauth_exportedAuthorization(new MTPDauth_exportedAuthorization(_id, _bytes)); +} + +inline uint32 MTPinputNotifyPeer::size() const { + switch (_type) { + case mtpc_inputNotifyPeer: { + const MTPDinputNotifyPeer &v(c_inputNotifyPeer()); + return v.vpeer.size(); + } + case mtpc_inputNotifyGeoChatPeer: { + const MTPDinputNotifyGeoChatPeer &v(c_inputNotifyGeoChatPeer()); + return v.vpeer.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputNotifyPeer::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputNotifyPeer::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputNotifyPeer: _type = cons; { + if (!data) setData(new MTPDinputNotifyPeer()); + MTPDinputNotifyPeer &v(_inputNotifyPeer()); + v.vpeer.read(from, end); + } break; + case mtpc_inputNotifyUsers: _type = cons; break; + case mtpc_inputNotifyChats: _type = cons; break; + case mtpc_inputNotifyAll: _type = cons; break; + case mtpc_inputNotifyGeoChatPeer: _type = cons; { + if (!data) setData(new MTPDinputNotifyGeoChatPeer()); + MTPDinputNotifyGeoChatPeer &v(_inputNotifyGeoChatPeer()); + v.vpeer.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputNotifyPeer"); + } +} +inline void MTPinputNotifyPeer::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputNotifyPeer: { + const MTPDinputNotifyPeer &v(c_inputNotifyPeer()); + v.vpeer.write(to); + } break; + case mtpc_inputNotifyGeoChatPeer: { + const MTPDinputNotifyGeoChatPeer &v(c_inputNotifyGeoChatPeer()); + v.vpeer.write(to); + } break; + } +} +inline MTPinputNotifyPeer::MTPinputNotifyPeer(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputNotifyPeer: setData(new MTPDinputNotifyPeer()); break; + case mtpc_inputNotifyUsers: break; + case mtpc_inputNotifyChats: break; + case mtpc_inputNotifyAll: break; + case mtpc_inputNotifyGeoChatPeer: setData(new MTPDinputNotifyGeoChatPeer()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputNotifyPeer"); + } +} +inline MTPinputNotifyPeer::MTPinputNotifyPeer(MTPDinputNotifyPeer *_data) : _type(mtpc_inputNotifyPeer), mtpDataOwner(_data) { +} +inline MTPinputNotifyPeer::MTPinputNotifyPeer(MTPDinputNotifyGeoChatPeer *_data) : _type(mtpc_inputNotifyGeoChatPeer), mtpDataOwner(_data) { +} +inline MTPinputNotifyPeer MTP_inputNotifyPeer(const MTPInputPeer &_peer) { + return MTPinputNotifyPeer(new MTPDinputNotifyPeer(_peer)); +} +inline MTPinputNotifyPeer MTP_inputNotifyUsers() { + return MTPinputNotifyPeer(mtpc_inputNotifyUsers); +} +inline MTPinputNotifyPeer MTP_inputNotifyChats() { + return MTPinputNotifyPeer(mtpc_inputNotifyChats); +} +inline MTPinputNotifyPeer MTP_inputNotifyAll() { + return MTPinputNotifyPeer(mtpc_inputNotifyAll); +} +inline MTPinputNotifyPeer MTP_inputNotifyGeoChatPeer(const MTPInputGeoChat &_peer) { + return MTPinputNotifyPeer(new MTPDinputNotifyGeoChatPeer(_peer)); +} + +inline uint32 MTPinputPeerNotifyEvents::size() const { + return 0; +} +inline mtpTypeId MTPinputPeerNotifyEvents::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputPeerNotifyEvents::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + switch (cons) { + case mtpc_inputPeerNotifyEventsEmpty: _type = cons; break; + case mtpc_inputPeerNotifyEventsAll: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPinputPeerNotifyEvents"); + } +} +inline void MTPinputPeerNotifyEvents::write(mtpBuffer &to) const { + switch (_type) { + } +} +inline MTPinputPeerNotifyEvents::MTPinputPeerNotifyEvents(mtpTypeId type) : _type(type) { + switch (type) { + case mtpc_inputPeerNotifyEventsEmpty: break; + case mtpc_inputPeerNotifyEventsAll: break; + default: throw mtpErrorBadTypeId(type, "MTPinputPeerNotifyEvents"); + } +} +inline MTPinputPeerNotifyEvents MTP_inputPeerNotifyEventsEmpty() { + return MTPinputPeerNotifyEvents(mtpc_inputPeerNotifyEventsEmpty); +} +inline MTPinputPeerNotifyEvents MTP_inputPeerNotifyEventsAll() { + return MTPinputPeerNotifyEvents(mtpc_inputPeerNotifyEventsAll); +} + +inline MTPinputPeerNotifySettings::MTPinputPeerNotifySettings() : mtpDataOwner(new MTPDinputPeerNotifySettings()) { +} + +inline uint32 MTPinputPeerNotifySettings::size() const { + const MTPDinputPeerNotifySettings &v(c_inputPeerNotifySettings()); + return v.vmute_until.size() + v.vsound.size() + v.vshow_previews.size() + v.vevents_mask.size(); +} +inline mtpTypeId MTPinputPeerNotifySettings::type() const { + return mtpc_inputPeerNotifySettings; +} +inline void MTPinputPeerNotifySettings::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_inputPeerNotifySettings) throw mtpErrorUnexpected(cons, "MTPinputPeerNotifySettings"); + + if (!data) setData(new MTPDinputPeerNotifySettings()); + MTPDinputPeerNotifySettings &v(_inputPeerNotifySettings()); + v.vmute_until.read(from, end); + v.vsound.read(from, end); + v.vshow_previews.read(from, end); + v.vevents_mask.read(from, end); +} +inline void MTPinputPeerNotifySettings::write(mtpBuffer &to) const { + const MTPDinputPeerNotifySettings &v(c_inputPeerNotifySettings()); + v.vmute_until.write(to); + v.vsound.write(to); + v.vshow_previews.write(to); + v.vevents_mask.write(to); +} +inline MTPinputPeerNotifySettings::MTPinputPeerNotifySettings(MTPDinputPeerNotifySettings *_data) : mtpDataOwner(_data) { +} +inline MTPinputPeerNotifySettings MTP_inputPeerNotifySettings(MTPint _mute_until, const MTPstring &_sound, MTPBool _show_previews, MTPint _events_mask) { + return MTPinputPeerNotifySettings(new MTPDinputPeerNotifySettings(_mute_until, _sound, _show_previews, _events_mask)); +} + +inline uint32 MTPpeerNotifyEvents::size() const { + return 0; +} +inline mtpTypeId MTPpeerNotifyEvents::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPpeerNotifyEvents::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + switch (cons) { + case mtpc_peerNotifyEventsEmpty: _type = cons; break; + case mtpc_peerNotifyEventsAll: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPpeerNotifyEvents"); + } +} +inline void MTPpeerNotifyEvents::write(mtpBuffer &to) const { + switch (_type) { + } +} +inline MTPpeerNotifyEvents::MTPpeerNotifyEvents(mtpTypeId type) : _type(type) { + switch (type) { + case mtpc_peerNotifyEventsEmpty: break; + case mtpc_peerNotifyEventsAll: break; + default: throw mtpErrorBadTypeId(type, "MTPpeerNotifyEvents"); + } +} +inline MTPpeerNotifyEvents MTP_peerNotifyEventsEmpty() { + return MTPpeerNotifyEvents(mtpc_peerNotifyEventsEmpty); +} +inline MTPpeerNotifyEvents MTP_peerNotifyEventsAll() { + return MTPpeerNotifyEvents(mtpc_peerNotifyEventsAll); +} + +inline uint32 MTPpeerNotifySettings::size() const { + switch (_type) { + case mtpc_peerNotifySettings: { + const MTPDpeerNotifySettings &v(c_peerNotifySettings()); + return v.vmute_until.size() + v.vsound.size() + v.vshow_previews.size() + v.vevents_mask.size(); + } + } + return 0; +} +inline mtpTypeId MTPpeerNotifySettings::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPpeerNotifySettings::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_peerNotifySettingsEmpty: _type = cons; break; + case mtpc_peerNotifySettings: _type = cons; { + if (!data) setData(new MTPDpeerNotifySettings()); + MTPDpeerNotifySettings &v(_peerNotifySettings()); + v.vmute_until.read(from, end); + v.vsound.read(from, end); + v.vshow_previews.read(from, end); + v.vevents_mask.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPpeerNotifySettings"); + } +} +inline void MTPpeerNotifySettings::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_peerNotifySettings: { + const MTPDpeerNotifySettings &v(c_peerNotifySettings()); + v.vmute_until.write(to); + v.vsound.write(to); + v.vshow_previews.write(to); + v.vevents_mask.write(to); + } break; + } +} +inline MTPpeerNotifySettings::MTPpeerNotifySettings(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_peerNotifySettingsEmpty: break; + case mtpc_peerNotifySettings: setData(new MTPDpeerNotifySettings()); break; + default: throw mtpErrorBadTypeId(type, "MTPpeerNotifySettings"); + } +} +inline MTPpeerNotifySettings::MTPpeerNotifySettings(MTPDpeerNotifySettings *_data) : _type(mtpc_peerNotifySettings), mtpDataOwner(_data) { +} +inline MTPpeerNotifySettings MTP_peerNotifySettingsEmpty() { + return MTPpeerNotifySettings(mtpc_peerNotifySettingsEmpty); +} +inline MTPpeerNotifySettings MTP_peerNotifySettings(MTPint _mute_until, const MTPstring &_sound, MTPBool _show_previews, MTPint _events_mask) { + return MTPpeerNotifySettings(new MTPDpeerNotifySettings(_mute_until, _sound, _show_previews, _events_mask)); +} + +inline uint32 MTPwallPaper::size() const { + switch (_type) { + case mtpc_wallPaper: { + const MTPDwallPaper &v(c_wallPaper()); + return v.vid.size() + v.vtitle.size() + v.vsizes.size() + v.vcolor.size(); + } + case mtpc_wallPaperSolid: { + const MTPDwallPaperSolid &v(c_wallPaperSolid()); + return v.vid.size() + v.vtitle.size() + v.vbg_color.size() + v.vcolor.size(); + } + } + return 0; +} +inline mtpTypeId MTPwallPaper::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPwallPaper::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_wallPaper: _type = cons; { + if (!data) setData(new MTPDwallPaper()); + MTPDwallPaper &v(_wallPaper()); + v.vid.read(from, end); + v.vtitle.read(from, end); + v.vsizes.read(from, end); + v.vcolor.read(from, end); + } break; + case mtpc_wallPaperSolid: _type = cons; { + if (!data) setData(new MTPDwallPaperSolid()); + MTPDwallPaperSolid &v(_wallPaperSolid()); + v.vid.read(from, end); + v.vtitle.read(from, end); + v.vbg_color.read(from, end); + v.vcolor.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPwallPaper"); + } +} +inline void MTPwallPaper::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_wallPaper: { + const MTPDwallPaper &v(c_wallPaper()); + v.vid.write(to); + v.vtitle.write(to); + v.vsizes.write(to); + v.vcolor.write(to); + } break; + case mtpc_wallPaperSolid: { + const MTPDwallPaperSolid &v(c_wallPaperSolid()); + v.vid.write(to); + v.vtitle.write(to); + v.vbg_color.write(to); + v.vcolor.write(to); + } break; + } +} +inline MTPwallPaper::MTPwallPaper(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_wallPaper: setData(new MTPDwallPaper()); break; + case mtpc_wallPaperSolid: setData(new MTPDwallPaperSolid()); break; + default: throw mtpErrorBadTypeId(type, "MTPwallPaper"); + } +} +inline MTPwallPaper::MTPwallPaper(MTPDwallPaper *_data) : _type(mtpc_wallPaper), mtpDataOwner(_data) { +} +inline MTPwallPaper::MTPwallPaper(MTPDwallPaperSolid *_data) : _type(mtpc_wallPaperSolid), mtpDataOwner(_data) { +} +inline MTPwallPaper MTP_wallPaper(MTPint _id, const MTPstring &_title, const MTPVector &_sizes, MTPint _color) { + return MTPwallPaper(new MTPDwallPaper(_id, _title, _sizes, _color)); +} +inline MTPwallPaper MTP_wallPaperSolid(MTPint _id, const MTPstring &_title, MTPint _bg_color, MTPint _color) { + return MTPwallPaper(new MTPDwallPaperSolid(_id, _title, _bg_color, _color)); +} + +inline MTPuserFull::MTPuserFull() : mtpDataOwner(new MTPDuserFull()) { +} + +inline uint32 MTPuserFull::size() const { + const MTPDuserFull &v(c_userFull()); + return v.vuser.size() + v.vlink.size() + v.vprofile_photo.size() + v.vnotify_settings.size() + v.vblocked.size() + v.vreal_first_name.size() + v.vreal_last_name.size(); +} +inline mtpTypeId MTPuserFull::type() const { + return mtpc_userFull; +} +inline void MTPuserFull::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_userFull) throw mtpErrorUnexpected(cons, "MTPuserFull"); + + if (!data) setData(new MTPDuserFull()); + MTPDuserFull &v(_userFull()); + v.vuser.read(from, end); + v.vlink.read(from, end); + v.vprofile_photo.read(from, end); + v.vnotify_settings.read(from, end); + v.vblocked.read(from, end); + v.vreal_first_name.read(from, end); + v.vreal_last_name.read(from, end); +} +inline void MTPuserFull::write(mtpBuffer &to) const { + const MTPDuserFull &v(c_userFull()); + v.vuser.write(to); + v.vlink.write(to); + v.vprofile_photo.write(to); + v.vnotify_settings.write(to); + v.vblocked.write(to); + v.vreal_first_name.write(to); + v.vreal_last_name.write(to); +} +inline MTPuserFull::MTPuserFull(MTPDuserFull *_data) : mtpDataOwner(_data) { +} +inline MTPuserFull MTP_userFull(const MTPUser &_user, const MTPcontacts_Link &_link, const MTPPhoto &_profile_photo, const MTPPeerNotifySettings &_notify_settings, MTPBool _blocked, const MTPstring &_real_first_name, const MTPstring &_real_last_name) { + return MTPuserFull(new MTPDuserFull(_user, _link, _profile_photo, _notify_settings, _blocked, _real_first_name, _real_last_name)); +} + +inline MTPcontact::MTPcontact() : mtpDataOwner(new MTPDcontact()) { +} + +inline uint32 MTPcontact::size() const { + const MTPDcontact &v(c_contact()); + return v.vuser_id.size() + v.vmutual.size(); +} +inline mtpTypeId MTPcontact::type() const { + return mtpc_contact; +} +inline void MTPcontact::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_contact) throw mtpErrorUnexpected(cons, "MTPcontact"); + + if (!data) setData(new MTPDcontact()); + MTPDcontact &v(_contact()); + v.vuser_id.read(from, end); + v.vmutual.read(from, end); +} +inline void MTPcontact::write(mtpBuffer &to) const { + const MTPDcontact &v(c_contact()); + v.vuser_id.write(to); + v.vmutual.write(to); +} +inline MTPcontact::MTPcontact(MTPDcontact *_data) : mtpDataOwner(_data) { +} +inline MTPcontact MTP_contact(MTPint _user_id, MTPBool _mutual) { + return MTPcontact(new MTPDcontact(_user_id, _mutual)); +} + +inline MTPimportedContact::MTPimportedContact() : mtpDataOwner(new MTPDimportedContact()) { +} + +inline uint32 MTPimportedContact::size() const { + const MTPDimportedContact &v(c_importedContact()); + return v.vuser_id.size() + v.vclient_id.size(); +} +inline mtpTypeId MTPimportedContact::type() const { + return mtpc_importedContact; +} +inline void MTPimportedContact::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_importedContact) throw mtpErrorUnexpected(cons, "MTPimportedContact"); + + if (!data) setData(new MTPDimportedContact()); + MTPDimportedContact &v(_importedContact()); + v.vuser_id.read(from, end); + v.vclient_id.read(from, end); +} +inline void MTPimportedContact::write(mtpBuffer &to) const { + const MTPDimportedContact &v(c_importedContact()); + v.vuser_id.write(to); + v.vclient_id.write(to); +} +inline MTPimportedContact::MTPimportedContact(MTPDimportedContact *_data) : mtpDataOwner(_data) { +} +inline MTPimportedContact MTP_importedContact(MTPint _user_id, const MTPlong &_client_id) { + return MTPimportedContact(new MTPDimportedContact(_user_id, _client_id)); +} + +inline MTPcontactBlocked::MTPcontactBlocked() : mtpDataOwner(new MTPDcontactBlocked()) { +} + +inline uint32 MTPcontactBlocked::size() const { + const MTPDcontactBlocked &v(c_contactBlocked()); + return v.vuser_id.size() + v.vdate.size(); +} +inline mtpTypeId MTPcontactBlocked::type() const { + return mtpc_contactBlocked; +} +inline void MTPcontactBlocked::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_contactBlocked) throw mtpErrorUnexpected(cons, "MTPcontactBlocked"); + + if (!data) setData(new MTPDcontactBlocked()); + MTPDcontactBlocked &v(_contactBlocked()); + v.vuser_id.read(from, end); + v.vdate.read(from, end); +} +inline void MTPcontactBlocked::write(mtpBuffer &to) const { + const MTPDcontactBlocked &v(c_contactBlocked()); + v.vuser_id.write(to); + v.vdate.write(to); +} +inline MTPcontactBlocked::MTPcontactBlocked(MTPDcontactBlocked *_data) : mtpDataOwner(_data) { +} +inline MTPcontactBlocked MTP_contactBlocked(MTPint _user_id, MTPint _date) { + return MTPcontactBlocked(new MTPDcontactBlocked(_user_id, _date)); +} + +inline MTPcontactFound::MTPcontactFound() : mtpDataOwner(new MTPDcontactFound()) { +} + +inline uint32 MTPcontactFound::size() const { + const MTPDcontactFound &v(c_contactFound()); + return v.vuser_id.size(); +} +inline mtpTypeId MTPcontactFound::type() const { + return mtpc_contactFound; +} +inline void MTPcontactFound::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_contactFound) throw mtpErrorUnexpected(cons, "MTPcontactFound"); + + if (!data) setData(new MTPDcontactFound()); + MTPDcontactFound &v(_contactFound()); + v.vuser_id.read(from, end); +} +inline void MTPcontactFound::write(mtpBuffer &to) const { + const MTPDcontactFound &v(c_contactFound()); + v.vuser_id.write(to); +} +inline MTPcontactFound::MTPcontactFound(MTPDcontactFound *_data) : mtpDataOwner(_data) { +} +inline MTPcontactFound MTP_contactFound(MTPint _user_id) { + return MTPcontactFound(new MTPDcontactFound(_user_id)); +} + +inline MTPcontactSuggested::MTPcontactSuggested() : mtpDataOwner(new MTPDcontactSuggested()) { +} + +inline uint32 MTPcontactSuggested::size() const { + const MTPDcontactSuggested &v(c_contactSuggested()); + return v.vuser_id.size() + v.vmutual_contacts.size(); +} +inline mtpTypeId MTPcontactSuggested::type() const { + return mtpc_contactSuggested; +} +inline void MTPcontactSuggested::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_contactSuggested) throw mtpErrorUnexpected(cons, "MTPcontactSuggested"); + + if (!data) setData(new MTPDcontactSuggested()); + MTPDcontactSuggested &v(_contactSuggested()); + v.vuser_id.read(from, end); + v.vmutual_contacts.read(from, end); +} +inline void MTPcontactSuggested::write(mtpBuffer &to) const { + const MTPDcontactSuggested &v(c_contactSuggested()); + v.vuser_id.write(to); + v.vmutual_contacts.write(to); +} +inline MTPcontactSuggested::MTPcontactSuggested(MTPDcontactSuggested *_data) : mtpDataOwner(_data) { +} +inline MTPcontactSuggested MTP_contactSuggested(MTPint _user_id, MTPint _mutual_contacts) { + return MTPcontactSuggested(new MTPDcontactSuggested(_user_id, _mutual_contacts)); +} + +inline MTPcontactStatus::MTPcontactStatus() : mtpDataOwner(new MTPDcontactStatus()) { +} + +inline uint32 MTPcontactStatus::size() const { + const MTPDcontactStatus &v(c_contactStatus()); + return v.vuser_id.size() + v.vexpires.size(); +} +inline mtpTypeId MTPcontactStatus::type() const { + return mtpc_contactStatus; +} +inline void MTPcontactStatus::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_contactStatus) throw mtpErrorUnexpected(cons, "MTPcontactStatus"); + + if (!data) setData(new MTPDcontactStatus()); + MTPDcontactStatus &v(_contactStatus()); + v.vuser_id.read(from, end); + v.vexpires.read(from, end); +} +inline void MTPcontactStatus::write(mtpBuffer &to) const { + const MTPDcontactStatus &v(c_contactStatus()); + v.vuser_id.write(to); + v.vexpires.write(to); +} +inline MTPcontactStatus::MTPcontactStatus(MTPDcontactStatus *_data) : mtpDataOwner(_data) { +} +inline MTPcontactStatus MTP_contactStatus(MTPint _user_id, MTPint _expires) { + return MTPcontactStatus(new MTPDcontactStatus(_user_id, _expires)); +} + +inline MTPchatLocated::MTPchatLocated() : mtpDataOwner(new MTPDchatLocated()) { +} + +inline uint32 MTPchatLocated::size() const { + const MTPDchatLocated &v(c_chatLocated()); + return v.vchat_id.size() + v.vdistance.size(); +} +inline mtpTypeId MTPchatLocated::type() const { + return mtpc_chatLocated; +} +inline void MTPchatLocated::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_chatLocated) throw mtpErrorUnexpected(cons, "MTPchatLocated"); + + if (!data) setData(new MTPDchatLocated()); + MTPDchatLocated &v(_chatLocated()); + v.vchat_id.read(from, end); + v.vdistance.read(from, end); +} +inline void MTPchatLocated::write(mtpBuffer &to) const { + const MTPDchatLocated &v(c_chatLocated()); + v.vchat_id.write(to); + v.vdistance.write(to); +} +inline MTPchatLocated::MTPchatLocated(MTPDchatLocated *_data) : mtpDataOwner(_data) { +} +inline MTPchatLocated MTP_chatLocated(MTPint _chat_id, MTPint _distance) { + return MTPchatLocated(new MTPDchatLocated(_chat_id, _distance)); +} + +inline uint32 MTPcontacts_foreignLink::size() const { + switch (_type) { + case mtpc_contacts_foreignLinkRequested: { + const MTPDcontacts_foreignLinkRequested &v(c_contacts_foreignLinkRequested()); + return v.vhas_phone.size(); + } + } + return 0; +} +inline mtpTypeId MTPcontacts_foreignLink::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPcontacts_foreignLink::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_contacts_foreignLinkUnknown: _type = cons; break; + case mtpc_contacts_foreignLinkRequested: _type = cons; { + if (!data) setData(new MTPDcontacts_foreignLinkRequested()); + MTPDcontacts_foreignLinkRequested &v(_contacts_foreignLinkRequested()); + v.vhas_phone.read(from, end); + } break; + case mtpc_contacts_foreignLinkMutual: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPcontacts_foreignLink"); + } +} +inline void MTPcontacts_foreignLink::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_contacts_foreignLinkRequested: { + const MTPDcontacts_foreignLinkRequested &v(c_contacts_foreignLinkRequested()); + v.vhas_phone.write(to); + } break; + } +} +inline MTPcontacts_foreignLink::MTPcontacts_foreignLink(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_contacts_foreignLinkUnknown: break; + case mtpc_contacts_foreignLinkRequested: setData(new MTPDcontacts_foreignLinkRequested()); break; + case mtpc_contacts_foreignLinkMutual: break; + default: throw mtpErrorBadTypeId(type, "MTPcontacts_foreignLink"); + } +} +inline MTPcontacts_foreignLink::MTPcontacts_foreignLink(MTPDcontacts_foreignLinkRequested *_data) : _type(mtpc_contacts_foreignLinkRequested), mtpDataOwner(_data) { +} +inline MTPcontacts_foreignLink MTP_contacts_foreignLinkUnknown() { + return MTPcontacts_foreignLink(mtpc_contacts_foreignLinkUnknown); +} +inline MTPcontacts_foreignLink MTP_contacts_foreignLinkRequested(MTPBool _has_phone) { + return MTPcontacts_foreignLink(new MTPDcontacts_foreignLinkRequested(_has_phone)); +} +inline MTPcontacts_foreignLink MTP_contacts_foreignLinkMutual() { + return MTPcontacts_foreignLink(mtpc_contacts_foreignLinkMutual); +} + +inline uint32 MTPcontacts_myLink::size() const { + switch (_type) { + case mtpc_contacts_myLinkRequested: { + const MTPDcontacts_myLinkRequested &v(c_contacts_myLinkRequested()); + return v.vcontact.size(); + } + } + return 0; +} +inline mtpTypeId MTPcontacts_myLink::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPcontacts_myLink::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_contacts_myLinkEmpty: _type = cons; break; + case mtpc_contacts_myLinkRequested: _type = cons; { + if (!data) setData(new MTPDcontacts_myLinkRequested()); + MTPDcontacts_myLinkRequested &v(_contacts_myLinkRequested()); + v.vcontact.read(from, end); + } break; + case mtpc_contacts_myLinkContact: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPcontacts_myLink"); + } +} +inline void MTPcontacts_myLink::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_contacts_myLinkRequested: { + const MTPDcontacts_myLinkRequested &v(c_contacts_myLinkRequested()); + v.vcontact.write(to); + } break; + } +} +inline MTPcontacts_myLink::MTPcontacts_myLink(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_contacts_myLinkEmpty: break; + case mtpc_contacts_myLinkRequested: setData(new MTPDcontacts_myLinkRequested()); break; + case mtpc_contacts_myLinkContact: break; + default: throw mtpErrorBadTypeId(type, "MTPcontacts_myLink"); + } +} +inline MTPcontacts_myLink::MTPcontacts_myLink(MTPDcontacts_myLinkRequested *_data) : _type(mtpc_contacts_myLinkRequested), mtpDataOwner(_data) { +} +inline MTPcontacts_myLink MTP_contacts_myLinkEmpty() { + return MTPcontacts_myLink(mtpc_contacts_myLinkEmpty); +} +inline MTPcontacts_myLink MTP_contacts_myLinkRequested(MTPBool _contact) { + return MTPcontacts_myLink(new MTPDcontacts_myLinkRequested(_contact)); +} +inline MTPcontacts_myLink MTP_contacts_myLinkContact() { + return MTPcontacts_myLink(mtpc_contacts_myLinkContact); +} + +inline MTPcontacts_link::MTPcontacts_link() : mtpDataOwner(new MTPDcontacts_link()) { +} + +inline uint32 MTPcontacts_link::size() const { + const MTPDcontacts_link &v(c_contacts_link()); + return v.vmy_link.size() + v.vforeign_link.size() + v.vuser.size(); +} +inline mtpTypeId MTPcontacts_link::type() const { + return mtpc_contacts_link; +} +inline void MTPcontacts_link::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_contacts_link) throw mtpErrorUnexpected(cons, "MTPcontacts_link"); + + if (!data) setData(new MTPDcontacts_link()); + MTPDcontacts_link &v(_contacts_link()); + v.vmy_link.read(from, end); + v.vforeign_link.read(from, end); + v.vuser.read(from, end); +} +inline void MTPcontacts_link::write(mtpBuffer &to) const { + const MTPDcontacts_link &v(c_contacts_link()); + v.vmy_link.write(to); + v.vforeign_link.write(to); + v.vuser.write(to); +} +inline MTPcontacts_link::MTPcontacts_link(MTPDcontacts_link *_data) : mtpDataOwner(_data) { +} +inline MTPcontacts_link MTP_contacts_link(const MTPcontacts_MyLink &_my_link, const MTPcontacts_ForeignLink &_foreign_link, const MTPUser &_user) { + return MTPcontacts_link(new MTPDcontacts_link(_my_link, _foreign_link, _user)); +} + +inline uint32 MTPcontacts_contacts::size() const { + switch (_type) { + case mtpc_contacts_contacts: { + const MTPDcontacts_contacts &v(c_contacts_contacts()); + return v.vcontacts.size() + v.vusers.size(); + } + } + return 0; +} +inline mtpTypeId MTPcontacts_contacts::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPcontacts_contacts::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_contacts_contacts: _type = cons; { + if (!data) setData(new MTPDcontacts_contacts()); + MTPDcontacts_contacts &v(_contacts_contacts()); + v.vcontacts.read(from, end); + v.vusers.read(from, end); + } break; + case mtpc_contacts_contactsNotModified: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPcontacts_contacts"); + } +} +inline void MTPcontacts_contacts::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_contacts_contacts: { + const MTPDcontacts_contacts &v(c_contacts_contacts()); + v.vcontacts.write(to); + v.vusers.write(to); + } break; + } +} +inline MTPcontacts_contacts::MTPcontacts_contacts(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_contacts_contacts: setData(new MTPDcontacts_contacts()); break; + case mtpc_contacts_contactsNotModified: break; + default: throw mtpErrorBadTypeId(type, "MTPcontacts_contacts"); + } +} +inline MTPcontacts_contacts::MTPcontacts_contacts(MTPDcontacts_contacts *_data) : _type(mtpc_contacts_contacts), mtpDataOwner(_data) { +} +inline MTPcontacts_contacts MTP_contacts_contacts(const MTPVector &_contacts, const MTPVector &_users) { + return MTPcontacts_contacts(new MTPDcontacts_contacts(_contacts, _users)); +} +inline MTPcontacts_contacts MTP_contacts_contactsNotModified() { + return MTPcontacts_contacts(mtpc_contacts_contactsNotModified); +} + +inline MTPcontacts_importedContacts::MTPcontacts_importedContacts() : mtpDataOwner(new MTPDcontacts_importedContacts()) { +} + +inline uint32 MTPcontacts_importedContacts::size() const { + const MTPDcontacts_importedContacts &v(c_contacts_importedContacts()); + return v.vimported.size() + v.vretry_contacts.size() + v.vusers.size(); +} +inline mtpTypeId MTPcontacts_importedContacts::type() const { + return mtpc_contacts_importedContacts; +} +inline void MTPcontacts_importedContacts::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_contacts_importedContacts) throw mtpErrorUnexpected(cons, "MTPcontacts_importedContacts"); + + if (!data) setData(new MTPDcontacts_importedContacts()); + MTPDcontacts_importedContacts &v(_contacts_importedContacts()); + v.vimported.read(from, end); + v.vretry_contacts.read(from, end); + v.vusers.read(from, end); +} +inline void MTPcontacts_importedContacts::write(mtpBuffer &to) const { + const MTPDcontacts_importedContacts &v(c_contacts_importedContacts()); + v.vimported.write(to); + v.vretry_contacts.write(to); + v.vusers.write(to); +} +inline MTPcontacts_importedContacts::MTPcontacts_importedContacts(MTPDcontacts_importedContacts *_data) : mtpDataOwner(_data) { +} +inline MTPcontacts_importedContacts MTP_contacts_importedContacts(const MTPVector &_imported, const MTPVector &_retry_contacts, const MTPVector &_users) { + return MTPcontacts_importedContacts(new MTPDcontacts_importedContacts(_imported, _retry_contacts, _users)); +} + +inline uint32 MTPcontacts_blocked::size() const { + switch (_type) { + case mtpc_contacts_blocked: { + const MTPDcontacts_blocked &v(c_contacts_blocked()); + return v.vblocked.size() + v.vusers.size(); + } + case mtpc_contacts_blockedSlice: { + const MTPDcontacts_blockedSlice &v(c_contacts_blockedSlice()); + return v.vcount.size() + v.vblocked.size() + v.vusers.size(); + } + } + return 0; +} +inline mtpTypeId MTPcontacts_blocked::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPcontacts_blocked::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_contacts_blocked: _type = cons; { + if (!data) setData(new MTPDcontacts_blocked()); + MTPDcontacts_blocked &v(_contacts_blocked()); + v.vblocked.read(from, end); + v.vusers.read(from, end); + } break; + case mtpc_contacts_blockedSlice: _type = cons; { + if (!data) setData(new MTPDcontacts_blockedSlice()); + MTPDcontacts_blockedSlice &v(_contacts_blockedSlice()); + v.vcount.read(from, end); + v.vblocked.read(from, end); + v.vusers.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPcontacts_blocked"); + } +} +inline void MTPcontacts_blocked::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_contacts_blocked: { + const MTPDcontacts_blocked &v(c_contacts_blocked()); + v.vblocked.write(to); + v.vusers.write(to); + } break; + case mtpc_contacts_blockedSlice: { + const MTPDcontacts_blockedSlice &v(c_contacts_blockedSlice()); + v.vcount.write(to); + v.vblocked.write(to); + v.vusers.write(to); + } break; + } +} +inline MTPcontacts_blocked::MTPcontacts_blocked(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_contacts_blocked: setData(new MTPDcontacts_blocked()); break; + case mtpc_contacts_blockedSlice: setData(new MTPDcontacts_blockedSlice()); break; + default: throw mtpErrorBadTypeId(type, "MTPcontacts_blocked"); + } +} +inline MTPcontacts_blocked::MTPcontacts_blocked(MTPDcontacts_blocked *_data) : _type(mtpc_contacts_blocked), mtpDataOwner(_data) { +} +inline MTPcontacts_blocked::MTPcontacts_blocked(MTPDcontacts_blockedSlice *_data) : _type(mtpc_contacts_blockedSlice), mtpDataOwner(_data) { +} +inline MTPcontacts_blocked MTP_contacts_blocked(const MTPVector &_blocked, const MTPVector &_users) { + return MTPcontacts_blocked(new MTPDcontacts_blocked(_blocked, _users)); +} +inline MTPcontacts_blocked MTP_contacts_blockedSlice(MTPint _count, const MTPVector &_blocked, const MTPVector &_users) { + return MTPcontacts_blocked(new MTPDcontacts_blockedSlice(_count, _blocked, _users)); +} + +inline MTPcontacts_found::MTPcontacts_found() : mtpDataOwner(new MTPDcontacts_found()) { +} + +inline uint32 MTPcontacts_found::size() const { + const MTPDcontacts_found &v(c_contacts_found()); + return v.vresults.size() + v.vusers.size(); +} +inline mtpTypeId MTPcontacts_found::type() const { + return mtpc_contacts_found; +} +inline void MTPcontacts_found::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_contacts_found) throw mtpErrorUnexpected(cons, "MTPcontacts_found"); + + if (!data) setData(new MTPDcontacts_found()); + MTPDcontacts_found &v(_contacts_found()); + v.vresults.read(from, end); + v.vusers.read(from, end); +} +inline void MTPcontacts_found::write(mtpBuffer &to) const { + const MTPDcontacts_found &v(c_contacts_found()); + v.vresults.write(to); + v.vusers.write(to); +} +inline MTPcontacts_found::MTPcontacts_found(MTPDcontacts_found *_data) : mtpDataOwner(_data) { +} +inline MTPcontacts_found MTP_contacts_found(const MTPVector &_results, const MTPVector &_users) { + return MTPcontacts_found(new MTPDcontacts_found(_results, _users)); +} + +inline MTPcontacts_suggested::MTPcontacts_suggested() : mtpDataOwner(new MTPDcontacts_suggested()) { +} + +inline uint32 MTPcontacts_suggested::size() const { + const MTPDcontacts_suggested &v(c_contacts_suggested()); + return v.vresults.size() + v.vusers.size(); +} +inline mtpTypeId MTPcontacts_suggested::type() const { + return mtpc_contacts_suggested; +} +inline void MTPcontacts_suggested::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_contacts_suggested) throw mtpErrorUnexpected(cons, "MTPcontacts_suggested"); + + if (!data) setData(new MTPDcontacts_suggested()); + MTPDcontacts_suggested &v(_contacts_suggested()); + v.vresults.read(from, end); + v.vusers.read(from, end); +} +inline void MTPcontacts_suggested::write(mtpBuffer &to) const { + const MTPDcontacts_suggested &v(c_contacts_suggested()); + v.vresults.write(to); + v.vusers.write(to); +} +inline MTPcontacts_suggested::MTPcontacts_suggested(MTPDcontacts_suggested *_data) : mtpDataOwner(_data) { +} +inline MTPcontacts_suggested MTP_contacts_suggested(const MTPVector &_results, const MTPVector &_users) { + return MTPcontacts_suggested(new MTPDcontacts_suggested(_results, _users)); +} + +inline uint32 MTPmessages_dialogs::size() const { + switch (_type) { + case mtpc_messages_dialogs: { + const MTPDmessages_dialogs &v(c_messages_dialogs()); + return v.vdialogs.size() + v.vmessages.size() + v.vchats.size() + v.vusers.size(); + } + case mtpc_messages_dialogsSlice: { + const MTPDmessages_dialogsSlice &v(c_messages_dialogsSlice()); + return v.vcount.size() + v.vdialogs.size() + v.vmessages.size() + v.vchats.size() + v.vusers.size(); + } + } + return 0; +} +inline mtpTypeId MTPmessages_dialogs::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessages_dialogs::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messages_dialogs: _type = cons; { + if (!data) setData(new MTPDmessages_dialogs()); + MTPDmessages_dialogs &v(_messages_dialogs()); + v.vdialogs.read(from, end); + v.vmessages.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + } break; + case mtpc_messages_dialogsSlice: _type = cons; { + if (!data) setData(new MTPDmessages_dialogsSlice()); + MTPDmessages_dialogsSlice &v(_messages_dialogsSlice()); + v.vcount.read(from, end); + v.vdialogs.read(from, end); + v.vmessages.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessages_dialogs"); + } +} +inline void MTPmessages_dialogs::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messages_dialogs: { + const MTPDmessages_dialogs &v(c_messages_dialogs()); + v.vdialogs.write(to); + v.vmessages.write(to); + v.vchats.write(to); + v.vusers.write(to); + } break; + case mtpc_messages_dialogsSlice: { + const MTPDmessages_dialogsSlice &v(c_messages_dialogsSlice()); + v.vcount.write(to); + v.vdialogs.write(to); + v.vmessages.write(to); + v.vchats.write(to); + v.vusers.write(to); + } break; + } +} +inline MTPmessages_dialogs::MTPmessages_dialogs(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_messages_dialogs: setData(new MTPDmessages_dialogs()); break; + case mtpc_messages_dialogsSlice: setData(new MTPDmessages_dialogsSlice()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessages_dialogs"); + } +} +inline MTPmessages_dialogs::MTPmessages_dialogs(MTPDmessages_dialogs *_data) : _type(mtpc_messages_dialogs), mtpDataOwner(_data) { +} +inline MTPmessages_dialogs::MTPmessages_dialogs(MTPDmessages_dialogsSlice *_data) : _type(mtpc_messages_dialogsSlice), mtpDataOwner(_data) { +} +inline MTPmessages_dialogs MTP_messages_dialogs(const MTPVector &_dialogs, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) { + return MTPmessages_dialogs(new MTPDmessages_dialogs(_dialogs, _messages, _chats, _users)); +} +inline MTPmessages_dialogs MTP_messages_dialogsSlice(MTPint _count, const MTPVector &_dialogs, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) { + return MTPmessages_dialogs(new MTPDmessages_dialogsSlice(_count, _dialogs, _messages, _chats, _users)); +} + +inline uint32 MTPmessages_messages::size() const { + switch (_type) { + case mtpc_messages_messages: { + const MTPDmessages_messages &v(c_messages_messages()); + return v.vmessages.size() + v.vchats.size() + v.vusers.size(); + } + case mtpc_messages_messagesSlice: { + const MTPDmessages_messagesSlice &v(c_messages_messagesSlice()); + return v.vcount.size() + v.vmessages.size() + v.vchats.size() + v.vusers.size(); + } + } + return 0; +} +inline mtpTypeId MTPmessages_messages::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessages_messages::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messages_messages: _type = cons; { + if (!data) setData(new MTPDmessages_messages()); + MTPDmessages_messages &v(_messages_messages()); + v.vmessages.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + } break; + case mtpc_messages_messagesSlice: _type = cons; { + if (!data) setData(new MTPDmessages_messagesSlice()); + MTPDmessages_messagesSlice &v(_messages_messagesSlice()); + v.vcount.read(from, end); + v.vmessages.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessages_messages"); + } +} +inline void MTPmessages_messages::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messages_messages: { + const MTPDmessages_messages &v(c_messages_messages()); + v.vmessages.write(to); + v.vchats.write(to); + v.vusers.write(to); + } break; + case mtpc_messages_messagesSlice: { + const MTPDmessages_messagesSlice &v(c_messages_messagesSlice()); + v.vcount.write(to); + v.vmessages.write(to); + v.vchats.write(to); + v.vusers.write(to); + } break; + } +} +inline MTPmessages_messages::MTPmessages_messages(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_messages_messages: setData(new MTPDmessages_messages()); break; + case mtpc_messages_messagesSlice: setData(new MTPDmessages_messagesSlice()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessages_messages"); + } +} +inline MTPmessages_messages::MTPmessages_messages(MTPDmessages_messages *_data) : _type(mtpc_messages_messages), mtpDataOwner(_data) { +} +inline MTPmessages_messages::MTPmessages_messages(MTPDmessages_messagesSlice *_data) : _type(mtpc_messages_messagesSlice), mtpDataOwner(_data) { +} +inline MTPmessages_messages MTP_messages_messages(const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) { + return MTPmessages_messages(new MTPDmessages_messages(_messages, _chats, _users)); +} +inline MTPmessages_messages MTP_messages_messagesSlice(MTPint _count, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) { + return MTPmessages_messages(new MTPDmessages_messagesSlice(_count, _messages, _chats, _users)); +} + +inline uint32 MTPmessages_message::size() const { + switch (_type) { + case mtpc_messages_message: { + const MTPDmessages_message &v(c_messages_message()); + return v.vmessage.size() + v.vchats.size() + v.vusers.size(); + } + } + return 0; +} +inline mtpTypeId MTPmessages_message::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessages_message::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messages_messageEmpty: _type = cons; break; + case mtpc_messages_message: _type = cons; { + if (!data) setData(new MTPDmessages_message()); + MTPDmessages_message &v(_messages_message()); + v.vmessage.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessages_message"); + } +} +inline void MTPmessages_message::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messages_message: { + const MTPDmessages_message &v(c_messages_message()); + v.vmessage.write(to); + v.vchats.write(to); + v.vusers.write(to); + } break; + } +} +inline MTPmessages_message::MTPmessages_message(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_messages_messageEmpty: break; + case mtpc_messages_message: setData(new MTPDmessages_message()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessages_message"); + } +} +inline MTPmessages_message::MTPmessages_message(MTPDmessages_message *_data) : _type(mtpc_messages_message), mtpDataOwner(_data) { +} +inline MTPmessages_message MTP_messages_messageEmpty() { + return MTPmessages_message(mtpc_messages_messageEmpty); +} +inline MTPmessages_message MTP_messages_message(const MTPMessage &_message, const MTPVector &_chats, const MTPVector &_users) { + return MTPmessages_message(new MTPDmessages_message(_message, _chats, _users)); +} + +inline uint32 MTPmessages_statedMessages::size() const { + switch (_type) { + case mtpc_messages_statedMessages: { + const MTPDmessages_statedMessages &v(c_messages_statedMessages()); + return v.vmessages.size() + v.vchats.size() + v.vusers.size() + v.vpts.size() + v.vseq.size(); + } + case mtpc_messages_statedMessagesLinks: { + const MTPDmessages_statedMessagesLinks &v(c_messages_statedMessagesLinks()); + return v.vmessages.size() + v.vchats.size() + v.vusers.size() + v.vlinks.size() + v.vpts.size() + v.vseq.size(); + } + } + return 0; +} +inline mtpTypeId MTPmessages_statedMessages::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessages_statedMessages::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messages_statedMessages: _type = cons; { + if (!data) setData(new MTPDmessages_statedMessages()); + MTPDmessages_statedMessages &v(_messages_statedMessages()); + v.vmessages.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + v.vpts.read(from, end); + v.vseq.read(from, end); + } break; + case mtpc_messages_statedMessagesLinks: _type = cons; { + if (!data) setData(new MTPDmessages_statedMessagesLinks()); + MTPDmessages_statedMessagesLinks &v(_messages_statedMessagesLinks()); + v.vmessages.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + v.vlinks.read(from, end); + v.vpts.read(from, end); + v.vseq.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessages_statedMessages"); + } +} +inline void MTPmessages_statedMessages::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messages_statedMessages: { + const MTPDmessages_statedMessages &v(c_messages_statedMessages()); + v.vmessages.write(to); + v.vchats.write(to); + v.vusers.write(to); + v.vpts.write(to); + v.vseq.write(to); + } break; + case mtpc_messages_statedMessagesLinks: { + const MTPDmessages_statedMessagesLinks &v(c_messages_statedMessagesLinks()); + v.vmessages.write(to); + v.vchats.write(to); + v.vusers.write(to); + v.vlinks.write(to); + v.vpts.write(to); + v.vseq.write(to); + } break; + } +} +inline MTPmessages_statedMessages::MTPmessages_statedMessages(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_messages_statedMessages: setData(new MTPDmessages_statedMessages()); break; + case mtpc_messages_statedMessagesLinks: setData(new MTPDmessages_statedMessagesLinks()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessages_statedMessages"); + } +} +inline MTPmessages_statedMessages::MTPmessages_statedMessages(MTPDmessages_statedMessages *_data) : _type(mtpc_messages_statedMessages), mtpDataOwner(_data) { +} +inline MTPmessages_statedMessages::MTPmessages_statedMessages(MTPDmessages_statedMessagesLinks *_data) : _type(mtpc_messages_statedMessagesLinks), mtpDataOwner(_data) { +} +inline MTPmessages_statedMessages MTP_messages_statedMessages(const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users, MTPint _pts, MTPint _seq) { + return MTPmessages_statedMessages(new MTPDmessages_statedMessages(_messages, _chats, _users, _pts, _seq)); +} +inline MTPmessages_statedMessages MTP_messages_statedMessagesLinks(const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users, const MTPVector &_links, MTPint _pts, MTPint _seq) { + return MTPmessages_statedMessages(new MTPDmessages_statedMessagesLinks(_messages, _chats, _users, _links, _pts, _seq)); +} + +inline uint32 MTPmessages_statedMessage::size() const { + switch (_type) { + case mtpc_messages_statedMessage: { + const MTPDmessages_statedMessage &v(c_messages_statedMessage()); + return v.vmessage.size() + v.vchats.size() + v.vusers.size() + v.vpts.size() + v.vseq.size(); + } + case mtpc_messages_statedMessageLink: { + const MTPDmessages_statedMessageLink &v(c_messages_statedMessageLink()); + return v.vmessage.size() + v.vchats.size() + v.vusers.size() + v.vlinks.size() + v.vpts.size() + v.vseq.size(); + } + } + return 0; +} +inline mtpTypeId MTPmessages_statedMessage::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessages_statedMessage::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messages_statedMessage: _type = cons; { + if (!data) setData(new MTPDmessages_statedMessage()); + MTPDmessages_statedMessage &v(_messages_statedMessage()); + v.vmessage.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + v.vpts.read(from, end); + v.vseq.read(from, end); + } break; + case mtpc_messages_statedMessageLink: _type = cons; { + if (!data) setData(new MTPDmessages_statedMessageLink()); + MTPDmessages_statedMessageLink &v(_messages_statedMessageLink()); + v.vmessage.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + v.vlinks.read(from, end); + v.vpts.read(from, end); + v.vseq.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessages_statedMessage"); + } +} +inline void MTPmessages_statedMessage::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messages_statedMessage: { + const MTPDmessages_statedMessage &v(c_messages_statedMessage()); + v.vmessage.write(to); + v.vchats.write(to); + v.vusers.write(to); + v.vpts.write(to); + v.vseq.write(to); + } break; + case mtpc_messages_statedMessageLink: { + const MTPDmessages_statedMessageLink &v(c_messages_statedMessageLink()); + v.vmessage.write(to); + v.vchats.write(to); + v.vusers.write(to); + v.vlinks.write(to); + v.vpts.write(to); + v.vseq.write(to); + } break; + } +} +inline MTPmessages_statedMessage::MTPmessages_statedMessage(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_messages_statedMessage: setData(new MTPDmessages_statedMessage()); break; + case mtpc_messages_statedMessageLink: setData(new MTPDmessages_statedMessageLink()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessages_statedMessage"); + } +} +inline MTPmessages_statedMessage::MTPmessages_statedMessage(MTPDmessages_statedMessage *_data) : _type(mtpc_messages_statedMessage), mtpDataOwner(_data) { +} +inline MTPmessages_statedMessage::MTPmessages_statedMessage(MTPDmessages_statedMessageLink *_data) : _type(mtpc_messages_statedMessageLink), mtpDataOwner(_data) { +} +inline MTPmessages_statedMessage MTP_messages_statedMessage(const MTPMessage &_message, const MTPVector &_chats, const MTPVector &_users, MTPint _pts, MTPint _seq) { + return MTPmessages_statedMessage(new MTPDmessages_statedMessage(_message, _chats, _users, _pts, _seq)); +} +inline MTPmessages_statedMessage MTP_messages_statedMessageLink(const MTPMessage &_message, const MTPVector &_chats, const MTPVector &_users, const MTPVector &_links, MTPint _pts, MTPint _seq) { + return MTPmessages_statedMessage(new MTPDmessages_statedMessageLink(_message, _chats, _users, _links, _pts, _seq)); +} + +inline uint32 MTPmessages_sentMessage::size() const { + switch (_type) { + case mtpc_messages_sentMessage: { + const MTPDmessages_sentMessage &v(c_messages_sentMessage()); + return v.vid.size() + v.vdate.size() + v.vpts.size() + v.vseq.size(); + } + case mtpc_messages_sentMessageLink: { + const MTPDmessages_sentMessageLink &v(c_messages_sentMessageLink()); + return v.vid.size() + v.vdate.size() + v.vpts.size() + v.vseq.size() + v.vlinks.size(); + } + } + return 0; +} +inline mtpTypeId MTPmessages_sentMessage::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessages_sentMessage::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messages_sentMessage: _type = cons; { + if (!data) setData(new MTPDmessages_sentMessage()); + MTPDmessages_sentMessage &v(_messages_sentMessage()); + v.vid.read(from, end); + v.vdate.read(from, end); + v.vpts.read(from, end); + v.vseq.read(from, end); + } break; + case mtpc_messages_sentMessageLink: _type = cons; { + if (!data) setData(new MTPDmessages_sentMessageLink()); + MTPDmessages_sentMessageLink &v(_messages_sentMessageLink()); + v.vid.read(from, end); + v.vdate.read(from, end); + v.vpts.read(from, end); + v.vseq.read(from, end); + v.vlinks.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessages_sentMessage"); + } +} +inline void MTPmessages_sentMessage::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messages_sentMessage: { + const MTPDmessages_sentMessage &v(c_messages_sentMessage()); + v.vid.write(to); + v.vdate.write(to); + v.vpts.write(to); + v.vseq.write(to); + } break; + case mtpc_messages_sentMessageLink: { + const MTPDmessages_sentMessageLink &v(c_messages_sentMessageLink()); + v.vid.write(to); + v.vdate.write(to); + v.vpts.write(to); + v.vseq.write(to); + v.vlinks.write(to); + } break; + } +} +inline MTPmessages_sentMessage::MTPmessages_sentMessage(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_messages_sentMessage: setData(new MTPDmessages_sentMessage()); break; + case mtpc_messages_sentMessageLink: setData(new MTPDmessages_sentMessageLink()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessages_sentMessage"); + } +} +inline MTPmessages_sentMessage::MTPmessages_sentMessage(MTPDmessages_sentMessage *_data) : _type(mtpc_messages_sentMessage), mtpDataOwner(_data) { +} +inline MTPmessages_sentMessage::MTPmessages_sentMessage(MTPDmessages_sentMessageLink *_data) : _type(mtpc_messages_sentMessageLink), mtpDataOwner(_data) { +} +inline MTPmessages_sentMessage MTP_messages_sentMessage(MTPint _id, MTPint _date, MTPint _pts, MTPint _seq) { + return MTPmessages_sentMessage(new MTPDmessages_sentMessage(_id, _date, _pts, _seq)); +} +inline MTPmessages_sentMessage MTP_messages_sentMessageLink(MTPint _id, MTPint _date, MTPint _pts, MTPint _seq, const MTPVector &_links) { + return MTPmessages_sentMessage(new MTPDmessages_sentMessageLink(_id, _date, _pts, _seq, _links)); +} + +inline MTPmessages_chat::MTPmessages_chat() : mtpDataOwner(new MTPDmessages_chat()) { +} + +inline uint32 MTPmessages_chat::size() const { + const MTPDmessages_chat &v(c_messages_chat()); + return v.vchat.size() + v.vusers.size(); +} +inline mtpTypeId MTPmessages_chat::type() const { + return mtpc_messages_chat; +} +inline void MTPmessages_chat::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_messages_chat) throw mtpErrorUnexpected(cons, "MTPmessages_chat"); + + if (!data) setData(new MTPDmessages_chat()); + MTPDmessages_chat &v(_messages_chat()); + v.vchat.read(from, end); + v.vusers.read(from, end); +} +inline void MTPmessages_chat::write(mtpBuffer &to) const { + const MTPDmessages_chat &v(c_messages_chat()); + v.vchat.write(to); + v.vusers.write(to); +} +inline MTPmessages_chat::MTPmessages_chat(MTPDmessages_chat *_data) : mtpDataOwner(_data) { +} +inline MTPmessages_chat MTP_messages_chat(const MTPChat &_chat, const MTPVector &_users) { + return MTPmessages_chat(new MTPDmessages_chat(_chat, _users)); +} + +inline MTPmessages_chats::MTPmessages_chats() : mtpDataOwner(new MTPDmessages_chats()) { +} + +inline uint32 MTPmessages_chats::size() const { + const MTPDmessages_chats &v(c_messages_chats()); + return v.vchats.size() + v.vusers.size(); +} +inline mtpTypeId MTPmessages_chats::type() const { + return mtpc_messages_chats; +} +inline void MTPmessages_chats::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_messages_chats) throw mtpErrorUnexpected(cons, "MTPmessages_chats"); + + if (!data) setData(new MTPDmessages_chats()); + MTPDmessages_chats &v(_messages_chats()); + v.vchats.read(from, end); + v.vusers.read(from, end); +} +inline void MTPmessages_chats::write(mtpBuffer &to) const { + const MTPDmessages_chats &v(c_messages_chats()); + v.vchats.write(to); + v.vusers.write(to); +} +inline MTPmessages_chats::MTPmessages_chats(MTPDmessages_chats *_data) : mtpDataOwner(_data) { +} +inline MTPmessages_chats MTP_messages_chats(const MTPVector &_chats, const MTPVector &_users) { + return MTPmessages_chats(new MTPDmessages_chats(_chats, _users)); +} + +inline MTPmessages_chatFull::MTPmessages_chatFull() : mtpDataOwner(new MTPDmessages_chatFull()) { +} + +inline uint32 MTPmessages_chatFull::size() const { + const MTPDmessages_chatFull &v(c_messages_chatFull()); + return v.vfull_chat.size() + v.vchats.size() + v.vusers.size(); +} +inline mtpTypeId MTPmessages_chatFull::type() const { + return mtpc_messages_chatFull; +} +inline void MTPmessages_chatFull::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_messages_chatFull) throw mtpErrorUnexpected(cons, "MTPmessages_chatFull"); + + if (!data) setData(new MTPDmessages_chatFull()); + MTPDmessages_chatFull &v(_messages_chatFull()); + v.vfull_chat.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); +} +inline void MTPmessages_chatFull::write(mtpBuffer &to) const { + const MTPDmessages_chatFull &v(c_messages_chatFull()); + v.vfull_chat.write(to); + v.vchats.write(to); + v.vusers.write(to); +} +inline MTPmessages_chatFull::MTPmessages_chatFull(MTPDmessages_chatFull *_data) : mtpDataOwner(_data) { +} +inline MTPmessages_chatFull MTP_messages_chatFull(const MTPChatFull &_full_chat, const MTPVector &_chats, const MTPVector &_users) { + return MTPmessages_chatFull(new MTPDmessages_chatFull(_full_chat, _chats, _users)); +} + +inline MTPmessages_affectedHistory::MTPmessages_affectedHistory() : mtpDataOwner(new MTPDmessages_affectedHistory()) { +} + +inline uint32 MTPmessages_affectedHistory::size() const { + const MTPDmessages_affectedHistory &v(c_messages_affectedHistory()); + return v.vpts.size() + v.vseq.size() + v.voffset.size(); +} +inline mtpTypeId MTPmessages_affectedHistory::type() const { + return mtpc_messages_affectedHistory; +} +inline void MTPmessages_affectedHistory::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_messages_affectedHistory) throw mtpErrorUnexpected(cons, "MTPmessages_affectedHistory"); + + if (!data) setData(new MTPDmessages_affectedHistory()); + MTPDmessages_affectedHistory &v(_messages_affectedHistory()); + v.vpts.read(from, end); + v.vseq.read(from, end); + v.voffset.read(from, end); +} +inline void MTPmessages_affectedHistory::write(mtpBuffer &to) const { + const MTPDmessages_affectedHistory &v(c_messages_affectedHistory()); + v.vpts.write(to); + v.vseq.write(to); + v.voffset.write(to); +} +inline MTPmessages_affectedHistory::MTPmessages_affectedHistory(MTPDmessages_affectedHistory *_data) : mtpDataOwner(_data) { +} +inline MTPmessages_affectedHistory MTP_messages_affectedHistory(MTPint _pts, MTPint _seq, MTPint _offset) { + return MTPmessages_affectedHistory(new MTPDmessages_affectedHistory(_pts, _seq, _offset)); +} + +inline uint32 MTPmessagesFilter::size() const { + return 0; +} +inline mtpTypeId MTPmessagesFilter::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessagesFilter::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + switch (cons) { + case mtpc_inputMessagesFilterEmpty: _type = cons; break; + case mtpc_inputMessagesFilterPhotos: _type = cons; break; + case mtpc_inputMessagesFilterVideo: _type = cons; break; + case mtpc_inputMessagesFilterPhotoVideo: _type = cons; break; + case mtpc_inputMessagesFilterDocument: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPmessagesFilter"); + } +} +inline void MTPmessagesFilter::write(mtpBuffer &to) const { + switch (_type) { + } +} +inline MTPmessagesFilter::MTPmessagesFilter(mtpTypeId type) : _type(type) { + switch (type) { + case mtpc_inputMessagesFilterEmpty: break; + case mtpc_inputMessagesFilterPhotos: break; + case mtpc_inputMessagesFilterVideo: break; + case mtpc_inputMessagesFilterPhotoVideo: break; + case mtpc_inputMessagesFilterDocument: break; + default: throw mtpErrorBadTypeId(type, "MTPmessagesFilter"); + } +} +inline MTPmessagesFilter MTP_inputMessagesFilterEmpty() { + return MTPmessagesFilter(mtpc_inputMessagesFilterEmpty); +} +inline MTPmessagesFilter MTP_inputMessagesFilterPhotos() { + return MTPmessagesFilter(mtpc_inputMessagesFilterPhotos); +} +inline MTPmessagesFilter MTP_inputMessagesFilterVideo() { + return MTPmessagesFilter(mtpc_inputMessagesFilterVideo); +} +inline MTPmessagesFilter MTP_inputMessagesFilterPhotoVideo() { + return MTPmessagesFilter(mtpc_inputMessagesFilterPhotoVideo); +} +inline MTPmessagesFilter MTP_inputMessagesFilterDocument() { + return MTPmessagesFilter(mtpc_inputMessagesFilterDocument); +} + +inline uint32 MTPupdate::size() const { + switch (_type) { + case mtpc_updateNewMessage: { + const MTPDupdateNewMessage &v(c_updateNewMessage()); + return v.vmessage.size() + v.vpts.size(); + } + case mtpc_updateMessageID: { + const MTPDupdateMessageID &v(c_updateMessageID()); + return v.vid.size() + v.vrandom_id.size(); + } + case mtpc_updateReadMessages: { + const MTPDupdateReadMessages &v(c_updateReadMessages()); + return v.vmessages.size() + v.vpts.size(); + } + case mtpc_updateDeleteMessages: { + const MTPDupdateDeleteMessages &v(c_updateDeleteMessages()); + return v.vmessages.size() + v.vpts.size(); + } + case mtpc_updateRestoreMessages: { + const MTPDupdateRestoreMessages &v(c_updateRestoreMessages()); + return v.vmessages.size() + v.vpts.size(); + } + case mtpc_updateUserTyping: { + const MTPDupdateUserTyping &v(c_updateUserTyping()); + return v.vuser_id.size(); + } + case mtpc_updateChatUserTyping: { + const MTPDupdateChatUserTyping &v(c_updateChatUserTyping()); + return v.vchat_id.size() + v.vuser_id.size(); + } + case mtpc_updateChatParticipants: { + const MTPDupdateChatParticipants &v(c_updateChatParticipants()); + return v.vparticipants.size(); + } + case mtpc_updateUserStatus: { + const MTPDupdateUserStatus &v(c_updateUserStatus()); + return v.vuser_id.size() + v.vstatus.size(); + } + case mtpc_updateUserName: { + const MTPDupdateUserName &v(c_updateUserName()); + return v.vuser_id.size() + v.vfirst_name.size() + v.vlast_name.size(); + } + case mtpc_updateUserPhoto: { + const MTPDupdateUserPhoto &v(c_updateUserPhoto()); + return v.vuser_id.size() + v.vdate.size() + v.vphoto.size() + v.vprevious.size(); + } + case mtpc_updateContactRegistered: { + const MTPDupdateContactRegistered &v(c_updateContactRegistered()); + return v.vuser_id.size() + v.vdate.size(); + } + case mtpc_updateContactLink: { + const MTPDupdateContactLink &v(c_updateContactLink()); + return v.vuser_id.size() + v.vmy_link.size() + v.vforeign_link.size(); + } + case mtpc_updateActivation: { + const MTPDupdateActivation &v(c_updateActivation()); + return v.vuser_id.size(); + } + case mtpc_updateNewAuthorization: { + const MTPDupdateNewAuthorization &v(c_updateNewAuthorization()); + return v.vauth_key_id.size() + v.vdate.size() + v.vdevice.size() + v.vlocation.size(); + } + case mtpc_updateNewGeoChatMessage: { + const MTPDupdateNewGeoChatMessage &v(c_updateNewGeoChatMessage()); + return v.vmessage.size(); + } + case mtpc_updateNewEncryptedMessage: { + const MTPDupdateNewEncryptedMessage &v(c_updateNewEncryptedMessage()); + return v.vmessage.size() + v.vqts.size(); + } + case mtpc_updateEncryptedChatTyping: { + const MTPDupdateEncryptedChatTyping &v(c_updateEncryptedChatTyping()); + return v.vchat_id.size(); + } + case mtpc_updateEncryption: { + const MTPDupdateEncryption &v(c_updateEncryption()); + return v.vchat.size() + v.vdate.size(); + } + case mtpc_updateEncryptedMessagesRead: { + const MTPDupdateEncryptedMessagesRead &v(c_updateEncryptedMessagesRead()); + return v.vchat_id.size() + v.vmax_date.size() + v.vdate.size(); + } + case mtpc_updateChatParticipantAdd: { + const MTPDupdateChatParticipantAdd &v(c_updateChatParticipantAdd()); + return v.vchat_id.size() + v.vuser_id.size() + v.vinviter_id.size() + v.vversion.size(); + } + case mtpc_updateChatParticipantDelete: { + const MTPDupdateChatParticipantDelete &v(c_updateChatParticipantDelete()); + return v.vchat_id.size() + v.vuser_id.size() + v.vversion.size(); + } + case mtpc_updateDcOptions: { + const MTPDupdateDcOptions &v(c_updateDcOptions()); + return v.vdc_options.size(); + } + case mtpc_updateUserBlocked: { + const MTPDupdateUserBlocked &v(c_updateUserBlocked()); + return v.vuser_id.size() + v.vblocked.size(); + } + case mtpc_updateNotifySettings: { + const MTPDupdateNotifySettings &v(c_updateNotifySettings()); + return v.vpeer.size() + v.vnotify_settings.size(); + } + } + return 0; +} +inline mtpTypeId MTPupdate::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPupdate::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_updateNewMessage: _type = cons; { + if (!data) setData(new MTPDupdateNewMessage()); + MTPDupdateNewMessage &v(_updateNewMessage()); + v.vmessage.read(from, end); + v.vpts.read(from, end); + } break; + case mtpc_updateMessageID: _type = cons; { + if (!data) setData(new MTPDupdateMessageID()); + MTPDupdateMessageID &v(_updateMessageID()); + v.vid.read(from, end); + v.vrandom_id.read(from, end); + } break; + case mtpc_updateReadMessages: _type = cons; { + if (!data) setData(new MTPDupdateReadMessages()); + MTPDupdateReadMessages &v(_updateReadMessages()); + v.vmessages.read(from, end); + v.vpts.read(from, end); + } break; + case mtpc_updateDeleteMessages: _type = cons; { + if (!data) setData(new MTPDupdateDeleteMessages()); + MTPDupdateDeleteMessages &v(_updateDeleteMessages()); + v.vmessages.read(from, end); + v.vpts.read(from, end); + } break; + case mtpc_updateRestoreMessages: _type = cons; { + if (!data) setData(new MTPDupdateRestoreMessages()); + MTPDupdateRestoreMessages &v(_updateRestoreMessages()); + v.vmessages.read(from, end); + v.vpts.read(from, end); + } break; + case mtpc_updateUserTyping: _type = cons; { + if (!data) setData(new MTPDupdateUserTyping()); + MTPDupdateUserTyping &v(_updateUserTyping()); + v.vuser_id.read(from, end); + } break; + case mtpc_updateChatUserTyping: _type = cons; { + if (!data) setData(new MTPDupdateChatUserTyping()); + MTPDupdateChatUserTyping &v(_updateChatUserTyping()); + v.vchat_id.read(from, end); + v.vuser_id.read(from, end); + } break; + case mtpc_updateChatParticipants: _type = cons; { + if (!data) setData(new MTPDupdateChatParticipants()); + MTPDupdateChatParticipants &v(_updateChatParticipants()); + v.vparticipants.read(from, end); + } break; + case mtpc_updateUserStatus: _type = cons; { + if (!data) setData(new MTPDupdateUserStatus()); + MTPDupdateUserStatus &v(_updateUserStatus()); + v.vuser_id.read(from, end); + v.vstatus.read(from, end); + } break; + case mtpc_updateUserName: _type = cons; { + if (!data) setData(new MTPDupdateUserName()); + MTPDupdateUserName &v(_updateUserName()); + v.vuser_id.read(from, end); + v.vfirst_name.read(from, end); + v.vlast_name.read(from, end); + } break; + case mtpc_updateUserPhoto: _type = cons; { + if (!data) setData(new MTPDupdateUserPhoto()); + MTPDupdateUserPhoto &v(_updateUserPhoto()); + v.vuser_id.read(from, end); + v.vdate.read(from, end); + v.vphoto.read(from, end); + v.vprevious.read(from, end); + } break; + case mtpc_updateContactRegistered: _type = cons; { + if (!data) setData(new MTPDupdateContactRegistered()); + MTPDupdateContactRegistered &v(_updateContactRegistered()); + v.vuser_id.read(from, end); + v.vdate.read(from, end); + } break; + case mtpc_updateContactLink: _type = cons; { + if (!data) setData(new MTPDupdateContactLink()); + MTPDupdateContactLink &v(_updateContactLink()); + v.vuser_id.read(from, end); + v.vmy_link.read(from, end); + v.vforeign_link.read(from, end); + } break; + case mtpc_updateActivation: _type = cons; { + if (!data) setData(new MTPDupdateActivation()); + MTPDupdateActivation &v(_updateActivation()); + v.vuser_id.read(from, end); + } break; + case mtpc_updateNewAuthorization: _type = cons; { + if (!data) setData(new MTPDupdateNewAuthorization()); + MTPDupdateNewAuthorization &v(_updateNewAuthorization()); + v.vauth_key_id.read(from, end); + v.vdate.read(from, end); + v.vdevice.read(from, end); + v.vlocation.read(from, end); + } break; + case mtpc_updateNewGeoChatMessage: _type = cons; { + if (!data) setData(new MTPDupdateNewGeoChatMessage()); + MTPDupdateNewGeoChatMessage &v(_updateNewGeoChatMessage()); + v.vmessage.read(from, end); + } break; + case mtpc_updateNewEncryptedMessage: _type = cons; { + if (!data) setData(new MTPDupdateNewEncryptedMessage()); + MTPDupdateNewEncryptedMessage &v(_updateNewEncryptedMessage()); + v.vmessage.read(from, end); + v.vqts.read(from, end); + } break; + case mtpc_updateEncryptedChatTyping: _type = cons; { + if (!data) setData(new MTPDupdateEncryptedChatTyping()); + MTPDupdateEncryptedChatTyping &v(_updateEncryptedChatTyping()); + v.vchat_id.read(from, end); + } break; + case mtpc_updateEncryption: _type = cons; { + if (!data) setData(new MTPDupdateEncryption()); + MTPDupdateEncryption &v(_updateEncryption()); + v.vchat.read(from, end); + v.vdate.read(from, end); + } break; + case mtpc_updateEncryptedMessagesRead: _type = cons; { + if (!data) setData(new MTPDupdateEncryptedMessagesRead()); + MTPDupdateEncryptedMessagesRead &v(_updateEncryptedMessagesRead()); + v.vchat_id.read(from, end); + v.vmax_date.read(from, end); + v.vdate.read(from, end); + } break; + case mtpc_updateChatParticipantAdd: _type = cons; { + if (!data) setData(new MTPDupdateChatParticipantAdd()); + MTPDupdateChatParticipantAdd &v(_updateChatParticipantAdd()); + v.vchat_id.read(from, end); + v.vuser_id.read(from, end); + v.vinviter_id.read(from, end); + v.vversion.read(from, end); + } break; + case mtpc_updateChatParticipantDelete: _type = cons; { + if (!data) setData(new MTPDupdateChatParticipantDelete()); + MTPDupdateChatParticipantDelete &v(_updateChatParticipantDelete()); + v.vchat_id.read(from, end); + v.vuser_id.read(from, end); + v.vversion.read(from, end); + } break; + case mtpc_updateDcOptions: _type = cons; { + if (!data) setData(new MTPDupdateDcOptions()); + MTPDupdateDcOptions &v(_updateDcOptions()); + v.vdc_options.read(from, end); + } break; + case mtpc_updateUserBlocked: _type = cons; { + if (!data) setData(new MTPDupdateUserBlocked()); + MTPDupdateUserBlocked &v(_updateUserBlocked()); + v.vuser_id.read(from, end); + v.vblocked.read(from, end); + } break; + case mtpc_updateNotifySettings: _type = cons; { + if (!data) setData(new MTPDupdateNotifySettings()); + MTPDupdateNotifySettings &v(_updateNotifySettings()); + v.vpeer.read(from, end); + v.vnotify_settings.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPupdate"); + } +} +inline void MTPupdate::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_updateNewMessage: { + const MTPDupdateNewMessage &v(c_updateNewMessage()); + v.vmessage.write(to); + v.vpts.write(to); + } break; + case mtpc_updateMessageID: { + const MTPDupdateMessageID &v(c_updateMessageID()); + v.vid.write(to); + v.vrandom_id.write(to); + } break; + case mtpc_updateReadMessages: { + const MTPDupdateReadMessages &v(c_updateReadMessages()); + v.vmessages.write(to); + v.vpts.write(to); + } break; + case mtpc_updateDeleteMessages: { + const MTPDupdateDeleteMessages &v(c_updateDeleteMessages()); + v.vmessages.write(to); + v.vpts.write(to); + } break; + case mtpc_updateRestoreMessages: { + const MTPDupdateRestoreMessages &v(c_updateRestoreMessages()); + v.vmessages.write(to); + v.vpts.write(to); + } break; + case mtpc_updateUserTyping: { + const MTPDupdateUserTyping &v(c_updateUserTyping()); + v.vuser_id.write(to); + } break; + case mtpc_updateChatUserTyping: { + const MTPDupdateChatUserTyping &v(c_updateChatUserTyping()); + v.vchat_id.write(to); + v.vuser_id.write(to); + } break; + case mtpc_updateChatParticipants: { + const MTPDupdateChatParticipants &v(c_updateChatParticipants()); + v.vparticipants.write(to); + } break; + case mtpc_updateUserStatus: { + const MTPDupdateUserStatus &v(c_updateUserStatus()); + v.vuser_id.write(to); + v.vstatus.write(to); + } break; + case mtpc_updateUserName: { + const MTPDupdateUserName &v(c_updateUserName()); + v.vuser_id.write(to); + v.vfirst_name.write(to); + v.vlast_name.write(to); + } break; + case mtpc_updateUserPhoto: { + const MTPDupdateUserPhoto &v(c_updateUserPhoto()); + v.vuser_id.write(to); + v.vdate.write(to); + v.vphoto.write(to); + v.vprevious.write(to); + } break; + case mtpc_updateContactRegistered: { + const MTPDupdateContactRegistered &v(c_updateContactRegistered()); + v.vuser_id.write(to); + v.vdate.write(to); + } break; + case mtpc_updateContactLink: { + const MTPDupdateContactLink &v(c_updateContactLink()); + v.vuser_id.write(to); + v.vmy_link.write(to); + v.vforeign_link.write(to); + } break; + case mtpc_updateActivation: { + const MTPDupdateActivation &v(c_updateActivation()); + v.vuser_id.write(to); + } break; + case mtpc_updateNewAuthorization: { + const MTPDupdateNewAuthorization &v(c_updateNewAuthorization()); + v.vauth_key_id.write(to); + v.vdate.write(to); + v.vdevice.write(to); + v.vlocation.write(to); + } break; + case mtpc_updateNewGeoChatMessage: { + const MTPDupdateNewGeoChatMessage &v(c_updateNewGeoChatMessage()); + v.vmessage.write(to); + } break; + case mtpc_updateNewEncryptedMessage: { + const MTPDupdateNewEncryptedMessage &v(c_updateNewEncryptedMessage()); + v.vmessage.write(to); + v.vqts.write(to); + } break; + case mtpc_updateEncryptedChatTyping: { + const MTPDupdateEncryptedChatTyping &v(c_updateEncryptedChatTyping()); + v.vchat_id.write(to); + } break; + case mtpc_updateEncryption: { + const MTPDupdateEncryption &v(c_updateEncryption()); + v.vchat.write(to); + v.vdate.write(to); + } break; + case mtpc_updateEncryptedMessagesRead: { + const MTPDupdateEncryptedMessagesRead &v(c_updateEncryptedMessagesRead()); + v.vchat_id.write(to); + v.vmax_date.write(to); + v.vdate.write(to); + } break; + case mtpc_updateChatParticipantAdd: { + const MTPDupdateChatParticipantAdd &v(c_updateChatParticipantAdd()); + v.vchat_id.write(to); + v.vuser_id.write(to); + v.vinviter_id.write(to); + v.vversion.write(to); + } break; + case mtpc_updateChatParticipantDelete: { + const MTPDupdateChatParticipantDelete &v(c_updateChatParticipantDelete()); + v.vchat_id.write(to); + v.vuser_id.write(to); + v.vversion.write(to); + } break; + case mtpc_updateDcOptions: { + const MTPDupdateDcOptions &v(c_updateDcOptions()); + v.vdc_options.write(to); + } break; + case mtpc_updateUserBlocked: { + const MTPDupdateUserBlocked &v(c_updateUserBlocked()); + v.vuser_id.write(to); + v.vblocked.write(to); + } break; + case mtpc_updateNotifySettings: { + const MTPDupdateNotifySettings &v(c_updateNotifySettings()); + v.vpeer.write(to); + v.vnotify_settings.write(to); + } break; + } +} +inline MTPupdate::MTPupdate(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_updateNewMessage: setData(new MTPDupdateNewMessage()); break; + case mtpc_updateMessageID: setData(new MTPDupdateMessageID()); break; + case mtpc_updateReadMessages: setData(new MTPDupdateReadMessages()); break; + case mtpc_updateDeleteMessages: setData(new MTPDupdateDeleteMessages()); break; + case mtpc_updateRestoreMessages: setData(new MTPDupdateRestoreMessages()); break; + case mtpc_updateUserTyping: setData(new MTPDupdateUserTyping()); break; + case mtpc_updateChatUserTyping: setData(new MTPDupdateChatUserTyping()); break; + case mtpc_updateChatParticipants: setData(new MTPDupdateChatParticipants()); break; + case mtpc_updateUserStatus: setData(new MTPDupdateUserStatus()); break; + case mtpc_updateUserName: setData(new MTPDupdateUserName()); break; + case mtpc_updateUserPhoto: setData(new MTPDupdateUserPhoto()); break; + case mtpc_updateContactRegistered: setData(new MTPDupdateContactRegistered()); break; + case mtpc_updateContactLink: setData(new MTPDupdateContactLink()); break; + case mtpc_updateActivation: setData(new MTPDupdateActivation()); break; + case mtpc_updateNewAuthorization: setData(new MTPDupdateNewAuthorization()); break; + case mtpc_updateNewGeoChatMessage: setData(new MTPDupdateNewGeoChatMessage()); break; + case mtpc_updateNewEncryptedMessage: setData(new MTPDupdateNewEncryptedMessage()); break; + case mtpc_updateEncryptedChatTyping: setData(new MTPDupdateEncryptedChatTyping()); break; + case mtpc_updateEncryption: setData(new MTPDupdateEncryption()); break; + case mtpc_updateEncryptedMessagesRead: setData(new MTPDupdateEncryptedMessagesRead()); break; + case mtpc_updateChatParticipantAdd: setData(new MTPDupdateChatParticipantAdd()); break; + case mtpc_updateChatParticipantDelete: setData(new MTPDupdateChatParticipantDelete()); break; + case mtpc_updateDcOptions: setData(new MTPDupdateDcOptions()); break; + case mtpc_updateUserBlocked: setData(new MTPDupdateUserBlocked()); break; + case mtpc_updateNotifySettings: setData(new MTPDupdateNotifySettings()); break; + default: throw mtpErrorBadTypeId(type, "MTPupdate"); + } +} +inline MTPupdate::MTPupdate(MTPDupdateNewMessage *_data) : _type(mtpc_updateNewMessage), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateMessageID *_data) : _type(mtpc_updateMessageID), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateReadMessages *_data) : _type(mtpc_updateReadMessages), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateDeleteMessages *_data) : _type(mtpc_updateDeleteMessages), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateRestoreMessages *_data) : _type(mtpc_updateRestoreMessages), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateUserTyping *_data) : _type(mtpc_updateUserTyping), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateChatUserTyping *_data) : _type(mtpc_updateChatUserTyping), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateChatParticipants *_data) : _type(mtpc_updateChatParticipants), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateUserStatus *_data) : _type(mtpc_updateUserStatus), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateUserName *_data) : _type(mtpc_updateUserName), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateUserPhoto *_data) : _type(mtpc_updateUserPhoto), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateContactRegistered *_data) : _type(mtpc_updateContactRegistered), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateContactLink *_data) : _type(mtpc_updateContactLink), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateActivation *_data) : _type(mtpc_updateActivation), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateNewAuthorization *_data) : _type(mtpc_updateNewAuthorization), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateNewGeoChatMessage *_data) : _type(mtpc_updateNewGeoChatMessage), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateNewEncryptedMessage *_data) : _type(mtpc_updateNewEncryptedMessage), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateEncryptedChatTyping *_data) : _type(mtpc_updateEncryptedChatTyping), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateEncryption *_data) : _type(mtpc_updateEncryption), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateEncryptedMessagesRead *_data) : _type(mtpc_updateEncryptedMessagesRead), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateChatParticipantAdd *_data) : _type(mtpc_updateChatParticipantAdd), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateChatParticipantDelete *_data) : _type(mtpc_updateChatParticipantDelete), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateDcOptions *_data) : _type(mtpc_updateDcOptions), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateUserBlocked *_data) : _type(mtpc_updateUserBlocked), mtpDataOwner(_data) { +} +inline MTPupdate::MTPupdate(MTPDupdateNotifySettings *_data) : _type(mtpc_updateNotifySettings), mtpDataOwner(_data) { +} +inline MTPupdate MTP_updateNewMessage(const MTPMessage &_message, MTPint _pts) { + return MTPupdate(new MTPDupdateNewMessage(_message, _pts)); +} +inline MTPupdate MTP_updateMessageID(MTPint _id, const MTPlong &_random_id) { + return MTPupdate(new MTPDupdateMessageID(_id, _random_id)); +} +inline MTPupdate MTP_updateReadMessages(const MTPVector &_messages, MTPint _pts) { + return MTPupdate(new MTPDupdateReadMessages(_messages, _pts)); +} +inline MTPupdate MTP_updateDeleteMessages(const MTPVector &_messages, MTPint _pts) { + return MTPupdate(new MTPDupdateDeleteMessages(_messages, _pts)); +} +inline MTPupdate MTP_updateRestoreMessages(const MTPVector &_messages, MTPint _pts) { + return MTPupdate(new MTPDupdateRestoreMessages(_messages, _pts)); +} +inline MTPupdate MTP_updateUserTyping(MTPint _user_id) { + return MTPupdate(new MTPDupdateUserTyping(_user_id)); +} +inline MTPupdate MTP_updateChatUserTyping(MTPint _chat_id, MTPint _user_id) { + return MTPupdate(new MTPDupdateChatUserTyping(_chat_id, _user_id)); +} +inline MTPupdate MTP_updateChatParticipants(const MTPChatParticipants &_participants) { + return MTPupdate(new MTPDupdateChatParticipants(_participants)); +} +inline MTPupdate MTP_updateUserStatus(MTPint _user_id, const MTPUserStatus &_status) { + return MTPupdate(new MTPDupdateUserStatus(_user_id, _status)); +} +inline MTPupdate MTP_updateUserName(MTPint _user_id, const MTPstring &_first_name, const MTPstring &_last_name) { + return MTPupdate(new MTPDupdateUserName(_user_id, _first_name, _last_name)); +} +inline MTPupdate MTP_updateUserPhoto(MTPint _user_id, MTPint _date, const MTPUserProfilePhoto &_photo, MTPBool _previous) { + return MTPupdate(new MTPDupdateUserPhoto(_user_id, _date, _photo, _previous)); +} +inline MTPupdate MTP_updateContactRegistered(MTPint _user_id, MTPint _date) { + return MTPupdate(new MTPDupdateContactRegistered(_user_id, _date)); +} +inline MTPupdate MTP_updateContactLink(MTPint _user_id, const MTPcontacts_MyLink &_my_link, const MTPcontacts_ForeignLink &_foreign_link) { + return MTPupdate(new MTPDupdateContactLink(_user_id, _my_link, _foreign_link)); +} +inline MTPupdate MTP_updateActivation(MTPint _user_id) { + return MTPupdate(new MTPDupdateActivation(_user_id)); +} +inline MTPupdate MTP_updateNewAuthorization(const MTPlong &_auth_key_id, MTPint _date, const MTPstring &_device, const MTPstring &_location) { + return MTPupdate(new MTPDupdateNewAuthorization(_auth_key_id, _date, _device, _location)); +} +inline MTPupdate MTP_updateNewGeoChatMessage(const MTPGeoChatMessage &_message) { + return MTPupdate(new MTPDupdateNewGeoChatMessage(_message)); +} +inline MTPupdate MTP_updateNewEncryptedMessage(const MTPEncryptedMessage &_message, MTPint _qts) { + return MTPupdate(new MTPDupdateNewEncryptedMessage(_message, _qts)); +} +inline MTPupdate MTP_updateEncryptedChatTyping(MTPint _chat_id) { + return MTPupdate(new MTPDupdateEncryptedChatTyping(_chat_id)); +} +inline MTPupdate MTP_updateEncryption(const MTPEncryptedChat &_chat, MTPint _date) { + return MTPupdate(new MTPDupdateEncryption(_chat, _date)); +} +inline MTPupdate MTP_updateEncryptedMessagesRead(MTPint _chat_id, MTPint _max_date, MTPint _date) { + return MTPupdate(new MTPDupdateEncryptedMessagesRead(_chat_id, _max_date, _date)); +} +inline MTPupdate MTP_updateChatParticipantAdd(MTPint _chat_id, MTPint _user_id, MTPint _inviter_id, MTPint _version) { + return MTPupdate(new MTPDupdateChatParticipantAdd(_chat_id, _user_id, _inviter_id, _version)); +} +inline MTPupdate MTP_updateChatParticipantDelete(MTPint _chat_id, MTPint _user_id, MTPint _version) { + return MTPupdate(new MTPDupdateChatParticipantDelete(_chat_id, _user_id, _version)); +} +inline MTPupdate MTP_updateDcOptions(const MTPVector &_dc_options) { + return MTPupdate(new MTPDupdateDcOptions(_dc_options)); +} +inline MTPupdate MTP_updateUserBlocked(MTPint _user_id, MTPBool _blocked) { + return MTPupdate(new MTPDupdateUserBlocked(_user_id, _blocked)); +} +inline MTPupdate MTP_updateNotifySettings(const MTPNotifyPeer &_peer, const MTPPeerNotifySettings &_notify_settings) { + return MTPupdate(new MTPDupdateNotifySettings(_peer, _notify_settings)); +} + +inline MTPupdates_state::MTPupdates_state() : mtpDataOwner(new MTPDupdates_state()) { +} + +inline uint32 MTPupdates_state::size() const { + const MTPDupdates_state &v(c_updates_state()); + return v.vpts.size() + v.vqts.size() + v.vdate.size() + v.vseq.size() + v.vunread_count.size(); +} +inline mtpTypeId MTPupdates_state::type() const { + return mtpc_updates_state; +} +inline void MTPupdates_state::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_updates_state) throw mtpErrorUnexpected(cons, "MTPupdates_state"); + + if (!data) setData(new MTPDupdates_state()); + MTPDupdates_state &v(_updates_state()); + v.vpts.read(from, end); + v.vqts.read(from, end); + v.vdate.read(from, end); + v.vseq.read(from, end); + v.vunread_count.read(from, end); +} +inline void MTPupdates_state::write(mtpBuffer &to) const { + const MTPDupdates_state &v(c_updates_state()); + v.vpts.write(to); + v.vqts.write(to); + v.vdate.write(to); + v.vseq.write(to); + v.vunread_count.write(to); +} +inline MTPupdates_state::MTPupdates_state(MTPDupdates_state *_data) : mtpDataOwner(_data) { +} +inline MTPupdates_state MTP_updates_state(MTPint _pts, MTPint _qts, MTPint _date, MTPint _seq, MTPint _unread_count) { + return MTPupdates_state(new MTPDupdates_state(_pts, _qts, _date, _seq, _unread_count)); +} + +inline uint32 MTPupdates_difference::size() const { + switch (_type) { + case mtpc_updates_differenceEmpty: { + const MTPDupdates_differenceEmpty &v(c_updates_differenceEmpty()); + return v.vdate.size() + v.vseq.size(); + } + case mtpc_updates_difference: { + const MTPDupdates_difference &v(c_updates_difference()); + return v.vnew_messages.size() + v.vnew_encrypted_messages.size() + v.vother_updates.size() + v.vchats.size() + v.vusers.size() + v.vstate.size(); + } + case mtpc_updates_differenceSlice: { + const MTPDupdates_differenceSlice &v(c_updates_differenceSlice()); + return v.vnew_messages.size() + v.vnew_encrypted_messages.size() + v.vother_updates.size() + v.vchats.size() + v.vusers.size() + v.vintermediate_state.size(); + } + } + return 0; +} +inline mtpTypeId MTPupdates_difference::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPupdates_difference::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_updates_differenceEmpty: _type = cons; { + if (!data) setData(new MTPDupdates_differenceEmpty()); + MTPDupdates_differenceEmpty &v(_updates_differenceEmpty()); + v.vdate.read(from, end); + v.vseq.read(from, end); + } break; + case mtpc_updates_difference: _type = cons; { + if (!data) setData(new MTPDupdates_difference()); + MTPDupdates_difference &v(_updates_difference()); + v.vnew_messages.read(from, end); + v.vnew_encrypted_messages.read(from, end); + v.vother_updates.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + v.vstate.read(from, end); + } break; + case mtpc_updates_differenceSlice: _type = cons; { + if (!data) setData(new MTPDupdates_differenceSlice()); + MTPDupdates_differenceSlice &v(_updates_differenceSlice()); + v.vnew_messages.read(from, end); + v.vnew_encrypted_messages.read(from, end); + v.vother_updates.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + v.vintermediate_state.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPupdates_difference"); + } +} +inline void MTPupdates_difference::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_updates_differenceEmpty: { + const MTPDupdates_differenceEmpty &v(c_updates_differenceEmpty()); + v.vdate.write(to); + v.vseq.write(to); + } break; + case mtpc_updates_difference: { + const MTPDupdates_difference &v(c_updates_difference()); + v.vnew_messages.write(to); + v.vnew_encrypted_messages.write(to); + v.vother_updates.write(to); + v.vchats.write(to); + v.vusers.write(to); + v.vstate.write(to); + } break; + case mtpc_updates_differenceSlice: { + const MTPDupdates_differenceSlice &v(c_updates_differenceSlice()); + v.vnew_messages.write(to); + v.vnew_encrypted_messages.write(to); + v.vother_updates.write(to); + v.vchats.write(to); + v.vusers.write(to); + v.vintermediate_state.write(to); + } break; + } +} +inline MTPupdates_difference::MTPupdates_difference(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_updates_differenceEmpty: setData(new MTPDupdates_differenceEmpty()); break; + case mtpc_updates_difference: setData(new MTPDupdates_difference()); break; + case mtpc_updates_differenceSlice: setData(new MTPDupdates_differenceSlice()); break; + default: throw mtpErrorBadTypeId(type, "MTPupdates_difference"); + } +} +inline MTPupdates_difference::MTPupdates_difference(MTPDupdates_differenceEmpty *_data) : _type(mtpc_updates_differenceEmpty), mtpDataOwner(_data) { +} +inline MTPupdates_difference::MTPupdates_difference(MTPDupdates_difference *_data) : _type(mtpc_updates_difference), mtpDataOwner(_data) { +} +inline MTPupdates_difference::MTPupdates_difference(MTPDupdates_differenceSlice *_data) : _type(mtpc_updates_differenceSlice), mtpDataOwner(_data) { +} +inline MTPupdates_difference MTP_updates_differenceEmpty(MTPint _date, MTPint _seq) { + return MTPupdates_difference(new MTPDupdates_differenceEmpty(_date, _seq)); +} +inline MTPupdates_difference MTP_updates_difference(const MTPVector &_new_messages, const MTPVector &_new_encrypted_messages, const MTPVector &_other_updates, const MTPVector &_chats, const MTPVector &_users, const MTPupdates_State &_state) { + return MTPupdates_difference(new MTPDupdates_difference(_new_messages, _new_encrypted_messages, _other_updates, _chats, _users, _state)); +} +inline MTPupdates_difference MTP_updates_differenceSlice(const MTPVector &_new_messages, const MTPVector &_new_encrypted_messages, const MTPVector &_other_updates, const MTPVector &_chats, const MTPVector &_users, const MTPupdates_State &_intermediate_state) { + return MTPupdates_difference(new MTPDupdates_differenceSlice(_new_messages, _new_encrypted_messages, _other_updates, _chats, _users, _intermediate_state)); +} + +inline uint32 MTPupdates::size() const { + switch (_type) { + case mtpc_updateShortMessage: { + const MTPDupdateShortMessage &v(c_updateShortMessage()); + return v.vid.size() + v.vfrom_id.size() + v.vmessage.size() + v.vpts.size() + v.vdate.size() + v.vseq.size(); + } + case mtpc_updateShortChatMessage: { + const MTPDupdateShortChatMessage &v(c_updateShortChatMessage()); + return v.vid.size() + v.vfrom_id.size() + v.vchat_id.size() + v.vmessage.size() + v.vpts.size() + v.vdate.size() + v.vseq.size(); + } + case mtpc_updateShort: { + const MTPDupdateShort &v(c_updateShort()); + return v.vupdate.size() + v.vdate.size(); + } + case mtpc_updatesCombined: { + const MTPDupdatesCombined &v(c_updatesCombined()); + return v.vupdates.size() + v.vusers.size() + v.vchats.size() + v.vdate.size() + v.vseq_start.size() + v.vseq.size(); + } + case mtpc_updates: { + const MTPDupdates &v(c_updates()); + return v.vupdates.size() + v.vusers.size() + v.vchats.size() + v.vdate.size() + v.vseq.size(); + } + } + return 0; +} +inline mtpTypeId MTPupdates::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPupdates::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_updatesTooLong: _type = cons; break; + case mtpc_updateShortMessage: _type = cons; { + if (!data) setData(new MTPDupdateShortMessage()); + MTPDupdateShortMessage &v(_updateShortMessage()); + v.vid.read(from, end); + v.vfrom_id.read(from, end); + v.vmessage.read(from, end); + v.vpts.read(from, end); + v.vdate.read(from, end); + v.vseq.read(from, end); + } break; + case mtpc_updateShortChatMessage: _type = cons; { + if (!data) setData(new MTPDupdateShortChatMessage()); + MTPDupdateShortChatMessage &v(_updateShortChatMessage()); + v.vid.read(from, end); + v.vfrom_id.read(from, end); + v.vchat_id.read(from, end); + v.vmessage.read(from, end); + v.vpts.read(from, end); + v.vdate.read(from, end); + v.vseq.read(from, end); + } break; + case mtpc_updateShort: _type = cons; { + if (!data) setData(new MTPDupdateShort()); + MTPDupdateShort &v(_updateShort()); + v.vupdate.read(from, end); + v.vdate.read(from, end); + } break; + case mtpc_updatesCombined: _type = cons; { + if (!data) setData(new MTPDupdatesCombined()); + MTPDupdatesCombined &v(_updatesCombined()); + v.vupdates.read(from, end); + v.vusers.read(from, end); + v.vchats.read(from, end); + v.vdate.read(from, end); + v.vseq_start.read(from, end); + v.vseq.read(from, end); + } break; + case mtpc_updates: _type = cons; { + if (!data) setData(new MTPDupdates()); + MTPDupdates &v(_updates()); + v.vupdates.read(from, end); + v.vusers.read(from, end); + v.vchats.read(from, end); + v.vdate.read(from, end); + v.vseq.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPupdates"); + } +} +inline void MTPupdates::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_updateShortMessage: { + const MTPDupdateShortMessage &v(c_updateShortMessage()); + v.vid.write(to); + v.vfrom_id.write(to); + v.vmessage.write(to); + v.vpts.write(to); + v.vdate.write(to); + v.vseq.write(to); + } break; + case mtpc_updateShortChatMessage: { + const MTPDupdateShortChatMessage &v(c_updateShortChatMessage()); + v.vid.write(to); + v.vfrom_id.write(to); + v.vchat_id.write(to); + v.vmessage.write(to); + v.vpts.write(to); + v.vdate.write(to); + v.vseq.write(to); + } break; + case mtpc_updateShort: { + const MTPDupdateShort &v(c_updateShort()); + v.vupdate.write(to); + v.vdate.write(to); + } break; + case mtpc_updatesCombined: { + const MTPDupdatesCombined &v(c_updatesCombined()); + v.vupdates.write(to); + v.vusers.write(to); + v.vchats.write(to); + v.vdate.write(to); + v.vseq_start.write(to); + v.vseq.write(to); + } break; + case mtpc_updates: { + const MTPDupdates &v(c_updates()); + v.vupdates.write(to); + v.vusers.write(to); + v.vchats.write(to); + v.vdate.write(to); + v.vseq.write(to); + } break; + } +} +inline MTPupdates::MTPupdates(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_updatesTooLong: break; + case mtpc_updateShortMessage: setData(new MTPDupdateShortMessage()); break; + case mtpc_updateShortChatMessage: setData(new MTPDupdateShortChatMessage()); break; + case mtpc_updateShort: setData(new MTPDupdateShort()); break; + case mtpc_updatesCombined: setData(new MTPDupdatesCombined()); break; + case mtpc_updates: setData(new MTPDupdates()); break; + default: throw mtpErrorBadTypeId(type, "MTPupdates"); + } +} +inline MTPupdates::MTPupdates(MTPDupdateShortMessage *_data) : _type(mtpc_updateShortMessage), mtpDataOwner(_data) { +} +inline MTPupdates::MTPupdates(MTPDupdateShortChatMessage *_data) : _type(mtpc_updateShortChatMessage), mtpDataOwner(_data) { +} +inline MTPupdates::MTPupdates(MTPDupdateShort *_data) : _type(mtpc_updateShort), mtpDataOwner(_data) { +} +inline MTPupdates::MTPupdates(MTPDupdatesCombined *_data) : _type(mtpc_updatesCombined), mtpDataOwner(_data) { +} +inline MTPupdates::MTPupdates(MTPDupdates *_data) : _type(mtpc_updates), mtpDataOwner(_data) { +} +inline MTPupdates MTP_updatesTooLong() { + return MTPupdates(mtpc_updatesTooLong); +} +inline MTPupdates MTP_updateShortMessage(MTPint _id, MTPint _from_id, const MTPstring &_message, MTPint _pts, MTPint _date, MTPint _seq) { + return MTPupdates(new MTPDupdateShortMessage(_id, _from_id, _message, _pts, _date, _seq)); +} +inline MTPupdates MTP_updateShortChatMessage(MTPint _id, MTPint _from_id, MTPint _chat_id, const MTPstring &_message, MTPint _pts, MTPint _date, MTPint _seq) { + return MTPupdates(new MTPDupdateShortChatMessage(_id, _from_id, _chat_id, _message, _pts, _date, _seq)); +} +inline MTPupdates MTP_updateShort(const MTPUpdate &_update, MTPint _date) { + return MTPupdates(new MTPDupdateShort(_update, _date)); +} +inline MTPupdates MTP_updatesCombined(const MTPVector &_updates, const MTPVector &_users, const MTPVector &_chats, MTPint _date, MTPint _seq_start, MTPint _seq) { + return MTPupdates(new MTPDupdatesCombined(_updates, _users, _chats, _date, _seq_start, _seq)); +} +inline MTPupdates MTP_updates(const MTPVector &_updates, const MTPVector &_users, const MTPVector &_chats, MTPint _date, MTPint _seq) { + return MTPupdates(new MTPDupdates(_updates, _users, _chats, _date, _seq)); +} + +inline uint32 MTPphotos_photos::size() const { + switch (_type) { + case mtpc_photos_photos: { + const MTPDphotos_photos &v(c_photos_photos()); + return v.vphotos.size() + v.vusers.size(); + } + case mtpc_photos_photosSlice: { + const MTPDphotos_photosSlice &v(c_photos_photosSlice()); + return v.vcount.size() + v.vphotos.size() + v.vusers.size(); + } + } + return 0; +} +inline mtpTypeId MTPphotos_photos::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPphotos_photos::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_photos_photos: _type = cons; { + if (!data) setData(new MTPDphotos_photos()); + MTPDphotos_photos &v(_photos_photos()); + v.vphotos.read(from, end); + v.vusers.read(from, end); + } break; + case mtpc_photos_photosSlice: _type = cons; { + if (!data) setData(new MTPDphotos_photosSlice()); + MTPDphotos_photosSlice &v(_photos_photosSlice()); + v.vcount.read(from, end); + v.vphotos.read(from, end); + v.vusers.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPphotos_photos"); + } +} +inline void MTPphotos_photos::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_photos_photos: { + const MTPDphotos_photos &v(c_photos_photos()); + v.vphotos.write(to); + v.vusers.write(to); + } break; + case mtpc_photos_photosSlice: { + const MTPDphotos_photosSlice &v(c_photos_photosSlice()); + v.vcount.write(to); + v.vphotos.write(to); + v.vusers.write(to); + } break; + } +} +inline MTPphotos_photos::MTPphotos_photos(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_photos_photos: setData(new MTPDphotos_photos()); break; + case mtpc_photos_photosSlice: setData(new MTPDphotos_photosSlice()); break; + default: throw mtpErrorBadTypeId(type, "MTPphotos_photos"); + } +} +inline MTPphotos_photos::MTPphotos_photos(MTPDphotos_photos *_data) : _type(mtpc_photos_photos), mtpDataOwner(_data) { +} +inline MTPphotos_photos::MTPphotos_photos(MTPDphotos_photosSlice *_data) : _type(mtpc_photos_photosSlice), mtpDataOwner(_data) { +} +inline MTPphotos_photos MTP_photos_photos(const MTPVector &_photos, const MTPVector &_users) { + return MTPphotos_photos(new MTPDphotos_photos(_photos, _users)); +} +inline MTPphotos_photos MTP_photos_photosSlice(MTPint _count, const MTPVector &_photos, const MTPVector &_users) { + return MTPphotos_photos(new MTPDphotos_photosSlice(_count, _photos, _users)); +} + +inline MTPphotos_photo::MTPphotos_photo() : mtpDataOwner(new MTPDphotos_photo()) { +} + +inline uint32 MTPphotos_photo::size() const { + const MTPDphotos_photo &v(c_photos_photo()); + return v.vphoto.size() + v.vusers.size(); +} +inline mtpTypeId MTPphotos_photo::type() const { + return mtpc_photos_photo; +} +inline void MTPphotos_photo::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_photos_photo) throw mtpErrorUnexpected(cons, "MTPphotos_photo"); + + if (!data) setData(new MTPDphotos_photo()); + MTPDphotos_photo &v(_photos_photo()); + v.vphoto.read(from, end); + v.vusers.read(from, end); +} +inline void MTPphotos_photo::write(mtpBuffer &to) const { + const MTPDphotos_photo &v(c_photos_photo()); + v.vphoto.write(to); + v.vusers.write(to); +} +inline MTPphotos_photo::MTPphotos_photo(MTPDphotos_photo *_data) : mtpDataOwner(_data) { +} +inline MTPphotos_photo MTP_photos_photo(const MTPPhoto &_photo, const MTPVector &_users) { + return MTPphotos_photo(new MTPDphotos_photo(_photo, _users)); +} + +inline MTPupload_file::MTPupload_file() : mtpDataOwner(new MTPDupload_file()) { +} + +inline uint32 MTPupload_file::size() const { + const MTPDupload_file &v(c_upload_file()); + return v.vtype.size() + v.vmtime.size() + v.vbytes.size(); +} +inline mtpTypeId MTPupload_file::type() const { + return mtpc_upload_file; +} +inline void MTPupload_file::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_upload_file) throw mtpErrorUnexpected(cons, "MTPupload_file"); + + if (!data) setData(new MTPDupload_file()); + MTPDupload_file &v(_upload_file()); + v.vtype.read(from, end); + v.vmtime.read(from, end); + v.vbytes.read(from, end); +} +inline void MTPupload_file::write(mtpBuffer &to) const { + const MTPDupload_file &v(c_upload_file()); + v.vtype.write(to); + v.vmtime.write(to); + v.vbytes.write(to); +} +inline MTPupload_file::MTPupload_file(MTPDupload_file *_data) : mtpDataOwner(_data) { +} +inline MTPupload_file MTP_upload_file(const MTPstorage_FileType &_type, MTPint _mtime, const MTPbytes &_bytes) { + return MTPupload_file(new MTPDupload_file(_type, _mtime, _bytes)); +} + +inline MTPdcOption::MTPdcOption() : mtpDataOwner(new MTPDdcOption()) { +} + +inline uint32 MTPdcOption::size() const { + const MTPDdcOption &v(c_dcOption()); + return v.vid.size() + v.vhostname.size() + v.vip_address.size() + v.vport.size(); +} +inline mtpTypeId MTPdcOption::type() const { + return mtpc_dcOption; +} +inline void MTPdcOption::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_dcOption) throw mtpErrorUnexpected(cons, "MTPdcOption"); + + if (!data) setData(new MTPDdcOption()); + MTPDdcOption &v(_dcOption()); + v.vid.read(from, end); + v.vhostname.read(from, end); + v.vip_address.read(from, end); + v.vport.read(from, end); +} +inline void MTPdcOption::write(mtpBuffer &to) const { + const MTPDdcOption &v(c_dcOption()); + v.vid.write(to); + v.vhostname.write(to); + v.vip_address.write(to); + v.vport.write(to); +} +inline MTPdcOption::MTPdcOption(MTPDdcOption *_data) : mtpDataOwner(_data) { +} +inline MTPdcOption MTP_dcOption(MTPint _id, const MTPstring &_hostname, const MTPstring &_ip_address, MTPint _port) { + return MTPdcOption(new MTPDdcOption(_id, _hostname, _ip_address, _port)); +} + +inline MTPconfig::MTPconfig() : mtpDataOwner(new MTPDconfig()) { +} + +inline uint32 MTPconfig::size() const { + const MTPDconfig &v(c_config()); + return v.vdate.size() + v.vtest_mode.size() + v.vthis_dc.size() + v.vdc_options.size() + v.vchat_size_max.size() + v.vbroadcast_size_max.size(); +} +inline mtpTypeId MTPconfig::type() const { + return mtpc_config; +} +inline void MTPconfig::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_config) throw mtpErrorUnexpected(cons, "MTPconfig"); + + if (!data) setData(new MTPDconfig()); + MTPDconfig &v(_config()); + v.vdate.read(from, end); + v.vtest_mode.read(from, end); + v.vthis_dc.read(from, end); + v.vdc_options.read(from, end); + v.vchat_size_max.read(from, end); + v.vbroadcast_size_max.read(from, end); +} +inline void MTPconfig::write(mtpBuffer &to) const { + const MTPDconfig &v(c_config()); + v.vdate.write(to); + v.vtest_mode.write(to); + v.vthis_dc.write(to); + v.vdc_options.write(to); + v.vchat_size_max.write(to); + v.vbroadcast_size_max.write(to); +} +inline MTPconfig::MTPconfig(MTPDconfig *_data) : mtpDataOwner(_data) { +} +inline MTPconfig MTP_config(MTPint _date, MTPBool _test_mode, MTPint _this_dc, const MTPVector &_dc_options, MTPint _chat_size_max, MTPint _broadcast_size_max) { + return MTPconfig(new MTPDconfig(_date, _test_mode, _this_dc, _dc_options, _chat_size_max, _broadcast_size_max)); +} + +inline MTPnearestDc::MTPnearestDc() : mtpDataOwner(new MTPDnearestDc()) { +} + +inline uint32 MTPnearestDc::size() const { + const MTPDnearestDc &v(c_nearestDc()); + return v.vcountry.size() + v.vthis_dc.size() + v.vnearest_dc.size(); +} +inline mtpTypeId MTPnearestDc::type() const { + return mtpc_nearestDc; +} +inline void MTPnearestDc::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_nearestDc) throw mtpErrorUnexpected(cons, "MTPnearestDc"); + + if (!data) setData(new MTPDnearestDc()); + MTPDnearestDc &v(_nearestDc()); + v.vcountry.read(from, end); + v.vthis_dc.read(from, end); + v.vnearest_dc.read(from, end); +} +inline void MTPnearestDc::write(mtpBuffer &to) const { + const MTPDnearestDc &v(c_nearestDc()); + v.vcountry.write(to); + v.vthis_dc.write(to); + v.vnearest_dc.write(to); +} +inline MTPnearestDc::MTPnearestDc(MTPDnearestDc *_data) : mtpDataOwner(_data) { +} +inline MTPnearestDc MTP_nearestDc(const MTPstring &_country, MTPint _this_dc, MTPint _nearest_dc) { + return MTPnearestDc(new MTPDnearestDc(_country, _this_dc, _nearest_dc)); +} + +inline uint32 MTPhelp_appUpdate::size() const { + switch (_type) { + case mtpc_help_appUpdate: { + const MTPDhelp_appUpdate &v(c_help_appUpdate()); + return v.vid.size() + v.vcritical.size() + v.vurl.size() + v.vtext.size(); + } + } + return 0; +} +inline mtpTypeId MTPhelp_appUpdate::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPhelp_appUpdate::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_help_appUpdate: _type = cons; { + if (!data) setData(new MTPDhelp_appUpdate()); + MTPDhelp_appUpdate &v(_help_appUpdate()); + v.vid.read(from, end); + v.vcritical.read(from, end); + v.vurl.read(from, end); + v.vtext.read(from, end); + } break; + case mtpc_help_noAppUpdate: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPhelp_appUpdate"); + } +} +inline void MTPhelp_appUpdate::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_help_appUpdate: { + const MTPDhelp_appUpdate &v(c_help_appUpdate()); + v.vid.write(to); + v.vcritical.write(to); + v.vurl.write(to); + v.vtext.write(to); + } break; + } +} +inline MTPhelp_appUpdate::MTPhelp_appUpdate(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_help_appUpdate: setData(new MTPDhelp_appUpdate()); break; + case mtpc_help_noAppUpdate: break; + default: throw mtpErrorBadTypeId(type, "MTPhelp_appUpdate"); + } +} +inline MTPhelp_appUpdate::MTPhelp_appUpdate(MTPDhelp_appUpdate *_data) : _type(mtpc_help_appUpdate), mtpDataOwner(_data) { +} +inline MTPhelp_appUpdate MTP_help_appUpdate(MTPint _id, MTPBool _critical, const MTPstring &_url, const MTPstring &_text) { + return MTPhelp_appUpdate(new MTPDhelp_appUpdate(_id, _critical, _url, _text)); +} +inline MTPhelp_appUpdate MTP_help_noAppUpdate() { + return MTPhelp_appUpdate(mtpc_help_noAppUpdate); +} + +inline MTPhelp_inviteText::MTPhelp_inviteText() : mtpDataOwner(new MTPDhelp_inviteText()) { +} + +inline uint32 MTPhelp_inviteText::size() const { + const MTPDhelp_inviteText &v(c_help_inviteText()); + return v.vmessage.size(); +} +inline mtpTypeId MTPhelp_inviteText::type() const { + return mtpc_help_inviteText; +} +inline void MTPhelp_inviteText::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_help_inviteText) throw mtpErrorUnexpected(cons, "MTPhelp_inviteText"); + + if (!data) setData(new MTPDhelp_inviteText()); + MTPDhelp_inviteText &v(_help_inviteText()); + v.vmessage.read(from, end); +} +inline void MTPhelp_inviteText::write(mtpBuffer &to) const { + const MTPDhelp_inviteText &v(c_help_inviteText()); + v.vmessage.write(to); +} +inline MTPhelp_inviteText::MTPhelp_inviteText(MTPDhelp_inviteText *_data) : mtpDataOwner(_data) { +} +inline MTPhelp_inviteText MTP_help_inviteText(const MTPstring &_message) { + return MTPhelp_inviteText(new MTPDhelp_inviteText(_message)); +} + +inline MTPinputGeoChat::MTPinputGeoChat() : mtpDataOwner(new MTPDinputGeoChat()) { +} + +inline uint32 MTPinputGeoChat::size() const { + const MTPDinputGeoChat &v(c_inputGeoChat()); + return v.vchat_id.size() + v.vaccess_hash.size(); +} +inline mtpTypeId MTPinputGeoChat::type() const { + return mtpc_inputGeoChat; +} +inline void MTPinputGeoChat::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_inputGeoChat) throw mtpErrorUnexpected(cons, "MTPinputGeoChat"); + + if (!data) setData(new MTPDinputGeoChat()); + MTPDinputGeoChat &v(_inputGeoChat()); + v.vchat_id.read(from, end); + v.vaccess_hash.read(from, end); +} +inline void MTPinputGeoChat::write(mtpBuffer &to) const { + const MTPDinputGeoChat &v(c_inputGeoChat()); + v.vchat_id.write(to); + v.vaccess_hash.write(to); +} +inline MTPinputGeoChat::MTPinputGeoChat(MTPDinputGeoChat *_data) : mtpDataOwner(_data) { +} +inline MTPinputGeoChat MTP_inputGeoChat(MTPint _chat_id, const MTPlong &_access_hash) { + return MTPinputGeoChat(new MTPDinputGeoChat(_chat_id, _access_hash)); +} + +inline uint32 MTPgeoChatMessage::size() const { + switch (_type) { + case mtpc_geoChatMessageEmpty: { + const MTPDgeoChatMessageEmpty &v(c_geoChatMessageEmpty()); + return v.vchat_id.size() + v.vid.size(); + } + case mtpc_geoChatMessage: { + const MTPDgeoChatMessage &v(c_geoChatMessage()); + return v.vchat_id.size() + v.vid.size() + v.vfrom_id.size() + v.vdate.size() + v.vmessage.size() + v.vmedia.size(); + } + case mtpc_geoChatMessageService: { + const MTPDgeoChatMessageService &v(c_geoChatMessageService()); + return v.vchat_id.size() + v.vid.size() + v.vfrom_id.size() + v.vdate.size() + v.vaction.size(); + } + } + return 0; +} +inline mtpTypeId MTPgeoChatMessage::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPgeoChatMessage::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_geoChatMessageEmpty: _type = cons; { + if (!data) setData(new MTPDgeoChatMessageEmpty()); + MTPDgeoChatMessageEmpty &v(_geoChatMessageEmpty()); + v.vchat_id.read(from, end); + v.vid.read(from, end); + } break; + case mtpc_geoChatMessage: _type = cons; { + if (!data) setData(new MTPDgeoChatMessage()); + MTPDgeoChatMessage &v(_geoChatMessage()); + v.vchat_id.read(from, end); + v.vid.read(from, end); + v.vfrom_id.read(from, end); + v.vdate.read(from, end); + v.vmessage.read(from, end); + v.vmedia.read(from, end); + } break; + case mtpc_geoChatMessageService: _type = cons; { + if (!data) setData(new MTPDgeoChatMessageService()); + MTPDgeoChatMessageService &v(_geoChatMessageService()); + v.vchat_id.read(from, end); + v.vid.read(from, end); + v.vfrom_id.read(from, end); + v.vdate.read(from, end); + v.vaction.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPgeoChatMessage"); + } +} +inline void MTPgeoChatMessage::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_geoChatMessageEmpty: { + const MTPDgeoChatMessageEmpty &v(c_geoChatMessageEmpty()); + v.vchat_id.write(to); + v.vid.write(to); + } break; + case mtpc_geoChatMessage: { + const MTPDgeoChatMessage &v(c_geoChatMessage()); + v.vchat_id.write(to); + v.vid.write(to); + v.vfrom_id.write(to); + v.vdate.write(to); + v.vmessage.write(to); + v.vmedia.write(to); + } break; + case mtpc_geoChatMessageService: { + const MTPDgeoChatMessageService &v(c_geoChatMessageService()); + v.vchat_id.write(to); + v.vid.write(to); + v.vfrom_id.write(to); + v.vdate.write(to); + v.vaction.write(to); + } break; + } +} +inline MTPgeoChatMessage::MTPgeoChatMessage(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_geoChatMessageEmpty: setData(new MTPDgeoChatMessageEmpty()); break; + case mtpc_geoChatMessage: setData(new MTPDgeoChatMessage()); break; + case mtpc_geoChatMessageService: setData(new MTPDgeoChatMessageService()); break; + default: throw mtpErrorBadTypeId(type, "MTPgeoChatMessage"); + } +} +inline MTPgeoChatMessage::MTPgeoChatMessage(MTPDgeoChatMessageEmpty *_data) : _type(mtpc_geoChatMessageEmpty), mtpDataOwner(_data) { +} +inline MTPgeoChatMessage::MTPgeoChatMessage(MTPDgeoChatMessage *_data) : _type(mtpc_geoChatMessage), mtpDataOwner(_data) { +} +inline MTPgeoChatMessage::MTPgeoChatMessage(MTPDgeoChatMessageService *_data) : _type(mtpc_geoChatMessageService), mtpDataOwner(_data) { +} +inline MTPgeoChatMessage MTP_geoChatMessageEmpty(MTPint _chat_id, MTPint _id) { + return MTPgeoChatMessage(new MTPDgeoChatMessageEmpty(_chat_id, _id)); +} +inline MTPgeoChatMessage MTP_geoChatMessage(MTPint _chat_id, MTPint _id, MTPint _from_id, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media) { + return MTPgeoChatMessage(new MTPDgeoChatMessage(_chat_id, _id, _from_id, _date, _message, _media)); +} +inline MTPgeoChatMessage MTP_geoChatMessageService(MTPint _chat_id, MTPint _id, MTPint _from_id, MTPint _date, const MTPMessageAction &_action) { + return MTPgeoChatMessage(new MTPDgeoChatMessageService(_chat_id, _id, _from_id, _date, _action)); +} + +inline MTPgeochats_statedMessage::MTPgeochats_statedMessage() : mtpDataOwner(new MTPDgeochats_statedMessage()) { +} + +inline uint32 MTPgeochats_statedMessage::size() const { + const MTPDgeochats_statedMessage &v(c_geochats_statedMessage()); + return v.vmessage.size() + v.vchats.size() + v.vusers.size() + v.vseq.size(); +} +inline mtpTypeId MTPgeochats_statedMessage::type() const { + return mtpc_geochats_statedMessage; +} +inline void MTPgeochats_statedMessage::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_geochats_statedMessage) throw mtpErrorUnexpected(cons, "MTPgeochats_statedMessage"); + + if (!data) setData(new MTPDgeochats_statedMessage()); + MTPDgeochats_statedMessage &v(_geochats_statedMessage()); + v.vmessage.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + v.vseq.read(from, end); +} +inline void MTPgeochats_statedMessage::write(mtpBuffer &to) const { + const MTPDgeochats_statedMessage &v(c_geochats_statedMessage()); + v.vmessage.write(to); + v.vchats.write(to); + v.vusers.write(to); + v.vseq.write(to); +} +inline MTPgeochats_statedMessage::MTPgeochats_statedMessage(MTPDgeochats_statedMessage *_data) : mtpDataOwner(_data) { +} +inline MTPgeochats_statedMessage MTP_geochats_statedMessage(const MTPGeoChatMessage &_message, const MTPVector &_chats, const MTPVector &_users, MTPint _seq) { + return MTPgeochats_statedMessage(new MTPDgeochats_statedMessage(_message, _chats, _users, _seq)); +} + +inline MTPgeochats_located::MTPgeochats_located() : mtpDataOwner(new MTPDgeochats_located()) { +} + +inline uint32 MTPgeochats_located::size() const { + const MTPDgeochats_located &v(c_geochats_located()); + return v.vresults.size() + v.vmessages.size() + v.vchats.size() + v.vusers.size(); +} +inline mtpTypeId MTPgeochats_located::type() const { + return mtpc_geochats_located; +} +inline void MTPgeochats_located::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_geochats_located) throw mtpErrorUnexpected(cons, "MTPgeochats_located"); + + if (!data) setData(new MTPDgeochats_located()); + MTPDgeochats_located &v(_geochats_located()); + v.vresults.read(from, end); + v.vmessages.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); +} +inline void MTPgeochats_located::write(mtpBuffer &to) const { + const MTPDgeochats_located &v(c_geochats_located()); + v.vresults.write(to); + v.vmessages.write(to); + v.vchats.write(to); + v.vusers.write(to); +} +inline MTPgeochats_located::MTPgeochats_located(MTPDgeochats_located *_data) : mtpDataOwner(_data) { +} +inline MTPgeochats_located MTP_geochats_located(const MTPVector &_results, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) { + return MTPgeochats_located(new MTPDgeochats_located(_results, _messages, _chats, _users)); +} + +inline uint32 MTPgeochats_messages::size() const { + switch (_type) { + case mtpc_geochats_messages: { + const MTPDgeochats_messages &v(c_geochats_messages()); + return v.vmessages.size() + v.vchats.size() + v.vusers.size(); + } + case mtpc_geochats_messagesSlice: { + const MTPDgeochats_messagesSlice &v(c_geochats_messagesSlice()); + return v.vcount.size() + v.vmessages.size() + v.vchats.size() + v.vusers.size(); + } + } + return 0; +} +inline mtpTypeId MTPgeochats_messages::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPgeochats_messages::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_geochats_messages: _type = cons; { + if (!data) setData(new MTPDgeochats_messages()); + MTPDgeochats_messages &v(_geochats_messages()); + v.vmessages.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + } break; + case mtpc_geochats_messagesSlice: _type = cons; { + if (!data) setData(new MTPDgeochats_messagesSlice()); + MTPDgeochats_messagesSlice &v(_geochats_messagesSlice()); + v.vcount.read(from, end); + v.vmessages.read(from, end); + v.vchats.read(from, end); + v.vusers.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPgeochats_messages"); + } +} +inline void MTPgeochats_messages::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_geochats_messages: { + const MTPDgeochats_messages &v(c_geochats_messages()); + v.vmessages.write(to); + v.vchats.write(to); + v.vusers.write(to); + } break; + case mtpc_geochats_messagesSlice: { + const MTPDgeochats_messagesSlice &v(c_geochats_messagesSlice()); + v.vcount.write(to); + v.vmessages.write(to); + v.vchats.write(to); + v.vusers.write(to); + } break; + } +} +inline MTPgeochats_messages::MTPgeochats_messages(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_geochats_messages: setData(new MTPDgeochats_messages()); break; + case mtpc_geochats_messagesSlice: setData(new MTPDgeochats_messagesSlice()); break; + default: throw mtpErrorBadTypeId(type, "MTPgeochats_messages"); + } +} +inline MTPgeochats_messages::MTPgeochats_messages(MTPDgeochats_messages *_data) : _type(mtpc_geochats_messages), mtpDataOwner(_data) { +} +inline MTPgeochats_messages::MTPgeochats_messages(MTPDgeochats_messagesSlice *_data) : _type(mtpc_geochats_messagesSlice), mtpDataOwner(_data) { +} +inline MTPgeochats_messages MTP_geochats_messages(const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) { + return MTPgeochats_messages(new MTPDgeochats_messages(_messages, _chats, _users)); +} +inline MTPgeochats_messages MTP_geochats_messagesSlice(MTPint _count, const MTPVector &_messages, const MTPVector &_chats, const MTPVector &_users) { + return MTPgeochats_messages(new MTPDgeochats_messagesSlice(_count, _messages, _chats, _users)); +} + +inline uint32 MTPencryptedChat::size() const { + switch (_type) { + case mtpc_encryptedChatEmpty: { + const MTPDencryptedChatEmpty &v(c_encryptedChatEmpty()); + return v.vid.size(); + } + case mtpc_encryptedChatWaiting: { + const MTPDencryptedChatWaiting &v(c_encryptedChatWaiting()); + return v.vid.size() + v.vaccess_hash.size() + v.vdate.size() + v.vadmin_id.size() + v.vparticipant_id.size(); + } + case mtpc_encryptedChatRequested: { + const MTPDencryptedChatRequested &v(c_encryptedChatRequested()); + return v.vid.size() + v.vaccess_hash.size() + v.vdate.size() + v.vadmin_id.size() + v.vparticipant_id.size() + v.vg_a.size(); + } + case mtpc_encryptedChat: { + const MTPDencryptedChat &v(c_encryptedChat()); + return v.vid.size() + v.vaccess_hash.size() + v.vdate.size() + v.vadmin_id.size() + v.vparticipant_id.size() + v.vg_a_or_b.size() + v.vkey_fingerprint.size(); + } + case mtpc_encryptedChatDiscarded: { + const MTPDencryptedChatDiscarded &v(c_encryptedChatDiscarded()); + return v.vid.size(); + } + } + return 0; +} +inline mtpTypeId MTPencryptedChat::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPencryptedChat::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_encryptedChatEmpty: _type = cons; { + if (!data) setData(new MTPDencryptedChatEmpty()); + MTPDencryptedChatEmpty &v(_encryptedChatEmpty()); + v.vid.read(from, end); + } break; + case mtpc_encryptedChatWaiting: _type = cons; { + if (!data) setData(new MTPDencryptedChatWaiting()); + MTPDencryptedChatWaiting &v(_encryptedChatWaiting()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + v.vdate.read(from, end); + v.vadmin_id.read(from, end); + v.vparticipant_id.read(from, end); + } break; + case mtpc_encryptedChatRequested: _type = cons; { + if (!data) setData(new MTPDencryptedChatRequested()); + MTPDencryptedChatRequested &v(_encryptedChatRequested()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + v.vdate.read(from, end); + v.vadmin_id.read(from, end); + v.vparticipant_id.read(from, end); + v.vg_a.read(from, end); + } break; + case mtpc_encryptedChat: _type = cons; { + if (!data) setData(new MTPDencryptedChat()); + MTPDencryptedChat &v(_encryptedChat()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + v.vdate.read(from, end); + v.vadmin_id.read(from, end); + v.vparticipant_id.read(from, end); + v.vg_a_or_b.read(from, end); + v.vkey_fingerprint.read(from, end); + } break; + case mtpc_encryptedChatDiscarded: _type = cons; { + if (!data) setData(new MTPDencryptedChatDiscarded()); + MTPDencryptedChatDiscarded &v(_encryptedChatDiscarded()); + v.vid.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPencryptedChat"); + } +} +inline void MTPencryptedChat::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_encryptedChatEmpty: { + const MTPDencryptedChatEmpty &v(c_encryptedChatEmpty()); + v.vid.write(to); + } break; + case mtpc_encryptedChatWaiting: { + const MTPDencryptedChatWaiting &v(c_encryptedChatWaiting()); + v.vid.write(to); + v.vaccess_hash.write(to); + v.vdate.write(to); + v.vadmin_id.write(to); + v.vparticipant_id.write(to); + } break; + case mtpc_encryptedChatRequested: { + const MTPDencryptedChatRequested &v(c_encryptedChatRequested()); + v.vid.write(to); + v.vaccess_hash.write(to); + v.vdate.write(to); + v.vadmin_id.write(to); + v.vparticipant_id.write(to); + v.vg_a.write(to); + } break; + case mtpc_encryptedChat: { + const MTPDencryptedChat &v(c_encryptedChat()); + v.vid.write(to); + v.vaccess_hash.write(to); + v.vdate.write(to); + v.vadmin_id.write(to); + v.vparticipant_id.write(to); + v.vg_a_or_b.write(to); + v.vkey_fingerprint.write(to); + } break; + case mtpc_encryptedChatDiscarded: { + const MTPDencryptedChatDiscarded &v(c_encryptedChatDiscarded()); + v.vid.write(to); + } break; + } +} +inline MTPencryptedChat::MTPencryptedChat(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_encryptedChatEmpty: setData(new MTPDencryptedChatEmpty()); break; + case mtpc_encryptedChatWaiting: setData(new MTPDencryptedChatWaiting()); break; + case mtpc_encryptedChatRequested: setData(new MTPDencryptedChatRequested()); break; + case mtpc_encryptedChat: setData(new MTPDencryptedChat()); break; + case mtpc_encryptedChatDiscarded: setData(new MTPDencryptedChatDiscarded()); break; + default: throw mtpErrorBadTypeId(type, "MTPencryptedChat"); + } +} +inline MTPencryptedChat::MTPencryptedChat(MTPDencryptedChatEmpty *_data) : _type(mtpc_encryptedChatEmpty), mtpDataOwner(_data) { +} +inline MTPencryptedChat::MTPencryptedChat(MTPDencryptedChatWaiting *_data) : _type(mtpc_encryptedChatWaiting), mtpDataOwner(_data) { +} +inline MTPencryptedChat::MTPencryptedChat(MTPDencryptedChatRequested *_data) : _type(mtpc_encryptedChatRequested), mtpDataOwner(_data) { +} +inline MTPencryptedChat::MTPencryptedChat(MTPDencryptedChat *_data) : _type(mtpc_encryptedChat), mtpDataOwner(_data) { +} +inline MTPencryptedChat::MTPencryptedChat(MTPDencryptedChatDiscarded *_data) : _type(mtpc_encryptedChatDiscarded), mtpDataOwner(_data) { +} +inline MTPencryptedChat MTP_encryptedChatEmpty(MTPint _id) { + return MTPencryptedChat(new MTPDencryptedChatEmpty(_id)); +} +inline MTPencryptedChat MTP_encryptedChatWaiting(MTPint _id, const MTPlong &_access_hash, MTPint _date, MTPint _admin_id, MTPint _participant_id) { + return MTPencryptedChat(new MTPDencryptedChatWaiting(_id, _access_hash, _date, _admin_id, _participant_id)); +} +inline MTPencryptedChat MTP_encryptedChatRequested(MTPint _id, const MTPlong &_access_hash, MTPint _date, MTPint _admin_id, MTPint _participant_id, const MTPbytes &_g_a) { + return MTPencryptedChat(new MTPDencryptedChatRequested(_id, _access_hash, _date, _admin_id, _participant_id, _g_a)); +} +inline MTPencryptedChat MTP_encryptedChat(MTPint _id, const MTPlong &_access_hash, MTPint _date, MTPint _admin_id, MTPint _participant_id, const MTPbytes &_g_a_or_b, const MTPlong &_key_fingerprint) { + return MTPencryptedChat(new MTPDencryptedChat(_id, _access_hash, _date, _admin_id, _participant_id, _g_a_or_b, _key_fingerprint)); +} +inline MTPencryptedChat MTP_encryptedChatDiscarded(MTPint _id) { + return MTPencryptedChat(new MTPDencryptedChatDiscarded(_id)); +} + +inline MTPinputEncryptedChat::MTPinputEncryptedChat() : mtpDataOwner(new MTPDinputEncryptedChat()) { +} + +inline uint32 MTPinputEncryptedChat::size() const { + const MTPDinputEncryptedChat &v(c_inputEncryptedChat()); + return v.vchat_id.size() + v.vaccess_hash.size(); +} +inline mtpTypeId MTPinputEncryptedChat::type() const { + return mtpc_inputEncryptedChat; +} +inline void MTPinputEncryptedChat::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_inputEncryptedChat) throw mtpErrorUnexpected(cons, "MTPinputEncryptedChat"); + + if (!data) setData(new MTPDinputEncryptedChat()); + MTPDinputEncryptedChat &v(_inputEncryptedChat()); + v.vchat_id.read(from, end); + v.vaccess_hash.read(from, end); +} +inline void MTPinputEncryptedChat::write(mtpBuffer &to) const { + const MTPDinputEncryptedChat &v(c_inputEncryptedChat()); + v.vchat_id.write(to); + v.vaccess_hash.write(to); +} +inline MTPinputEncryptedChat::MTPinputEncryptedChat(MTPDinputEncryptedChat *_data) : mtpDataOwner(_data) { +} +inline MTPinputEncryptedChat MTP_inputEncryptedChat(MTPint _chat_id, const MTPlong &_access_hash) { + return MTPinputEncryptedChat(new MTPDinputEncryptedChat(_chat_id, _access_hash)); +} + +inline uint32 MTPencryptedFile::size() const { + switch (_type) { + case mtpc_encryptedFile: { + const MTPDencryptedFile &v(c_encryptedFile()); + return v.vid.size() + v.vaccess_hash.size() + v.vsize.size() + v.vdc_id.size() + v.vkey_fingerprint.size(); + } + } + return 0; +} +inline mtpTypeId MTPencryptedFile::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPencryptedFile::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_encryptedFileEmpty: _type = cons; break; + case mtpc_encryptedFile: _type = cons; { + if (!data) setData(new MTPDencryptedFile()); + MTPDencryptedFile &v(_encryptedFile()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + v.vsize.read(from, end); + v.vdc_id.read(from, end); + v.vkey_fingerprint.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPencryptedFile"); + } +} +inline void MTPencryptedFile::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_encryptedFile: { + const MTPDencryptedFile &v(c_encryptedFile()); + v.vid.write(to); + v.vaccess_hash.write(to); + v.vsize.write(to); + v.vdc_id.write(to); + v.vkey_fingerprint.write(to); + } break; + } +} +inline MTPencryptedFile::MTPencryptedFile(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_encryptedFileEmpty: break; + case mtpc_encryptedFile: setData(new MTPDencryptedFile()); break; + default: throw mtpErrorBadTypeId(type, "MTPencryptedFile"); + } +} +inline MTPencryptedFile::MTPencryptedFile(MTPDencryptedFile *_data) : _type(mtpc_encryptedFile), mtpDataOwner(_data) { +} +inline MTPencryptedFile MTP_encryptedFileEmpty() { + return MTPencryptedFile(mtpc_encryptedFileEmpty); +} +inline MTPencryptedFile MTP_encryptedFile(const MTPlong &_id, const MTPlong &_access_hash, MTPint _size, MTPint _dc_id, MTPint _key_fingerprint) { + return MTPencryptedFile(new MTPDencryptedFile(_id, _access_hash, _size, _dc_id, _key_fingerprint)); +} + +inline uint32 MTPinputEncryptedFile::size() const { + switch (_type) { + case mtpc_inputEncryptedFileUploaded: { + const MTPDinputEncryptedFileUploaded &v(c_inputEncryptedFileUploaded()); + return v.vid.size() + v.vparts.size() + v.vmd5_checksum.size() + v.vkey_fingerprint.size(); + } + case mtpc_inputEncryptedFile: { + const MTPDinputEncryptedFile &v(c_inputEncryptedFile()); + return v.vid.size() + v.vaccess_hash.size(); + } + case mtpc_inputEncryptedFileBigUploaded: { + const MTPDinputEncryptedFileBigUploaded &v(c_inputEncryptedFileBigUploaded()); + return v.vid.size() + v.vparts.size() + v.vkey_fingerprint.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputEncryptedFile::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputEncryptedFile::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputEncryptedFileEmpty: _type = cons; break; + case mtpc_inputEncryptedFileUploaded: _type = cons; { + if (!data) setData(new MTPDinputEncryptedFileUploaded()); + MTPDinputEncryptedFileUploaded &v(_inputEncryptedFileUploaded()); + v.vid.read(from, end); + v.vparts.read(from, end); + v.vmd5_checksum.read(from, end); + v.vkey_fingerprint.read(from, end); + } break; + case mtpc_inputEncryptedFile: _type = cons; { + if (!data) setData(new MTPDinputEncryptedFile()); + MTPDinputEncryptedFile &v(_inputEncryptedFile()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + } break; + case mtpc_inputEncryptedFileBigUploaded: _type = cons; { + if (!data) setData(new MTPDinputEncryptedFileBigUploaded()); + MTPDinputEncryptedFileBigUploaded &v(_inputEncryptedFileBigUploaded()); + v.vid.read(from, end); + v.vparts.read(from, end); + v.vkey_fingerprint.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputEncryptedFile"); + } +} +inline void MTPinputEncryptedFile::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputEncryptedFileUploaded: { + const MTPDinputEncryptedFileUploaded &v(c_inputEncryptedFileUploaded()); + v.vid.write(to); + v.vparts.write(to); + v.vmd5_checksum.write(to); + v.vkey_fingerprint.write(to); + } break; + case mtpc_inputEncryptedFile: { + const MTPDinputEncryptedFile &v(c_inputEncryptedFile()); + v.vid.write(to); + v.vaccess_hash.write(to); + } break; + case mtpc_inputEncryptedFileBigUploaded: { + const MTPDinputEncryptedFileBigUploaded &v(c_inputEncryptedFileBigUploaded()); + v.vid.write(to); + v.vparts.write(to); + v.vkey_fingerprint.write(to); + } break; + } +} +inline MTPinputEncryptedFile::MTPinputEncryptedFile(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputEncryptedFileEmpty: break; + case mtpc_inputEncryptedFileUploaded: setData(new MTPDinputEncryptedFileUploaded()); break; + case mtpc_inputEncryptedFile: setData(new MTPDinputEncryptedFile()); break; + case mtpc_inputEncryptedFileBigUploaded: setData(new MTPDinputEncryptedFileBigUploaded()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputEncryptedFile"); + } +} +inline MTPinputEncryptedFile::MTPinputEncryptedFile(MTPDinputEncryptedFileUploaded *_data) : _type(mtpc_inputEncryptedFileUploaded), mtpDataOwner(_data) { +} +inline MTPinputEncryptedFile::MTPinputEncryptedFile(MTPDinputEncryptedFile *_data) : _type(mtpc_inputEncryptedFile), mtpDataOwner(_data) { +} +inline MTPinputEncryptedFile::MTPinputEncryptedFile(MTPDinputEncryptedFileBigUploaded *_data) : _type(mtpc_inputEncryptedFileBigUploaded), mtpDataOwner(_data) { +} +inline MTPinputEncryptedFile MTP_inputEncryptedFileEmpty() { + return MTPinputEncryptedFile(mtpc_inputEncryptedFileEmpty); +} +inline MTPinputEncryptedFile MTP_inputEncryptedFileUploaded(const MTPlong &_id, MTPint _parts, const MTPstring &_md5_checksum, MTPint _key_fingerprint) { + return MTPinputEncryptedFile(new MTPDinputEncryptedFileUploaded(_id, _parts, _md5_checksum, _key_fingerprint)); +} +inline MTPinputEncryptedFile MTP_inputEncryptedFile(const MTPlong &_id, const MTPlong &_access_hash) { + return MTPinputEncryptedFile(new MTPDinputEncryptedFile(_id, _access_hash)); +} +inline MTPinputEncryptedFile MTP_inputEncryptedFileBigUploaded(const MTPlong &_id, MTPint _parts, MTPint _key_fingerprint) { + return MTPinputEncryptedFile(new MTPDinputEncryptedFileBigUploaded(_id, _parts, _key_fingerprint)); +} + +inline uint32 MTPencryptedMessage::size() const { + switch (_type) { + case mtpc_encryptedMessage: { + const MTPDencryptedMessage &v(c_encryptedMessage()); + return v.vrandom_id.size() + v.vchat_id.size() + v.vdate.size() + v.vbytes.size() + v.vfile.size(); + } + case mtpc_encryptedMessageService: { + const MTPDencryptedMessageService &v(c_encryptedMessageService()); + return v.vrandom_id.size() + v.vchat_id.size() + v.vdate.size() + v.vbytes.size(); + } + } + return 0; +} +inline mtpTypeId MTPencryptedMessage::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPencryptedMessage::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_encryptedMessage: _type = cons; { + if (!data) setData(new MTPDencryptedMessage()); + MTPDencryptedMessage &v(_encryptedMessage()); + v.vrandom_id.read(from, end); + v.vchat_id.read(from, end); + v.vdate.read(from, end); + v.vbytes.read(from, end); + v.vfile.read(from, end); + } break; + case mtpc_encryptedMessageService: _type = cons; { + if (!data) setData(new MTPDencryptedMessageService()); + MTPDencryptedMessageService &v(_encryptedMessageService()); + v.vrandom_id.read(from, end); + v.vchat_id.read(from, end); + v.vdate.read(from, end); + v.vbytes.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPencryptedMessage"); + } +} +inline void MTPencryptedMessage::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_encryptedMessage: { + const MTPDencryptedMessage &v(c_encryptedMessage()); + v.vrandom_id.write(to); + v.vchat_id.write(to); + v.vdate.write(to); + v.vbytes.write(to); + v.vfile.write(to); + } break; + case mtpc_encryptedMessageService: { + const MTPDencryptedMessageService &v(c_encryptedMessageService()); + v.vrandom_id.write(to); + v.vchat_id.write(to); + v.vdate.write(to); + v.vbytes.write(to); + } break; + } +} +inline MTPencryptedMessage::MTPencryptedMessage(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_encryptedMessage: setData(new MTPDencryptedMessage()); break; + case mtpc_encryptedMessageService: setData(new MTPDencryptedMessageService()); break; + default: throw mtpErrorBadTypeId(type, "MTPencryptedMessage"); + } +} +inline MTPencryptedMessage::MTPencryptedMessage(MTPDencryptedMessage *_data) : _type(mtpc_encryptedMessage), mtpDataOwner(_data) { +} +inline MTPencryptedMessage::MTPencryptedMessage(MTPDencryptedMessageService *_data) : _type(mtpc_encryptedMessageService), mtpDataOwner(_data) { +} +inline MTPencryptedMessage MTP_encryptedMessage(const MTPlong &_random_id, MTPint _chat_id, MTPint _date, const MTPbytes &_bytes, const MTPEncryptedFile &_file) { + return MTPencryptedMessage(new MTPDencryptedMessage(_random_id, _chat_id, _date, _bytes, _file)); +} +inline MTPencryptedMessage MTP_encryptedMessageService(const MTPlong &_random_id, MTPint _chat_id, MTPint _date, const MTPbytes &_bytes) { + return MTPencryptedMessage(new MTPDencryptedMessageService(_random_id, _chat_id, _date, _bytes)); +} + +inline MTPdecryptedMessageLayer::MTPdecryptedMessageLayer() : mtpDataOwner(new MTPDdecryptedMessageLayer()) { +} + +inline uint32 MTPdecryptedMessageLayer::size() const { + const MTPDdecryptedMessageLayer &v(c_decryptedMessageLayer()); + return v.vlayer.size() + v.vmessage.size(); +} +inline mtpTypeId MTPdecryptedMessageLayer::type() const { + return mtpc_decryptedMessageLayer; +} +inline void MTPdecryptedMessageLayer::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_decryptedMessageLayer) throw mtpErrorUnexpected(cons, "MTPdecryptedMessageLayer"); + + if (!data) setData(new MTPDdecryptedMessageLayer()); + MTPDdecryptedMessageLayer &v(_decryptedMessageLayer()); + v.vlayer.read(from, end); + v.vmessage.read(from, end); +} +inline void MTPdecryptedMessageLayer::write(mtpBuffer &to) const { + const MTPDdecryptedMessageLayer &v(c_decryptedMessageLayer()); + v.vlayer.write(to); + v.vmessage.write(to); +} +inline MTPdecryptedMessageLayer::MTPdecryptedMessageLayer(MTPDdecryptedMessageLayer *_data) : mtpDataOwner(_data) { +} +inline MTPdecryptedMessageLayer MTP_decryptedMessageLayer(MTPint _layer, const MTPDecryptedMessage &_message) { + return MTPdecryptedMessageLayer(new MTPDdecryptedMessageLayer(_layer, _message)); +} + +inline uint32 MTPdecryptedMessage::size() const { + switch (_type) { + case mtpc_decryptedMessage: { + const MTPDdecryptedMessage &v(c_decryptedMessage()); + return v.vrandom_id.size() + v.vrandom_bytes.size() + v.vmessage.size() + v.vmedia.size(); + } + case mtpc_decryptedMessageService: { + const MTPDdecryptedMessageService &v(c_decryptedMessageService()); + return v.vrandom_id.size() + v.vrandom_bytes.size() + v.vaction.size(); + } + } + return 0; +} +inline mtpTypeId MTPdecryptedMessage::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPdecryptedMessage::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_decryptedMessage: _type = cons; { + if (!data) setData(new MTPDdecryptedMessage()); + MTPDdecryptedMessage &v(_decryptedMessage()); + v.vrandom_id.read(from, end); + v.vrandom_bytes.read(from, end); + v.vmessage.read(from, end); + v.vmedia.read(from, end); + } break; + case mtpc_decryptedMessageService: _type = cons; { + if (!data) setData(new MTPDdecryptedMessageService()); + MTPDdecryptedMessageService &v(_decryptedMessageService()); + v.vrandom_id.read(from, end); + v.vrandom_bytes.read(from, end); + v.vaction.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPdecryptedMessage"); + } +} +inline void MTPdecryptedMessage::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_decryptedMessage: { + const MTPDdecryptedMessage &v(c_decryptedMessage()); + v.vrandom_id.write(to); + v.vrandom_bytes.write(to); + v.vmessage.write(to); + v.vmedia.write(to); + } break; + case mtpc_decryptedMessageService: { + const MTPDdecryptedMessageService &v(c_decryptedMessageService()); + v.vrandom_id.write(to); + v.vrandom_bytes.write(to); + v.vaction.write(to); + } break; + } +} +inline MTPdecryptedMessage::MTPdecryptedMessage(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_decryptedMessage: setData(new MTPDdecryptedMessage()); break; + case mtpc_decryptedMessageService: setData(new MTPDdecryptedMessageService()); break; + default: throw mtpErrorBadTypeId(type, "MTPdecryptedMessage"); + } +} +inline MTPdecryptedMessage::MTPdecryptedMessage(MTPDdecryptedMessage *_data) : _type(mtpc_decryptedMessage), mtpDataOwner(_data) { +} +inline MTPdecryptedMessage::MTPdecryptedMessage(MTPDdecryptedMessageService *_data) : _type(mtpc_decryptedMessageService), mtpDataOwner(_data) { +} +inline MTPdecryptedMessage MTP_decryptedMessage(const MTPlong &_random_id, const MTPbytes &_random_bytes, const MTPstring &_message, const MTPDecryptedMessageMedia &_media) { + return MTPdecryptedMessage(new MTPDdecryptedMessage(_random_id, _random_bytes, _message, _media)); +} +inline MTPdecryptedMessage MTP_decryptedMessageService(const MTPlong &_random_id, const MTPbytes &_random_bytes, const MTPDecryptedMessageAction &_action) { + return MTPdecryptedMessage(new MTPDdecryptedMessageService(_random_id, _random_bytes, _action)); +} + +inline uint32 MTPdecryptedMessageMedia::size() const { + switch (_type) { + case mtpc_decryptedMessageMediaPhoto: { + const MTPDdecryptedMessageMediaPhoto &v(c_decryptedMessageMediaPhoto()); + return v.vthumb.size() + v.vthumb_w.size() + v.vthumb_h.size() + v.vw.size() + v.vh.size() + v.vsize.size() + v.vkey.size() + v.viv.size(); + } + case mtpc_decryptedMessageMediaVideo: { + const MTPDdecryptedMessageMediaVideo &v(c_decryptedMessageMediaVideo()); + return v.vthumb.size() + v.vthumb_w.size() + v.vthumb_h.size() + v.vduration.size() + v.vmime_type.size() + v.vw.size() + v.vh.size() + v.vsize.size() + v.vkey.size() + v.viv.size(); + } + case mtpc_decryptedMessageMediaGeoPoint: { + const MTPDdecryptedMessageMediaGeoPoint &v(c_decryptedMessageMediaGeoPoint()); + return v.vlat.size() + v.vlong.size(); + } + case mtpc_decryptedMessageMediaContact: { + const MTPDdecryptedMessageMediaContact &v(c_decryptedMessageMediaContact()); + return v.vphone_number.size() + v.vfirst_name.size() + v.vlast_name.size() + v.vuser_id.size(); + } + case mtpc_decryptedMessageMediaDocument: { + const MTPDdecryptedMessageMediaDocument &v(c_decryptedMessageMediaDocument()); + return v.vthumb.size() + v.vthumb_w.size() + v.vthumb_h.size() + v.vfile_name.size() + v.vmime_type.size() + v.vsize.size() + v.vkey.size() + v.viv.size(); + } + case mtpc_decryptedMessageMediaAudio: { + const MTPDdecryptedMessageMediaAudio &v(c_decryptedMessageMediaAudio()); + return v.vduration.size() + v.vmime_type.size() + v.vsize.size() + v.vkey.size() + v.viv.size(); + } + } + return 0; +} +inline mtpTypeId MTPdecryptedMessageMedia::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPdecryptedMessageMedia::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_decryptedMessageMediaEmpty: _type = cons; break; + case mtpc_decryptedMessageMediaPhoto: _type = cons; { + if (!data) setData(new MTPDdecryptedMessageMediaPhoto()); + MTPDdecryptedMessageMediaPhoto &v(_decryptedMessageMediaPhoto()); + v.vthumb.read(from, end); + v.vthumb_w.read(from, end); + v.vthumb_h.read(from, end); + v.vw.read(from, end); + v.vh.read(from, end); + v.vsize.read(from, end); + v.vkey.read(from, end); + v.viv.read(from, end); + } break; + case mtpc_decryptedMessageMediaVideo: _type = cons; { + if (!data) setData(new MTPDdecryptedMessageMediaVideo()); + MTPDdecryptedMessageMediaVideo &v(_decryptedMessageMediaVideo()); + v.vthumb.read(from, end); + v.vthumb_w.read(from, end); + v.vthumb_h.read(from, end); + v.vduration.read(from, end); + v.vmime_type.read(from, end); + v.vw.read(from, end); + v.vh.read(from, end); + v.vsize.read(from, end); + v.vkey.read(from, end); + v.viv.read(from, end); + } break; + case mtpc_decryptedMessageMediaGeoPoint: _type = cons; { + if (!data) setData(new MTPDdecryptedMessageMediaGeoPoint()); + MTPDdecryptedMessageMediaGeoPoint &v(_decryptedMessageMediaGeoPoint()); + v.vlat.read(from, end); + v.vlong.read(from, end); + } break; + case mtpc_decryptedMessageMediaContact: _type = cons; { + if (!data) setData(new MTPDdecryptedMessageMediaContact()); + MTPDdecryptedMessageMediaContact &v(_decryptedMessageMediaContact()); + v.vphone_number.read(from, end); + v.vfirst_name.read(from, end); + v.vlast_name.read(from, end); + v.vuser_id.read(from, end); + } break; + case mtpc_decryptedMessageMediaDocument: _type = cons; { + if (!data) setData(new MTPDdecryptedMessageMediaDocument()); + MTPDdecryptedMessageMediaDocument &v(_decryptedMessageMediaDocument()); + v.vthumb.read(from, end); + v.vthumb_w.read(from, end); + v.vthumb_h.read(from, end); + v.vfile_name.read(from, end); + v.vmime_type.read(from, end); + v.vsize.read(from, end); + v.vkey.read(from, end); + v.viv.read(from, end); + } break; + case mtpc_decryptedMessageMediaAudio: _type = cons; { + if (!data) setData(new MTPDdecryptedMessageMediaAudio()); + MTPDdecryptedMessageMediaAudio &v(_decryptedMessageMediaAudio()); + v.vduration.read(from, end); + v.vmime_type.read(from, end); + v.vsize.read(from, end); + v.vkey.read(from, end); + v.viv.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPdecryptedMessageMedia"); + } +} +inline void MTPdecryptedMessageMedia::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_decryptedMessageMediaPhoto: { + const MTPDdecryptedMessageMediaPhoto &v(c_decryptedMessageMediaPhoto()); + v.vthumb.write(to); + v.vthumb_w.write(to); + v.vthumb_h.write(to); + v.vw.write(to); + v.vh.write(to); + v.vsize.write(to); + v.vkey.write(to); + v.viv.write(to); + } break; + case mtpc_decryptedMessageMediaVideo: { + const MTPDdecryptedMessageMediaVideo &v(c_decryptedMessageMediaVideo()); + v.vthumb.write(to); + v.vthumb_w.write(to); + v.vthumb_h.write(to); + v.vduration.write(to); + v.vmime_type.write(to); + v.vw.write(to); + v.vh.write(to); + v.vsize.write(to); + v.vkey.write(to); + v.viv.write(to); + } break; + case mtpc_decryptedMessageMediaGeoPoint: { + const MTPDdecryptedMessageMediaGeoPoint &v(c_decryptedMessageMediaGeoPoint()); + v.vlat.write(to); + v.vlong.write(to); + } break; + case mtpc_decryptedMessageMediaContact: { + const MTPDdecryptedMessageMediaContact &v(c_decryptedMessageMediaContact()); + v.vphone_number.write(to); + v.vfirst_name.write(to); + v.vlast_name.write(to); + v.vuser_id.write(to); + } break; + case mtpc_decryptedMessageMediaDocument: { + const MTPDdecryptedMessageMediaDocument &v(c_decryptedMessageMediaDocument()); + v.vthumb.write(to); + v.vthumb_w.write(to); + v.vthumb_h.write(to); + v.vfile_name.write(to); + v.vmime_type.write(to); + v.vsize.write(to); + v.vkey.write(to); + v.viv.write(to); + } break; + case mtpc_decryptedMessageMediaAudio: { + const MTPDdecryptedMessageMediaAudio &v(c_decryptedMessageMediaAudio()); + v.vduration.write(to); + v.vmime_type.write(to); + v.vsize.write(to); + v.vkey.write(to); + v.viv.write(to); + } break; + } +} +inline MTPdecryptedMessageMedia::MTPdecryptedMessageMedia(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_decryptedMessageMediaEmpty: break; + case mtpc_decryptedMessageMediaPhoto: setData(new MTPDdecryptedMessageMediaPhoto()); break; + case mtpc_decryptedMessageMediaVideo: setData(new MTPDdecryptedMessageMediaVideo()); break; + case mtpc_decryptedMessageMediaGeoPoint: setData(new MTPDdecryptedMessageMediaGeoPoint()); break; + case mtpc_decryptedMessageMediaContact: setData(new MTPDdecryptedMessageMediaContact()); break; + case mtpc_decryptedMessageMediaDocument: setData(new MTPDdecryptedMessageMediaDocument()); break; + case mtpc_decryptedMessageMediaAudio: setData(new MTPDdecryptedMessageMediaAudio()); break; + default: throw mtpErrorBadTypeId(type, "MTPdecryptedMessageMedia"); + } +} +inline MTPdecryptedMessageMedia::MTPdecryptedMessageMedia(MTPDdecryptedMessageMediaPhoto *_data) : _type(mtpc_decryptedMessageMediaPhoto), mtpDataOwner(_data) { +} +inline MTPdecryptedMessageMedia::MTPdecryptedMessageMedia(MTPDdecryptedMessageMediaVideo *_data) : _type(mtpc_decryptedMessageMediaVideo), mtpDataOwner(_data) { +} +inline MTPdecryptedMessageMedia::MTPdecryptedMessageMedia(MTPDdecryptedMessageMediaGeoPoint *_data) : _type(mtpc_decryptedMessageMediaGeoPoint), mtpDataOwner(_data) { +} +inline MTPdecryptedMessageMedia::MTPdecryptedMessageMedia(MTPDdecryptedMessageMediaContact *_data) : _type(mtpc_decryptedMessageMediaContact), mtpDataOwner(_data) { +} +inline MTPdecryptedMessageMedia::MTPdecryptedMessageMedia(MTPDdecryptedMessageMediaDocument *_data) : _type(mtpc_decryptedMessageMediaDocument), mtpDataOwner(_data) { +} +inline MTPdecryptedMessageMedia::MTPdecryptedMessageMedia(MTPDdecryptedMessageMediaAudio *_data) : _type(mtpc_decryptedMessageMediaAudio), mtpDataOwner(_data) { +} +inline MTPdecryptedMessageMedia MTP_decryptedMessageMediaEmpty() { + return MTPdecryptedMessageMedia(mtpc_decryptedMessageMediaEmpty); +} +inline MTPdecryptedMessageMedia MTP_decryptedMessageMediaPhoto(const MTPbytes &_thumb, MTPint _thumb_w, MTPint _thumb_h, MTPint _w, MTPint _h, MTPint _size, const MTPbytes &_key, const MTPbytes &_iv) { + return MTPdecryptedMessageMedia(new MTPDdecryptedMessageMediaPhoto(_thumb, _thumb_w, _thumb_h, _w, _h, _size, _key, _iv)); +} +inline MTPdecryptedMessageMedia MTP_decryptedMessageMediaVideo(const MTPbytes &_thumb, MTPint _thumb_w, MTPint _thumb_h, MTPint _duration, const MTPstring &_mime_type, MTPint _w, MTPint _h, MTPint _size, const MTPbytes &_key, const MTPbytes &_iv) { + return MTPdecryptedMessageMedia(new MTPDdecryptedMessageMediaVideo(_thumb, _thumb_w, _thumb_h, _duration, _mime_type, _w, _h, _size, _key, _iv)); +} +inline MTPdecryptedMessageMedia MTP_decryptedMessageMediaGeoPoint(const MTPdouble &_lat, const MTPdouble &_long) { + return MTPdecryptedMessageMedia(new MTPDdecryptedMessageMediaGeoPoint(_lat, _long)); +} +inline MTPdecryptedMessageMedia MTP_decryptedMessageMediaContact(const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name, MTPint _user_id) { + return MTPdecryptedMessageMedia(new MTPDdecryptedMessageMediaContact(_phone_number, _first_name, _last_name, _user_id)); +} +inline MTPdecryptedMessageMedia MTP_decryptedMessageMediaDocument(const MTPbytes &_thumb, MTPint _thumb_w, MTPint _thumb_h, const MTPstring &_file_name, const MTPstring &_mime_type, MTPint _size, const MTPbytes &_key, const MTPbytes &_iv) { + return MTPdecryptedMessageMedia(new MTPDdecryptedMessageMediaDocument(_thumb, _thumb_w, _thumb_h, _file_name, _mime_type, _size, _key, _iv)); +} +inline MTPdecryptedMessageMedia MTP_decryptedMessageMediaAudio(MTPint _duration, const MTPstring &_mime_type, MTPint _size, const MTPbytes &_key, const MTPbytes &_iv) { + return MTPdecryptedMessageMedia(new MTPDdecryptedMessageMediaAudio(_duration, _mime_type, _size, _key, _iv)); +} + +inline uint32 MTPdecryptedMessageAction::size() const { + switch (_type) { + case mtpc_decryptedMessageActionSetMessageTTL: { + const MTPDdecryptedMessageActionSetMessageTTL &v(c_decryptedMessageActionSetMessageTTL()); + return v.vttl_seconds.size(); + } + case mtpc_decryptedMessageActionReadMessages: { + const MTPDdecryptedMessageActionReadMessages &v(c_decryptedMessageActionReadMessages()); + return v.vrandom_ids.size(); + } + case mtpc_decryptedMessageActionDeleteMessages: { + const MTPDdecryptedMessageActionDeleteMessages &v(c_decryptedMessageActionDeleteMessages()); + return v.vrandom_ids.size(); + } + case mtpc_decryptedMessageActionScreenshotMessages: { + const MTPDdecryptedMessageActionScreenshotMessages &v(c_decryptedMessageActionScreenshotMessages()); + return v.vrandom_ids.size(); + } + case mtpc_decryptedMessageActionNotifyLayer: { + const MTPDdecryptedMessageActionNotifyLayer &v(c_decryptedMessageActionNotifyLayer()); + return v.vlayer.size(); + } + } + return 0; +} +inline mtpTypeId MTPdecryptedMessageAction::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPdecryptedMessageAction::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_decryptedMessageActionSetMessageTTL: _type = cons; { + if (!data) setData(new MTPDdecryptedMessageActionSetMessageTTL()); + MTPDdecryptedMessageActionSetMessageTTL &v(_decryptedMessageActionSetMessageTTL()); + v.vttl_seconds.read(from, end); + } break; + case mtpc_decryptedMessageActionReadMessages: _type = cons; { + if (!data) setData(new MTPDdecryptedMessageActionReadMessages()); + MTPDdecryptedMessageActionReadMessages &v(_decryptedMessageActionReadMessages()); + v.vrandom_ids.read(from, end); + } break; + case mtpc_decryptedMessageActionDeleteMessages: _type = cons; { + if (!data) setData(new MTPDdecryptedMessageActionDeleteMessages()); + MTPDdecryptedMessageActionDeleteMessages &v(_decryptedMessageActionDeleteMessages()); + v.vrandom_ids.read(from, end); + } break; + case mtpc_decryptedMessageActionScreenshotMessages: _type = cons; { + if (!data) setData(new MTPDdecryptedMessageActionScreenshotMessages()); + MTPDdecryptedMessageActionScreenshotMessages &v(_decryptedMessageActionScreenshotMessages()); + v.vrandom_ids.read(from, end); + } break; + case mtpc_decryptedMessageActionFlushHistory: _type = cons; break; + case mtpc_decryptedMessageActionNotifyLayer: _type = cons; { + if (!data) setData(new MTPDdecryptedMessageActionNotifyLayer()); + MTPDdecryptedMessageActionNotifyLayer &v(_decryptedMessageActionNotifyLayer()); + v.vlayer.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPdecryptedMessageAction"); + } +} +inline void MTPdecryptedMessageAction::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_decryptedMessageActionSetMessageTTL: { + const MTPDdecryptedMessageActionSetMessageTTL &v(c_decryptedMessageActionSetMessageTTL()); + v.vttl_seconds.write(to); + } break; + case mtpc_decryptedMessageActionReadMessages: { + const MTPDdecryptedMessageActionReadMessages &v(c_decryptedMessageActionReadMessages()); + v.vrandom_ids.write(to); + } break; + case mtpc_decryptedMessageActionDeleteMessages: { + const MTPDdecryptedMessageActionDeleteMessages &v(c_decryptedMessageActionDeleteMessages()); + v.vrandom_ids.write(to); + } break; + case mtpc_decryptedMessageActionScreenshotMessages: { + const MTPDdecryptedMessageActionScreenshotMessages &v(c_decryptedMessageActionScreenshotMessages()); + v.vrandom_ids.write(to); + } break; + case mtpc_decryptedMessageActionNotifyLayer: { + const MTPDdecryptedMessageActionNotifyLayer &v(c_decryptedMessageActionNotifyLayer()); + v.vlayer.write(to); + } break; + } +} +inline MTPdecryptedMessageAction::MTPdecryptedMessageAction(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_decryptedMessageActionSetMessageTTL: setData(new MTPDdecryptedMessageActionSetMessageTTL()); break; + case mtpc_decryptedMessageActionReadMessages: setData(new MTPDdecryptedMessageActionReadMessages()); break; + case mtpc_decryptedMessageActionDeleteMessages: setData(new MTPDdecryptedMessageActionDeleteMessages()); break; + case mtpc_decryptedMessageActionScreenshotMessages: setData(new MTPDdecryptedMessageActionScreenshotMessages()); break; + case mtpc_decryptedMessageActionFlushHistory: break; + case mtpc_decryptedMessageActionNotifyLayer: setData(new MTPDdecryptedMessageActionNotifyLayer()); break; + default: throw mtpErrorBadTypeId(type, "MTPdecryptedMessageAction"); + } +} +inline MTPdecryptedMessageAction::MTPdecryptedMessageAction(MTPDdecryptedMessageActionSetMessageTTL *_data) : _type(mtpc_decryptedMessageActionSetMessageTTL), mtpDataOwner(_data) { +} +inline MTPdecryptedMessageAction::MTPdecryptedMessageAction(MTPDdecryptedMessageActionReadMessages *_data) : _type(mtpc_decryptedMessageActionReadMessages), mtpDataOwner(_data) { +} +inline MTPdecryptedMessageAction::MTPdecryptedMessageAction(MTPDdecryptedMessageActionDeleteMessages *_data) : _type(mtpc_decryptedMessageActionDeleteMessages), mtpDataOwner(_data) { +} +inline MTPdecryptedMessageAction::MTPdecryptedMessageAction(MTPDdecryptedMessageActionScreenshotMessages *_data) : _type(mtpc_decryptedMessageActionScreenshotMessages), mtpDataOwner(_data) { +} +inline MTPdecryptedMessageAction::MTPdecryptedMessageAction(MTPDdecryptedMessageActionNotifyLayer *_data) : _type(mtpc_decryptedMessageActionNotifyLayer), mtpDataOwner(_data) { +} +inline MTPdecryptedMessageAction MTP_decryptedMessageActionSetMessageTTL(MTPint _ttl_seconds) { + return MTPdecryptedMessageAction(new MTPDdecryptedMessageActionSetMessageTTL(_ttl_seconds)); +} +inline MTPdecryptedMessageAction MTP_decryptedMessageActionReadMessages(const MTPVector &_random_ids) { + return MTPdecryptedMessageAction(new MTPDdecryptedMessageActionReadMessages(_random_ids)); +} +inline MTPdecryptedMessageAction MTP_decryptedMessageActionDeleteMessages(const MTPVector &_random_ids) { + return MTPdecryptedMessageAction(new MTPDdecryptedMessageActionDeleteMessages(_random_ids)); +} +inline MTPdecryptedMessageAction MTP_decryptedMessageActionScreenshotMessages(const MTPVector &_random_ids) { + return MTPdecryptedMessageAction(new MTPDdecryptedMessageActionScreenshotMessages(_random_ids)); +} +inline MTPdecryptedMessageAction MTP_decryptedMessageActionFlushHistory() { + return MTPdecryptedMessageAction(mtpc_decryptedMessageActionFlushHistory); +} +inline MTPdecryptedMessageAction MTP_decryptedMessageActionNotifyLayer(MTPint _layer) { + return MTPdecryptedMessageAction(new MTPDdecryptedMessageActionNotifyLayer(_layer)); +} + +inline uint32 MTPmessages_dhConfig::size() const { + switch (_type) { + case mtpc_messages_dhConfigNotModified: { + const MTPDmessages_dhConfigNotModified &v(c_messages_dhConfigNotModified()); + return v.vrandom.size(); + } + case mtpc_messages_dhConfig: { + const MTPDmessages_dhConfig &v(c_messages_dhConfig()); + return v.vg.size() + v.vp.size() + v.vversion.size() + v.vrandom.size(); + } + } + return 0; +} +inline mtpTypeId MTPmessages_dhConfig::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessages_dhConfig::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messages_dhConfigNotModified: _type = cons; { + if (!data) setData(new MTPDmessages_dhConfigNotModified()); + MTPDmessages_dhConfigNotModified &v(_messages_dhConfigNotModified()); + v.vrandom.read(from, end); + } break; + case mtpc_messages_dhConfig: _type = cons; { + if (!data) setData(new MTPDmessages_dhConfig()); + MTPDmessages_dhConfig &v(_messages_dhConfig()); + v.vg.read(from, end); + v.vp.read(from, end); + v.vversion.read(from, end); + v.vrandom.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessages_dhConfig"); + } +} +inline void MTPmessages_dhConfig::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messages_dhConfigNotModified: { + const MTPDmessages_dhConfigNotModified &v(c_messages_dhConfigNotModified()); + v.vrandom.write(to); + } break; + case mtpc_messages_dhConfig: { + const MTPDmessages_dhConfig &v(c_messages_dhConfig()); + v.vg.write(to); + v.vp.write(to); + v.vversion.write(to); + v.vrandom.write(to); + } break; + } +} +inline MTPmessages_dhConfig::MTPmessages_dhConfig(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_messages_dhConfigNotModified: setData(new MTPDmessages_dhConfigNotModified()); break; + case mtpc_messages_dhConfig: setData(new MTPDmessages_dhConfig()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessages_dhConfig"); + } +} +inline MTPmessages_dhConfig::MTPmessages_dhConfig(MTPDmessages_dhConfigNotModified *_data) : _type(mtpc_messages_dhConfigNotModified), mtpDataOwner(_data) { +} +inline MTPmessages_dhConfig::MTPmessages_dhConfig(MTPDmessages_dhConfig *_data) : _type(mtpc_messages_dhConfig), mtpDataOwner(_data) { +} +inline MTPmessages_dhConfig MTP_messages_dhConfigNotModified(const MTPbytes &_random) { + return MTPmessages_dhConfig(new MTPDmessages_dhConfigNotModified(_random)); +} +inline MTPmessages_dhConfig MTP_messages_dhConfig(MTPint _g, const MTPbytes &_p, MTPint _version, const MTPbytes &_random) { + return MTPmessages_dhConfig(new MTPDmessages_dhConfig(_g, _p, _version, _random)); +} + +inline uint32 MTPmessages_sentEncryptedMessage::size() const { + switch (_type) { + case mtpc_messages_sentEncryptedMessage: { + const MTPDmessages_sentEncryptedMessage &v(c_messages_sentEncryptedMessage()); + return v.vdate.size(); + } + case mtpc_messages_sentEncryptedFile: { + const MTPDmessages_sentEncryptedFile &v(c_messages_sentEncryptedFile()); + return v.vdate.size() + v.vfile.size(); + } + } + return 0; +} +inline mtpTypeId MTPmessages_sentEncryptedMessage::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessages_sentEncryptedMessage::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messages_sentEncryptedMessage: _type = cons; { + if (!data) setData(new MTPDmessages_sentEncryptedMessage()); + MTPDmessages_sentEncryptedMessage &v(_messages_sentEncryptedMessage()); + v.vdate.read(from, end); + } break; + case mtpc_messages_sentEncryptedFile: _type = cons; { + if (!data) setData(new MTPDmessages_sentEncryptedFile()); + MTPDmessages_sentEncryptedFile &v(_messages_sentEncryptedFile()); + v.vdate.read(from, end); + v.vfile.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessages_sentEncryptedMessage"); + } +} +inline void MTPmessages_sentEncryptedMessage::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messages_sentEncryptedMessage: { + const MTPDmessages_sentEncryptedMessage &v(c_messages_sentEncryptedMessage()); + v.vdate.write(to); + } break; + case mtpc_messages_sentEncryptedFile: { + const MTPDmessages_sentEncryptedFile &v(c_messages_sentEncryptedFile()); + v.vdate.write(to); + v.vfile.write(to); + } break; + } +} +inline MTPmessages_sentEncryptedMessage::MTPmessages_sentEncryptedMessage(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_messages_sentEncryptedMessage: setData(new MTPDmessages_sentEncryptedMessage()); break; + case mtpc_messages_sentEncryptedFile: setData(new MTPDmessages_sentEncryptedFile()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessages_sentEncryptedMessage"); + } +} +inline MTPmessages_sentEncryptedMessage::MTPmessages_sentEncryptedMessage(MTPDmessages_sentEncryptedMessage *_data) : _type(mtpc_messages_sentEncryptedMessage), mtpDataOwner(_data) { +} +inline MTPmessages_sentEncryptedMessage::MTPmessages_sentEncryptedMessage(MTPDmessages_sentEncryptedFile *_data) : _type(mtpc_messages_sentEncryptedFile), mtpDataOwner(_data) { +} +inline MTPmessages_sentEncryptedMessage MTP_messages_sentEncryptedMessage(MTPint _date) { + return MTPmessages_sentEncryptedMessage(new MTPDmessages_sentEncryptedMessage(_date)); +} +inline MTPmessages_sentEncryptedMessage MTP_messages_sentEncryptedFile(MTPint _date, const MTPEncryptedFile &_file) { + return MTPmessages_sentEncryptedMessage(new MTPDmessages_sentEncryptedFile(_date, _file)); +} + +inline uint32 MTPinputAudio::size() const { + switch (_type) { + case mtpc_inputAudio: { + const MTPDinputAudio &v(c_inputAudio()); + return v.vid.size() + v.vaccess_hash.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputAudio::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputAudio::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputAudioEmpty: _type = cons; break; + case mtpc_inputAudio: _type = cons; { + if (!data) setData(new MTPDinputAudio()); + MTPDinputAudio &v(_inputAudio()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputAudio"); + } +} +inline void MTPinputAudio::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputAudio: { + const MTPDinputAudio &v(c_inputAudio()); + v.vid.write(to); + v.vaccess_hash.write(to); + } break; + } +} +inline MTPinputAudio::MTPinputAudio(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputAudioEmpty: break; + case mtpc_inputAudio: setData(new MTPDinputAudio()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputAudio"); + } +} +inline MTPinputAudio::MTPinputAudio(MTPDinputAudio *_data) : _type(mtpc_inputAudio), mtpDataOwner(_data) { +} +inline MTPinputAudio MTP_inputAudioEmpty() { + return MTPinputAudio(mtpc_inputAudioEmpty); +} +inline MTPinputAudio MTP_inputAudio(const MTPlong &_id, const MTPlong &_access_hash) { + return MTPinputAudio(new MTPDinputAudio(_id, _access_hash)); +} + +inline uint32 MTPinputDocument::size() const { + switch (_type) { + case mtpc_inputDocument: { + const MTPDinputDocument &v(c_inputDocument()); + return v.vid.size() + v.vaccess_hash.size(); + } + } + return 0; +} +inline mtpTypeId MTPinputDocument::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputDocument::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputDocumentEmpty: _type = cons; break; + case mtpc_inputDocument: _type = cons; { + if (!data) setData(new MTPDinputDocument()); + MTPDinputDocument &v(_inputDocument()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputDocument"); + } +} +inline void MTPinputDocument::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputDocument: { + const MTPDinputDocument &v(c_inputDocument()); + v.vid.write(to); + v.vaccess_hash.write(to); + } break; + } +} +inline MTPinputDocument::MTPinputDocument(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_inputDocumentEmpty: break; + case mtpc_inputDocument: setData(new MTPDinputDocument()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputDocument"); + } +} +inline MTPinputDocument::MTPinputDocument(MTPDinputDocument *_data) : _type(mtpc_inputDocument), mtpDataOwner(_data) { +} +inline MTPinputDocument MTP_inputDocumentEmpty() { + return MTPinputDocument(mtpc_inputDocumentEmpty); +} +inline MTPinputDocument MTP_inputDocument(const MTPlong &_id, const MTPlong &_access_hash) { + return MTPinputDocument(new MTPDinputDocument(_id, _access_hash)); +} + +inline uint32 MTPaudio::size() const { + switch (_type) { + case mtpc_audioEmpty: { + const MTPDaudioEmpty &v(c_audioEmpty()); + return v.vid.size(); + } + case mtpc_audio: { + const MTPDaudio &v(c_audio()); + return v.vid.size() + v.vaccess_hash.size() + v.vuser_id.size() + v.vdate.size() + v.vduration.size() + v.vmime_type.size() + v.vsize.size() + v.vdc_id.size(); + } + } + return 0; +} +inline mtpTypeId MTPaudio::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPaudio::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_audioEmpty: _type = cons; { + if (!data) setData(new MTPDaudioEmpty()); + MTPDaudioEmpty &v(_audioEmpty()); + v.vid.read(from, end); + } break; + case mtpc_audio: _type = cons; { + if (!data) setData(new MTPDaudio()); + MTPDaudio &v(_audio()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + v.vuser_id.read(from, end); + v.vdate.read(from, end); + v.vduration.read(from, end); + v.vmime_type.read(from, end); + v.vsize.read(from, end); + v.vdc_id.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPaudio"); + } +} +inline void MTPaudio::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_audioEmpty: { + const MTPDaudioEmpty &v(c_audioEmpty()); + v.vid.write(to); + } break; + case mtpc_audio: { + const MTPDaudio &v(c_audio()); + v.vid.write(to); + v.vaccess_hash.write(to); + v.vuser_id.write(to); + v.vdate.write(to); + v.vduration.write(to); + v.vmime_type.write(to); + v.vsize.write(to); + v.vdc_id.write(to); + } break; + } +} +inline MTPaudio::MTPaudio(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_audioEmpty: setData(new MTPDaudioEmpty()); break; + case mtpc_audio: setData(new MTPDaudio()); break; + default: throw mtpErrorBadTypeId(type, "MTPaudio"); + } +} +inline MTPaudio::MTPaudio(MTPDaudioEmpty *_data) : _type(mtpc_audioEmpty), mtpDataOwner(_data) { +} +inline MTPaudio::MTPaudio(MTPDaudio *_data) : _type(mtpc_audio), mtpDataOwner(_data) { +} +inline MTPaudio MTP_audioEmpty(const MTPlong &_id) { + return MTPaudio(new MTPDaudioEmpty(_id)); +} +inline MTPaudio MTP_audio(const MTPlong &_id, const MTPlong &_access_hash, MTPint _user_id, MTPint _date, MTPint _duration, const MTPstring &_mime_type, MTPint _size, MTPint _dc_id) { + return MTPaudio(new MTPDaudio(_id, _access_hash, _user_id, _date, _duration, _mime_type, _size, _dc_id)); +} + +inline uint32 MTPdocument::size() const { + switch (_type) { + case mtpc_documentEmpty: { + const MTPDdocumentEmpty &v(c_documentEmpty()); + return v.vid.size(); + } + case mtpc_document: { + const MTPDdocument &v(c_document()); + return v.vid.size() + v.vaccess_hash.size() + v.vuser_id.size() + v.vdate.size() + v.vfile_name.size() + v.vmime_type.size() + v.vsize.size() + v.vthumb.size() + v.vdc_id.size(); + } + } + return 0; +} +inline mtpTypeId MTPdocument::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPdocument::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_documentEmpty: _type = cons; { + if (!data) setData(new MTPDdocumentEmpty()); + MTPDdocumentEmpty &v(_documentEmpty()); + v.vid.read(from, end); + } break; + case mtpc_document: _type = cons; { + if (!data) setData(new MTPDdocument()); + MTPDdocument &v(_document()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + v.vuser_id.read(from, end); + v.vdate.read(from, end); + v.vfile_name.read(from, end); + v.vmime_type.read(from, end); + v.vsize.read(from, end); + v.vthumb.read(from, end); + v.vdc_id.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPdocument"); + } +} +inline void MTPdocument::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_documentEmpty: { + const MTPDdocumentEmpty &v(c_documentEmpty()); + v.vid.write(to); + } break; + case mtpc_document: { + const MTPDdocument &v(c_document()); + v.vid.write(to); + v.vaccess_hash.write(to); + v.vuser_id.write(to); + v.vdate.write(to); + v.vfile_name.write(to); + v.vmime_type.write(to); + v.vsize.write(to); + v.vthumb.write(to); + v.vdc_id.write(to); + } break; + } +} +inline MTPdocument::MTPdocument(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_documentEmpty: setData(new MTPDdocumentEmpty()); break; + case mtpc_document: setData(new MTPDdocument()); break; + default: throw mtpErrorBadTypeId(type, "MTPdocument"); + } +} +inline MTPdocument::MTPdocument(MTPDdocumentEmpty *_data) : _type(mtpc_documentEmpty), mtpDataOwner(_data) { +} +inline MTPdocument::MTPdocument(MTPDdocument *_data) : _type(mtpc_document), mtpDataOwner(_data) { +} +inline MTPdocument MTP_documentEmpty(const MTPlong &_id) { + return MTPdocument(new MTPDdocumentEmpty(_id)); +} +inline MTPdocument MTP_document(const MTPlong &_id, const MTPlong &_access_hash, MTPint _user_id, MTPint _date, const MTPstring &_file_name, const MTPstring &_mime_type, MTPint _size, const MTPPhotoSize &_thumb, MTPint _dc_id) { + return MTPdocument(new MTPDdocument(_id, _access_hash, _user_id, _date, _file_name, _mime_type, _size, _thumb, _dc_id)); +} + +inline MTPhelp_support::MTPhelp_support() : mtpDataOwner(new MTPDhelp_support()) { +} + +inline uint32 MTPhelp_support::size() const { + const MTPDhelp_support &v(c_help_support()); + return v.vphone_number.size() + v.vuser.size(); +} +inline mtpTypeId MTPhelp_support::type() const { + return mtpc_help_support; +} +inline void MTPhelp_support::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_help_support) throw mtpErrorUnexpected(cons, "MTPhelp_support"); + + if (!data) setData(new MTPDhelp_support()); + MTPDhelp_support &v(_help_support()); + v.vphone_number.read(from, end); + v.vuser.read(from, end); +} +inline void MTPhelp_support::write(mtpBuffer &to) const { + const MTPDhelp_support &v(c_help_support()); + v.vphone_number.write(to); + v.vuser.write(to); +} +inline MTPhelp_support::MTPhelp_support(MTPDhelp_support *_data) : mtpDataOwner(_data) { +} +inline MTPhelp_support MTP_help_support(const MTPstring &_phone_number, const MTPUser &_user) { + return MTPhelp_support(new MTPDhelp_support(_phone_number, _user)); +} + +inline uint32 MTPnotifyPeer::size() const { + switch (_type) { + case mtpc_notifyPeer: { + const MTPDnotifyPeer &v(c_notifyPeer()); + return v.vpeer.size(); + } + } + return 0; +} +inline mtpTypeId MTPnotifyPeer::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPnotifyPeer::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_notifyPeer: _type = cons; { + if (!data) setData(new MTPDnotifyPeer()); + MTPDnotifyPeer &v(_notifyPeer()); + v.vpeer.read(from, end); + } break; + case mtpc_notifyUsers: _type = cons; break; + case mtpc_notifyChats: _type = cons; break; + case mtpc_notifyAll: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPnotifyPeer"); + } +} +inline void MTPnotifyPeer::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_notifyPeer: { + const MTPDnotifyPeer &v(c_notifyPeer()); + v.vpeer.write(to); + } break; + } +} +inline MTPnotifyPeer::MTPnotifyPeer(mtpTypeId type) : _type(type), mtpDataOwner(0) { + switch (type) { + case mtpc_notifyPeer: setData(new MTPDnotifyPeer()); break; + case mtpc_notifyUsers: break; + case mtpc_notifyChats: break; + case mtpc_notifyAll: break; + default: throw mtpErrorBadTypeId(type, "MTPnotifyPeer"); + } +} +inline MTPnotifyPeer::MTPnotifyPeer(MTPDnotifyPeer *_data) : _type(mtpc_notifyPeer), mtpDataOwner(_data) { +} +inline MTPnotifyPeer MTP_notifyPeer(const MTPPeer &_peer) { + return MTPnotifyPeer(new MTPDnotifyPeer(_peer)); +} +inline MTPnotifyPeer MTP_notifyUsers() { + return MTPnotifyPeer(mtpc_notifyUsers); +} +inline MTPnotifyPeer MTP_notifyChats() { + return MTPnotifyPeer(mtpc_notifyChats); +} +inline MTPnotifyPeer MTP_notifyAll() { + return MTPnotifyPeer(mtpc_notifyAll); +} + +// Human-readable text serialization +#if (defined _DEBUG || defined _WITH_DEBUG) + +inline QString mtpTextSerialize(const mtpPrime *&from, const mtpPrime *end, mtpPrime cons, uint32 level, mtpPrime vcons) { + QString add = QString(" ").repeated(level * 2); + + const mtpPrime *start = from; + try { + if (!cons) { + if (from >= end) { + throw Exception("from >= 2"); + } + cons = *from; + ++from; + ++start; + } + + QString result; + switch (cons) { + case mtpc_messages_chatFull: + result += "\n" + add; + result += " full_chat: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_chatFull" + result + "}"; + + case mtpc_messages_affectedHistory: + result += "\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " offset: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_affectedHistory" + result + "}"; + + case mtpc_inputFileLocation: + result += "\n" + add; + result += " volume_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " local_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " secret: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputFileLocation" + result + "}"; + + case mtpc_inputVideoFileLocation: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputVideoFileLocation" + result + "}"; + + case mtpc_inputEncryptedFileLocation: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputEncryptedFileLocation" + result + "}"; + + case mtpc_inputAudioFileLocation: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputAudioFileLocation" + result + "}"; + + case mtpc_inputDocumentFileLocation: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputDocumentFileLocation" + result + "}"; + + case mtpc_dh_gen_ok: + result += "\n" + add; + result += " nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " server_nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " new_nonce_hash1: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + return "{ dh_gen_ok" + result + "}"; + + case mtpc_dh_gen_retry: + result += "\n" + add; + result += " nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " server_nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " new_nonce_hash2: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + return "{ dh_gen_retry" + result + "}"; + + case mtpc_dh_gen_fail: + result += "\n" + add; + result += " nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " server_nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " new_nonce_hash3: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + return "{ dh_gen_fail" + result + "}"; + + case mtpc_chatEmpty: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ chatEmpty" + result + "}"; + + case mtpc_chat: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " title: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " participants_count: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " left: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " version: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ chat" + result + "}"; + + case mtpc_chatForbidden: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " title: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ chatForbidden" + result + "}"; + + case mtpc_geoChat: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " title: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " address: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " venue: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " geo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " participants_count: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " checked_in: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " version: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ geoChat" + result + "}"; + + case mtpc_inputDocumentEmpty: + result = " "; + return "{ inputDocumentEmpty" + result + "}"; + + case mtpc_inputDocument: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputDocument" + result + "}"; + + case mtpc_messages_statedMessage: + result += "\n" + add; + result += " message: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_statedMessage" + result + "}"; + + case mtpc_messages_statedMessageLink: + result += "\n" + add; + result += " message: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " links: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_statedMessageLink" + result + "}"; + + case mtpc_upload_file: + result += "\n" + add; + result += " type: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " mtime: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ upload_file" + result + "}"; + + case mtpc_inputMediaEmpty: + result = " "; + return "{ inputMediaEmpty" + result + "}"; + + case mtpc_inputMediaUploadedPhoto: + result += "\n" + add; + result += " file: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ inputMediaUploadedPhoto" + result + "}"; + + case mtpc_inputMediaPhoto: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ inputMediaPhoto" + result + "}"; + + case mtpc_inputMediaGeoPoint: + result += "\n" + add; + result += " geo_point: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ inputMediaGeoPoint" + result + "}"; + + case mtpc_inputMediaContact: + result += "\n" + add; + result += " phone_number: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ inputMediaContact" + result + "}"; + + case mtpc_inputMediaUploadedVideo: + result += "\n" + add; + result += " file: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " duration: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " w: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " h: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " mime_type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ inputMediaUploadedVideo" + result + "}"; + + case mtpc_inputMediaUploadedThumbVideo: + result += "\n" + add; + result += " file: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " thumb: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " duration: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " w: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " h: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " mime_type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ inputMediaUploadedThumbVideo" + result + "}"; + + case mtpc_inputMediaVideo: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ inputMediaVideo" + result + "}"; + + case mtpc_inputMediaUploadedAudio: + result += "\n" + add; + result += " file: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " duration: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " mime_type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ inputMediaUploadedAudio" + result + "}"; + + case mtpc_inputMediaAudio: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ inputMediaAudio" + result + "}"; + + case mtpc_inputMediaUploadedDocument: + result += "\n" + add; + result += " file: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " file_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " mime_type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ inputMediaUploadedDocument" + result + "}"; + + case mtpc_inputMediaUploadedThumbDocument: + result += "\n" + add; + result += " file: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " thumb: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " file_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " mime_type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ inputMediaUploadedThumbDocument" + result + "}"; + + case mtpc_inputMediaDocument: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ inputMediaDocument" + result + "}"; + + case mtpc_contact: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " mutual: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contact" + result + "}"; + + case mtpc_pong: + result += "\n" + add; + result += " msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " ping_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ pong" + result + "}"; + + case mtpc_chatParticipantsForbidden: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ chatParticipantsForbidden" + result + "}"; + + case mtpc_chatParticipants: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " admin_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " participants: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " version: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ chatParticipants" + result + "}"; + + case mtpc_chatParticipant: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " inviter_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ chatParticipant" + result + "}"; + + case mtpc_msgs_all_info: + result += "\n" + add; + result += " msg_ids: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_long) + ",\n" + add; + result += " info: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ msgs_all_info" + result + "}"; + + case mtpc_messages_messageEmpty: + result = " "; + return "{ messages_messageEmpty" + result + "}"; + + case mtpc_messages_message: + result += "\n" + add; + result += " message: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_message" + result + "}"; + + case mtpc_nearestDc: + result += "\n" + add; + result += " country: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " this_dc: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " nearest_dc: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ nearestDc" + result + "}"; + + case mtpc_contacts_importedContacts: + result += "\n" + add; + result += " imported: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " retry_contacts: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_long) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_importedContacts" + result + "}"; + + case mtpc_auth_exportedAuthorization: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ auth_exportedAuthorization" + result + "}"; + + case mtpc_inputPhotoCropAuto: + result = " "; + return "{ inputPhotoCropAuto" + result + "}"; + + case mtpc_inputPhotoCrop: + result += "\n" + add; + result += " crop_left: " + mtpTextSerialize(from, end, mtpc_double, level + 1) + ",\n" + add; + result += " crop_top: " + mtpTextSerialize(from, end, mtpc_double, level + 1) + ",\n" + add; + result += " crop_width: " + mtpTextSerialize(from, end, mtpc_double, level + 1) + ",\n" + add; + return "{ inputPhotoCrop" + result + "}"; + + case mtpc_contactBlocked: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ contactBlocked" + result + "}"; + + case mtpc_decryptedMessageMediaEmpty: + result = " "; + return "{ decryptedMessageMediaEmpty" + result + "}"; + + case mtpc_decryptedMessageMediaPhoto: + result += "\n" + add; + result += " thumb: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " thumb_w: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " thumb_h: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " w: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " h: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " size: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " key: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " iv: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ decryptedMessageMediaPhoto" + result + "}"; + + case mtpc_decryptedMessageMediaVideo: + result += "\n" + add; + result += " thumb: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " thumb_w: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " thumb_h: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " duration: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " mime_type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " w: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " h: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " size: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " key: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " iv: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ decryptedMessageMediaVideo" + result + "}"; + + case mtpc_decryptedMessageMediaGeoPoint: + result += "\n" + add; + result += " lat: " + mtpTextSerialize(from, end, mtpc_double, level + 1) + ",\n" + add; + result += " long: " + mtpTextSerialize(from, end, mtpc_double, level + 1) + ",\n" + add; + return "{ decryptedMessageMediaGeoPoint" + result + "}"; + + case mtpc_decryptedMessageMediaContact: + result += "\n" + add; + result += " phone_number: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ decryptedMessageMediaContact" + result + "}"; + + case mtpc_decryptedMessageMediaDocument: + result += "\n" + add; + result += " thumb: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " thumb_w: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " thumb_h: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " file_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " mime_type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " size: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " key: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " iv: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ decryptedMessageMediaDocument" + result + "}"; + + case mtpc_decryptedMessageMediaAudio: + result += "\n" + add; + result += " duration: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " mime_type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " size: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " key: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " iv: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ decryptedMessageMediaAudio" + result + "}"; + + case mtpc_encryptedChatEmpty: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ encryptedChatEmpty" + result + "}"; + + case mtpc_encryptedChatWaiting: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " admin_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " participant_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ encryptedChatWaiting" + result + "}"; + + case mtpc_encryptedChatRequested: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " admin_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " participant_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " g_a: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ encryptedChatRequested" + result + "}"; + + case mtpc_encryptedChat: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " admin_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " participant_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " g_a_or_b: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " key_fingerprint: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ encryptedChat" + result + "}"; + + case mtpc_encryptedChatDiscarded: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ encryptedChatDiscarded" + result + "}"; + + case mtpc_server_DH_inner_data: + result += "\n" + add; + result += " nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " server_nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " g: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " dh_prime: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " g_a: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " server_time: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ server_DH_inner_data" + result + "}"; + + case mtpc_bad_msg_notification: + result += "\n" + add; + result += " bad_msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " bad_msg_seqno: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " error_code: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ bad_msg_notification" + result + "}"; + + case mtpc_bad_server_salt: + result += "\n" + add; + result += " bad_msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " bad_msg_seqno: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " error_code: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " new_server_salt: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ bad_server_salt" + result + "}"; + + case mtpc_dcOption: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " hostname: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " ip_address: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " port: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ dcOption" + result + "}"; + + case mtpc_chatFull: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " participants: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chat_photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " notify_settings: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ chatFull" + result + "}"; + + case mtpc_p_q_inner_data: + result += "\n" + add; + result += " pq: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " p: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " q: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " server_nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " new_nonce: " + mtpTextSerialize(from, end, mtpc_int256, level + 1) + ",\n" + add; + return "{ p_q_inner_data" + result + "}"; + + case mtpc_msgs_state_req: + result += "\n" + add; + result += " msg_ids: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_long) + ",\n" + add; + return "{ msgs_state_req" + result + "}"; + + case mtpc_chatLocated: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " distance: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ chatLocated" + result + "}"; + + case mtpc_future_salt: + result += "\n" + add; + result += " valid_since: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " valid_until: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " salt: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ future_salt" + result + "}"; + + case mtpc_decryptedMessage: + result += "\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " random_bytes: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " message: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " media: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ decryptedMessage" + result + "}"; + + case mtpc_decryptedMessageService: + result += "\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " random_bytes: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " action: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ decryptedMessageService" + result + "}"; + + case mtpc_inputAudioEmpty: + result = " "; + return "{ inputAudioEmpty" + result + "}"; + + case mtpc_inputAudio: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputAudio" + result + "}"; + + case mtpc_encryptedMessage: + result += "\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " file: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ encryptedMessage" + result + "}"; + + case mtpc_encryptedMessageService: + result += "\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ encryptedMessageService" + result + "}"; + + case mtpc_geochats_messages: + result += "\n" + add; + result += " messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ geochats_messages" + result + "}"; + + case mtpc_geochats_messagesSlice: + result += "\n" + add; + result += " count: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ geochats_messagesSlice" + result + "}"; + + case mtpc_updates_differenceEmpty: + result += "\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updates_differenceEmpty" + result + "}"; + + case mtpc_updates_difference: + result += "\n" + add; + result += " new_messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " new_encrypted_messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " other_updates: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " state: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ updates_difference" + result + "}"; + + case mtpc_updates_differenceSlice: + result += "\n" + add; + result += " new_messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " new_encrypted_messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " other_updates: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " intermediate_state: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ updates_differenceSlice" + result + "}"; + + case mtpc_userEmpty: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ userEmpty" + result + "}"; + + case mtpc_userSelf: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " phone: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " status: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " inactive: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ userSelf" + result + "}"; + + case mtpc_userContact: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " phone: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " status: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ userContact" + result + "}"; + + case mtpc_userRequest: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " phone: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " status: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ userRequest" + result + "}"; + + case mtpc_userForeign: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " status: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ userForeign" + result + "}"; + + case mtpc_userDeleted: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ userDeleted" + result + "}"; + + case mtpc_new_session_created: + result += "\n" + add; + result += " first_msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " unique_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " server_salt: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ new_session_created" + result + "}"; + + case mtpc_inputPhotoEmpty: + result = " "; + return "{ inputPhotoEmpty" + result + "}"; + + case mtpc_inputPhoto: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputPhoto" + result + "}"; + + case mtpc_geochats_statedMessage: + result += "\n" + add; + result += " message: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ geochats_statedMessage" + result + "}"; + + case mtpc_inputMessagesFilterEmpty: + result = " "; + return "{ inputMessagesFilterEmpty" + result + "}"; + + case mtpc_inputMessagesFilterPhotos: + result = " "; + return "{ inputMessagesFilterPhotos" + result + "}"; + + case mtpc_inputMessagesFilterVideo: + result = " "; + return "{ inputMessagesFilterVideo" + result + "}"; + + case mtpc_inputMessagesFilterPhotoVideo: + result = " "; + return "{ inputMessagesFilterPhotoVideo" + result + "}"; + + case mtpc_inputMessagesFilterDocument: + result = " "; + return "{ inputMessagesFilterDocument" + result + "}"; + + case mtpc_peerUser: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ peerUser" + result + "}"; + + case mtpc_peerChat: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ peerChat" + result + "}"; + + case mtpc_notifyPeer: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ notifyPeer" + result + "}"; + + case mtpc_notifyUsers: + result = " "; + return "{ notifyUsers" + result + "}"; + + case mtpc_notifyChats: + result = " "; + return "{ notifyChats" + result + "}"; + + case mtpc_notifyAll: + result = " "; + return "{ notifyAll" + result + "}"; + + case mtpc_messages_sentMessage: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_sentMessage" + result + "}"; + + case mtpc_messages_sentMessageLink: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " links: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_sentMessageLink" + result + "}"; + + case mtpc_inputFile: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " parts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " md5_checksum: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ inputFile" + result + "}"; + + case mtpc_inputFileBig: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " parts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ inputFileBig" + result + "}"; + + case mtpc_inputAppEvent: + result += "\n" + add; + result += " time: " + mtpTextSerialize(from, end, mtpc_double, level + 1) + ",\n" + add; + result += " type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " peer: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " data: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ inputAppEvent" + result + "}"; + + case mtpc_geochats_located: + result += "\n" + add; + result += " results: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ geochats_located" + result + "}"; + + case mtpc_messages_dialogs: + result += "\n" + add; + result += " dialogs: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_dialogs" + result + "}"; + + case mtpc_messages_dialogsSlice: + result += "\n" + add; + result += " count: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " dialogs: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_dialogsSlice" + result + "}"; + + case mtpc_contacts_myLinkEmpty: + result = " "; + return "{ contacts_myLinkEmpty" + result + "}"; + + case mtpc_contacts_myLinkRequested: + result += "\n" + add; + result += " contact: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_myLinkRequested" + result + "}"; + + case mtpc_contacts_myLinkContact: + result = " "; + return "{ contacts_myLinkContact" + result + "}"; + + case mtpc_inputPeerNotifySettings: + result += "\n" + add; + result += " mute_until: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " sound: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " show_previews: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " events_mask: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ inputPeerNotifySettings" + result + "}"; + + case mtpc_chatPhotoEmpty: + result = " "; + return "{ chatPhotoEmpty" + result + "}"; + + case mtpc_chatPhoto: + result += "\n" + add; + result += " photo_small: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " photo_big: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ chatPhoto" + result + "}"; + + case mtpc_messages_sentEncryptedMessage: + result += "\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_sentEncryptedMessage" + result + "}"; + + case mtpc_messages_sentEncryptedFile: + result += "\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " file: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_sentEncryptedFile" + result + "}"; + + case mtpc_decryptedMessageActionSetMessageTTL: + result += "\n" + add; + result += " ttl_seconds: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ decryptedMessageActionSetMessageTTL" + result + "}"; + + case mtpc_decryptedMessageActionReadMessages: + result += "\n" + add; + result += " random_ids: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_long) + ",\n" + add; + return "{ decryptedMessageActionReadMessages" + result + "}"; + + case mtpc_decryptedMessageActionDeleteMessages: + result += "\n" + add; + result += " random_ids: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_long) + ",\n" + add; + return "{ decryptedMessageActionDeleteMessages" + result + "}"; + + case mtpc_decryptedMessageActionScreenshotMessages: + result += "\n" + add; + result += " random_ids: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_long) + ",\n" + add; + return "{ decryptedMessageActionScreenshotMessages" + result + "}"; + + case mtpc_decryptedMessageActionFlushHistory: + result = " "; + return "{ decryptedMessageActionFlushHistory" + result + "}"; + + case mtpc_decryptedMessageActionNotifyLayer: + result += "\n" + add; + result += " layer: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ decryptedMessageActionNotifyLayer" + result + "}"; + + case mtpc_contacts_blocked: + result += "\n" + add; + result += " blocked: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_blocked" + result + "}"; + + case mtpc_contacts_blockedSlice: + result += "\n" + add; + result += " count: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " blocked: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_blockedSlice" + result + "}"; + + case mtpc_photoEmpty: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ photoEmpty" + result + "}"; + + case mtpc_photo: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " caption: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " geo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " sizes: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ photo" + result + "}"; + + case mtpc_decryptedMessageLayer: + result += "\n" + add; + result += " layer: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " message: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ decryptedMessageLayer" + result + "}"; + + case mtpc_encryptedFileEmpty: + result = " "; + return "{ encryptedFileEmpty" + result + "}"; + + case mtpc_encryptedFile: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " size: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " dc_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " key_fingerprint: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ encryptedFile" + result + "}"; + + case mtpc_userFull: + result += "\n" + add; + result += " user: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " link: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " profile_photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " notify_settings: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " blocked: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " real_first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " real_last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ userFull" + result + "}"; + + case mtpc_messageMediaEmpty: + result = " "; + return "{ messageMediaEmpty" + result + "}"; + + case mtpc_messageMediaPhoto: + result += "\n" + add; + result += " photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messageMediaPhoto" + result + "}"; + + case mtpc_messageMediaVideo: + result += "\n" + add; + result += " video: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messageMediaVideo" + result + "}"; + + case mtpc_messageMediaGeo: + result += "\n" + add; + result += " geo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messageMediaGeo" + result + "}"; + + case mtpc_messageMediaContact: + result += "\n" + add; + result += " phone_number: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messageMediaContact" + result + "}"; + + case mtpc_messageMediaUnsupported: + result += "\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ messageMediaUnsupported" + result + "}"; + + case mtpc_messageMediaDocument: + result += "\n" + add; + result += " document: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messageMediaDocument" + result + "}"; + + case mtpc_messageMediaAudio: + result += "\n" + add; + result += " audio: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messageMediaAudio" + result + "}"; + + case mtpc_help_inviteText: + result += "\n" + add; + result += " message: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ help_inviteText" + result + "}"; + + case mtpc_contactStatus: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " expires: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ contactStatus" + result + "}"; + + case mtpc_messageEmpty: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messageEmpty" + result + "}"; + + case mtpc_message: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " from_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " to_id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " out: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " unread: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " message: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " media: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ message" + result + "}"; + + case mtpc_messageForwarded: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " fwd_from_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " fwd_date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " from_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " to_id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " out: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " unread: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " message: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " media: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messageForwarded" + result + "}"; + + case mtpc_messageService: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " from_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " to_id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " out: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " unread: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " action: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messageService" + result + "}"; + + case mtpc_updates_state: + result += "\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " qts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " unread_count: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updates_state" + result + "}"; + + case mtpc_msgs_state_info: + result += "\n" + add; + result += " req_msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " info: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ msgs_state_info" + result + "}"; + + case mtpc_help_support: + result += "\n" + add; + result += " phone_number: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " user: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ help_support" + result + "}"; + + case mtpc_messages_chats: + result += "\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_chats" + result + "}"; + + case mtpc_msgs_ack: + result += "\n" + add; + result += " msg_ids: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_long) + ",\n" + add; + return "{ msgs_ack" + result + "}"; + + case mtpc_messages_dhConfigNotModified: + result += "\n" + add; + result += " random: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ messages_dhConfigNotModified" + result + "}"; + + case mtpc_messages_dhConfig: + result += "\n" + add; + result += " g: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " p: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " version: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " random: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ messages_dhConfig" + result + "}"; + + case mtpc_contactFound: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ contactFound" + result + "}"; + + case mtpc_inputGeoPointEmpty: + result = " "; + return "{ inputGeoPointEmpty" + result + "}"; + + case mtpc_inputGeoPoint: + result += "\n" + add; + result += " lat: " + mtpTextSerialize(from, end, mtpc_double, level + 1) + ",\n" + add; + result += " long: " + mtpTextSerialize(from, end, mtpc_double, level + 1) + ",\n" + add; + return "{ inputGeoPoint" + result + "}"; + + case mtpc_inputUserEmpty: + result = " "; + return "{ inputUserEmpty" + result + "}"; + + case mtpc_inputUserSelf: + result = " "; + return "{ inputUserSelf" + result + "}"; + + case mtpc_inputUserContact: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ inputUserContact" + result + "}"; + + case mtpc_inputUserForeign: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputUserForeign" + result + "}"; + + case mtpc_rpc_error: + result += "\n" + add; + result += " error_code: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " error_message: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ rpc_error" + result + "}"; + + case mtpc_contacts_suggested: + result += "\n" + add; + result += " results: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_suggested" + result + "}"; + + case mtpc_client_DH_inner_data: + result += "\n" + add; + result += " nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " server_nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " retry_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " g_b: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ client_DH_inner_data" + result + "}"; + + case mtpc_dialog: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " top_message: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " unread_count: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " notify_settings: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ dialog" + result + "}"; + + case mtpc_inputEncryptedFileEmpty: + result = " "; + return "{ inputEncryptedFileEmpty" + result + "}"; + + case mtpc_inputEncryptedFileUploaded: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " parts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " md5_checksum: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " key_fingerprint: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ inputEncryptedFileUploaded" + result + "}"; + + case mtpc_inputEncryptedFile: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputEncryptedFile" + result + "}"; + + case mtpc_inputEncryptedFileBigUploaded: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " parts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " key_fingerprint: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ inputEncryptedFileBigUploaded" + result + "}"; + + case mtpc_auth_checkedPhone: + result += "\n" + add; + result += " phone_registered: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " phone_invited: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ auth_checkedPhone" + result + "}"; + + case mtpc_contactSuggested: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " mutual_contacts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ contactSuggested" + result + "}"; + + case mtpc_photoSizeEmpty: + result += "\n" + add; + result += " type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ photoSizeEmpty" + result + "}"; + + case mtpc_photoSize: + result += "\n" + add; + result += " type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " location: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " w: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " h: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " size: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ photoSize" + result + "}"; + + case mtpc_photoCachedSize: + result += "\n" + add; + result += " type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " location: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " w: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " h: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ photoCachedSize" + result + "}"; + + case mtpc_rpc_answer_unknown: + result = " "; + return "{ rpc_answer_unknown" + result + "}"; + + case mtpc_rpc_answer_dropped_running: + result = " "; + return "{ rpc_answer_dropped_running" + result + "}"; + + case mtpc_rpc_answer_dropped: + result += "\n" + add; + result += " msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " seq_no: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ rpc_answer_dropped" + result + "}"; + + case mtpc_inputNotifyPeer: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ inputNotifyPeer" + result + "}"; + + case mtpc_inputNotifyUsers: + result = " "; + return "{ inputNotifyUsers" + result + "}"; + + case mtpc_inputNotifyChats: + result = " "; + return "{ inputNotifyChats" + result + "}"; + + case mtpc_inputNotifyAll: + result = " "; + return "{ inputNotifyAll" + result + "}"; + + case mtpc_inputNotifyGeoChatPeer: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ inputNotifyGeoChatPeer" + result + "}"; + + case mtpc_geoPointEmpty: + result = " "; + return "{ geoPointEmpty" + result + "}"; + + case mtpc_geoPoint: + result += "\n" + add; + result += " long: " + mtpTextSerialize(from, end, mtpc_double, level + 1) + ",\n" + add; + result += " lat: " + mtpTextSerialize(from, end, mtpc_double, level + 1) + ",\n" + add; + return "{ geoPoint" + result + "}"; + + case mtpc_photos_photo: + result += "\n" + add; + result += " photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ photos_photo" + result + "}"; + + case mtpc_userStatusEmpty: + result = " "; + return "{ userStatusEmpty" + result + "}"; + + case mtpc_userStatusOnline: + result += "\n" + add; + result += " expires: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ userStatusOnline" + result + "}"; + + case mtpc_userStatusOffline: + result += "\n" + add; + result += " was_online: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ userStatusOffline" + result + "}"; + + case mtpc_contacts_found: + result += "\n" + add; + result += " results: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_found" + result + "}"; + + case mtpc_contacts_contacts: + result += "\n" + add; + result += " contacts: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_contacts" + result + "}"; + + case mtpc_contacts_contactsNotModified: + result = " "; + return "{ contacts_contactsNotModified" + result + "}"; + + case mtpc_userProfilePhotoEmpty: + result = " "; + return "{ userProfilePhotoEmpty" + result + "}"; + + case mtpc_userProfilePhoto: + result += "\n" + add; + result += " photo_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " photo_small: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " photo_big: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ userProfilePhoto" + result + "}"; + + case mtpc_messageActionEmpty: + result = " "; + return "{ messageActionEmpty" + result + "}"; + + case mtpc_messageActionChatCreate: + result += "\n" + add; + result += " title: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_int) + ",\n" + add; + return "{ messageActionChatCreate" + result + "}"; + + case mtpc_messageActionChatEditTitle: + result += "\n" + add; + result += " title: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ messageActionChatEditTitle" + result + "}"; + + case mtpc_messageActionChatEditPhoto: + result += "\n" + add; + result += " photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messageActionChatEditPhoto" + result + "}"; + + case mtpc_messageActionChatDeletePhoto: + result = " "; + return "{ messageActionChatDeletePhoto" + result + "}"; + + case mtpc_messageActionChatAddUser: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messageActionChatAddUser" + result + "}"; + + case mtpc_messageActionChatDeleteUser: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messageActionChatDeleteUser" + result + "}"; + + case mtpc_messageActionGeoChatCreate: + result += "\n" + add; + result += " title: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " address: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ messageActionGeoChatCreate" + result + "}"; + + case mtpc_messageActionGeoChatCheckin: + result = " "; + return "{ messageActionGeoChatCheckin" + result + "}"; + + case mtpc_messages_statedMessages: + result += "\n" + add; + result += " messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_statedMessages" + result + "}"; + + case mtpc_messages_statedMessagesLinks: + result += "\n" + add; + result += " messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " links: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_statedMessagesLinks" + result + "}"; + + case mtpc_wallPaper: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " title: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " sizes: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " color: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ wallPaper" + result + "}"; + + case mtpc_wallPaperSolid: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " title: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " bg_color: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " color: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ wallPaperSolid" + result + "}"; + + case mtpc_inputEncryptedChat: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputEncryptedChat" + result + "}"; + + case mtpc_updatesTooLong: + result = " "; + return "{ updatesTooLong" + result + "}"; + + case mtpc_updateShortMessage: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " from_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " message: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateShortMessage" + result + "}"; + + case mtpc_updateShortChatMessage: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " from_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " message: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateShortChatMessage" + result + "}"; + + case mtpc_updateShort: + result += "\n" + add; + result += " update: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateShort" + result + "}"; + + case mtpc_updatesCombined: + result += "\n" + add; + result += " updates: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq_start: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updatesCombined" + result + "}"; + + case mtpc_updates: + result += "\n" + add; + result += " updates: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " seq: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updates" + result + "}"; + + case mtpc_videoEmpty: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ videoEmpty" + result + "}"; + + case mtpc_video: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " caption: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " duration: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " mime_type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " size: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " thumb: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " dc_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " w: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " h: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ video" + result + "}"; + + case mtpc_inputPeerNotifyEventsEmpty: + result = " "; + return "{ inputPeerNotifyEventsEmpty" + result + "}"; + + case mtpc_inputPeerNotifyEventsAll: + result = " "; + return "{ inputPeerNotifyEventsAll" + result + "}"; + + case mtpc_messages_messages: + result += "\n" + add; + result += " messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_messages" + result + "}"; + + case mtpc_messages_messagesSlice: + result += "\n" + add; + result += " count: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " messages: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chats: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_messagesSlice" + result + "}"; + + case mtpc_updateNewMessage: + result += "\n" + add; + result += " message: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateNewMessage" + result + "}"; + + case mtpc_updateMessageID: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ updateMessageID" + result + "}"; + + case mtpc_updateReadMessages: + result += "\n" + add; + result += " messages: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_int) + ",\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateReadMessages" + result + "}"; + + case mtpc_updateDeleteMessages: + result += "\n" + add; + result += " messages: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_int) + ",\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateDeleteMessages" + result + "}"; + + case mtpc_updateRestoreMessages: + result += "\n" + add; + result += " messages: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_int) + ",\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateRestoreMessages" + result + "}"; + + case mtpc_updateUserTyping: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateUserTyping" + result + "}"; + + case mtpc_updateChatUserTyping: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateChatUserTyping" + result + "}"; + + case mtpc_updateChatParticipants: + result += "\n" + add; + result += " participants: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ updateChatParticipants" + result + "}"; + + case mtpc_updateUserStatus: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " status: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ updateUserStatus" + result + "}"; + + case mtpc_updateUserName: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ updateUserName" + result + "}"; + + case mtpc_updateUserPhoto: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " previous: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ updateUserPhoto" + result + "}"; + + case mtpc_updateContactRegistered: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateContactRegistered" + result + "}"; + + case mtpc_updateContactLink: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " my_link: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " foreign_link: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ updateContactLink" + result + "}"; + + case mtpc_updateActivation: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateActivation" + result + "}"; + + case mtpc_updateNewAuthorization: + result += "\n" + add; + result += " auth_key_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " device: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " location: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ updateNewAuthorization" + result + "}"; + + case mtpc_updateNewGeoChatMessage: + result += "\n" + add; + result += " message: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ updateNewGeoChatMessage" + result + "}"; + + case mtpc_updateNewEncryptedMessage: + result += "\n" + add; + result += " message: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " qts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateNewEncryptedMessage" + result + "}"; + + case mtpc_updateEncryptedChatTyping: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateEncryptedChatTyping" + result + "}"; + + case mtpc_updateEncryption: + result += "\n" + add; + result += " chat: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateEncryption" + result + "}"; + + case mtpc_updateEncryptedMessagesRead: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " max_date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateEncryptedMessagesRead" + result + "}"; + + case mtpc_updateChatParticipantAdd: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " inviter_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " version: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateChatParticipantAdd" + result + "}"; + + case mtpc_updateChatParticipantDelete: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " version: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updateChatParticipantDelete" + result + "}"; + + case mtpc_updateDcOptions: + result += "\n" + add; + result += " dc_options: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ updateDcOptions" + result + "}"; + + case mtpc_updateUserBlocked: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " blocked: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ updateUserBlocked" + result + "}"; + + case mtpc_updateNotifySettings: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " notify_settings: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ updateNotifySettings" + result + "}"; + + case mtpc_storage_fileUnknown: + result = " "; + return "{ storage_fileUnknown" + result + "}"; + + case mtpc_storage_fileJpeg: + result = " "; + return "{ storage_fileJpeg" + result + "}"; + + case mtpc_storage_fileGif: + result = " "; + return "{ storage_fileGif" + result + "}"; + + case mtpc_storage_filePng: + result = " "; + return "{ storage_filePng" + result + "}"; + + case mtpc_storage_filePdf: + result = " "; + return "{ storage_filePdf" + result + "}"; + + case mtpc_storage_fileMp3: + result = " "; + return "{ storage_fileMp3" + result + "}"; + + case mtpc_storage_fileMov: + result = " "; + return "{ storage_fileMov" + result + "}"; + + case mtpc_storage_filePartial: + result = " "; + return "{ storage_filePartial" + result + "}"; + + case mtpc_storage_fileMp4: + result = " "; + return "{ storage_fileMp4" + result + "}"; + + case mtpc_storage_fileWebp: + result = " "; + return "{ storage_fileWebp" + result + "}"; + + case mtpc_documentEmpty: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ documentEmpty" + result + "}"; + + case mtpc_document: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " file_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " mime_type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " size: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " thumb: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " dc_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ document" + result + "}"; + + case mtpc_resPQ: + result += "\n" + add; + result += " nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " server_nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " pq: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " server_public_key_fingerprints: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_long) + ",\n" + add; + return "{ resPQ" + result + "}"; + + case mtpc_audioEmpty: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ audioEmpty" + result + "}"; + + case mtpc_audio: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " duration: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " mime_type: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " size: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " dc_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ audio" + result + "}"; + + case mtpc_fileLocationUnavailable: + result += "\n" + add; + result += " volume_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " local_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " secret: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ fileLocationUnavailable" + result + "}"; + + case mtpc_fileLocation: + result += "\n" + add; + result += " dc_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " volume_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " local_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " secret: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ fileLocation" + result + "}"; + + case mtpc_contacts_foreignLinkUnknown: + result = " "; + return "{ contacts_foreignLinkUnknown" + result + "}"; + + case mtpc_contacts_foreignLinkRequested: + result += "\n" + add; + result += " has_phone: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_foreignLinkRequested" + result + "}"; + + case mtpc_contacts_foreignLinkMutual: + result = " "; + return "{ contacts_foreignLinkMutual" + result + "}"; + + case mtpc_inputVideoEmpty: + result = " "; + return "{ inputVideoEmpty" + result + "}"; + + case mtpc_inputVideo: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputVideo" + result + "}"; + + case mtpc_peerNotifySettingsEmpty: + result = " "; + return "{ peerNotifySettingsEmpty" + result + "}"; + + case mtpc_peerNotifySettings: + result += "\n" + add; + result += " mute_until: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " sound: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " show_previews: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " events_mask: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ peerNotifySettings" + result + "}"; + + case mtpc_auth_sentCode: + result += "\n" + add; + result += " phone_registered: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " phone_code_hash: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " send_call_timeout: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " is_password: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ auth_sentCode" + result + "}"; + + case mtpc_inputGeoChat: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputGeoChat" + result + "}"; + + case mtpc_destroy_session_ok: + result += "\n" + add; + result += " session_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ destroy_session_ok" + result + "}"; + + case mtpc_destroy_session_none: + result += "\n" + add; + result += " session_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ destroy_session_none" + result + "}"; + + case mtpc_server_DH_params_fail: + result += "\n" + add; + result += " nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " server_nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " new_nonce_hash: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + return "{ server_DH_params_fail" + result + "}"; + + case mtpc_server_DH_params_ok: + result += "\n" + add; + result += " nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " server_nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " encrypted_answer: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ server_DH_params_ok" + result + "}"; + + case mtpc_auth_authorization: + result += "\n" + add; + result += " expires: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " user: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ auth_authorization" + result + "}"; + + case mtpc_future_salts: + result += "\n" + add; + result += " req_msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " now: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " salts: " + mtpTextSerialize(from, end, mtpc_vector, level + 1, mtpc_future_salt) + ",\n" + add; + return "{ future_salts" + result + "}"; + + case mtpc_geoChatMessageEmpty: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ geoChatMessageEmpty" + result + "}"; + + case mtpc_geoChatMessage: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " from_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " message: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " media: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ geoChatMessage" + result + "}"; + + case mtpc_geoChatMessageService: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " from_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " action: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ geoChatMessageService" + result + "}"; + + case mtpc_help_appUpdate: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " critical: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " url: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " text: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ help_appUpdate" + result + "}"; + + case mtpc_help_noAppUpdate: + result = " "; + return "{ help_noAppUpdate" + result + "}"; + + case mtpc_peerNotifyEventsEmpty: + result = " "; + return "{ peerNotifyEventsEmpty" + result + "}"; + + case mtpc_peerNotifyEventsAll: + result = " "; + return "{ peerNotifyEventsAll" + result + "}"; + + case mtpc_inputPeerEmpty: + result = " "; + return "{ inputPeerEmpty" + result + "}"; + + case mtpc_inputPeerSelf: + result = " "; + return "{ inputPeerSelf" + result + "}"; + + case mtpc_inputPeerContact: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ inputPeerContact" + result + "}"; + + case mtpc_inputPeerForeign: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " access_hash: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ inputPeerForeign" + result + "}"; + + case mtpc_inputPeerChat: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ inputPeerChat" + result + "}"; + + case mtpc_inputChatPhotoEmpty: + result = " "; + return "{ inputChatPhotoEmpty" + result + "}"; + + case mtpc_inputChatUploadedPhoto: + result += "\n" + add; + result += " file: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " crop: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ inputChatUploadedPhoto" + result + "}"; + + case mtpc_inputChatPhoto: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " crop: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ inputChatPhoto" + result + "}"; + + case mtpc_messages_chat: + result += "\n" + add; + result += " chat: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_chat" + result + "}"; + + case mtpc_importedContact: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " client_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ importedContact" + result + "}"; + + case mtpc_inputPhoneContact: + result += "\n" + add; + result += " client_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " phone: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ inputPhoneContact" + result + "}"; + + case mtpc_http_wait: + result += "\n" + add; + result += " max_delay: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " wait_after: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " max_wait: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ http_wait" + result + "}"; + + case mtpc_contacts_link: + result += "\n" + add; + result += " my_link: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " foreign_link: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " user: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_link" + result + "}"; + + case mtpc_msg_resend_req: + result += "\n" + add; + result += " msg_ids: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_long) + ",\n" + add; + return "{ msg_resend_req" + result + "}"; + + case mtpc_config: + result += "\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " test_mode: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " this_dc: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " dc_options: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " chat_size_max: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " broadcast_size_max: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ config" + result + "}"; + + case mtpc_msg_detailed_info: + result += "\n" + add; + result += " msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " answer_msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " status: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ msg_detailed_info" + result + "}"; + + case mtpc_msg_new_detailed_info: + result += "\n" + add; + result += " answer_msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " status: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ msg_new_detailed_info" + result + "}"; + + case mtpc_photos_photos: + result += "\n" + add; + result += " photos: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ photos_photos" + result + "}"; + + case mtpc_photos_photosSlice: + result += "\n" + add; + result += " count: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " photos: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ photos_photosSlice" + result + "}"; + + case mtpc_messages_readHistory: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " max_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " offset: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_readHistory" + result + "}"; + + case mtpc_messages_deleteHistory: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " offset: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_deleteHistory" + result + "}"; + + case mtpc_set_client_DH_params: + result += "\n" + add; + result += " nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " server_nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " encrypted_data: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ set_client_DH_params" + result + "}"; + + case mtpc_messages_getDhConfig: + result += "\n" + add; + result += " version: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " random_length: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_getDhConfig" + result + "}"; + + case mtpc_geochats_getRecents: + result += "\n" + add; + result += " offset: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ geochats_getRecents" + result + "}"; + + case mtpc_geochats_search: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " q: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " filter: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " min_date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " max_date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " offset: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " max_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ geochats_search" + result + "}"; + + case mtpc_geochats_getHistory: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " offset: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " max_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ geochats_getHistory" + result + "}"; + + case mtpc_messages_receivedQueue: + result += "\n" + add; + result += " max_qts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_receivedQueue" + result + "}"; + + case mtpc_messages_sendMedia: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " media: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ messages_sendMedia" + result + "}"; + + case mtpc_messages_editChatTitle: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " title: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ messages_editChatTitle" + result + "}"; + + case mtpc_messages_editChatPhoto: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_editChatPhoto" + result + "}"; + + case mtpc_messages_addChatUser: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " fwd_limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_addChatUser" + result + "}"; + + case mtpc_messages_deleteChatUser: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_deleteChatUser" + result + "}"; + + case mtpc_messages_createChat: + result += "\n" + add; + result += " users: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " title: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ messages_createChat" + result + "}"; + + case mtpc_messages_forwardMessage: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ messages_forwardMessage" + result + "}"; + + case mtpc_users_getFullUser: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ users_getFullUser" + result + "}"; + + case mtpc_contacts_getBlocked: + result += "\n" + add; + result += " offset: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ contacts_getBlocked" + result + "}"; + + case mtpc_messages_getChats: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_int) + ",\n" + add; + return "{ messages_getChats" + result + "}"; + + case mtpc_contacts_getSuggested: + result += "\n" + add; + result += " limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ contacts_getSuggested" + result + "}"; + + case mtpc_auth_checkPhone: + result += "\n" + add; + result += " phone_number: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ auth_checkPhone" + result + "}"; + + case mtpc_contacts_getContacts: + result += "\n" + add; + result += " hash: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ contacts_getContacts" + result + "}"; + + case mtpc_rpc_drop_answer: + result += "\n" + add; + result += " req_msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ rpc_drop_answer" + result + "}"; + + case mtpc_contacts_importContacts: + result += "\n" + add; + result += " contacts: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " replace: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_importContacts" + result + "}"; + + case mtpc_auth_exportAuthorization: + result += "\n" + add; + result += " dc_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ auth_exportAuthorization" + result + "}"; + + case mtpc_auth_sendCode: + result += "\n" + add; + result += " phone_number: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " sms_type: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " api_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " api_hash: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " lang_code: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ auth_sendCode" + result + "}"; + + case mtpc_photos_uploadProfilePhoto: + result += "\n" + add; + result += " file: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " caption: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " geo_point: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " crop: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ photos_uploadProfilePhoto" + result + "}"; + + case mtpc_upload_getFile: + result += "\n" + add; + result += " location: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " offset: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ upload_getFile" + result + "}"; + + case mtpc_contacts_search: + result += "\n" + add; + result += " q: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ contacts_search" + result + "}"; + + case mtpc_help_getNearestDc: + result = " "; + return "{ help_getNearestDc" + result + "}"; + + case mtpc_messages_requestEncryption: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " g_a: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ messages_requestEncryption" + result + "}"; + + case mtpc_messages_acceptEncryption: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " g_b: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " key_fingerprint: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ messages_acceptEncryption" + result + "}"; + + case mtpc_users_getUsers: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ users_getUsers" + result + "}"; + + case mtpc_messages_forwardMessages: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_int) + ",\n" + add; + return "{ messages_forwardMessages" + result + "}"; + + case mtpc_messages_sendBroadcast: + result += "\n" + add; + result += " contacts: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " message: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " media: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_sendBroadcast" + result + "}"; + + case mtpc_photos_getUserPhotos: + result += "\n" + add; + result += " user_id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " offset: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " max_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ photos_getUserPhotos" + result + "}"; + + case mtpc_updates_getDifference: + result += "\n" + add; + result += " pts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " qts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ updates_getDifference" + result + "}"; + + case mtpc_account_updateProfile: + result += "\n" + add; + result += " first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ account_updateProfile" + result + "}"; + + case mtpc_account_getWallPapers: + result = " "; + return "{ account_getWallPapers" + result + "}"; + + case mtpc_messages_getMessages: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_int) + ",\n" + add; + return "{ messages_getMessages" + result + "}"; + + case mtpc_messages_getHistory: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " offset: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " max_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_getHistory" + result + "}"; + + case mtpc_messages_search: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " q: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " filter: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " min_date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " max_date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " offset: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " max_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_search" + result + "}"; + + case mtpc_req_DH_params: + result += "\n" + add; + result += " nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " server_nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + result += " p: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " q: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " public_key_fingerprint: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " encrypted_data: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ req_DH_params" + result + "}"; + + case mtpc_geochats_checkin: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ geochats_checkin" + result + "}"; + + case mtpc_geochats_editChatTitle: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " title: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " address: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ geochats_editChatTitle" + result + "}"; + + case mtpc_geochats_editChatPhoto: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " photo: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ geochats_editChatPhoto" + result + "}"; + + case mtpc_geochats_sendMessage: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " message: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ geochats_sendMessage" + result + "}"; + + case mtpc_geochats_sendMedia: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " media: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ geochats_sendMedia" + result + "}"; + + case mtpc_geochats_createGeoChat: + result += "\n" + add; + result += " title: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " geo_point: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " address: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " venue: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ geochats_createGeoChat" + result + "}"; + + case mtpc_req_pq: + result += "\n" + add; + result += " nonce: " + mtpTextSerialize(from, end, mtpc_int128, level + 1) + ",\n" + add; + return "{ req_pq" + result + "}"; + + case mtpc_invokeAfterMsg: + result += "\n" + add; + result += " msg_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " query: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ invokeAfterMsg" + result + "}"; + + case mtpc_invokeAfterMsgs: + result += "\n" + add; + result += " msg_ids: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_long) + ",\n" + add; + result += " query: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ invokeAfterMsgs" + result + "}"; + + case mtpc_initConnection: + result += "\n" + add; + result += " api_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " device_model: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " system_version: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " app_version: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " lang_code: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " query: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ initConnection" + result + "}"; + + case mtpc_messages_sendMessage: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " message: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ messages_sendMessage" + result + "}"; + + case mtpc_contacts_getStatuses: + result = " "; + return "{ contacts_getStatuses" + result + "}"; + + case mtpc_geochats_getLocated: + result += "\n" + add; + result += " geo_point: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " radius: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ geochats_getLocated" + result + "}"; + + case mtpc_account_getNotifySettings: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ account_getNotifySettings" + result + "}"; + + case mtpc_register_saveDeveloperInfo: + result += "\n" + add; + result += " name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " email: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " phone_number: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " age: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " city: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ register_saveDeveloperInfo" + result + "}"; + + case mtpc_auth_sendCall: + result += "\n" + add; + result += " phone_number: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " phone_code_hash: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ auth_sendCall" + result + "}"; + + case mtpc_auth_logOut: + result = " "; + return "{ auth_logOut" + result + "}"; + + case mtpc_auth_resetAuthorizations: + result = " "; + return "{ auth_resetAuthorizations" + result + "}"; + + case mtpc_auth_sendInvites: + result += "\n" + add; + result += " phone_numbers: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_string) + ",\n" + add; + result += " message: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ auth_sendInvites" + result + "}"; + + case mtpc_account_registerDevice: + result += "\n" + add; + result += " token_type: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " token: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " device_model: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " system_version: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " app_version: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " app_sandbox: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " lang_code: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ account_registerDevice" + result + "}"; + + case mtpc_account_unregisterDevice: + result += "\n" + add; + result += " token_type: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " token: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ account_unregisterDevice" + result + "}"; + + case mtpc_account_updateNotifySettings: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " settings: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ account_updateNotifySettings" + result + "}"; + + case mtpc_account_resetNotifySettings: + result = " "; + return "{ account_resetNotifySettings" + result + "}"; + + case mtpc_account_updateStatus: + result += "\n" + add; + result += " offline: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ account_updateStatus" + result + "}"; + + case mtpc_contacts_deleteContacts: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_deleteContacts" + result + "}"; + + case mtpc_contacts_block: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_block" + result + "}"; + + case mtpc_contacts_unblock: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_unblock" + result + "}"; + + case mtpc_messages_setTyping: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " typing: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_setTyping" + result + "}"; + + case mtpc_upload_saveFilePart: + result += "\n" + add; + result += " file_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " file_part: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ upload_saveFilePart" + result + "}"; + + case mtpc_help_saveAppLog: + result += "\n" + add; + result += " events: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ help_saveAppLog" + result + "}"; + + case mtpc_geochats_setTyping: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " typing: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ geochats_setTyping" + result + "}"; + + case mtpc_messages_discardEncryption: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_discardEncryption" + result + "}"; + + case mtpc_messages_setEncryptedTyping: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " typing: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_setEncryptedTyping" + result + "}"; + + case mtpc_messages_readEncryptedHistory: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " max_date: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_readEncryptedHistory" + result + "}"; + + case mtpc_upload_saveBigFilePart: + result += "\n" + add; + result += " file_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " file_part: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " file_total_parts: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ upload_saveBigFilePart" + result + "}"; + + case mtpc_messages_getDialogs: + result += "\n" + add; + result += " offset: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " max_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " limit: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_getDialogs" + result + "}"; + + case mtpc_destroy_session: + result += "\n" + add; + result += " session_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ destroy_session" + result + "}"; + + case mtpc_messages_getFullChat: + result += "\n" + add; + result += " chat_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_getFullChat" + result + "}"; + + case mtpc_geochats_getFullChat: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ geochats_getFullChat" + result + "}"; + + case mtpc_messages_sendEncrypted: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " data: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ messages_sendEncrypted" + result + "}"; + + case mtpc_messages_sendEncryptedFile: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " data: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + result += " file: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ messages_sendEncryptedFile" + result + "}"; + + case mtpc_messages_sendEncryptedService: + result += "\n" + add; + result += " peer: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " random_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " data: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ messages_sendEncryptedService" + result + "}"; + + case mtpc_get_future_salts: + result += "\n" + add; + result += " num: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ get_future_salts" + result + "}"; + + case mtpc_help_getInviteText: + result += "\n" + add; + result += " lang_code: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ help_getInviteText" + result + "}"; + + case mtpc_help_getConfig: + result = " "; + return "{ help_getConfig" + result + "}"; + + case mtpc_auth_signUp: + result += "\n" + add; + result += " phone_number: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " phone_code_hash: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " phone_code: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " first_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " last_name: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ auth_signUp" + result + "}"; + + case mtpc_auth_signIn: + result += "\n" + add; + result += " phone_number: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " phone_code_hash: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " phone_code: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ auth_signIn" + result + "}"; + + case mtpc_auth_importAuthorization: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + result += " bytes: " + mtpTextSerialize(from, end, mtpc_bytes, level + 1) + ",\n" + add; + return "{ auth_importAuthorization" + result + "}"; + + case mtpc_photos_updateProfilePhoto: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + result += " crop: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ photos_updateProfilePhoto" + result + "}"; + + case mtpc_contacts_deleteContact: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1) + ",\n" + add; + return "{ contacts_deleteContact" + result + "}"; + + case mtpc_messages_deleteMessages: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_int) + ",\n" + add; + return "{ messages_deleteMessages" + result + "}"; + + case mtpc_messages_restoreMessages: + result += "\n" + add; + result += " id: " + mtpTextSerialize(from, end, 0, level + 1, mtpc_int) + ",\n" + add; + return "{ messages_restoreMessages" + result + "}"; + + case mtpc_messages_receivedMessages: + result += "\n" + add; + result += " max_id: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ messages_receivedMessages" + result + "}"; + + case mtpc_help_getAppUpdate: + result += "\n" + add; + result += " device_model: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " system_version: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " app_version: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + result += " lang_code: " + mtpTextSerialize(from, end, mtpc_string, level + 1) + ",\n" + add; + return "{ help_getAppUpdate" + result + "}"; + + case mtpc_updates_getState: + result = " "; + return "{ updates_getState" + result + "}"; + + case mtpc_help_getSupport: + result = " "; + return "{ help_getSupport" + result + "}"; + + case mtpc_ping: + result += "\n" + add; + result += " ping_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + return "{ ping" + result + "}"; + + case mtpc_ping_delay_disconnect: + result += "\n" + add; + result += " ping_id: " + mtpTextSerialize(from, end, mtpc_long, level + 1) + ",\n" + add; + result += " disconnect_delay: " + mtpTextSerialize(from, end, mtpc_int, level + 1) + ",\n" + add; + return "{ ping_delay_disconnect" + result + "}"; + } + + return mtpTextSerializeCore(from, end, cons, level, vcons); + } catch (Exception &e) { + QString result = "(" + QString(e.what()) + QString("), cons: %1").arg(cons); + if (vcons) result += QString(", vcons: %1").arg(vcons); + result += ", " + mb(start, (end - start) * sizeof(mtpPrime)).str(); + return "[ERROR] " + result; + } +} + +#endif diff --git a/Telegram/SourceFiles/mtproto/mtpSession.cpp b/Telegram/SourceFiles/mtproto/mtpSession.cpp new file mode 100644 index 000000000..c510769b6 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpSession.cpp @@ -0,0 +1,439 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include + +void MTPSessionData::clear() { + RPCCallbackClears clearCallbacks; + { + QReadLocker locker1(haveSentMutex()), locker2(toResendMutex()), locker3(haveReceivedMutex()), locker4(wereAckedMutex()); + mtpResponseMap::const_iterator end = haveReceived.cend(); + clearCallbacks.reserve(haveSent.size() + wereAcked.size()); + for (mtpRequestMap::const_iterator i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { + mtpRequestId requestId = i.value()->requestId; + if (haveReceived.find(requestId) == end) { + clearCallbacks.push_back(requestId); + } + } + for (mtpRequestIdsMap::const_iterator i = toResend.cbegin(), e = toResend.cend(); i != e; ++i) { + mtpRequestId requestId = i.value(); + if (haveReceived.find(requestId) == end) { + clearCallbacks.push_back(requestId); + } + } + for (mtpRequestIdsMap::const_iterator i = wereAcked.cbegin(), e = wereAcked.cend(); i != e; ++i) { + mtpRequestId requestId = i.value(); + if (haveReceived.find(requestId) == end) { + clearCallbacks.push_back(requestId); + } + } + } + { + QWriteLocker locker(haveSentMutex()); + haveSent.clear(); + } + { + QWriteLocker locker(toResendMutex()); + toResend.clear(); + } + { + QWriteLocker locker(wereAckedMutex()); + wereAcked.clear(); + } + { + QWriteLocker locker(receivedIdsMutex()); + receivedIds.clear(); + } + _mtp_internal::clearCallbacksDelayed(clearCallbacks); +} + + +MTProtoSession::MTProtoSession() : data(this), dc(0), dcId(0), msSendCall(0), msWait(0) { +} + +void MTProtoSession::start(int32 dcenter, uint32 connects) { + if (dcId) { + DEBUG_LOG(("Session Info: MTProtoSession::start called on already started session")); + return; + } + if (connects < 1) { + connects = cConnectionsInSession(); + } else if (connects > 4) { + connects = 4; + } + + msSendCall = msWait = 0; + + connect(&timeouter, SIGNAL(timeout()), this, SLOT(checkRequestsByTimer())); + timeouter.start(1000); + + connect(&sender, SIGNAL(timeout()), this, SIGNAL(needToSend())); + connect(this, SIGNAL(startSendTimer(int)), &sender, SLOT(start(int))); + connect(this, SIGNAL(stopSendTimer()), &sender, SLOT(stop())); + connect(this, SIGNAL(needToSendAsync()), this, SIGNAL(needToSend())); + sender.setSingleShot(true); + + MTProtoDCMap &dcs(mtpDCMap()); + + connections.reserve(connects); + for (uint32 i = 0; i < connects; ++i) { + connections.push_back(new MTProtoConnection()); + dcId = connections.back()->start(&data, dcenter); + if (!dcId) { + for (MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend(); j != e; ++j) { + delete *j; + } + connections.clear(); + DEBUG_LOG(("Session Info: could not start connection %1 to dc %2").arg(i).arg(dcenter)); + return; + } + if (!dc) { + dcenter = dcId; + MTProtoDCMap::const_iterator dcIndex = dcs.constFind(dcId % _mtp_internal::dcShift); + if (dcIndex == dcs.cend()) { + dc = MTProtoDCPtr(new MTProtoDC(dcId % _mtp_internal::dcShift, mtpAuthKeyPtr())); + dcs.insert(dcId % _mtp_internal::dcShift, dc); + } else { + dc = dcIndex.value(); + } + + ReadLockerAttempt lock(keyMutex()); + data.setKey(lock ? dc->getKey() : mtpAuthKeyPtr(0)); + + connect(dc.data(), SIGNAL(authKeyCreated()), this, SLOT(authKeyCreatedForDC())); + } + } +} + +void MTProtoSession::restart() { + for (MTProtoConnections::const_iterator i = connections.cbegin(), e = connections.cend(); i != e; ++i) { + (*i)->restart(); + } +} + +void MTProtoSession::stop() { + while (connections.size()) { + connections.back()->stop(); + connections.pop_back(); + } +} + +void MTProtoSession::checkRequestsByTimer() { + MTPMsgsStateReq stateRequest(MTP_msgs_state_req(MTP_vector(0))); + QVector &stateRequestIds(stateRequest._msgs_state_req().vmsg_ids._vector().v); + + QVector resendingIds; + QVector removingIds; // remove very old (10 minutes) containers and resend requests + + { + QReadLocker locker(data.haveSentMutex()); + mtpRequestMap &haveSent(data.haveSentMap()); + uint32 haveSentCount(haveSent.size()); + uint64 ms = getms(); + for (mtpRequestMap::iterator i = haveSent.begin(), e = haveSent.end(); i != e; ++i) { + mtpRequest &req(i.value()); + if (req->msDate > 0) { + if (req->msDate + MTPCheckResendTimeout < ms) { // need to resend or check state + if (mtpRequestData::messageSize(req) < MTPResendThreshold) { // resend + resendingIds.reserve(haveSentCount); + resendingIds.push_back(i.key()); + } else { + req->msDate = ms; + stateRequestIds.reserve(haveSentCount); + stateRequestIds.push_back(MTP_long(i.key())); + } + } + } else if (unixtime() > (uint32)(i.key() >> 32) + MTPContainerLives) { + removingIds.reserve(haveSentCount); + removingIds.push_back(i.key()); + } + } + } + + if (stateRequestIds.size()) { + DEBUG_LOG(("MTP Info: requesting state of msgs: %1").arg(logVectorLong(stateRequestIds))); + send(stateRequest, RPCResponseHandler(), MTPCheckResendWaiting); + } + for (uint32 i = 0, l = resendingIds.size(); i < l; ++i) { + DEBUG_LOG(("MTP Info: resending request %1").arg(resendingIds[i])); + resend(resendingIds[i], MTPCheckResendWaiting); + } + uint32 removingIdsCount = removingIds.size(); + if (removingIdsCount) { + RPCCallbackClears clearCallbacks; + { + QWriteLocker locker(data.haveSentMutex()); + mtpRequestMap &haveSent(data.haveSentMap()); + for (uint32 i = 0; i < removingIdsCount; ++i) { + mtpRequestMap::iterator j = haveSent.find(removingIds[i]); + if (j != haveSent.cend()) { + if (j.value()->requestId) { + clearCallbacks.push_back(j.value()->requestId); + } + haveSent.erase(j); + } + } + } + _mtp_internal::clearCallbacksDelayed(clearCallbacks); + } +} + +void MTProtoSession::onConnectionStateChange(qint32 newState) { + _mtp_internal::onStateChange(dcId, newState); +} + +void MTProtoSession::cancel(mtpRequestId requestId) { + QWriteLocker locker(data.toSendMutex()); + mtpPreRequestMap &toSend(data.toSendMap()); + mtpPreRequestMap::iterator i = toSend.find(requestId); + if (i != toSend.end()) toSend.erase(i); +} + +int32 MTProtoSession::requestState(mtpRequestId requestId) const { + MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend(); + int32 result = MTP::RequestSent; + for (; j != e; ++j) { + int32 s = (*j)->state(); + if (s == MTProtoConnection::Connected) { + break; + } else if (s == MTProtoConnection::Connecting || s == MTProtoConnection::Disconnected) { + if (result < 0 || result == MTP::RequestSent) { + result = MTP::RequestConnecting; + } + } else if (s < 0) { + if (result < 0 && s > result || result == MTP::RequestSent) { + result = s; + } + } + } + if (j == e) { // no one is connected + return result; + } + if (!requestId) return MTP::RequestSent; + + QWriteLocker locker(data.toSendMutex()); + const mtpPreRequestMap &toSend(data.toSendMap()); + mtpPreRequestMap::const_iterator i = toSend.constFind(requestId); + if (i != toSend.cend()) { + return MTP::RequestSending; + } else { + return MTP::RequestSent; + } +} + +int32 MTProtoSession::getState() const { + MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend(); + int32 result = -86400000; + for (; j != e; ++j) { + int32 s = (*j)->state(); + if (s == MTProtoConnection::Connected) { + return s; + } else if (s == MTProtoConnection::Connecting || s == MTProtoConnection::Disconnected) { + if (result < 0) { + return s; + } + } else if (s < 0) { + if (result < 0 && s > result) { + result = s; + } + } + } + if (result == -86400000) { + result = MTProtoConnection::Disconnected; + } + return result; +} + +QString MTProtoSession::transport() const { + MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend(); + for (; j != e; ++j) { + QString s = (*j)->transport(); + if (!s.isEmpty()) return s; + } + return QString(); +} + +mtpRequestId MTProtoSession::resend(mtpMsgId msgId, uint64 msCanWait, bool forceContainer, bool sendMsgStateInfo) { + mtpRequest request; + { + QWriteLocker locker(data.haveSentMutex()); + mtpRequestMap &haveSent(data.haveSentMap()); + + mtpRequestMap::iterator i = haveSent.find(msgId); + if (i == haveSent.end()) { + if (sendMsgStateInfo) { + char cantResend[2] = {1, 0}; + DEBUG_LOG(("Message Info: cant resend %1, request not found").arg(msgId)); + + return send(MTP_msgs_state_info(MTP_long(msgId), MTP_string(string(cantResend, cantResend + 1)))); + } + return 0; + } + + request = i.value(); + haveSent.erase(i); + } + if (mtpRequestData::isSentContainer(request)) { // for container just resend all messages we can + DEBUG_LOG(("Message Info: resending container from haveSent, msgId %1").arg(msgId)); + const mtpMsgId *ids = (const mtpMsgId *)(request->constData() + 8); + for (uint32 i = 0, l = (request->size() - 8) >> 1; i < l; ++i) { + resend(ids[i], 10, true); + } + return 0xFFFFFFFF; + } else if (!mtpRequestData::isStateRequest(request)) { + request->msDate = forceContainer ? 0 : getms(); + sendPrepared(request, msCanWait, false); + { + QWriteLocker locker(data.toResendMutex()); + data.toResendMap().insert(msgId, request->requestId); + } + return request->requestId; + } else { + return 0; + } +} + +void MTProtoSession::resendAll() { + QVector toResend; + { + QReadLocker locker(data.haveSentMutex()); + const mtpRequestMap &haveSent(data.haveSentMap()); + toResend.reserve(haveSent.size()); + for (mtpRequestMap::const_iterator i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { + if (i.value()->requestId) toResend.push_back(i.key()); + } + } + for (uint32 i = 0, l = toResend.size(); i < l; ++i) { + resend(toResend[i], 10, true); + } +} + +void MTProtoSession::sendPrepared(const mtpRequest &request, uint64 msCanWait, bool newRequest) { // returns true, if emit of needToSend() is needed + { + QWriteLocker locker(data.toSendMutex()); + data.toSendMap().insert(request->requestId, request); + + if (newRequest) { + *(mtpMsgId*)(request->data() + 4) = 0; + *(request->data() + 6) = 0; + } + } + + DEBUG_LOG(("MTP Info: added, requestId %1").arg(request->requestId)); + + uint64 ms = getms(); + if (msSendCall) { + if (ms > msSendCall + msWait) { + msWait = 0; + } else { + msWait = (msSendCall + msWait) - ms; + if (msWait > msCanWait) { + msWait = msCanWait; + } + } + } else { + msWait = msCanWait; + } + if (msWait) { + msSendCall = ms; + emit startSendTimer(msWait); + DEBUG_LOG(("MTP Info: can wait for %1ms from current %2").arg(msWait).arg(msSendCall)); + } else { + emit stopSendTimer(); + msSendCall = 0; + emit needToSendAsync(); + } +} + +void MTProtoSession::sendPreparedWithInit(const mtpRequest &request, uint64 msCanWait) { // returns true, if emit of needToSend() is needed + if (request->size() > 8 && request->at(8) == mtpc_initConnection) { + sendPrepared(request, msCanWait, false); + return; + } + MTPInitConnection requestWrap(MTPinitConnection(MTP_int(ApiId), MTP_string(cApiDeviceModel()), MTP_string(cApiSystemVersion()), MTP_string(cApiAppVersion()), MTP_string(ApiLang), request)); + uint32 requestSize = requestWrap.size() >> 2; + mtpRequest reqSerialized(mtpRequestData::prepare(requestSize)); + requestWrap.write(*reqSerialized); + + reqSerialized->msDate = getms(); // > 0 - can send without container + _mtp_internal::replaceRequest(reqSerialized, request); + sendPrepared(reqSerialized, msCanWait); +} + +QReadWriteLock *MTProtoSession::keyMutex() const { + return dc->keyMutex(); +} + +void MTProtoSession::authKeyCreatedForDC() { + DEBUG_LOG(("AuthKey Info: MTProtoSession::authKeyCreatedForDC slot, emitting authKeyCreated(), dc %1").arg(dcId)); + data.setKey(dc->getKey()); + emit authKeyCreated(); +} + +void MTProtoSession::keyCreated(const mtpAuthKeyPtr &key) { + DEBUG_LOG(("AuthKey Info: MTProtoSession::keyCreated(), setting, dc %1").arg(dcId)); + dc->setKey(key); +} + +void MTProtoSession::destroyKey() { + if (!dc) return; + + if (data.getKey()) { + DEBUG_LOG(("MTP Info: destroying auth_key for dc %1").arg(dcId)); + if (data.getKey() == dc->getKey()) { + dc->destroyKey(); + } + data.setKey(mtpAuthKeyPtr(0)); + } +} + +int32 MTProtoSession::getDC() const { + return dcId; +} + +void MTProtoSession::tryToReceive() { + while (true) { + mtpRequestId requestId; + mtpResponse response; + { + QWriteLocker locker(data.haveReceivedMutex()); + mtpResponseMap &responses(data.haveReceivedMap()); + mtpResponseMap::iterator i = responses.begin(); + if (i == responses.end()) return; + + requestId = i.key(); + response = i.value(); + responses.erase(i); + } + if (requestId <= 0) { + _mtp_internal::globalCallback(response.constData(), response.constData() + response.size()); + } else { + _mtp_internal::execCallback(requestId, response.constData(), response.constData() + response.size()); + } + } +} + +MTProtoSession::~MTProtoSession() { + for (MTProtoConnections::const_iterator i = connections.cbegin(), e = connections.cend(); i != e; ++i) { + delete *i; + } +} + +MTPrpcError rpcClientError(const QString &type, const QString &description) { + return MTP_rpc_error(MTP_int(0), MTP_string(("CLIENT_" + type + (description.length() ? (": " + description) : "")).toUtf8().constData())); +} diff --git a/Telegram/SourceFiles/mtproto/mtpSession.h b/Telegram/SourceFiles/mtproto/mtpSession.h new file mode 100644 index 000000000..1f198e142 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpSession.h @@ -0,0 +1,272 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "mtpConnection.h" +#include "mtpDC.h" +#include "mtpRPC.h" + +class MTProtoSession; + +class MTPSessionData { +public: + + MTPSessionData(MTProtoSession *creator) + : _session(0), _salt(0), fakeRequestId(-2000000000) + , _messagesSent(0), keyChecked(false) + , _owner(creator) { + } + + void setSession(uint64 session) { + DEBUG_LOG(("MTP Info: setting server_session: %1").arg(session)); + + QWriteLocker locker(&lock); + if (_session != session) { + _session = session; + _messagesSent = 0; + } + } + uint64 getSession() const { + QReadLocker locker(&lock); + return _session; + } + + void setSalt(uint64 salt) { + QWriteLocker locker(&lock); + _salt = salt; + } + uint64 getSalt() const { + QReadLocker locker(&lock); + return _salt; + } + + const mtpAuthKeyPtr &getKey() const { + return authKey; + } + void setKey(const mtpAuthKeyPtr &key) { + if (authKey != key) { + uint64 session; + memset_rand(&session, sizeof(uint64)); + + authKey = key; + + DEBUG_LOG(("MTP Info: new auth key set in SessionData, id %1, setting random server_session %2").arg(key ? key->keyId() : 0).arg(session)); + setSession(session); + } + } + + bool isCheckedKey() const { + QReadLocker locker(&lock); + return keyChecked; + } + void setCheckedKey(bool checked) { + QWriteLocker locker(&lock); + keyChecked = checked; + } + + QReadWriteLock *keyMutex() const; + + QReadWriteLock *toSendMutex() const { + return &toSendLock; + } + QReadWriteLock *haveSentMutex() const { + return &haveSentLock; + } + QReadWriteLock *toResendMutex() const { + return &toResendLock; + } + QReadWriteLock *wereAckedMutex() const { + return &wereAckedLock; + } + QReadWriteLock *receivedIdsMutex() const { + return &receivedIdsLock; + } + QReadWriteLock *haveReceivedMutex() const { + return &haveReceivedLock; + } + + mtpPreRequestMap &toSendMap() { + return toSend; + } + const mtpPreRequestMap &toSendMap() const { + return toSend; + } + mtpRequestMap &haveSentMap() { + return haveSent; + } + const mtpRequestMap &haveSentMap() const { + return haveSent; + } + mtpRequestIdsMap &toResendMap() { // msgId -> requestId, on which toSend: requestId -> request for resended requests + return toResend; + } + const mtpRequestIdsMap &toResendMap() const { + return toResend; + } + mtpMsgIdsSet &receivedIdsSet() { + return receivedIds; + } + const mtpMsgIdsSet &receivedIdsSet() const { + return receivedIds; + } + mtpRequestIdsMap &wereAckedMap() { + return wereAcked; + } + const mtpRequestIdsMap &wereAckedMap() const { + return wereAcked; + } + mtpResponseMap &haveReceivedMap() { + return haveReceived; + } + const mtpResponseMap &haveReceivedMap() const { + return haveReceived; + } + + mtpRequestId nextFakeRequestId() { // must be locked by haveReceivedMutex() + if (haveReceived.isEmpty() || haveReceived.cbegin().key() > 0) { + fakeRequestId = -2000000000; + } else { + ++fakeRequestId; + } + return fakeRequestId; + } + + MTProtoSession *owner() { + return _owner; + } + const MTProtoSession *owner() const { + return _owner; + } + + uint32 nextRequestSeqNumber(bool needAck = true) { + QWriteLocker locker(&lock); + uint32 result(_messagesSent); + _messagesSent += (needAck ? 1 : 0); + return result * 2 + (needAck ? 1 : 0); + } + + void clear(); + +private: + uint64 _session, _salt; + + uint32 _messagesSent; + mtpRequestId fakeRequestId; + + MTProtoSession *_owner; + + mtpAuthKeyPtr authKey; + bool keyChecked; + + mtpPreRequestMap toSend; // map of request_id -> request, that is waiting to be sent + mtpRequestMap haveSent; // map of msg_id -> request, that was sent, msDate = 0 for msgs_state_req (no resend / state req), msDate = 0, seqNo = 0 for containers + mtpRequestIdsMap toResend; // map of msg_id -> request_id, that request_id -> request lies in toSend and is waiting to be resent + mtpMsgIdsSet receivedIds; // set of received msg_id's, for checking new msg_ids + mtpRequestIdsMap wereAcked; // map of msg_id -> request_id, this msg_ids already were acked or do not need ack + mtpResponseMap haveReceived; // map of request_id -> response, that should be processed in other thread + + // mutexes + mutable QReadWriteLock lock; + mutable QReadWriteLock toSendLock; + mutable QReadWriteLock haveSentLock; + mutable QReadWriteLock toResendLock; + mutable QReadWriteLock receivedIdsLock; + mutable QReadWriteLock wereAckedLock; + mutable QReadWriteLock haveReceivedLock; + +}; + +class MTProtoSession : public QObject { + Q_OBJECT + +public: + + MTProtoSession(); + + void start(int32 dcenter = 0, uint32 connects = 0); + void restart(); + void stop(); + + int32 getDC() const; + ~MTProtoSession(); + + QReadWriteLock *keyMutex() const; + void keyCreated(const mtpAuthKeyPtr &key); + void destroyKey(); + + template + mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, uint32 layer = 0, bool toMainDC = false); // send mtp request + + void cancel(mtpRequestId requestId); + int32 requestState(mtpRequestId requestId) const; + int32 getState() const; + QString transport() const; + + mtpRequestId resend(mtpMsgId msgId, uint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false); + void resendAll(); // after connection restart + + void sendPrepared(const mtpRequest &request, uint64 msCanWait = 0, bool newRequest = true); // nulls msgId and seqNo in request, if newRequest = true + void sendPreparedWithInit(const mtpRequest &request, uint64 msCanWait = 0); + +signals: + + void authKeyCreated(); + + void needToSend(); + void needToSendAsync(); // emit this signal, to emit needToSend() in MTProtoSession thread + + void startSendTimer(int msec); // manipulating timer from all threads + void stopSendTimer(); + +public slots: + + void authKeyCreatedForDC(); + + void tryToReceive(); + void checkRequestsByTimer(); + void onConnectionStateChange(qint32 newState); + +private: + + template + mtpRequestId sendFirst(const MTPInitConnection &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, uint32 layer = 0, bool toMainDC = false); // send first mtp request + + typedef QList MTProtoConnections; + MTProtoConnections connections; + + MTPSessionData data; + + int32 dcId; + MTProtoDCPtr dc; + + uint64 msSendCall, msWait; + + QTimer timeouter; + QTimer sender; + +}; + +inline QReadWriteLock *MTPSessionData::keyMutex() const { + return _owner->keyMutex(); +} + +MTPrpcError rpcClientError(const QString &type, const QString &description = QString()); + +// here + +typedef QSharedPointer MTProtoSessionPtr; diff --git a/Telegram/SourceFiles/mtproto/mtpSessionImpl.h b/Telegram/SourceFiles/mtproto/mtpSessionImpl.h new file mode 100644 index 000000000..3c0ac7989 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/mtpSessionImpl.h @@ -0,0 +1,86 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +template +mtpRequestId MTProtoSession::send(const TRequest &request, RPCResponseHandler callbacks, uint64 msCanWait, uint32 layer, bool toMainDC) { + mtpRequestId requestId = 0; + if (layer && dc->needConnectionInit()) { + MTPInitConnection requestWrap(MTPinitConnection(MTP_int(ApiId), MTP_string(cApiDeviceModel()), MTP_string(cApiSystemVersion()), MTP_string(cApiAppVersion()), MTP_string(ApiLang), request)); + return sendFirst(requestWrap, callbacks, msCanWait, layer, toMainDC); + } + try { + uint32 requestSize = request.size() >> 2; + if (dc->connectionInited()) layer = 0; + mtpRequest reqSerialized(mtpRequestData::prepare(requestSize + (layer ? 1 : 0))); + if (layer) reqSerialized->push_back(mtpLayers[layer]); + request.write(*reqSerialized); + + DEBUG_LOG(("MTP Info: adding request to toSendMap, msCanWait %1").arg(msCanWait)); + + reqSerialized->msDate = getms(); // > 0 - can send without container + requestId = _mtp_internal::storeRequest(reqSerialized, callbacks); + + sendPrepared(reqSerialized, msCanWait); + } catch (Exception &e) { + requestId = 0; + _mtp_internal::rpcErrorOccured(requestId, callbacks, rpcClientError("NO_REQUEST_ID", QString("send() failed to queue request, exception: %1").arg(e.what()))); + } + if (requestId) _mtp_internal::registerRequest(requestId, toMainDC ? -getDC() : getDC()); + return requestId; +} + +class RPCWrappedDcDoneHandler : public RPCAbstractDoneHandler { +public: + RPCWrappedDcDoneHandler(const MTProtoDCPtr &dc, const RPCDoneHandlerPtr &ondone) : _dc(dc), _ondone(ondone) { + } + + void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const { + _dc->setConnectionInited(); + return (*_ondone)(requestId, from, end); + } + +private: + MTProtoDCPtr _dc; + RPCDoneHandlerPtr _ondone; +}; + +template +mtpRequestId MTProtoSession::sendFirst(const MTPInitConnection &request, RPCResponseHandler callbacks, uint64 msCanWait, uint32 layer, bool toMainDC) { + mtpRequestId requestId = 0; + try { + uint32 requestSize = request.size() >> 2; + mtpRequest reqSerialized(mtpRequestData::prepare(requestSize + (layer ? 1 : 0))); + if (layer) reqSerialized->push_back(mtpLayers[layer]); + request.write(*reqSerialized); + + DEBUG_LOG(("MTP Info: adding wrapped to init connection request to toSendMap, msCanWait %1").arg(msCanWait)); + callbacks.onDone = RPCDoneHandlerPtr(new RPCWrappedDcDoneHandler(dc, callbacks.onDone)); + reqSerialized->msDate = getms(); // > 0 - can send without container + requestId = _mtp_internal::storeRequest(reqSerialized, callbacks); + + sendPrepared(reqSerialized, msCanWait); + } catch (Exception &e) { + requestId = 0; + _mtp_internal::rpcErrorOccured(requestId, callbacks, rpcClientError("NO_REQUEST_ID", QString("sendFirst() failed to queue request, exception: %1").arg(e.what()))); + } + if (requestId) { + _mtp_internal::registerRequest(requestId, toMainDC ? -getDC() : getDC()); + } + return requestId; +} diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl new file mode 100644 index 000000000..8b84bcf13 --- /dev/null +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -0,0 +1,625 @@ +// Core types (no need to gen) + +//boolFalse#bc799737 = Bool; +//boolTrue#997275b5 = Bool; + +//vector#1cb5c415 {t:Type} # [ t ] = Vector t; + +//error#c4b9f9bb code:int text:string = Error; + +//null#56730bcc = Null; + +/////////////////////////////// +/////////////////// Layer cons +/////////////////////////////// + + +//invokeAfterMsg#cb9f372d msg_id:long query:!X = X; +//invokeAfterMsgs#3dc4b4f0 msg_ids:Vector query:!X = X; +//invokeWithLayer1#53835315 query:!X = X; +//invokeWithLayer2#289dd1f6 query:!X = X; +//invokeWithLayer3#b7475268 query:!X = X; +//invokeWithLayer4#dea0d430 query:!X = X; +//invokeWithLayer5#417a57ae query:!X = X; +//invokeWithLayer6#3a64d54d query:!X = X; +//invokeWithLayer7#a5be56d3 query:!X = X; +//invokeWithLayer8#e9abd9fd query:!X = X; +//invokeWithLayer9#76715a63 query:!X = X; +//invokeWithLayer10#39620c41 query:!X = X; +//invokeWithLayer11#a6b88fdf query:!X = X; +//invokeWithLayer12#dda60d3c query:!X = X; +//invokeWithLayer13#427c8ea2 query:!X = X; +//invokeWithLayer14#2b9b08fa query:!X = X; + +/////////////////////////////// +/// Authorization key creation +/////////////////////////////// + +resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector = ResPQ; + +p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; + +server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; +server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; + +server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; + +client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data; + +dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; +dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; +dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; + +---functions--- + +req_pq#60469778 nonce:int128 = ResPQ; + +req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params; + +set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer; + +/////////////////////////////// +////////////// System messages +/////////////////////////////// + +---types--- + +msgs_ack#62d6b459 msg_ids:Vector = MsgsAck; + +bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification; +bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification; + +msgs_state_req#da69fb52 msg_ids:Vector = MsgsStateReq; +msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo; +msgs_all_info#8cc0d131 msg_ids:Vector info:string = MsgsAllInfo; + +msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo; +msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo; + +msg_resend_req#7d861a08 msg_ids:Vector = MsgResendReq; + +//rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; // parsed manually + +rpc_error#2144ca19 error_code:int error_message:string = RpcError; + +rpc_answer_unknown#5e2ad36e = RpcDropAnswer; +rpc_answer_dropped_running#cd78e586 = RpcDropAnswer; +rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer; + +future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt; +future_salts#ae500895 req_msg_id:long now:int salts:vector = FutureSalts; + +pong#347773c5 msg_id:long ping_id:long = Pong; + +destroy_session_ok#e22045fc session_id:long = DestroySessionRes; +destroy_session_none#62d350c9 session_id:long = DestroySessionRes; + +new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession; + +//message msg_id:long seqno:int bytes:int body:Object = Message; // parsed manually +//msg_container#73f1f8dc messages:vector = MessageContainer; // parsed manually +//msg_copy#e06046b2 orig_message:Message = MessageCopy; // parsed manually, not used - use msg_container +//gzip_packed#3072cfa1 packed_data:string = Object; // parsed manually + +http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; + +---functions--- + +rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer; + +get_future_salts#b921bd04 num:int = FutureSalts; + +ping#7abe77ec ping_id:long = Pong; +ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong; + +destroy_session#e7512126 session_id:long = DestroySessionRes; + +register.saveDeveloperInfo#9a5f6e95 name:string email:string phone_number:string age:int city:string = Bool; + +/////////////////////////////// +///////// Main application API +/////////////////////////////// + +---types--- + + +inputPeerEmpty#7f3b18ea = InputPeer; +inputPeerSelf#7da07ec9 = InputPeer; +inputPeerContact#1023dbe8 user_id:int = InputPeer; +inputPeerForeign#9b447325 user_id:int access_hash:long = InputPeer; +inputPeerChat#179be863 chat_id:int = InputPeer; + +inputUserEmpty#b98886cf = InputUser; +inputUserSelf#f7c1b13f = InputUser; +inputUserContact#86e94f65 user_id:int = InputUser; +inputUserForeign#655e74ff user_id:int access_hash:long = InputUser; + +inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; + +inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; + +inputMediaEmpty#9664f57f = InputMedia; +inputMediaUploadedPhoto#2dc53a7d file:InputFile = InputMedia; +inputMediaPhoto#8f2ab2ec id:InputPhoto = InputMedia; +inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; +inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; +inputMediaUploadedVideo#133ad6f6 file:InputFile duration:int w:int h:int mime_type:string = InputMedia; +inputMediaUploadedThumbVideo#9912dabf file:InputFile thumb:InputFile duration:int w:int h:int mime_type:string = InputMedia; +inputMediaVideo#7f023ae6 id:InputVideo = InputMedia; + +inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; +inputChatUploadedPhoto#94254732 file:InputFile crop:InputPhotoCrop = InputChatPhoto; +inputChatPhoto#b2e1bf08 id:InputPhoto crop:InputPhotoCrop = InputChatPhoto; + +inputGeoPointEmpty#e4c123d6 = InputGeoPoint; +inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; + +inputPhotoEmpty#1cd7bf0d = InputPhoto; +inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; + +inputVideoEmpty#5508ec75 = InputVideo; +inputVideo#ee579652 id:long access_hash:long = InputVideo; + +inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; +inputVideoFileLocation#3d0364ec id:long access_hash:long = InputFileLocation; + +inputPhotoCropAuto#ade6b004 = InputPhotoCrop; +inputPhotoCrop#d9915325 crop_left:double crop_top:double crop_width:double = InputPhotoCrop; + +inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; + +peerUser#9db1bc6d user_id:int = Peer; +peerChat#bad0e5bb chat_id:int = Peer; + +storage.fileUnknown#aa963b05 = storage.FileType; +storage.fileJpeg#7efe0e = storage.FileType; +storage.fileGif#cae1aadf = storage.FileType; +storage.filePng#a4f63c0 = storage.FileType; +storage.filePdf#ae1e508d = storage.FileType; +storage.fileMp3#528a0677 = storage.FileType; +storage.fileMov#4b09ebbc = storage.FileType; +storage.filePartial#40bc6f52 = storage.FileType; +storage.fileMp4#b3cea0e4 = storage.FileType; +storage.fileWebp#1081464c = storage.FileType; + +fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; +fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; + +userEmpty#200250ba id:int = User; +userSelf#720535ec id:int first_name:string last_name:string phone:string photo:UserProfilePhoto status:UserStatus inactive:Bool = User; +userContact#f2fb8319 id:int first_name:string last_name:string access_hash:long phone:string photo:UserProfilePhoto status:UserStatus = User; +userRequest#22e8ceb0 id:int first_name:string last_name:string access_hash:long phone:string photo:UserProfilePhoto status:UserStatus = User; +userForeign#5214c89d id:int first_name:string last_name:string access_hash:long photo:UserProfilePhoto status:UserStatus = User; +userDeleted#b29ad7cc id:int first_name:string last_name:string = User; + +userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; +userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; + +userStatusEmpty#9d05049 = UserStatus; +userStatusOnline#edb93949 expires:int = UserStatus; +userStatusOffline#8c703f was_online:int = UserStatus; + +chatEmpty#9ba2d800 id:int = Chat; +chat#6e9c9bc7 id:int title:string photo:ChatPhoto participants_count:int date:int left:Bool version:int = Chat; +chatForbidden#fb0ccc41 id:int title:string date:int = Chat; + +chatFull#630e61be id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings = ChatFull; + +chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; + +chatParticipantsForbidden#fd2bb8a chat_id:int = ChatParticipants; +chatParticipants#7841b415 chat_id:int admin_id:int participants:Vector version:int = ChatParticipants; + +chatPhotoEmpty#37c1011c = ChatPhoto; +chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; + +messageEmpty#83e5de54 id:int = Message; +message#22eb6aba id:int from_id:int to_id:Peer out:Bool unread:Bool date:int message:string media:MessageMedia = Message; +messageForwarded#5f46804 id:int fwd_from_id:int fwd_date:int from_id:int to_id:Peer out:Bool unread:Bool date:int message:string media:MessageMedia = Message; +messageService#9f8d60bb id:int from_id:int to_id:Peer out:Bool unread:Bool date:int action:MessageAction = Message; + +messageMediaEmpty#3ded6320 = MessageMedia; +messageMediaPhoto#c8c45a2a photo:Photo = MessageMedia; +messageMediaVideo#a2d24290 video:Video = MessageMedia; +messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; +messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; +messageMediaUnsupported#29632a36 bytes:bytes = MessageMedia; + +messageActionEmpty#b6aef7b0 = MessageAction; +messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; +messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; +messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; +messageActionChatDeletePhoto#95e3fbef = MessageAction; +messageActionChatAddUser#5e3cfc4b user_id:int = MessageAction; +messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; + +dialog#ab3a99ac peer:Peer top_message:int unread_count:int notify_settings:PeerNotifySettings = Dialog; + +photoEmpty#2331b22d id:long = Photo; +photo#22b56751 id:long access_hash:long user_id:int date:int caption:string geo:GeoPoint sizes:Vector = Photo; + +photoSizeEmpty#e17e23c type:string = PhotoSize; +photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; +photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; + +videoEmpty#c10658a8 id:long = Video; +video#388fa391 id:long access_hash:long user_id:int date:int caption:string duration:int mime_type:string size:int thumb:PhotoSize dc_id:int w:int h:int = Video; + +geoPointEmpty#1117dd5f = GeoPoint; +geoPoint#2049d70c long:double lat:double = GeoPoint; + +auth.checkedPhone#e300cc3b phone_registered:Bool phone_invited:Bool = auth.CheckedPhone; + +auth.sentCode#efed51d9 phone_registered:Bool phone_code_hash:string send_call_timeout:int is_password:Bool = auth.SentCode; + +auth.authorization#f6b673a4 expires:int user:User = auth.Authorization; + +auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; + +inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; +inputNotifyUsers#193b4417 = InputNotifyPeer; +inputNotifyChats#4a95e84e = InputNotifyPeer; +inputNotifyAll#a429b886 = InputNotifyPeer; + +inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents; +inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents; + +inputPeerNotifySettings#46a2ce98 mute_until:int sound:string show_previews:Bool events_mask:int = InputPeerNotifySettings; + +peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents; +peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents; + +peerNotifySettingsEmpty#70a68512 = PeerNotifySettings; +peerNotifySettings#8d5e11ee mute_until:int sound:string show_previews:Bool events_mask:int = PeerNotifySettings; + +wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; + +userFull#771095da user:User link:contacts.Link profile_photo:Photo notify_settings:PeerNotifySettings blocked:Bool real_first_name:string real_last_name:string = UserFull; + +contact#f911c994 user_id:int mutual:Bool = Contact; + +importedContact#d0028438 user_id:int client_id:long = ImportedContact; + +contactBlocked#561bc879 user_id:int date:int = ContactBlocked; + +contactFound#ea879f95 user_id:int = ContactFound; + +contactSuggested#3de191a1 user_id:int mutual_contacts:int = ContactSuggested; + +contactStatus#aa77b873 user_id:int expires:int = ContactStatus; + +chatLocated#3631cf4c chat_id:int distance:int = ChatLocated; + +contacts.foreignLinkUnknown#133421f8 = contacts.ForeignLink; +contacts.foreignLinkRequested#a7801f47 has_phone:Bool = contacts.ForeignLink; +contacts.foreignLinkMutual#1bea8ce1 = contacts.ForeignLink; + +contacts.myLinkEmpty#d22a1c60 = contacts.MyLink; +contacts.myLinkRequested#6c69efee contact:Bool = contacts.MyLink; +contacts.myLinkContact#c240ebd9 = contacts.MyLink; + +contacts.link#eccea3f5 my_link:contacts.MyLink foreign_link:contacts.ForeignLink user:User = contacts.Link; + +contacts.contacts#6f8b8cb2 contacts:Vector users:Vector = contacts.Contacts; +contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; + +contacts.importedContacts#ad524315 imported:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; + +contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; +contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; + +contacts.found#566000e results:Vector users:Vector = contacts.Found; + +contacts.suggested#5649dcc5 results:Vector users:Vector = contacts.Suggested; + +messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; +messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; + +messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; +messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; + +messages.messageEmpty#3f4e0648 = messages.Message; +messages.message#ff90c417 message:Message chats:Vector users:Vector = messages.Message; + +messages.statedMessages#969478bb messages:Vector chats:Vector users:Vector pts:int seq:int = messages.StatedMessages; + +messages.statedMessage#d07ae726 message:Message chats:Vector users:Vector pts:int seq:int = messages.StatedMessage; + +messages.sentMessage#d1f4d35c id:int date:int pts:int seq:int = messages.SentMessage; + +messages.chat#40e9002a chat:Chat users:Vector = messages.Chat; + +messages.chats#8150cbd8 chats:Vector users:Vector = messages.Chats; + +messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; + +messages.affectedHistory#b7de36f2 pts:int seq:int offset:int = messages.AffectedHistory; + +inputMessagesFilterEmpty#57e2f66c = MessagesFilter; +inputMessagesFilterPhotos#9609a51c = MessagesFilter; +inputMessagesFilterVideo#9fc00e65 = MessagesFilter; +inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; +inputMessagesFilterDocument#9eddf188 = MessagesFilter; + +updateNewMessage#13abdb3 message:Message pts:int = Update; +updateMessageID#4e90bfd6 id:int random_id:long = Update; +updateReadMessages#c6649e31 messages:Vector pts:int = Update; +updateDeleteMessages#a92bfe26 messages:Vector pts:int = Update; +updateRestoreMessages#d15de04d messages:Vector pts:int = Update; +updateUserTyping#6baa8508 user_id:int = Update; +updateChatUserTyping#3c46cfe6 chat_id:int user_id:int = Update; +updateChatParticipants#7761198 participants:ChatParticipants = Update; +updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; +updateUserName#da22d9ad user_id:int first_name:string last_name:string = Update; +updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; +updateContactRegistered#2575bbb9 user_id:int date:int = Update; +updateContactLink#51a48a9a user_id:int my_link:contacts.MyLink foreign_link:contacts.ForeignLink = Update; +updateActivation#6f690963 user_id:int = Update; +updateNewAuthorization#8f06529a auth_key_id:long date:int device:string location:string = Update; + +updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; + +updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; +updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; +updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; + +updatesTooLong#e317af7e = Updates; +updateShortMessage#d3f45784 id:int from_id:int message:string pts:int date:int seq:int = Updates; +updateShortChatMessage#2b2fbd4e id:int from_id:int chat_id:int message:string pts:int date:int seq:int = Updates; +updateShort#78d4dec1 update:Update date:int = Updates; +updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; +updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; + +photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; +photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; + +photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; + +upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; + +dcOption#2ec2a43c id:int hostname:string ip_address:string port:int = DcOption; + +config#2e54dd74 date:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int broadcast_size_max:int = Config; + +nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; + +help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; +help.noAppUpdate#c45a6536 = help.AppUpdate; + +help.inviteText#18cb9f78 message:string = help.InviteText; + +messages.statedMessagesLinks#3e74f5c6 messages:Vector chats:Vector users:Vector links:Vector pts:int seq:int = messages.StatedMessages; + +messages.statedMessageLink#a9af2881 message:Message chats:Vector users:Vector links:Vector pts:int seq:int = messages.StatedMessage; + +messages.sentMessageLink#e9db4a3f id:int date:int pts:int seq:int links:Vector = messages.SentMessage; + +inputGeoChat#74d456fa chat_id:int access_hash:long = InputGeoChat; + +inputNotifyGeoChatPeer#4d8ddec8 peer:InputGeoChat = InputNotifyPeer; + +geoChat#75eaea5a id:int access_hash:long title:string address:string venue:string geo:GeoPoint photo:ChatPhoto participants_count:int date:int checked_in:Bool version:int = Chat; + +geoChatMessageEmpty#60311a9b chat_id:int id:int = GeoChatMessage; +geoChatMessage#4505f8e1 chat_id:int id:int from_id:int date:int message:string media:MessageMedia = GeoChatMessage; +geoChatMessageService#d34fa24e chat_id:int id:int from_id:int date:int action:MessageAction = GeoChatMessage; + +geochats.statedMessage#17b1578b message:GeoChatMessage chats:Vector users:Vector seq:int = geochats.StatedMessage; + +geochats.located#48feb267 results:Vector messages:Vector chats:Vector users:Vector = geochats.Located; + +geochats.messages#d1526db1 messages:Vector chats:Vector users:Vector = geochats.Messages; +geochats.messagesSlice#bc5863e8 count:int messages:Vector chats:Vector users:Vector = geochats.Messages; + +messageActionGeoChatCreate#6f038ebc title:string address:string = MessageAction; +messageActionGeoChatCheckin#c7d53de = MessageAction; + +updateNewGeoChatMessage#5a68e3f7 message:GeoChatMessage = Update; + +wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; + +updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; +updateEncryptedChatTyping#1710f156 chat_id:int = Update; +updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; +updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; + +encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; +encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; +encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; +encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; +encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; + +inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; + +encryptedFileEmpty#c21f497e = EncryptedFile; +encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; + +inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; +inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; +inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; + +inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; + +encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; +encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; + +decryptedMessageLayer#99a438cf layer:int message:DecryptedMessage = DecryptedMessageLayer; + +decryptedMessage#1f814f1f random_id:long random_bytes:bytes message:string media:DecryptedMessageMedia = DecryptedMessage; +decryptedMessageService#aa48327d random_id:long random_bytes:bytes action:DecryptedMessageAction = DecryptedMessage; + +decryptedMessageMediaEmpty#89f5c4a = DecryptedMessageMedia; +decryptedMessageMediaPhoto#32798a8c thumb:bytes thumb_w:int thumb_h:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia; +decryptedMessageMediaVideo#524a415d thumb:bytes thumb_w:int thumb_h:int duration:int mime_type:string w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia; +decryptedMessageMediaGeoPoint#35480a59 lat:double long:double = DecryptedMessageMedia; +decryptedMessageMediaContact#588a0a97 phone_number:string first_name:string last_name:string user_id:int = DecryptedMessageMedia; + +decryptedMessageActionSetMessageTTL#a1733aec ttl_seconds:int = DecryptedMessageAction; + +messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; +messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; + +messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; +messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; + +inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; + +inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; + +updateChatParticipantAdd#3a0eeb22 chat_id:int user_id:int inviter_id:int version:int = Update; +updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; +updateDcOptions#8e5e9873 dc_options:Vector = Update; + +inputMediaUploadedAudio#4e498cab file:InputFile duration:int mime_type:string = InputMedia; +inputMediaAudio#89938781 id:InputAudio = InputMedia; +inputMediaUploadedDocument#34e794bd file:InputFile file_name:string mime_type:string = InputMedia; +inputMediaUploadedThumbDocument#3e46de5d file:InputFile thumb:InputFile file_name:string mime_type:string = InputMedia; +inputMediaDocument#d184e841 id:InputDocument = InputMedia; + +messageMediaDocument#2fda2204 document:Document = MessageMedia; +messageMediaAudio#c6b68300 audio:Audio = MessageMedia; + +inputAudioEmpty#d95adc84 = InputAudio; +inputAudio#77d440ff id:long access_hash:long = InputAudio; + +inputDocumentEmpty#72f0eaae = InputDocument; +inputDocument#18798952 id:long access_hash:long = InputDocument; + +inputAudioFileLocation#74dc404d id:long access_hash:long = InputFileLocation; +inputDocumentFileLocation#4e45abe9 id:long access_hash:long = InputFileLocation; + +decryptedMessageMediaDocument#b095434b thumb:bytes thumb_w:int thumb_h:int file_name:string mime_type:string size:int key:bytes iv:bytes = DecryptedMessageMedia; +decryptedMessageMediaAudio#57e0a9cb duration:int mime_type:string size:int key:bytes iv:bytes = DecryptedMessageMedia; + +audioEmpty#586988d8 id:long = Audio; +audio#c7ac6496 id:long access_hash:long user_id:int date:int duration:int mime_type:string size:int dc_id:int = Audio; + +documentEmpty#36f8c871 id:long = Document; +document#9efc6326 id:long access_hash:long user_id:int date:int file_name:string mime_type:string size:int thumb:PhotoSize dc_id:int = Document; + +help.support#17c6b5f6 phone_number:string user:User = help.Support; + +decryptedMessageActionReadMessages#c4f40be random_ids:Vector = DecryptedMessageAction; +decryptedMessageActionDeleteMessages#65614304 random_ids:Vector = DecryptedMessageAction; +decryptedMessageActionScreenshotMessages#8ac1f475 random_ids:Vector = DecryptedMessageAction; +decryptedMessageActionFlushHistory#6719e45c = DecryptedMessageAction; +decryptedMessageActionNotifyLayer#f3048883 layer:int = DecryptedMessageAction; + +notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; +notifyUsers#b4c83b4c = NotifyPeer; +notifyChats#c007cec3 = NotifyPeer; +notifyAll#74d07c60 = NotifyPeer; + +updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; +updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; + +---functions--- + +invokeAfterMsg#cb9f372d msg_id:long query:!X = X; + +invokeAfterMsgs#3dc4b4f0 msg_ids:Vector query:!X = X; + +auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone; +auth.sendCode#768d5f4d phone_number:string sms_type:int api_id:int api_hash:string lang_code:string = auth.SentCode; +auth.sendCall#3c51564 phone_number:string phone_code_hash:string = Bool; +auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; +auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; +auth.logOut#5717da40 = Bool; +auth.resetAuthorizations#9fab0d1a = Bool; +auth.sendInvites#771c1d97 phone_numbers:Vector message:string = Bool; +auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; +auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; + +account.registerDevice#446c712c token_type:int token:string device_model:string system_version:string app_version:string app_sandbox:Bool lang_code:string = Bool; +account.unregisterDevice#65c55b40 token_type:int token:string = Bool; +account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; +account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; +account.resetNotifySettings#db7e1747 = Bool; +account.updateProfile#f0888d68 first_name:string last_name:string = User; +account.updateStatus#6628562c offline:Bool = Bool; +account.getWallPapers#c04cfac2 = Vector; + +users.getUsers#d91a548 id:Vector = Vector; +users.getFullUser#ca30a5b1 id:InputUser = UserFull; + +contacts.getStatuses#c4a353ee = Vector; +contacts.getContacts#22c6aa08 hash:string = contacts.Contacts; +contacts.importContacts#da30b32d contacts:Vector replace:Bool = contacts.ImportedContacts; +contacts.search#11f812d8 q:string limit:int = contacts.Found; +contacts.getSuggested#cd773428 limit:int = contacts.Suggested; +contacts.deleteContact#8e953744 id:InputUser = contacts.Link; +contacts.deleteContacts#59ab389e id:Vector = Bool; +contacts.block#332b49fc id:InputUser = Bool; +contacts.unblock#e54100bd id:InputUser = Bool; +contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; + +messages.getMessages#4222fa74 id:Vector = messages.Messages; +messages.getDialogs#eccf1df6 offset:int max_id:int limit:int = messages.Dialogs; +messages.getHistory#92a1df2f peer:InputPeer offset:int max_id:int limit:int = messages.Messages; +messages.search#7e9f2ab peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages; +messages.readHistory#b04f2510 peer:InputPeer max_id:int offset:int = messages.AffectedHistory; +messages.deleteHistory#f4f8fb61 peer:InputPeer offset:int = messages.AffectedHistory; +messages.deleteMessages#14f2dd0a id:Vector = Vector; +messages.restoreMessages#395f9d7e id:Vector = Vector; +messages.receivedMessages#28abcb68 max_id:int = Vector; +messages.setTyping#719839e9 peer:InputPeer typing:Bool = Bool; +messages.sendMessage#4cde0aab peer:InputPeer message:string random_id:long = messages.SentMessage; +messages.sendMedia#a3c85d76 peer:InputPeer media:InputMedia random_id:long = messages.StatedMessage; +messages.forwardMessages#514cd10f peer:InputPeer id:Vector = messages.StatedMessages; +messages.getChats#3c6aa187 id:Vector = messages.Chats; +messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; +messages.editChatTitle#b4bc68b5 chat_id:int title:string = messages.StatedMessage; +messages.editChatPhoto#d881821d chat_id:int photo:InputChatPhoto = messages.StatedMessage; +messages.addChatUser#2ee9ee9e chat_id:int user_id:InputUser fwd_limit:int = messages.StatedMessage; +messages.deleteChatUser#c3c5cd23 chat_id:int user_id:InputUser = messages.StatedMessage; +messages.createChat#419d9aee users:Vector title:string = messages.StatedMessage; + +updates.getState#edd4882a = updates.State; +updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference; + +photos.updateProfilePhoto#eef579a0 id:InputPhoto crop:InputPhotoCrop = UserProfilePhoto; +photos.uploadProfilePhoto#d50f9c88 file:InputFile caption:string geo_point:InputGeoPoint crop:InputPhotoCrop = photos.Photo; + +upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; +upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; + +help.getConfig#c4f9186b = Config; +help.getNearestDc#1fb33026 = NearestDc; +help.getAppUpdate#c812ac7e device_model:string system_version:string app_version:string lang_code:string = help.AppUpdate; +help.saveAppLog#6f02f748 events:Vector = Bool; +help.getInviteText#a4a95186 lang_code:string = help.InviteText; + +photos.getUserPhotos#b7ee553c user_id:InputUser offset:int max_id:int limit:int = photos.Photos; + +messages.forwardMessage#3f3f4f2 peer:InputPeer id:int random_id:long = messages.StatedMessage; +messages.sendBroadcast#41bb0972 contacts:Vector message:string media:InputMedia = messages.StatedMessages; + +geochats.getLocated#7f192d8f geo_point:InputGeoPoint radius:int limit:int = geochats.Located; +geochats.getRecents#e1427e6f offset:int limit:int = geochats.Messages; +geochats.checkin#55b3e8fb peer:InputGeoChat = geochats.StatedMessage; +geochats.getFullChat#6722dd6f peer:InputGeoChat = messages.ChatFull; +geochats.editChatTitle#4c8e2273 peer:InputGeoChat title:string address:string = geochats.StatedMessage; +geochats.editChatPhoto#35d81a95 peer:InputGeoChat photo:InputChatPhoto = geochats.StatedMessage; +geochats.search#cfcdc44d peer:InputGeoChat q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = geochats.Messages; +geochats.getHistory#b53f7a68 peer:InputGeoChat offset:int max_id:int limit:int = geochats.Messages; +geochats.setTyping#8b8a729 peer:InputGeoChat typing:Bool = Bool; +geochats.sendMessage#61b0044 peer:InputGeoChat message:string random_id:long = geochats.StatedMessage; +geochats.sendMedia#b8f0deff peer:InputGeoChat media:InputMedia random_id:long = geochats.StatedMessage; +geochats.createGeoChat#e092e16 title:string geo_point:InputGeoPoint address:string venue:string = geochats.StatedMessage; + +messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; +messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; +messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; +messages.discardEncryption#edd923c5 chat_id:int = Bool; +messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; +messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; +messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; +messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; +messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; +messages.receivedQueue#55a5bb66 max_qts:int = Vector; + +upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; + +initConnection#69796de9 api_id:int device_model:string system_version:string app_version:string lang_code:string query:!X = X; + +help.getSupport#9cdf08cd = help.Support; diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp new file mode 100644 index 000000000..b22e83e22 --- /dev/null +++ b/Telegram/SourceFiles/profilewidget.cpp @@ -0,0 +1,841 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" + +#include "lang.h" +#include "window.h" +#include "mainwidget.h" +#include "profilewidget.h" +#include "boxes/addcontactbox.h" +#include "boxes/confirmbox.h" +#include "boxes/photocropbox.h" +#include "application.h" +#include "boxes/addparticipantbox.h" +#include "gui/filedialog.h" + +ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const PeerData *peer) : TWidget(0), + _profile(profile), _scroll(scroll), _peer(App::peer(peer->id)), + _peerUser(_peer->chat ? 0 : _peer->asUser()), _peerChat(_peer->chat ? _peer->asChat() : 0), + _chatAdmin(_peerChat ? (_peerChat->admin == MTP::authedId()) : false), + + // profile + _nameCache(peer->name), + _uploadPhoto(this, lang(lng_profile_set_group_photo), st::btnShareContact), + _addParticipant(this, lang(lng_profile_add_participant), st::btnShareContact), + _sendMessage(this, lang(lng_profile_send_message), st::btnShareContact), + _shareContact(this, lang(lng_profile_share_contact), st::btnShareContact), + _cancelPhoto(this, lang(lng_cancel)), + + a_photo(0), + _photoOver(false), + + // settings + _enableNotifications(this, lang(lng_profile_enable_notifications)), + _clearHistory(this, lang(lng_profile_clear_history)), + + // participants + _pHeight(st::profileListPhotoSize + st::profileListPadding.height() * 2), + _kickWidth(st::linkFont->m.width(lang(lng_profile_kick))), + _selectedRow(-1), _lastPreload(0), _contactId(0), + _kickOver(0), _kickDown(0), _kickConfirm(0), + + _loadingId(0) { + + if (_peerUser) { + _phoneText = _peerUser->phone.isEmpty() ? QString() : App::formatPhone(_peerUser->phone); + _loadingId = MTP::send(MTPusers_GetFullUser(_peerUser->inputUser), rpcDone(&ProfileInner::gotFullUser)); + } else if (_peerChat->photoId) { + PhotoData *ph = App::photo(_peerChat->photoId); + if (ph->date) { + _photoLink = TextLinkPtr(new PhotoLink(ph)); + } + } else { + _loadingId = MTP::send(MTPmessages_GetFullChat(App::peerToMTP(_peerChat->id).c_peerChat().vchat_id), rpcDone(&ProfileInner::gotFullChat)); + } + + // profile + _nameText.setText(st::profileNameFont, _nameCache, _textNameOptions); + + connect(&_uploadPhoto, SIGNAL(clicked()), this, SLOT(onUpdatePhoto())); + connect(&_addParticipant, SIGNAL(clicked()), this, SLOT(onAddParticipant())); + connect(&_sendMessage, SIGNAL(clicked()), this, SLOT(onSendMessage())); + connect(&_shareContact, SIGNAL(clicked()), this, SLOT(onShareContact())); + connect(&_cancelPhoto, SIGNAL(clicked()), this, SLOT(onUpdatePhotoCancel())); + + connect(App::app(), SIGNAL(peerPhotoDone(PeerId)), this, SLOT(onPhotoUpdateDone(PeerId))); + connect(App::app(), SIGNAL(peerPhotoFail(PeerId)), this, SLOT(onPhotoUpdateFail(PeerId))); + + connect(App::main(), SIGNAL(peerPhotoChanged(PeerData *)), this, SLOT(peerUpdated(PeerData *))); + connect(App::main(), SIGNAL(peerUpdated(PeerData *)), this, SLOT(peerUpdated(PeerData *))); + connect(App::main(), SIGNAL(peerNameChanged(PeerData *, const PeerData::Names &, const PeerData::NameFirstChars &)), this, SLOT(peerUpdated(PeerData *))); + + // settings + connect(&_enableNotifications, SIGNAL(clicked()), this, SLOT(onEnableNotifications())); + connect(&_clearHistory, SIGNAL(clicked()), this, SLOT(onClearHistory())); + + App::contextItem(0); + + resizeEvent(0); + showAll(); +} + +void ProfileInner::onShareContact() { + App::main()->shareContactLayer(_peerUser); +} + +void ProfileInner::onSendMessage() { + App::main()->showPeer(_peer->id); +} + +void ProfileInner::onEnableNotifications() { + App::main()->updateNotifySetting(_peer, _enableNotifications.checked()); +} + +void ProfileInner::saveError(const QString &str) { + _errorText = str; + resizeEvent(0); + showAll(); + update(); +} + +void ProfileInner::loadProfilePhotos(int32 yFrom) { + _lastPreload = yFrom; + + int32 yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5; + MTP::clearLoaderPriorities(); + + int32 partfrom = (_enableNotifications.y() + _enableNotifications.height()) + st::profileHeaderSkip; + yFrom -= partfrom; + yTo -= partfrom; + + if (yTo < 0) return; + if (yFrom < 0) yFrom = 0; + yFrom /= _pHeight; + yTo = yTo / _pHeight + 1; + if (yFrom >= _participants.size()) return; + if (yTo > _participants.size()) yTo = _participants.size(); + for (int32 i = yFrom; i < yTo; ++i) { + _participants[i]->photo->load(); + } +} + +void ProfileInner::onUpdatePhoto() { + saveError(); + + QStringList imgExtensions(cImgExtensions()); + QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;All files (*.*)")); + + QImage img; + QString file; + QByteArray remoteContent; + if (filedialogGetOpenFile(file, remoteContent, lang(lng_choose_images), filter)) { + if (!remoteContent.isEmpty()) { + img = App::readImage(remoteContent); + } else { + if (!file.isEmpty()) { + img = App::readImage(file); + } + } + } else { + return; + } + + if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) { + saveError(lang(lng_bad_photo)); + return; + } + PhotoCropBox *box = new PhotoCropBox(img, _peer->id); + connect(box, SIGNAL(closed()), this, SLOT(onPhotoUpdateStart())); + App::wnd()->showLayer(box); +} + +void ProfileInner::onClearHistory() { + ConfirmBox *box = new ConfirmBox(lang(lng_sure_delete_history).replace(qsl("{contact}"), _peer->name)); + connect(box, SIGNAL(confirmed()), this, SLOT(onClearHistorySure())); + App::wnd()->showLayer(box); +} + +void ProfileInner::onClearHistorySure() { + App::main()->showPeer(0, true); + App::wnd()->hideLayer(); + App::main()->clearHistory(_peer); +} + +void ProfileInner::onAddParticipant() { + AddParticipantBox *box = new AddParticipantBox(_peerChat); + App::wnd()->showLayer(box); +} + +void ProfileInner::onUpdatePhotoCancel() { + App::app()->cancelPhotoUpdate(_peer->id); + showAll(); + update(); +} + +void ProfileInner::onPhotoUpdateStart() { + showAll(); + update(); +} + +void ProfileInner::onPhotoUpdateFail(PeerId peer) { + if (_peer->id != peer) return; + saveError(lang(lng_bad_photo)); + showAll(); + update(); +} + +void ProfileInner::onPhotoUpdateDone(PeerId peer) { + if (_peer->id != peer) return; + saveError(); + showAll(); + update(); +} + +void ProfileInner::gotFullUser(const MTPUserFull &user) { + _loadingId = 0; + const MTPDuserFull &d(user.c_userFull()); + App::feedPhoto(d.vprofile_photo); + App::feedUsers(MTP_vector(QVector(1, d.vuser))); + PhotoData *userPhoto = _peerUser->photoId ? App::photo(_peerUser->photoId) : 0; + if (userPhoto && userPhoto->date) { + _photoLink = TextLinkPtr(new PhotoLink(userPhoto)); + } else { + _photoLink = TextLinkPtr(); + } + App::main()->gotNotifySetting(MTP_inputNotifyPeer(_peer->input), d.vnotify_settings); + App::feedUserLink(MTP_int(_peerUser->id), d.vlink.c_contacts_link().vmy_link, d.vlink.c_contacts_link().vforeign_link); +} + +void ProfileInner::gotFullChat(const MTPmessages_ChatFull &res) { + _loadingId = 0; + const MTPDmessages_chatFull &d(res.c_messages_chatFull()); + PeerId peerId = App::peerFromChat(d.vfull_chat.c_chatFull().vid); + App::feedUsers(d.vusers); + App::feedChats(d.vchats); + App::feedParticipants(d.vfull_chat.c_chatFull().vparticipants); + App::main()->gotNotifySetting(MTP_inputNotifyPeer(_peer->input), d.vfull_chat.c_chatFull().vnotify_settings); + PhotoData *photo = App::feedPhoto(d.vfull_chat.c_chatFull().vchat_photo); + if (photo) { + ChatData *chat = App::peer(peerId)->asChat(); + if (chat) { + chat->photoId = photo->id; + photo->chat = chat; + } + } + emit App::main()->peerUpdated(_peer); +} + +void ProfileInner::peerUpdated(PeerData *data) { + if (data == _peer) { + PhotoData *photo = 0; + if (_peerUser) { + _phoneText = _peerUser->phone.isEmpty() ? QString() : App::formatPhone(_peerUser->phone); + if (_peerUser->photoId) photo = App::photo(_peerUser->photoId); + } else { + if (_peerChat->photoId) photo = App::photo(_peerChat->photoId); + } + _photoLink = (photo && photo->date) ? TextLinkPtr(new PhotoLink(photo)) : TextLinkPtr(); + if (_peer->name != _nameCache) { + _nameCache = _peer->name; + _nameText.setText(st::profileNameFont, _nameCache, _textNameOptions); + } + } + showAll(); + update(); +} + +void ProfileInner::updateOnlineDisplay() { + reorderParticipants(); + update(); +} + +void ProfileInner::updateOnlineDisplayTimer() { + int32 t = unixtime(), minIn = 86400; + if (_peerChat) { + if (_peerChat->participants.isEmpty()) return; + + for (ChatData::Participants::const_iterator i = _peerChat->participants.cbegin(), e = _peerChat->participants.cend(); i != e; ++i) { + int32 onlineWillChangeIn = App::onlineWillChangeIn(i.key()->onlineTill, t); + if (onlineWillChangeIn < minIn) { + minIn = onlineWillChangeIn; + } + } + } else { + minIn = App::onlineWillChangeIn(_peerUser->onlineTill, t); + } + App::main()->updateOnlineDisplayIn(minIn * 1000); +} + +void ProfileInner::reorderParticipants() { + int32 was = _participants.size(), t = unixtime(), onlineCount = 0; + if (_peerChat && !_peerChat->forbidden) { + if (_peerChat->count <= 0 || !_peerChat->participants.isEmpty()) { + _participants.clear(); + for (ParticipantsData::iterator i = _participantsData.begin(), e = _participantsData.end(); i != e; ++i) { + if (*i) { + delete *i; + *i = 0; + } + } + _participants.reserve(_peerChat->participants.size()); + _participantsData.resize(_peerChat->participants.size()); + } + UserData *self = App::self(); + for (ChatData::Participants::const_iterator i = _peerChat->participants.cbegin(), e = _peerChat->participants.cend(); i != e; ++i) { + UserData *user = i.key(); + int32 until = user->onlineTill; + Participants::iterator before = _participants.begin(); + if (user != self) { + if (before != _participants.end() && (*before) == self) { + ++before; + } + while (before != _participants.end() && (*before)->onlineTill >= until) { + ++before; + } + } + _participants.insert(before, user); + if (until > t) { + ++onlineCount; + } + } + if (_peerChat->count > 0 && _participants.isEmpty() && !_loadingId) { + _loadingId = MTP::send(MTPmessages_GetFullChat(App::peerToMTP(_peerChat->id).c_peerChat().vchat_id), rpcDone(&ProfileInner::gotFullChat)); + if (_onlineText.isEmpty()) _onlineText = lang(lng_chat_members).arg(_peerChat->count); + } else if (onlineCount) { + _onlineText = lang(lng_chat_members_online).arg(_participants.size()).arg(onlineCount); + } else { + _onlineText = lang(lng_chat_members).arg(_participants.size()); + } + loadProfilePhotos(_lastPreload); + } else { + _participants.clear(); + if (_peerUser) { + _onlineText = App::onlineText(_peerUser->onlineTill, t); + } else { + _onlineText = lang(lng_chat_no_members); + } + } + if (was != _participants.size()) { + resizeEvent(0); + } +} + +bool ProfileInner::event(QEvent *e) { + if (e->type() == QEvent::MouseMove) { + QMouseEvent *ev = dynamic_cast(e); + if (ev) { + _lastPos = ev->globalPos(); + updateSelected(); + } + } + return QWidget::event(e); +} + +void ProfileInner::paintEvent(QPaintEvent *e) { + QPainter p(this); + + QRect r(e->rect()); + p.setClipRect(r); + + int32 top = 0, l_time = unixtime(); + + // profile + top += st::profilePadding.top(); + if (_photoLink || !_peerChat || _peerChat->forbidden) { + p.drawPixmap(_left, top, _peer->photo->pix(st::profilePhotoSize)); + } else { + if (a_photo.current() < 1) { + p.drawPixmap(QPoint(_left, top), App::sprite(), st::setPhotoImg); + } + if (a_photo.current() > 0) { + p.setOpacity(a_photo.current()); + p.drawPixmap(QPoint(_left, top), App::sprite(), st::setOverPhotoImg); + p.setOpacity(1); + } + } + p.setPen(st::black->p); + _nameText.drawElided(p, _left + st::profilePhotoSize + st::profileNameLeft, top + st::profileNameTop, _width - st::profilePhotoSize - st::profileNameLeft); + + p.setFont(st::profileStatusFont->f); + p.setPen((_peerUser && _peerUser->onlineTill >= l_time ? st::profileOnlineColor : st::profileOfflineColor)->p); + p.drawText(_left + st::profilePhotoSize + st::profileStatusLeft, top + st::profileStatusTop + st::linkFont->ascent, _onlineText); + if (!_cancelPhoto.isHidden()) { + p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, _cancelPhoto.y() + st::linkFont->ascent, lang(lng_settings_uploading_photo)); + } + + if (!_errorText.isEmpty()) { + p.setFont(st::setErrFont->f); + p.setPen(st::setErrColor->p); + p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, top + st::profilePhoneTop + st::profilePhoneFont->ascent, _errorText); + } + if (!_phoneText.isEmpty()) { + p.setPen(st::black->p); + p.setFont(st::linkFont->f); + p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, top + st::profilePhoneTop + st::profilePhoneFont->ascent, _phoneText); + } + top += st::profilePhotoSize; + top += st::profileButtonTop; + + if (_peerChat && _peerChat->forbidden) { + int32 w = st::btnShareContact.font->m.width(lang(lng_chat_no_members)); + p.setFont(st::btnShareContact.font->f); + p.setPen(st::profileOfflineColor->p); + p.drawText(_left + (_width - w) / 2, top + st::btnShareContact.textTop + st::btnShareContact.font->ascent, lang(lng_chat_no_members)); + } + top += _shareContact.height(); + + // settings + p.setFont(st::profileHeaderFont->f); + p.setPen(st::profileHeaderColor->p); + p.drawText(_left + st::profileHeaderLeft, top + st::profileHeaderTop + st::profileHeaderFont->ascent, lang(lng_profile_settings_section)); + top += st::profileHeaderSkip; + + top += _enableNotifications.height(); + + // participants + if (_peerChat && (_peerChat->count > 0 || !_participants.isEmpty())) { + QString sectionHeader = lang(_participants.isEmpty() ? lng_profile_loading : lng_profile_participants_section); + p.setFont(st::profileHeaderFont->f); + p.setPen(st::profileHeaderColor->p); + p.drawText(_left + st::profileHeaderLeft, top + st::profileHeaderTop + st::profileHeaderFont->ascent, sectionHeader); + top += st::profileHeaderSkip; + + int32 partfrom = top; + if (!_participants.isEmpty()) { + int32 cnt = 0, fullCnt = _participants.size(); + for (Participants::const_iterator i = _participants.cbegin(), e = _participants.cend(); i != e; ++i, ++cnt) { + int32 top = partfrom + cnt * _pHeight; + if (top + _pHeight <= r.top()) continue; + if (top > r.bottom()) break; + + if (_selectedRow == cnt) { + p.fillRect(_left - st::profileListPadding.width(), top, _width + 2 * st::profileListPadding.width(), _pHeight, st::profileHoverBG->b); + } + + UserData *user = *i; + p.drawPixmap(_left, top + st::profileListPadding.height(), user->photo->pix(st::profileListPhotoSize)); + ParticipantData *data = _participantsData[cnt]; + if (!data) { + data = _participantsData[cnt] = new ParticipantData(); + data->name.setText(st::profileListNameFont, user->name, _textNameOptions); + data->online = App::onlineText(user->onlineTill, l_time); + data->cankick = (user != App::self()) && (_chatAdmin || (_peerChat->cankick.constFind(user) != _peerChat->cankick.cend())); + } + p.setPen(st::profileListNameColor->p); + p.setFont(st::linkFont->f); + data->name.drawElided(p, _left + st::profileListPhotoSize + st::profileListPadding.width(), top + st::profileListNameTop, _width - _kickWidth - st::profileListPadding.width() - st::profileListPhotoSize - st::profileListPadding.width()); + p.setFont(st::profileSubFont->f); + p.setPen((user->onlineTill >= l_time ? st::profileOnlineColor : st::profileOfflineColor)->p); + p.drawText(_left + st::profileListPhotoSize + st::profileListPadding.width(), top + st::profileListPadding.height() + st::profileListPhotoSize - st::profileListStatusBottom, data->online); + + if (data->cankick) { + bool over = (user == _kickOver && (!_kickDown || _kickDown == _kickOver)); + p.setFont((over ? st::linkOverFont : st::linkFont)->f); + if (user == _kickOver && _kickOver == _kickDown) { + p.setPen(st::btnDefLink.downColor->p); + } else { + p.setPen(st::btnDefLink.color->p); + } + p.drawText(_left + _width - _kickWidth, top + (_pHeight - st::linkFont->height) / 2 + st::linkFont->ascent, lang(lng_profile_kick)); + } + } + top += fullCnt * _pHeight; + } + } + + top += st::profileHeaderTop + st::profileHeaderFont->ascent - st::linkFont->ascent; + top += _clearHistory.height(); +} + +void ProfileInner::mouseMoveEvent(QMouseEvent *e) { + _lastPos = e->globalPos(); + updateSelected(); + + bool photoOver = QRect(_left, st::profilePadding.top(), st::setPhotoSize, st::setPhotoSize).contains(e->pos()); + if (photoOver != _photoOver) { + _photoOver = photoOver; + if (!_photoLink && _peerChat && !_peerChat->forbidden) { + a_photo.start(_photoOver ? 1 : 0); + anim::start(this); + } + } + if (!_photoLink && (!_peerChat || _peerChat->forbidden)) { + setCursor((_kickOver || _kickDown) ? style::cur_pointer : style::cur_default); + } else { + setCursor((_kickOver || _kickDown || _photoOver) ? style::cur_pointer : style::cur_default); + } +} + +void ProfileInner::updateSelected() { + if (!isVisible()) return; + + QPoint lp = mapFromGlobal(_lastPos); + + int32 partfrom = (_enableNotifications.y() + _enableNotifications.height()) + st::profileHeaderSkip; + int32 newSelected = (lp.x() >= _left - st::profileListPadding.width() && lp.x() < _left + _width + st::profileListPadding.width() && lp.y() >= partfrom) ? (lp.y() - partfrom) / _pHeight : -1; + + UserData *newKickOver = 0; + if (newSelected >= 0 && newSelected < _participants.size()) { + ParticipantData *data = _participantsData[newSelected]; + if (data && data->cankick) { + int32 top = partfrom + newSelected * _pHeight + (_pHeight - st::linkFont->height) / 2; + if ((lp.x() >= _left + _width - _kickWidth) && (lp.x() < _left + _width) && (lp.y() >= top) && (lp.y() < top + st::linkFont->height)) { + newKickOver = _participants[newSelected]; + } + } + } + if (_kickOver != newKickOver) { + _kickOver = newKickOver; + update(); + } + if (_kickDown) return; + + if (newSelected != _selectedRow) { + _selectedRow = newSelected; + update(); + } +} + +void ProfileInner::mousePressEvent(QMouseEvent *e) { + _lastPos = e->globalPos(); + updateSelected(); + if (_kickOver) { + _kickDown = _kickOver; + update(); + } else if (_selectedRow >= 0 && _selectedRow < _participants.size()) { + App::main()->showPeerProfile(_participants[_selectedRow]); + } else if (QRect(_left, st::profilePadding.top(), st::setPhotoSize, st::setPhotoSize).contains(e->pos())) { + if (_photoLink) { + _photoLink->onClick(e->button()); + } else if (_peerChat && !_peerChat->forbidden) { + onUpdatePhoto(); + } + } +} + +void ProfileInner::mouseReleaseEvent(QMouseEvent *e) { + if (_kickDown && _kickDown == _kickOver) { + _kickConfirm = _kickOver; + ConfirmBox *box = new ConfirmBox(lang(lng_profile_sure_kick).replace(qsl("{user}"), _kickOver->firstName)); + connect(box, SIGNAL(confirmed()), this, SLOT(onKickConfirm())); + App::wnd()->showLayer(box); + } + _kickDown = 0; + setCursor(_kickOver ? style::cur_pointer : style::cur_default); + update(); +} + +void ProfileInner::onKickConfirm() { + App::main()->kickParticipant(_peerChat, _kickConfirm); +} + +void ProfileInner::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + App::main()->showPeer(0, true); + } +} + +void ProfileInner::enterEvent(QEvent *e) { + setMouseTracking(true); + _lastPos = QCursor::pos(); + updateSelected(); + return TWidget::enterEvent(e); +} + +void ProfileInner::leaveEvent(QEvent *e) { + setMouseTracking(false); + _lastPos = QCursor::pos(); + updateSelected(); + return TWidget::leaveEvent(e); +} + +void ProfileInner::leaveToChildEvent(QEvent *e) { + _lastPos = QCursor::pos(); + updateSelected(); + return TWidget::leaveToChildEvent(e); +} + +void ProfileInner::resizeEvent(QResizeEvent *e) { + _width = qMin(width() - st::profilePadding.left() - st::profilePadding.right(), int(st::profileMaxWidth)); + _left = (width() - _width) / 2; + + int32 top = 0, btnWidth = (_width - st::profileButtonSkip) / 2; + + // profile + top += st::profilePadding.top(); + _cancelPhoto.move(_left + _width - _cancelPhoto.width(), top + st::profilePhoneTop); + top += st::profilePhotoSize; + + top += st::profileButtonTop; + _uploadPhoto.setGeometry(_left, top, btnWidth, _uploadPhoto.height()); + _sendMessage.setGeometry(_left, top, btnWidth, _sendMessage.height()); + _addParticipant.setGeometry(_left + _width - btnWidth, top, btnWidth, _addParticipant.height()); + _shareContact.setGeometry(_left + _width - btnWidth, top, btnWidth, _shareContact.height()); + top += _shareContact.height(); + + // settings + top += st::profileHeaderSkip; + _enableNotifications.move(_left, top); top += _enableNotifications.height(); + if (_peerChat && (_peerChat->count > 0 || !_participants.isEmpty())) { + top += st::profileHeaderSkip; + if (!_participants.isEmpty()) { + int32 fullCnt = _participants.size(); + top += fullCnt * _pHeight; + } + } + top += st::profileHeaderTop + st::profileHeaderFont->ascent - st::linkFont->ascent; + _clearHistory.move(_left, top); +} + +void ProfileInner::contextMenuEvent(QContextMenuEvent *e) { +} + +bool ProfileInner::animStep(float64 ms) { + float64 dt = ms / st::setPhotoDuration; + bool res = true; + if (dt >= 1) { + res = false; + a_photo.finish(); + } else { + a_photo.update(dt, anim::linear); + } + update(_left, st::profilePadding.top(), st::setPhotoSize, st::setPhotoSize); + return res; +} + +bool ProfileInner::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + if (_peerUser && photo->id == _peerUser->photoId || _peerChat && photo->id == _peerChat->photoId) { + x = _left; + y = st::profilePadding.top(); + w = st::setPhotoSize; + return true; + } + return false; +} + +PeerData *ProfileInner::peer() const { + return _peer; +} + +ProfileInner::~ProfileInner() { + for (ParticipantsData::iterator i = _participantsData.begin(), e = _participantsData.end(); i != e; ++i) { + delete *i; + } + _participantsData.clear(); +} + +void ProfileInner::openContextImage() { +} + +void ProfileInner::deleteContextImage() { +} + +void ProfileInner::updateNotifySettings() { + _enableNotifications.setChecked(_peer->notify == EmptyNotifySettings || _peer->notify == UnknownNotifySettings || _peer->notify->mute < unixtime()); +} + +void ProfileInner::showAll() { + if (_peerChat) { + _sendMessage.hide(); + _shareContact.hide(); + if (_peerChat->forbidden) { + _uploadPhoto.hide(); + _cancelPhoto.hide(); + _addParticipant.hide(); + } else { + if (App::app()->isPhotoUpdating(_peer->id)) { + _uploadPhoto.hide(); + _cancelPhoto.show(); + } else { + _uploadPhoto.show(); + _cancelPhoto.hide(); + } + if (_peerChat->count < cMaxGroupCount()) { + _addParticipant.show(); + } else { + _addParticipant.hide(); + } + } + _enableNotifications.show(); + _clearHistory.hide(); + } else { + _uploadPhoto.hide(); + _cancelPhoto.hide(); + _addParticipant.hide(); + _sendMessage.show(); + if (_peerUser->phone.isEmpty()) { + _shareContact.hide(); + } else { + _shareContact.show(); + } + _enableNotifications.show(); + _clearHistory.show(); + } + updateNotifySettings(); + + // participants + reorderParticipants(); + int32 h; + if (_peerUser) { + h = _clearHistory.y() + _clearHistory.height() + st::profileHeaderSkip; + } else { + h = _enableNotifications.y() + _enableNotifications.height() + st::profileHeaderSkip; + if (!_participants.isEmpty()) { + h += st::profileHeaderSkip + _participants.size() * _pHeight; + } else if (_peerChat->count > 0) { + h += st::profileHeaderSkip; + } + } + resize(width(), h); +} + +ProfileWidget::ProfileWidget(QWidget *parent, const PeerData *peer) : QWidget(parent), + _inner(this, &_scroll, peer), _scroll(this, st::setScroll), _showing(false) { + _scroll.setWidget(&_inner); + _scroll.move(0, 0); + _inner.move(0, 0); + _scroll.show(); + connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSelected())); + connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); +} + +void ProfileWidget::onScroll() { + _inner.loadProfilePhotos(_scroll.scrollTop()); +} + +void ProfileWidget::resizeEvent(QResizeEvent *e) { + _scroll.resize(size()); + _inner.resize(width(), _inner.height()); +} + +void ProfileWidget::mousePressEvent(QMouseEvent *e) { +} + +void ProfileWidget::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (animating() && _showing) { + p.setOpacity(a_bgAlpha.current()); + p.drawPixmap(a_bgCoord.current(), 0, _bgAnimCache); + p.setOpacity(a_alpha.current()); + p.drawPixmap(a_coord.current(), 0, _animCache); + } else { + p.fillRect(e->rect(), st::white->b); + } +} + +void ProfileWidget::dragEnterEvent(QDragEnterEvent *e) { +} + +void ProfileWidget::dropEvent(QDropEvent *e) { +} + +bool ProfileWidget::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + if (_inner.getPhotoCoords(photo, x, y, w)) { + x += _inner.x(); + y += _inner.y(); + return true; + } + return false; +} + +void ProfileWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) { + if (animating() && _showing) { + p.setOpacity(a_bgAlpha.current()); + p.drawPixmap(a_bgCoord.current(), 0, _bgAnimTopBarCache); + p.setOpacity(a_alpha.current()); + p.drawPixmap(a_coord.current(), 0, _animTopBarCache); + } else { + p.setOpacity(st::topBarBackAlpha + (1 - st::topBarBackAlpha) * over); + p.drawPixmap(QPoint(st::topBarBackPadding.left(), (st::topBarHeight - st::topBarBackImg.height()) / 2), App::sprite(), st::topBarBackImg); + p.setFont(st::topBarBackFont->f); + p.setPen(st::topBarBackColor->p); + p.drawText(st::topBarBackPadding.left() + st::topBarBackImg.width() + st::topBarBackPadding.right(), (st::topBarHeight - st::titleFont->height) / 2 + st::titleFont->ascent, lang(peer()->chat ? lng_profile_group_info : lng_profile_info)); + } +} + +void ProfileWidget::topBarClick() { + App::main()->showPeerBack(); +} + +PeerData *ProfileWidget::peer() const { + return _inner.peer(); +} + +void ProfileWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back) { + _bgAnimCache = bgAnimCache; + _bgAnimTopBarCache = bgAnimTopBarCache; + _animCache = grab(rect()); + App::main()->topBar()->showAll(); + _animTopBarCache = App::main()->topBar()->grab(QRect(0, 0, width(), st::topBarHeight)); + App::main()->topBar()->hideAll(); + _scroll.hide(); + a_coord = back ? anim::ivalue(-st::introSlideShift, 0) : anim::ivalue(st::introSlideShift, 0); + a_alpha = anim::fvalue(0, 1); + a_bgCoord = back ? anim::ivalue(0, st::introSlideShift) : anim::ivalue(0, -st::introSlideShift); + a_bgAlpha = anim::fvalue(1, 0); + anim::start(this); + _showing = true; + show(); + _inner.setFocus(); + App::main()->topBar()->update(); +} + +bool ProfileWidget::animStep(float64 ms) { + float64 fullDuration = st::introSlideDelta + st::introSlideDuration, dt = ms / fullDuration; + float64 dt1 = (ms > st::introSlideDuration) ? 1 : (ms / st::introSlideDuration), dt2 = (ms > st::introSlideDelta) ? (ms - st::introSlideDelta) / (st::introSlideDuration) : 0; + bool res = true; + if (dt2 >= 1) { + res = _showing = false; + a_bgCoord.finish(); + a_bgAlpha.finish(); + a_coord.finish(); + a_alpha.finish(); + _bgAnimCache = _animCache = _animTopBarCache = _bgAnimTopBarCache = QPixmap(); + App::main()->topBar()->showAll(); + _scroll.show(); + activate(); + } else { + a_bgCoord.update(dt1, st::introHideFunc); + a_bgAlpha.update(dt1, st::introAlphaHideFunc); + a_coord.update(dt2, st::introShowFunc); + a_alpha.update(dt2, st::introAlphaShowFunc); + } + update(); + App::main()->topBar()->update(); + return res; +} + +void ProfileWidget::updateOnlineDisplay() { + _inner.updateOnlineDisplay(); + updateOnlineDisplayTimer(); +} + +void ProfileWidget::updateOnlineDisplayTimer() { + _inner.updateOnlineDisplayTimer(); +} + +void ProfileWidget::updateNotifySettings() { + _inner.updateNotifySettings(); +} + +ProfileWidget::~ProfileWidget() { +} + +void ProfileWidget::activate() { + _inner.setFocus(); +} diff --git a/Telegram/SourceFiles/profilewidget.h b/Telegram/SourceFiles/profilewidget.h new file mode 100644 index 000000000..6e8cffe20 --- /dev/null +++ b/Telegram/SourceFiles/profilewidget.h @@ -0,0 +1,188 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +class ProfileWidget; +class ProfileInner : public TWidget, public RPCSender, public Animated { + Q_OBJECT + +public: + + ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const PeerData *peer); + + bool event(QEvent *e); + void paintEvent(QPaintEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void keyPressEvent(QKeyEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void leaveToChildEvent(QEvent *e); + void resizeEvent(QResizeEvent *e); + void contextMenuEvent(QContextMenuEvent *e); + + bool animStep(float64 ms); + + bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const; + + PeerData *peer() const; + + void gotFullUser(const MTPUserFull &user); + void gotFullChat(const MTPmessages_ChatFull &res); + + void updateOnlineDisplay(); + void updateOnlineDisplayTimer(); + void reorderParticipants(); + + void saveError(const QString &str = QString()); + + void loadProfilePhotos(int32 yFrom); + + void updateNotifySettings(); + + ~ProfileInner(); + +public slots: + + void peerUpdated(PeerData *data); + void updateSelected(); + + void openContextImage(); + void deleteContextImage(); + + void onShareContact(); + void onSendMessage(); + void onEnableNotifications(); + + void onClearHistory(); + void onClearHistorySure(); + void onAddParticipant(); + + void onUpdatePhoto(); + void onUpdatePhotoCancel(); + + void onPhotoUpdateDone(PeerId peer); + void onPhotoUpdateFail(PeerId peer); + void onPhotoUpdateStart(); + + void onKickConfirm(); + +private: + + void showAll(); + + ProfileWidget *_profile; + ScrollArea *_scroll; + + PeerData *_peer; + UserData *_peerUser; + ChatData *_peerChat; + bool _chatAdmin; + + int32 _width, _left; + + // profile + Text _nameText; + QString _nameCache; + QString _phoneText; + TextLinkPtr _photoLink; + FlatButton _uploadPhoto, _addParticipant; + FlatButton _sendMessage, _shareContact; + LinkButton _cancelPhoto; + + anim::fvalue a_photo; + bool _photoOver; + + QString _errorText; + + // settings + FlatCheckbox _enableNotifications; + LinkButton _clearHistory; + + // participants + int32 _pHeight; + int32 _kickWidth, _selectedRow, _lastPreload; + uint64 _contactId; + UserData *_kickOver, *_kickDown, *_kickConfirm; + + typedef struct { + Text name; + QString online; + bool cankick; + } ParticipantData; + typedef QVector Participants; + Participants _participants; + typedef QVector ParticipantsData; + ParticipantsData _participantsData; + + mtpRequestId _loadingId; + + QPoint _lastPos; + + QString _onlineText; + +}; + +class ProfileWidget : public QWidget, public RPCSender, public Animated { + Q_OBJECT + +public: + + ProfileWidget(QWidget *parent, const PeerData *peer); + + void resizeEvent(QResizeEvent *e); + void mousePressEvent(QMouseEvent *e); + void paintEvent(QPaintEvent *e); + void dragEnterEvent(QDragEnterEvent *e); + void dropEvent(QDropEvent *e); + + bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const; + + void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth); + void topBarClick(); + + PeerData *peer() const; + + void animShow(const QPixmap &oldAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false); + bool animStep(float64 ms); + + void updateOnlineDisplay(); + void updateOnlineDisplayTimer(); + + void updateNotifySettings(); + + ~ProfileWidget(); + +public slots: + + void activate(); + void onScroll(); + +private: + + ScrollArea _scroll; + ProfileInner _inner; + + bool _showing; + QPixmap _animCache, _bgAnimCache, _animTopBarCache, _bgAnimTopBarCache; + anim::ivalue a_coord, a_bgCoord; + anim::fvalue a_alpha, a_bgAlpha; + +}; + diff --git a/Telegram/SourceFiles/pspecific.h b/Telegram/SourceFiles/pspecific.h new file mode 100644 index 000000000..a20715723 --- /dev/null +++ b/Telegram/SourceFiles/pspecific.h @@ -0,0 +1,34 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include +#include "sysbuttons.h" + +#ifdef Q_OS_MAC +#include "pspecific_mac.h" +#endif + +#ifdef Q_OS_LINUX + +#endif + +#ifdef Q_OS_WIN +#include "pspecific_wnd.h" +#endif diff --git a/Telegram/SourceFiles/pspecific_mac.cpp b/Telegram/SourceFiles/pspecific_mac.cpp new file mode 100644 index 000000000..8b6405ffb --- /dev/null +++ b/Telegram/SourceFiles/pspecific_mac.cpp @@ -0,0 +1,2470 @@ +#include "stdafx.h" +#include "pspecific.h" + +#include "lang.h" +#include "application.h" +#include "mainwidget.h" + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) < (b) ? (b) : (a)) + +namespace { + bool frameless = true; + bool useDWM = false; + bool useTheme = false; + bool useOpenAs = false; + bool themeInited = false; + bool finished = true; + int menuShown = 0, menuHidden = 0; + int dleft = 0, dtop = 0; + QMargins simpleMargins, margins; + //HICON bigIcon = 0, smallIcon = 0, overlayIcon = 0; + + //UINT tbCreatedMsgId = 0; + //ITaskbarList3 *tbListInterface = 0; + + /*HWND createTaskbarHider() { + HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0); + HWND hWnd = 0; + + QString cn = QString("TelegramTaskbarHider"); + LPCWSTR _cn = (LPCWSTR)cn.utf16(); + WNDCLASSEX wc; + + wc.cbSize = sizeof(wc); + wc.style = 0; + wc.lpfnWndProc = DefWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = appinst; + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = 0; + wc.lpszMenuName = NULL; + wc.lpszClassName = _cn; + wc.hIconSm = 0; + if (!RegisterClassEx(&wc)) { + DEBUG_LOG(("Application Error: could not register taskbar hider window class, error: %1").arg(GetLastError())); + return hWnd; + } + + hWnd = CreateWindowEx(WS_EX_TOOLWINDOW, _cn, 0, WS_POPUP, 0, 0, 0, 0, 0, 0, appinst, 0); + if (!hWnd) { + DEBUG_LOG(("Application Error: could not create taskbar hider window class, error: %1").arg(GetLastError())); + return hWnd; + } + return hWnd; + } + + enum { + _PsShadowMoved = 0x01, + _PsShadowResized = 0x02, + _PsShadowShown = 0x04, + _PsShadowHidden = 0x08, + _PsShadowActivate = 0x10, + }; + + enum { + _PsInitHor = 0x01, + _PsInitVer = 0x02, + }; + + int32 _psSize = 0; + class _PsShadowWindows { + public: + + _PsShadowWindows() : screenDC(0), max_w(0), max_h(0), _x(0), _y(0), _w(0), _h(0), hidden(true), r(0), g(0), b(0), noKeyColor(RGB(255, 255, 255)) { + for (int i = 0; i < 4; ++i) { + dcs[i] = 0; + bitmaps[i] = 0; + hwnds[i] = 0; + } + } + + void setColor(QColor c) { + r = c.red(); + g = c.green(); + b = c.blue(); + + if (!hwnds[0]) return; + Gdiplus::SolidBrush brush(Gdiplus::Color(_alphas[0], r, g, b)); + for (int i = 0; i < 4; ++i) { + Gdiplus::Graphics graphics(dcs[i]); + graphics.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + if ((i % 2) && _h || !(i % 2) && _w) { + graphics.FillRectangle(&brush, 0, 0, (i % 2) ? _size : _w, (i % 2) ? _h : _size); + } + } + initCorners(); + + _x = _y = _w = _h = 0; + update(_PsShadowMoved | _PsShadowResized); + } + + bool init(QColor c) { + style::rect topLeft = st::wndShadow; + _fullsize = topLeft.width(); + _shift = st::wndShadowShift; + QImage cornersImage(_fullsize, _fullsize, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&cornersImage); + p.drawPixmap(QPoint(0, 0), App::sprite(), topLeft); + } + uchar *bits = cornersImage.bits(); + if (bits) { + for ( + quint32 *p = (quint32*)bits, *end = (quint32*)(bits + cornersImage.byteCount()); + p < end; + ++p + ) { + *p = (*p ^ 0x00ffffff) << 24; + } + } + + _metaSize = _fullsize + 2 * _shift; + _alphas.reserve(_metaSize); + _colors.reserve(_metaSize * _metaSize); + for (int32 j = 0; j < _metaSize; ++j) { + for (int32 i = 0; i < _metaSize; ++i) { + _colors.push_back((i < 2 * _shift || j < 2 * _shift) ? 1 : qMax(BYTE(1), BYTE(cornersImage.pixel(QPoint(i - 2 * _shift, j - 2 * _shift)) >> 24))); + } + } + uchar prev = 0; + for (int32 i = 0; i < _metaSize; ++i) { + uchar a = _colors[(_metaSize - 1) * _metaSize + i]; + if (a < prev) break; + + _alphas.push_back(a); + prev = a; + } + _psSize = _size = _alphas.size() - 2 * _shift; + + setColor(c); + + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + ULONG_PTR gdiplusToken; + Gdiplus::Status gdiRes = Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + + if (gdiRes != Gdiplus::Ok) { + DEBUG_LOG(("Application Error: could not init GDI+, error: %1").arg((int)gdiRes)); + return false; + } + blend.AlphaFormat = AC_SRC_ALPHA; + blend.SourceConstantAlpha = 255; + blend.BlendFlags = 0; + blend.BlendOp = AC_SRC_OVER; + + screenDC = GetDC(0); + if (!screenDC) return false; + + QRect avail(QDesktopWidget().availableGeometry()); + max_w = avail.width(); + if (max_w < st::wndMinWidth) max_w = st::wndMinWidth; + max_h = avail.height(); + if (max_h < st::wndMinHeight) max_h = st::wndMinHeight; + + HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0); + + for (int i = 0; i < 4; ++i) { + QString cn = QString("TelegramShadow%1").arg(i); + LPCWSTR _cn = (LPCWSTR)cn.utf16(); + WNDCLASSEX wc; + + wc.cbSize = sizeof(wc); + wc.style = 0; + wc.lpfnWndProc = wndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = appinst; + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = 0; + wc.lpszMenuName = NULL; + wc.lpszClassName = _cn; + wc.hIconSm = 0; + if (!RegisterClassEx(&wc)) { + DEBUG_LOG(("Application Error: could not register shadow window class %1, error: %2").arg(i).arg(GetLastError())); + destroy(); + return false; + } + + hwnds[i] = CreateWindowEx(WS_EX_LAYERED | WS_EX_TOOLWINDOW, _cn, 0, WS_POPUP, 0, 0, 0, 0, 0, 0, appinst, 0); + if (!hwnds[i]) { + DEBUG_LOG(("Application Error: could not create shadow window class %1, error: %2").arg(i).arg(GetLastError())); + destroy(); + return false; + } + + dcs[i] = CreateCompatibleDC(screenDC); + if (!dcs[i]) { + DEBUG_LOG(("Application Error: could not create dc for shadow window class %1, error: %2").arg(i).arg(GetLastError())); + destroy(); + return false; + } + + bitmaps[i] = CreateCompatibleBitmap(screenDC, (i % 2) ? _size : max_w, (i % 2) ? max_h : _size); + if (!bitmaps[i]) { + DEBUG_LOG(("Application Error: could not create bitmap for shadow window class %1, error: %2").arg(i).arg(GetLastError())); + destroy(); + return false; + } + + SelectObject(dcs[i], bitmaps[i]); + } + + initCorners(); + return true; + } + + void initCorners(int directions = (_PsInitHor | _PsInitVer)) { + bool hor = (directions & _PsInitHor), ver = (directions & _PsInitVer); + Gdiplus::Graphics graphics0(dcs[0]), graphics1(dcs[1]), graphics2(dcs[2]), graphics3(dcs[3]); + graphics0.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + graphics1.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + graphics2.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + graphics3.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + + Gdiplus::SolidBrush brush(Gdiplus::Color(_alphas[0], r, g, b)); + if (hor) graphics0.FillRectangle(&brush, 0, 0, _fullsize - (_size - _shift), 2 * _shift); + + if (ver) { + graphics1.FillRectangle(&brush, 0, 0, _size, 2 * _shift); + graphics3.FillRectangle(&brush, 0, 0, _size, 2 * _shift); + graphics1.FillRectangle(&brush, _size - _shift, 2 * _shift, _shift, _fullsize); + graphics3.FillRectangle(&brush, 0, 2 * _shift, _shift, _fullsize); + } + + if (hor) { + for (int j = 2 * _shift; j < _size; ++j) { + for (int k = 0; k < _fullsize - (_size - _shift); ++k) { + brush.SetColor(Gdiplus::Color(_colors[j * _metaSize + k + (_size + _shift)], r, g, b)); + graphics0.FillRectangle(&brush, k, j, 1, 1); + graphics2.FillRectangle(&brush, k, _size - (j - 2 * _shift) - 1, 1, 1); + } + } + for (int j = _size; j < _size + 2 * _shift; ++j) { + for (int k = 0; k < _fullsize - (_size - _shift); ++k) { + brush.SetColor(Gdiplus::Color(_colors[j * _metaSize + k + (_size + _shift)], r, g, b)); + graphics2.FillRectangle(&brush, k, _size - (j - 2 * _shift) - 1, 1, 1); + } + } + } + if (ver) { + for (int j = 2 * _shift; j < _fullsize + 2 * _shift; ++j) { + for (int k = _shift; k < _size; ++k) { + brush.SetColor(Gdiplus::Color(_colors[j * _metaSize + (k + _shift)], r, g, b)); + graphics1.FillRectangle(&brush, _size - k - 1, j, 1, 1); + graphics3.FillRectangle(&brush, k, j, 1, 1); + } + } + } + } + void verCorners(int h, Gdiplus::Graphics *pgraphics1, Gdiplus::Graphics *pgraphics3) { + Gdiplus::SolidBrush brush(Gdiplus::Color(_alphas[0], r, g, b)); + pgraphics1->FillRectangle(&brush, _size - _shift, h - _fullsize, _shift, _fullsize); + pgraphics3->FillRectangle(&brush, 0, h - _fullsize, _shift, _fullsize); + for (int j = 0; j < _fullsize; ++j) { + for (int k = _shift; k < _size; ++k) { + brush.SetColor(Gdiplus::Color(_colors[(j + 2 * _shift) * _metaSize + k + _shift], r, g, b)); + pgraphics1->FillRectangle(&brush, _size - k - 1, h - j - 1, 1, 1); + pgraphics3->FillRectangle(&brush, k, h - j - 1, 1, 1); + } + } + } + void horCorners(int w, Gdiplus::Graphics *pgraphics0, Gdiplus::Graphics *pgraphics2) { + Gdiplus::SolidBrush brush(Gdiplus::Color(_alphas[0], r, g, b)); + pgraphics0->FillRectangle(&brush, w - 2 * _size - (_fullsize - (_size - _shift)), 0, _fullsize - (_size - _shift), 2 * _shift); + for (int j = 2 * _shift; j < _size; ++j) { + for (int k = 0; k < _fullsize - (_size - _shift); ++k) { + brush.SetColor(Gdiplus::Color(_colors[j * _metaSize + k + (_size + _shift)], r, g, b)); + pgraphics0->FillRectangle(&brush, w - 2 * _size - k - 1, j, 1, 1); + pgraphics2->FillRectangle(&brush, w - 2 * _size - k - 1, _size - (j - 2 * _shift) - 1, 1, 1); + } + } + for (int j = _size; j < _size + 2 * _shift; ++j) { + for (int k = 0; k < _fullsize - (_size - _shift); ++k) { + brush.SetColor(Gdiplus::Color(_colors[j * _metaSize + k + (_size + _shift)], r, g, b)); + pgraphics2->FillRectangle(&brush, w - 2 * _size - k - 1, _size - (j - 2 * _shift) - 1, 1, 1); + } + } + } + + void update(int changes, WINDOWPOS *pos = 0) { + HWND hwnd = Application::wnd() ? Application::wnd()->psHwnd() : 0; + if (!hwnd || !hwnds[0]) return; + + if (changes == _PsShadowActivate) { + for (int i = 0; i < 4; ++i) { + SetWindowPos(hwnds[i], hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + return; + } + + if (changes & _PsShadowHidden) { + if (!hidden) { + for (int i = 0; i < 4; ++i) { + hidden = true; + ShowWindow(hwnds[i], SW_HIDE); + } + } + return; + } + if (!Application::wnd()->psPosInited()) return; + + int x = _x, y = _y, w = _w, h = _h; + if (pos && (!(pos->flags & SWP_NOMOVE) || !(pos->flags & SWP_NOSIZE) || !(pos->flags & SWP_NOREPOSITION))) { + if (!(pos->flags & SWP_NOMOVE)) { + x = pos->x - _size; + y = pos->y - _size; + } else if (pos->flags & SWP_NOSIZE) { + for (int i = 0; i < 4; ++i) { + SetWindowPos(hwnds[i], hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + return; + } + if (!(pos->flags & SWP_NOSIZE)) { + w = pos->cx + 2 * _size; + h = pos->cy + 2 * _size; + } + } else { + RECT r; + GetWindowRect(hwnd, &r); + x = r.left - _size; + y = r.top - _size; + w = r.right + _size - x; + h = r.bottom + _size - y; + } + if (h < 2 * _fullsize + 2 * _shift) { + h = 2 * _fullsize + 2 * _shift; + } + if (w < 2 * (_fullsize + _shift)) { + w = 2 * (_fullsize + _shift); + } + + if (w != _w) { + int from = (_w > 2 * (_fullsize + _shift)) ? (_w - _size - _fullsize - _shift) : (_fullsize - (_size - _shift)); + int to = w - _size - _fullsize - _shift; + if (w > max_w) { + from = _fullsize - (_size - _shift); + max_w *= 2; + for (int i = 0; i < 4; i += 2) { + DeleteObject(bitmaps[i]); + bitmaps[i] = CreateCompatibleBitmap(screenDC, max_w, _size); + SelectObject(dcs[i], bitmaps[i]); + } + initCorners(_PsInitHor); + } + Gdiplus::Graphics graphics0(dcs[0]), graphics2(dcs[2]); + graphics0.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + graphics2.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + Gdiplus::SolidBrush brush(Gdiplus::Color(_alphas[0], r, g, b)); + if (to > from) { + graphics0.FillRectangle(&brush, from, 0, to - from, 2 * _shift); + for (int i = 2 * _shift; i < _size; ++i) { + Gdiplus::Pen pen(Gdiplus::Color(_alphas[i], r, g, b)); + graphics0.DrawLine(&pen, from, i, to, i); + graphics2.DrawLine(&pen, from, _size - (i - 2 * _shift) - 1, to, _size - (i - 2 * _shift) - 1); + } + for (int i = _size; i < _size + 2 * _shift; ++i) { + Gdiplus::Pen pen(Gdiplus::Color(_alphas[i], r, g, b)); + graphics2.DrawLine(&pen, from, _size - (i - 2 * _shift) - 1, to, _size - (i - 2 * _shift) - 1); + } + } + if (_w > w) { + graphics0.FillRectangle(&brush, w - _size - _fullsize - _shift, 0, _fullsize - (_size - _shift), _size); + graphics2.FillRectangle(&brush, w - _size - _fullsize - _shift, 0, _fullsize - (_size - _shift), _size); + } + horCorners(w, &graphics0, &graphics2); + POINT p0 = { x + _size, y }, p2 = { x + _size, y + h - _size }, f = { 0, 0 }; + SIZE s = { w - 2 * _size, _size }; + updateWindow(0, &p0, &s); + updateWindow(2, &p2, &s); + } else if (x != _x || y != _y) { + POINT p0 = { x + _size, y }, p2 = { x + _size, y + h - _size }; + updateWindow(0, &p0); + updateWindow(2, &p2); + } else if (h != _h) { + POINT p2 = { x + _size, y + h - _size }; + updateWindow(2, &p2); + } + + if (h != _h) { + int from = (_h > 2 * _fullsize + 2 * _shift) ? (_h - _fullsize) : (_fullsize + 2 * _shift); + int to = h - _fullsize; + if (h > max_h) { + from = (_fullsize + 2 * _shift); + max_h *= 2; + for (int i = 1; i < 4; i += 2) { + DeleteObject(bitmaps[i]); + bitmaps[i] = CreateCompatibleBitmap(dcs[i], _size, max_h); + SelectObject(dcs[i], bitmaps[i]); + } + initCorners(_PsInitVer); + } + Gdiplus::Graphics graphics1(dcs[1]), graphics3(dcs[3]); + graphics1.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + graphics3.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + + Gdiplus::SolidBrush brush(Gdiplus::Color(_alphas[0], r, g, b)); + if (to > from) { + graphics1.FillRectangle(&brush, _size - _shift, from, _shift, to - from); + graphics3.FillRectangle(&brush, 0, from, _shift, to - from); + for (int i = 2 * _shift; i < _size + _shift; ++i) { + Gdiplus::Pen pen(Gdiplus::Color(_alphas[i], r, g, b)); + graphics1.DrawLine(&pen, _size + _shift - i - 1, from, _size + _shift - i - 1, to); + graphics3.DrawLine(&pen, i - _shift, from, i - _shift, to); + } + } + if (_h > h) { + graphics1.FillRectangle(&brush, 0, h - _fullsize, _size, _fullsize); + graphics3.FillRectangle(&brush, 0, h - _fullsize, _size, _fullsize); + } + verCorners(h, &graphics1, &graphics3); + + POINT p1 = {x + w - _size, y}, p3 = {x, y}, f = {0, 0}; + SIZE s = { _size, h }; + updateWindow(1, &p1, &s); + updateWindow(3, &p3, &s); + } else if (x != _x || y != _y) { + POINT p1 = { x + w - _size, y }, p3 = { x, y }; + updateWindow(1, &p1); + updateWindow(3, &p3); + } else if (w != _w) { + POINT p1 = { x + w - _size, y }; + updateWindow(1, &p1); + } + _x = x; + _y = y; + _w = w; + _h = h; + + if (hidden && (changes & _PsShadowShown)) { + for (int i = 0; i < 4; ++i) { + SetWindowPos(hwnds[i], hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE); + } + hidden = false; + } + } + + void updateWindow(int i, POINT *p, SIZE *s = 0) { + static POINT f = {0, 0}; + if (s) { + UpdateLayeredWindow(hwnds[i], (s ? screenDC : 0), p, s, (s ? dcs[i] : 0), (s ? (&f) : 0), noKeyColor, &blend, ULW_ALPHA); + } else { + SetWindowPos(hwnds[i], 0, p->x, p->y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); + } + } + + void destroy() { + for (int i = 0; i < 4; ++i) { + if (dcs[i]) DeleteDC(dcs[i]); + if (bitmaps[i]) DeleteObject(bitmaps[i]); + if (hwnds[i]) DestroyWindow(hwnds[i]); + dcs[i] = 0; + bitmaps[i] = 0; + hwnds[i] = 0; + } + if (screenDC) ReleaseDC(0, screenDC); + } + + private: + + int _x, _y, _w, _h; + int _metaSize, _fullsize, _size, _shift; + QVector _alphas, _colors; + + bool hidden; + + HWND hwnds[4]; + HDC dcs[4], screenDC; + HBITMAP bitmaps[4]; + int max_w, max_h; + BLENDFUNCTION blend; + + BYTE r, g, b; + COLORREF noKeyColor; + + static LRESULT CALLBACK _PsShadowWindows::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + + }; + _PsShadowWindows _psShadowWindows; + + LRESULT CALLBACK _PsShadowWindows::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + if (finished) return DefWindowProc(hwnd, msg, wParam, lParam); + + int i; + for (i = 0; i < 4; ++i) { + if (_psShadowWindows.hwnds[i] && hwnd == _psShadowWindows.hwnds[i]) { + break; + } + } + if (i == 4) return DefWindowProc(hwnd, msg, wParam, lParam); + + switch (msg) { + case WM_CLOSE: + Application::wnd()->close(); + break; + case WM_NCHITTEST: { + int32 xPos = GET_X_LPARAM(lParam), yPos = GET_Y_LPARAM(lParam); + switch (i) { + case 0: return HTTOP; + case 1: return (yPos < _psShadowWindows._y + _psSize) ? HTTOPRIGHT : ((yPos >= _psShadowWindows._y + _psShadowWindows._h - _psSize) ? HTBOTTOMRIGHT : HTRIGHT); + case 2: return HTBOTTOM; + case 3: return (yPos < _psShadowWindows._y + _psSize) ? HTTOPLEFT : ((yPos >= _psShadowWindows._y + _psShadowWindows._h - _psSize) ? HTBOTTOMLEFT : HTLEFT); + } + return HTTRANSPARENT; + } break; + + case WM_NCACTIVATE: return DefWindowProc(hwnd, msg, wParam, lParam); + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + case WM_NCLBUTTONDBLCLK: + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + case WM_NCMBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + case WM_NCRBUTTONDBLCLK: + case WM_NCXBUTTONDOWN: + case WM_NCXBUTTONUP: + case WM_NCXBUTTONDBLCLK: + case WM_NCMOUSEHOVER: + case WM_NCMOUSELEAVE: + case WM_NCMOUSEMOVE: + case WM_NCPOINTERUPDATE: + case WM_NCPOINTERDOWN: + case WM_NCPOINTERUP: + if (App::wnd() && App::wnd()->psHwnd()) { + if (msg == WM_NCLBUTTONDOWN) { + ::SetForegroundWindow(App::wnd()->psHwnd()); + } + LRESULT res = SendMessage(App::wnd()->psHwnd(), msg, wParam, lParam); + return res; + } + return 0; + break; + case WM_ACTIVATE: + if (App::wnd() && App::wnd()->psHwnd() && wParam == WA_ACTIVE) { + if ((HWND)lParam != App::wnd()->psHwnd()) { + ::SetForegroundWindow(hwnd); + ::SetWindowPos(App::wnd()->psHwnd(), hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + } + } + return DefWindowProc(hwnd, msg, wParam, lParam); + break; + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; + } + + QColor _shActive(0, 0, 0), _shInactive(0, 0, 0); + + typedef BOOL (FAR STDAPICALLTYPE *f_dwmDefWindowProc)(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, _Out_ LRESULT *plResult); + f_dwmDefWindowProc dwmDefWindowProc; + + typedef HRESULT (FAR STDAPICALLTYPE *f_dwmSetWindowAttribute)(HWND hWnd, DWORD dwAttribute, _In_ LPCVOID pvAttribute, DWORD cbAttribute); + f_dwmSetWindowAttribute dwmSetWindowAttribute; + + typedef HRESULT (FAR STDAPICALLTYPE *f_dwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS *pMarInset); + f_dwmExtendFrameIntoClientArea dwmExtendFrameIntoClientArea; + + typedef HRESULT (FAR STDAPICALLTYPE *f_setWindowTheme)(HWND hWnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList); + f_setWindowTheme setWindowTheme; + + typedef HRESULT (FAR STDAPICALLTYPE *f_openAs_RunDLL)(HWND hWnd, HINSTANCE hInstance, LPCWSTR lpszCmdLine, int nCmdShow); + f_openAs_RunDLL openAs_RunDLL; + + typedef HRESULT (FAR STDAPICALLTYPE *f_shOpenWithDialog)(HWND hwndParent, const OPENASINFO *poainfo); + f_shOpenWithDialog shOpenWithDialog; + + template + bool loadFunction(HINSTANCE dll, LPCSTR name, TFunction &func) { + if (!dll) return false; + + func = (TFunction)GetProcAddress(dll, name); + return !!func; + } + + class _PsInitializer { + public: + _PsInitializer() { + setupDWM(); + useDWM = true; + frameless = !useDWM; + + setupUx(); + setupOpenAs(); + } + void setupDWM() { + HINSTANCE procId = LoadLibrary(L"DWMAPI.DLL"); + + if (!loadFunction(procId, "DwmDefWindowProc", dwmDefWindowProc)) return; + if (!loadFunction(procId, "DwmSetWindowAttribute", dwmSetWindowAttribute)) return; + if (!loadFunction(procId, "DwmExtendFrameIntoClientArea", dwmExtendFrameIntoClientArea)) return; + useDWM = true; + } + void setupUx() { + HINSTANCE procId = LoadLibrary(L"UXTHEME.DLL"); + + if (!loadFunction(procId, "SetWindowTheme", setWindowTheme)) return; + useTheme = true; + } + void setupOpenAs() { + HINSTANCE procId = LoadLibrary(L"SHELL32.DLL"); + + if (!loadFunction(procId, "SHOpenWithDialog", shOpenWithDialog) && !loadFunction(procId, "OpenAs_RunDLLW", openAs_RunDLL)) return; + useOpenAs = true; + } + }; + _PsInitializer _psInitializer; + + class _PsEventFilter : public QAbstractNativeEventFilter { + public: + _PsEventFilter() { + } + + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) { + Window *wnd = Application::wnd(); + if (!wnd) return false; + + MSG *msg = (MSG*)message; + if (msg->message == WM_ENDSESSION) { + App::quit(); + return false; + } + if (msg->hwnd == wnd->psHwnd() || msg->hwnd && !wnd->psHwnd()) { + return mainWindowEvent(msg->hwnd, msg->message, msg->wParam, msg->lParam, (LRESULT*)result); + } + return false; + } + + bool mainWindowEvent(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result) { + if (tbCreatedMsgId && msg == tbCreatedMsgId) { + if (CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_ALL, IID_ITaskbarList3, (void**)&tbListInterface) != S_OK) { + tbListInterface = 0; + } + } + switch (msg) { + + case WM_DESTROY: { + App::quit(); + } return false; + + case WM_ACTIVATE: { + if (LOWORD(wParam) == WA_CLICKACTIVE) { + App::wnd()->inactivePress(true); + } + Application::wnd()->psUpdateMargins(); + if (LOWORD(wParam) != WA_INACTIVE) { + _psShadowWindows.setColor(_shActive); + _psShadowWindows.update(_PsShadowActivate); + } else { + _psShadowWindows.setColor(_shInactive); + } + QTimer::singleShot(0, Application::wnd(), SLOT(psUpdateCounter())); + Application::wnd()->update(); + } return false; + + case WM_NCPAINT: if (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS8) return false; *result = 0; return true; + + case WM_NCCALCSIZE: if (!useDWM) return false; { + if (wParam == TRUE) { + LPNCCALCSIZE_PARAMS params = (LPNCCALCSIZE_PARAMS)lParam; + params->rgrc[0].left += margins.left() - simpleMargins.left(); + params->rgrc[0].top += margins.top() - simpleMargins.top(); + params->rgrc[0].right -= margins.right() - simpleMargins.right(); + params->rgrc[0].bottom -= margins.bottom() - simpleMargins.bottom(); + } else if (wParam == FALSE) { + LPRECT rect = (LPRECT)lParam; + + rect->left += margins.left() - simpleMargins.left(); + rect->top += margins.top() - simpleMargins.top(); + rect->right += margins.right() - simpleMargins.right(); + rect->bottom += margins.bottom() - simpleMargins.bottom(); + } + *result = 0; + } return true; + + case WM_NCACTIVATE: { + Application::wnd()->psUpdateMargins(); + *result = LRESULT(TRUE); + Application::wnd()->repaint(); + } return true; + + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: { + _psShadowWindows.update(_PsShadowMoved | _PsShadowResized, (WINDOWPOS*)lParam); + } return false; + + case WM_SIZE: { + if (App::wnd()) { + if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED || wParam == SIZE_MINIMIZED) { + if (wParam != SIZE_RESTORED || App::wnd()->windowState() != Qt::WindowNoState) { + Qt::WindowState state = Qt::WindowNoState; + if (wParam == SIZE_MAXIMIZED) { + state = Qt::WindowMaximized; + } else if (wParam == SIZE_MINIMIZED) { + state = Qt::WindowMinimized; + } + emit App::wnd()->windowHandle()->windowStateChanged(state); + } else { + App::wnd()->psUpdatedPosition(); + } + int changes = (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXIMIZED) ? _PsShadowHidden : (_PsShadowResized | _PsShadowShown); + _psShadowWindows.update(changes); + } + } + } return false; + + case WM_SHOWWINDOW: { + LONG style = GetWindowLong(hWnd, GWL_STYLE); + int changes = _PsShadowResized | ((wParam && !(style & (WS_MAXIMIZE | WS_MINIMIZE))) ? _PsShadowShown : _PsShadowHidden); + _psShadowWindows.update(changes); + } return false; + + case WM_MOVE: { + _psShadowWindows.update(_PsShadowMoved); + App::wnd()->psUpdatedPosition(); + } return false; + + case WM_NCHITTEST: { + POINTS p = MAKEPOINTS(lParam); + RECT r; + GetWindowRect(hWnd, &r); + HitTestType res = Application::wnd()->hitTest(QPoint(p.x - r.left + dleft, p.y - r.top + dtop)); + switch (res) { + case HitTestClient: + case HitTestSysButton: *result = HTCLIENT; break; + case HitTestIcon: *result = HTCAPTION; break; + case HitTestCaption: *result = HTCAPTION; break; + case HitTestTop: *result = HTTOP; break; + case HitTestTopRight: *result = HTTOPRIGHT; break; + case HitTestRight: *result = HTRIGHT; break; + case HitTestBottomRight: *result = HTBOTTOMRIGHT; break; + case HitTestBottom: *result = HTBOTTOM; break; + case HitTestBottomLeft: *result = HTBOTTOMLEFT; break; + case HitTestLeft: *result = HTLEFT; break; + case HitTestTopLeft: *result = HTTOPLEFT; break; + case HitTestNone: + default: *result = HTTRANSPARENT; break; + }; + } return true; + + case WM_NCRBUTTONUP: { + SendMessage(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam); + } return true; + + case WM_NCLBUTTONDOWN: { + POINTS p = MAKEPOINTS(lParam); + RECT r; + GetWindowRect(hWnd, &r); + HitTestType res = Application::wnd()->hitTest(QPoint(p.x - r.left + dleft, p.y - r.top + dtop)); + switch (res) { + case HitTestIcon: + if (menuHidden && getms() < menuHidden + 10) { + menuHidden = 0; + if (getms() < menuShown + GetDoubleClickTime()) { + Application::wnd()->close(); + } + } else { + QRect icon = Application::wnd()->iconRect(); + p.x = r.left - dleft + icon.left(); + p.y = r.top - dtop + icon.top() + icon.height(); + Application::wnd()->psUpdateSysMenu(Application::wnd()->windowHandle()->windowState()); + menuShown = getms(); + menuHidden = 0; + TrackPopupMenu(Application::wnd()->psMenu(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON, p.x, p.y, 0, hWnd, 0); + menuHidden = getms(); + } + return true; + }; + } return false; + + case WM_NCLBUTTONDBLCLK: { + POINTS p = MAKEPOINTS(lParam); + RECT r; + GetWindowRect(hWnd, &r); + HitTestType res = Application::wnd()->hitTest(QPoint(p.x - r.left + dleft, p.y - r.top + dtop)); + switch (res) { + case HitTestIcon: Application::wnd()->close(); return true; + }; + } return false; + + case WM_SYSCOMMAND: { + if (wParam == SC_MOUSEMENU) { + POINTS p = MAKEPOINTS(lParam); + Application::wnd()->psUpdateSysMenu(Application::wnd()->windowHandle()->windowState()); + TrackPopupMenu(Application::wnd()->psMenu(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON, p.x, p.y, 0, hWnd, 0); + } + } return false; + + case WM_COMMAND: { + if (HIWORD(wParam)) return false; + int cmd = LOWORD(wParam); + switch (cmd) { + case SC_CLOSE: Application::wnd()->close(); return true; + case SC_MINIMIZE: Application::wnd()->setWindowState(Qt::WindowMinimized); return true; + case SC_MAXIMIZE: Application::wnd()->setWindowState(Qt::WindowMaximized); return true; + case SC_RESTORE: Application::wnd()->setWindowState(Qt::WindowNoState); return true; + } + } return true; + + } + return false; + } + }; + _PsEventFilter *_psEventFilter = 0;*/ + +}; + +PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent), icon256(qsl(":/gui/art/iconround256.png")), + trayIcon(0), trayIconMenu(0), posInited(false) { + //tbCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated"); + icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation); + icon32 = icon256.scaledToWidth(32, Qt::SmoothTransformation); + //connect(&psIdleTimer, SIGNAL(timeout()), this, SLOT(psIdleTimeout())); + //psIdleTimer.setSingleShot(false); +} + +void PsMainWindow::psIdleTimeout() { + /*LASTINPUTINFO lii; + lii.cbSize = sizeof(LASTINPUTINFO); + BOOL res = GetLastInputInfo(&lii); + if (res) { + uint64 ticks = GetTickCount(); + if (lii.dwTime >= ticks - IdleMsecs) { + psIdle = false; + psIdleTimer.stop(); + if (App::main()) App::main()->setOnline(); + } + }*/ +} + +bool PsMainWindow::psIsActive() const { + return isActiveWindow() && isVisible() && !(windowState() & Qt::WindowMinimized); +} + +bool PsMainWindow::psIsOnline(int windowState) const { + if (windowState < 0) windowState = this->windowState(); + if (windowState & Qt::WindowMinimized) { + return false; + } else if (!isVisible()) { + return false; + } + /*LASTINPUTINFO lii; + lii.cbSize = sizeof(LASTINPUTINFO); + BOOL res = GetLastInputInfo(&lii); + if (res) { + uint64 ticks = GetTickCount(); + if (lii.dwTime < ticks - IdleMsecs) { + if (!psIdle) { + psIdle = true; + psIdleTimer.start(900); + } + return false; + } else { + psIdle = false; + psIdleTimer.stop(); + } + }*/ + return true; +} + +void PsMainWindow::psRefreshTaskbarIcon() { + /*QWidget *w = new QWidget(this); + w->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + w->setGeometry(x() + 1, y() + 1, 1, 1); + QPalette p(w->palette()); + p.setColor(QPalette::Background, st::titleBG->c); + QWindow *wnd = w->windowHandle(); + w->setPalette(p); + w->show(); + w->activateWindow(); + delete w;*/ +} + +void PsMainWindow::psUpdateWorkmode() { + /*switch (cWorkMode()) { + case dbiwmWindowAndTray: { + setupTrayIcon(); + HWND psOwner = (HWND)GetWindowLong(ps_hWnd, GWL_HWNDPARENT); + if (psOwner) { + SetWindowLong(ps_hWnd, GWL_HWNDPARENT, 0); + psRefreshTaskbarIcon(); + } + } break; + + case dbiwmTrayOnly: { + setupTrayIcon(); + HWND psOwner = (HWND)GetWindowLong(ps_hWnd, GWL_HWNDPARENT); + if (!psOwner) { + SetWindowLong(ps_hWnd, GWL_HWNDPARENT, (LONG)ps_tbHider_hWnd); + } + } break; + + case dbiwmWindowOnly: { + if (trayIconMenu) trayIconMenu->deleteLater(); + trayIconMenu = 0; + if (trayIcon) trayIcon->deleteLater(); + trayIcon = 0; + + HWND psOwner = (HWND)GetWindowLong(ps_hWnd, GWL_HWNDPARENT); + if (psOwner) { + SetWindowLong(ps_hWnd, GWL_HWNDPARENT, 0); + psRefreshTaskbarIcon(); + } + } break; + }*/ +} + +/*HICON qt_pixmapToWinHICON(const QPixmap &); +static HICON _qt_createHIcon(const QIcon &icon, int xSize, int ySize) { + if (!icon.isNull()) { + const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize))); + if (!pm.isNull()) + return qt_pixmapToWinHICON(pm); + } + return 0; +}*/ + +void PsMainWindow::psUpdateCounter() { + int32 counter = App::histories().unreadFull; + style::color bg = (App::histories().unreadMuted < counter) ? st::counterBG : st::counterMuteBG; + QIcon icon; + QImage cicon16(icon16), cicon32(icon32); + if (counter > 0) { + { + QString cnt = (counter < 1000) ? QString("%1").arg(counter) : QString("..%1").arg(counter % 100, 2, 10, QChar('0')); + QPainter p16(&cicon16); + p16.setBrush(bg->b); + p16.setPen(Qt::NoPen); + p16.setRenderHint(QPainter::Antialiasing); + int32 fontSize = 8; + style::font f(fontSize); + int32 w = f->m.width(cnt), d = 2, r = 3; + p16.drawRoundedRect(QRect(16 - w - d * 2, 16 - f->height, w + d * 2, f->height), r, r); + p16.setFont(f->f); + + p16.setPen(st::counterColor->p); + + p16.drawText(16 - w - d, 16 - f->height + f->ascent, cnt); + } + /*if (!tbListInterface) { + QString cnt = (counter < 10000) ? QString("%1").arg(counter) : ((counter < 1000000) ? QString("%1K").arg(counter / 1000) : QString("%1M").arg(counter / 1000000)); + QPainter p32(&cicon32); + style::font f(10); + int32 w = f->m.width(cnt), d = 3, r = 6; + p32.setBrush(bg->b); + p32.setPen(Qt::NoPen); + p32.setRenderHint(QPainter::Antialiasing); + p32.drawRoundedRect(QRect(32 - w - d * 2, 0, w + d * 2, f->height - 1), r, r); + p32.setPen(st::counterColor->p); + p32.setFont(f->f); + p32.drawText(32 - w - d, f->ascent - 1, cnt); + }*/ + } + icon.addPixmap(QPixmap::fromImage(cicon16)); + icon.addPixmap(QPixmap::fromImage(cicon32)); + if (trayIcon) { + QIcon ticon; + QImage ticon16(icon16); + if (counter > 0) { + QString cnt = (counter < 1000) ? QString("%1").arg(counter) : QString("..%1").arg(counter % 100, 2, 10, QChar('0')); + { + QPainter p16(&ticon16); + p16.setBrush(bg->b); + p16.setPen(Qt::NoPen); + p16.setRenderHint(QPainter::Antialiasing); + int32 fontSize = 8; + style::font f(fontSize); + int32 w = f->m.width(cnt), d = 2, r = 3; + p16.drawRoundedRect(QRect(16 - w - d * 2, 16 - f->height, w + d * 2, f->height), r, r); + p16.setFont(f->f); + + p16.setPen(st::counterColor->p); + + p16.drawText(16 - w - d, 16 - f->height + f->ascent, cnt); + } + } + ticon.addPixmap(QPixmap::fromImage(ticon16)); + ticon.addPixmap(QPixmap::fromImage(cicon32)); + trayIcon->setIcon(ticon); + } + + /*setWindowTitle((counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram")); + psDestroyIcons(); + ps_iconSmall = _qt_createHIcon(icon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); + ps_iconBig = _qt_createHIcon(icon, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON)); + SendMessage(ps_hWnd, WM_SETICON, 0, (LPARAM)ps_iconSmall); + SendMessage(ps_hWnd, WM_SETICON, 1, (LPARAM)(ps_iconBig ? ps_iconBig : ps_iconSmall)); + if (tbListInterface) { + if (counter > 0) { + QString cnt = (counter < 1000) ? QString("%1").arg(counter) : QString("..%1").arg(counter % 100, 2, 10, QChar('0')); + QImage oicon16(16, 16, QImage::Format_ARGB32); + int32 cntSize = cnt.size(); + oicon16.fill(st::transparent->c); + { + QPainter p16(&oicon16); + p16.setBrush(bg->b); + p16.setPen(Qt::NoPen); + p16.setRenderHint(QPainter::Antialiasing); + int32 fontSize = (cntSize < 2) ? 12 : ((cntSize < 3) ? 12 : 8); + style::font f(fontSize); + int32 w = f->m.width(cnt), d = (cntSize < 2) ? 5 : ((cntSize < 3) ? 2 : 2), r = (cntSize < 2) ? 8 : ((cntSize < 3) ? 7 : 3); + p16.drawRoundedRect(QRect(16 - w - d * 2, 16 - f->height, w + d * 2, f->height), r, r); + p16.setFont(f->f); + + p16.setPen(st::counterColor->p); + + p16.drawText(16 - w - d, 16 - f->height + f->ascent, cnt); + } + QIcon oicon(QPixmap::fromImage(oicon16)); + ps_iconOverlay = _qt_createHIcon(oicon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); + } + QString description = counter > 0 ? QString("%1 unread messages").arg(counter) : qsl("No unread messages"); + static WCHAR descriptionArr[1024]; + description.toWCharArray(descriptionArr); + tbListInterface->SetOverlayIcon(ps_hWnd, ps_iconOverlay, descriptionArr); + }*/ +} + +/*namespace { + HMONITOR enumMonitor = 0; + RECT enumMonitorWork; + + BOOL CALLBACK _monitorEnumProc( + _In_ HMONITOR hMonitor, + _In_ HDC hdcMonitor, + _In_ LPRECT lprcMonitor, + _In_ LPARAM dwData + ) { + MONITORINFOEX info; + info.cbSize = sizeof(info); + GetMonitorInfo(hMonitor, &info); + if (dwData == hashCrc32(info.szDevice, sizeof(info.szDevice))) { + enumMonitor = hMonitor; + enumMonitorWork = info.rcWork; + return FALSE; + } + return TRUE; + } +}*/ + +void PsMainWindow::psInitSize() { + setMinimumWidth(st::wndMinWidth); + setMinimumHeight(st::wndMinHeight); + + TWindowPos pos(cWindowPos()); + if (cDebug()) { // temp while design + pos.w = 800; + pos.h = 600; + } + QRect avail(QDesktopWidget().availableGeometry()); + bool maximized = false; + QRect geom(avail.x() + (avail.width() - st::wndDefWidth) / 2, avail.y() + (avail.height() - st::wndDefHeight) / 2, st::wndDefWidth, st::wndDefHeight); + if (pos.w && pos.h) { + if (pos.y < 0) pos.y = 0; + //enumMonitor = 0; + //EnumDisplayMonitors(0, 0, &_monitorEnumProc, pos.moncrc); + /*if (enumMonitor) { + int32 w = enumMonitorWork.right - enumMonitorWork.left, h = enumMonitorWork.bottom - enumMonitorWork.top; + if (w >= st::wndMinWidth && h >= st::wndMinHeight) { + if (pos.w > w) pos.w = w; + if (pos.h > h) pos.h = h; + pos.x += enumMonitorWork.left; + pos.y += enumMonitorWork.top; + if (pos.x < enumMonitorWork.right - 10 && pos.y < enumMonitorWork.bottom - 10) { + geom = QRect(pos.x, pos.y, pos.w, pos.h); + } + } + }*/ + maximized = pos.maximized; + } + setGeometry(geom); +} + +void PsMainWindow::psInitFrameless() { + /*psUpdatedPositionTimer.setSingleShot(true); + connect(&psUpdatedPositionTimer, SIGNAL(timeout()), this, SLOT(psSavePosition())); + + QPlatformNativeInterface *i = QGuiApplication::platformNativeInterface(); + ps_hWnd = static_cast(i->nativeResourceForWindow(QByteArrayLiteral("handle"), windowHandle())); + + if (!ps_hWnd) return; + + if (frameless) { + setWindowFlags(Qt::FramelessWindowHint); + } + +// RegisterApplicationRestart(NULL, 0); + + psInitSysMenu();*/ + connect(windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(psStateChanged(Qt::WindowState))); +} + +void PsMainWindow::psSavePosition(Qt::WindowState state) { + /*if (state == Qt::WindowActive) state = windowHandle()->windowState(); + if (state == Qt::WindowMinimized || !posInited) return; + + TWindowPos pos(cWindowPos()), curPos = pos; + + if (state == Qt::WindowMaximized) { + curPos.maximized = 1; + } else { + RECT w; + GetWindowRect(ps_hWnd, &w); + curPos.x = w.left; + curPos.y = w.top; + curPos.w = w.right - w.left; + curPos.h = w.bottom - w.top; + curPos.maximized = 0; + } + + HMONITOR hMonitor = MonitorFromWindow(ps_hWnd, MONITOR_DEFAULTTONEAREST); + if (hMonitor) { + MONITORINFOEX info; + info.cbSize = sizeof(info); + GetMonitorInfo(hMonitor, &info); + if (!curPos.maximized) { + curPos.x -= info.rcWork.left; + curPos.y -= info.rcWork.top; + } + curPos.moncrc = hashCrc32(info.szDevice, sizeof(info.szDevice)); + } + + if (curPos.w >= st::wndMinWidth && curPos.h >= st::wndMinHeight) { + if (curPos.x != pos.x || curPos.y != pos.y || curPos.w != pos.w || curPos.h != pos.h || curPos.moncrc != pos.moncrc || curPos.maximized != pos.maximized) { + cSetWindowPos(curPos); + App::writeConfig(); + } + }*/ +} + +void PsMainWindow::psUpdatedPosition() { + //psUpdatedPositionTimer.start(4000); +} + +void PsMainWindow::psStateChanged(Qt::WindowState state) { + psUpdateSysMenu(state); + psUpdateMargins(); + /*if (state == Qt::WindowMinimized && GetWindowLong(ps_hWnd, GWL_HWNDPARENT)) { + minimizeToTray(); + } + psSavePosition(state);*/ +} + +//Q_DECLARE_METATYPE(QMargins); +void PsMainWindow::psFirstShow() { + //_psShadowWindows.init(_shActive); + finished = false; + + //psUpdateMargins(); + + //_psShadowWindows.update(_PsShadowHidden); + bool showShadows = true; + + show(); + if (cWindowPos().maximized) { + setWindowState(Qt::WindowMaximized); + } + + if (cFromAutoStart()) { + if (cStartMinimized()) { + setWindowState(Qt::WindowMinimized); + if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { + hide(); + } else { + show(); + } + showShadows = false; + } else { + show(); + } + } else { + show(); + } + posInited = true; + //if (showShadows) { + // _psShadowWindows.update(_PsShadowMoved | _PsShadowResized | _PsShadowShown); + //} +} + +bool PsMainWindow::psHandleTitle() { + //return useDWM; + return true; +} + +void PsMainWindow::psInitSysMenu() { + /*Qt::WindowStates states = windowState(); + ps_menu = GetSystemMenu(ps_hWnd, FALSE); + psUpdateSysMenu(windowHandle()->windowState());*/ +} + +void PsMainWindow::psUpdateSysMenu(Qt::WindowState state) { + /*if (!ps_menu) return; + + int menuToDisable = SC_RESTORE; + if (state == Qt::WindowMaximized) { + menuToDisable = SC_MAXIMIZE; + } else if (state == Qt::WindowMinimized) { + menuToDisable = SC_MINIMIZE; + } + int itemCount = GetMenuItemCount(ps_menu); + for (int i = 0; i < itemCount; ++i) { + MENUITEMINFO itemInfo = {0}; + itemInfo.cbSize = sizeof(itemInfo); + itemInfo.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID; + if (GetMenuItemInfo(ps_menu, i, TRUE, &itemInfo)) { + if (itemInfo.fType & MFT_SEPARATOR) { + continue; + } + if (itemInfo.wID && !(itemInfo.fState & MFS_DEFAULT)) { + UINT fOldState = itemInfo.fState, fState = itemInfo.fState & ~MFS_DISABLED; + if (itemInfo.wID == SC_CLOSE) { + fState |= MFS_DEFAULT; + } else if (itemInfo.wID == menuToDisable || (itemInfo.wID != SC_MINIMIZE && itemInfo.wID != SC_MAXIMIZE && itemInfo.wID != SC_RESTORE)) { + fState |= MFS_DISABLED; + } + itemInfo.fMask = MIIM_STATE; + itemInfo.fState = fState; + if (!SetMenuItemInfo(ps_menu, i, TRUE, &itemInfo)) { + DEBUG_LOG(("PS Error: could not set state %1 to menu item %2, old state %3, error %4").arg(fState).arg(itemInfo.wID).arg(fOldState).arg(GetLastError())); + DestroyMenu(ps_menu); + ps_menu = 0; + break; + } + } + } else { + DEBUG_LOG(("PS Error: could not get state, menu item %1 of %2, error %3").arg(i).arg(itemCount).arg(GetLastError())); + DestroyMenu(ps_menu); + ps_menu = 0; + break; + } + }*/ +} + +void PsMainWindow::psUpdateMargins() { + /*if (!useDWM) return; + + RECT r, a; + + GetClientRect(ps_hWnd, &r); + a = r; + + LONG style = GetWindowLong(ps_hWnd, GWL_STYLE), styleEx = GetWindowLong(ps_hWnd, GWL_EXSTYLE); + AdjustWindowRectEx(&a, style, false, styleEx); + simpleMargins = QMargins(a.left - r.left, a.top - r.top, r.right - a.right, r.bottom - a.bottom); + if (style & WS_MAXIMIZE) { + RECT w, m; + GetWindowRect(ps_hWnd, &w); + m = w; + + HMONITOR hMonitor = MonitorFromRect(&w, MONITOR_DEFAULTTONEAREST); + if (hMonitor) { + MONITORINFO mi; + mi.cbSize = sizeof(mi); + GetMonitorInfo(hMonitor, &mi); + m = mi.rcWork; + } + + dleft = w.left - m.left; + dtop = w.top - m.top; + + margins.setLeft(simpleMargins.left() - w.left + m.left); + margins.setRight(simpleMargins.right() - m.right + w.right); + margins.setBottom(simpleMargins.bottom() - m.bottom + w.bottom); + margins.setTop(simpleMargins.top() - w.top + m.top); + } else { + margins = simpleMargins; + dleft = dtop = 0; + } + + QPlatformNativeInterface *i = QGuiApplication::platformNativeInterface(); + i->setWindowProperty(windowHandle()->handle(), "WindowsCustomMargins", QVariant::fromValue(margins)); + if (!themeInited) { + themeInited = true; + if (useTheme) { + if (QSysInfo::WindowsVersion < QSysInfo::WV_WINDOWS8) { + setWindowTheme(ps_hWnd, L" ", L" "); + QApplication::setStyle(QStyleFactory::create("Windows")); + } + } + }*/ +} + +void PsMainWindow::psFlash() { + /*if (GetForegroundWindow() == ps_hWnd) return; + + FLASHWINFO info; + info.cbSize = sizeof(info); + info.hwnd = ps_hWnd; + info.dwFlags = FLASHW_ALL; + info.dwTimeout = 0; + info.uCount = 1; + FlashWindowEx(&info);*/ +} + +/*HWND PsMainWindow::psHwnd() const { + return ps_hWnd; +} + +HMENU PsMainWindow::psMenu() const { + return ps_menu; +}*/ + +/*void PsMainWindow::psDestroyIcons() { + if (ps_iconBig) { + DestroyIcon(ps_iconBig); + ps_iconBig = 0; + } + if (ps_iconSmall) { + DestroyIcon(ps_iconSmall); + ps_iconSmall = 0; + } + if (ps_iconOverlay) { + DestroyIcon(ps_iconOverlay); + ps_iconOverlay = 0; + } +}*/ + +PsMainWindow::~PsMainWindow() { + finished = true; + //if (ps_menu) DestroyMenu(ps_menu); + //psDestroyIcons(); + //_psShadowWindows.destroy(); + //psClearNotifyFast(); + //if (ps_tbHider_hWnd) DestroyWindow(ps_tbHider_hWnd); +} + +void PsMainWindow::psNotify(History *history) { + /*if (App::quiting()) return; + if (!cDesktopNotify()) { + history->clearNotifyFrom(); + } + if (notifyHistories.constFind(history) != notifyHistories.cend()) return; + notifyHistories.insert(history); + psShowNextNotify();*/ +} + +void PsMainWindow::psClearNotify(History *history) { + /*if (!history) { + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + (*i)->unlinkHistory(); + } + for (NotifyHistories::const_iterator i = notifyHistories.cbegin(), e = notifyHistories.cend(); i != e; ++i) { + (*i)->clearNotifyFrom(); + } + notifyHistories.clear(); + return; + } + notifyHistories.remove(history); + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + (*i)->unlinkHistory(history); + }*/ +} + +void PsMainWindow::psClearNotifyFast() { + /*notifyHistories.clear(); + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + (*i)->deleteLater(); + } + notifyWindows.clear();*/ +} + +/*void PsMainWindow::psShowNextNotify(PsNotifyWindow *remove) { + if (App::quiting()) return; + + int32 count = NotifyWindows; + if (remove) { + for (PsNotifyWindows::iterator i = notifyWindows.begin(), e = notifyWindows.end(); i != e; ++i) { + if ((*i) == remove) { + notifyWindows.erase(i); + break; + } + } + } + QRect r = QApplication::desktop()->availableGeometry(App::wnd()); + int32 x = r.width() - st::notifyWidth - st::notifyDeltaX, y = r.bottom() - st::notifyHeight - st::notifyDeltaY; + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + int32 ind = (*i)->index(); + if (ind < 0) continue; + --count; + } + while (count > 0) { + HistoryItem *notify = 0; + for (NotifyHistories::iterator i = notifyHistories.begin(), e = notifyHistories.end(); i != e;) { + if ((*i)->notifyFrom) { + if (!notify || (*i)->notifyFrom->date < notify->date) { + notify = (*i)->notifyFrom; + } + ++i; + } else { + i = notifyHistories.erase(i); + } + } + if (notify) { + notifyWindows.push_back(new PsNotifyWindow(notify, x, y)); + notify->history()->getNextNotifyFrom(); + --count; + } else { + break; + } + } + count = NotifyWindows - count; + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + int32 ind = (*i)->index(); + if (ind < 0) continue; + --count; + (*i)->moveTo(x, y - count * (st::notifyHeight + st::notifyDeltaY)); + } +}*/ + +void PsMainWindow::psStopHiding() { + /*for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + (*i)->stopHiding(); + }*/ +} + +void PsMainWindow::psStartHiding() { + /*for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + (*i)->startHiding(); + }*/ +} + +void PsMainWindow::psUpdateNotifies() { + /*for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + (*i)->updatePeerPhoto(); + }*/ +} + +/*PsNotifyWindow::PsNotifyWindow(HistoryItem *item, int32 x, int32 y) : history(item->history()), aOpacity(0), _index(0), hiding(false), started(GetTickCount()), + alphaDuration(st::notifyFastAnim), posDuration(st::notifyFastAnim), aY(y + st::notifyHeight + st::notifyDeltaY), close(this, st::notifyClose), aOpacityFunc(st::notifyFastAnimFunc) { + + int32 w = st::notifyWidth, h = st::notifyHeight; + QImage img(w, h, QImage::Format_ARGB32_Premultiplied); + img.fill(st::notifyBG->c); + + { + QPainter p(&img); + p.setPen(st::notifyBorder->p); + p.setBrush(Qt::NoBrush); + p.drawRect(0, 0, w - 1, h - 1); + + if (history->peer->photo->loaded()) { + p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), history->peer->photo->pix(st::notifyPhotoSize)); + } else { + MTP::clearLoaderPriorities(); + peerPhoto = history->peer->photo; + peerPhoto->load(true, true); + } + + int32 itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width; + + QRect rectForName(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height); + if (history->peer->chat) { + p.drawPixmap(QPoint(rectForName.left() + st::dlgChatImgLeft, rectForName.top() + st::dlgChatImgTop), App::sprite(), st::dlgChatImg); + rectForName.setLeft(rectForName.left() + st::dlgChatImgSkip); + } + + QDateTime now(QDateTime::currentDateTime()), lastTime(item->date); + QDate nowDate(now.date()), lastDate(lastTime.date()); + QString dt = lastTime.toString(qsl("hh:mm")); + int32 dtWidth = st::dlgHistFont->m.width(dt); + rectForName.setWidth(rectForName.width() - dtWidth - st::dlgDateSkip); + p.setFont(st::dlgDateFont->f); + p.setPen(st::dlgDateColor->p); + p.drawText(rectForName.left() + rectForName.width() + st::dlgDateSkip, rectForName.top() + st::dlgHistFont->ascent, dt); + + const HistoryItem *textCachedFor = 0; + Text itemTextCache(itemWidth); + bool active = false; + item->drawInDialog(p, QRect(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dlgFont->height), active, textCachedFor, itemTextCache); + + p.setPen(st::dlgNameColor->p); + history->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); + } + pm = QPixmap::fromImage(img); + + hideTimer.setSingleShot(true); + connect(&hideTimer, SIGNAL(timeout()), this, SLOT(hideByTimer())); + + inputTimer.setSingleShot(true); + connect(&inputTimer, SIGNAL(timeout()), this, SLOT(checkLastInput())); + + connect(&close, SIGNAL(clicked()), this, SLOT(unlinkHistory())); + close.setAcceptBoth(true); + close.move(w - st::notifyClose.width - st::notifyClosePos.x(), st::notifyClosePos.y()); + close.show(); + + aY.start(y); + setGeometry(x, aY.current(), st::notifyWidth, st::notifyHeight); + + aOpacity.start(1); + setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint); + + show(); + + setWindowOpacity(aOpacity.current()); + + alphaDuration = posDuration = st::notifyFastAnim; + anim::start(this); + + checkLastInput(); +} + +void PsNotifyWindow::checkLastInput() { + LASTINPUTINFO lii; + lii.cbSize = sizeof(LASTINPUTINFO); + BOOL res = GetLastInputInfo(&lii); + if (!res || lii.dwTime >= started) { + hideTimer.start(st::notifyWaitLongHide); + } else { + inputTimer.start(300); + } +} + +void PsNotifyWindow::moveTo(int32 x, int32 y, int32 index) { + if (index >= 0) { + _index = index; + } + move(x, aY.current()); + aY.start(y); + aOpacity.restart(); + posDuration = st::notifyFastAnim; + anim::start(this); +} + +void PsNotifyWindow::updatePeerPhoto() { + if (!peerPhoto->isNull() && peerPhoto->loaded()) { + QImage img(pm.toImage()); + { + QPainter p(&img); + p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), peerPhoto->pix(st::notifyPhotoSize)); + } + peerPhoto = ImagePtr(); + pm = QPixmap::fromImage(img); + update(); + } +} + +void PsNotifyWindow::unlinkHistory(History *hist) { + if (!hist || hist == history) { + animHide(st::notifyFastAnim, st::notifyFastAnimFunc); + history = 0; + App::wnd()->psShowNextNotify(); + } +} + +void PsNotifyWindow::enterEvent(QEvent *e) { + if (!history) return; + if (App::wnd()) App::wnd()->psStopHiding(); +} + +void PsNotifyWindow::leaveEvent(QEvent *e) { + if (!history) return; + App::wnd()->psStartHiding(); +} + +void PsNotifyWindow::startHiding() { + hideTimer.start(st::notifyWaitShortHide); +} + +void PsNotifyWindow::mousePressEvent(QMouseEvent *e) { + if (!history) return; + if (e->button() == Qt::RightButton) { + unlinkHistory(); + } else if (history) { + App::wnd()->showFromTray(); + App::wnd()->hideSettings(); + App::main()->showPeer(history->peer->id, false, true); + e->ignore(); + } +} + +void PsNotifyWindow::paintEvent(QPaintEvent *e) { + QPainter p(this); + p.drawPixmap(0, 0, pm); +} + +void PsNotifyWindow::animHide(float64 duration, anim::transition func) { + if (!history) return; + alphaDuration = duration; + aOpacityFunc = func; + aOpacity.start(0); + aY.restart(); + hiding = true; + anim::start(this); +} + +void PsNotifyWindow::stopHiding() { + if (!history) return; + alphaDuration = st::notifyFastAnim; + aOpacityFunc = st::notifyFastAnimFunc; + aOpacity.start(1); + aY.restart(); + hiding = false; + hideTimer.stop(); + anim::start(this); +} + +void PsNotifyWindow::hideByTimer() { + if (!history) return; + animHide(st::notifySlowHide, st::notifySlowHideFunc); +} + +bool PsNotifyWindow::animStep(float64 ms) { + float64 dtAlpha = ms / alphaDuration, dtPos = ms / posDuration; + if (dtAlpha >= 1) { + aOpacity.finish(); + if (hiding) { + deleteLater(); + } + } else { + aOpacity.update(dtAlpha, aOpacityFunc); + } + setWindowOpacity(aOpacity.current()); + if (dtPos >= 1) { + aY.finish(); + } else { + aY.update(dtPos, anim::linear); + } + move(x(), aY.current()); + update(); + return (dtAlpha < 1 || !hiding && dtPos < 1); +} + +PsNotifyWindow::~PsNotifyWindow() { + if (App::wnd()) App::wnd()->psShowNextNotify(this); +}*/ + +PsApplication::PsApplication(int argc, char *argv[]) : QApplication(argc, argv) { +} + +void PsApplication::psInstallEventFilter() { + /*delete _psEventFilter; + _psEventFilter = new _PsEventFilter(); + installNativeEventFilter(_psEventFilter);*/ +} + +PsApplication::~PsApplication() { + //delete _psEventFilter; + //_psEventFilter = 0; +} + +PsUpdateDownloader::PsUpdateDownloader(QThread *thread, const MTPDhelp_appUpdate &update) : already(0), reply(0), full(0) { + updateUrl = qs(update.vurl); + moveToThread(thread); + manager.moveToThread(thread); + App::setProxySettings(manager); + + connect(thread, SIGNAL(started()), this, SLOT(start())); + initOutput(); +} + +PsUpdateDownloader::PsUpdateDownloader(QThread *thread, const QString &url) : already(0), reply(0), full(0) { + updateUrl = url; + moveToThread(thread); + manager.moveToThread(thread); + App::setProxySettings(manager); + + connect(thread, SIGNAL(started()), this, SLOT(start())); + initOutput(); +} + +void PsUpdateDownloader::initOutput() { + QString fileName; + QRegularExpressionMatch m = QRegularExpression(qsl("/([^/\\?]+)(\\?|$)")).match(updateUrl); + if (m.hasMatch()) { + fileName = m.captured(1).replace(QRegularExpression(qsl("[^a-zA-Z0-9_\\-]")), QString()); + } + if (fileName.isEmpty()) { + fileName = qsl("tupdate-%1").arg(rand()); + } + QString dirStr = cWorkingDir() + qsl("tupdates/"); + fileName = dirStr + fileName; + QFileInfo file(fileName); + + QDir dir(dirStr); + if (dir.exists()) { + QFileInfoList all = dir.entryInfoList(QDir::Files); + for (QFileInfoList::iterator i = all.begin(), e = all.end(); i != e; ++i) { + if (i->absoluteFilePath() != file.absoluteFilePath()) { + QFile::remove(i->absoluteFilePath()); + } + } + } else { + dir.mkdir(dir.absolutePath()); + } + outputFile.setFileName(fileName); + if (file.exists()) { + uint64 fullSize = file.size(); + if (fullSize < INT_MAX) { + int32 goodSize = (int32)fullSize; + if (goodSize % UpdateChunk) { + goodSize = goodSize - (goodSize % UpdateChunk); + if (goodSize) { + if (outputFile.open(QIODevice::ReadOnly)) { + QByteArray goodData = outputFile.readAll().mid(0, goodSize); + outputFile.close(); + if (outputFile.open(QIODevice::WriteOnly)) { + outputFile.write(goodData); + outputFile.close(); + + QMutexLocker lock(&mutex); + already = goodSize; + } + } + } + } else { + QMutexLocker lock(&mutex); + already = goodSize; + } + } + if (!already) { + QFile::remove(fileName); + } + } +} + +void PsUpdateDownloader::start() { + sendRequest(); +} + +void PsUpdateDownloader::sendRequest() { + QNetworkRequest req(updateUrl); + QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(already) + "-";// + QByteArray::number(already + cUpdateChunk() - 1); + req.setRawHeader("Range", rangeHeaderValue); + req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); + if (reply) reply->deleteLater(); + reply = manager.get(req); + connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(partFinished(qint64,qint64))); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(partFailed(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(metaDataChanged()), this, SLOT(partMetaGot())); +} + +void PsUpdateDownloader::partMetaGot() { + typedef QList Pairs; + Pairs pairs = reply->rawHeaderPairs(); + for (Pairs::iterator i = pairs.begin(), e = pairs.end(); i != e; ++i) { + if (QString::fromUtf8(i->first).toLower() == "content-range") { + QRegularExpressionMatch m = QRegularExpression(qsl("/(\\d+)([^\\d]|$)")).match(QString::fromUtf8(i->second)); + if (m.hasMatch()) { + { + QMutexLocker lock(&mutex); + full = m.captured(1).toInt(); + } + emit App::app()->updateDownloading(already, full); + } + } + } +} + +int32 PsUpdateDownloader::ready() { + QMutexLocker lock(&mutex); + return already; +} + +int32 PsUpdateDownloader::size() { + QMutexLocker lock(&mutex); + return full; +} + +void PsUpdateDownloader::partFinished(qint64 got, qint64 total) { + if (!reply) return; + + QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + if (statusCode.isValid()) { + int status = statusCode.toInt(); + if (status != 200 && status != 206 && status != 416) { + LOG(("Update Error: Bad HTTP status received in partFinished(): %1").arg(status)); + return fatalFail(); + } + } + + if (!already && !full) { + QMutexLocker lock(&mutex); + full = total; + } + DEBUG_LOG(("Update Info: part %1 of %2").arg(got).arg(total)); + + if (!outputFile.isOpen()) { + if (!outputFile.open(QIODevice::Append)) { + LOG(("Update Error: Could not open output file '%1' for appending").arg(outputFile.fileName())); + return fatalFail(); + } + } + QByteArray r = reply->readAll(); + if (!r.isEmpty()) { + outputFile.write(r); + + QMutexLocker lock(&mutex); + already += r.size(); + } + if (got >= total) { + reply->deleteLater(); + reply = 0; + outputFile.close(); + unpackUpdate(); + } else { + emit App::app()->updateDownloading(already, full); + } +} + +void PsUpdateDownloader::partFailed(QNetworkReply::NetworkError e) { + if (!reply) return; + + QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + reply->deleteLater(); + reply = 0; + if (statusCode.isValid()) { + int status = statusCode.toInt(); + if (status == 416) { // Requested range not satisfiable + outputFile.close(); + unpackUpdate(); + return; + } + } + LOG(("Update Error: failed to download part starting from %1, error %2").arg(already).arg(e)); + emit App::app()->updateFailed(); +} + +void PsUpdateDownloader::deleteDir(const QString &dir) { + /*std::wstring wDir = QDir::toNativeSeparators(dir).toStdWString(); + WCHAR path[4096]; + memcpy(path, wDir.c_str(), (wDir.size() + 1) * sizeof(WCHAR)); + path[wDir.size() + 1] = 0; + SHFILEOPSTRUCT file_op = { + NULL, + FO_DELETE, + path, + L"", + FOF_NOCONFIRMATION | + FOF_NOERRORUI | + FOF_SILENT, + false, + 0, + L"" + }; + int res = SHFileOperation(&file_op);*/ +} + +void PsUpdateDownloader::fatalFail() { + clearAll(); + emit App::app()->updateFailed(); +} + +void PsUpdateDownloader::clearAll() { + deleteDir(cWorkingDir() + qsl("tupdates")); +} + +void PsUpdateDownloader::unpackUpdate() { + /*QByteArray packed; + if (!outputFile.open(QIODevice::ReadOnly)) { + LOG(("Update Error: cant read updates file!")); + return fatalFail(); + } + + const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header + + QByteArray compressed = outputFile.readAll(); + int32 compressedLen = compressed.size() - hSize; + if (compressedLen <= 0) { + LOG(("Update Error: bad compressed size: %1").arg(compressed.size())); + return fatalFail(); + } + outputFile.close(); + + QString tempDirPath = cWorkingDir() + qsl("tupdates/temp"), readyDirPath = cWorkingDir() + qsl("tupdates/ready"); + deleteDir(tempDirPath); + deleteDir(readyDirPath); + + QDir tempDir(tempDirPath), readyDir(readyDirPath); + if (tempDir.exists() || readyDir.exists()) { + LOG(("Update Error: cant clear tupdates/temp or tupdates/ready dir!")); + return fatalFail(); + } + + uchar sha1Buffer[20]; + bool goodSha1 = !memcmp(compressed.constData() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen); + if (!goodSha1) { + LOG(("Update Error: bad SHA1 hash of update file!")); + return fatalFail(); + } + + RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast(UpdatesPublicKey), -1), 0, 0, 0); + if (!pbKey) { + LOG(("Update Error: cant read public rsa key!")); + return fatalFail(); + } + if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature + RSA_free(pbKey); + LOG(("Update Error: bad RSA signature of update file!")); + return fatalFail(); + } + RSA_free(pbKey); + + QByteArray uncompressed; + + int32 uncompressedLen; + memcpy(&uncompressedLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen); + uncompressed.resize(uncompressedLen); + + size_t resultLen = uncompressed.size(); + SizeT srcLen = compressedLen; + int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); + if (uncompressRes != SZ_OK) { + LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes)); + return fatalFail(); + } + + tempDir.mkdir(tempDir.absolutePath()); + + quint32 version; + { + QBuffer buffer(&uncompressed); + buffer.open(QIODevice::ReadOnly); + QDataStream stream(&buffer); + stream.setVersion(QDataStream::Qt_5_1); + + stream >> version; + if (stream.status() != QDataStream::Ok) { + LOG(("Update Error: cant read version from downloaded stream, status: %1").arg(stream.status())); + return fatalFail(); + } + if (version <= AppVersion) { + LOG(("Update Error: downloaded version %1 is not greater, than mine %2").arg(version).arg(AppVersion)); + return fatalFail(); + } + + quint32 filesCount; + stream >> filesCount; + if (stream.status() != QDataStream::Ok) { + LOG(("Update Error: cant read files count from downloaded stream, status: %1").arg(stream.status())); + return fatalFail(); + } + if (!filesCount) { + LOG(("Update Error: update is empty!")); + return fatalFail(); + } + for (int32 i = 0; i < filesCount; ++i) { + QString relativeName; + quint32 fileSize; + QByteArray fileInnerData; + + stream >> relativeName >> fileSize >> fileInnerData; + if (stream.status() != QDataStream::Ok) { + LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status())); + return fatalFail(); + } + if (fileSize != fileInnerData.size()) { + LOG(("Update Error: bad file size %1 not matching data size %2").arg(fileSize).arg(fileInnerData.size())); + return fatalFail(); + } + + QFile f(tempDirPath + '/' + relativeName); + if (!f.open(QIODevice::WriteOnly)) { + LOG(("Update Error: cant open file '%1' for writing").arg(tempDirPath + '/' + relativeName)); + return fatalFail(); + } + if (f.write(fileInnerData) != fileSize) { + f.close(); + LOG(("Update Error: cant write file '%1'").arg(tempDirPath + '/' + relativeName)); + return fatalFail(); + } + f.close(); + } + + // create tdata/version file + tempDir.mkdir(QDir(tempDirPath + qsl("/tdata")).absolutePath()); + std::wstring versionString = ((version % 1000) ? QString("%1.%2.%3").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000)).arg(int(version % 1000)) : QString("%1.%2").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000))).toStdWString(); + DWORD versionNum = DWORD(version), versionLen = DWORD(versionString.size() * sizeof(WCHAR)); + WCHAR versionStr[32]; + memcpy(versionStr, versionString.c_str(), versionLen); + + QFile fVersion(tempDirPath + qsl("/tdata/version")); + if (!fVersion.open(QIODevice::WriteOnly)) { + LOG(("Update Error: cant write version file '%1'").arg(tempDirPath + qsl("/version"))); + return fatalFail(); + } + fVersion.write((const char*)&versionNum, sizeof(DWORD)); + fVersion.write((const char*)&versionLen, sizeof(DWORD)); + fVersion.write((const char*)&versionStr[0], versionLen); + fVersion.close(); + } + + if (!tempDir.rename(tempDir.absolutePath(), readyDir.absolutePath())) { + LOG(("Update Error: cant rename temp dir '%1' to ready dir '%2'").arg(tempDir.absolutePath()).arg(readyDir.absolutePath())); + return fatalFail(); + } + deleteDir(tempDirPath); + outputFile.remove(); + + emit App::app()->updateReady();*/ +} + +PsUpdateDownloader::~PsUpdateDownloader() { + delete reply; + reply = 0; +} + +/*namespace { + BOOL CALLBACK _ActivateProcess(HWND hWnd, LPARAM lParam) { + uint64 &processId(*(uint64*)lParam); + + DWORD dwProcessId; + ::GetWindowThreadProcessId(hWnd, &dwProcessId); + + if ((uint64)dwProcessId == processId) { // found top-level window + static const int32 nameBufSize = 1024; + WCHAR nameBuf[nameBufSize]; + int32 len = GetWindowText(hWnd, nameBuf, nameBufSize); + if (len && len < nameBufSize) { + if (QRegularExpression(qsl("^Telegram(\\s*\\(\\d+\\))?$")).match(QString::fromStdWString(nameBuf)).hasMatch()) { + BOOL res = ::SetForegroundWindow(hWnd); + return FALSE; + } + } + } + return TRUE; + } +}*/ + +void psActivateProcess(uint64 pid) { + //::EnumWindows((WNDENUMPROC)_ActivateProcess, (LPARAM)&pid); +} + +QString psCurrentCountry() { + /*int chCount = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, 0, 0); + if (chCount && chCount < 128) { + WCHAR wstrCountry[128]; + int len = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, wstrCountry, chCount); + return len ? QString::fromStdWString(std::wstring(wstrCountry)) : QString::fromLatin1(DefaultCountry); + } + return QString::fromLatin1(DefaultCountry);*/ + return QString(""); + //TODO +} + +/*namespace { + QString langById(int lngId) { + int primary = lngId & 0xFF; + switch (primary) { + case 0x36: return qsl("af"); + case 0x1C: return qsl("sq"); + case 0x5E: return qsl("am"); + case 0x01: return qsl("ar"); + case 0x2B: return qsl("hy"); + case 0x4D: return qsl("as"); + case 0x2C: return qsl("az"); + case 0x45: return qsl("bn"); + case 0x6D: return qsl("ba"); + case 0x2D: return qsl("eu"); + case 0x23: return qsl("be"); + case 0x1A: + if (lngId == LANG_CROATIAN) { + return qsl("hr"); + } else if (lngId == LANG_BOSNIAN_NEUTRAL || lngId == LANG_BOSNIAN) { + return qsl("bs"); + } + return qsl("sr"); + break; + case 0x7E: return qsl("br"); + case 0x02: return qsl("bg"); + case 0x92: return qsl("ku"); + case 0x03: return qsl("ca"); + case 0x04: return qsl("zh"); + case 0x83: return qsl("co"); + case 0x05: return qsl("cs"); + case 0x06: return qsl("da"); + case 0x65: return qsl("dv"); + case 0x13: return qsl("nl"); + case 0x09: return qsl("en"); + case 0x25: return qsl("et"); + case 0x38: return qsl("fo"); + case 0x0B: return qsl("fi"); + case 0x0c: return qsl("fr"); + case 0x62: return qsl("fy"); + case 0x56: return qsl("gl"); + case 0x37: return qsl("ka"); + case 0x07: return qsl("de"); + case 0x08: return qsl("el"); + case 0x6F: return qsl("kl"); + case 0x47: return qsl("gu"); + case 0x68: return qsl("ha"); + case 0x0D: return qsl("he"); + case 0x39: return qsl("hi"); + case 0x0E: return qsl("hu"); + case 0x0F: return qsl("is"); + case 0x70: return qsl("ig"); + case 0x21: return qsl("id"); + case 0x5D: return qsl("iu"); + case 0x3C: return qsl("ga"); + case 0x34: return qsl("xh"); + case 0x35: return qsl("zu"); + case 0x10: return qsl("it"); + case 0x11: return qsl("ja"); + case 0x4B: return qsl("kn"); + case 0x3F: return qsl("kk"); + case 0x53: return qsl("kh"); + case 0x87: return qsl("rw"); + case 0x12: return qsl("ko"); + case 0x40: return qsl("ky"); + case 0x54: return qsl("lo"); + case 0x26: return qsl("lv"); + case 0x27: return qsl("lt"); + case 0x6E: return qsl("lb"); + case 0x2F: return qsl("mk"); + case 0x3E: return qsl("ms"); + case 0x4C: return qsl("ml"); + case 0x3A: return qsl("mt"); + case 0x81: return qsl("mi"); + case 0x4E: return qsl("mr"); + case 0x50: return qsl("mn"); + case 0x61: return qsl("ne"); + case 0x14: return qsl("no"); + case 0x82: return qsl("oc"); + case 0x48: return qsl("or"); + case 0x63: return qsl("ps"); + case 0x29: return qsl("fa"); + case 0x15: return qsl("pl"); + case 0x16: return qsl("pt"); + case 0x67: return qsl("ff"); + case 0x46: return qsl("pa"); + case 0x18: return qsl("ro"); + case 0x17: return qsl("rm"); + case 0x19: return qsl("ru"); + case 0x3B: return qsl("se"); + case 0x4F: return qsl("sa"); + case 0x32: return qsl("tn"); + case 0x59: return qsl("sd"); + case 0x5B: return qsl("si"); + case 0x1B: return qsl("sk"); + case 0x24: return qsl("sl"); + case 0x0A: return qsl("es"); + case 0x41: return qsl("sw"); + case 0x1D: return qsl("sv"); + case 0x28: return qsl("tg"); + case 0x49: return qsl("ta"); + case 0x44: return qsl("tt"); + case 0x4A: return qsl("te"); + case 0x1E: return qsl("th"); + case 0x51: return qsl("bo"); + case 0x73: return qsl("ti"); + case 0x1F: return qsl("tr"); + case 0x42: return qsl("tk"); + case 0x22: return qsl("uk"); + case 0x20: return qsl("ur"); + case 0x80: return qsl("ug"); + case 0x43: return qsl("uz"); + case 0x2A: return qsl("vi"); + case 0x52: return qsl("cy"); + case 0x88: return qsl("wo"); + case 0x78: return qsl("ii"); + case 0x6A: return qsl("yo"); + } + return QString::fromLatin1(DefaultLanguage); + } +}*/ + +QString psCurrentLanguage() { +/* int chCount = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNAME, 0, 0); + if (chCount && chCount < 128) { + WCHAR wstrLocale[128]; + int len = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNAME, wstrLocale, chCount); + if (!len) return QString::fromLatin1(DefaultLanguage); + QString locale = QString::fromStdWString(std::wstring(wstrLocale)); + QRegularExpressionMatch m = QRegularExpression("(^|[^a-z])([a-z]{2})-").match(locale); + if (m.hasMatch()) { + return m.captured(2); + } + } + chCount = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, 0, 0); + if (chCount && chCount < 128) { + WCHAR wstrLocale[128]; + int len = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, wstrLocale, chCount), lngId = 0; + if (len < 5) return QString::fromLatin1(DefaultLanguage); + + for (int i = 0; i < 4; ++i) { + WCHAR ch = wstrLocale[i]; + lngId *= 16; + if (ch >= WCHAR('0') && ch <= WCHAR('9')) { + lngId += (ch - WCHAR('0')); + } else if (ch >= WCHAR('A') && ch <= WCHAR('F')) { + lngId += (10 + ch - WCHAR('A')); + } else { + return QString::fromLatin1(DefaultLanguage); + } + } + return langById(lngId); + } + return QString::fromLatin1(DefaultLanguage);*/ + return QString("en"); +} + +QString psAppDataPath() { + /*static const int maxFileLen = MAX_PATH * 10; + WCHAR wstrPath[maxFileLen]; + if (GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen)) { + QDir appData(QString::fromStdWString(std::wstring(wstrPath))); + return appData.absolutePath() + "/" + QString::fromWCharArray(AppName) + "/"; + }*/ + return QString(); +} + +QString psCurrentExeDirectory() { + /*LPWSTR *args; + int argsCount; + args = CommandLineToArgvW(GetCommandLine(), &argsCount); + if (args) { + QFileInfo info(QDir::fromNativeSeparators(QString::fromWCharArray(args[0]))); + if (info.isFile()) { + return info.absoluteDir().absolutePath() + '/'; + } + LocalFree(args); + }*/ + return QString(); +} + +void psDoCleanup() { + try { + psAutoStart(false, true); + } catch (...) { + } +} + +int psCleanup() { + /*__try + { + psDoCleanup(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return 0; + }*/ + return 0; +} + +void psDoFixPrevious() { + /*try { + static const int bufSize = 4096; + DWORD checkType, checkSize = bufSize * 2; + WCHAR checkStr[bufSize]; + + QString appId = QString::fromStdWString(AppId); + QString newKeyStr1 = QString("Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%1_is1").arg(appId); + QString newKeyStr2 = QString("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%1_is1").arg(appId); + QString oldKeyStr1 = QString("SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%1_is1").arg(appId); + QString oldKeyStr2 = QString("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%1_is1").arg(appId); + HKEY newKey1, newKey2, oldKey1, oldKey2; + LSTATUS newKeyRes1 = RegOpenKeyEx(HKEY_CURRENT_USER, newKeyStr1.toStdWString().c_str(), 0, KEY_READ, &newKey1); + LSTATUS newKeyRes2 = RegOpenKeyEx(HKEY_CURRENT_USER, newKeyStr2.toStdWString().c_str(), 0, KEY_READ, &newKey2); + LSTATUS oldKeyRes1 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, oldKeyStr1.toStdWString().c_str(), 0, KEY_READ, &oldKey1); + LSTATUS oldKeyRes2 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, oldKeyStr2.toStdWString().c_str(), 0, KEY_READ, &oldKey2); + + bool existNew1 = (newKeyRes1 == ERROR_SUCCESS) && (RegQueryValueEx(newKey1, L"InstallDate", 0, &checkType, (BYTE*)checkStr, &checkSize) == ERROR_SUCCESS); checkSize = bufSize * 2; + bool existNew2 = (newKeyRes2 == ERROR_SUCCESS) && (RegQueryValueEx(newKey2, L"InstallDate", 0, &checkType, (BYTE*)checkStr, &checkSize) == ERROR_SUCCESS); checkSize = bufSize * 2; + bool existOld1 = (oldKeyRes1 == ERROR_SUCCESS) && (RegQueryValueEx(oldKey1, L"InstallDate", 0, &checkType, (BYTE*)checkStr, &checkSize) == ERROR_SUCCESS); checkSize = bufSize * 2; + bool existOld2 = (oldKeyRes2 == ERROR_SUCCESS) && (RegQueryValueEx(oldKey2, L"InstallDate", 0, &checkType, (BYTE*)checkStr, &checkSize) == ERROR_SUCCESS); checkSize = bufSize * 2; + + if (newKeyRes1 == ERROR_SUCCESS) RegCloseKey(newKey1); + if (newKeyRes2 == ERROR_SUCCESS) RegCloseKey(newKey2); + if (oldKeyRes1 == ERROR_SUCCESS) RegCloseKey(oldKey1); + if (oldKeyRes2 == ERROR_SUCCESS) RegCloseKey(oldKey2); + + if (existNew1 || existNew2) { + oldKeyRes1 = existOld1 ? RegDeleteKey(HKEY_LOCAL_MACHINE, oldKeyStr1.toStdWString().c_str()) : ERROR_SUCCESS; + oldKeyRes2 = existOld2 ? RegDeleteKey(HKEY_LOCAL_MACHINE, oldKeyStr2.toStdWString().c_str()) : ERROR_SUCCESS; + } + + QString userDesktopLnk, commonDesktopLnk; + WCHAR userDesktopFolder[MAX_PATH], commonDesktopFolder[MAX_PATH]; + HRESULT userDesktopRes = SHGetFolderPath(0, CSIDL_DESKTOPDIRECTORY, 0, SHGFP_TYPE_CURRENT, userDesktopFolder); + HRESULT commonDesktopRes = SHGetFolderPath(0, CSIDL_COMMON_DESKTOPDIRECTORY, 0, SHGFP_TYPE_CURRENT, commonDesktopFolder); + if (SUCCEEDED(userDesktopRes)) { + userDesktopLnk = QString::fromWCharArray(userDesktopFolder) + "\\Telegram.lnk"; + } + if (SUCCEEDED(commonDesktopRes)) { + commonDesktopLnk = QString::fromWCharArray(commonDesktopFolder) + "\\Telegram.lnk"; + } + QFile userDesktopFile(userDesktopLnk), commonDesktopFile(commonDesktopLnk); + if (QFile::exists(userDesktopLnk) && QFile::exists(commonDesktopLnk) && userDesktopLnk != commonDesktopLnk) { + bool removed = QFile::remove(commonDesktopLnk); + } + } catch (...) { + }*/ +} + +int psFixPrevious() { + /*__try + { + psDoFixPrevious(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return 0; + }*/ + return 0; +} + +bool psCheckReadyUpdate() { + /*QString readyPath = cWorkingDir() + qsl("tupdates/ready"); + if (!QDir(readyPath).exists()) { + return false; + } + + // check ready version + QString versionPath = readyPath + qsl("/tdata/version"); + { + QFile fVersion(versionPath); + if (!fVersion.open(QIODevice::ReadOnly)) { + LOG(("Update Error: cant read version file '%1'").arg(versionPath)); + PsUpdateDownloader::clearAll(); + return false; + } + DWORD versionNum; + if (fVersion.read((char*)&versionNum, sizeof(DWORD)) != sizeof(DWORD)) { + LOG(("Update Error: cant read version from file '%1'").arg(versionPath)); + PsUpdateDownloader::clearAll(); + return false; + } + fVersion.close(); + if (versionNum <= AppVersion) { + LOG(("Update Error: cant install version %1 having version %2").arg(versionNum).arg(AppVersion)); + PsUpdateDownloader::clearAll(); + return false; + } + } + + QString curUpdater = (cExeDir() + "Updater.exe"); + QFileInfo updater(cWorkingDir() + "tupdates/ready/Updater.exe"); + if (!updater.exists()) { + QFileInfo current(curUpdater); + if (!current.exists()) { + PsUpdateDownloader::clearAll(); + return false; + } + if (CopyFile(current.absoluteFilePath().toStdWString().c_str(), updater.absoluteFilePath().toStdWString().c_str(), TRUE) == FALSE) { + PsUpdateDownloader::clearAll(); + return false; + } + } + if (CopyFile(updater.absoluteFilePath().toStdWString().c_str(), curUpdater.toStdWString().c_str(), FALSE) == FALSE) { + PsUpdateDownloader::clearAll(); + return false; + } + if (DeleteFile(updater.absoluteFilePath().toStdWString().c_str()) == FALSE) { + PsUpdateDownloader::clearAll(); + return false; + }*/ + return false; // TODO +} + +void psPostprocessFile(const QString &name) { + /*std::wstring zoneFile = QDir::toNativeSeparators(name).toStdWString() + L":Zone.Identifier"; + HANDLE f = CreateFile(zoneFile.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (f == INVALID_HANDLE_VALUE) { // :( + return; + } + + const char data[] = "[ZoneTransfer]\r\nZoneId=3\r\n"; + + DWORD written = 0; + BOOL result = WriteFile(f, data, sizeof(data), &written, NULL); + CloseHandle(f); + + if (!result || written != sizeof(data)) { // :( + return; + }*/ +} + +void psOpenFile(const QString &name, bool openWith) { + /*std::wstring wname = QDir::toNativeSeparators(name).toStdWString(); + + if (openWith && useOpenAs) { + if (shOpenWithDialog) { + OPENASINFO info; + info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC; + info.pcszClass = NULL; + info.pcszFile = wname.c_str(); + shOpenWithDialog(0, &info); + } else { + openAs_RunDLL(0, 0, wname.c_str(), SW_SHOWNORMAL); + } + } else { + ShellExecute(0, L"open", wname.c_str(), 0, 0, SW_SHOWNORMAL); + }*/ +} + +void psShowInFolder(const QString &name) { + //QString nameEscaped = QDir::toNativeSeparators(name).replace('"', qsl("\"\"")); + //ShellExecute(0, 0, qsl("explorer").toStdWString().c_str(), (qsl("/select,") + nameEscaped).toStdWString().c_str(), 0, SW_SHOWNORMAL); +} + +void psExecUpdater() { + /*QString targs = qsl("-update"); + if (cFromAutoStart()) targs += qsl(" -autostart"); + if (cDebug()) targs += qsl(" -debug"); + + QString updater(QDir::toNativeSeparators(cExeDir() + "Updater.exe")), wdir(QDir::toNativeSeparators(cWorkingDir())); + + DEBUG_LOG(("Application Info: executing %1 %2").arg(cExeDir() + "Updater.exe").arg(targs)); + HINSTANCE r = ShellExecute(0, 0, updater.toStdWString().c_str(), targs.toStdWString().c_str(), wdir.isEmpty() ? 0 : wdir.toStdWString().c_str(), SW_SHOWNORMAL); + if (long(r) < 32) { + DEBUG_LOG(("Application Error: failed to execute %1, working directory: '%2', result: %3").arg(updater).arg(wdir).arg(long(r))); + QString readyPath = cWorkingDir() + qsl("tupdates/ready"); + PsUpdateDownloader::deleteDir(readyPath); + }*/ +} + +void psExecTelegram() { + /*QString targs = qsl("-noupdate -tosettings"); + if (cFromAutoStart()) targs += qsl(" -autostart"); + if (cDebug()) targs += qsl(" -debug"); + if (cDataFile() != (cTestMode() ? qsl("data_test") : qsl("data"))) targs += qsl(" -key \"") + cDataFile() + '"'; + + QString telegram(QDir::toNativeSeparators(cExeDir() + "Telegram.exe")), wdir(QDir::toNativeSeparators(cWorkingDir())); + + DEBUG_LOG(("Application Info: executing %1 %2").arg(cExeDir() + "Telegram.exe").arg(targs)); + HINSTANCE r = ShellExecute(0, 0, telegram.toStdWString().c_str(), targs.toStdWString().c_str(), wdir.isEmpty() ? 0 : wdir.toStdWString().c_str(), SW_SHOWNORMAL); + if (long(r) < 32) { + DEBUG_LOG(("Application Error: failed to execute %1, working directory: '%2', result: %3").arg(telegram).arg(wdir).arg(long(r))); + }*/ +} + +void psAutoStart(bool start, bool silent) { + /*WCHAR startupFolder[MAX_PATH]; + HRESULT hres = SHGetFolderPath(0, CSIDL_STARTUP, 0, SHGFP_TYPE_CURRENT, startupFolder); + if (SUCCEEDED(hres)) { + QString lnk = QString::fromWCharArray(startupFolder) + "\\Telegram.lnk"; + if (start) { + IShellLink* psl; + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); + if (SUCCEEDED(hres)) { + IPersistFile* ppf; + + QString exe = QDir::toNativeSeparators(QDir(cExeDir()).absolutePath() + "//Telegram.exe"), dir = QDir::toNativeSeparators(QDir(cWorkingDir()).absolutePath()); + psl->SetArguments(L"-autostart"); + psl->SetPath(exe.toStdWString().c_str()); + psl->SetWorkingDirectory(dir.toStdWString().c_str()); + psl->SetDescription(L"Telegram autorun link.\nYou can disable autorun in Telegram settings."); + + hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); + + if (SUCCEEDED(hres)) { + hres = ppf->Save(lnk.toStdWString().c_str(), TRUE); + ppf->Release(); + } else { + if (!silent) LOG(("App Error: could not create interface IID_IPersistFile %1").arg(hres)); + } + psl->Release(); + } else { + if (!silent) LOG(("App Error: could not create instance of IID_IShellLink %1").arg(hres)); + } + } else { + QFile::remove(lnk); + } + } else { + if (!silent) LOG(("App Error: could not get CSIDL_STARTUP folder %1").arg(hres)); + }*/ +} diff --git a/Telegram/SourceFiles/pspecific_mac.h b/Telegram/SourceFiles/pspecific_mac.h new file mode 100644 index 000000000..276ddc274 --- /dev/null +++ b/Telegram/SourceFiles/pspecific_mac.h @@ -0,0 +1,227 @@ +#pragma once + +inline QString psServerPrefix() { + return qsl("/tmp/"); +} +inline void psCheckLocalSocket(const QString &serverName) { + QFile address(serverName); + if (address.exists()) { + address.remove(); + } +} + +/* +class PsNotifyWindow : public QWidget, public Animated { + Q_OBJECT + +public: + + PsNotifyWindow(HistoryItem *item, int32 x, int32 y); + + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void mousePressEvent(QMouseEvent *e); + void paintEvent(QPaintEvent *e); + + bool animStep(float64 ms); + void animHide(float64 duration, anim::transition func); + void startHiding(); + void stopHiding(); + void moveTo(int32 x, int32 y, int32 index = -1); + + void updatePeerPhoto(); + + int32 index() const { + return history ? _index : -1; + } + + ~PsNotifyWindow(); + +public slots: + + void hideByTimer(); + void checkLastInput(); + + void unlinkHistory(History *hist = 0); + +private: + + DWORD started; + + History *history; + IconedButton close; + QPixmap pm; + float64 alphaDuration, posDuration; + QTimer hideTimer, inputTimer; + bool hiding; + int32 _index; + anim::fvalue aOpacity; + anim::transition aOpacityFunc; + anim::ivalue aY; + ImagePtr peerPhoto; + +}; + +typedef QList PsNotifyWindows;*/ + +class PsMainWindow : public QMainWindow { + Q_OBJECT + +public: + PsMainWindow(QWidget *parent = 0); + + int32 psResizeRowWidth() const { + return 0;//st::wndResizeAreaWidth; + } + + void psInitFrameless(); + void psInitSize(); + //HWND psHwnd() const; + //HMENU psMenu() const; + + void psFirstShow(); + void psInitSysMenu(); + void psUpdateSysMenu(Qt::WindowState state); + void psUpdateMargins(); + void psUpdatedPosition(); + + bool psHandleTitle(); + + void psFlash(); + + bool psIsActive() const; + bool psIsOnline(int windowState) const; + + void psUpdateWorkmode(); + + void psRefreshTaskbarIcon(); + virtual bool minimizeToTray() { + return false; + } + + void psNotify(History *history); + void psClearNotify(History *history = 0); + void psClearNotifyFast(); + //void psShowNextNotify(PsNotifyWindow *remove = 0); + void psStopHiding(); + void psStartHiding(); + void psUpdateNotifies(); + + bool psPosInited() const { + return posInited; + } + + ~PsMainWindow(); + +public slots: + + void psStateChanged(Qt::WindowState state); + void psUpdateCounter(); + void psSavePosition(Qt::WindowState state = Qt::WindowActive); + void psIdleTimeout(); + +protected: + + bool posInited; + QSystemTrayIcon *trayIcon; + QMenu *trayIconMenu; + QImage icon16, icon32, icon256; + virtual void setupTrayIcon() { + } +/* + typedef QSet NotifyHistories; + NotifyHistories notifyHistories; + PsNotifyWindows notifyWindows; + + QTimer psUpdatedPositionTimer;*/ + +/*private: + HWND ps_hWnd; + HWND ps_tbHider_hWnd; + HMENU ps_menu; + HICON ps_iconBig, ps_iconSmall, ps_iconOverlay; + + mutable bool psIdle; + mutable QTimer psIdleTimer; + + void psDestroyIcons();*/ +}; + + +class PsApplication : public QApplication { + Q_OBJECT + +public: + + PsApplication(int argc, char *argv[]); + void psInstallEventFilter(); + ~PsApplication(); + +signals: + + void updateChecking(); + void updateLatest(); + void updateDownloading(qint64 ready, qint64 total); + void updateReady(); + void updateFailed(); + +}; + +class PsUpdateDownloader : public QObject { + Q_OBJECT + +public: + PsUpdateDownloader(QThread *thread, const MTPDhelp_appUpdate &update); + PsUpdateDownloader(QThread *thread, const QString &url); + + void unpackUpdate(); + + int32 ready(); + int32 size(); + + static void deleteDir(const QString &dir); + static void clearAll(); + + ~PsUpdateDownloader(); + +public slots: + + void start(); + void partMetaGot(); + void partFinished(qint64 got, qint64 total); + void partFailed(QNetworkReply::NetworkError e); + void sendRequest(); + +private: + void initOutput(); + + void fatalFail(); + + QString updateUrl; + QNetworkAccessManager manager; + QNetworkReply *reply; + int32 already, full; + QFile outputFile; + + QMutex mutex; + +}; + +void psActivateProcess(uint64 pid); +QString psLocalServerPrefix(); +QString psCurrentCountry(); +QString psCurrentLanguage(); +QString psAppDataPath(); +QString psCurrentExeDirectory(); +void psAutoStart(bool start, bool silent = false); + +int psCleanup(); +int psFixPrevious(); + +bool psCheckReadyUpdate(); +void psExecUpdater(); +void psExecTelegram(); + +void psPostprocessFile(const QString &name); +void psOpenFile(const QString &name, bool openWith = false); +void psShowInFolder(const QString &name); diff --git a/Telegram/SourceFiles/pspecific_wnd.cpp b/Telegram/SourceFiles/pspecific_wnd.cpp new file mode 100644 index 000000000..79fae055a --- /dev/null +++ b/Telegram/SourceFiles/pspecific_wnd.cpp @@ -0,0 +1,2806 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "pspecific.h" + +#include "lang.h" +#include "application.h" +#include "mainwidget.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) < (b) ? (b) : (a)) + +#ifndef DCX_USESTYLE +#define DCX_USESTYLE 0x00010000 +#endif + +#ifndef WM_NCPOINTERUPDATE +#define WM_NCPOINTERUPDATE 0x0241 +#define WM_NCPOINTERDOWN 0x0242 +#define WM_NCPOINTERUP 0x0243 +#endif + +#include +#pragma comment (lib,"Gdiplus.lib") +#pragma comment (lib,"Msimg32.lib") + +namespace { + bool frameless = true; + bool useDWM = false; + bool useTheme = false; + bool useOpenAs = false; + bool themeInited = false; + bool finished = true; + int menuShown = 0, menuHidden = 0; + int dleft = 0, dtop = 0; + QMargins simpleMargins, margins; + HICON bigIcon = 0, smallIcon = 0, overlayIcon = 0; + + UINT tbCreatedMsgId = 0; + ITaskbarList3 *tbListInterface = 0; + + HWND createTaskbarHider() { + HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0); + HWND hWnd = 0; + + QString cn = QString("TelegramTaskbarHider"); + LPCWSTR _cn = (LPCWSTR)cn.utf16(); + WNDCLASSEX wc; + + wc.cbSize = sizeof(wc); + wc.style = 0; + wc.lpfnWndProc = DefWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = appinst; + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = 0; + wc.lpszMenuName = NULL; + wc.lpszClassName = _cn; + wc.hIconSm = 0; + if (!RegisterClassEx(&wc)) { + DEBUG_LOG(("Application Error: could not register taskbar hider window class, error: %1").arg(GetLastError())); + return hWnd; + } + + hWnd = CreateWindowEx(WS_EX_TOOLWINDOW, _cn, 0, WS_POPUP, 0, 0, 0, 0, 0, 0, appinst, 0); + if (!hWnd) { + DEBUG_LOG(("Application Error: could not create taskbar hider window class, error: %1").arg(GetLastError())); + return hWnd; + } + return hWnd; + } + + enum { + _PsShadowMoved = 0x01, + _PsShadowResized = 0x02, + _PsShadowShown = 0x04, + _PsShadowHidden = 0x08, + _PsShadowActivate = 0x10, + }; + + enum { + _PsInitHor = 0x01, + _PsInitVer = 0x02, + }; + + int32 _psSize = 0; + class _PsShadowWindows { + public: + + _PsShadowWindows() : screenDC(0), max_w(0), max_h(0), _x(0), _y(0), _w(0), _h(0), hidden(true), r(0), g(0), b(0), noKeyColor(RGB(255, 255, 255)) { + for (int i = 0; i < 4; ++i) { + dcs[i] = 0; + bitmaps[i] = 0; + hwnds[i] = 0; + } + } + + void setColor(QColor c) { + r = c.red(); + g = c.green(); + b = c.blue(); + + if (!hwnds[0]) return; + Gdiplus::SolidBrush brush(Gdiplus::Color(_alphas[0], r, g, b)); + for (int i = 0; i < 4; ++i) { + Gdiplus::Graphics graphics(dcs[i]); + graphics.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + if ((i % 2) && _h || !(i % 2) && _w) { + graphics.FillRectangle(&brush, 0, 0, (i % 2) ? _size : _w, (i % 2) ? _h : _size); + } + } + initCorners(); + + _x = _y = _w = _h = 0; + update(_PsShadowMoved | _PsShadowResized); + } + + bool init(QColor c) { + style::rect topLeft = st::wndShadow; + _fullsize = topLeft.width(); + _shift = st::wndShadowShift; + QImage cornersImage(_fullsize, _fullsize, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&cornersImage); + p.drawPixmap(QPoint(0, 0), App::sprite(), topLeft); + } + uchar *bits = cornersImage.bits(); + if (bits) { + for ( + quint32 *p = (quint32*)bits, *end = (quint32*)(bits + cornersImage.byteCount()); + p < end; + ++p + ) { + *p = (*p ^ 0x00ffffff) << 24; + } + } + + _metaSize = _fullsize + 2 * _shift; + _alphas.reserve(_metaSize); + _colors.reserve(_metaSize * _metaSize); + for (int32 j = 0; j < _metaSize; ++j) { + for (int32 i = 0; i < _metaSize; ++i) { + _colors.push_back((i < 2 * _shift || j < 2 * _shift) ? 1 : qMax(BYTE(1), BYTE(cornersImage.pixel(QPoint(i - 2 * _shift, j - 2 * _shift)) >> 24))); + } + } + uchar prev = 0; + for (int32 i = 0; i < _metaSize; ++i) { + uchar a = _colors[(_metaSize - 1) * _metaSize + i]; + if (a < prev) break; + + _alphas.push_back(a); + prev = a; + } + _psSize = _size = _alphas.size() - 2 * _shift; + + setColor(c); + + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + ULONG_PTR gdiplusToken; + Gdiplus::Status gdiRes = Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + + if (gdiRes != Gdiplus::Ok) { + DEBUG_LOG(("Application Error: could not init GDI+, error: %1").arg((int)gdiRes)); + return false; + } + blend.AlphaFormat = AC_SRC_ALPHA; + blend.SourceConstantAlpha = 255; + blend.BlendFlags = 0; + blend.BlendOp = AC_SRC_OVER; + + screenDC = GetDC(0); + if (!screenDC) return false; + + QRect avail(QDesktopWidget().availableGeometry()); + max_w = avail.width(); + if (max_w < st::wndMinWidth) max_w = st::wndMinWidth; + max_h = avail.height(); + if (max_h < st::wndMinHeight) max_h = st::wndMinHeight; + + HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0); + + for (int i = 0; i < 4; ++i) { + QString cn = QString("TelegramShadow%1").arg(i); + LPCWSTR _cn = (LPCWSTR)cn.utf16(); + WNDCLASSEX wc; + + wc.cbSize = sizeof(wc); + wc.style = 0; + wc.lpfnWndProc = wndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = appinst; + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = 0; + wc.lpszMenuName = NULL; + wc.lpszClassName = _cn; + wc.hIconSm = 0; + if (!RegisterClassEx(&wc)) { + DEBUG_LOG(("Application Error: could not register shadow window class %1, error: %2").arg(i).arg(GetLastError())); + destroy(); + return false; + } + + hwnds[i] = CreateWindowEx(WS_EX_LAYERED | WS_EX_TOOLWINDOW, _cn, 0, WS_POPUP, 0, 0, 0, 0, 0, 0, appinst, 0); + if (!hwnds[i]) { + DEBUG_LOG(("Application Error: could not create shadow window class %1, error: %2").arg(i).arg(GetLastError())); + destroy(); + return false; + } + + dcs[i] = CreateCompatibleDC(screenDC); + if (!dcs[i]) { + DEBUG_LOG(("Application Error: could not create dc for shadow window class %1, error: %2").arg(i).arg(GetLastError())); + destroy(); + return false; + } + + bitmaps[i] = CreateCompatibleBitmap(screenDC, (i % 2) ? _size : max_w, (i % 2) ? max_h : _size); + if (!bitmaps[i]) { + DEBUG_LOG(("Application Error: could not create bitmap for shadow window class %1, error: %2").arg(i).arg(GetLastError())); + destroy(); + return false; + } + + SelectObject(dcs[i], bitmaps[i]); + } + + initCorners(); + return true; + } + + void initCorners(int directions = (_PsInitHor | _PsInitVer)) { + bool hor = (directions & _PsInitHor), ver = (directions & _PsInitVer); + Gdiplus::Graphics graphics0(dcs[0]), graphics1(dcs[1]), graphics2(dcs[2]), graphics3(dcs[3]); + graphics0.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + graphics1.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + graphics2.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + graphics3.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + + Gdiplus::SolidBrush brush(Gdiplus::Color(_alphas[0], r, g, b)); + if (hor) graphics0.FillRectangle(&brush, 0, 0, _fullsize - (_size - _shift), 2 * _shift); + + if (ver) { + graphics1.FillRectangle(&brush, 0, 0, _size, 2 * _shift); + graphics3.FillRectangle(&brush, 0, 0, _size, 2 * _shift); + graphics1.FillRectangle(&brush, _size - _shift, 2 * _shift, _shift, _fullsize); + graphics3.FillRectangle(&brush, 0, 2 * _shift, _shift, _fullsize); + } + + if (hor) { + for (int j = 2 * _shift; j < _size; ++j) { + for (int k = 0; k < _fullsize - (_size - _shift); ++k) { + brush.SetColor(Gdiplus::Color(_colors[j * _metaSize + k + (_size + _shift)], r, g, b)); + graphics0.FillRectangle(&brush, k, j, 1, 1); + graphics2.FillRectangle(&brush, k, _size - (j - 2 * _shift) - 1, 1, 1); + } + } + for (int j = _size; j < _size + 2 * _shift; ++j) { + for (int k = 0; k < _fullsize - (_size - _shift); ++k) { + brush.SetColor(Gdiplus::Color(_colors[j * _metaSize + k + (_size + _shift)], r, g, b)); + graphics2.FillRectangle(&brush, k, _size - (j - 2 * _shift) - 1, 1, 1); + } + } + } + if (ver) { + for (int j = 2 * _shift; j < _fullsize + 2 * _shift; ++j) { + for (int k = _shift; k < _size; ++k) { + brush.SetColor(Gdiplus::Color(_colors[j * _metaSize + (k + _shift)], r, g, b)); + graphics1.FillRectangle(&brush, _size - k - 1, j, 1, 1); + graphics3.FillRectangle(&brush, k, j, 1, 1); + } + } + } + } + void verCorners(int h, Gdiplus::Graphics *pgraphics1, Gdiplus::Graphics *pgraphics3) { + Gdiplus::SolidBrush brush(Gdiplus::Color(_alphas[0], r, g, b)); + pgraphics1->FillRectangle(&brush, _size - _shift, h - _fullsize, _shift, _fullsize); + pgraphics3->FillRectangle(&brush, 0, h - _fullsize, _shift, _fullsize); + for (int j = 0; j < _fullsize; ++j) { + for (int k = _shift; k < _size; ++k) { + brush.SetColor(Gdiplus::Color(_colors[(j + 2 * _shift) * _metaSize + k + _shift], r, g, b)); + pgraphics1->FillRectangle(&brush, _size - k - 1, h - j - 1, 1, 1); + pgraphics3->FillRectangle(&brush, k, h - j - 1, 1, 1); + } + } + } + void horCorners(int w, Gdiplus::Graphics *pgraphics0, Gdiplus::Graphics *pgraphics2) { + Gdiplus::SolidBrush brush(Gdiplus::Color(_alphas[0], r, g, b)); + pgraphics0->FillRectangle(&brush, w - 2 * _size - (_fullsize - (_size - _shift)), 0, _fullsize - (_size - _shift), 2 * _shift); + for (int j = 2 * _shift; j < _size; ++j) { + for (int k = 0; k < _fullsize - (_size - _shift); ++k) { + brush.SetColor(Gdiplus::Color(_colors[j * _metaSize + k + (_size + _shift)], r, g, b)); + pgraphics0->FillRectangle(&brush, w - 2 * _size - k - 1, j, 1, 1); + pgraphics2->FillRectangle(&brush, w - 2 * _size - k - 1, _size - (j - 2 * _shift) - 1, 1, 1); + } + } + for (int j = _size; j < _size + 2 * _shift; ++j) { + for (int k = 0; k < _fullsize - (_size - _shift); ++k) { + brush.SetColor(Gdiplus::Color(_colors[j * _metaSize + k + (_size + _shift)], r, g, b)); + pgraphics2->FillRectangle(&brush, w - 2 * _size - k - 1, _size - (j - 2 * _shift) - 1, 1, 1); + } + } + } + + void update(int changes, WINDOWPOS *pos = 0) { + HWND hwnd = Application::wnd() ? Application::wnd()->psHwnd() : 0; + if (!hwnd || !hwnds[0]) return; + + if (changes == _PsShadowActivate) { + for (int i = 0; i < 4; ++i) { + SetWindowPos(hwnds[i], hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + return; + } + + if (changes & _PsShadowHidden) { + if (!hidden) { + for (int i = 0; i < 4; ++i) { + hidden = true; + ShowWindow(hwnds[i], SW_HIDE); + } + } + return; + } + if (!Application::wnd()->psPosInited()) return; + + int x = _x, y = _y, w = _w, h = _h; + if (pos && (!(pos->flags & SWP_NOMOVE) || !(pos->flags & SWP_NOSIZE) || !(pos->flags & SWP_NOREPOSITION))) { + if (!(pos->flags & SWP_NOMOVE)) { + x = pos->x - _size; + y = pos->y - _size; + } else if (pos->flags & SWP_NOSIZE) { + for (int i = 0; i < 4; ++i) { + SetWindowPos(hwnds[i], hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + return; + } + if (!(pos->flags & SWP_NOSIZE)) { + w = pos->cx + 2 * _size; + h = pos->cy + 2 * _size; + } + } else { + RECT r; + GetWindowRect(hwnd, &r); + x = r.left - _size; + y = r.top - _size; + w = r.right + _size - x; + h = r.bottom + _size - y; + } + if (h < 2 * _fullsize + 2 * _shift) { + h = 2 * _fullsize + 2 * _shift; + } + if (w < 2 * (_fullsize + _shift)) { + w = 2 * (_fullsize + _shift); + } + + if (w != _w) { + int from = (_w > 2 * (_fullsize + _shift)) ? (_w - _size - _fullsize - _shift) : (_fullsize - (_size - _shift)); + int to = w - _size - _fullsize - _shift; + if (w > max_w) { + from = _fullsize - (_size - _shift); + max_w *= 2; + for (int i = 0; i < 4; i += 2) { + DeleteObject(bitmaps[i]); + bitmaps[i] = CreateCompatibleBitmap(screenDC, max_w, _size); + SelectObject(dcs[i], bitmaps[i]); + } + initCorners(_PsInitHor); + } + Gdiplus::Graphics graphics0(dcs[0]), graphics2(dcs[2]); + graphics0.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + graphics2.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + Gdiplus::SolidBrush brush(Gdiplus::Color(_alphas[0], r, g, b)); + if (to > from) { + graphics0.FillRectangle(&brush, from, 0, to - from, 2 * _shift); + for (int i = 2 * _shift; i < _size; ++i) { + Gdiplus::Pen pen(Gdiplus::Color(_alphas[i], r, g, b)); + graphics0.DrawLine(&pen, from, i, to, i); + graphics2.DrawLine(&pen, from, _size - (i - 2 * _shift) - 1, to, _size - (i - 2 * _shift) - 1); + } + for (int i = _size; i < _size + 2 * _shift; ++i) { + Gdiplus::Pen pen(Gdiplus::Color(_alphas[i], r, g, b)); + graphics2.DrawLine(&pen, from, _size - (i - 2 * _shift) - 1, to, _size - (i - 2 * _shift) - 1); + } + } + if (_w > w) { + graphics0.FillRectangle(&brush, w - _size - _fullsize - _shift, 0, _fullsize - (_size - _shift), _size); + graphics2.FillRectangle(&brush, w - _size - _fullsize - _shift, 0, _fullsize - (_size - _shift), _size); + } + horCorners(w, &graphics0, &graphics2); + POINT p0 = { x + _size, y }, p2 = { x + _size, y + h - _size }, f = { 0, 0 }; + SIZE s = { w - 2 * _size, _size }; + updateWindow(0, &p0, &s); + updateWindow(2, &p2, &s); + } else if (x != _x || y != _y) { + POINT p0 = { x + _size, y }, p2 = { x + _size, y + h - _size }; + updateWindow(0, &p0); + updateWindow(2, &p2); + } else if (h != _h) { + POINT p2 = { x + _size, y + h - _size }; + updateWindow(2, &p2); + } + + if (h != _h) { + int from = (_h > 2 * _fullsize + 2 * _shift) ? (_h - _fullsize) : (_fullsize + 2 * _shift); + int to = h - _fullsize; + if (h > max_h) { + from = (_fullsize + 2 * _shift); + max_h *= 2; + for (int i = 1; i < 4; i += 2) { + DeleteObject(bitmaps[i]); + bitmaps[i] = CreateCompatibleBitmap(dcs[i], _size, max_h); + SelectObject(dcs[i], bitmaps[i]); + } + initCorners(_PsInitVer); + } + Gdiplus::Graphics graphics1(dcs[1]), graphics3(dcs[3]); + graphics1.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + graphics3.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + + Gdiplus::SolidBrush brush(Gdiplus::Color(_alphas[0], r, g, b)); + if (to > from) { + graphics1.FillRectangle(&brush, _size - _shift, from, _shift, to - from); + graphics3.FillRectangle(&brush, 0, from, _shift, to - from); + for (int i = 2 * _shift; i < _size + _shift; ++i) { + Gdiplus::Pen pen(Gdiplus::Color(_alphas[i], r, g, b)); + graphics1.DrawLine(&pen, _size + _shift - i - 1, from, _size + _shift - i - 1, to); + graphics3.DrawLine(&pen, i - _shift, from, i - _shift, to); + } + } + if (_h > h) { + graphics1.FillRectangle(&brush, 0, h - _fullsize, _size, _fullsize); + graphics3.FillRectangle(&brush, 0, h - _fullsize, _size, _fullsize); + } + verCorners(h, &graphics1, &graphics3); + + POINT p1 = {x + w - _size, y}, p3 = {x, y}, f = {0, 0}; + SIZE s = { _size, h }; + updateWindow(1, &p1, &s); + updateWindow(3, &p3, &s); + } else if (x != _x || y != _y) { + POINT p1 = { x + w - _size, y }, p3 = { x, y }; + updateWindow(1, &p1); + updateWindow(3, &p3); + } else if (w != _w) { + POINT p1 = { x + w - _size, y }; + updateWindow(1, &p1); + } + _x = x; + _y = y; + _w = w; + _h = h; + + if (hidden && (changes & _PsShadowShown)) { + for (int i = 0; i < 4; ++i) { + SetWindowPos(hwnds[i], hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE); + } + hidden = false; + } + } + + void updateWindow(int i, POINT *p, SIZE *s = 0) { + static POINT f = {0, 0}; + if (s) { + UpdateLayeredWindow(hwnds[i], (s ? screenDC : 0), p, s, (s ? dcs[i] : 0), (s ? (&f) : 0), noKeyColor, &blend, ULW_ALPHA); + } else { + SetWindowPos(hwnds[i], 0, p->x, p->y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); + } + } + + void destroy() { + for (int i = 0; i < 4; ++i) { + if (dcs[i]) DeleteDC(dcs[i]); + if (bitmaps[i]) DeleteObject(bitmaps[i]); + if (hwnds[i]) DestroyWindow(hwnds[i]); + dcs[i] = 0; + bitmaps[i] = 0; + hwnds[i] = 0; + } + if (screenDC) ReleaseDC(0, screenDC); + } + + private: + + int _x, _y, _w, _h; + int _metaSize, _fullsize, _size, _shift; + QVector _alphas, _colors; + + bool hidden; + + HWND hwnds[4]; + HDC dcs[4], screenDC; + HBITMAP bitmaps[4]; + int max_w, max_h; + BLENDFUNCTION blend; + + BYTE r, g, b; + COLORREF noKeyColor; + + static LRESULT CALLBACK _PsShadowWindows::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + + }; + _PsShadowWindows _psShadowWindows; + + LRESULT CALLBACK _PsShadowWindows::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + if (finished) return DefWindowProc(hwnd, msg, wParam, lParam); + + int i; + for (i = 0; i < 4; ++i) { + if (_psShadowWindows.hwnds[i] && hwnd == _psShadowWindows.hwnds[i]) { + break; + } + } + if (i == 4) return DefWindowProc(hwnd, msg, wParam, lParam); + + switch (msg) { + case WM_CLOSE: + Application::wnd()->close(); + break; + case WM_NCHITTEST: { + int32 xPos = GET_X_LPARAM(lParam), yPos = GET_Y_LPARAM(lParam); + switch (i) { + case 0: return HTTOP; + case 1: return (yPos < _psShadowWindows._y + _psSize) ? HTTOPRIGHT : ((yPos >= _psShadowWindows._y + _psShadowWindows._h - _psSize) ? HTBOTTOMRIGHT : HTRIGHT); + case 2: return HTBOTTOM; + case 3: return (yPos < _psShadowWindows._y + _psSize) ? HTTOPLEFT : ((yPos >= _psShadowWindows._y + _psShadowWindows._h - _psSize) ? HTBOTTOMLEFT : HTLEFT); + } + return HTTRANSPARENT; + } break; + + case WM_NCACTIVATE: return DefWindowProc(hwnd, msg, wParam, lParam); + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + case WM_NCLBUTTONDBLCLK: + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + case WM_NCMBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + case WM_NCRBUTTONDBLCLK: + case WM_NCXBUTTONDOWN: + case WM_NCXBUTTONUP: + case WM_NCXBUTTONDBLCLK: + case WM_NCMOUSEHOVER: + case WM_NCMOUSELEAVE: + case WM_NCMOUSEMOVE: + case WM_NCPOINTERUPDATE: + case WM_NCPOINTERDOWN: + case WM_NCPOINTERUP: + if (App::wnd() && App::wnd()->psHwnd()) { + if (msg == WM_NCLBUTTONDOWN) { + ::SetForegroundWindow(App::wnd()->psHwnd()); + } + LRESULT res = SendMessage(App::wnd()->psHwnd(), msg, wParam, lParam); + return res; + } + return 0; + break; + case WM_ACTIVATE: + if (App::wnd() && App::wnd()->psHwnd() && wParam == WA_ACTIVE) { + if ((HWND)lParam != App::wnd()->psHwnd()) { + ::SetForegroundWindow(hwnd); + ::SetWindowPos(App::wnd()->psHwnd(), hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + } + } + return DefWindowProc(hwnd, msg, wParam, lParam); + break; + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; + } + + QColor _shActive(0, 0, 0), _shInactive(0, 0, 0); + + typedef BOOL (FAR STDAPICALLTYPE *f_dwmDefWindowProc)(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, _Out_ LRESULT *plResult); + f_dwmDefWindowProc dwmDefWindowProc; + + typedef HRESULT (FAR STDAPICALLTYPE *f_dwmSetWindowAttribute)(HWND hWnd, DWORD dwAttribute, _In_ LPCVOID pvAttribute, DWORD cbAttribute); + f_dwmSetWindowAttribute dwmSetWindowAttribute; + + typedef HRESULT (FAR STDAPICALLTYPE *f_dwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS *pMarInset); + f_dwmExtendFrameIntoClientArea dwmExtendFrameIntoClientArea; + + typedef HRESULT (FAR STDAPICALLTYPE *f_setWindowTheme)(HWND hWnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList); + f_setWindowTheme setWindowTheme; + + typedef HRESULT (FAR STDAPICALLTYPE *f_openAs_RunDLL)(HWND hWnd, HINSTANCE hInstance, LPCWSTR lpszCmdLine, int nCmdShow); + f_openAs_RunDLL openAs_RunDLL; + + typedef HRESULT (FAR STDAPICALLTYPE *f_shOpenWithDialog)(HWND hwndParent, const OPENASINFO *poainfo); + f_shOpenWithDialog shOpenWithDialog; + + template + bool loadFunction(HINSTANCE dll, LPCSTR name, TFunction &func) { + if (!dll) return false; + + func = (TFunction)GetProcAddress(dll, name); + return !!func; + } + + class _PsInitializer { + public: + _PsInitializer() { + setupDWM(); + useDWM = true; + frameless = !useDWM; + + setupUx(); + setupOpenAs(); + } + void setupDWM() { + HINSTANCE procId = LoadLibrary(L"DWMAPI.DLL"); + + if (!loadFunction(procId, "DwmDefWindowProc", dwmDefWindowProc)) return; + if (!loadFunction(procId, "DwmSetWindowAttribute", dwmSetWindowAttribute)) return; + if (!loadFunction(procId, "DwmExtendFrameIntoClientArea", dwmExtendFrameIntoClientArea)) return; + useDWM = true; + } + void setupUx() { + HINSTANCE procId = LoadLibrary(L"UXTHEME.DLL"); + + if (!loadFunction(procId, "SetWindowTheme", setWindowTheme)) return; + useTheme = true; + } + void setupOpenAs() { + HINSTANCE procId = LoadLibrary(L"SHELL32.DLL"); + + if (!loadFunction(procId, "SHOpenWithDialog", shOpenWithDialog) && !loadFunction(procId, "OpenAs_RunDLLW", openAs_RunDLL)) return; + useOpenAs = true; + } + }; + _PsInitializer _psInitializer; + + class _PsEventFilter : public QAbstractNativeEventFilter { + public: + _PsEventFilter() { + } + + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) { + Window *wnd = Application::wnd(); + if (!wnd) return false; + + MSG *msg = (MSG*)message; + if (msg->message == WM_ENDSESSION) { + App::quit(); + return false; + } + if (msg->hwnd == wnd->psHwnd() || msg->hwnd && !wnd->psHwnd()) { + return mainWindowEvent(msg->hwnd, msg->message, msg->wParam, msg->lParam, (LRESULT*)result); + } + return false; + } + + bool mainWindowEvent(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result) { + if (tbCreatedMsgId && msg == tbCreatedMsgId) { + if (CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_ALL, IID_ITaskbarList3, (void**)&tbListInterface) != S_OK) { + tbListInterface = 0; + } + } + switch (msg) { + + case WM_DESTROY: { + App::quit(); + } return false; + + case WM_ACTIVATE: { + if (LOWORD(wParam) == WA_CLICKACTIVE) { + App::wnd()->inactivePress(true); + } + Application::wnd()->psUpdateMargins(); + if (LOWORD(wParam) != WA_INACTIVE) { + _psShadowWindows.setColor(_shActive); + _psShadowWindows.update(_PsShadowActivate); + } else { + _psShadowWindows.setColor(_shInactive); + } + QTimer::singleShot(0, Application::wnd(), SLOT(psUpdateCounter())); + Application::wnd()->update(); + } return false; + + case WM_NCPAINT: if (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS8) return false; *result = 0; return true; + + case WM_NCCALCSIZE: if (!useDWM) return false; { + if (wParam == TRUE) { + LPNCCALCSIZE_PARAMS params = (LPNCCALCSIZE_PARAMS)lParam; + params->rgrc[0].left += margins.left() - simpleMargins.left(); + params->rgrc[0].top += margins.top() - simpleMargins.top(); + params->rgrc[0].right -= margins.right() - simpleMargins.right(); + params->rgrc[0].bottom -= margins.bottom() - simpleMargins.bottom(); + } else if (wParam == FALSE) { + LPRECT rect = (LPRECT)lParam; + + rect->left += margins.left() - simpleMargins.left(); + rect->top += margins.top() - simpleMargins.top(); + rect->right += margins.right() - simpleMargins.right(); + rect->bottom += margins.bottom() - simpleMargins.bottom(); + } + *result = 0; + } return true; + + case WM_NCACTIVATE: { + Application::wnd()->psUpdateMargins(); + *result = LRESULT(TRUE); + Application::wnd()->repaint(); + } return true; + + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: { + _psShadowWindows.update(_PsShadowMoved | _PsShadowResized, (WINDOWPOS*)lParam); + } return false; + + case WM_SIZE: { + if (App::wnd()) { + if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED || wParam == SIZE_MINIMIZED) { + if (wParam != SIZE_RESTORED || App::wnd()->windowState() != Qt::WindowNoState) { + Qt::WindowState state = Qt::WindowNoState; + if (wParam == SIZE_MAXIMIZED) { + state = Qt::WindowMaximized; + } else if (wParam == SIZE_MINIMIZED) { + state = Qt::WindowMinimized; + } + emit App::wnd()->windowHandle()->windowStateChanged(state); + } else { + App::wnd()->psUpdatedPosition(); + } + int changes = (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXIMIZED) ? _PsShadowHidden : (_PsShadowResized | _PsShadowShown); + _psShadowWindows.update(changes); + } + } + } return false; + + case WM_SHOWWINDOW: { + LONG style = GetWindowLong(hWnd, GWL_STYLE); + int changes = _PsShadowResized | ((wParam && !(style & (WS_MAXIMIZE | WS_MINIMIZE))) ? _PsShadowShown : _PsShadowHidden); + _psShadowWindows.update(changes); + } return false; + + case WM_MOVE: { + _psShadowWindows.update(_PsShadowMoved); + App::wnd()->psUpdatedPosition(); + } return false; + + case WM_NCHITTEST: { + POINTS p = MAKEPOINTS(lParam); + RECT r; + GetWindowRect(hWnd, &r); + HitTestType res = Application::wnd()->hitTest(QPoint(p.x - r.left + dleft, p.y - r.top + dtop)); + switch (res) { + case HitTestClient: + case HitTestSysButton: *result = HTCLIENT; break; + case HitTestIcon: *result = HTCAPTION; break; + case HitTestCaption: *result = HTCAPTION; break; + case HitTestTop: *result = HTTOP; break; + case HitTestTopRight: *result = HTTOPRIGHT; break; + case HitTestRight: *result = HTRIGHT; break; + case HitTestBottomRight: *result = HTBOTTOMRIGHT; break; + case HitTestBottom: *result = HTBOTTOM; break; + case HitTestBottomLeft: *result = HTBOTTOMLEFT; break; + case HitTestLeft: *result = HTLEFT; break; + case HitTestTopLeft: *result = HTTOPLEFT; break; + case HitTestNone: + default: *result = HTTRANSPARENT; break; + }; + } return true; + + case WM_NCRBUTTONUP: { + SendMessage(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam); + } return true; + + case WM_NCLBUTTONDOWN: { + POINTS p = MAKEPOINTS(lParam); + RECT r; + GetWindowRect(hWnd, &r); + HitTestType res = Application::wnd()->hitTest(QPoint(p.x - r.left + dleft, p.y - r.top + dtop)); + switch (res) { + case HitTestIcon: + if (menuHidden && getms() < menuHidden + 10) { + menuHidden = 0; + if (getms() < menuShown + GetDoubleClickTime()) { + Application::wnd()->close(); + } + } else { + QRect icon = Application::wnd()->iconRect(); + p.x = r.left - dleft + icon.left(); + p.y = r.top - dtop + icon.top() + icon.height(); + Application::wnd()->psUpdateSysMenu(Application::wnd()->windowHandle()->windowState()); + menuShown = getms(); + menuHidden = 0; + TrackPopupMenu(Application::wnd()->psMenu(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON, p.x, p.y, 0, hWnd, 0); + menuHidden = getms(); + } + return true; + }; + } return false; + + case WM_NCLBUTTONDBLCLK: { + POINTS p = MAKEPOINTS(lParam); + RECT r; + GetWindowRect(hWnd, &r); + HitTestType res = Application::wnd()->hitTest(QPoint(p.x - r.left + dleft, p.y - r.top + dtop)); + switch (res) { + case HitTestIcon: Application::wnd()->close(); return true; + }; + } return false; + + case WM_SYSCOMMAND: { + if (wParam == SC_MOUSEMENU) { + POINTS p = MAKEPOINTS(lParam); + Application::wnd()->psUpdateSysMenu(Application::wnd()->windowHandle()->windowState()); + TrackPopupMenu(Application::wnd()->psMenu(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON, p.x, p.y, 0, hWnd, 0); + } + } return false; + + case WM_COMMAND: { + if (HIWORD(wParam)) return false; + int cmd = LOWORD(wParam); + switch (cmd) { + case SC_CLOSE: Application::wnd()->close(); return true; + case SC_MINIMIZE: Application::wnd()->setWindowState(Qt::WindowMinimized); return true; + case SC_MAXIMIZE: Application::wnd()->setWindowState(Qt::WindowMaximized); return true; + case SC_RESTORE: Application::wnd()->setWindowState(Qt::WindowNoState); return true; + } + } return true; + + } + return false; + } + }; + _PsEventFilter *_psEventFilter = 0; + +}; + +PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent), ps_hWnd(0), ps_menu(0), icon256(qsl(":/gui/art/iconround256.png")), + ps_iconBig(0), ps_iconSmall(0), ps_iconOverlay(0), trayIcon(0), trayIconMenu(0), posInited(false), ps_tbHider_hWnd(createTaskbarHider()), psIdle(false) { + tbCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated"); + icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation); + icon32 = icon256.scaledToWidth(32, Qt::SmoothTransformation); + connect(&psIdleTimer, SIGNAL(timeout()), this, SLOT(psIdleTimeout())); + psIdleTimer.setSingleShot(false); + connect(¬ifyWaitTimer, SIGNAL(timeout()), this, SLOT(psNotifyFire())); + notifyWaitTimer.setSingleShot(true); +} + +void PsMainWindow::psIdleTimeout() { + LASTINPUTINFO lii; + lii.cbSize = sizeof(LASTINPUTINFO); + BOOL res = GetLastInputInfo(&lii); + if (res) { + uint64 ticks = GetTickCount(); + if (lii.dwTime >= ticks - IdleMsecs) { + psIdle = false; + psIdleTimer.stop(); + if (App::main()) App::main()->setOnline(); + } + } +} + +bool PsMainWindow::psIsActive() const { + return isActiveWindow() && isVisible() && !(windowState() & Qt::WindowMinimized); +} + +bool PsMainWindow::psIsOnline(int windowState) const { + if (windowState < 0) windowState = this->windowState(); + if (windowState & Qt::WindowMinimized) { + return false; + } else if (!isVisible()) { + return false; + } + LASTINPUTINFO lii; + lii.cbSize = sizeof(LASTINPUTINFO); + BOOL res = GetLastInputInfo(&lii); + if (res) { + uint64 ticks = GetTickCount(); + if (lii.dwTime < ticks - IdleMsecs) { + if (!psIdle) { + psIdle = true; + psIdleTimer.start(900); + } + return false; + } else { + psIdle = false; + psIdleTimer.stop(); + } + } + return true; +} + +void PsMainWindow::psRefreshTaskbarIcon() { + QWidget *w = new QWidget(this); + w->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + w->setGeometry(x() + 1, y() + 1, 1, 1); + QPalette p(w->palette()); + p.setColor(QPalette::Background, st::titleBG->c); + QWindow *wnd = w->windowHandle(); + w->setPalette(p); + w->show(); + w->activateWindow(); + delete w; +} + +void PsMainWindow::psUpdateWorkmode() { + switch (cWorkMode()) { + case dbiwmWindowAndTray: { + setupTrayIcon(); + HWND psOwner = (HWND)GetWindowLong(ps_hWnd, GWL_HWNDPARENT); + if (psOwner) { + SetWindowLong(ps_hWnd, GWL_HWNDPARENT, 0); + psRefreshTaskbarIcon(); + } + } break; + + case dbiwmTrayOnly: { + setupTrayIcon(); + HWND psOwner = (HWND)GetWindowLong(ps_hWnd, GWL_HWNDPARENT); + if (!psOwner) { + SetWindowLong(ps_hWnd, GWL_HWNDPARENT, (LONG)ps_tbHider_hWnd); + } + } break; + + case dbiwmWindowOnly: { + if (trayIconMenu) trayIconMenu->deleteLater(); + trayIconMenu = 0; + if (trayIcon) trayIcon->deleteLater(); + trayIcon = 0; + + HWND psOwner = (HWND)GetWindowLong(ps_hWnd, GWL_HWNDPARENT); + if (psOwner) { + SetWindowLong(ps_hWnd, GWL_HWNDPARENT, 0); + psRefreshTaskbarIcon(); + } + } break; + } +} + +HICON qt_pixmapToWinHICON(const QPixmap &); +static HICON _qt_createHIcon(const QIcon &icon, int xSize, int ySize) { + if (!icon.isNull()) { + const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize))); + if (!pm.isNull()) + return qt_pixmapToWinHICON(pm); + } + return 0; +} + +void PsMainWindow::psUpdateCounter() { + int32 counter = App::histories().unreadFull; + style::color bg = (App::histories().unreadMuted < counter) ? st::counterBG : st::counterMuteBG; + QIcon icon; + QImage cicon16(icon16), cicon32(icon32); + if (counter > 0) { + { + QString cnt = (counter < 1000) ? QString("%1").arg(counter) : QString("..%1").arg(counter % 100, 2, 10, QChar('0')); + QPainter p16(&cicon16); + p16.setBrush(bg->b); + p16.setPen(Qt::NoPen); + p16.setRenderHint(QPainter::Antialiasing); + int32 fontSize = 8; + style::font f(fontSize); + int32 w = f->m.width(cnt), d = 2, r = 3; + p16.drawRoundedRect(QRect(16 - w - d * 2, 16 - f->height, w + d * 2, f->height), r, r); + p16.setFont(f->f); + + p16.setPen(st::counterColor->p); + + p16.drawText(16 - w - d, 16 - f->height + f->ascent, cnt); + } + if (!tbListInterface) { + QString cnt = (counter < 10000) ? QString("%1").arg(counter) : ((counter < 1000000) ? QString("%1K").arg(counter / 1000) : QString("%1M").arg(counter / 1000000)); + QPainter p32(&cicon32); + style::font f(10); + int32 w = f->m.width(cnt), d = 3, r = 6; + p32.setBrush(bg->b); + p32.setPen(Qt::NoPen); + p32.setRenderHint(QPainter::Antialiasing); + p32.drawRoundedRect(QRect(32 - w - d * 2, 0, w + d * 2, f->height - 1), r, r); + p32.setPen(st::counterColor->p); + p32.setFont(f->f); + p32.drawText(32 - w - d, f->ascent - 1, cnt); + } + } + icon.addPixmap(QPixmap::fromImage(cicon16)); + icon.addPixmap(QPixmap::fromImage(cicon32)); + if (trayIcon) { + QIcon ticon; + QImage ticon16(icon16); + if (counter > 0) { + QString cnt = (counter < 1000) ? QString("%1").arg(counter) : QString("..%1").arg(counter % 100, 2, 10, QChar('0')); + { + QPainter p16(&ticon16); + p16.setBrush(bg->b); + p16.setPen(Qt::NoPen); + p16.setRenderHint(QPainter::Antialiasing); + int32 fontSize = 8; + style::font f(fontSize); + int32 w = f->m.width(cnt), d = 2, r = 3; + p16.drawRoundedRect(QRect(16 - w - d * 2, 16 - f->height, w + d * 2, f->height), r, r); + p16.setFont(f->f); + + p16.setPen(st::counterColor->p); + + p16.drawText(16 - w - d, 16 - f->height + f->ascent, cnt); + } + } + ticon.addPixmap(QPixmap::fromImage(ticon16)); + ticon.addPixmap(QPixmap::fromImage(cicon32)); + trayIcon->setIcon(ticon); + } + + setWindowTitle((counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram")); + psDestroyIcons(); + ps_iconSmall = _qt_createHIcon(icon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); + ps_iconBig = _qt_createHIcon(icon, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON)); + SendMessage(ps_hWnd, WM_SETICON, 0, (LPARAM)ps_iconSmall); + SendMessage(ps_hWnd, WM_SETICON, 1, (LPARAM)(ps_iconBig ? ps_iconBig : ps_iconSmall)); + if (tbListInterface) { + if (counter > 0) { + QString cnt = (counter < 1000) ? QString("%1").arg(counter) : QString("..%1").arg(counter % 100, 2, 10, QChar('0')); + QImage oicon16(16, 16, QImage::Format_ARGB32); + int32 cntSize = cnt.size(); + oicon16.fill(st::transparent->c); + { + QPainter p16(&oicon16); + p16.setBrush(bg->b); + p16.setPen(Qt::NoPen); + p16.setRenderHint(QPainter::Antialiasing); + int32 fontSize = (cntSize < 2) ? 12 : ((cntSize < 3) ? 12 : 8); + style::font f(fontSize); + int32 w = f->m.width(cnt), d = (cntSize < 2) ? 5 : ((cntSize < 3) ? 2 : 2), r = (cntSize < 2) ? 8 : ((cntSize < 3) ? 7 : 3); + p16.drawRoundedRect(QRect(16 - w - d * 2, 16 - f->height, w + d * 2, f->height), r, r); + p16.setFont(f->f); + + p16.setPen(st::counterColor->p); + + p16.drawText(16 - w - d, 16 - f->height + f->ascent, cnt); + } + QIcon oicon(QPixmap::fromImage(oicon16)); + ps_iconOverlay = _qt_createHIcon(oicon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); + } + QString description = counter > 0 ? QString("%1 unread messages").arg(counter) : qsl("No unread messages"); + static WCHAR descriptionArr[1024]; + description.toWCharArray(descriptionArr); + tbListInterface->SetOverlayIcon(ps_hWnd, ps_iconOverlay, descriptionArr); + } +} + +namespace { + HMONITOR enumMonitor = 0; + RECT enumMonitorWork; + + BOOL CALLBACK _monitorEnumProc( + _In_ HMONITOR hMonitor, + _In_ HDC hdcMonitor, + _In_ LPRECT lprcMonitor, + _In_ LPARAM dwData + ) { + MONITORINFOEX info; + info.cbSize = sizeof(info); + GetMonitorInfo(hMonitor, &info); + if (dwData == hashCrc32(info.szDevice, sizeof(info.szDevice))) { + enumMonitor = hMonitor; + enumMonitorWork = info.rcWork; + return FALSE; + } + return TRUE; + } +} + +void PsMainWindow::psInitSize() { + setMinimumWidth(st::wndMinWidth); + setMinimumHeight(st::wndMinHeight); + + TWindowPos pos(cWindowPos()); + if (cDebug()) { // temp while design + pos.w = 800; + pos.h = 600; + } + QRect avail(QDesktopWidget().availableGeometry()); + bool maximized = false; + QRect geom(avail.x() + (avail.width() - st::wndDefWidth) / 2, avail.y() + (avail.height() - st::wndDefHeight) / 2, st::wndDefWidth, st::wndDefHeight); + if (pos.w && pos.h) { + if (pos.y < 0) pos.y = 0; + enumMonitor = 0; + EnumDisplayMonitors(0, 0, &_monitorEnumProc, pos.moncrc); + if (enumMonitor) { + int32 w = enumMonitorWork.right - enumMonitorWork.left, h = enumMonitorWork.bottom - enumMonitorWork.top; + if (w >= st::wndMinWidth && h >= st::wndMinHeight) { + if (pos.w > w) pos.w = w; + if (pos.h > h) pos.h = h; + pos.x += enumMonitorWork.left; + pos.y += enumMonitorWork.top; + if (pos.x < enumMonitorWork.right - 10 && pos.y < enumMonitorWork.bottom - 10) { + geom = QRect(pos.x, pos.y, pos.w, pos.h); + } + } + } + maximized = pos.maximized; + } + setGeometry(geom); +} + +void PsMainWindow::psInitFrameless() { + psUpdatedPositionTimer.setSingleShot(true); + connect(&psUpdatedPositionTimer, SIGNAL(timeout()), this, SLOT(psSavePosition())); + + QPlatformNativeInterface *i = QGuiApplication::platformNativeInterface(); + ps_hWnd = static_cast(i->nativeResourceForWindow(QByteArrayLiteral("handle"), windowHandle())); + + if (!ps_hWnd) return; + + if (frameless) { + setWindowFlags(Qt::FramelessWindowHint); + } + +// RegisterApplicationRestart(NULL, 0); + + psInitSysMenu(); + connect(windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(psStateChanged(Qt::WindowState))); +} + +void PsMainWindow::psSavePosition(Qt::WindowState state) { + if (state == Qt::WindowActive) state = windowHandle()->windowState(); + if (state == Qt::WindowMinimized || !posInited) return; + + TWindowPos pos(cWindowPos()), curPos = pos; + + if (state == Qt::WindowMaximized) { + curPos.maximized = 1; + } else { + RECT w; + GetWindowRect(ps_hWnd, &w); + curPos.x = w.left; + curPos.y = w.top; + curPos.w = w.right - w.left; + curPos.h = w.bottom - w.top; + curPos.maximized = 0; + } + + HMONITOR hMonitor = MonitorFromWindow(ps_hWnd, MONITOR_DEFAULTTONEAREST); + if (hMonitor) { + MONITORINFOEX info; + info.cbSize = sizeof(info); + GetMonitorInfo(hMonitor, &info); + if (!curPos.maximized) { + curPos.x -= info.rcWork.left; + curPos.y -= info.rcWork.top; + } + curPos.moncrc = hashCrc32(info.szDevice, sizeof(info.szDevice)); + } + + if (curPos.w >= st::wndMinWidth && curPos.h >= st::wndMinHeight) { + if (curPos.x != pos.x || curPos.y != pos.y || curPos.w != pos.w || curPos.h != pos.h || curPos.moncrc != pos.moncrc || curPos.maximized != pos.maximized) { + cSetWindowPos(curPos); + App::writeConfig(); + } + } +} + +void PsMainWindow::psUpdatedPosition() { + psUpdatedPositionTimer.start(4000); +} + +void PsMainWindow::psStateChanged(Qt::WindowState state) { + psUpdateSysMenu(state); + psUpdateMargins(); + if (state == Qt::WindowMinimized && GetWindowLong(ps_hWnd, GWL_HWNDPARENT)) { + minimizeToTray(); + } + psSavePosition(state); +} + +Q_DECLARE_METATYPE(QMargins); +void PsMainWindow::psFirstShow() { + _psShadowWindows.init(_shActive); + finished = false; + + psUpdateMargins(); + + _psShadowWindows.update(_PsShadowHidden); + bool showShadows = true; + + show(); + if (cWindowPos().maximized) { + setWindowState(Qt::WindowMaximized); + } + + if (cFromAutoStart()) { + if (cStartMinimized()) { + setWindowState(Qt::WindowMinimized); + if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { + hide(); + } else { + show(); + } + showShadows = false; + } else { + show(); + } + } else { + show(); + } + posInited = true; + if (showShadows) { + _psShadowWindows.update(_PsShadowMoved | _PsShadowResized | _PsShadowShown); + } +} + +bool PsMainWindow::psHandleTitle() { + return useDWM; +} + +void PsMainWindow::psInitSysMenu() { + Qt::WindowStates states = windowState(); + ps_menu = GetSystemMenu(ps_hWnd, FALSE); + psUpdateSysMenu(windowHandle()->windowState()); +} + +void PsMainWindow::psUpdateSysMenu(Qt::WindowState state) { + if (!ps_menu) return; + + int menuToDisable = SC_RESTORE; + if (state == Qt::WindowMaximized) { + menuToDisable = SC_MAXIMIZE; + } else if (state == Qt::WindowMinimized) { + menuToDisable = SC_MINIMIZE; + } + int itemCount = GetMenuItemCount(ps_menu); + for (int i = 0; i < itemCount; ++i) { + MENUITEMINFO itemInfo = {0}; + itemInfo.cbSize = sizeof(itemInfo); + itemInfo.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID; + if (GetMenuItemInfo(ps_menu, i, TRUE, &itemInfo)) { + if (itemInfo.fType & MFT_SEPARATOR) { + continue; + } + if (itemInfo.wID && !(itemInfo.fState & MFS_DEFAULT)) { + UINT fOldState = itemInfo.fState, fState = itemInfo.fState & ~MFS_DISABLED; + if (itemInfo.wID == SC_CLOSE) { + fState |= MFS_DEFAULT; + } else if (itemInfo.wID == menuToDisable || (itemInfo.wID != SC_MINIMIZE && itemInfo.wID != SC_MAXIMIZE && itemInfo.wID != SC_RESTORE)) { + fState |= MFS_DISABLED; + } + itemInfo.fMask = MIIM_STATE; + itemInfo.fState = fState; + if (!SetMenuItemInfo(ps_menu, i, TRUE, &itemInfo)) { + DEBUG_LOG(("PS Error: could not set state %1 to menu item %2, old state %3, error %4").arg(fState).arg(itemInfo.wID).arg(fOldState).arg(GetLastError())); + DestroyMenu(ps_menu); + ps_menu = 0; + break; + } + } + } else { + DEBUG_LOG(("PS Error: could not get state, menu item %1 of %2, error %3").arg(i).arg(itemCount).arg(GetLastError())); + DestroyMenu(ps_menu); + ps_menu = 0; + break; + } + } +} + +void PsMainWindow::psUpdateMargins() { + if (!useDWM) return; + + RECT r, a; + + GetClientRect(ps_hWnd, &r); + a = r; + + LONG style = GetWindowLong(ps_hWnd, GWL_STYLE), styleEx = GetWindowLong(ps_hWnd, GWL_EXSTYLE); + AdjustWindowRectEx(&a, style, false, styleEx); + simpleMargins = QMargins(a.left - r.left, a.top - r.top, r.right - a.right, r.bottom - a.bottom); + if (style & WS_MAXIMIZE) { + RECT w, m; + GetWindowRect(ps_hWnd, &w); + m = w; + + HMONITOR hMonitor = MonitorFromRect(&w, MONITOR_DEFAULTTONEAREST); + if (hMonitor) { + MONITORINFO mi; + mi.cbSize = sizeof(mi); + GetMonitorInfo(hMonitor, &mi); + m = mi.rcWork; + } + + dleft = w.left - m.left; + dtop = w.top - m.top; + + margins.setLeft(simpleMargins.left() - w.left + m.left); + margins.setRight(simpleMargins.right() - m.right + w.right); + margins.setBottom(simpleMargins.bottom() - m.bottom + w.bottom); + margins.setTop(simpleMargins.top() - w.top + m.top); + } else { + margins = simpleMargins; + dleft = dtop = 0; + } + + QPlatformNativeInterface *i = QGuiApplication::platformNativeInterface(); + i->setWindowProperty(windowHandle()->handle(), "WindowsCustomMargins", QVariant::fromValue(margins)); + if (!themeInited) { + themeInited = true; + if (useTheme) { + if (QSysInfo::WindowsVersion < QSysInfo::WV_WINDOWS8) { + setWindowTheme(ps_hWnd, L" ", L" "); + QApplication::setStyle(QStyleFactory::create("Windows")); + } + } + } +} + +void PsMainWindow::psFlash() { + if (GetForegroundWindow() == ps_hWnd) return; + + FLASHWINFO info; + info.cbSize = sizeof(info); + info.hwnd = ps_hWnd; + info.dwFlags = FLASHW_ALL; + info.dwTimeout = 0; + info.uCount = 1; + FlashWindowEx(&info); +} + +HWND PsMainWindow::psHwnd() const { + return ps_hWnd; +} + +HMENU PsMainWindow::psMenu() const { + return ps_menu; +} + +void PsMainWindow::psDestroyIcons() { + if (ps_iconBig) { + DestroyIcon(ps_iconBig); + ps_iconBig = 0; + } + if (ps_iconSmall) { + DestroyIcon(ps_iconSmall); + ps_iconSmall = 0; + } + if (ps_iconOverlay) { + DestroyIcon(ps_iconOverlay); + ps_iconOverlay = 0; + } +} + +PsMainWindow::~PsMainWindow() { + finished = true; + if (ps_menu) DestroyMenu(ps_menu); + psDestroyIcons(); + _psShadowWindows.destroy(); + psClearNotifyFast(); + if (ps_tbHider_hWnd) DestroyWindow(ps_tbHider_hWnd); +} + +void PsMainWindow::psNotify(History *history, MsgId msgId) { + if (App::quiting() || !history->notifyFrom) return; + + bool haveSetting = (history->peer->notify != UnknownNotifySettings); + if (haveSetting) { + if (history->peer->notify != EmptyNotifySettings && history->peer->notify->mute > unixtime()) { + history->clearNotifyFrom(); + return; + } + } else { + App::wnd()->getNotifySetting(MTP_inputNotifyPeer(history->peer->input)); + } + + uint64 ms = getms() + NotifyWaitTimeout; + notifyWhenAlerts[history].insert(ms); + if (cDesktopNotify()) { + NotifyWhenMaps::iterator i = notifyWhenMaps.find(history); + if (i == notifyWhenMaps.end()) { + i = notifyWhenMaps.insert(history, NotifyWhenMap()); + } + if (i.value().constFind(msgId) == i.value().cend()) { + i.value().insert(msgId, ms); + } + NotifyWaiters *addTo = haveSetting ? ¬ifyWaiters : ¬ifySettingWaiters; + if (addTo->constFind(history) == addTo->cend()) { + addTo->insert(history, NotifyWaiter(msgId, ms)); + } + } + if (haveSetting) { + if (!notifyWaitTimer.isActive()) { + notifyWaitTimer.start(NotifyWaitTimeout); + } + } +} + +void PsMainWindow::psNotifyFire() { + psShowNextNotify(); +} + +void PsMainWindow::psNotifySettingGot() { + int32 t = unixtime(); + for (NotifyWaiters::iterator i = notifySettingWaiters.begin(); i != notifySettingWaiters.end();) { + History *history = i.key(); + if (history->peer->notify == UnknownNotifySettings) { + ++i; + } else { + if (history->peer->notify == EmptyNotifySettings || history->peer->notify->mute <= t) { + notifyWaiters.insert(i.key(), i.value()); + } + i = notifySettingWaiters.erase(i); + } + } + notifyWaitTimer.stop(); + psShowNextNotify(); +} + +void PsMainWindow::psClearNotify(History *history) { + if (!history) { + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + (*i)->unlinkHistory(); + } + for (NotifyWhenMaps::const_iterator i = notifyWhenMaps.cbegin(), e = notifyWhenMaps.cend(); i != e; ++i) { + i.key()->clearNotifyFrom(); + } + notifyWaiters.clear(); + notifySettingWaiters.clear(); + notifyWhenMaps.clear(); + return; + } + notifyWaiters.remove(history); + notifySettingWaiters.remove(history); + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + (*i)->unlinkHistory(history); + } + notifyWhenMaps.remove(history); + notifyWhenAlerts.remove(history); +} + +void PsMainWindow::psClearNotifyFast() { + notifyWaiters.clear(); + notifySettingWaiters.clear(); + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + (*i)->deleteLater(); + } + notifyWindows.clear(); + notifyWhenMaps.clear(); + notifyWhenAlerts.clear(); +} + +// QApplication::desktop()->availableGeometry(App::wnd()) works not very fine, returns not nearest +namespace { + //RECT _monitorRECT; + QRect _monitorRect; + //uint32 _monitorDelta; + //int32 _wndX, _wndY; + uint64 _monitorLastGot = 0; + + //BOOL CALLBACK _monitorRectProc( + //_In_ HMONITOR hMonitor, + //_In_ HDC hdcMonitor, + //_In_ LPRECT lprcMonitor, + //_In_ LPARAM dwData + //) { + // MONITORINFOEX info; + // info.cbSize = sizeof(info); + // GetMonitorInfo(hMonitor, &info); + // int32 centerx = (info.rcWork.right + info.rcWork.left) / 2, centery = (info.rcWork.bottom + info.rcWork.top) / 2; + // uint32 delta = (info.rcWork.right > _wndX && info.rcWork.left <= _wndX && info.rcWork.bottom > _wndY && info.rcWork.top <= _wndY) ? 0 : ((centerx - _wndX) * (centerx - _wndX) + (centery - _wndY) * (centery - _wndY)); + // if (delta < _monitorDelta) { + // _monitorDelta = delta; + // _monitorRECT = info.rcWork; + // } + // return !!delta; + //} + QRect _desktopRect() { + uint64 tnow = getms(); + if (tnow > _monitorLastGot + 1000 || tnow < _monitorLastGot) { + _monitorLastGot = tnow; + //RECT r; + //GetWindowRect(App::wnd()->psHwnd(), &r); + //_wndX = (r.right + r.left) / 2; + //_wndY = (r.bottom + r.top) / 2; + //_monitorDelta = INT_MAX; + //EnumDisplayMonitors(0, 0, &_monitorRectProc, 0); + //_monitorRect = (_monitorDelta < INT_MAX) ? QRect(_monitorRECT.left, _monitorRECT.top, _monitorRECT.right - _monitorRECT.left, _monitorRECT.bottom - _monitorRECT.top) : QApplication::desktop()->availableGeometry(App::wnd()); + HMONITOR hMonitor = MonitorFromWindow(App::wnd()->psHwnd(), MONITOR_DEFAULTTONEAREST); + if (hMonitor) { + MONITORINFOEX info; + info.cbSize = sizeof(info); + GetMonitorInfo(hMonitor, &info); + _monitorRect = QRect(info.rcWork.left, info.rcWork.top, info.rcWork.right - info.rcWork.left, info.rcWork.bottom - info.rcWork.top); + } else { + _monitorRect = QApplication::desktop()->availableGeometry(App::wnd()); + } + } + return _monitorRect; + } +} + +void PsMainWindow::psShowNextNotify(PsNotifyWindow *remove) { + if (App::quiting()) return; + + int32 count = NotifyWindows; + if (remove) { + for (PsNotifyWindows::iterator i = notifyWindows.begin(), e = notifyWindows.end(); i != e; ++i) { + if ((*i) == remove) { + notifyWindows.erase(i); + break; + } + } + } + + uint64 ms = getms(), nextAlert = 0; + bool alert = false; + for (NotifyWhenAlerts::iterator i = notifyWhenAlerts.begin(); i != notifyWhenAlerts.end();) { + while (!i.value().isEmpty() && *i.value().begin() <= ms) { + i.value().erase(i.value().begin()); + NotifySettingsPtr n = i.key()->peer->notify; + if (n == EmptyNotifySettings || n != UnknownNotifySettings && n->mute <= unixtime()) { + alert = true; + } + } + if (i.value().isEmpty()) { + i = notifyWhenAlerts.erase(i); + } else { + if (!nextAlert || nextAlert > *i.value().begin()) { + nextAlert = *i.value().begin(); + } + ++i; + } + } + if (alert) { + psFlash(); + App::playSound(); + } + + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + int32 ind = (*i)->index(); + if (ind < 0) continue; + --count; + } + if (count <= 0 || !cDesktopNotify()) { + if (nextAlert) { + notifyWaitTimer.start(nextAlert - ms); + } + return; + } + + QRect r = _desktopRect(); + int32 x = r.x() + r.width() - st::notifyWidth - st::notifyDeltaX, y = r.y() + r.height() - st::notifyHeight - st::notifyDeltaY; + while (count > 0) { + uint64 next = 0; + HistoryItem *notifyItem = 0; + NotifyWaiters::iterator notifyWaiter; + for (NotifyWaiters::iterator i = notifyWaiters.begin(); i != notifyWaiters.end(); ++i) { + History *history = i.key(); + if (history->notifyFrom && history->notifyFrom->id != i.value().msg) { + NotifyWhenMaps::iterator j = notifyWhenMaps.find(history); + if (j == notifyWhenMaps.end()) { + history->clearNotifyFrom(); + i = notifyWaiters.erase(i); + continue; + } + do { + NotifyWhenMap::const_iterator k = j.value().constFind(history->notifyFrom->id); + if (k != j.value().cend()) { + i.value().msg = k.key(); + i.value().when = k.value(); + break; + } + history->getNextNotifyFrom(); + } while (history->notifyFrom); + } + if (!history->notifyFrom) { + notifyWhenMaps.remove(history); + i = notifyWaiters.erase(i); + continue; + } + uint64 when = i.value().when; + if (!notifyItem || next > when) { + next = when; + notifyItem = history->notifyFrom; + notifyWaiter = i; + } + } + if (notifyItem) { + if (next > ms) { + if (nextAlert && nextAlert < next) { + next = nextAlert; + nextAlert = 0; + } + notifyWaitTimer.start(next - ms); + break; + } else { + notifyWindows.push_back(new PsNotifyWindow(notifyItem, x, y)); + --count; + + uint64 ms = getms(); + History *history = notifyItem->history(); + history->getNextNotifyFrom(); + NotifyWhenMaps::iterator j = notifyWhenMaps.find(history); + if (j == notifyWhenMaps.end() || !history->notifyFrom) { + history->clearNotifyFrom(); + notifyWaiters.erase(notifyWaiter); + if (j != notifyWhenMaps.end()) notifyWhenMaps.erase(j); + continue; + } + j.value().remove(notifyItem->id); + do { + NotifyWhenMap::const_iterator k = j.value().constFind(history->notifyFrom->id); + if (k != j.value().cend()) { + notifyWaiter.value().msg = k.key(); + notifyWaiter.value().when = k.value(); + break; + } + history->getNextNotifyFrom(); + } while (history->notifyFrom); + if (!history->notifyFrom) { + notifyWaiters.erase(notifyWaiter); + notifyWhenMaps.erase(j); + continue; + } + } + } else { + break; + } + } + if (nextAlert) { + notifyWaitTimer.start(nextAlert - ms); + } + + count = NotifyWindows - count; + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + int32 ind = (*i)->index(); + if (ind < 0) continue; + --count; + (*i)->moveTo(x, y - count * (st::notifyHeight + st::notifyDeltaY)); + } +} + +void PsMainWindow::psStopHiding() { + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + (*i)->stopHiding(); + } +} + +void PsMainWindow::psStartHiding() { + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + (*i)->startHiding(); + } +} + +void PsMainWindow::psUpdateNotifies() { + for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { + (*i)->updatePeerPhoto(); + } +} + +PsNotifyWindow::PsNotifyWindow(HistoryItem *item, int32 x, int32 y) : history(item->history()), aOpacity(0), _index(0), hiding(false), started(GetTickCount()), + alphaDuration(st::notifyFastAnim), posDuration(st::notifyFastAnim), aY(y + st::notifyHeight + st::notifyDeltaY), close(this, st::notifyClose), aOpacityFunc(st::notifyFastAnimFunc) { + + int32 w = st::notifyWidth, h = st::notifyHeight; + QImage img(w, h, QImage::Format_ARGB32_Premultiplied); + img.fill(st::notifyBG->c); + + { + QPainter p(&img); + p.setPen(st::notifyBorder->p); + p.setBrush(Qt::NoBrush); + p.drawRect(0, 0, w - 1, h - 1); + + if (history->peer->photo->loaded()) { + p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), history->peer->photo->pix(st::notifyPhotoSize)); + } else { + MTP::clearLoaderPriorities(); + peerPhoto = history->peer->photo; + peerPhoto->load(true, true); + } + + int32 itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width; + + QRect rectForName(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height); + if (history->peer->chat) { + p.drawPixmap(QPoint(rectForName.left() + st::dlgChatImgLeft, rectForName.top() + st::dlgChatImgTop), App::sprite(), st::dlgChatImg); + rectForName.setLeft(rectForName.left() + st::dlgChatImgSkip); + } + + QDateTime now(QDateTime::currentDateTime()), lastTime(item->date); + QDate nowDate(now.date()), lastDate(lastTime.date()); + QString dt = lastTime.toString(qsl("hh:mm")); + int32 dtWidth = st::dlgHistFont->m.width(dt); + rectForName.setWidth(rectForName.width() - dtWidth - st::dlgDateSkip); + p.setFont(st::dlgDateFont->f); + p.setPen(st::dlgDateColor->p); + p.drawText(rectForName.left() + rectForName.width() + st::dlgDateSkip, rectForName.top() + st::dlgHistFont->ascent, dt); + + const HistoryItem *textCachedFor = 0; + Text itemTextCache(itemWidth); + bool active = false; + item->drawInDialog(p, QRect(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dlgFont->height), active, textCachedFor, itemTextCache); + + p.setPen(st::dlgNameColor->p); + history->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); + } + pm = QPixmap::fromImage(img); + + hideTimer.setSingleShot(true); + connect(&hideTimer, SIGNAL(timeout()), this, SLOT(hideByTimer())); + + inputTimer.setSingleShot(true); + connect(&inputTimer, SIGNAL(timeout()), this, SLOT(checkLastInput())); + + connect(&close, SIGNAL(clicked()), this, SLOT(unlinkHistory())); + close.setAcceptBoth(true); + close.move(w - st::notifyClose.width - st::notifyClosePos.x(), st::notifyClosePos.y()); + close.show(); + + aY.start(y); + setGeometry(x, aY.current(), st::notifyWidth, st::notifyHeight); + + aOpacity.start(1); + setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint); + + show(); + + setWindowOpacity(aOpacity.current()); + + alphaDuration = posDuration = st::notifyFastAnim; + anim::start(this); + + checkLastInput(); +} + +void PsNotifyWindow::checkLastInput() { + LASTINPUTINFO lii; + lii.cbSize = sizeof(LASTINPUTINFO); + BOOL res = GetLastInputInfo(&lii); + if (!res || lii.dwTime >= started) { + hideTimer.start(st::notifyWaitLongHide); + } else { + inputTimer.start(300); + } +} + +void PsNotifyWindow::moveTo(int32 x, int32 y, int32 index) { + if (index >= 0) { + _index = index; + } + move(x, aY.current()); + aY.start(y); + aOpacity.restart(); + posDuration = st::notifyFastAnim; + anim::start(this); +} + +void PsNotifyWindow::updatePeerPhoto() { + if (!peerPhoto->isNull() && peerPhoto->loaded()) { + QImage img(pm.toImage()); + { + QPainter p(&img); + p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), peerPhoto->pix(st::notifyPhotoSize)); + } + peerPhoto = ImagePtr(); + pm = QPixmap::fromImage(img); + update(); + } +} + +void PsNotifyWindow::unlinkHistory(History *hist) { + if (!hist || hist == history) { + animHide(st::notifyFastAnim, st::notifyFastAnimFunc); + history = 0; + App::wnd()->psShowNextNotify(); + } +} + +void PsNotifyWindow::enterEvent(QEvent *e) { + if (!history) return; + if (App::wnd()) App::wnd()->psStopHiding(); +} + +void PsNotifyWindow::leaveEvent(QEvent *e) { + if (!history) return; + App::wnd()->psStartHiding(); +} + +void PsNotifyWindow::startHiding() { + hideTimer.start(st::notifyWaitShortHide); +} + +void PsNotifyWindow::mousePressEvent(QMouseEvent *e) { + if (!history) return; + if (e->button() == Qt::RightButton) { + unlinkHistory(); + } else if (history) { + App::wnd()->showFromTray(); + App::wnd()->hideSettings(); + App::main()->showPeer(history->peer->id, false, true); + e->ignore(); + } +} + +void PsNotifyWindow::paintEvent(QPaintEvent *e) { + QPainter p(this); + p.drawPixmap(0, 0, pm); +} + +void PsNotifyWindow::animHide(float64 duration, anim::transition func) { + if (!history) return; + alphaDuration = duration; + aOpacityFunc = func; + aOpacity.start(0); + aY.restart(); + hiding = true; + anim::start(this); +} + +void PsNotifyWindow::stopHiding() { + if (!history) return; + alphaDuration = st::notifyFastAnim; + aOpacityFunc = st::notifyFastAnimFunc; + aOpacity.start(1); + aY.restart(); + hiding = false; + hideTimer.stop(); + anim::start(this); +} + +void PsNotifyWindow::hideByTimer() { + if (!history) return; + animHide(st::notifySlowHide, st::notifySlowHideFunc); +} + +bool PsNotifyWindow::animStep(float64 ms) { + float64 dtAlpha = ms / alphaDuration, dtPos = ms / posDuration; + if (dtAlpha >= 1) { + aOpacity.finish(); + if (hiding) { + deleteLater(); + } + } else { + aOpacity.update(dtAlpha, aOpacityFunc); + } + setWindowOpacity(aOpacity.current()); + if (dtPos >= 1) { + aY.finish(); + } else { + aY.update(dtPos, anim::linear); + } + move(x(), aY.current()); + update(); + return (dtAlpha < 1 || !hiding && dtPos < 1); +} + +PsNotifyWindow::~PsNotifyWindow() { + if (App::wnd()) App::wnd()->psShowNextNotify(this); +} + +PsApplication::PsApplication(int argc, char *argv[]) : QApplication(argc, argv) { +} + +void PsApplication::psInstallEventFilter() { + delete _psEventFilter; + _psEventFilter = new _PsEventFilter(); + installNativeEventFilter(_psEventFilter); +} + +PsApplication::~PsApplication() { + delete _psEventFilter; + _psEventFilter = 0; +} + +PsUpdateDownloader::PsUpdateDownloader(QThread *thread, const MTPDhelp_appUpdate &update) : already(0), reply(0), full(0) { + updateUrl = qs(update.vurl); + moveToThread(thread); + manager.moveToThread(thread); + App::setProxySettings(manager); + + connect(thread, SIGNAL(started()), this, SLOT(start())); + initOutput(); +} + +PsUpdateDownloader::PsUpdateDownloader(QThread *thread, const QString &url) : already(0), reply(0), full(0) { + updateUrl = url; + moveToThread(thread); + manager.moveToThread(thread); + App::setProxySettings(manager); + + connect(thread, SIGNAL(started()), this, SLOT(start())); + initOutput(); +} + +void PsUpdateDownloader::initOutput() { + QString fileName; + QRegularExpressionMatch m = QRegularExpression(qsl("/([^/\\?]+)(\\?|$)")).match(updateUrl); + if (m.hasMatch()) { + fileName = m.captured(1).replace(QRegularExpression(qsl("[^a-zA-Z0-9_\\-]")), QString()); + } + if (fileName.isEmpty()) { + fileName = qsl("tupdate-%1").arg(rand()); + } + QString dirStr = cWorkingDir() + qsl("tupdates/"); + fileName = dirStr + fileName; + QFileInfo file(fileName); + + QDir dir(dirStr); + if (dir.exists()) { + QFileInfoList all = dir.entryInfoList(QDir::Files); + for (QFileInfoList::iterator i = all.begin(), e = all.end(); i != e; ++i) { + if (i->absoluteFilePath() != file.absoluteFilePath()) { + QFile::remove(i->absoluteFilePath()); + } + } + } else { + dir.mkdir(dir.absolutePath()); + } + outputFile.setFileName(fileName); + if (file.exists()) { + uint64 fullSize = file.size(); + if (fullSize < INT_MAX) { + int32 goodSize = (int32)fullSize; + if (goodSize % UpdateChunk) { + goodSize = goodSize - (goodSize % UpdateChunk); + if (goodSize) { + if (outputFile.open(QIODevice::ReadOnly)) { + QByteArray goodData = outputFile.readAll().mid(0, goodSize); + outputFile.close(); + if (outputFile.open(QIODevice::WriteOnly)) { + outputFile.write(goodData); + outputFile.close(); + + QMutexLocker lock(&mutex); + already = goodSize; + } + } + } + } else { + QMutexLocker lock(&mutex); + already = goodSize; + } + } + if (!already) { + QFile::remove(fileName); + } + } +} + +void PsUpdateDownloader::start() { + sendRequest(); +} + +void PsUpdateDownloader::sendRequest() { + QNetworkRequest req(updateUrl); + QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(already) + "-";// + QByteArray::number(already + cUpdateChunk() - 1); + req.setRawHeader("Range", rangeHeaderValue); + req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); + if (reply) reply->deleteLater(); + reply = manager.get(req); + connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(partFinished(qint64,qint64))); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(partFailed(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(metaDataChanged()), this, SLOT(partMetaGot())); +} + +void PsUpdateDownloader::partMetaGot() { + typedef QList Pairs; + Pairs pairs = reply->rawHeaderPairs(); + for (Pairs::iterator i = pairs.begin(), e = pairs.end(); i != e; ++i) { + if (QString::fromUtf8(i->first).toLower() == "content-range") { + QRegularExpressionMatch m = QRegularExpression(qsl("/(\\d+)([^\\d]|$)")).match(QString::fromUtf8(i->second)); + if (m.hasMatch()) { + { + QMutexLocker lock(&mutex); + full = m.captured(1).toInt(); + } + emit App::app()->updateDownloading(already, full); + } + } + } +} + +int32 PsUpdateDownloader::ready() { + QMutexLocker lock(&mutex); + return already; +} + +int32 PsUpdateDownloader::size() { + QMutexLocker lock(&mutex); + return full; +} + +void PsUpdateDownloader::partFinished(qint64 got, qint64 total) { + if (!reply) return; + + QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + if (statusCode.isValid()) { + int status = statusCode.toInt(); + if (status != 200 && status != 206 && status != 416) { + LOG(("Update Error: Bad HTTP status received in partFinished(): %1").arg(status)); + return fatalFail(); + } + } + + if (!already && !full) { + QMutexLocker lock(&mutex); + full = total; + } + DEBUG_LOG(("Update Info: part %1 of %2").arg(got).arg(total)); + + if (!outputFile.isOpen()) { + if (!outputFile.open(QIODevice::Append)) { + LOG(("Update Error: Could not open output file '%1' for appending").arg(outputFile.fileName())); + return fatalFail(); + } + } + QByteArray r = reply->readAll(); + if (!r.isEmpty()) { + outputFile.write(r); + + QMutexLocker lock(&mutex); + already += r.size(); + } + if (got >= total) { + reply->deleteLater(); + reply = 0; + outputFile.close(); + unpackUpdate(); + } else { + emit App::app()->updateDownloading(already, full); + } +} + +void PsUpdateDownloader::partFailed(QNetworkReply::NetworkError e) { + if (!reply) return; + + QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + reply->deleteLater(); + reply = 0; + if (statusCode.isValid()) { + int status = statusCode.toInt(); + if (status == 416) { // Requested range not satisfiable + outputFile.close(); + unpackUpdate(); + return; + } + } + LOG(("Update Error: failed to download part starting from %1, error %2").arg(already).arg(e)); + emit App::app()->updateFailed(); +} + +void PsUpdateDownloader::deleteDir(const QString &dir) { + std::wstring wDir = QDir::toNativeSeparators(dir).toStdWString(); + WCHAR path[4096]; + memcpy(path, wDir.c_str(), (wDir.size() + 1) * sizeof(WCHAR)); + path[wDir.size() + 1] = 0; + SHFILEOPSTRUCT file_op = { + NULL, + FO_DELETE, + path, + L"", + FOF_NOCONFIRMATION | + FOF_NOERRORUI | + FOF_SILENT, + false, + 0, + L"" + }; + int res = SHFileOperation(&file_op); +} + +void PsUpdateDownloader::fatalFail() { + clearAll(); + emit App::app()->updateFailed(); +} + +void PsUpdateDownloader::clearAll() { + deleteDir(cWorkingDir() + qsl("tupdates")); +} + +void PsUpdateDownloader::unpackUpdate() { + QByteArray packed; + if (!outputFile.open(QIODevice::ReadOnly)) { + LOG(("Update Error: cant read updates file!")); + return fatalFail(); + } + + const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header + + QByteArray compressed = outputFile.readAll(); + int32 compressedLen = compressed.size() - hSize; + if (compressedLen <= 0) { + LOG(("Update Error: bad compressed size: %1").arg(compressed.size())); + return fatalFail(); + } + outputFile.close(); + + QString tempDirPath = cWorkingDir() + qsl("tupdates/temp"), readyDirPath = cWorkingDir() + qsl("tupdates/ready"); + deleteDir(tempDirPath); + deleteDir(readyDirPath); + + QDir tempDir(tempDirPath), readyDir(readyDirPath); + if (tempDir.exists() || readyDir.exists()) { + LOG(("Update Error: cant clear tupdates/temp or tupdates/ready dir!")); + return fatalFail(); + } + + uchar sha1Buffer[20]; + bool goodSha1 = !memcmp(compressed.constData() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen); + if (!goodSha1) { + LOG(("Update Error: bad SHA1 hash of update file!")); + return fatalFail(); + } + + RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast(UpdatesPublicKey), -1), 0, 0, 0); + if (!pbKey) { + LOG(("Update Error: cant read public rsa key!")); + return fatalFail(); + } + if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature + RSA_free(pbKey); + LOG(("Update Error: bad RSA signature of update file!")); + return fatalFail(); + } + RSA_free(pbKey); + + QByteArray uncompressed; + + int32 uncompressedLen; + memcpy(&uncompressedLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen); + uncompressed.resize(uncompressedLen); + + size_t resultLen = uncompressed.size(); + SizeT srcLen = compressedLen; + int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); + if (uncompressRes != SZ_OK) { + LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes)); + return fatalFail(); + } + + tempDir.mkdir(tempDir.absolutePath()); + + quint32 version; + { + QBuffer buffer(&uncompressed); + buffer.open(QIODevice::ReadOnly); + QDataStream stream(&buffer); + stream.setVersion(QDataStream::Qt_5_1); + + stream >> version; + if (stream.status() != QDataStream::Ok) { + LOG(("Update Error: cant read version from downloaded stream, status: %1").arg(stream.status())); + return fatalFail(); + } + if (version <= AppVersion) { + LOG(("Update Error: downloaded version %1 is not greater, than mine %2").arg(version).arg(AppVersion)); + return fatalFail(); + } + + quint32 filesCount; + stream >> filesCount; + if (stream.status() != QDataStream::Ok) { + LOG(("Update Error: cant read files count from downloaded stream, status: %1").arg(stream.status())); + return fatalFail(); + } + if (!filesCount) { + LOG(("Update Error: update is empty!")); + return fatalFail(); + } + for (int32 i = 0; i < filesCount; ++i) { + QString relativeName; + quint32 fileSize; + QByteArray fileInnerData; + + stream >> relativeName >> fileSize >> fileInnerData; + if (stream.status() != QDataStream::Ok) { + LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status())); + return fatalFail(); + } + if (fileSize != fileInnerData.size()) { + LOG(("Update Error: bad file size %1 not matching data size %2").arg(fileSize).arg(fileInnerData.size())); + return fatalFail(); + } + + QFile f(tempDirPath + '/' + relativeName); + if (!f.open(QIODevice::WriteOnly)) { + LOG(("Update Error: cant open file '%1' for writing").arg(tempDirPath + '/' + relativeName)); + return fatalFail(); + } + if (f.write(fileInnerData) != fileSize) { + f.close(); + LOG(("Update Error: cant write file '%1'").arg(tempDirPath + '/' + relativeName)); + return fatalFail(); + } + f.close(); + } + + // create tdata/version file + tempDir.mkdir(QDir(tempDirPath + qsl("/tdata")).absolutePath()); + std::wstring versionString = ((version % 1000) ? QString("%1.%2.%3").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000)).arg(int(version % 1000)) : QString("%1.%2").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000))).toStdWString(); + DWORD versionNum = DWORD(version), versionLen = DWORD(versionString.size() * sizeof(WCHAR)); + WCHAR versionStr[32]; + memcpy(versionStr, versionString.c_str(), versionLen); + + QFile fVersion(tempDirPath + qsl("/tdata/version")); + if (!fVersion.open(QIODevice::WriteOnly)) { + LOG(("Update Error: cant write version file '%1'").arg(tempDirPath + qsl("/version"))); + return fatalFail(); + } + fVersion.write((const char*)&versionNum, sizeof(DWORD)); + fVersion.write((const char*)&versionLen, sizeof(DWORD)); + fVersion.write((const char*)&versionStr[0], versionLen); + fVersion.close(); + } + + if (!tempDir.rename(tempDir.absolutePath(), readyDir.absolutePath())) { + LOG(("Update Error: cant rename temp dir '%1' to ready dir '%2'").arg(tempDir.absolutePath()).arg(readyDir.absolutePath())); + return fatalFail(); + } + deleteDir(tempDirPath); + outputFile.remove(); + + emit App::app()->updateReady(); +} + +PsUpdateDownloader::~PsUpdateDownloader() { + delete reply; + reply = 0; +} + +namespace { + BOOL CALLBACK _ActivateProcess(HWND hWnd, LPARAM lParam) { + uint64 &processId(*(uint64*)lParam); + + DWORD dwProcessId; + ::GetWindowThreadProcessId(hWnd, &dwProcessId); + + if ((uint64)dwProcessId == processId) { // found top-level window + static const int32 nameBufSize = 1024; + WCHAR nameBuf[nameBufSize]; + int32 len = GetWindowText(hWnd, nameBuf, nameBufSize); + if (len && len < nameBufSize) { + if (QRegularExpression(qsl("^Telegram(\\s*\\(\\d+\\))?$")).match(QString::fromStdWString(nameBuf)).hasMatch()) { + BOOL res = ::SetForegroundWindow(hWnd); + return FALSE; + } + } + } + return TRUE; + } +} + +void psActivateProcess(uint64 pid) { + ::EnumWindows((WNDENUMPROC)_ActivateProcess, (LPARAM)&pid); +} + +QString psCurrentCountry() { + int chCount = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, 0, 0); + if (chCount && chCount < 128) { + WCHAR wstrCountry[128]; + int len = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, wstrCountry, chCount); + return len ? QString::fromStdWString(std::wstring(wstrCountry)) : QString::fromLatin1(DefaultCountry); + } + return QString::fromLatin1(DefaultCountry); +} + +namespace { + QString langById(int lngId) { + int primary = lngId & 0xFF; + switch (primary) { + case 0x36: return qsl("af"); + case 0x1C: return qsl("sq"); + case 0x5E: return qsl("am"); + case 0x01: return qsl("ar"); + case 0x2B: return qsl("hy"); + case 0x4D: return qsl("as"); + case 0x2C: return qsl("az"); + case 0x45: return qsl("bn"); + case 0x6D: return qsl("ba"); + case 0x2D: return qsl("eu"); + case 0x23: return qsl("be"); + case 0x1A: + if (lngId == LANG_CROATIAN) { + return qsl("hr"); + } else if (lngId == LANG_BOSNIAN_NEUTRAL || lngId == LANG_BOSNIAN) { + return qsl("bs"); + } + return qsl("sr"); + break; + case 0x7E: return qsl("br"); + case 0x02: return qsl("bg"); + case 0x92: return qsl("ku"); + case 0x03: return qsl("ca"); + case 0x04: return qsl("zh"); + case 0x83: return qsl("co"); + case 0x05: return qsl("cs"); + case 0x06: return qsl("da"); + case 0x65: return qsl("dv"); + case 0x13: return qsl("nl"); + case 0x09: return qsl("en"); + case 0x25: return qsl("et"); + case 0x38: return qsl("fo"); + case 0x0B: return qsl("fi"); + case 0x0c: return qsl("fr"); + case 0x62: return qsl("fy"); + case 0x56: return qsl("gl"); + case 0x37: return qsl("ka"); + case 0x07: return qsl("de"); + case 0x08: return qsl("el"); + case 0x6F: return qsl("kl"); + case 0x47: return qsl("gu"); + case 0x68: return qsl("ha"); + case 0x0D: return qsl("he"); + case 0x39: return qsl("hi"); + case 0x0E: return qsl("hu"); + case 0x0F: return qsl("is"); + case 0x70: return qsl("ig"); + case 0x21: return qsl("id"); + case 0x5D: return qsl("iu"); + case 0x3C: return qsl("ga"); + case 0x34: return qsl("xh"); + case 0x35: return qsl("zu"); + case 0x10: return qsl("it"); + case 0x11: return qsl("ja"); + case 0x4B: return qsl("kn"); + case 0x3F: return qsl("kk"); + case 0x53: return qsl("kh"); + case 0x87: return qsl("rw"); + case 0x12: return qsl("ko"); + case 0x40: return qsl("ky"); + case 0x54: return qsl("lo"); + case 0x26: return qsl("lv"); + case 0x27: return qsl("lt"); + case 0x6E: return qsl("lb"); + case 0x2F: return qsl("mk"); + case 0x3E: return qsl("ms"); + case 0x4C: return qsl("ml"); + case 0x3A: return qsl("mt"); + case 0x81: return qsl("mi"); + case 0x4E: return qsl("mr"); + case 0x50: return qsl("mn"); + case 0x61: return qsl("ne"); + case 0x14: return qsl("no"); + case 0x82: return qsl("oc"); + case 0x48: return qsl("or"); + case 0x63: return qsl("ps"); + case 0x29: return qsl("fa"); + case 0x15: return qsl("pl"); + case 0x16: return qsl("pt"); + case 0x67: return qsl("ff"); + case 0x46: return qsl("pa"); + case 0x18: return qsl("ro"); + case 0x17: return qsl("rm"); + case 0x19: return qsl("ru"); + case 0x3B: return qsl("se"); + case 0x4F: return qsl("sa"); + case 0x32: return qsl("tn"); + case 0x59: return qsl("sd"); + case 0x5B: return qsl("si"); + case 0x1B: return qsl("sk"); + case 0x24: return qsl("sl"); + case 0x0A: return qsl("es"); + case 0x41: return qsl("sw"); + case 0x1D: return qsl("sv"); + case 0x28: return qsl("tg"); + case 0x49: return qsl("ta"); + case 0x44: return qsl("tt"); + case 0x4A: return qsl("te"); + case 0x1E: return qsl("th"); + case 0x51: return qsl("bo"); + case 0x73: return qsl("ti"); + case 0x1F: return qsl("tr"); + case 0x42: return qsl("tk"); + case 0x22: return qsl("uk"); + case 0x20: return qsl("ur"); + case 0x80: return qsl("ug"); + case 0x43: return qsl("uz"); + case 0x2A: return qsl("vi"); + case 0x52: return qsl("cy"); + case 0x88: return qsl("wo"); + case 0x78: return qsl("ii"); + case 0x6A: return qsl("yo"); + } + return QString::fromLatin1(DefaultLanguage); + } +} + +QString psCurrentLanguage() { + int chCount = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNAME, 0, 0); + if (chCount && chCount < 128) { + WCHAR wstrLocale[128]; + int len = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNAME, wstrLocale, chCount); + if (!len) return QString::fromLatin1(DefaultLanguage); + QString locale = QString::fromStdWString(std::wstring(wstrLocale)); + QRegularExpressionMatch m = QRegularExpression("(^|[^a-z])([a-z]{2})-").match(locale); + if (m.hasMatch()) { + return m.captured(2); + } + } + chCount = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, 0, 0); + if (chCount && chCount < 128) { + WCHAR wstrLocale[128]; + int len = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, wstrLocale, chCount), lngId = 0; + if (len < 5) return QString::fromLatin1(DefaultLanguage); + + for (int i = 0; i < 4; ++i) { + WCHAR ch = wstrLocale[i]; + lngId *= 16; + if (ch >= WCHAR('0') && ch <= WCHAR('9')) { + lngId += (ch - WCHAR('0')); + } else if (ch >= WCHAR('A') && ch <= WCHAR('F')) { + lngId += (10 + ch - WCHAR('A')); + } else { + return QString::fromLatin1(DefaultLanguage); + } + } + return langById(lngId); + } + return QString::fromLatin1(DefaultLanguage); +} + +QString psAppDataPath() { + static const int maxFileLen = MAX_PATH * 10; + WCHAR wstrPath[maxFileLen]; + if (GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen)) { + QDir appData(QString::fromStdWString(std::wstring(wstrPath))); + return appData.absolutePath() + "/" + QString::fromWCharArray(AppName) + "/"; + } + return QString(); +} + +QString psCurrentExeDirectory() { + LPWSTR *args; + int argsCount; + args = CommandLineToArgvW(GetCommandLine(), &argsCount); + if (args) { + QFileInfo info(QDir::fromNativeSeparators(QString::fromWCharArray(args[0]))); + if (info.isFile()) { + return info.absoluteDir().absolutePath() + '/'; + } + LocalFree(args); + } + return QString(); +} + +void psDoCleanup() { + try { + psAutoStart(false, true); + } catch (...) { + } +} + +int psCleanup() { + __try + { + psDoCleanup(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return 0; + } + return 0; +} + +void psDoFixPrevious() { + try { + static const int bufSize = 4096; + DWORD checkType, checkSize = bufSize * 2; + WCHAR checkStr[bufSize]; + + QString appId = QString::fromStdWString(AppId); + QString newKeyStr1 = QString("Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%1_is1").arg(appId); + QString newKeyStr2 = QString("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%1_is1").arg(appId); + QString oldKeyStr1 = QString("SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%1_is1").arg(appId); + QString oldKeyStr2 = QString("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%1_is1").arg(appId); + HKEY newKey1, newKey2, oldKey1, oldKey2; + LSTATUS newKeyRes1 = RegOpenKeyEx(HKEY_CURRENT_USER, newKeyStr1.toStdWString().c_str(), 0, KEY_READ, &newKey1); + LSTATUS newKeyRes2 = RegOpenKeyEx(HKEY_CURRENT_USER, newKeyStr2.toStdWString().c_str(), 0, KEY_READ, &newKey2); + LSTATUS oldKeyRes1 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, oldKeyStr1.toStdWString().c_str(), 0, KEY_READ, &oldKey1); + LSTATUS oldKeyRes2 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, oldKeyStr2.toStdWString().c_str(), 0, KEY_READ, &oldKey2); + + bool existNew1 = (newKeyRes1 == ERROR_SUCCESS) && (RegQueryValueEx(newKey1, L"InstallDate", 0, &checkType, (BYTE*)checkStr, &checkSize) == ERROR_SUCCESS); checkSize = bufSize * 2; + bool existNew2 = (newKeyRes2 == ERROR_SUCCESS) && (RegQueryValueEx(newKey2, L"InstallDate", 0, &checkType, (BYTE*)checkStr, &checkSize) == ERROR_SUCCESS); checkSize = bufSize * 2; + bool existOld1 = (oldKeyRes1 == ERROR_SUCCESS) && (RegQueryValueEx(oldKey1, L"InstallDate", 0, &checkType, (BYTE*)checkStr, &checkSize) == ERROR_SUCCESS); checkSize = bufSize * 2; + bool existOld2 = (oldKeyRes2 == ERROR_SUCCESS) && (RegQueryValueEx(oldKey2, L"InstallDate", 0, &checkType, (BYTE*)checkStr, &checkSize) == ERROR_SUCCESS); checkSize = bufSize * 2; + + if (newKeyRes1 == ERROR_SUCCESS) RegCloseKey(newKey1); + if (newKeyRes2 == ERROR_SUCCESS) RegCloseKey(newKey2); + if (oldKeyRes1 == ERROR_SUCCESS) RegCloseKey(oldKey1); + if (oldKeyRes2 == ERROR_SUCCESS) RegCloseKey(oldKey2); + + if (existNew1 || existNew2) { + oldKeyRes1 = existOld1 ? RegDeleteKey(HKEY_LOCAL_MACHINE, oldKeyStr1.toStdWString().c_str()) : ERROR_SUCCESS; + oldKeyRes2 = existOld2 ? RegDeleteKey(HKEY_LOCAL_MACHINE, oldKeyStr2.toStdWString().c_str()) : ERROR_SUCCESS; + } + + QString userDesktopLnk, commonDesktopLnk; + WCHAR userDesktopFolder[MAX_PATH], commonDesktopFolder[MAX_PATH]; + HRESULT userDesktopRes = SHGetFolderPath(0, CSIDL_DESKTOPDIRECTORY, 0, SHGFP_TYPE_CURRENT, userDesktopFolder); + HRESULT commonDesktopRes = SHGetFolderPath(0, CSIDL_COMMON_DESKTOPDIRECTORY, 0, SHGFP_TYPE_CURRENT, commonDesktopFolder); + if (SUCCEEDED(userDesktopRes)) { + userDesktopLnk = QString::fromWCharArray(userDesktopFolder) + "\\Telegram.lnk"; + } + if (SUCCEEDED(commonDesktopRes)) { + commonDesktopLnk = QString::fromWCharArray(commonDesktopFolder) + "\\Telegram.lnk"; + } + QFile userDesktopFile(userDesktopLnk), commonDesktopFile(commonDesktopLnk); + if (QFile::exists(userDesktopLnk) && QFile::exists(commonDesktopLnk) && userDesktopLnk != commonDesktopLnk) { + bool removed = QFile::remove(commonDesktopLnk); + } + } catch (...) { + } +} + +int psFixPrevious() { + __try + { + psDoFixPrevious(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return 0; + } + return 0; +} + +bool psCheckReadyUpdate() { + QString readyPath = cWorkingDir() + qsl("tupdates/ready"); + if (!QDir(readyPath).exists()) { + return false; + } + + // check ready version + QString versionPath = readyPath + qsl("/tdata/version"); + { + QFile fVersion(versionPath); + if (!fVersion.open(QIODevice::ReadOnly)) { + LOG(("Update Error: cant read version file '%1'").arg(versionPath)); + PsUpdateDownloader::clearAll(); + return false; + } + DWORD versionNum; + if (fVersion.read((char*)&versionNum, sizeof(DWORD)) != sizeof(DWORD)) { + LOG(("Update Error: cant read version from file '%1'").arg(versionPath)); + PsUpdateDownloader::clearAll(); + return false; + } + fVersion.close(); + if (versionNum <= AppVersion) { + LOG(("Update Error: cant install version %1 having version %2").arg(versionNum).arg(AppVersion)); + PsUpdateDownloader::clearAll(); + return false; + } + } + + QString curUpdater = (cExeDir() + "Updater.exe"); + QFileInfo updater(cWorkingDir() + "tupdates/ready/Updater.exe"); + if (!updater.exists()) { + QFileInfo current(curUpdater); + if (!current.exists()) { + PsUpdateDownloader::clearAll(); + return false; + } + if (CopyFile(current.absoluteFilePath().toStdWString().c_str(), updater.absoluteFilePath().toStdWString().c_str(), TRUE) == FALSE) { + PsUpdateDownloader::clearAll(); + return false; + } + } + if (CopyFile(updater.absoluteFilePath().toStdWString().c_str(), curUpdater.toStdWString().c_str(), FALSE) == FALSE) { + PsUpdateDownloader::clearAll(); + return false; + } + if (DeleteFile(updater.absoluteFilePath().toStdWString().c_str()) == FALSE) { + PsUpdateDownloader::clearAll(); + return false; + } + return true; +} + +void psPostprocessFile(const QString &name) { + std::wstring zoneFile = QDir::toNativeSeparators(name).toStdWString() + L":Zone.Identifier"; + HANDLE f = CreateFile(zoneFile.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (f == INVALID_HANDLE_VALUE) { // :( + return; + } + + const char data[] = "[ZoneTransfer]\r\nZoneId=3\r\n"; + + DWORD written = 0; + BOOL result = WriteFile(f, data, sizeof(data), &written, NULL); + CloseHandle(f); + + if (!result || written != sizeof(data)) { // :( + return; + } +} + +void psOpenFile(const QString &name, bool openWith) { + std::wstring wname = QDir::toNativeSeparators(name).toStdWString(); + + if (openWith && useOpenAs) { + if (shOpenWithDialog) { + OPENASINFO info; + info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC; + info.pcszClass = NULL; + info.pcszFile = wname.c_str(); + shOpenWithDialog(0, &info); + } else { + openAs_RunDLL(0, 0, wname.c_str(), SW_SHOWNORMAL); + } + } else { + ShellExecute(0, L"open", wname.c_str(), 0, 0, SW_SHOWNORMAL); + } +} + +void psShowInFolder(const QString &name) { + QString nameEscaped = QDir::toNativeSeparators(name).replace('"', qsl("\"\"")); + ShellExecute(0, 0, qsl("explorer").toStdWString().c_str(), (qsl("/select,") + nameEscaped).toStdWString().c_str(), 0, SW_SHOWNORMAL); +} + +void psExecUpdater() { + QString targs = qsl("-update"); + if (cFromAutoStart()) targs += qsl(" -autostart"); + if (cDebug()) targs += qsl(" -debug"); + + QString updater(QDir::toNativeSeparators(cExeDir() + "Updater.exe")), wdir(QDir::toNativeSeparators(cWorkingDir())); + + DEBUG_LOG(("Application Info: executing %1 %2").arg(cExeDir() + "Updater.exe").arg(targs)); + HINSTANCE r = ShellExecute(0, 0, updater.toStdWString().c_str(), targs.toStdWString().c_str(), wdir.isEmpty() ? 0 : wdir.toStdWString().c_str(), SW_SHOWNORMAL); + if (long(r) < 32) { + DEBUG_LOG(("Application Error: failed to execute %1, working directory: '%2', result: %3").arg(updater).arg(wdir).arg(long(r))); + QString readyPath = cWorkingDir() + qsl("tupdates/ready"); + PsUpdateDownloader::deleteDir(readyPath); + } +} + +void psExecTelegram() { + QString targs = qsl("-noupdate -tosettings"); + if (cFromAutoStart()) targs += qsl(" -autostart"); + if (cDebug()) targs += qsl(" -debug"); + if (cDataFile() != (cTestMode() ? qsl("data_test") : qsl("data"))) targs += qsl(" -key \"") + cDataFile() + '"'; + + QString telegram(QDir::toNativeSeparators(cExeDir() + "Telegram.exe")), wdir(QDir::toNativeSeparators(cWorkingDir())); + + DEBUG_LOG(("Application Info: executing %1 %2").arg(cExeDir() + "Telegram.exe").arg(targs)); + HINSTANCE r = ShellExecute(0, 0, telegram.toStdWString().c_str(), targs.toStdWString().c_str(), wdir.isEmpty() ? 0 : wdir.toStdWString().c_str(), SW_SHOWNORMAL); + if (long(r) < 32) { + DEBUG_LOG(("Application Error: failed to execute %1, working directory: '%2', result: %3").arg(telegram).arg(wdir).arg(long(r))); + } +} + +void psAutoStart(bool start, bool silent) { + WCHAR startupFolder[MAX_PATH]; + HRESULT hres = SHGetFolderPath(0, CSIDL_STARTUP, 0, SHGFP_TYPE_CURRENT, startupFolder); + if (SUCCEEDED(hres)) { + QString lnk = QString::fromWCharArray(startupFolder) + "\\Telegram.lnk"; + if (start) { + IShellLink* psl; + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); + if (SUCCEEDED(hres)) { + IPersistFile* ppf; + + QString exe = QDir::toNativeSeparators(QDir(cExeDir()).absolutePath() + "//Telegram.exe"), dir = QDir::toNativeSeparators(QDir(cWorkingDir()).absolutePath()); + psl->SetArguments(L"-autostart"); + psl->SetPath(exe.toStdWString().c_str()); + psl->SetWorkingDirectory(dir.toStdWString().c_str()); + psl->SetDescription(L"Telegram autorun link.\nYou can disable autorun in Telegram settings."); + + hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); + + if (SUCCEEDED(hres)) { + hres = ppf->Save(lnk.toStdWString().c_str(), TRUE); + ppf->Release(); + } else { + if (!silent) LOG(("App Error: could not create interface IID_IPersistFile %1").arg(hres)); + } + psl->Release(); + } else { + if (!silent) LOG(("App Error: could not create instance of IID_IShellLink %1").arg(hres)); + } + } else { + QFile::remove(lnk); + } + } else { + if (!silent) LOG(("App Error: could not get CSIDL_STARTUP folder %1").arg(hres)); + } +} + +#ifdef _NEED_WIN_GENERATE_DUMP +static const WCHAR *_programName = L"Telegram Win (Unofficial)"; // folder in APPDATA, if current path is unavailable for writing +static const WCHAR *_exeName = L"Telegram.exe"; + +LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter = 0; + +typedef BOOL (FAR STDAPICALLTYPE *t_miniDumpWriteDump)( + _In_ HANDLE hProcess, + _In_ DWORD ProcessId, + _In_ HANDLE hFile, + _In_ MINIDUMP_TYPE DumpType, + _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam +); +t_miniDumpWriteDump miniDumpWriteDump = 0; + +HANDLE _generateDumpFileAtPath(const WCHAR *path) { + static const int maxFileLen = MAX_PATH * 10; + + WCHAR szPath[maxFileLen]; + wsprintf(szPath, L"%stdumps\\", path); + + if (!CreateDirectory(szPath, NULL)) { + DWORD errCode = GetLastError(); + if (errCode && errCode != ERROR_ALREADY_EXISTS) { + return 0; + } + } + + WCHAR szFileName[maxFileLen]; + WCHAR szExeName[maxFileLen]; + + wcscpy_s(szExeName, _exeName); + WCHAR *dotFrom = wcschr(szExeName, WCHAR(L'.')); + if (dotFrom) { + wsprintf(dotFrom, L""); + } + + SYSTEMTIME stLocalTime; + + GetLocalTime(&stLocalTime); + + wsprintf(szFileName, L"%s%s-%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp", + szPath, szExeName, AppVersionStr, + stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, + stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond, + GetCurrentProcessId(), GetCurrentThreadId()); + return CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); +} + +void _generateDump(EXCEPTION_POINTERS* pExceptionPointers) { + static const int maxFileLen = MAX_PATH * 10; + + HMODULE hDll = LoadLibrary(L"DBGHELP.DLL"); + if (!hDll) return; + + miniDumpWriteDump = (t_miniDumpWriteDump)GetProcAddress(hDll, "MiniDumpWriteDump"); + if (!miniDumpWriteDump) return; + + HANDLE hDumpFile = 0; + + WCHAR szPath[maxFileLen]; + DWORD len = GetModuleFileName(GetModuleHandle(0), szPath, maxFileLen); + if (!len) return; + + WCHAR *pathEnd = szPath + len; + + if (!_wcsicmp(pathEnd - wcslen(_exeName), _exeName)) { + wsprintf(pathEnd - wcslen(_exeName), L""); + hDumpFile = _generateDumpFileAtPath(szPath); + } + if (!hDumpFile || hDumpFile == INVALID_HANDLE_VALUE) { + WCHAR wstrPath[maxFileLen]; + DWORD wstrPathLen; + if (wstrPathLen = GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen)) { + wsprintf(wstrPath + wstrPathLen, L"\\%s\\", _programName); + hDumpFile = _generateDumpFileAtPath(wstrPath); + } + } + + if (!hDumpFile || hDumpFile == INVALID_HANDLE_VALUE) { + return; + } + + MINIDUMP_EXCEPTION_INFORMATION ExpParam = {0}; + ExpParam.ThreadId = GetCurrentThreadId(); + ExpParam.ExceptionPointers = pExceptionPointers; + ExpParam.ClientPointers = TRUE; + + miniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL); +} + +LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers) { + _generateDump(pExceptionPointers); + return _oldWndExceptionFilter ? (*_oldWndExceptionFilter)(pExceptionPointers) : EXCEPTION_CONTINUE_SEARCH; +} +#endif diff --git a/Telegram/SourceFiles/pspecific_wnd.h b/Telegram/SourceFiles/pspecific_wnd.h new file mode 100644 index 000000000..70634a5e3 --- /dev/null +++ b/Telegram/SourceFiles/pspecific_wnd.h @@ -0,0 +1,261 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +inline QString psServerPrefix() { + return qsl("Global\\"); +} +inline void psCheckLocalSocket(const QString &) { +} + +class PsNotifyWindow : public QWidget, public Animated { + Q_OBJECT + +public: + + PsNotifyWindow(HistoryItem *item, int32 x, int32 y); + + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void mousePressEvent(QMouseEvent *e); + void paintEvent(QPaintEvent *e); + + bool animStep(float64 ms); + void animHide(float64 duration, anim::transition func); + void startHiding(); + void stopHiding(); + void moveTo(int32 x, int32 y, int32 index = -1); + + void updatePeerPhoto(); + + int32 index() const { + return history ? _index : -1; + } + + ~PsNotifyWindow(); + +public slots: + + void hideByTimer(); + void checkLastInput(); + + void unlinkHistory(History *hist = 0); + +private: + + DWORD started; + + History *history; + IconedButton close; + QPixmap pm; + float64 alphaDuration, posDuration; + QTimer hideTimer, inputTimer; + bool hiding; + int32 _index; + anim::fvalue aOpacity; + anim::transition aOpacityFunc; + anim::ivalue aY; + ImagePtr peerPhoto; + +}; + +typedef QList PsNotifyWindows; + +class PsMainWindow : public QMainWindow { + Q_OBJECT + +public: + PsMainWindow(QWidget *parent = 0); + + int32 psResizeRowWidth() const { + return 0;//st::wndResizeAreaWidth; + } + + void psInitFrameless(); + void psInitSize(); + HWND psHwnd() const; + HMENU psMenu() const; + + void psFirstShow(); + void psInitSysMenu(); + void psUpdateSysMenu(Qt::WindowState state); + void psUpdateMargins(); + void psUpdatedPosition(); + + bool psHandleTitle(); + + void psFlash(); + void psNotifySettingGot(); + + bool psIsActive() const; + bool psIsOnline(int windowState) const; + + void psUpdateWorkmode(); + + void psRefreshTaskbarIcon(); + virtual bool minimizeToTray() { + return false; + } + + void psNotify(History *history, MsgId msgId); + void psClearNotify(History *history = 0); + void psClearNotifyFast(); + void psShowNextNotify(PsNotifyWindow *remove = 0); + void psStopHiding(); + void psStartHiding(); + void psUpdateNotifies(); + + bool psPosInited() const { + return posInited; + } + + ~PsMainWindow(); + +public slots: + + void psStateChanged(Qt::WindowState state); + void psUpdateCounter(); + void psSavePosition(Qt::WindowState state = Qt::WindowActive); + void psIdleTimeout(); + void psNotifyFire(); + +protected: + + bool posInited; + QSystemTrayIcon *trayIcon; + QMenu *trayIconMenu; + QImage icon16, icon32, icon256; + virtual void setupTrayIcon() { + } + + typedef QMap NotifyWhenMap; + typedef QMap NotifyWhenMaps; + NotifyWhenMaps notifyWhenMaps; + struct NotifyWaiter { + NotifyWaiter(MsgId msg, uint64 when) : msg(msg), when(when) { + } + MsgId msg; + uint64 when; + }; + typedef QMap NotifyWaiters; + NotifyWaiters notifyWaiters; + NotifyWaiters notifySettingWaiters; + QTimer notifyWaitTimer; + + typedef QSet NotifyWhenAlert; + typedef QMap NotifyWhenAlerts; + NotifyWhenAlerts notifyWhenAlerts; + + PsNotifyWindows notifyWindows; + + QTimer psUpdatedPositionTimer; + +private: + HWND ps_hWnd; + HWND ps_tbHider_hWnd; + HMENU ps_menu; + HICON ps_iconBig, ps_iconSmall, ps_iconOverlay; + + mutable bool psIdle; + mutable QTimer psIdleTimer; + + void psDestroyIcons(); +}; + +#ifdef _NEED_WIN_GENERATE_DUMP +extern LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter; +LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers); +#endif _NEED_WIN_GENERATE_DUMP + +class PsApplication : public QApplication { + Q_OBJECT + +public: + + PsApplication(int argc, char *argv[]); + void psInstallEventFilter(); + ~PsApplication(); + +signals: + + void updateChecking(); + void updateLatest(); + void updateDownloading(qint64 ready, qint64 total); + void updateReady(); + void updateFailed(); + +}; + +class PsUpdateDownloader : public QObject { + Q_OBJECT + +public: + PsUpdateDownloader(QThread *thread, const MTPDhelp_appUpdate &update); + PsUpdateDownloader(QThread *thread, const QString &url); + + void unpackUpdate(); + + int32 ready(); + int32 size(); + + static void deleteDir(const QString &dir); + static void clearAll(); + + ~PsUpdateDownloader(); + +public slots: + + void start(); + void partMetaGot(); + void partFinished(qint64 got, qint64 total); + void partFailed(QNetworkReply::NetworkError e); + void sendRequest(); + +private: + void initOutput(); + + void fatalFail(); + + QString updateUrl; + QNetworkAccessManager manager; + QNetworkReply *reply; + int32 already, full; + QFile outputFile; + + QMutex mutex; + +}; + +void psActivateProcess(uint64 pid); +QString psLocalServerPrefix(); +QString psCurrentCountry(); +QString psCurrentLanguage(); +QString psAppDataPath(); +QString psCurrentExeDirectory(); +void psAutoStart(bool start, bool silent = false); + +int psCleanup(); +int psFixPrevious(); + +bool psCheckReadyUpdate(); +void psExecUpdater(); +void psExecTelegram(); + +void psPostprocessFile(const QString &name); +void psOpenFile(const QString &name, bool openWith = false); +void psShowInFolder(const QString &name); diff --git a/Telegram/SourceFiles/qmime/freedesktop.org.xml b/Telegram/SourceFiles/qmime/freedesktop.org.xml new file mode 100644 index 000000000..a419a4b8f --- /dev/null +++ b/Telegram/SourceFiles/qmime/freedesktop.org.xml @@ -0,0 +1,33999 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + ATK inset + شكل ATK + UstaÅ­ka ATK + Сбор — ATK + inset ATK + Vložka ATK + ATK-indsættelse + ATK-Inset + ATK inset + inserción ATK + ATK sartzapena + ATK-osio + ATK innskot + encart ATK + intlis ATK + conxunto ATK + תוספת ATK + ATK betét + Inset ATK + Inset ATK + ATK インセット + ATK беті + ATK inset + ATK inset + ATK ielaidums + ATK-innsats + ATK-invoegsel + ATK-innskot + Wstawka ATK + Conjunto de entrada do ATK + Inset ATK + вкладка ATK + Vložka ATK + Vložka ATK + Inset ATK + ATK-inlägg + вкладка ATK + Bá»™ dát ATK + ATK 嵌入对象 + ATK + Andrew Toolkit + + + + + electronic book document + مستند كتاب إلكتروني + elektronnaja kniha + Документ — електронна книга + document de llibre electrònic + Dokument elektronické knihy + elektronisk bogdokument + Elektronisches Buch + έγγÏαφο ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Î²Î¹Î²Î»Î¯Î¿Ï… + electronic book document + documento de libro electrónico + liburu elektronikoaren dokumentua + elektroninen kirja + elektroniskbóka skjal + document livre électronique + leabhar leictreonach + documento de libro electrónico + מסמך מסוג ספר ×לקטרוני + dokument elektroniÄke knjige + elektronikus könyvdokumentum + dokumen buku elektronik + Documento libro elettronico + é›»å­ãƒ–ックドキュメント + Ñлектронды кітабы + ì „ìžì±… 문서 + elektroninÄ—s knygos dokumentas + elektroniskÄs grÄmatas dokuments + elektronisch boek + elektronisk bok-dokument + Dokument książki elektronicznej + Documento de livro eletrônico + document carte electronică + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ ÐºÐ½Ð¸Ð³Ð° + Dokument elektronickej knihy + dokument elektronske knjige + Dokument libri elektronik + elektroniskt bokdokument + elektronik kitap belgesi + документ електронної книги + tài liệu cuốn sách Ä‘iện tá»­ + 电å­ä¹¦æ–‡æ¡£ + é›»å­æ›¸æ–‡ä»¶ + + + + + + + + + + + + + + Adobe Illustrator document + مستند أدوبي المصور + Dakument Adobe Illustrator + Документ — Adobe Illustrator + document d'Adobe Illustrator + Dokument Adobe Illustrator + Adobe Illustrator-dokument + Adobe-Illustrator-Dokument + έγγÏαφο Adobe Illustrator + Adobe Illustrator document + dokumento de Adobe Illustrator + documento de Adobe Illustrator + Adobe Illustrator dokumentua + Adobe Illustrator -asiakirja + Adobe Illustrator skjal + document Adobe Illustrator + cáipéis Adobe Illustrator + documento de Adobe Ilustrator + מסמך Adobe Ill + Adobe Illustrator dokument + Adobe Illustrator-dokumentum + Dokumen Adobe Illustrator + Documento Adobe Illustrator + Adobe Illustrator ドキュメント + Adobe Illustrator-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + Adobe Illustrator құжаты + ì–´ë„비 ì¼ëŸ¬ìŠ¤íŠ¸ë ˆì´í„° 문서 + Adobe Illustrator dokumentas + Adobe Illustrator dokuments + Dokumen Adobe Illustrator + Adobe Illustrator-dokument + Adobe Illustrator-document + Adobe Illustrator-dokument + Dokument Adobe Illustrator + documento Adobe Illustrator + Documento do Adobe Illustrator + Document Adobe Illustrator + документ Adobe Illustrator + Dokument Adobe Illustrator + Dokument Adobe Illustrator + Dokument Adobe Illustrator + Ðдоуби ИлуÑтратор документ + Adobe Illustrator-dokument + документ Adobe Illustrator + Tài liệu Adobe Illustrator + Adobe Illustrator 文档 + Adobe Illustrator 文件 + + + + + Macintosh BinHex-encoded file + مل٠Macintosh BinHex مشÙر + Macintosh BinHex-kodlanmış fayl + FajÅ‚ Macintosh, BinHex-zakadavany + Файл — кодиран във формат BinHex за Macintosh + fitxer codificat BinHex de Macintosh + Soubor kódovaný pomocí Macintosh BinHex + Ffeil BinHex-amgodwyd Macintosh + Macintosh BinHex-kodet fil + Macintosh-Datei (BinHex-kodiert) + αÏχείο Macintosh κωδικοποίησης BinHex + Macintosh BinHex-encoded file + dosiero kodigita laÅ­ Macintosh BinHex + archivo Macintosh codificado con BinHex + Macintosh BinHex-ekin kodetutako fitxategia + Macintosh BinHex -koodattu tiedosto + Macintosh BinHex-bronglað fíla + fichier codé Macintosh BinHex + comhad ionchódaithe le Macintosh BinHex + ficheiro de Macintosh codificado con BinHex + קובץ מסוג Macintosh BinHex-encoded + Macintosh BinHex-kodirana datoteka + Macintosh BinHex kódolású fájl + Berkas tersandi Macintosh BinHex + File Macintosh codificato BinHex + Macintosh BinHex エンコードファイル + Macintosh BinHex кодталған файлы + 매킨토시 BinHex ì¸ì½”ë”©ëœ ì••ì¶• íŒŒì¼ + Macintosh BinHex-encoded failas + Macintosh BinHex-kodÄ“ts datne + Fail terenkod-BinHex Macintosh + Macintosh BinHe-kodet arkiv + Macintosh BinHex-gecodeerd bestand + Macintosh BinHex-koda fil + Zakodowany w BinHex plik Macintosh + ficheiro codificado em BinHex de Macintosh + Arquivo do Macintosh codificado com BinHex + FiÈ™ier codat Macintosh BinHex + файл (закодированный Macintosh BinHex) + Súbor kódovaný pomocou Macintosh BinHex + Kodirana datoteka Macintosh (BinHex) + File Macintosh i kodifikuar BinHex + Мекинтош BinHex-encoded датотека + Macintosh BinHex-kodad fil + файл закодований Macintosh BinHex + Tập tin đã mã hoá BinHex của Macintosh + Macintosh BinHex ç¼–ç çš„文件 + Macintosh BinHex 編碼檔 + + + + + + + Mathematica Notebook + مذكرة رياضيات + Natatnik Mathematica + Тетрадка — Mathematica + llibreta de notes de Mathematica + SeÅ¡it Mathematica + Mathematica Notebook + Mathematica-Dokument + σημειωματάÏιο Mathematica + Mathematica Notebook + notebook de Mathematica + Mathematica Notebook + Mathematica-muistilehtiö + Mathematica skriviblokkur + carnet de notes Mathematica + leabhar nótaí Mathematica + notebook de Mathematica + מחברת מתמטיקה + Mathematica notesz + Mathematica Notebook + Notebook Mathematica + Mathematica ノートブック + Mathematica Notebook + Mathematica ë…¸íŠ¸ë¶ + Mathematica užraÅ¡inÄ— + Mathematica bloknots + Mathematica notisblokk + Mathematica-notitieboek + Mathematica-notatbok + Notatnik Mathematica + Caderno do Mathematica + CarneÈ›el Mathematica + Mathematica Notebook + ZoÅ¡it Mathematica + Datoteka dokumenta Mathematica + Notebook matematike + Mathematica Notebook-dokument + математичний запиÑник + Cuốn vở Mathematica + Mathematica 记事 + Mathematica Notebook + + + + + + + + + + + + MathML document + مستند MathML + MathML sÉ™nÉ™di + Dakument MathML + Документ — MathML + document de MathML + Dokument MathML + Dogfen MathML + MathML-dokument + MathML-Dokument + έγγÏαφο MathML + MathML document + MathML-dokumento + documento MathML + MathML dokumentua + MathML-asiakirja + MathML skjal + document MathML + cáipéis MathML + documento de MathML + מסמך MathML + MathML dokument + MathML-dokumentum + Dokumen MathML + Documento MathML + MathML ドキュメント + MathML-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + MathML құжаты + MathML 문서 + MathML dokumentas + MathML dokuments + Dokumen MathML + MathML-dokument + MathML-document + MathML-dokument + Dokument MathML + documento MathML + Documento do MathML + Document MathML + документ MathML + Dokument MathML + Dokument MathML + Dokument MathML + MathML документ + MathML-dokument + MathML belgesi + документ MathML + Tài liệu MathML + MathML 文档 + MathML 文件 + MathML + Mathematical Markup Language + + + + + + + mailbox file + مل٠صندوق البريد + fajÅ‚ paÅ¡tovaj skryni + Файл — Mailbox + fitxer mailbox + Soubor mailbox + postkassefil + Mailbox-Datei + αÏχείο mailbox + mailbox file + archivo de buzón de correo + mailbox fitxategia + mailbox-tiedosto + postkassafíla + fichier boîte aux lettres + comhad bhosca poist + ficheiro de caixa de correo + קובץ תיבת-דו×ר + datoteka poÅ¡tanskog sanduÄića + mailbox fájl + berkas kotak surat + File mailbox + メールボックスファイル + пошта жәшігінің файлы + ë©”ì¼í•¨ íŒŒì¼ + paÅ¡to dėžutÄ—s failas + pastkastÄ«tes datne + postboksfil + mailbox-bestand + mailbox-fil + Plik poczty (Mailbox) + Arquivo de caixa de correio + fiÈ™ier căsuță poÈ™tală + файл почтового Ñщика + Súbor mailbox + datoteka poÅ¡tnega predala + File mailbox + brevlÃ¥defil + файл поштової Ñкриньки + tập tin há»™p thÆ° + mailbox 文件 + 郵箱檔 + + + + + + + + + Metalink file + مل٠ميتالنك + ИзтеглÑне — Metalink + fitxer Metalink + Soubor metalink + Metahenvisningsfil + Metalink-Datei + αÏχείο Metalink + Metalink file + Metalink-dosiero + archivo de metaenlace + Metaestekaren fitxategia + Metalink-tiedosto + Metalink fíla + fichier metalink + comhad Metalink + ficheiro Metalink + קובץ Metalink + Metalink fájl + Berkas Metalink + File Metalink + Metalink ファイル + Metalink файлы + Metalink íŒŒì¼ + Metalink failas + Metalink datne + Metalink bestand + Plik Metalink + Arquivo Metalink + FiÈ™ier Metalink + файл Metalink + Súbor Metalink + Datoteka povezave Metalink + Metalink-fil + Metalink dosyası + файл метапоÑÐ¸Ð»Ð°Ð½Ð½Ñ + 元链接文件 + Metalink 檔案 + + + + + + + + + Metalink file + مل٠ميتالنك + ИзтеглÑне — Metalink + fitxer Metalink + Soubor metalink + Metahenvisningsfil + Metalink-Datei + αÏχείο Metalink + Metalink file + Metalink-dosiero + archivo de metaenlace + Metaestekaren fitxategia + Metalink-tiedosto + Metalink fíla + fichier metalink + comhad Metalink + ficheiro Metalink + קובץ Metalink + Metalink fájl + Berkas Metalink + File Metalink + Metalink ファイル + Metalink файлы + Metalink íŒŒì¼ + Metalink failas + Metalink datne + Metalink bestand + Plik Metalink + Arquivo Metalink + FiÈ™ier Metalink + файл Metalink + Súbor Metalink + Datoteka povezave Metalink + Metalink-fil + Metalink dosyası + файл метапоÑÐ¸Ð»Ð°Ð½Ð½Ñ + 元链接文件 + Metalink 檔案 + + + + + + + + + unknown + مجهول + nieviadomy + ÐеизвеÑтен тип + desconegut + Neznámý + ukendt + Unbekannt + άγνωστο + unknown + nekonate + desconocido + ezezaguna + tuntematon + ókent + inconnu + anaithnid + descoñecido + ×œ× ×™×“×•×¢ + nepoznato + ismeretlen + tak diketahui + Sconosciuto + ä¸æ˜Ž + უცნáƒáƒ‘ი + белгіÑіз + ì•Œ 수 ì—†ìŒ + nežinoma + nezinÄms + Entah + ukjent + onbekend + ukjend + Nieznany typ + desconhecido + Desconhecido + necunoscut + неизвеÑтно + Neznámy + neznano + Nuk njihet + непознато + okänd + невідомо + không rõ + 未知 + ä¸æ˜Ž + + + + ODA document + مستند ODA + ODA sÉ™nÉ™di + Dakument ODA + Документ — ODA + document ODA + Dokument ODA + Dogfen ODA + ODA-dokument + ODA-Dokument + έγγÏαφο ODA + ODA document + ODA-dokumento + documento ODA + ODA dokumentua + ODA-asiakirja + ODA skjal + document ODA + cáipéis ODA + documento ODA + מסמך ODA + ODA dokument + ODA-dokumentum + Dokumen ODA + Documento ODA + ODA ドキュメント + ODA დáƒáƒ™áƒ£áƒ›áƒ”ნტი + ODA құжаты + ODA 문서 + ODA dokumentas + ODA dokuments + Dokumen ODA + ODA-dokument + ODA-document + ODA-dokument + Dokument ODA + documento ODA + Documento ODA + Document ODA + документ ODA + Dokument ODA + Dokument ODA + Dokument ODA + ODA документ + ODA-dokument + ODA belgesi + документ ODA + Tài liệu ODA + ODA 文档 + ODA 文件 + ODA + Office Document Architecture + + + + + WWF document + Документ — WWF + document WWF + Dokument WWF + WWF-dokument + WWF-Dokument + έγγÏαφο WWF + WWF document + WWF-dokumento + Documento de WWF + WWF-asiakirja + document WWF + documento de WWF + מסמך WWF + WWF dokument + WWF dokumentum + Dokumen WWF + Documento WWF + WWF 文書 + WWF დáƒáƒ™áƒ£áƒ›áƒ”ნტი + WWF құжаты + WWF 문서 + WWF dokuments + WWF document + Dokument WWF + Documento WWF + документ WWF + Dokument WWF + WWF-dokument + документ WWF + WWF + WWF 文件 + + + + + + + PDF document + مستند PDF + Dakument PDF + Документ — PDF + document PDF + Dokument PDF + Dogfen PDF + PDF-dokument + PDF-Dokument + έγγÏαφο PDF + PDF document + PDF-dokumento + documento PDF + PDF dokumentua + PDF-asiakirja + PDF skjal + document PDF + cáipéis PDF + documento PDF + מסמך PDF + PDF-dokumentum + Dokumen PDF + Documento PDF + PDF ドキュメント + PDF құжаты + PDF 문서 + PDF dokumentas + PDF dokuments + Dokumen PDF + PDF-dokument + PDF-document + PDF-dokument + Dokument PDF + documento PDF + Documento PDF + Document PDF + документ PDF + Dokument PDF + Dokument PDF + Dokument PDF + PDF документ + PDF-dokument + PDF belgesi + документ PDF + Tài liệu PDF + PDF 文档 + PDF 文件 + PDF + Portable Document Format + + + + + + + + + + + XSPF playlist + قائمة تشغيل XSPF + Åšpis piesieÅ„ XSPF + СпиÑък за изпълнение — XSPF + llista de reproducció XSPF + Seznam skladeb XSPF + XSPF-afspilningsliste + XSPF-Wiedergabeliste + λίστα αναπαÏαγωγής XSPF + XSPF playlist + XSPF-ludlisto + lista de reproducción XSPF + XSPF erreprodukzio-zerrenda + XSPF-soittolista + XSPF avspælingarlisti + liste de lecture XSPF + seinmliosta XSPF + lista de reprodución XSPF + רשימת השמעה XSPF + XSPF popis za reprodukciju + XSPF-lejátszólista + Senarai pular XSPF + Scaletta XSPF + XSPF å†ç”Ÿãƒªã‚¹ãƒˆ + XSPF ойнау тізімі + XSPF ìž¬ìƒ ëª©ë¡ + XSPF grojaraÅ¡tis + XSPF repertuÄrs + XSPF-spilleliste + XSPF-afspeellijst + XSPF-speleliste + Lista odtwarzania XSPF + Lista de reprodução XSPF + Listă XSPF + ÑпиÑок воÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ XSPF + Zoznam skladieb XSPF + Seznam predvajanja XSPF + Listë titujsh XSPF + XSPF-spellista + ÑпиÑок Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð²Ð°Ð½Ð½Ñ XSPF + Danh mục nhạc XSPF + XSPF 播放列表 + XSPF 播放清單 + XSPF + XML Shareable Playlist Format + + + + + + + + + + + + Microsoft Windows theme pack + حزمة سمات Microsoft Works + Пакет Ñ Ñ‚ÐµÐ¼Ð° — Microsoft Windows + paquet de temes Windows de Microsoft + Balík motivů Microsoft Windows + Microsoft Windows-temapakke + Themenpaket für Microsoft Windows + θεματικό πάÏκο Microsoft Windows + Microsoft Windows theme pack + paquete de tema para Microsoft Windows + Microsoft Windows-en gaiaren paketea + Microsoft Windows -teemapaketti + Microsoft Windows tema pakki + paquet de thèmes Microsoft Windows + paca téamaí Microsoft Windows + paquete de tema de Microsoft Windows + חבילת ערכות × ×•×©× ×©×œ Microsoft Windows + Microsoft Windows paket tema + Microsoft Windows témacsomag + Pak tema Microsoft Windows + Pacchetto temi Microsoft Windows + Microsoft Windows テーマパック + Microsoft Windows-ის თემის შეკვრრ+ Microsoft Windows тема деÑтеÑÑ– + 마ì´í¬ë¡œì†Œí”„트 Windows 테마 패키지 + Microsoft Windows temų paketas + Microsoft Windows motÄ«vu paka + Microsoft Windows thema pack + Pakiet motywu Microsoft Windows + Pacote de temas do Microsoft Windows + Pachet de teme Microsoft Windows + пакет темы Microsoft Windows + Balík tém Microsoft Windows + Datoteka teme Microsoft Windows + Microsoft Windows-temapaket + пакунок з темою Microsoft Windows + Microsoft Windows 主题包 + 微軟視窗佈景主題包 + + + + + + AmazonMP3 download file + + + + GSM 06.10 audio + GSM 06.10 سمعي + Ðудио — GSM 06.10 + àudio GSM 06.10 + Zvuk GSM 06.10 + GSM 06.10-lyd + GSM-06.10-Audio + ήχος GSM 06.10 + GSM 06.10 audio + sonido GSM 06.10 + GSM 06.10 audioa + GSM 06.10 -ääni + GSM 06.10 ljóður + audio GSM 06.10 + fuaim GSM 06.10 + son de GSM 06.10 + שמע GSM 06.10 + GSM 06.10 audio + GSM 06.10 hang + Audio GSM 06.10 + Audio GSM 06.10 + GSM 06.10 オーディオ + GSM 06.10 áƒáƒ£áƒ“ირ+ GSM 06.10 аудиоÑÑ‹ + GSM 06.10 오디오 + GSM 06.10 garso įraÅ¡as + GSM 06.10 audio + GSM 06.10 audio + Plik dźwiÄ™kowy GSM 06.10 + Ãudio GSM 06.10 + GSM 06.10 audio + аудио GSM 06.10 + Zvuk GSM 06.10 + ZvoÄna datoteka GSM 06.10 + GSM 06.10-ljud + звук GSM 06.10 + Âm thanh GSM 06.10 + GSM 06.10 音频 + GSM 06.10 音訊 + GSM + Global System for Mobile communications + + + + iRiver Playlist + قائمة تشغيل iRiver + Åšpis piesieÅ„ iRiver + СпиÑък за изпълнение — iRiver + llista de reproducció iRiver + Seznam skladeb iRiver + iRiver-afspilningsliste + iRiver-Wiedergabeliste + λίστα αναπαÏαγωγής iRiver + iRiver Playlist + iRiver-ludlisto + lista de reproducción de iRiver + iRiver erreprodukzio-zerrenda + iRiver-soittolista + iRiver avspælingarlisti + liste de lecture iRiver + seinmliosta iRiver + lista de reprodución de iRiver + רשימת השמעה של iRiver + iRiver popis za reprodukciju + iRiver lejátszólista + iRiver Playlist + Scaletta iRiver + iRiver å†ç”Ÿãƒªã‚¹ãƒˆ + iRiver ойнау тізімі + iRiver ìž¬ìƒ ëª©ë¡ + iRiver grojaraÅ¡tis + iRiver repertuÄrs + iRiver-spilleliste + iRiver-afspeellijst + iRiver speleliste + Lista odtwarzania iRiver + Lista de reprodução do iRiver + Listă iRiver + ÑпиÑок воÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ iRiver + Zoznam skladieb iRiver + Seznam predvajanja iRiver + Listë titujsh iRiver + iRiver-spellista + ÑпиÑок Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð²Ð°Ð½Ð½Ñ iRiver + danh mục nhạc iRiver + iRiver 播放列表 + iRiver 播放清單 + + + + + + + PGP/MIME-encrypted message header + ترويسة رسالة PGP/MIME-مشÙرة + ZahaÅ‚ovak paviedamleÅ„nia, zaÅ¡yfravany Å­ PGP/MIME + Заглавна чаÑÑ‚ на шифрирано Ñъобщение — PGP/MIME + capçalera de missatge xifrat amb PGP/MIME + Záhlaví zprávy zaÅ¡ifrované pomocí PGP/MIME + PGP-/MIME-krypteret meddelelseshoved + PGP/MIME-verschlüsselter Nachrichtenkopf + κεφαλίδα μηνÏματος κÏυπτογÏαφημένου κατά PGP/MIME + PGP/MIME-encrypted message header + PGP/MIME-ĉifrita ĉapo de mesaÄo + cabecera de mensaje cifrado PGP/MIME + PGP/MIME enkriptatutako mezu-goiburua + PGP/MIME-salattu viestiotsikko + PGP/MIME-encrypted boð tekshøvd + en-tête de message codé PGP/MIME + ceanntásc teachtaireachta ionchódaithe le PGP/MIME + cabeceira de mensaxe cifrado PGP/MIME + כותר של קובץ מוצפן מסוג PGP/MIME + PGP/MIME titkosított üzenetfejléc + Tajuk pesan terenkripsi PGP/MIME + Intestazione messaggio PGP/MIME-encrypted + PGP/MIME æš—å·åŒ–メッセージヘッダー + PGP/MIME-шифрленген мәлімдеме тақырыптамаÑÑ‹ + PGP/MIME으로 ì•”í˜¸í™”ëœ ë©”ì‹œì§€ í—¤ë” + PGP/MIME užšifruota žinutÄ—s antraÅ¡tÄ— + PGP/MIME-Å¡ifrÄ“ta ziņas galvene + Pengepala mesej terenkripsi PGP/MIME + PGP/MIME-kryptert meldingshode + PGP/MIME-versleutelde berichtkopregels + PGP/MIME-kryptert meldingshovud + Nagłówek listu zaszyfrowanego PGP/MIME + cabeçalho de mensagem cifrada com PGP/MIME + Cabeçalho de mensagem criptografada PGP/MIME + Antet de mesaj encriptat PGP/MIME + заголовок ÑообщениÑ, зашифрованный PGP/MIME + HlaviÄke správy zaÅ¡ifrovaná pomocou PGP/MIME + Datoteka glave Å¡ifriranega sporoÄila PGP/MIME + Header mesazhi të kriptuar PGP/MIME + ПГП/МИМЕ шифровано заглавље поруке + PGP/MIME-krypterat meddelandehuvud + заголовок шифрованого PGP/MIME Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ + Phần đầu thông Ä‘iệp đã mật mã bằng PGP/MIME + PGP/MIME 加密的信件头 + PGP/MIME 加密訊æ¯æ¨™é ­ + + + + + + + + + + + PGP keys + Ù…Ùاتيح PGP + PGP açarları + KluÄy PGP + Ключове — PGP + claus PGP + KlíÄe PGP + Allweddi PGP + PGP-nøgler + PGP-Schlüssel + κλειδιά PGP + PGP keys + PGP-Ålosiloj + claves PGP + PGP giltzak + PGP-avainrengas + PGP lyklar + clés PGP + eochracha PGP + Chaves PGP + מפתח PGP + PGP-kulcs + Kunci PGP + Chiavi PGP + PGP éµ + PGP кілттері + PGP 키 + PGP raktai + PGP atslÄ“gas + Kekunci PGP + PGP-nøkler + PGP-sleutels + PGP-nøkler + Klucze PGP + chaves PGP + Chaves PGP + Chei PGP + ключи PGP + KľúÄe PGP + Datoteka kljuÄa PGP + Kyçe PGP + PGP кључ + PGP-nycklar + PGP anahtarları + ключі PGP + Khoá PGP + PGP 密钥 + PGP 鑰匙 + PGP + Pretty Good Privacy + + + + + + + + + + + + + + + + + + detached OpenPGP signature + إمضاء OpenPGP Ù…Ùصول + adÅ‚uÄany podpis OpenPGP + Отделен Ð¿Ð¾Ð´Ð¿Ð¸Ñ â€” OpenPGP + signatura OpenPGP separada + OddÄ›lený podpis OpenPGP + frigjort OpenPGP-signatur + Isolierte OpenPGP-Signatur + αποκομμένη υπογÏαφή OpenPGP + detached OpenPGP signature + dekroĉa OpenPGP-subskribo + firma OpenPGP separada + desuzturtako OpenPGP sinadura + erillinen OpenPGP-allekirjoitus + skild OpenPGP undirskrift + signature OpenPGP détachée + síniú OpenPGP scartha + sinatura de OpenPGP independente + חתימת OpenPGP מנותקת + odvojen OpenPGP potpis + leválasztott OpenPGP-aláírás + tanda tangan OpenPGP yang terlepas + Firma staccata OpenPGP + 分離 OpenPGP ç½²å + бөлінген OpenPGP қолтаңбаÑÑ‹ + ë¶„ë¦¬ëœ OpenPGP 서명 + neprisegtas OpenPGP paraÅ¡as + atvienots OpenPGP paraksts + Tandatangan OpenPGP terlerai + frakoblet OpenPGP-signatur + losse OpenPGP-ondertekening + frÃ¥kopla OpenPGP-signatur + Oddzielony podpis OpenPGP + assinatura OpenPGP solta + Assinatura OpenPGP destacada + semnătură OpenPGP detaÈ™ată + отÑÐ¾ÐµÐ´Ð¸Ð½Ñ‘Ð½Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ OpenPGP + Oddelený podpis OpenPGP + odpet podpis OpenPGP + Firmë e shkëputur OpenPGP + одвојени ОпенПГП Ð¿Ð¾Ñ‚Ð¿Ð¸Ñ + frikopplad OpenPGP-signatur + відокремлений OpenPGP Ð¿Ñ–Ð´Ð¿Ð¸Ñ + chữ ký OpenPGP tách rá»i + 分离的 OpenPGP ç­¾å + 分離的 OpenPGP 簽章 + + + + + + + + + + + + + PKCS#7 Message or Certificate + PKCS + Public-Key Cryptography Standards + + + + + + detached S/MIME signature + إمضاء S/MIME Ù…Ùصول + adÅ‚uÄany podpis S/MIME + Отделен Ð¿Ð¾Ð´Ð¿Ð¸Ñ â€” S/MIME + signatura S/MIME separada + OddÄ›lený podpis S/MIME + frigjort S/MIME-signatur + Isolierte S/MIME-Signatur + αποκομμένη υπογÏαφή S/MIME + detached S/MIME signature + dekroĉa S/MIME-subskribo + firma S/MIME separada + desuzturtako S/MIME sinadura + erillinen S/MIME-allekirjoitus + skild S/MIME undirskrift + signature S/MIME détachée + síniú S/MIME scartha + sinatura S/MIME independente + חתימת S/MIME מנותקת + odvojen S/MIME potpis + leválasztott S/MIME-aláírás + tanda tangan S/MIME yang terlepas + Firma staccata S/MIME + 分離 S/MIME ç½²å + бөлінген S/MIME қолтаңбаÑÑ‹ + ë¶„ë¦¬ëœ S/MIME 서명 + neprisegtas S/MIME paraÅ¡as + atvienots S/MIME paraksts + Tandatangan S/MIME terlerai + frakoblet S/MIME-signatur + losse S/MIME-ondertekening + frÃ¥kopla S/MIME-signatur + Oddzielony podpis S/MIME + assinatura S/MIME solta + Assinatura S/MIME destacada + semnătură S/MIME detaÈ™ată + отÑÐ¾ÐµÐ´Ð¸Ð½Ñ‘Ð½Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ S/MIME + Oddelený podpis S/MIME + odpet podpis S/MIME + Firmë e shkëputur S/MIME + одвојени S/MIME Ð¿Ð¾Ñ‚Ð¿Ð¸Ñ + frikopplad S/MIME-signatur + відокремлений S/MIME Ð¿Ñ–Ð´Ð¿Ð¸Ñ + chữ ký S/MIME tách rá»i + 分离的 S/MIME ç­¾å + 分離的 S/MIME 簽章 + S/MIME + Secure/Multipurpose Internet Mail Extensions + + + + + + PKCS#8 private key + رزمة الشهادة PKCS#8 + Ключ, чаÑтен — PKCS#8 + clau privada PKCS#8 + Soukromý klÃ­Ä PKCS#8 + PKCS#8-privat nøgle + PKCS#8 Geheimer Schlüssel + ιδιωτικό κλειδί PKCS#8 + PKCS#8 private key + clave privada PCKS#8 + PKCS#8 yksityinen avain + PKCS#8 privatur lykil + clé privée PKCS#8 + eochair phríobháideach PKCS#8 + Chave privada PKCS#8 + מפתח פרטי של PKCS#8 + PKCS#8 személyes kulcs + Kunci privat PKCS#8 + Chiave privata PKCS#8 + PKCS#8 ç§˜å¯†éµ + PKCS#8 меншік кілті + PKCS#8 ê°œì¸ í‚¤ + PKCS#8 asmeninis raktas + PKCS#8 privÄtÄ atslÄ“ga + PKCS#8 private sleutel + Klucz prywatny PKCS#8 + Chave privada PKCS#8 + Cheie privată PKCS#8 + личный ключ PKCS#8 + Súkromný kÄ¾ÃºÄ PKCS#8 + Datoteka osebnega kljuÄa PKCS#8 + Privat PKCS#8-nyckel + закритий ключ PKCS#8 + PKCS#8 ç§é’¥ + PKCS#8 ç§äººé‡‘é‘° + PKCS + Public-Key Cryptography Standards + + + + PKCS#10 certification request + طلب شهادة PKCS#10 + Zapyt sertyfikacyi PKCS#10 + ЗаÑвка за Ñертификат — PKCS#10 + sol·licitud de certificació PKCS#10 + Požadavek na certifikát PKCS#10 + PKCS#10-certifikatanmodning + PKCS#10-Zertifikatanfrage + αίτηση πιστοποίησης PKCS#10 + PKCS#10 certification request + petición de certificados PKCS#10 + PKCS#10 ziurtagirien eskaera + PKCS#10-varmennepyyntö + PKCS#10 váttanarumbøn + requête de certification PKCS#10 + iarratas dheimhniúchán PKCS#10 + Solicitude de certificado PKCS#10 + בקשה מוסמכת PLCS#10 + PKCS#10-tanúsítványkérés + Permintaan sertifikasi PKCS#10 + Richiesta certificazione PKCS#10 + PKCS#10 証明書署åè¦æ±‚ + PKCS#10 ÑертификациÑға Ñұранымы + PKCS#10 ì¸ì¦ì„œ 요청 + PKCS#10 liudijimų užklausa + PKCS#10 sertifikÄcijas pieprasÄ«jums + PKCS#10-sertifikatforespørsel + PKCS#10-certificatieverzoek + PKCS#10-sertifiseringsførespurnad + Żądanie certyfikatu PKCS#10 + Pedido de certificação PKCS#12 + Cerere de certificat PKCS#10 + Ð·Ð°Ð¿Ñ€Ð¾Ñ Ñертификации PKCS#10 + Požiadavka na certifikát PKCS#10 + Datoteka potrdila PKCS#10 + Kërkesë çertifikimi PKCS#10 + PKCS#10-certifikatbegäran + комплект Ñертифікатів PKCS#10 + Yêu cầu chứng nhận PKCS#10 + PKCS#10 认è¯è¯·æ±‚ + PKCS#10 憑證請求 + PKCS + Public-Key Cryptography Standards + + + + + X.509 certificate + شهادة X.509 + Сертификат — X.509 + certificat X.509 + Certifikát X.509 + X.509-certifikat + X.509-Zertifikat + Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ì X.509 + X.509 certificate + certificado X.509 + X.509 ziurtagiria + X.509-varmenne + X.509 prógv + certificat X.509 + teastas X.509 + Certificado X.509 + ×ישור X.509 + X.509 certifikat + X.509 tanúsítvány + Sertifikat X.509 + Certificato X.509 + X.509 証明書 + X.509 Ñертификаты + X.509 ì¸ì¦ì„œ + X.509 liudijimas + X.509 sertifikÄts + X.509 certificaat + Certyfikat X.509 + Certificado X.509 + Certificat X.509 + Ñертификат X.509 + Certifikát X.509 + Datoteka potrdila X.509 + X.509-certifikat + Ñертифікат X.509 + X.509 è¯ä¹¦ + X.509 憑證 + + + + Certificate revocation list + قائمة إبطال الشهادات + СпиÑък Ñ Ð¾Ñ‚Ñ…Ð²ÑŠÑ€Ð»ÐµÐ½Ð¸ Ñертификати + llista de revocació de certificats + Seznam odvolaných certifikátů + Certifikattilbagekaldelsesliste + Liste widerrufener Zertifikate + κατάλογος ανάκλησης Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï + Certificate revocation list + lista de revocación de certificados + Ziurtagiri-errebokatzeen zerrenda + Varmenteiden sulkulista + Prógv afturtøkulisti + liste de révocation de certificat + liosta teastas cúlghairmthe + lista de certificados de revogación + רשימת ××™×©×•×¨×™× ×ž×‘×•×˜×œ×™× + popis povuÄenih certifikata + Tanúsítvány-visszavonási lista + Daftar pencabutan sertificat (CRL) + Elenco certificati di revoca + 証明書失効リスト + Сертификатты қайта шақыру тізімі + ì¸ì¦ì„œ 철회 ëª©ë¡ + Panaikintų liudijimų sÄ…raÅ¡as + SertifikÄtu atsaukÅ¡anu saraksts + Certificaat revocation lijst + Lista unieważnieÅ„ certyfikatów + Lista de revogação de certificado + Listă de revocare a certificatelor + СпиÑок Ð°Ð½Ð½ÑƒÐ»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñертификатов + Zoznam zruÅ¡ených certifikátov + Datoteka seznama preklica potrdil + Spärrlista för certifikat + ÑпиÑок Ð²Ñ–Ð´ÐºÐ»Ð¸ÐºÐ°Ð½Ð½Ñ Ñертифікатів + è¯ä¹¦åŠé”€åˆ—表 + 憑證撤銷清單 + + + + PkiPath certification path + مسار شهادة PkiPath + Сертификационна верига — PkiPath + ruta de certificació PkiPath + Cesta k certifikátu PkiPath + PkiPath-certifikationssti + PkiPath-Zertifikatspfad + διαδÏομή Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï PkiPath + PkiPath certification path + ruta de certificación PkiPath + PkiPath ziurtagirien bide-izena + PkiPath-varmennepolku + PkiPath váttanleið + chemin de certification PkiPath + conair dheimhniúcháin PkiPath + Ruta de certificación PkiPath + נתיב מ×ושר של PkiPath + PkiPath tanúsítványútvonal + Alamat sertifikasi PkiPath + Percorso certificazione PkiPath + PkiPath 証明書パス + PkiPath Ñертификаттау жолы + PkiPath ì¸ì¦ì„œ 요청 + PkiPath liudijimų marÅ¡rutas + PkiPath sertifikÄta ceļš + PkiPath-certificatiepad + Åšcieżka certyfikacji PkiPath + Pedido de certificação PkiPath + Cale certificare PkiPath + путь Ñертификации PkiPath + Cesta k certifikátu PkiPath + Datoteka poti potrdila PkiPath + PkiPath-certifikatsekvens + шлÑÑ… Ñертифікації PkiPath + ÄÆ°á»ng dẫn cấp chứng nhận PkiPath + PkiPath è¯ä¹¦ç›®å½• + PkiPath 憑證路徑 + + + + PS document + مستند PS + Dakument PS + Документ — PS + document PS + Dokument PS + PS-dokument + PS-Dokument + έγγÏαφο PS + PS document + PS-dokumento + documento PS + PS dokumentua + PS-asiakirja + PS skjal + document PS + cáipéis PS + documento PS + מסמך PS + PS dokumentum + Dokumen PS + Documento PS + PS ドキュメント + PS құжаты + PS 문서 + PS dokumentas + PS dokuments + PS-dokument + PS-document + PS-dokument + Dokument PS + Documento PS + Document PS + документ PS + Dokument PS + Dokument PS + Dokument PS + PS-dokument + PS belgesi + документ PS + Tài liệu PS + PS 文档 + Ps 文件 + PS + PostScript + + + + + + + + + + Plucker document + مستند Plucker + Dakument Plucker + Документ — Plucker + document Plucker + Dokument Plucker + Pluckerdokument + Plucker-Dokument + έγγÏαφο Plucker + Plucker document + Plucker-dokumento + documento de Plucker + Plucker dokumentua + Plucker-asiakirja + Plucker skjal + document Plucker + cáipéis Plucker + documento de Plucker + מסמך של Plucker + Plucker dokumentum + Dokumen Plucker + Documento Plucker + Plucker ドキュメント + Plucker құжаты + Plucker 문서 + Plucker dokumentas + Plucker dokuments + Plucker-dokument + Plucker-document + Plucker-dokument + Dokument Plucker + Documento do Plucker + Document Plucker + документ Plucker + Dokument Plucker + Dokument Plucker + Dokument Plucker + Plucker-dokument + Plucker belgesi + документ Plucker + Tài liệu Plucker + Plucker 文档 + Plucker 文件 + + + + + + + RELAX NG XML schema + مخطط RELAX NG XML + Схема за XML — RELAX NG + esquema XML RELAX NG + Schéma RELAX NG XML + RELAX NG XML-skema + RELAX NG XML-Schema + σχήμα RELAX NG XML + RELAX NG XML schema + Esquema XML RELAX NG + RELAX NG XML-skeema + schéma XML RELAX NG + scéimre XML RELAX NG + Esquema XML RELAX NG + סכנת RELAX NG XML + RELAX NG XML shema + RELAX NG XML-séma + Skema XML RELAX NG + Schema XML RELAX NG + RELAX NG XML スキーマ + RELAX NG XML ÑұлбаÑÑ‹ + RELAX NG XML 스키마 + RELAX NG XML schema + RELAX NG XML shÄ“ma + RELAX NG XML schema + Schemat XML RELAX NG + Esquema XML de RELAX NG + Schemă RELAX NG XML + XML-Ñхема RELAX NG + XML schéma RELAX NG + Datoteka shema RELAX NG XML + RELAX NG XML-schema + XML-Ñхема RELAX NG + RELAX NG XML æ¨¡å¼ + RELAX NG XML schema + RELAX NG + REgular LAnguage for XML Next Generation + + + + + + + RTF document + مستند RTF + Dakument RTF + Документ — RTF + document RTF + Dokument RTF + RTF-dokument + RTF-Dokument + έγγÏαφο RTF + RTF document + RTF-dokumento + documento RTF + RTF dokumentua + RTF-asiakirja + RTF skjal + document RTF + cáipéis RTF + documento RTF + מסמך RTF + RTF dokument + RTF dokumentum + Dokumen RTF + Documento RTF + RTF ドキュメント + RTF құжаты + RTF 문서 + RTF dokumentas + RTF dokuments + RTF-dokument + RTF-document + TRF-dokument + Dokument RTF + Documento RTF + Document RTF + документ RTF + Dokument RTF + Dokument RTF + Dokument RTF + RTF-dokument + документ RTF + Tài liệu RTF + RTF 文档 + RTF 文件 + RTF + Rich Text Format + + + + + + + + + + Sieve mail filter script + سكربت مرشح بريد Sieve + Skrypt filtravaÅ„nia poÅ¡ty Sieve + Скрипт-филтър за преÑÑване на поща + script de filtre de correu Sieve + Skript poÅ¡tovního filtru Sieve + Sieve e-post-filterprogram + Sieve-E-Mail-Filterskript + σενάÏιο φιλτÏαÏίσματος αλληλογÏαφίας Sieve + Sieve mail filter script + script de filtro de correo Sieve + Sieve posta-iragazki script-a + Sieve-postinsuodatuskomentotiedosto + script de filtrage de courriel Sieve + script scagaire phost Sieve + Script de filtro de correo Sieve + תסריט סינון דו×ר של Sieve + Sieve levélszűrÅ‘ parancsfájl + Skrip filter surat Sieve + Script filtro posta Sieve + Sieve メールフィルタスクリプト + Sieve пошталық фильтр Ñценарийі + Sieve ë©”ì¼ í•„í„° 스í¬ë¦½íŠ¸ + Sieve paÅ¡to filtro scenarijus + Sieve pasta filtra skripts + Sieve e-postfilter skript + Sieve mailfilter-script + Sieve e-postfilterskript + Skrypt filtra poczty Sieve + Script de filtro de mensagens do Sieve + Script filtrare email Sieve + Ñценарий почтового фильтра Sieve + Skript poÅ¡tového filtra Sieve + Skriptna datoteka Sieve poÅ¡tnega filtra + Script filtrim poste Sieve + Sieve-epostfilterskript + Ñкрипт поштового фільтру Sieve + Văn lệnh lá»c thÆ° Sieve + Sieve 邮件过滤脚本 + Sieve 郵件éŽæ¿¾æŒ‡ä»¤ç¨¿ + + + + + + SMIL document + مستند SMIL + Dakument SMIL + Документ — SMIL + document SMIL + Dokument SMIL + SMIL-dokument + SMIL-Dokument + έγγÏαφο SMIL + SMIL document + SMIL-dokumento + documento SMIL + SMIL dokumentua + SMIL-asiakirja + SMIL skjal + document SMIL + cáipéis SMIL + documento SMIL + מסמך SMIL + SMIL dokument + SMIL dokumentum + Dokumen SMIL + Documento SMIL + SMIL ドキュメント + SMIL құжаты + SMIL 문서 + SMIL dokumentas + SMIL dokuments + SMIL-dokument + SMIL-document + SMIL-dokument + Dokument SMIL + Documento SMIL + Document SMIL + документ SMIL + Dokument SMIL + Dokument SMIL + Dokument SMIL + SMIL-dokument + SMIL belgesi + документ SMIL + Tài liệu SMIL + SMIL 文档 + SMIL 文件 + SMIL + Synchronized Multimedia Integration Language + + + + + + + + + + + + + + + + WPL playlist + قائمة تشغيل WPL + СпиÑък за изпълнение — WPL + llista de reproducció WPL + Seznam skladeb WPL + WPL-afspilningsliste + WPL-Wiedergabeliste + λίστα αναπαÏαγωγής WPL + WPL playlist + WPL-ludlisto + lista de reproducción WPL + WPL erreprodukzio-zerrenda + WPL-soittolista + WPL avspælingarlisti + liste de lecture WPL + seinmliosta WPL + lista de reprodución WPL + רשימת השמעה WPL + WPL popis za reprodukciju + WPL-lejátszólista + Senarai putar WPL + Scaletta WPL + WPL å†ç”Ÿãƒªã‚¹ãƒˆ + WPL ойнау тізімі + WPL ìž¬ìƒ ëª©ë¡ + WPL grojaraÅ¡tis + WPL repertuÄrs + WPL-afspeellijst + Lista odtwarzania WPL + Lista de reprodução do WPL + Listă redare WPL + ÑпиÑок воÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ WPL + Zoznam skladieb WPL + Seznam predvajanja WPL + WPL-spellista + ÑпиÑок Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ WPL + Danh mục nhạc WPL + WPL 播放列表 + WPL 播放清單 + WPL + Windows Media Player Playlist + + + + + + + + SQLite2 database + قاعدة بيانات SQLite2 + Baza źviestak SQLite2 + База от данни — SQLite2 + base de dades SQLite2 + Databáze SQLite2 + SQLite2-database + SQLite2-Datenbank + βάση δεδομένων SQLite2 + SQLite2 database + SQLite2-datumbazo + base de datos SQLite2 + SQLite2 datu-basea + SQLite2-tietokanta + SQLite2 dátustovnur + base de données SQLite2 + bunachar sonraí SQLite2 + base de datos SQLite2 + בסיס מידע של SQLite2 + SQLite2 baza podataka + SQLite2 adatbázis + Basis data SQLite2 + Database SQLite2 + SQLite2 データベース + SQLite2 дерекқоры + SQLite2 ë°ì´í„°ë² ì´ìŠ¤ + SQLite2 duomenų bazÄ— + SQLite2 datubÄze + SQLite2-database + SQLite2-gegevensbank + SQLite2-database + Baza danych SQLite2 + Banco de dados do SQLite2 + Bază de date SQLite2 + база данных SQLite2 + Databáza SQLite2 + Podatkovna zbirka SQLite2 + Bazë me të dhëna SQLite2 + SQLite2-databas + SQLite2 veritabanı + База даних SQLite2 + CÆ¡ sở dữ liệu SQLite2 + SQLite2 æ•°æ®åº“ + SQLite2 資料庫 + + + + + + SQLite3 database + قاعدة بيانات SQLite3 + Baza źviestak SQLite3 + База от данни — SQLite3 + base de dades SQLite3 + Databáze SQLite3 + SQLite3-database + SQLite3-Datenbank + βάση δεδομένων SQLite3 + SQLite3 database + SQLite3-datumbazo + base de datos SQLite3 + SQLite3 datu-basea + SQLite3-tietokanta + SQLite3 dátustovnur + base de données SQLite3 + bunachar sonraí SQLite3 + base de datos SQLite3 + בסיס מידע של SQLite3 + SQLite3 baza podataka + SQLite3 adatbázis + Basis data SQLite3 + Database SQLite3 + SQLite3 データベース + SQLite3 дерекқоры + SQLite3 ë°ì´í„°ë² ì´ìŠ¤ + SQLite3 duomenų bazÄ— + SQLite3 datubÄze + SQLite3-database + SQLite3-gegevensbank + SQLite3-database + Baza danych SQLite3 + Banco de dados do SQLite3 + Bază de date SQLite3 + база данных SQLite3 + Databáza SQLite3 + Podatkovna zbirka SQLite3 + Bazë me të dhëna SQLite3 + SQLite3-databas + SQLite3 veritabanı + база даних SQLite3 + CÆ¡ sở dữ liệu SQLite3 + SQLite3 æ•°æ®åº“ + SQLite3 資料庫 + + + + + + GEDCOM family history + تاريخ عائلة GEDCOM + Siamiejnaja historyja GEDCOM + РодоÑловно дърво — GEDCOM + història familiar GEDCOM + Rodokmen GEDCOM + GEDCOM-familiehistorie + GEDCOM-Stammbaum + οικογενειακό ιστοÏικό GEDCOM + GEDCOM family history + historia familiar GEDCOM + GEDCOM famili historia + GEDCOM-sukuhistoria + GEDCOM familjusøga + généalogie GEDCOM + stair theaghlach GEDCOM + historial de familia GEDCOM + היסטוריה משפחתית של GEDCOM + GEDCOM obiteljska povijest + GEDCOM családtörténet + Sejarah keluarga GEDCOM + Cronologia famiglia GEDCOM + GEDCOM 家系図データ + GEDCOM áƒáƒ¯áƒáƒ®áƒ˜áƒ¡ ისტáƒáƒ áƒ˜áƒ + GEDCOM отбаÑÑ‹ тарихы + GEDCOM 가족 ë‚´ë ¥ + GEDCOM Å¡eimos istorija + GEDCOM Ä£imenes vÄ“sture + GEDCOM-familiehistorikk + GEDCOM-stamboom + GEDCOM-familehistorie + Plik historii rodziny GEDCOM + Histórico familiar do GEDCOM + Tablou genealogic GEDCOM + иÑÑ‚Ð¾Ñ€Ð¸Ñ Ñемьи GEDCOM + Rodokmeň GEDCOM + Datoteka družinske zgodovine GEDCOM + Kronollogji familje GEDCOM + GEDCOM-släktträd + Ñ–ÑÑ‚Ð¾Ñ€Ñ–Ñ Ñ€Ð¾Ð´Ð¸Ð½Ð¸ GEDCOM + Lịch sá»­ gia đình GEDCOM + GEDCOM 家谱 + GEDCOM 家æ—å² + GEDCOM + GEnealogical Data COMmunication + + + + + + + + + + Flash video + Flash مرئي + Videa Flash + Видео — Flash + vídeo de Flash + Video Flash + Flashvideo + Flash-Video + βίντεο Flash + Flash video + Flash-video + vídeo Flash + Flash bideoa + Flash-video + Flash video + vidéo Flash + físeán Flash + vídeo Flash + ויד×ו של פל×ש + Flash video + Flash videó + Video Flash + Video Flash + Flash å‹•ç”» + Flash-ის ვიდერ+ Flash видеоÑÑ‹ + Flash 비디오 + Flash vaizdo įraÅ¡as + Flash video + Flash-film + Flash-video + Flash-video + Plik wideo Flash + Vídeo Flash + Video Flash + видео Flash + Video Flash + Video datoteka Flash + Video Flash + Flash-video + відеокліп Flash + Ảnh Ä‘á»™ng Flash + Flash 影片 + Flash 視訊 + + + + + + + + + + + JavaFX video + Видео — JavaFX + vídeo JavaFX + Video JavaFX + JavaFX-video + JavaFX-Video + βίντεο JavaFX + JavaFX video + JavaFX-video + vídeo JavaFX + JavaFX-video + JavaFX video + vidéo JavaFX + físeán JavaFX + vídeo JavaFX + ויד×ו JavaFX + JavaFX video + JavaFX videó + Video JavaFX + Video JavaFX + JavaFX å‹•ç”» + JavaFX аудиоÑÑ‹ + JavaFX 비디오 + JavaFX video + JavaFX video + Plik wideo JavaFX + Vídeo JavaFX + Video JavaFX + видео JavaFX + Video JavaFX + Video JavaFX + JavaFX-video + відеокліп JavaFX + JavaFX 视频 + JavaFX 視訊 + + + + + + + + + + SGF record + تسجيلة SGF + Zapisanaja hulnia SGF + Ð—Ð°Ð¿Ð¸Ñ â€” SGF + registre SGF + Záznam SGF + SGF-optagelse + SGF-Aufzeichnung + εγγÏαφή SGF + SGF record + grabación SGF + SGF erregistroa + SGF-nauhoitus + SGF met + partie SGF + taifead SGF + Grabación SGF + הקלטת SGF + SGF zapis + SGF pontszám + Catatan SGF + Registrazione SGF + SGF レコード + SGF жазбаÑÑ‹ + SGF 기ë¡íŒŒì¼ + SGF įraÅ¡as + SGF ieraksts + SGF-oppføring + SGF-record + SGF-logg + Zapis gry SGF + Gravação SGF + ÃŽnregistrare SGF + запиÑÑŒ SGF + Záznam SGF + Datoteka shranjene igre SGF + Regjistrim SGF + SGF-protokoll + SGF kaydı + Ð·Ð°Ð¿Ð¸Ñ SGF + Mục ghi SGF + SGF 记录 + SGF 紀錄 + SGF + Smart Game Format + + + + + + + + + + XLIFF translation file + مل٠ترجمة XLIFF + FajÅ‚ pierakÅ‚adu XLIFF + Превод — XLIFF + fitxer traducció XLIFF + Soubor pÅ™ekladu XLIFF + XLIFF-oversættelsesfil + XLIFF-Ãœbersetzung + αÏχείο Ï€Ïος μετάφÏαση XLIFF + XLIFF translation file + archivo de traducción XLIFF + XLIFF itzulpen-fitxategia + XLIFF-käännöstiedosto + XLIFF týðingarfíla + fichier de traduction XLIFF + comhad aistrithe XLIFF + ficheiro de tradución XLIFF + קובץ ×ª×¨×’×•× CLIFF + XLIFF datoteka prijevoda + XLIFF fordítási fájl + Berkas terjemahan XLIFF + File traduzione XLIFF + XLIFF 翻訳ファイル + XLIFF аударма файлы + XLIFF 번역 íŒŒì¼ + XLIFF vertimo failas + XLIFF tulkoÅ¡anas datne + XLIFF-oversettelsesfil + XLIFF-vertalingsbestand + XLIFF-omsetjingsfil + Plik tÅ‚umaczenia XLIFF + Arquivo de tradução XLIFF + FiÈ™ier de traducere XLIFF + файл перевода XLIFF + Súbor prekladu XLIFF + Datoteka prevoda XLIFF + File përkthimesh XLIFF + XLIFF-översättningsfil + файл перекладу XLIFF + Tập tin dịch XLIFF + XLIFF 消æ¯ç¿»è¯‘文件 + XLIFF 翻譯檔 + XLIFF + XML Localization Interchange File Format + + + + + + + + + + + YAML document + مستند YAML + Документ — YAML + document YAML + Dokument YAML + YAML-dokument + YAML-Dokument + έγγÏαφο YAML + YAML document + YAML-dokumento + documento YAML + YAML-asiakirja + YAML skjal + document YAML + cáipéis YAML + documento YAML + מסמך YAML + YAML-dokumentum + Dokumen YAML + Documento YAML + YAML ドキュメント + YAML құжаты + YAML 문서 + YAML dokumentas + YAML dokuments + YAML document + Dokument YAML + Documento YAML + Document YAML + документ YAML + Dokument YAML + Dokument YAML + YAML-dokument + YAML belgesi + документ YAML + YAML 文档 + YAML 文件 + YAML + YAML Ain't Markup Language + + + + + + + + + + + + Corel Draw drawing + تصميم Corel Draw + Corel Draw çəkimi + Rysunak Corel Draw + Чертеж — Corel Draw + dibuix de Corel Draw + Kresba Corel Draw + Darlun Corel Draw + Corel Draw-tegning + Corel-Draw-Zeichnung + σχέδιο Corel Draw + Corel Draw drawing + grafikaĵo de Corel Draw + dibujo de Corel Draw + Corel Draw-eko marrazkia + Corel Draw -piirros + Corel Draw tekning + dessin Corel Draw + líníocht Corel Draw + debuxo de Corel Draw + ציור של Corel Draw + Corel Draw crtež + Corel Draw-rajz + Gambar Corel Draw + Disegno Corel Draw + Corel Draw ドロー + Corel Draw-ის ნáƒáƒ®áƒáƒ–ი + Corel Draw Ñуреті + ì½”ë  ë“œë¡œìš° 드로잉 + Corel Draw pieÅ¡inys + Corel Draw zÄ«mÄ“jums + Lukisan Corel Draw + Corel Draw-tegning + Corel Draw-tekening + Corel Draw-teikning + Rysunek Corel Draw + desenho Corel Draw + Desenho do Corel Draw + Desen Corel Draw + изображение Corel Draw + Kresba Corel Draw + Datoteka risbe Corel Draw + Vizatim Corel Draw + Corel Draw цртеж + Corel Draw-teckning + малюнок Corel Draw + Bản vẽ Corel Draw + Corel Draw 图形 + Corel Draw 繪圖 + + + + + + + + + + + + + + + HPGL file + مل٠HPGL + FajÅ‚ HPGL + Файл — HPGL + fitxer HPGL + Soubor HPGL + HPGL-fil + HPGL-Datei + αÏχείο HPGL + HPGL file + HPGL-dosiero + archivo HPGL + HPGL fitxategia + HPGL-tiedosto + HPGL fíla + fichier HPGL + comhad HPGL + ficheiro HPGL + קובץ HGPL + HPGL datoteka + HPGL fájl + Berkas HPGL + File HPGL + HPGL ファイル + HPGL файлы + HPGL íŒŒì¼ + HPGL failas + HPGL datne + HPGL-fil + HPGL-bestand + HPGL-fil + Plik HPGL + Arquivo HPGL + FiÈ™ier HPGL + файл HPGL + Súbor HPGL + Datoteka HPGL + File HPGL + HPGL-fil + файл HPGL + Tập tin HPGL + HPGL 文件 + HPGL 檔案 + HPGL + HP Graphics Language + + + + + PCL file + مل٠PCL + FajÅ‚ PCL + Файл — PCL + fitxer PCL + Soubor PCL + PCL-fil + PCL-Datei + αÏχείο PCL + PCL file + PCL-dosiero + archivo PCL + PCL fitxategia + PCL-tiedosto + PCL fíla + fichier PCL + comhad PCL + ficheiro PCL + קובץ PCL + PCL fájl + Berkas PCL + File PCL + PCL ファイル + PCL файлы + PCL íŒŒì¼ + PCL failas + PCL datne + PCL-fil + PCL-bestand + PCL-fil + Plik PCL + Arquivo PCL + FiÈ™ier PCL + файл PCL + Súbor PCL + Datoteka PCL + File PCL + PCL-fil + PCL dosyası + файл PCL + Tập tin PCL + PCL 文件 + PCL 檔 + PCL + HP Printer Control Language + + + + + Lotus 1-2-3 spreadsheet + جدول Lotus 1-2-3 + Lotus 1-2-3 hesab cÉ™dvÉ™li + Raźlikovy arkuÅ¡ Lotus 1-2-3 + Таблица — Lotus 1-2-3 + full de càlcul de Lotus 1-2-3 + SeÅ¡it Lotus 1-2-3 + Taenlen Lotus 1-2-3 + Lotus 1-2-3-regneark + Lotus-1-2-3-Tabelle + λογιστικό φÏλλο Lotus 1-2-3 + Lotus 1-2-3 spreadsheet + Kalkultabelo de Lotus 1-2-3 + hoja de cálculo de Lotus 1-2-3 + Lotus 1-2-3 kalkulu-orria + Lotus 1-2-3 -taulukko + Lotus 1-2-3 rokniark + feuille de calcul Lotus 1-2-3 + scarbhileog Lotus 1-2-3 + folla de cálculo de Lotus 1-2-3 + גליון × ×ª×•× ×™× ×©×œ Lotus 1-2-3 + Lotus 1-2-3 proraÄunska tablica + Lotus 1-2-3-munkafüzet + Lembar sebar Lotus 1-2-3 + Foglio di calcolo Lotus 1-2-3 + Lotus 1-2-3 スプレッドシート + Lotus 1-2-3 Ñлектрондық кеÑтеÑÑ– + Lotus 1-2-3 스프레드시트 + Lotus 1-2-3 skaiÄialentÄ— + Lotus 1-2-3 izklÄjlapa + Hamparan Lotus 1-2-3 + Lotus 1-2-3 regneark + Lotus 1-2-3-rekenblad + Lotus 1-2-3 rekneark + Arkusz Lotus 1-2-3 + folha de cálculo Lotus 1-2-3 + Planilha do Lotus 1-2-3 + Foaie de calcul Lotus 1-2-3 + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° Lotus 1-2-3 + ZoÅ¡it Lotus 1-2-3 + Preglednica Lotus 1-2-3 + Fletë llogaritjesh Lotus 1-2-3 + Lotus 1-2-3 табеларни прорачун + Lotus 1-2-3-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Lotus 1-2-3 + Bảng tính Lotus 1-2-3 + Lotus 1-2-3 工作簿 + Lotus 1-2-3 試算表 + + + + + + + + + + + + + + + + + Lotus Word Pro + + + + + + + + JET database + قاعدة بيانات JET + Baza źviestak JET + База от данни — JET + base de dades JET + Databáze JET + JET-database + JET-Datenbank + βάση δεδομένων JET + JET database + JET-datumbazo + base de datos JET + JET datu-basea + JET-tietokanta + JET dátustovnur + base de données JET + bunachar sonraí JET + base de datos JET + מסד × ×ª×•× ×™× JET + JET baza podataka + JET adatbázis + Basis data JET + Database JET + JET データベース + JET дерекқоры + JET ë°ì´í„°ë² ì´ìŠ¤ + JET duomenų bazÄ— + JET datubÄze + JET-database + JET-gegevensbank + JET-database + Baza Danych JET + Banco de dados JET + Bază de date JET + база данных JET + Databáza JET + Podatkovna zbirka JET + Bazë me të dhëna JET + JET-databas + JET veritabanı + База даних JET + CÆ¡ sở dữ liệu JET + JET æ•°æ®åº“ + JET 資料庫 + JET + Joint Engine Technology + + + + + + + + + + + + + + + Microsoft Cabinet archive + أرشي٠Microsoft Cabinet + Ðрхив — Microsoft Cabinet + arxiu Cabinet de Microsoft + Archiv Microsoft Cabinet + Microsoft Cabinet-arkiv + Microsoft-Cabinet-Archiv + συμπιεσμένο αÏχείο Microsoft Cabinet + Microsoft Cabinet archive + archivador Microsoft Cabinet + Microsoft Cabinet artxiboa + Microsoft Cabinet -arkisto + Microsoft Cabinet skjalasavn + archive Cab Microsoft + cartlann Microsoft Cabinet + arquivo de Microsoft Cabinet + ×רכיון CAB (מיקרוסופט) + Microsoft Cabinet arhiva + Microsoft Cabinet archívum + Arsip Microsoft Cabinet + Archivio Microsoft Cabinet + Microsoft Cabinet アーカイブ + Microsoft-ის Cabinet áƒáƒ áƒ¥áƒ˜áƒ•áƒ˜ + Microsoft Cabinet архиві + 마ì´í¬ë¡œì†Œí”„트 ìºë¹„ë‹› ë¬¶ìŒ + Microsoft Cabinet archyvas + Microsoft kabineta arhÄ«vs + Microsoft Cabinet-archief + Archiwum Microsoft Cabinet + Pacote do Microsoft Cabinet + Arhivă Microsoft Cabinet + архив Microsoft Cabinet + Archív Microsoft Cabinet + Datoteka arhiva Microsoft Cabinet + Microsoft Cabinet-arkiv + Microsoft Cabinet arÅŸivi + архів Cabinet Microsoft + Kho lÆ°u Cabinet Microsoft + Microsoft CAB 归档文件 + 微軟 Cabinet å°å­˜æª” + + + + + + + + + Excel spreadsheet + جدول Excel + Raźlikovy akruÅ¡ Excel + Таблица — Excel + full de càlcul d'Excel + SeÅ¡it Excel + Excelregneark + Excel-Tabelle + φυÌλλο εÏγασιÌας Excel + Excel spreadsheet + Excel-kalkultabelo + hoja de cálculo de Excel + Excel kalkulu-orria + Excel-taulukko + Excel rokniark + feuille de calcul Excel + scarbhileog Excel + folla de cálculo de Excel + גליון × ×ª×•× ×™× ×©×œ ×קסל + Excel proraÄunska tablica + Excel táblázat + Lembar sebar Excel + Foglio di calcolo Excel + Excel スプレッドシート + Excel-ის ცხრილი + Excel Ñлектрондық кеÑтеÑÑ– + ì—‘ì…€ 스프레드시트 + Excel skaiÄialentÄ— + Excel izklÄjlapa + Excel regneark + Excel-rekenblad + Excel-rekneark + Arkusz Excel + Planilha do Excel + Foaie de calcul Excel + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° Excel + ZoÅ¡it Excel + Razpredelnica Microsoft Excel + Fletë llogaritje Excel + Excel-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Excel + Bảng tính Excel + Microsoft Excel 工作簿 + Excel 試算表 + + + + + + + + + + + + + + + + + + Excel add-in + ПриÑтавка — Excel + complement d'Excel + DoplnÄ›k aplikace Excel + Excel-tilføjelse + Excel Add-in + Ï€Ïόσθετο Excel + Excel add-in + Complemento de Excel + Excel-lisäosa + complément Excel + complemento de Excel + תוסף של Excel + Excel prikljuÄak + Excel bÅ‘vítmény + Add-in Excel + Add-in Excel + Excel アドイン + Excel-ის დáƒáƒ›áƒáƒ¢áƒ”ბრ+ Excel қоÑымшаÑÑ‹ + ì—‘ì…€ 추가 기능 + Excel pievienojumprogramma + Excel add-in + Dodatek Excel + Suplemento do Excel + дополнение Excel + Vstavek Excel + додаток Excel + Excel 附加组件 + Excel 增益集 + + + + + + Excel 2007 binary spreadsheet + Таблица — Excel 2007, двоична + full de càlcul binari d'Excel 2007 + Binární formát seÅ¡itu Excel 2007 + Binært Excel 2007-regneark + Excel 2007-Tabelle (binär) + Excel 2007 binary spreadsheet + Hoja de cálculo de Excel 2007 + feuille de calcul binaire Excel 2007 + ficheiro binario de folla de cálculo Excel 2007 + גיליון × ×ª×•× ×™× ×‘×™× ×¨×™ של Excel 2007 + Excel 2007 binarna proraÄunska tablica + Excel 2007 bináris táblázat + Lembar kerja biner Excel 2007 + Foglio di calcolo binario Excel 2007 + Excel 2007 ãƒã‚¤ãƒŠãƒªã‚¹ãƒ—レッドシート + Excel 2007-ის ბინáƒáƒ áƒ£áƒšáƒ˜ ცხრილი + Excel 2007 бинарды кеÑтеÑÑ– + ì—‘ì…€ 2007 ë°”ì´ë„ˆë¦¬ 스프레드시트 + Excel 2007 binÄrÄ izklÄjlapa + Excel 2007 binary spreadsheet + Binarny arkusz Excel 2007 + Planilha binária do Excel 2007 + Ð´Ð²Ð¾Ð¸Ñ‡Ð½Ð°Ñ ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° Excel 2007 + Binarna preglednica Excel 2007 + бінарна електронна Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Excel 2007 + Excel 2007 二进制工作表 + Excel 2007 二進ä½è©¦ç®—表 + + + + + + Excel macro-enabled spreadsheet + Таблица — Excel, Ñ Ð¼Ð°ÐºÑ€Ð¾Ñи + full de càlcul amb macros d'Excel + SeÅ¡it Excel s podporou maker + Makro-aktiveret Excel-regneark + Excel-Tabelle mit aktivierten Makros + φÏλο εÏγασίας Excel με ενεÏγοποιημένες μακÏοεντολές + Excel macro-enabled spreadsheet + Hoja de cálculo con macros activados de Excel + feuille de calcul Excel avec macros + folla de cálculo de Excel con macros activadas + גיליון × ×ª×•× ×™× ×¢× ×ª×›×•× ×•×ª מקרו פעילות של Excel + Excel proraÄunska tablica s omogućenim makro naredbama + Excel makrókat tartalmazó táblázat + Lembar kerja Excel dengan makro + Foglio di calcolo Excel con macro abilitate + Excel マクロ有効スプレッドシート + Excel-ის მáƒáƒ™áƒ áƒáƒ¡áƒ˜áƒáƒœáƒ˜ ცხრილი + макроÑтары Ñ–Ñке қоÑылған Excel кеÑтеÑÑ– + ì—‘ì…€ 매í¬ë¡œ 사용 스프레드시트 + Excel izklÄjlapa ar makrosiem + Excel macro-enabled spreadsheet + Arkusz z wÅ‚Ä…czonymi makrami Excel + Planilha do Excel com macro ativada + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° Excel Ñ Ð²ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ñ‹Ð¼Ð¸ макроÑами + Preglednica Excel z omogoÄenimi makri + електронна Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Excel з увімкненими макроÑами + Excel å¯ç”¨å®çš„工作表 + Excel 巨集啟用試算表 + + + + + + Excel macro-enabled spreadsheet template + Шаблон за таблици — Excel, Ñ Ð¼Ð°ÐºÑ€Ð¾Ñи + plantilla de full de càlcul amb macros d'Excel + Å ablona seÅ¡itu Excel s podporou maker + Makro-aktiveret Excel-regnearksskabelon + Excel-Tabellenvorlage mit aktivierten Makros + Ï€Ïότυπο φÏλλο εÏγασίας Excel με ενεÏγοποιημένες μακÏοεντολές + Excel macro-enabled spreadsheet template + Plantilla de hoja de cálculo con macros activados de Excel + modèle de feuille de calcul Excel avec macros + modelo de folla de cálculo de Excel con macros activadas + תבנית של גיליון × ×ª×•× ×™× ×¢× ×ª×›×•× ×•×ª מקרו פעילות של Excel + Excel predložak proraÄunske tablice s omogućenim makro naredbama + Excel makrókat tartalmazó táblázatsablon + Templat lembar kerja Excel dengan makro + Modello foglio di calcolo Excel con macro abilitate + Excel マクロ有効スプレッドシートテンプレート + Excel-ის მáƒáƒ™áƒ áƒáƒ¡áƒ˜áƒáƒœáƒ˜ ცხრილის შáƒáƒ‘ლáƒáƒœáƒ˜ + макроÑтары Ñ–Ñке қоÑылған Excel кеÑтеÑінің үлгіÑÑ– + ì—‘ì…€ 매í¬ë¡œ 사용 스프레드시트 ì„œì‹ + Excel izklÄjlapas ar makrosiem veidne + Excel macro-enabled spreadsheet sjabloon + Szablon arkusza z wÅ‚Ä…czonymi makrami Excel + Módulo de planilha do Excel com macro ativada + шаблон Ñлектронной таблицы Excel Ñ Ð²ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ñ‹Ð¼Ð¸ макроÑами + Predloga preglednice Excel z omogoÄenimi makri + шаблон електронної таблиці Excel з увімкненими макроÑами + Excel å¯ç”¨å®çš„å·¥ä½œè¡¨æ¨¡æ¿ + Excel 巨集啟用試算表範本 + + + + + + PowerPoint presentation + عرض تقديمي PowerPoint + Prezentacyja PowerPoint + ÐŸÑ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ â€” PowerPoint + presentació de PowerPoint + Prezentace PowerPoint + PowerPoint-præsentation + PowerPoint-Präsentation + παÏουσιÌαση PowerPoint + PowerPoint presentation + PowerPoint-prezentaĵo + presentación de PowerPoint + PowerPoint aurkezpena + PowerPoint-esitys + PowerPoint framløga + présentation PowerPoint + láithreoireacht PowerPoint + presentación de PowerPoint + מצגת PowerPoint + PowerPoint prezentacija + PowerPoint prezentáció + Presentasi PowerPoint + Presentazione PowerPoint + PowerPoint プレゼンテーション + PowerPoint презентациÑÑÑ‹ + 파워í¬ì¸íŠ¸ 프리젠테ì´ì…˜ + PowerPoint pateiktis + PowerPoint prezentÄcija + PowerPoint-presentasjon + PowerPoint-presentatie + PowerPoint-presentasjon + Prezentacja PowerPoint + Apresentação do PowerPoint + Prezentare PowerPoint + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ PowerPoint + Prezentácia PowerPoint + Predstavitev Microsoft PowerPoint + Prezantim PowerPoint + PowerPoint-presentation + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ PowerPoint + Trình diá»…n PowerPoint + Microsoft PowerPoint 演示文稿 + PowerPoint ç°¡å ± + + + + + + + + + + + PowerPoint add-in + ПриÑтавка — PowerPoint + complement de + DoplnÄ›k PowerPoint + PowerPoint-tilføjelse + PowerPoint Add-in + Ï€Ïόσθετο PowerPoint + PowerPoint add-in + Complemento de PowerPoint + PowerPoint-lisäosa + complément PowerPoint + complemento de PowerPoint + תוסף של PowerPoint + PowerPoint prikljuÄak + PowerPoint bÅ‘vítmény + Add-in PowerPoint + Add-in PowerPoint + PowerPoint アドイン + PowerPoint-ის დáƒáƒ›áƒáƒ¢áƒ”ბრ+ PowerPoint қоÑымшаÑÑ‹ + 파워í¬ì¸íŠ¸ 추가 기능 + PowerPoint pievienojumprogramma + PowerPoint add-in + Dodatek PowerPoint + Suplemento do PowerPoint + дополнение PowerPoint + Vstavek PowerPoint + додаток PowerPoint + PowerPoint 附加组件 + PowerPoint 增益集 + + + + + PowerPoint macro-enabled presentation + ÐŸÑ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ â€” PowerPoint, Ñ Ð¼Ð°ÐºÑ€Ð¾Ñи + presentació amb macros + Prezentace PowerPoint s podporou maker + Makro-aktiveret PowerPoint-præsentation + PowerPoint-Präsentation mit aktivierten Makros + παÏουσίαση PowerPoint με ενεÏγοποιημένες μακÏοεντολές + PowerPoint macro-enabled presentation + Presentación con macros activadas de PowerPoint + présentation PowerPoint avec macros + presentación con macros activadas de PowerPoint + מצגת של PowerPoint בעלת תכונות מקרו פעילות + PowerPoint prezentacija s omogućenim makro naredbama + PowerPoint makrókat tartalmazó bemutató + Presentasi PowerPoint dengan makro + Presentazione PowerPoint con macro abilitate + PowerPoint マクロ有効プレゼンテーション + PowerPoint-ის მáƒáƒ™áƒ áƒáƒ¡áƒ˜áƒáƒœáƒ˜ პრეზენტáƒáƒªáƒ˜áƒ + макроÑтары Ñ–Ñке қоÑылған PowerPoint презентациÑÑÑ‹ + 파워í¬ì¸íŠ¸ 매í¬ë¡œ 사용 프리젠테ì´ì…˜ + PowerPoint prezentÄcija ar makrosiem + PowerPoint macro-enabled presentatie + Prezentacja z wÅ‚Ä…czonymi makrami PowerPoint + Apresentação do PowerPoint com macro ativada + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ PowerPoint Ñ Ð²ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ñ‹Ð¼Ð¸ макроÑами + Predstavitev PowerPoint z omogoÄenimi makri + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ PowerPoint з увімкненими макроÑами + PowerPoint å¯ç”¨å®çš„演示文稿 + PowerPoint 巨集啟用簡報 + + + + + + PowerPoint macro-enabled slide + Кадър — PowerPoint, Ñ Ð¼Ð°ÐºÑ€Ð¾Ñи + dispositiva amb macros + Snímek PowerPoint s podporou maker + Makro-aktiveret PowerPoint-slide + PowerPoint-Folie mit aktivierten Makros + σλάιντ PowerPoint με ενεÏγοποιημεÌνες μακÏοεντολεÌÏ‚ + PowerPoint macro-enabled slide + Diapositiva con macros activadas de PowerPoint + diapositive PowerPoint avec macros + Diapositiva con macros activadas de Powerpoint + שקופית של PowerPoint בעלת תכונות מקרו פעילות + PowerPoint slajd s omogućenim makro naredbama + PowerPoint makrókat tartalmazó dia + Slide PowerPoint dengan makro + Diapositiva PowerPoint con macro abilitate + PowerPoint マクロ有効スライド + PowerPoint-ის მáƒáƒ™áƒ áƒáƒ¡áƒ˜áƒáƒœáƒ˜ სლáƒáƒ˜áƒ“ი + макроÑтары Ñ–Ñке қоÑылған PowerPoint Ñлайды + 파워í¬ì¸íŠ¸ 매í¬ë¡œ 사용 슬ë¼ì´ë“œ + PowerPoint slaids ar makrosiem + PowerPoint macro-enabled dia + Slajd z wÅ‚Ä…czonymi makrami PowerPoint + Slide do PowerPoint com macro ativada + Ñлайд PowerPoint Ñ Ð²ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ñ‹Ð¼Ð¸ макроÑами + Prosojnica PowerPoint z omogoÄenimi makri + Ñлайд PowerPoint з увімкненими макроÑами + PowerPoint å¯ç”¨å®çš„å¹»ç¯ç‰‡ + PowerPoint 巨集啟用投影片 + + + + + + PowerPoint macro-enabled presentation + ÐŸÑ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ â€” PowerPoint, Ñ Ð¼Ð°ÐºÑ€Ð¾Ñи + presentació amb macros + Prezentace PowerPoint s podporou maker + Makro-aktiveret PowerPoint-præsentation + PowerPoint-Präsentation mit aktivierten Makros + παÏουσίαση PowerPoint με ενεÏγοποιημένες μακÏοεντολές + PowerPoint macro-enabled presentation + Presentación con macros activadas de PowerPoint + présentation PowerPoint avec macros + presentación con macros activadas de PowerPoint + מצגת של PowerPoint בעלת תכונות מקרו פעילות + PowerPoint prezentacija s omogućenim makro naredbama + PowerPoint makrókat tartalmazó bemutató + Presentasi PowerPoint dengan makro + Presentazione PowerPoint con macro abilitate + PowerPoint マクロ有効プレゼンテーション + PowerPoint-ის მáƒáƒ™áƒ áƒáƒ¡áƒ˜áƒáƒœáƒ˜ პრეზენტáƒáƒªáƒ˜áƒ + макроÑтары Ñ–Ñке қоÑылған PowerPoint презентациÑÑÑ‹ + 파워í¬ì¸íŠ¸ 매í¬ë¡œ 사용 프리젠테ì´ì…˜ + PowerPoint prezentÄcija ar makrosiem + PowerPoint macro-enabled presentatie + Prezentacja z wÅ‚Ä…czonymi makrami PowerPoint + Apresentação do PowerPoint com macro ativada + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ PowerPoint Ñ Ð²ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ñ‹Ð¼Ð¸ макроÑами + Predstavitev PowerPoint z omogoÄenimi makri + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ PowerPoint з увімкненими макроÑами + PowerPoint å¯ç”¨å®çš„演示文稿 + PowerPoint 巨集啟用簡報 + + + + + + PowerPoint macro-enabled presentation template + Шаблон за презентации — PowerPoint, Ñ Ð¼Ð°ÐºÑ€Ð¾Ñи + plantilla de presentació amb macros + Å ablona prezentace PowerPoint s podporou maker + Makro-aktiveret PowerPoint-præsentationsskabelon + PowerPoint-Präsentationsvorlage mit aktivierten Makros + Ï€Ïότυπη παÏουσίαση PowerPoint με ενεÏγοποιημένες μακÏοεντολές + PowerPoint macro-enabled presentation template + Plantilla de presentación con macros activadas de PowerPoint + modèle de présentation PowerPoint avec macros + modelo de presentación con macros activadas de PowerPoint + תבנית של מצגת של PowerPoint בעלת תכונות מקרו פעילות + PowerPoint predložak prezentacije s omogućenim makro naredbama + PowerPoint makrókat tartalmazó bemutatósablon + Templat presentasi PowerPoint dengan makro + Modello presentazione PowerPoint con macro abilitate + PowerPoint マクロ有効プレゼンテーションテンプレート + PowerPoint-ის მáƒáƒ™áƒ áƒáƒ¡áƒ˜áƒáƒœáƒ˜ პრეზენტáƒáƒªáƒ˜áƒ˜áƒ¡ შáƒáƒ‘ლáƒáƒœáƒ˜ + макроÑтары Ñ–Ñке қоÑылған PowerPoint презентациÑÑының үлгіÑÑ– + 파워í¬ì¸íŠ¸ 매í¬ë¡œ 사용 프리젠테ì´ì…˜ ì„œì‹ + PowerPoint prezentÄcijas ar makrosiem veidne + PowerPoint macro-enabled presentatie-sjabloon + Szablon prezentacji z wÅ‚Ä…czonymi makrami PowerPoint + Modelo de apresentação do PowerPoint com macro ativada + шаблон презентации PowerPoint Ñ Ð²ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ñ‹Ð¼Ð¸ макроÑами + Predloga predstavitve PowerPoint z omogoÄenimi makri + шаблон презентації PowerPoint з увімкненими макроÑами + PowerPoint å¯ç”¨å®çš„æ¼”ç¤ºæ–‡ç¨¿æ¨¡æ¿ + PowerPoint 巨集啟用簡報範本 + + + + + + Word macro-enabled document + Документ — Word, Ñ Ð¼Ð°ÐºÑ€Ð¾Ñи + document amb macros de Word + Dokument Word s podporou maker + Makro-aktiveret Word-dokument + Word-Dokument mit aktivierten Makros + εÌγγÏαφο Word με ενεÏγοποιημεÌνες μακÏοεντολεÌÏ‚ + Word macro-enabled document + Documento con macros activadas de Word + document Word avec macros + documento con macros activadas de Word + מסמך של Word בעל תכונות מקרו פעילות + Word dokument s omogućenim makro naredbama + Word makrókat tartalmazó dokumentum + Dokumen Word dengan makro + Documento Word con macro abilitate + Word マクロ有効文書 + Word-ის მáƒáƒ™áƒ áƒáƒ¡áƒ˜áƒáƒœáƒ˜ დáƒáƒ™áƒ£áƒ›áƒ”ნტი + макроÑтары Ñ–Ñке қоÑылған Word құжаты + 워드 매í¬ë¡œ 사용 문서 + Word dokuments ar makrosiem + Word macro-enabled document + Dokument z wÅ‚Ä…czonymi makrami Word + Documento do Word com macro ativada + документ Word Ñ Ð²ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ñ‹Ð¼Ð¸ макроÑами + Dokument Word z omogoÄenimi makri + документ Word з увімкненими макроÑами + Word å¯ç”¨å®çš„文档 + Word 巨集啟用文件 + + + + + + Word macro-enabled document template + Шаблон за документи — Word, Ñ Ð¼Ð°ÐºÑ€Ð¾Ñи + plantilla de document amb macros de Word + Å ablona dokumentu Word s podporou maker + Makro-aktiveret Word-dokumentskabelon + Word-Dokumentvorlage mit aktivierten Makros + Ï€ÏοÌτυπο έγγÏαφο Word με ενεÏγοποιημεÌνες μακÏοεντολεÌÏ‚ + Word macro-enabled document template + Plantilla de documento con macros activadas de Word + modèle de document Word avec macros + Plantilla de documento con macros activadas de Word + תבנית של מסמך של Word בעל תכונות מקרו פעילות + Word predložak dokumenta s omogućenim makro naredbama + Word makrókat tartalmazó dokumentumsablon + Templat dokumen Word dengan makro + Modello documento Word con macro abilitate + Word マクロ有効文書テンプレート + Word-ის მáƒáƒ™áƒ áƒáƒ¡áƒ˜áƒáƒœáƒ˜ დáƒáƒ™áƒ£áƒ›áƒ”ნტის შáƒáƒ‘ლáƒáƒœáƒ˜ + макроÑтары Ñ–Ñке қоÑылған Word құжатының үлгіÑÑ– + 워드 매í¬ë¡œ 사용 문서 ì„œì‹ + Word dokumenta ar makrosiem veidne + Word macro-enabled document sjabloon + Szablon dokumentu z wÅ‚Ä…czonymi makrami Word + Modelo de documento do Word com macro ativada + шаблон документа Word Ñ Ð²ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ñ‹Ð¼Ð¸ макроÑами + Predloga dokumenta Word z omogoÄenimi makri + шаблон документа Word з увімкненими макроÑами + Word å¯ç”¨å®çš„æ–‡æ¡£æ¨¡æ¿ + Word 巨集啟用文件範本 + + + + + + XPS document + مستند XPS + Dakument XPS + Документ — XPS + document XPS + Dokument XPS + XPS-dokument + XPS-Dokument + έγγÏαφο XPS + XPS document + XPS-dokumento + documento XPS + XPS dokumentua + XPS-asiakirja + XPS skjal + document XPS + cáipéis XPS + documento XPS + מסמך XPS + XPS dokument + XPS dokumentum + Dokumen XPS + Documento XPS + XPS ドキュメント + XPS құжаты + XPS 문서 + XPS dokumentas + XPS dokuments + XPS-dokument + XPS-document + XPS-dokument + Dokument XPS + Documento XPS + Document XPS + документ XPS + Dokument XPS + Dokument XPS + Dokument XPS + XPS-dokument + документ XPS + Tài liệu XPS + XPS 文档 + XPS 文件 + XPS + Open XML Paper Specification + + + + + + + + Microsoft Works document + مستند Microsoft Works + Dakument Microsoft Works + Документ — Microsoft Works + document Works de Microsoft + Dokument Microsoft Works + Microsoft Works-dokument + Microsoft-Works-Dokument + έγγÏαφο Microsoft Works + Microsoft Works document + documento de Microsoft Works + Microsoft Works dokumentua + Microsoft Works -asiakirja + Microsoft Works skjal + document Microsoft Works + cáipéis Microsoft Works + documento de Microsoft Works + מסמך Microsoft Works + Microsoft Works dokument + Microsoft Works dokumentum + Dokumen Microsoft Works + Documento Microsoft Works + Microsoft Works ドキュメント + Microsoft Works-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + Microsoft Works құжаты + 마ì´í¬ë¡œì†Œí”„트 Works 문서 + Microsoft Works dokumentas + Microsoft Works dokuments + Microsoft Works-dokument + Microsoft Works-document + Microsoft Works-dokument + Dokument Microsoft Works + Documento do Microsoft Works + Document Microsoft Works + документ Microsoft Works + Dokument Microsoft Works + Dokument Microsoft Works + Dokument Microsoft Works + Microsoft Works-dokument + Microsoft Works belgesi + документ Microsoft Works + Tài liệu Microsoft Works + Microsoft Works 文档 + 微軟 Works 文件 + + + + + + + + + + Microsoft Visio document + Документ — Microsoft Visio + document Visio de Microsoft + Microsoft Visio-dokument + Microsoft Visio-Dokument + έγγÏαφο Microsoft Visio + Microsoft Visio document + documento de Microsoft Visio + Microsoft Visio -asiakirja + document Microsoft Visio + Documento de Microsoft Visio + מסמך + Microsoft Visio dokument + Microsoft Visio dokumentum + Dokumen Microsoft Visio + Documento Microsoft Visio + Microsoft Visio ドキュメント + Microsoft Visio-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + Microsoft Visio құжаты + 마ì´í¬ë¡œì†Œí”„트 Visio 문서 + Microsoft Visio dokuments + Microsoft Visio document + Dokument Microsoft Visio + Documento do Microsoft Visio + документ Microsoft Visio + Dokument Microsoft Visio + документ Microsoft Visio + Microsoft Visio 文档 + Microsoft Visio文件 + + + + + + + + + Word document + مستند Word + Dakument Word + Документ — Word + document de Word + Dokument Word + Worddokument + Word-Dokument + εÌγγÏαφο Word + Word document + Word-dokumento + documento de Word + Word dokumentua + Word-asiakirja + Word skjal + document Word + cáipéis Word + documento de Word + מסמך Word + Word dokument + Word dokumentum + Dokumen Word + Documento Word + Word ドキュメント + Word құжаты + 워드 문서 + Word dokumentas + Word dokuments + Word-dokument + Word-document + Word-dokument + Dokument Word + Documento do Word + Document Word + документ Word + Dokument Word + Dokument Word + Dokument Word + Word-dokument + документ Word + Tài liệu Word + Microsoft Word 文档 + Word 文件 + + + + + + + + + + + + + + + + + + + + Word template + قالب Word + Å ablon Word + Шаблон за документи — Word + plantilla de Word + Å ablona Word + Wordskabelon + Word-Vorlage + Ï€Ïότυπο έγγÏαφο Word + Word template + Word-Åablono + plantilla de Word + Word txantiloia + Word-malli + Word formur + modèle Word + teimpléad Word + Plantilla de Word + תבנית Word + Word predložak + Word sablon + Templat Word + Modello Word + Word テンプレート + Word үлгіÑÑ– + 워드 ì„œì‹ + Word Å¡ablonas + Word veidne + Word-mal + Word-sjabloon + Word-mal + Szablon Word + Modelo do Word + Șablon Word + шаблон Word + Å ablóna Word + Predloga dokumenta Microsoft Word + Model Word + Word-mall + шаблон Word + Mẫu Word + Word æ¨¡æ¿ + Word 範本 + + + + + + GML document + GML + Geography Markup Language + + + + + + GNUnet search file + مل٠بحث GNUnet + fajÅ‚ poÅ¡uku GNUnet + Указател за Ñ‚ÑŠÑ€Ñене — GNUnet + fitxer de cerca GNUnet + Vyhledávací soubor GNUnet + GNunet-søgefil + GNUnet-Suchdatei + αÏχείο αναζήτησης GNUnet + GNUnet search file + archivo de búsqueda GNUnet + GNUnet bilaketako fitxategia + GNUnet-hakutiedosto + GNUnet leitifíla + fichier de recherche GNUnet + comhad cuardaigh GNUnet + ficheiro de busca de GNUnet + קובץ חיפוש של GNUnet + GNUnet datoteka pretrage + GNUnet keresési fájl + Berkas telusur GNUnet + File ricerca GNUnet + GNUnet 検索ファイル + GNUnet ძებნის ფáƒáƒ˜áƒšáƒ˜ + GNUnet іздеу файлы + GNUnet 검색 íŒŒì¼ + GNUnet paieÅ¡kos failas + GNUnet meklÄ“Å¡anas datne + GNUnet søkefil + GNUnet-zoekbestand + GNUnet-søkjefil + Plik wyszukiwania GNUnet + Arquivo de pesquisa do GNUnet + FiÈ™ier căutare GNUnet + файл поиÑка GNUnet + Vyhľadávací súbor GNUnet + Iskalna datoteka GNUnet + File kërkimi GNUnet + GNUnet-sökfil + файл пошуку GNUnet + Tập tin tìm kiếm GNUnet + GNUnet æœç´¢æ–‡ä»¶ + GNUnet æœå°‹æª”案 + + + + + + + TNEF message + رسالة TNEF + List TNEF + Съобщение — TNEF + missatge TNEF + Zpráva TNEF + TNEF-meddelelse + TNEF-Nachricht + μήνυμα TNEF + TNEF message + mensaje TNEF + TNEF mezua + TNEF-viesti + TNEF boð + message TNEF + teachtaireacht TNEF + mensaxe TNEF + הודעת TNEF + TNEF poruka + TNEF üzenet + Pesan TNEF + Messaggio TNEF + TNEF メッセージ + TNEF мәлімдемеÑÑ– + TNEF 메시지 + TNEF žinutÄ— + TNEF ziņojums + TNEF-melding + TNEF-bericht + TNEF-melding + Wiadomość TNEF + Mensagem TNEF + Mesaj TNEF + Ñообщение TNEF + Správa TNEF + Datoteka sporoÄila TNEF + Mesazh TNEF + TNEF-meddelande + Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ TNEF + Thông Ä‘iệp TNEF + TNEF 信件 + TNEF è¨Šæ¯ + TNEF + Transport Neutral Encapsulation Format + + + + + + + + + + StarCalc spreadsheet + جدول StarCalc + StarCalc hesab cÉ™dvÉ™li + Raźlikovy arkuÅ¡ StarCalc + Таблица — StarCalc + full de càlcul de StarCalc + SeÅ¡it StarCalc + Taenlen StarCalc + StarCalc-regneark + StarCalc-Tabelle + λογιστικό φÏλλο StarCalc + StarCalc spreadsheet + StarCalc-kalkultabelo + hoja de cálculo de StarCalc + StarCalc kalkulu-orria + StarCalc-taulukko + StarCalc rokniark + feuille de calcul StarCalc + scarbhileog StarCalc + folla de cálculo de StarCalc + גליון × ×ª×•× ×™× ×©×œ StarCalc + StarCalc proraÄunska tablica + StarCalc-munkafüzet + Lembar sebar StarCalc + Foglio di calcolo StarCalc + StarCalc スプレッドシート + StarCalc Ñлектрондық кеÑтеÑÑ– + StarCalc 스프레드시트 + StarCalc skaiÄialentÄ— + StarCalc izklÄjlapa + Hamparan StarCalc + StarCalc-regneark + StarCalc-rekenblad + StarCalc-rekneark + Arkusz StarCalc + folha de cálculo do StarCalc + Planilha do StarCalc + Foaie de calcul StarCalc + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° StarCalc + ZoÅ¡it StarCalc + Preglednica StarCalc + Fletë llogaritjesh StarCalc + StarCalc табеларни прорачун + StarCalc-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ StarCalc + Bảng tính StarCalc + STarCalc 工作簿 + StarCalc 試算表 + + + + + StarChart chart + مخطط StarChart + StarChart cÉ™dvÉ™li + Dyjahrama StarChart + Диаграма — StarChart + diagrama de StarChart + Graf StarChart + Siart StarChart + StarChart-diagram + StarChart-Diagramm + γÏάφημα StarChart + StarChart chart + StarChart-diagramo + gráfica de StarChart + StarChart diagrama + StarChart-kaavio + StarChart strikumynd + graphique StarChart + cairt StarChart + gráfica de StarChart + טבלה של StarChart + StarChart grafikon + StarChart-grafikon + Bagan StarChart + Grafico StarChart + StarChart ãƒãƒ£ãƒ¼ãƒˆ + StarChart диаграммаÑÑ‹ + StarCalc í‘œ + StarChart diagrama + StarChart diagramma + Carta StarChart + StarChart graf + StarChart-kaart + StarChart-graf + Wykres StarChart + gráfico do StarChart + Gráfico do StarChart + Diagramă StarChart + диаграмма StarChart + Graf StarChart + Datoteka grafikona StarChart + Grafik StarChart + StarChart графикон + StarChart-diagram + діаграма StarChart + Äồ thị StarChart + STarChart 图表 + StarChart 圖表 + + + + + StarDraw drawing + تصميم StarDraw + StarDraw çəkimi + Rysunak StarDraw + Чертеж — StarDraw + dibuix de StarDraw + Kresba StarDraw + Darlun StarDraw + StarDraw-tegning + StarDraw-Zeichnung + σχέδιο StarDraw + StarDraw drawing + StarDraw-grafikaĵo + dibujo de StarDraw + StarDraw marrazkia + StarDraw-piirros + StarDraw tekning + dessin StarDraw + líníocht StarDraw + debuxo de StarDraw + ציור של StarDrawing + StarDraw crtež + StarDraw-rajz + Gambar StarDraw + Disegno StarDraw + StarDraw ドロー + StarDraw Ñуреті + StarCalc 드로잉 + StarDraw pieÅ¡inys + StarDraw zÄ«mÄ“jums + Lukisan StarDraw + StarDraw tegning + StarDraw-tekening + StarDraw-teikning + Rysunek StarDraw + desenho do StarDraw + Desenho do StarDraw + Desen StarDraw + изображение StarDraw + Kresba StarDraw + Datoteka risbe StarDraw + Vizatim StarDraw + StarDraw drawing + StarDraw-teckning + малюнок StarDraw + Bản vẽ StarDraw + STarDraw 绘图 + StarDraw 繪圖 + + + + + StarImpress presentation + عرض تقديمي StarImpress + StarImpress tÉ™qdimatı + Prezentacyja StarImpress + ÐŸÑ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ â€” StarImpress + presentació de StarImpress + Prezentace StarImpress + Cyflwyniad StarImpress + StarImpress-præsentation + StarImpress-Präsentation + παÏουσίαση StarImpress + StarImpress presentation + StarImpress-prezentaĵo + presentación de StarImpress + StarImpress aurkezpena + StarImpress-esitys + StarImpress framløga + présentation StarImpress + láithreoireacht StarImpress + presentación de StarImpress + מצגת של StarImpress + StarImpress prezentacija + StarImpress-bemutató + Presentasi StarImpress + Presentazione StarImpress + StarImpress プレゼンテーション + StarImpress презентациÑÑÑ‹ + StarImpress 프리젠테ì´ì…˜ + StarImpress pateiktis + StarImpress prezentÄcija + Persembahan StarImpress + StarImpress-presentasjon + StarImpress-presentatie + StarImpress-presentasjon + Prezentacja StarImpress + apresentação do StarImpress + Apresentação do StarImpress + Prezentare StarImpress + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ StarImpress + Prezentácia StarImpress + Predstavitev StarImpress + Prezantim StarImpress + StarImpress презентација + StarImpress-presentation + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ StarImpress + Trình diá»…n StarImpress + STarImpress 演示文稿 + StarImpress 簡報檔 + + + + + + StarMail email + بريد StarMail الإلكتروني + Email StarMail + Електронно пиÑмо — StarMail + correu electrònic de StarMail + E-mail StarMail + StarMail-e-brev + StarMail-E-Mail + ηλ. μήνυμα StarMail + StarMail email + StarMail-retpoÅto + correo electrónico de StarMail + StarMail helb.el. + StarMail-sähköposti + StarMail t-postur + courriel StarMail + ríomhphost StarMail + Correo electrónico de StarMail + דו×"ל של StarMail + StarMail e-poÅ¡ta + StarMail e-mail + Email StarMail + Email StarMail + StarMail メール + StarMail Ñлектрондық хаты + StarMail ì „ìžìš°íŽ¸ + StarMail el. laiÅ¡kas + StarMail epasts + Emel StarMail + StarMail-melding + StarMail-e-mail + StarMail-fil + E-Mail StarMail + e-mail do StarMail + E-mail do StarMail + Email StarEmail + Ñлектронное пиÑьмо StarMail + E-mail StarMail + Datoteka poÅ¡te StarMail + Mesazh StarMail + StarMail пошта + StarMail-e-post + поштове Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ StarMail + ThÆ° Ä‘iện tá»­ StarMail + STarMail 电å­é‚®ä»¶ + StarMail 郵件 + + + + StarMath formula + صيغة StarMath + FormuÅ‚a StarMath + Формула — StarMath + fórmula de StarMath + Vzorec StarMath + StarMath-formel + StarMath-Formel + μαθηματικός Ï„Ïπος StarMath + StarMath formula + StarMath-formulo + fórmula de StarMath + StarMath formula + StarMath-kaava + StarMath frymil + formule StarMath + foirmle StarMath + fórmula de StarMath + נוסחה של StarMath + StarMath formula + StarMath-képlet + Formula StarMath + Formula StarMath + StarMath è¨ˆç®—å¼ + StarMath формулаÑÑ‹ + StarMath ìˆ˜ì‹ + StarMath formulÄ— + StarMath formula + Formula StarMath + StarMath-formel + StarMath-formule + StarMath-formel + FormuÅ‚a StarMath + fórmula do StarMath + Fórmula do StarMath + Formulă StarMath + формула StarMath + Vzorec StarMath + Datoteka formule StarMath + Formulë StarMath + StarMath формула + StarMath-formel + формула StarMath + Công thức StarMath + STarMath å…¬å¼ + StarMath å…¬å¼ + + + + + StarWriter document + مستند StarWriter + StarWriter sÉ™nÉ™di + Dakument StarWriter + Документ — StarWriter + document de StarWriter + Dokument StarWriter + Dogfen StarWriter + StarWriter-dokument + StarWriter-Dokument + έγγÏαφο StarWriter + StarWriter document + StarWriter-dokumento + documento de StarWriter + StarWriter dokumentua + StarWriter-asiakirja + StarWriter skjal + document StarWriter + cáipéis StarWriter + documento de StarWriter + מסמך של StarWriter + StarWriter dokument + StarWriter-dokumentum + Dokumen StarWriter + Documento StrarWriter + StarWriter ドキュメント + StarWriter құжаты + StarWriter 문서 + StarWriter dokumentas + StarWriter dokuments + Dokumen StarWriter + StarWriter-dokument + StarWriter-document + StarWriter document + Dokument StarWriter + documento do StarWriter + Documento do StarWriter + Document StarWriter + документ StarWriter + Dokument StarWriter + Dokument StarWriter + Dokument StarWriter + StarWriter документ + StarWriter-dokument + StarWriter belgesi + документ StarWriter + Tài liệu StarWriter + STarWriter 文档 + StarWriter 文件 + + + + + + + + + + OpenOffice Calc spreadsheet + جدول Calc المكتب المÙتوح + Raźlikovy arkuÅ¡ OpenOffice Calc + Таблица — OpenOffice Calc + full de càlcul d'OpenOffice Calc + SeÅ¡it OpenOffice Calc + OpenOffice Calc-regneark + OpenOffice-Calc-Tabelle + φυÌλλο εÏγασιÌας OpenOffice Calc + OpenOffice Calc spreadsheet + hoja de cálculo de OpenOffice Calc + OpenOffice.org Calc kalkulu-orria + OpenOffice Calc -taulukko + OpenOffice Calc rokniark + feuille de calcul OpenOffice Calc + scarbhileog OpenOffice Calc + folla de cálculo de OpenOffice Calc + גליון × ×ª×•× ×™× ×©×œ OpenOffice Calc + OpenOffice Calc táblázat + Lembar sebar OpenOffice Calc + Foglio di calcolo OpenOffice Calc + OpenOffice Calc スプレッドシート + OpenOffice Calc-ის ცხრილი + OpenOffice Calc Ñлектрондық кеÑтеÑÑ– + OpenOffice Calc 스프레드시트 + OpenOffice Calc skaiÄialentÄ— + OpenOffice Calc izklÄjlapa + OpenOffice Calc-regneark + OpenOffice.org Calc-rekenblad + OpenOffice Calc-rekneark + Arkusz kalkulacyjny OpenOffice.org Calc + Planilha do OpenOffice Calc + Foaie de calcul OpenOffice Calc + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° OpenOffice Calc + ZoÅ¡it OpenOffice Calc + Razpredelnica OpenOffice.org Calc + Fletë llogaritjesh OpenOffice Calc + OpenOffice Calc-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ OpenOffice Calc + Bảng tính Calc của OpenOffice.org + OpenOffice.org Calc 工作簿 + OpenOffice Calc 試算表 + + + + + + + + + + + + + OpenOffice Calc template + قالب Calc المكتب المÙتوح + Å ablon OpenOffice Calc + Шаблон за таблици — OpenOffice Calc + plantilla d'OpenOffice Calc + Å ablona OpenOffice Calc + OpenOffice Calc-skabelon + OpenOffice-Calc-Vorlage + Ï€Ïότυπο OpenOffice Calc + OpenOffice Calc template + plantilla de OpenOffice Calc + OpenOffice Calc txantiloia + OpenOffice Calc -malli + OpenOffice Calc formur + modèle OpenOffice Calc + teimpléad OpenOffice Calc + modelo de OpenOffice Calc + תבנית של OpenOffice Calc + OpenOffice Calc sablon + Templat OpenOffice Calc + Modello OpenOffice Calc + OpenOffice Calc テンプレート + OpenOffice Calc-ის შáƒáƒ‘ლáƒáƒœáƒ˜ + OpenOffice Calc үлгіÑÑ– + OpenOffice Calc 스프레드시트 문서 ì„œì‹ + OpenOffice Calc Å¡ablonas + OpenOffice Calc veidne + OpenOffice Calc-mal + OpenOffice.org Calc-sjabloon + OpenOffice Calc-mal + Szablon arkusza OpenOffice.org Calc + Modelo do OpenOffice Calc + Șablon OpenOffice Calc + шаблон OpenOffice Calc + Å ablóna OpenOffice Calc + Predloga OpenOffice.org Calc + Model OpenOffice Calc + OpenOffice Calc-mall + шаблон ел.таблиці OpenOffice Calc + Mẫu bảng tính Calc của OpenOffice.org + OpenOffice.org Calc å·¥ä½œç°¿æ¨¡æ¿ + OpenOffice Calc 範本 + + + + + + + + + + + + + OpenOffice Draw drawing + تصميم Draw المكتب المÙتوح + Rysunak OpenOffice Draw + Чертеж — OpenOffice Draw + dibuix d'OpenOffice Draw + Kresba OpenOffice Draw + OpenOffice Draw-tegning + OpenOffice-Draw-Zeichnung + σχέδιο OpenOffice Draw + OpenOffice Draw drawing + dibujo de OpenOffice Draw + OpenOffice.org Draw marrazkia + OpenOffice Draw -piirros + OpenOffice Draw tekning + dessin OpenOffice Draw + líníocht OpenOffice Draw + debuxo de OpenOffice Draw + ציור של OpenOffice Draw + OpenOffice Draw rajz + Gambar OpenOffice Draw + Disegno OpenOffice Draw + OpenOffice Draw ドロー + OpenOffice Draw-ის ნáƒáƒ®áƒáƒ–ი + OpenOffice Draw Ñуреті + OpenOffice Draw 그림 + OpenOffice Draw pieÅ¡inys + OpenOffice Draw zÄ«mÄ“jums + OpenOffice Draw-tegning + OpenOffice.org Draw-tekening + OpenOffice Draw-teikning + Rysunek OpenOffice.org Draw + Desenho do OpenOffice Draw + Desen OpenOffice Draw + изображение OpenOffice Draw + Kresba OpenOffice Draw + Datoteka risbe OpenOffice.org Draw + Vizatim OpenOffice Draw + OpenOffice Draw-teckning + малюнок OpenOffice Draw + Bản vẽ Draw của OpenOffice.org + OpenOffice.org Draw 绘图 + OpenOffice Draw 繪圖 + + + + + + + + + + + + + OpenOffice Draw template + قالب Draw المكتب المÙتوح + Å ablon OpenOffice Draw + Шаблон за чертежи — OpenOffice Draw + plantilla d'OpenOffice Draw + Å ablona OpenOffice Draw + OpenOffice Draw-skabelon + OpenOffice-Draw-Vorlage + Ï€ÏοÌτυπο OpenOffice Draw + OpenOffice Draw template + plantilla de OpenOffice.org Draw + OpenOffice Draw txantiloia + OpenOffice Draw -malli + OpenOffice Draw formur + modèle OpenOffice Draw + teimpléad OpenOffice Draw + modelo de OpenOffice Draw + תבנית של OpenOffice Draw + OpenOffice Draw sablon + Templat OpenOffice Draw + Modello OpenOffice Draw + OpenOffice Draw テンプレート + OpenOffice Draw-ის შáƒáƒ‘ლáƒáƒœáƒ˜ + OpenOffice Draw үлгіÑÑ– + OpenOffice Draw 그림 문서 ì„œì‹ + OpenOffice Draw Å¡ablonas + OpenOffice Draw veidne + OpenOffice Draw-mal + OpenOffice.org Draw-sjabloon + OpenOffice Draw-mal + Szablon rysunku OpenOffice.org Draw + Modelo do OpenOffice Draw + Șablon OpenOffice Draw + шаблон OpenOffice Draw + Å ablóna OpenOffice Draw + Predloga OpenOffice.org Draw + Model OpenOffice Draw + OpenOffice Draw-mall + шаблон малюнку OpenOffice Draw + Mẫu bản vẽ Draw của OpenOffice.org + OpenOffice.org Draw ç»˜å›¾æ¨¡æ¿ + OpenOffice Draw 範本 + + + + + + + + + + + + + OpenOffice Impress presentation + عرض تقديمي Impress المكتب المÙتوح + OpenOffice Impress sÉ™nÉ™di + Prezentacyja OpenOffice Impress + ÐŸÑ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ â€” OpenOffice Impress + presentació d'OpenOffice Impress + Prezentace OpenOffice Impress + Cyflwyniad OpenOffice (Impress) + OpenOffice Impress-præsentation + OpenOffice-Impress-Vorlage + παÏουσίαση OpenOffice Impress + OpenOffice Impress presentation + presentación de OpenOffice Impress + OpenOffice.org Impress aurkezpena + OpenOffice Impress -esitys + OpenOffice Impress framløga + présentation OpenOffice Impress + láithreoireacht OpenOffice Impress + presentación de de OpenOffice Impress + מצגת של OpenOffice Impress + OpenOffice Impress bemutató + Presentasi OpenOffice Impress + Presentazione OpenOffice Impress + OpenOffice Impress プレゼンテーション + OpenOffice Impress-ის პრეზენტáƒáƒªáƒ˜áƒ + OpenOffice Impress презентациÑÑÑ‹ + OpenOffice Impress 프리젠테ì´ì…˜ + OpenOffice Impress pateiktis + OpenOffice Impress prezentÄcija + OpenOffice Impress-presentasjon + OpenOffice.org Impress-presentatie + OpenOffice Impress-presentasjon + Prezentacja OpenOffice.org Impress + Apresentação do OpenOffice Impress + Prezentare OpenOffice Impress + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ OpenOffice Impress + Prezentácia OpenOffice Impress + Predstavitev OpenOffice.org Impress + Prezantim OpenOffice Impress + OpenOffice Impress-presentation + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ OpenOffice Impress + Trình diá»…n Impress của OpenOffice.org + OpenOffice.org Impress 演示文稿 + OpenOffice Impress ç°¡å ± + + + + + + + + + + + + + OpenOffice Impress template + قالب Impress المكتب المÙتوح + Å ablon OpenOffice Impress + Шаблон за презентации — OpenOffice Impress + plantilla d'OpenOffice Impress + Å ablona OpenOffice Impress + OpenOffice Impress-skabelon + OpenOffice-Impress-Vorlage + Ï€ÏοÌτυπο OpenOffice Impress + OpenOffice Impress template + plantilla de OpenOffice Impress + OpenOffice Impress txantiloia + OpenOffice Impress -malli + OpenOffice Impress formur + modèle OpenOffice Impress + teimpléad OpenOffice Impress + modelo de OpenOffice Impress + תבנית של OpenOffice Impress + OpenOffice Impress sablon + Templat OpenOffice Impress + Modello OpenOffice Impress + OpenOffice Impress テンプレート + OpenOffice Impress-ის შáƒáƒ‘ლáƒáƒœáƒ˜ + OpenOffice Impress үлгіÑÑ– + OpenOffice Impress 프리젠테ì´ì…˜ 문서 ì„œì‹ + OpenOffice Impress Å¡ablonas + OpenOffice Impress veidne + OpenOffice Impress-mal + OpenOffice.org Impress-sjabloon + OpenOffice Impress-mal + Szablon prezentacji OpenOffice.org Impress + Modelo do OpenOffice Impress + Șablon OpenOffice Impress + шаблон OpenOffice Impress + Å ablóna OpenOffice Impress + Predloga OpenOffice.org Impress + Model OpenOffice Impress + OpenOffice Impress-mall + шаблон презентації OpenOffice Impress + Mẫu trình diá»…n Impress của OpenOffice.org + OpenOffice.org Impress æ¼”ç¤ºæ–‡ç¨¿æ¨¡æ¿ + OpenOffice Impress 範本 + + + + + + + + + + + + + OpenOffice Math formula + صيغة Math المكتب المÙتوح + FormuÅ‚a OpenOffice Math + Формула — OpenOffice Math + fórmula d'OpenOffice Math + Vzorec OpenOffice Math + OpenOffice Math-formel + OpenOffice-Math-Formel + μαθηματικός Ï„Ïπος OpenOffice Math + OpenOffice Math formula + fórmula de OpenOffice Math + OpenOffice.org Math formula + OpenOffice Math -kaava + OpenOffice Math frymil + formule OpenOffice Math + foirmle OpenOffice Math + fórmula de OpenOffice Math + נוסחה של OpenOffice Math + OpenOffice Math képlet + Formula OpenOffice Math + Formula OpenOffice Math + OpenOffice Math è¨ˆç®—å¼ + OpenOffice Math-ის ფáƒáƒ áƒ›áƒ£áƒšáƒ + OpenOffice Math формулаÑÑ‹ + OpenOffice Math ìˆ˜ì‹ + OpenOffice Math formulÄ— + OpenOffice Math formula + OpenOffice Math-formel + OpenOffice.org Math-formule + OpenOffice Math-formel + FormuÅ‚a OpenOffice.org Math + Fórmula do OpenOffice Math + Formulă OpenOffice Math + формула OpenOffice Math + Vzorec OpenOffice Math + Dokument formule OpenOffice.org Math + Formulë OpenOffice Math + OpenOffice Math-formel + OpenOffice Math formülü + формула OpenOffice Math + Công thức Math của OpenOffice.org + OpenOffice.org Math å…¬å¼ + OpenOffice Math å…¬å¼ + + + + + + + + + + + + + OpenOffice Writer document + مستند Writer المكتب المÙتوح + OpenOffice Writer sÉ™nÉ™di + Dakument OpenOffice Writer + Документ — OpenOffice Writer + document d'OpenOffice Writer + Dokument OpenOffice Writer + Dogfen OpenOffice (Writer) + OpenOffice Writer-dokument + OpenOffice-Writer-Dokument + έγγÏαφο OpenOffice Writer + OpenOffice Writer document + documento de OpenOffice Writer + OpenOffice.org Writer dokumentua + OpenOffice Writer -asiakirja + OpenOffice Writer skjal + document OpenOffice Writer + cáipéis OpenOffice Writer + documento de OpenOffice Writer + מסמך של OpenOffice Writer + OpenOffice Writer dokumentum + Dokumen OpenOffice Writer + Documento OpenOffice Writer + OpenOffice Writer ドキュメント + OpenOffice Writer-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + OpenOffice Writer құжаты + OpenOffice Writer 문서 + OpenOffice Writer dokumentas + OpenOffice Writer dokuments + OpenOffice Writer-dokument + OpenOffice.org Writer-document + OpenOffice Writer-dokument + Dokument OpenOffice.org Writer + Documento do OpenOffice Writer + Document OpenOffice Writer + документ OpenOffice Writer + Dokument OpenOffice Writer + Dokument OpenOffice.org Writer + Dokument OpenOffice Writer + OpenOffice Writer-dokument + OpenOffice Writer belgesi + документ OpenOffice Writer + Tài liệu Writer của OpenOffice.org + OpenOffice.org Writer 文档 + OpenOffice Writer 文件 + + + + + + + + + + + + + OpenOffice Writer global document + مستند المكتب المÙتوح Writer العالمي + OpenOffice Writer qlobal sÉ™nÉ™di + Hlabalny dakument OpenOffice Writer + Документ - глобален — OpenOffice Writer + document global d'OpenOffice Writer + Globální dokument OpenOffice Writer + Dogfen eang OpenOffice (Writer) + OpenOffice Writer-globalt dokument + OpenOffice-Writer-Globaldokument + παγκόσμιο έγγÏαφο OpenOffice Writer + OpenOffice Writer global document + documento global de OpenOffice Writer + OpenOffice.org Writer dokumentu globala + OpenOffice Writer - yleinen asiakirja + OpenOffice Writer heiltøkt skjal + document global OpenOffice Writer + cáipéis chomhchoiteann OpenOffice Writer + documento global de OpenOffice Writer + מסמך גלובלי של OpenOffice Writer + OpenOffice Writer globális dokumentum + Dokumen global OpenOffice Writer + Documento globale OpenOffice Writer + OpenOffice Writer グローãƒãƒ«ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆ + OpenOffice Writer-ის გლáƒáƒ‘áƒáƒšáƒ£áƒ áƒ˜ დáƒáƒ™áƒ£áƒ›áƒ”ნტი + OpenOffice Writer негізгі құжаты + OpenOffice Writer 글로벌 문서 + OpenOffice Writer bendrinis dokumentas + OpenOffice Writer globÄlais dokuments + Global OpenOffice Writer globalt dokument + OpenOffice.org Writer-globaal-document + OpenOffice Writer globalt dokument + Globalny dokument OpenOffice.org Writer + Documento global do OpenOffice Writer + Document global OpenOffice Writer + оÑновной документ OpenOffice Writer + Globálny dokument OpenOffice Writer + SploÅ¡ni dokument OpenOffice.org Writer + Dokument i përgjithshëm OpenOffice Writer + OpenOffice Writer-globaldokument + загальний документ OpenOffice Writer + Tài liệu toàn cục Writer của OpenOffice.org + OpenOffice.org Writer 全局文档 + OpenOffice Writer 主控文件 + + + + + + + + + + + + + OpenOffice Writer template + قالب Writer المكتب المÙتوح + OpenOffice Writer ÅŸablonu + Å ablon OpenOffice Writer + Шаблон за документи — OpenOffice Writer + plantilla d'OpenOffice Writer + Å ablona OpenOffice Writer + Templed OpenOffice (Writer) + OpenOffice Writer-skabelon + OpenOffice-Writer-Vorlage + Ï€ÏοÌτυπο OpenOffice Writer + OpenOffice Writer template + plantilla de OpenOffice Writer + OpenOffice Writer txantiloia + OpenOffice Writer -malli + OpenOffice Writer formur + modèle OpenOffice Writer + teimpléad OpenOffice Writer + modelo de OpenOffice Writer + תסנית של OpenOffice Writer + OpenOffice Writer sablon + Templat OpenOffice Writer + Modello OpenOffice Writer + OpenOffice Writer ドキュメントテンプレート + OpenOffice Writer-ის შáƒáƒ‘ლáƒáƒœáƒ˜ + OpenOffice Writer үлгіÑÑ– + OpenOffice Writer 문서 ì„œì‹ + OpenOffice Writer Å¡ablonas + OpenOffice Writer veidne + Templat OpenOffice Writer + OpenOffice Writer-mal + OpenOffice.org Writer-sjabloon + OpenOffice Writer-mal + Szablon dokumentu OpenOffice.org Writer + Modelo do OpenOffice Writer + Șablon OpenOffice Writer + шаблон OpenOffice Writer + Å ablóna OpenOffice Writer + Predloga OpenOffice.org Writer + Model OpenOffice Writer + OpenOffice Writer-mall + шаблон документа OpenOffice Writer + Mẫu tài liệu Writer của OpenOffice.org + OpenOffice.org Writer æ–‡æ¡£æ¨¡æ¿ + OpenOffice Writer 範本 + + + + + + + + + + + + + ODT document + مستند ODT + Dakument ODT + Документ — ODT + document ODT + Dokument ODT + ODT-dokument + ODT-Dokument + έγγÏαφο ODT + ODT document + ODT-dokumento + documento ODT + ODT dokumentua + ODT-asiakirja + ODT skjal + document ODT + cáipéis ODT + documento ODT + מסמך ODT + ODT dokument + ODT-dokumentum + Dokumen ODT + Documento ODT + ODT ドキュメント + ODT დáƒáƒ™áƒ£áƒ›áƒ”ნტი + ODT құжаты + ODT 문서 + ODT dokumentas + ODT dokuments + ODT-dokument + ODT-document + ODT-dokument + Dokument ODT + Documento ODT + Document ODT + документ ODT + Dokument ODT + Dokument ODT + Dokument ODT + ODT-dokument + документ ODT + Tài liệu ODT + ODT 文档 + ODT 文件 + ODT + OpenDocument Text + + + + + + + + + + + + + ODT document (Flat XML) + مستند ODT (Flat XML) + Документ — ODT (Ñамо XML) + document ODT (XML pla) + Dokument ODT (Flat XML) + ODT-dokument (flad XML) + ODT-Dokument (Unkomprimiertes XML) + έγγÏαφο ODT (Flat XML) + ODT document (Flat XML) + documento ODT (XML plano) + ODT dokumentua (XML soila) + ODT skjal (Flat XML) + document ODT (XML plat) + cáipéis ODT (XML cothrom) + documento ODT (XML plano) + מסמך ODT†(Flat XML) + ODT-dokumentum (egyszerű XML) + Dokumen ODT (Flat XML) + Documento ODT (XML semplice) + ODT ドキュメント (Flat XML) + ODT დáƒáƒ™áƒ£áƒ›áƒ”ნტი (Flat XML) + ODT құжаты (Тек XML) + ODT 문서 (ë‹¨ì¼ XML) + ODT dokumentas (Flat XML) + ODT dokuments (plakans XML) + ODT document (Flat XML) + Dokument ODT (prosty XML) + Documento ODT (Flat XML) + Document ODT (XML simplu) + документ ODT (проÑтой XML) + Dokument ODT (Äisté XML) + Datoteka dokumenta ODT (nepovezan XML) + ODT-dokument (platt XML) + документ ODT (Flat XML) + ODT 文档(Flat XML) + ODT 文件 (Flat XML) + FODT + OpenDocument Text (Flat XML) + + + + + + ODT template + قالب ODT + Å ablon ODT + Шаблон за документи — ODT + plantilla ODT + Å ablona ODT + ODT-skabelon + ODT-Vorlage + Ï€Ïότυπο ODT + ODT template + ODT-Åablono + plantilla ODT + ODT txantiloia + ODT-malli + ODT formur + modèle ODT + teimpléad ODT + modelo ODT + תבנית ODT + ODT predložak + ODT-sablon + Templat ODT + Modello ODT + ODT テンプレート + ODT დáƒáƒ™áƒ£áƒ›áƒ”ნტი + ODT үлгіÑÑ– + ODT 문서 ì„œì‹ + ODT Å¡ablonas + ODT veidne + ODT-mal + ODT-sjabloon + ODT-mal + Szablon ODT + Modelo ODT + Șablon ODT + шаблон ODT + Å ablóna ODT + Predloga dokumenta ODT + Model ODT + ODT-mall + шаблон ODT + Mẫu ODT + ODT æ¨¡æ¿ + ODT 範本 + ODT + OpenDocument Text + + + + + + + + + + + + + OTH template + قالب OTH + Å ablon OTH + Шаблон за Ñтраници — OTH + plantilla OTH + Å ablona OTH + OTH-skabelon + OTH-Vorlage + Ï€Ïότυπο OTH + OTH template + OTH-Åablono + plantilla OTH + OTH txantiloia + OTH-malli + OTH formur + modèle OTH + teimpléad OTH + modelo OTH + תבנית OTH + OTH predložak + OTH-sablon + Templat OTH + Modello OTH + OTH テンプレート + OTH შáƒáƒ‘ლáƒáƒœáƒ˜ + OTH үлгіÑÑ– + OTH 문서 ì„œì‹ + OTH Å¡ablonas + OTH veidne + OTH-mal + OTH-sjabloon + OTH-mal + Szablon OTH + Modelo OTH + Șablon OTH + шаблон OTH + Å ablóna OTH + Predloga OTH + Model OTH + OTH-mall + шаблон OTH + Mẫu ODH + OTH æ¨¡æ¿ + OTH 範本 + OTH + OpenDocument HTML + + + + + + + + + + + + + ODM document + مستند ODM + Dakument ODM + Документ — ODM + document ODM + Dokument ODM + ODM-dokument + ODM-Dokument + έγγÏαφο ODM + ODM document + ODM-dokumento + documento ODM + ODM dokumentua + ODM-asiakirja + ODM skjal + document ODM + cáipéis ODM + documento ODM + מסמך ODM + ODM dokument + ODM-dokumentum + Dokumen ODM + Documento ODM + ODM ドキュメント + ODM დáƒáƒ™áƒ£áƒ›áƒ”ნტი + ODM құжаты + ODM 문서 + ODM dokumentas + ODM dokuments + ODM-dokument + ODM-document + ODM-dokument + Dokument ODM + Documento ODM + Document ODM + документ ODM + Dokument ODM + Dokument ODM + Dokument ODM + ODM-dokument + ODM belgesi + документ ODM + Tài liệu ODM + ODM 文档 + ODM 文件 + ODM + OpenDocument Master + + + + + + + + + + + + + ODG drawing + تصميم ODG + Rysunak ODG + Чертеж — ODG + dibuix ODG + Kresba ODG + ODG-tegning + ODG-Zeichnung + σχέδιο ODG + ODG drawing + ODG-desegnaĵo + dibujo ODG + ODG marrazkia + ODG-piirros + ODG tekning + dessin ODG + líníocht ODG + debuxo ODG + ציור ODG + ODG crtež + ODG-rajz + Gambar ODG + Disegno ODG + ODG ドロー + ODG-ის ნáƒáƒ®áƒáƒ–ი + ODG Ñуреті + ODG 드로잉 + ODG pieÅ¡inys + ODG zÄ«mÄ“jums + ODG-tegning + ODG-tekening + ODG-teikning + Rysunek ODG + Desenho ODG + Desen ODG + изображение ODG + Kresba ODG + Datoteka risbe ODG + Vizatim ODG + ODG-teckning + малюнок ODG + Bản vẽ ODG + ODG 绘图 + ODG 繪圖 + ODG + OpenDocument Drawing + + + + + + + + + + + + + ODG drawing (Flat XML) + رسمة ODG (Flat XML) + Чертеж — ODG (Ñамо XML) + dibuix ODG (XML pla) + Kresba ODG (Flat XML) + ODG-tegning (flad XML) + ODG-Zeichnung (Unkomprimiertes XML) + ODG drawing (Flat XML) + dibujo ODG (XML plano) + ODG marrazkia (XML soila) + ODG tekning (Flat XML) + dessin ODG (XML plat) + líníocht ODG (XML cothrom) + debuxo ODB (XML plano) + ציור ODG (Flat XML( + ODG-rajz (egyszerű XML) + Gambar ODG (FLAT XML) + Disegno ODG (XML semplice) + ODG ドロー (Flat XML) + ODG-ის ნáƒáƒ®áƒáƒ–ი (Flat XML) + ODG ÑызбаÑÑ‹ (Тек XML) + ODG 드로잉 (ë‹¨ì¼ XML) + ODG pieÅ¡inys (Flat XML) + ODG zÄ«mÄ“jums (plakans XML) + ODG-tekening (Flat XML) + Rysunek ODG (prosty XML) + Desenho ODG (Flat XML) + Desen ODG (XML simplu) + изображение ODG (проÑтой XML) + Kresba ODG (Äisté XML) + Datoteka risbe ODG (nepovezan XML) + ODG-teckning (platt XML) + малюнок ODG (Flat XML) + ODG 绘图(Flat XML) + ODG 繪圖 (Flat XML) + FODG + OpenDocument Drawing (Flat XML) + + + + + + ODG template + قالب ODG + Å ablon ODG + Шаблон за чертежи — ODG + plantilla ODG + Å ablona ODG + ODG-skabelon + ODG-Vorlage + Ï€Ïότυπο ODG + ODG template + ODG-Åablono + plantilla ODG + ODG txantiloia + ODG-malli + ODG formur + modèle ODG + teimpléad ODG + modelo ODG + תבנית ODG + ODG predložak + ODG-sablon + Templat ODG + Modello ODG + ODG テンプレート + ODG-ის შáƒáƒ‘ლáƒáƒœáƒ˜ + ODG үлгіÑÑ– + ODG 문서 ì„œì‹ + ODG Å¡ablonas + ODG veidne + ODG-mal + ODG-sjabloon + ODG-mal + Szablon ODG + Modelo ODG + Șablon ODG + шаблон ODG + Å ablóna ODG + Predloga dokumenta ODG + Model ODG + ODG-mall + шаблон ODG + Mẫu ODG + ODG æ¨¡æ¿ + ODG 範本 + ODG + OpenDocument Drawing + + + + + + + + + + + + + ODP presentation + عرض تقديمي ODP + Prezentacyja ODP + ÐŸÑ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ â€” ODP + presentació ODP + Prezentace ODP + ODP-præsentation + ODP-Präsentation + παÏουσίαση ODP + ODP presentation + ODP-prezentaĵo + presentación ODP + ODP aurkezpena + ODP-esitys + ODP framløga + présentation ODP + láithreoireacht ODP + presentación ODP + מצגת ODP + ODP prezentacija + ODP-prezentáció + Presentasi ODP + Presentazione ODP + ODP プレゼンテーション + ODP პრეზენტáƒáƒªáƒ˜áƒ + ODP презентациÑÑÑ‹ + ODP 프리젠테ì´ì…˜ + ODP pateiktis + ODP prezentÄcija + ODP-presentasjon + ODP-presentatie + ODP-presentasjon + Prezentacja ODP + Apresentação ODP + Prezentare ODP + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ ODP + Prezentácia ODP + Predstavitev ODP + Prezantim ODP + ODP-presentation + ODP sunumu + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ ODP + Trình diá»…n ODM + ODP 演示文稿 + ODP ç°¡å ± + ODP + OpenDocument Presentation + + + + + + + + + + + + + ODP presentation (Flat XML) + عرض ODP (Flat XML) + ÐŸÑ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ â€” ODP (Ñамо XML) + presentació ODP (XML pla) + Prezentace ODP (Flat XML) + ODP-præsentation (flad XML) + ODP-Präsentation (Unkomprimiertes XML) + παÏουσίαση ODP (Flat XML) + ODP presentation (Flat XML) + presentación ODP (XML plano) + ODP aurkezpena (XML soila) + ODP framløga (Flat XML) + présentation ODP (XML plat) + láithreoireacht ODP (XML cothrom) + presentación ODP (XML plano) + מצגת ODP†(Flat XML) + ODP-prezentáció (egyszerű XML) + Presentasi ODP (Flat XML) + Presentazione ODP (XML semplice) + ODP プレゼンテーション (Flat XML) + ODP პრეზენტáƒáƒªáƒ˜áƒ (Flat XML) + ODP презентациÑÑÑ‹ (Тек XML) + ODP 프리젠테ì´ì…˜ (ë‹¨ì¼ XML) + ODP pateiktis (Flat XML) + ODP prezentÄcija (plakans XML) + ODP presentatie (Flat XML) + Prezentacja ODP (prosty XML) + Apresentação ODP (Flat XML) + Prezentare ODP (XML simplu) + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ ODP (проÑтой XML) + Prezentácia ODP (Äisté XML) + Predstavitev ODP (nepovezan XML) + ODP-presentation (platt XML) + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ ODP (Flat XML) + ODP 演示文稿(Flat XML) + ODP 範本 (Flat XML) + FODP + OpenDocument Presentation (Flat XML) + + + + + + ODP template + قالب ODP + Å ablon ODP + Шаблон за презентации — ODP + plantilla ODP + Å ablona ODP + ODP-skabelon + ODP-Vorlage + Ï€Ïότυπο ODP + ODP template + ODP-Åablono + plantilla ODP + ODP txantiloia + ODP-malli + ODP formur + modèle ODP + teimpléad ODP + modelo ODP + תבנית ODP + ODP predložak + ODP-sablon + Templat ODP + Modello ODP + ODP テンプレート + ODP შáƒáƒ‘ლáƒáƒœáƒ˜ + ODP үлгіÑÑ– + ODP 문서 ì„œì‹ + ODP Å¡ablonas + ODP veidne + ODP-mal + ODP-sjabloon + ODP-mal + Szablon ODP + Modelo ODP + Șablon ODP + шаблон ODP + Å ablóna ODP + Predloga dokumenta ODP + Model ODP + ODP-mall + шаблон ODP + Mẫu ODP + ODP æ¨¡æ¿ + ODP 範本 + ODP + OpenDocument Presentation + + + + + + + + + + + + + ODS spreadsheet + جدول ODS + Raźlikovy arkuÅ¡ ODS + Таблица — ODS + full de càlcul ODS + SeÅ¡it ODS + ODS-regneark + ODS-Tabelle + φÏλλο εÏγασίας ODS + ODS spreadsheet + ODS-kalkultabelo + hoja de cálculo ODS + ODS kalkulu-orria + ODS-taulukko + ODS rokniark + feuille de calcul ODS + scarbhileog ODS + folla de cálculo ODS + גליון × ×ª×•× ×™× ODS + ODS proraÄunska tablica + ODS-táblázat + Lembar sebar ODS + Foglio di calcolo ODS + ODS スプレッドシート + ODS ცხრილი + ODS Ñлектрондық кеÑтеÑÑ– + ODS 스프레드시트 + ODS skaiÄialentÄ— + ODS izklÄjlapa + ODS-regneark + ODS-rekenblad + ODS-rekneark + Arkusz ODS + Planilha ODS + Foaie de calcul ODS + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° ODS + ZoÅ¡it ODS + Preglednica ODS + Fletë llogaritjesh ODS + ODS-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ ODS + Bảng tính ODS + ODS 工作簿 + ODS 試算表 + ODS + OpenDocument Spreadsheet + + + + + + + + + + + + + ODS spreadsheet (Flat XML) + جدول ODS (Flat XML) + Таблица — ODS (Ñамо XML) + full de càlcul ODS (XML pla) + SeÅ¡it ODS (Flat XML) + ODS-regneark (flad XML) + ODS-Tabelle (Unkomprimiertes XML) + φÏλλο εÏγασίας ODS (Flat XML) + ODS spreadsheet (Flat XML) + hoja de cálculo ODS (XML plano) + ODS kalkulu-orria (XML soila) + ODS rokniark (Flat XML) + feuille de calcul ODS (XML plat) + scarbhileog ODS (XML cothrom) + folla de cálculo ODS (XML plano) + גליון × ×ª×•× ×™× ODS†(XML פשוט) + ODS-táblázat (egyszerű XML) + Lembar sebar ODS (Flat XML) + Foglio di calcolo ODS (XML semplice) + ODS スプレッドシート (Flat XML) + ODS ცხრილი (Flat XML) + ODS Ñлектрондық кеÑтеÑÑ– (Тек XML) + ODS 스프레드시트 (ë‹¨ì¼ XML) + ODS skaiÄialentÄ— (Flat XML) + ODS izklÄjlapa (plakans XML) + ODS spreadsheet (Flat XML) + Arkusz ODS (prosty XML) + Planilha ODS (Flat XML) + Foaie de calcul ODS (XML simplu) + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° ODS (проÑтой XML) + ZoÅ¡it ODS (Äisté XML) + Preglednica ODS (nepovezan XML) + ODS-kalkylblad (platt XML) + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ ODS (Flat XML) + ODS 工作簿(Flat XML) + ODS 試算表 (Flat XML) + FODS + OpenDocument Spreadsheet (Flat XML) + + + + + + ODS template + قالب ODS + Å ablon ODS + Шаблон за таблици — ODS + plantilla ODS + Å ablona ODS + ODS-skabelon + ODS-Vorlage + Ï€Ïότυπο ODS + ODS template + ODS-Åablono + plantilla ODS + ODS txantiloia + ODS-malli + ODS formur + modèle ODS + teimpléad ODS + modelo ODS + תבנית ODS + ODS predložak + ODS-sablon + Templat ODS + Modello ODS + ODS テンプレート + ODS-ის შáƒáƒ‘ლáƒáƒœáƒ˜ + ODS үлгіÑÑ– + ODS 문서 ì„œì‹ + ODS Å¡ablonas + ODS veidne + ODS-mal + ODS-sjabloon + ODS-mal + Szablon ODS + Modelo ODS + Șablon ODS + шаблон ODS + Å ablóna ODS + Predloga dokumenta ODS + Model ODS + ODS-mall + шаблон ODS + Mẫu ODS + ODS æ¨¡æ¿ + ODS 範本 + ODS + OpenDocument Spreadsheet + + + + + + + + + + + + + ODC chart + مخطط ODC + Dyjahrama ODC + Диаграма — ODC + diagrama ODC + Graf ODC + ODC-diagram + ODC-Diagramm + διάγÏαμμα ODC + ODC chart + ODC-diagramo + gráfica ODC + ODC diagrama + ODC-kaavio + ODC strikumynd + graphique ODC + cairt ODC + gráfica ODC + תו ODC + ODC grafikon + ODC-táblázat + Bagan ODC + Grafico ODC + ODC ãƒãƒ£ãƒ¼ãƒˆ + ODC диаграммаÑÑ‹ + ODC 차트 + ODC diagrama + ODC diagramma + ODC-graf + ODC-grafiek + ODC-diagram + Wykres ODC + Gráfico ODC + Diagramă ODC + диаграмма ODC + Graf ODC + Datoteka grafikona ODC + Grafik ODC + ODC-diagram + діаграма ODC + SÆ¡ đồ ODC + ODC 图表 + ODC 圖表 + ODC + OpenDocument Chart + + + + + + + + + + + + + ODC template + قالب ODC + Шаблон за диаграми — ODC + plantilla ODC + Å ablona ODC + ODC-skabelon + ODC-Vorlage + Ï€Ïότυπο ODC + ODC template + ODC-Åablono + plantilla ODC + ODC txantiloia + ODC-malli + ODC formur + modèle ODC + teimpléad ODC + modelo ODC + תבנית ODC + ODC predložak + ODC-sablon + Templat ODC + Modello ODC + ODC テンプレート + ODC შáƒáƒ‘ლáƒáƒœáƒ˜ + ODC үлгіÑÑ– + ODC 문서 ì„œì‹ + ODC Å¡ablonas + ODC veidne + ODC-sjabloon + Szablon ODC + Modelo ODC + Șablon ODC + шаблон ODC + Å ablóna ODC + Predloga ODC + ODC-mall + шаблон ODC + Mẫu ODC + ODC æ¨¡æ¿ + ODC 範本 + ODC + OpenDocument Chart + + + + + + + + + + + + + ODF formula + صيغة ODF + FormuÅ‚a ODF + Формула — ODF + fórmula ODF + Vzorec ODF + ODF-formel + ODF-Formel + μαθηματικοÌÏ‚ Ï„Ï…Ìπος ODF + ODF formula + ODF-formulo + fórmula ODF + ODF formula + ODF-kaava + ODF frymil + formule ODF + foirmle ODF + Fórula ODF + נוסחת ODF + ODF formula + ODF-képlet + Formula ODF + Formula ODF + ODF è¨ˆç®—å¼ + ODF-ის ფáƒáƒ áƒ›áƒ£áƒšáƒ + ODF формулаÑÑ‹ + ODF ìˆ˜ì‹ + ODF formulÄ— + ODF formula + ODF-formel + ODF-formule + ODF-formel + FormuÅ‚a ODF + Fórmula ODF + Formulă ODF + формула ODF + Vzorec ODF + Dokument formule ODF + Formulë ODF + ODF-formel + формула ODF + Công thức ODF + ODF å…¬å¼ + ODF å…¬å¼ + ODF + OpenDocument Formula + + + + + + + + + + + + + ODF template + قالب ODF + Шаблон за формули — ODF + plantilla ODF + Å ablona ODF + ODF-skabelon + ODF-Vorlage + Ï€Ïότυπο ODF + ODF template + ODF-Åablono + plantilla ODF + ODF txantiloia + ODF-malli + ODF formur + modèle ODF + teimpléad ODF + modelo ODF + תבנית ODF + ODF predložak + ODG-sablon + Templat ODF + Modello ODF + ODF テンプレート + ODF-ის შáƒáƒ‘ლáƒáƒœáƒ˜ + ODF үлгіÑÑ– + ODF 문서 ì„œì‹ + ODF Å¡ablonas + ODF veidne + ODF-sjabloon + Szablon ODF + Modelo ODF + Șablon ODF + шаблон ODF + Å ablóna ODF + Predloga dokumenta ODF + ODF-mall + шаблон ODF + Mẫu ODF + ODF æ¨¡æ¿ + ODF 範本 + ODF + OpenDocument Formula + + + + + + + + + + + + + ODB database + قاعدة بيانات ODB + Baza źviestak ODB + База от данни — ODB + base de dades ODB + Databáze ODB + ODB-database + ODB-Datenbank + ΒαÌση δεδομεÌνων ODB + ODB database + ODB-datumbazo + base de datos ODB + ODB datu-basea + ODB-tietokanta + ODB dátustovnur + base de données ODB + bunachar sonraí ODB + base de datos ODB + בסיס × ×ª×•× ×™× ODB + ODB baza podataka + ODB-adatbázis + Basis data ODB + Database ODB + ODB データベース + ODB-ის მáƒáƒœáƒáƒªáƒ”მთრბáƒáƒ–რ+ ODB дерекқоры + ODB ë°ì´í„°ë² ì´ìŠ¤ + ODB duomenų bazÄ— + ODB datubÄze + ODB-database + ODB-gegevensbank + ODB-database + Baza danych ODB + Banco de dados ODB + Bază de date ODB + база данных ODB + Databáza ODB + Podatkovna zbirka ODB + Bazë me të dhëna ODB + ODB-databas + ODB veritabanı + база даних ODB + CÆ¡ sở dữ liệu ODB + ODB æ•°æ®åº“ + ODB 資料庫 + ODB + OpenDocument Database + + + + + + ODI image + صورة ODI + Vyjava ODI + Изображение — ODI + imatge ODI + Obrázek ODI + ODI-billede + ODI-Bild + εικόνα ODI + ODI image + ODI-bildo + imagen ODI + ODI irudia + ODI-kuva + ODI mynd + image ODI + íomhá ODI + imaxe ODI + תמונת ODI + ODI slika + ODI-kép + Citra ODI + Immagine ODI + ODI ç”»åƒ + ODI გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ ODI Ñуреті + ODI 그림 + ODI paveikslÄ—lis + ODI attÄ“ls + ODI-bilde + ODI-afbeelding + ODI-bilete + Obraz ODI + Imagem ODI + Imagine ODI + изображение ODI + Obrázok ODI + Slikovna datoteka ODI + Figurë ODI + ODI-bild + ODI görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ ODI + Ảnh ODI + ODI å›¾åƒ + ODI å½±åƒ + ODI + OpenDocument Image + + + + + + + + + + + + + OpenOffice.org extension + امتداد OpenOffice.org + PaÅ¡yreÅ„nie OpenOffice.org + Разширение — OpenOffice + extensió d'OpenOffice.org + Rozšíření OpenOffice.org + OpenOffice.org-udvidelse + OpenOffice.org-Erweiterung + επέκταση OpenOffice.org + OpenOffice.org extension + extensión de OpenOffice + OpenOffice.org luzapena + OpenOffice.org-laajennus + OpenOffice.org víðkan + extension OpenOffice.org + eisínteacht OpenOffice.org + Extensión de OpenOffice.org + הרחבה של OpenOffice.org + OpenOffice.org kiterjesztés + Ekstensi OpenOffice.org + Estensione OpenOffice.org + OpenOffice.org 拡張機能 + OpenOffice.org-ის გáƒáƒ¤áƒáƒ áƒ—áƒáƒ”ბრ+ OpenOffice.org кеңейтуі + OpenOffice.org 확장 + OpenOffice.org plÄ—tinys + OpenOffice.org paplaÅ¡inÄjums + OpenOffice.org-uitbreiding + OpenOffice Writer-utviding + Rozszerzenie OpenOffice.org + Extensão do OpenOffice + Extensie OpenOffice.org + раÑширение OpenOffice.org + Rozšírenie OpenOffice.org + RazÅ¡iritev OpenOffice.org + Shtojcë për OpenOffice.org + OpenOffice.org-tillägg + OpenOffice.org eklentisi + Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ OpenOffice.org + Phần mở rá»™ng của OpenOffice.org + OpenOffice.org 扩展 + OpenOffice.org 擴充套件 + + + + + + Android package + Пакет — Android + paquet d'Android + BalíÄky systému Android + Android-pakke + Android-Paket + πακέτο Android + Android package + Android-pakaĵo + Paquete de Android + Android-paketti + paquet Android + paquete de Android + חבילת ×נדרויד + Android paket + Android csomag + Paket Android + Pacchetto Android + Android パッケージ + Android-ის პáƒáƒ™áƒ”ტი + Android деÑтеÑÑ– + 안드로ì´ë“œ 패키지 + Android pakotne + Android pakket + Pakiet Androida + Pacote do Android + пакет Android + Paket Android + Android-paket + пакунок Android + Android + Android 套件 + + + + + SIS package + حزمة SIS + Pakunak SIS + Пакет — SIS + paquet SIS + BalíÄek SIS + SIS-pakke + SIS-Paket + πακέτο SIS + SIS package + SIS-pakaĵo + paquete SIS + SIS paketea + SIS-paketti + SIS pakki + paquet SIS + pacáiste SIS + paquete SIS + חבילת SIS + SIS paket + SIS csomag + Paket SIS + Pacchetto SIS + SIS パッケージ + SIS деÑтеÑÑ– + SIS 패키지 + SIS paketas + SIS pakotne + SIS-pakke + SIS-pakket + SIS-pakke + Pakiet SIS + Pacote SIS + Pachet SIS + пакет SIS + BalíÄek SIS + Datoteka paketa SIS + Paketë SIS + SIS-paket + SIS paketi + пакунок SIS + Gói SIS + SIS 软件包 + SIS 套件 + SIS + Symbian Installation File + + + + + + + + SISX package + حزمة SISX + Pakunak SISX + Пакет — SISX + paquet SISX + BalíÄek SISX + SISX-pakke + SISX-Paket + πακέτο SISX + SISX package + SISX-pakaĵo + paquete SISX + SISX paketea + SISX-paketti + SISX pakki + paquet SISX + pacáiste SISX + paquete SISX + חבילת SISX + SISX paket + SISX csomag + Paket SISX + Pacchetto SISX + SISX パッケージ + SISX деÑтеÑÑ– + SISX 패키지 + SISX paketas + SISX pakotne + SISX-pakke + SISX-pakket + SISX-pakke + Pakiet SISX + Pacote SISX + Pachet SISX + пакет SISX + BalíÄek SISX + Datoteka paketa SISX + Paketë SISX + SISX-paket + SISX paketi + пакунок SISX + Gói SISX + SISX 软件包 + SISX 套件 + SIS + Symbian Installation File + + + + + + + + Network Packet Capture + Прихванати пакети по мрежата + captura de paquets de xarxa + Network Packet Capture + Netværkspakkeoptegnelse + Netzwerk-Paketmitschnitt + ΣÏλληψη Πακέτων ΔικτÏου + Network Packet Capture + Caputra de paquete de red + capture de paquet réseau + Captura de Network Packet + לכידה של מנות × ×ª×•× ×™× ×‘×¨×©×ª + Hálózati csomagelfogás + Tangkapan Paket Jaringan + Cattura pacchetti rete + ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ‘ケットキャプãƒãƒ£ãƒ¼ + ქსელური პáƒáƒ™áƒ”ტის áƒáƒœáƒáƒ‘ეჭდი + Ò±Ñталған желілік пакеттер + ë„¤íŠ¸ì›Œí¬ íŒ¨í‚· 캡처 + Network Packet Capture + Network Packet Capture + Przechwycenie pakietu sieciowego + Pacote de captura de rede + захваченные Ñетевые пакеты + Zajem omrežnih paketov + перехоплені дані мережевих пакетів + ç½‘ç»œåŒ…æŠ“å– + 網路å°åŒ…æ•æ‰ + + + + + + + + + + + + WordPerfect document + مستند WordPerfect + WordPerfect sÉ™nÉ™di + Dakument WordPerfect + Документ — WordPerfect + document de WordPerfect + Dokument WordPerfect + Dogfen WordPerfect + WordPerfect-dokument + WordPerfect-Dokument + έγγÏαφο WordPerfect + WordPerfect document + WordPerfect-dokumento + documento de WordPerfect + WordPerfect dokumentua + WordPerfect-asiakirja + WordPerfect skjal + document WordPerfect + cáipéis WordPerfect + documento de WordPerfect + מסמך WordPerfect + WordPerfect dokument + WordPerfect-dokumentum + Dokumen WordPerfect + Documento WordPerfect + WordPerfect ドキュメント + WordPerfect құжаты + 워드í¼íŽ™íŠ¸ 문서 + WordPerfect dokumentas + WordPerfect dokuments + Dokumen WordPerfect + WordPerfect-dokument + WordPerfect-document + WordPerfect-dokument + Dokument WordPerfect + documento do WordPerfect + Documento do WordPerfect + Document WordPerfect + документ WordPerfect + Dokument WordPerfect + Dokument WordPerfect + Dokument WordPerfect + WordPerfect документ + WordPerfect-dokument + документ WordPerfect + Tài liệu WordPerfect + WordPerfect 文档 + WordPerfect 文件 + + + + + + + + + + + + + + + + SPSS Portable Data File + مل٠بيانات SPSS متنقلة + Данни — SPSS, преноÑими + fitxer de dades portables SPSS + Soubor pÅ™enositelných dat SPSS + Portabel SPSS-datafil + SPSS portable Datendatei + φοÏητό αÏχείο δεδομένων SPSS + SPSS Portable Data File + archivo de datos portable SPSS + SPSS datuen fitxategi eramangarria + SPSS flytifør dátufíla + fichier portable de données SPSS + comhad iniompartha sonraí SPSS + ficheiro de datos portábel SPSS + קובץ מידע נייד SPSS + SPSS prenosiva podatkovna datoteka + SPSS hordozható adatfájl + Berkas Data Portabel SPSS + File dati SPSS Portable + SPSS ãƒãƒ¼ã‚¿ãƒ–ルデータファイル + SPSS таÑымалы ақпарат файлы + SPSS ì´ë™ì‹ ë°ì´í„° íŒŒì¼ + SPSS perkeliamų duomenų failas + SPSS pÄrvietojamu datu datne + SPSS Portable Databestand + Plik przenoÅ›nych danych SPSS + Arquivo de Dados Portáteis SPSS + FiÈ™ier portabil de date SPSS + файл переноÑимых данных SPSS + Súbor prenosných dát SPSS + Prenosna podatkovna datoteka SPSS + Portabel SPSS-datafil + файл даних SPSS Portable + SPSS 便æºå¼æ•°æ®æ–‡ä»¶ + SPSS å¯æ”œå¼è³‡æ–™æª” + + + + + + + SPSS Data File + مل٠بيانات SPSS + Данни — SPSS + fitxer de dades SPSS + Datový soubor SPSS + SPSS-datafil + SPSS-Datendatei + αÏχείο δεδομένων SPSS + SPSS Data File + archivo de datos SPSS + SPSS datuen fitxategia + SPSS dátufíla + fichier de données SPSS + comhad sonraí SPSS + ficheiro de datos SPSS + קובץ מידע SPSS + SPSS podatkovna datoteka + SPSS adatfájl + Berkas Data SPSS + File dati SPSS + SPSS データファイル + SPSS ақпарат файлы + SPSS ë°ì´í„° íŒŒì¼ + SPSS duomenų failas + SPSS datu datne + SPSS Databstand + Plik danych SPSS + Arquivo de dados SPSS + FiÈ™ier date SPSS + файл данных SPSS + Dátový súbor SPSS + Podatkovna datoteka SPSS + SPSS-datafil + файл даних SPSS + SPSS æ•°æ®æ–‡ä»¶ + SPSS 資料檔 + + + + + + + + XBEL bookmarks + علامات XBEL + ZakÅ‚adki XBEL + Отметки — XBEL + llista d'adreces d'interès XBEL + Záložky XBEL + XBEL-bogmærker + XBEL-Lesezeichen + σελιδοδείκτες XBEL + XBEL bookmarks + XBEL-legosignoj + marcadores XBEL + XBEL laster-markak + XBEL-kirjanmerkit + XBEL bókamerki + marque-pages XBEL + leabharmharcanna XBEL + Marcadores XBEL + סמניית XBEL + XBEL knjižne oznake + XBEL-könyvjelzÅ‘k + Bookmark XBEL + Segnalibri XBEL + XBEL ブックマーク + XBEL бетбелгілері + XBEL 책갈피 + XBEL žymelÄ—s + XBEL grÄmatzÄ«mes + Tandabuku XBEL + XBEL-bokmerker + XBEL-bladwijzers + XBEL-bokmerker + ZakÅ‚adki XBEL + marcadores XBEL + Marcadores do XBEL + Semne de carte XBEL + закладки XBEL + Záložky XBEL + Datoteka zaznamkov XBEL + Libërshënues XBEL + XBEL обележивачи + XBEL-bokmärken + закладки XBEL + Liên kết đã lÆ°u XBEL + XBEL 书签 + XBEL æ ¼å¼æ›¸ç±¤ + XBEL + XML Bookmark Exchange Language + + + + + + + + + 7-zip archive + أرشي٠7-zip + ArchiÅ­ 7-zip + Ðрхив — 7-zip + arxiu 7-zip + Archiv 7-zip + 7-zip-arkiv + 7zip-Archiv + αÏχείο 7-zip + 7-zip archive + 7z-arkivo + archivador 7-zip + 7-zip artxiboa + 7-zip-arkisto + 7-zip skjalasavn + archive 7-zip + cartlann 7-zip + arquivo 7-zip + ×רכיון 7-zip + 7-zip arhiva + 7-zip archívum + Arsip 7-zip + Archivio 7-zip + 7-zip アーカイブ + 7-zip áƒáƒ áƒ¥áƒ˜áƒ•áƒ˜ + 7-zip архиві + 7-ZIP 압축 íŒŒì¼ + 7-zip archyvas + 7-zip arhÄ«vs + 7-zip-arkiv + 7-zip-archief + 7-zip-arkiv + Archiwum 7-zip + Pacote 7-zip + Arhivă 7-zip + архив 7-zip + Archív 7-zip + Datoteka arhiva 7-zip + Arkiv 7-zip + 7-zip-arkiv + 7-Zip arÅŸivi + архів 7-zip + Kho nén 7-zip + 7-zip 归档文件 + 7-zip å°å­˜æª” + + + + + + + + AbiWord document + مستند آبي وورد + Dakument AbiWord + Документ — AbiWord + document d'AbiWord + Dokument AbiWord + AbiWord-dokument + AbiWord-Dokument + έγγÏαφο AbiWord + AbiWord document + AbiWord-dokumento + documento de Abiword + AbiWord dokumentua + AbiWord-asiakirja + AbiWord skjal + document AbiWord + cáipéis AbiWord + documento de AbiWord + מסמך AbiWord + AbiWord dokument + AbiWord-dokumentum + Dokumen AbiWord + Documento AbiWord + AbiWord ドキュメント + AbiWord-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + AbiWord құжаты + AbiWord 문서 + AbiWord dokumentas + AbiWord dokuments + Dokumen AbiWord + AbiWord-dokument + AbiWord-document + AbiWord-dokument + Dokument AbiWord + documento AbiWord + Documento do AbiWord + Document AbiWord + документ AbiWord + Dokument AbiWord + Dokument AbiWord + Dokument AbiWord + Ðбиворд документ + AbiWord-dokument + AbiWord belgesi + документ AbiWord + Tài liệu AbiWord + AbiWord 文档 + AbiWord 文件 + + + + + + + + + + + + + + CD image cuesheet + صÙيحة صورة الـCD جديلة + Infarmacyjny arkuÅ¡ vyjavy CD + ОпиÑание на изображение на CD + «cuesheet» d'imatge de CD + Rozvržení stop obrazu CD + Cd-aftrykscuesheet + CD-Abbild-Cuesheet + CD image cuesheet + cue sheet de una imagen de CD + CD irudiaren CUE orria + CD-vedos cuesheet + index de pistes de CD + bileog chiúáil íomhá CD + cue sheet dunha imaxe de CD + גליון × ×ª×•× ×™× ×œ×ª×ž×•× ×ª דיסק + CD kép cuesheet + Citra cuesheet CD + Cuesheet immagine CD + CD イメージキューシート + CD бейнеÑінің құрама кеÑтеÑÑ– + CD ì´ë¯¸ì§€ í시트 + CD atvaizdžio apraÅ¡as + CD attÄ“la rindulapa + Filliste for CD-avtrykk + CD-inhoudsopgave + CD-bilete-indeksfil + Obraz cuesheet pÅ‚yty CD + Ãndice de Imagem de CD + Imagine CD cuesheet + таблица ÑÐ¾Ð´ÐµÑ€Ð¶Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ€Ð°Ð·Ð° CD + Rozvrhnutie stôp obrazu CD + Datoteka razpredelnice odtisa CD cue + Cuesheet imazhi CD + Indexblad för cd-avbild + Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ CUE образу CD + Tá» tín hiệu báo ảnh CD + CD 映åƒæ ‡è®°æ–‡ä»¶ + CD 映åƒæŒ‡ç¤ºè¡¨ + + + + + + Lotus AmiPro document + مستند Lotus AmiPro + Lotus AmiPro sÉ™nÉ™di + Dakument Lotus AmiPro + Документ — Lotus AmiPro + document de Lotus AmiPro + Dokument Lotus AmiPro + Dogfen Lotus AmiPro + Lotus AmiPro-dokument + Lotus-AmiPro-Dokument + έγγÏαφο Lotus AmiPro + Lotus AmiPro document + dokumento de Lotus AmiPro + documento de Lotus AmiPro + Lotus AmiPro dokumentua + Lotus AmiPro -asiakirja + Lotus AmiPro skjal + document Lotus AmiPro + cáipéis Lotus AmiPro + documento de Lotus AmiPro + מסמך של Lotus AmiPro + Lotus AmiPro dokument + Lotus AmiPro-dokumentum + Dokumen Lotus AmiPro + Documento Lotus AmiPro + Lotus AmiPro ドキュメント + Lotus AmiPro құжаты + Lotus AmiPro 문서 + Lotus AmiPro dokumentas + Lotus AmiPro dokuments + Dokumen Lotus AmiPro + Lotus AmiPro-dokument + Lotus AmiPro-document + Lotus AmiPro-dokument + Dokument Lotus AmiPro + documento Lotus AmiPro + Documento do Lotus AmiPro + Document Lotus AmiPro + документ Lotus AmiPro + Dokument Lotus AmiPro + Dokument Lotus AmiPro + Dokument Lotus AmiPro + Ð›Ð¾Ñ‚ÑƒÑ ÐмиПро документ + Lotus AmiPro-dokument + документ Lotus AmiPro + Tài liệu Lotus AmiPro + Lotus AmiPro 文档 + Lotus AmiPro 文件 + + + + + AportisDoc document + مستند AportisDoc + Документ — AportisDoc + document AportisDoc + Dokument AportisDoc + AportisDoc-dokument + AportisDoc-Dokument + έγγÏαφο AportisDoc + AportisDoc document + AportisDoc-dokumento + documento AportisDoc + AportisDoc dokumentua + AportisDoc-asiakirja + AportisDoc skjal + document AportisDoc + cáipéis AportisDoc + documento de AportiDoc + מסמך AportisDoc + AportisDoc dokument + AportisDoc-dokumentum + Dokumen AportisDoc + Documento AportisDoc + AportisDoc ドキュメント + AportisDoc-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + AportisDoc құжаты + AportisDoc 문서 + AportisDoc dokumentas + AportisDoc dokuments + AportisDoc-document + Dokument AportisDoc + Documento do AportisDoc + Document AportisDoc + документ AportisDoc + Dokument AportisDoc + Dokument AportisDoc + AportisDoc-dokument + AportisDoc belgesi + документ AportisDoc + Tài liệu AportisDoc + AportisDoc 文档 + AportisDoc 文件 + + + + + + + + + + + Applix Spreadsheets spreadsheet + جداول بيانات Applix + Raźlikovy arkuÅ¡ Applix Spreadsheets + Таблица — Applix Spreadsheets + full de càlcul d'Applix Spreadsheets + SeÅ¡it Applix Spreadsheets + Applix Spreadsheets-regneark + Applix-Spreadsheets-Tabelle + λογιστικό φÏλλο Applix Spreadsheets + Applix Spreadsheets spreadsheet + sterntabelo de Applix Spreadsheets + hoja de cálculo de Applix Spreadsheets + Applix Spreadsheets kalkulu-orria + Applix Spreadsheets -taulukko + Applix Spreadsheets rokniark + feuille de calcul Applix + scarbhileog Applix Spreadsheets + folla de cálculo de Applix + גליון × ×ª×•× ×™× ×©×œ Applix Spreadsheets + Applix Spreadsheets proraÄunska tablica + Applix Spreadsheets-munkafüzet + Lembar sebar Applix Spreadsheets + Foglio di calcolo Applix Spreadsheets + Applix Spreadsheets スプレッドシート + Applix Spreadsheets-ის ცხრილი + Applix Spreadsheets Ñлектрондық кеÑтеÑÑ– + Applix 스프레드시트 + Applix Spreadsheets skaiÄialentÄ— + Applix Spreadsheets izklÄjlapa + Hamparan Applix Spreadsheets + Applix Spreadsheets-regneark + Applix Spreadsheets-rekenblad + Applix Spreadsheets-dokument + Arkusz Applix Spreadsheets + folha de cálculo Applix Spreadsheets + Planilha do Applix Spreadsheets + Foaie de calcul Applix + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° Applix Spreadsheets + ZoÅ¡it Applix Spreadsheets + Razpredelnica Applix Spreadsheets + Fletë llogaritjesh Applix Spreadsheets + Applix табеларни документ + Applix Spreadsheets-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Applix Spreadsheets + Bảng tính Applix Spreadsheets + Applix Spreadsheets 工作簿 + Applix Spreadsheets 試算表 + + + + + + + + + + + Applix Words document + مستند كلمات Applix + Applix Words sÉ™nÉ™di + Dakument Applix Words + Документ — Applix Words + document d'Applix Words + Dokument Applix Words + Dogfen Applix Words + Applix Words-dokument + Applix-Words-Dokument + έγγÏαφο Applix Words + Applix Words document + dokumento de Applix Words + documento de Applix Words + Applix Words dokumentua + Applix Words -asiakirja + Applix Words skjal + document Applix Words + cáipéis Applix Words + documento de Applix Words + מסמך של Applix Words + Applix Words dokument + Applix Words-dokumentum + Dokumen Applix Words + Documento Applix Words + Applix Words ドキュメント + Applix Words-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + Applix Words құжаты + Applix Words 문서 + Applix Words dokumentas + Applix Words dokuments + Dokumen Perkataan Applix + Applix Words-dokument + Applix Words-document + Applix Words dokument + Dokument Applix Words + documento Applix Words + Documento do Applix Words + Document Applix Words + документ Applix Words + Dokument Applix Words + Dokument Applix Words + Dokument Applix Words + Applix Words документ + Applix Words-dokument + документ Applix Words + Tài liệu Applix Words + Applix Words 文档 + Applix Words 文件 + + + + + + + + + + ARC archive + أرشي٠ARC + ArchiÅ­ ARC + Ðрхив — ARC + arxiu ARC + Archiv ARC + ARC-arkiv + ARC-Archiv + αÏχείο ARC + ARC archive + ARC-arkivo + archivador ARC + ARC artxiboa + ARC-arkisto + ARC skjalasavn + archive ARC + cartlann ARC + arquivo ARC + ×רכיון ARC + ARC arhiva + ARC-archívum + Arsip ARC + Archivio ARC + ARC アーカイブ + ARC áƒáƒ áƒ¥áƒ˜áƒ•áƒ˜ + ARC архиві + ARC 압축 íŒŒì¼ + ARC archyvas + ARC arhÄ«vs + ARC-arkiv + ARC-archief + ARC-arkiv + Archiwum ARC + Pacote ARC + Arhivă ARC + архив ARC + Archív ARC + Datoteka arhiva ARC + Arkiv ARC + ARC-arkiv + ARC arÅŸivi + архів ARC + Kho nén ARC + ARC 归档文件 + ARC å°å­˜æª” + + + + + + + + + + + + AR archive + أرشي٠AR + ArchiÅ­ AR + Ðрхив — AR + arxiu AR + Archiv AR + AR-arkiv + AR-Archiv + σÏχείο AR + AR archive + AR-arkivo + archivador AR + AR artxiboa + AR-arkisto + AR skjalasavn + archive AR + cartlann AR + arquivo AR + ×רכיון AR + AR arhiva + AR-archívum + Arsip AR + Archivio AR + AR アーカイブ + AR áƒáƒ áƒ¥áƒ˜áƒ•áƒ˜ + AR архиві + AR ë¬¶ìŒ íŒŒì¼ + AR archyvas + AR arhÄ«vs + Arkib AR + AR-arkiv + AR-archief + AR-arkiv + Archiwum AR + arquivo AR + Pacote AR + Arhivă AR + архив AR + Archív AR + Datoteka arhiva AR + Arkiv AR + ÐР архива + AR-arkiv + AR arÅŸivi + архів AR + Kho nén AR + AR 归档文件 + AR å°å­˜æª” + + + + + + + + + + ARJ archive + أرشي٠ARJ + ARJ arxivi + ArchiÅ­ ARJ + Ðрхив — ARJ + arxiu ARJ + Archiv ARJ + Archif ARJ + ARJ-arkiv + ARJ-Archiv + αÏχείο ARJ + ARJ archive + ARJ-arkivo + archivador ARJ + ARJ artxiboa + ARJ-arkisto + ARJ skjalasavn + archive ARJ + cartlann ARJ + arquivo ARJ + ×רכיון ARJ + ARJ arhiva + ARJ-archívum + Arsip ARJ + Archivio ARJ + ARJ アーカイブ + ARJ áƒáƒ áƒ¥áƒ˜áƒ•áƒ˜ + ARJ архиві + ARJ 압축 íŒŒì¼ + ARJ archyvas + ARJ arhÄ«vs + Arkib ARJ + ARJ-arkiv + ARJ-archief + ARJ-arkiv + Archiwum ARJ + arquivo ARJ + Pacote ARJ + Arhivă ARJ + архив ARJ + Archív ARJ + Datoteka arhiva ARJ + Arkiv ARJ + ARJ архива + ARJ-arkiv + ARJ arÅŸivi + архів ARJ + Kho nén ARJ + ARJ 归档文件 + ARJ å°å­˜æª” + ARJ + Archived by Robert Jung + + + + + + + + ASP page + صÙحة ASP + Staronka ASP + Страница — ASP + pàgina ASP + Stránka ASP + ASP-side + ASP-Seite + σελιÌδα ASP + ASP page + ASP-paÄo + página ASP + ASP orria + ASP-sivu + ASP síða + page ASP + leathanach ASP + páxina ASP + עמוד ASP + ASP stranica + ASP oldal + Halaman ASP + Pagina ASP + ASP ページ + ASP გვერდი + ASP парағы + ASP 페ì´ì§€ + ASP puslapis + ASP lapa + ASP-side + ASP-pagina + ASP-side + Strona ASP + Página ASP + Pagină ASP + Ñтраница ASP + Stránka ASP + Datoteka spletne strani ASP + Faqe ASP + ASP-sida + Ñторінка ASP + Trang ASP + ASP é¡µé¢ + ASP é é¢ + ASP + Active Server Page + + + + + + AWK script + سكربت AWK + AWK skripti + Skrypt AWK + Скрипт — AWK + script AWK + Skript AWK + Sgript AWK + AWK-program + AWK-Skript + Ï€ÏόγÏαμμα εντολών AWK + AWK script + AWK-skripto + script en AWK + AWK script-a + AWK-komentotiedosto + AWK boðrøð + script AWK + script AWK + script de AWK + תסריט AWK + AWK skripta + AWK-parancsfájl + Skrip AWK + Script AWK + AWK スクリプト + AWK სცენáƒáƒ áƒ˜ + AWK Ñценарийі + AWK 스í¬ë¦½íŠ¸ + AWK scenarijus + AWK skripts + Skrip AWK + AWK-skript + AWK-script + WAK-skript + Skrypt AWK + 'script' AWK + Script AWK + Script AWK + Ñценарий AWK + Skript AWK + Skriptna datoteka AWK + Script AWK + AWK Ñкрипта + AWK-skript + AWK betiÄŸi + Ñкрипт AWK + Văn lệnh AWK + AWK 脚本 + AWK 指令稿 + + + + + + + + + + + + + + + + + + + BCPIO document + مستند BCPIO + BCPIO sÉ™nÉ™di + Dakument BCPIO + Документ — BCPIO + document BCPIO + Dokument BCPIO + Dogfen BCPIO + BCPIO-dokument + BCPIO-Dokument + έγγÏαφο BCPIO + BCPIO document + BCPIO-dokumento + documento BCPIO + BCPIO dokumentua + BCPIO-asiakirja + BCPIO skjal + document BCPIO + cáipéis BCPIO + documento BCPIO + מסמך של BCPO + BCPIO dokument + BCPIO-dokumentum + Dokumen BCPIO + Documento BCPIO + BCPIO ドキュメント + BCPIO-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + BCPIO құжаты + BCPIO 문서 + BCPIO dokumentas + BCPIO dokuments + Dokumen BCPIO + BCPIO-dokument + BCPIO-document + BCPIO-dokument + Dokument BCPIO + documento BCPIO + Documento BCPIO + Document BCPIO + документ BCPIO + Dokument BCPIO + Dokument BCPIO + Dokument BCPIO + BCPIO документ + BCPIO-dokument + BCPIO belgesi + документ BCPIO + Tài liệu BCPIO + BCPIO 文档 + BCPIO 文件 + BCPIO + Binary CPIO + + + + + BitTorrent seed file + مل٠باذر البت تورنت + BitTorrent seed faylı + FajÅ‚ krynicy BitTorrent + Файл-източник — BitTorrent + fitxer llavor de BitTorrent + Soubor BitTorrent + Ffeil hadu BitTorrent + BitTorrent-frøfil + BitTorrent-Seed-Datei + αÏχείο BitTorrent seed + BitTorrent seed file + BitTorrent-semdosiero + archivo semilla de BitTorrent + BitTorrent hazi-fitxategia + BitTorrent-siementiedosto + BitTorrent seed fíla + fichier graine BitTorrent + comhad síl BitTorrent + ficheiro de orixe BitTorrent + קובץ זריעה של BitTorrent + BitTorrent-magfájl + Berkas benih BitTorrent + File seed BitTorrent + BitTorrent シードファイル + BitTorrent көз файлы + 비트토렌트 시드 íŒŒì¼ + BitTorrent Å¡altinio failas + BitTorrent avota datne + Fail seed BitTorrent + Fil med utgangsverdi for BitTorrent + BitTorrent-bestand + Nedlastingsfil for BitTorrent + Plik ziarna BitTorrent + ficheiro de origem BitTorrent + Arquivo semente BitTorrent + FiÈ™ier sursă-completă BitTorrent + файл иÑточника BitTorrent + Súbor BitTorrent + Datoteka sejanja BitTorrent + File bazë BitTorrent + Датотека Ñа БитТорентовим полазиштима + BitTorrent-distributionsfil + файл Ð¿Ð¾ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ BitTorrent + Tải tập hạt BitTorrent + BitTorrent ç§å­æ–‡ä»¶ + BitTorrent 種å­æª” + + + + + + + Blender scene + مشهد بلندر + Scena Blender + Сцена — Blender + escena Blender + Scéna Blender + Blenderscene + Blender-Szene + σκηνή Blender + Blender scene + Blender-sceno + escena de Blender + Blender-eko fitxategia + Blender-näkymä + Blender leikmynd + scène Blender + radharc Blender + escena de Blender + סצנת Blender + Blender scena + Blender-jelenet + Scene Blender + Scena Blender + Blender シーン + Blender-ის სცენრ+ Blender ÑахнаÑÑ‹ + Blender 장면 + Blender scena + Blender aina + Babak Blender + Blender-scene + Blender-scène + Blender-scene + Scena programu Blender + cenário Blender + Cena do Blender + Scenă Blender + Ñцена Blender + Scéna Blender + Datoteka scene Blender + Skenë Blender + Блендер Ñцена + Blender-scen + Ñцена Blender + Cảnh Blender + Blender 场景 + Blender 場景 + + + + + + + + + + TeX DVI document (bzip-compressed) + مستند TeX DVI (مضغوط-bzip) + Dakument TeX DVI (bzip-skampresavany) + Документ — TeX DVI, компреÑиран Ñ bzip + document TeX DVI (comprimit amb bzip) + Dokument TeX DVI (komprimovaný pomocí bzip) + TeX DVI-dokument (bzip-komprimeret) + TeX-DVI-Dokument (bzip-komprimiert) + αÏχείο TeX DVI (συμπιεσμένο με bzip) + TeX DVI document (bzip-compressed) + documento DVI de TeX (comprimido con bzip) + TeX DVI dokumentua (bzip-ekin konprimitua) + TeX DVI -asiakirja (bzip-pakattu) + TeX DVI skjal (bzip-stappað) + document DVI TeX (compressé bzip) + cáipéis DVI TeX (comhbhrúite le bzip) + documento DVI de TeX (comprimido con bzip) + מסמך מסוג TeX DVI (מכווץ ×¢"×™ bzip) + TeX DVI dokument (komprimiran bzip-om) + TeX DVI dokumentum (bzip-pel tömörítve) + Dokumen TeX DVI (terkompresi bzip) + Documento TeX DVI (compresso con bzip) + Tex DVI ドキュメント (bzip 圧縮) + TeX DVI құжаты (bzip-пен Ñығылған) + TeX DVI 문서 (BZIP 압축) + TeX DVI dokumentas (suglaudintas su bzip) + TeX DVI dokuments (saspiests ar bzip) + TeX DVI-dokument (bzip-komprimert) + TeX DVI-document (ingepakt met bzip) + TeX DVI-dokument (pakka med bzip) + Dokument TeX DVI (kompresja bzip) + Documento DVI TeX (compactado com bzip) + Document TeX DVI (comprimat bzip) + документ TeX DVI (Ñжатый bzip) + Dokument TeX DVI (komprimovaný pomocou bzip) + Dokument TeX DVI (stisnjen z bzip) + Dokument Tex DVI (i kompresuar me bzip) + TeX DVI-dokument (bzip-komprimerat) + документ TeX DVI (ÑтиÑнений bzip) + Tài liệu DVI TeX (đã nén bzip) + TeX DVI 文档(gzip 压缩) + TeX DVI 文件 (bzip æ ¼å¼å£“縮) + + + + + + Bzip archive + أرشي٠Bzip + ArchiÅ­ bzip + Ðрхив — bzip + arxiu bzip + Archiv bzip + Bzip-arkiv + Bzip-Archiv + συμπιεσμένο αÏχείο Bzip + Bzip archive + Bzip-arkivo + archivador Bzip + Bzip artxiboa + Bzip-arkisto + Bzip skjalasavn + archive bzip + cartlann Bzip + arquivo Bzip + ×רכיון Bzip + Bzip arhiva + Bzip archívum + Arsip Bzip + Archivio bzip + Bzip アーカイブ + Bzip áƒáƒ áƒ¥áƒ˜áƒ•áƒ˜ + Bzip архиві + BZIP 압축 íŒŒì¼ + Bzip archyvas + Bzip arhÄ«vs + Bzip-arkiv + Bzip-archief + Bzip-arkiv + Archiwum bzip + Pacote Bzip + Arhivă Bzip + архив BZIP + Archív bzip + Datoteka arhiva Bzip + Arkiv bzip + Bzip-arkiv + Bzip arÅŸivi + архів bzip + Kho nén bzip + bzip 归档文件 + Bzip å°å­˜æª” + + + + + + + + + + Tar archive (bzip-compressed) + أرشي٠Tar (مضغوط-bzip) + ArchiÅ­ tar (bzip-skampresavany) + Ðрхив — tar, компреÑиран Ñ bzip + arxiu tar (comprimit amb bzip) + Archiv tar (komprimovaný pomocí bzip) + Tar-arkiv (bzip-komprimeret) + Tar-Archiv (bzip-komprimiert) + αÏχειÌο Tar (συμπιεσμεÌνο με bzip) + Tar archive (bzip-compressed) + archivador Tar (comprimido con bzip) + Tar artxiboa (bzip-ekin konprimitua) + Tar-arkisto (bzip-pakattu) + Tar skjalasavn (bzip-stappað) + archive tar (compressée bzip) + cartlann Tar (comhbhrúite le bzip) + arquivo Tar (comprimido con bzip) + ×רכיון Tar (מכווץ ×¢"×™ bzip) + Tar arhiva (komprimirana bzip-om) + Tar archívum (bzip-pel tömörítve) + Arsip Tar (terkompresi bzip) + Archivio tar (compresso con bzip) + Tar アーカイブ (bzip 圧縮) + Tar архиві (bzip-пен Ñығылған) + TAR ë¬¶ìŒ íŒŒì¼ (BZIP 압축) + Tar archyvas (suglaudintas su bzip) + Tar arhÄ«vs (saspiests ar bzip) + Tar-arkiv (bzip-komprimert) + Tar-archief (ingepakt met bzip) + Tar-arkiv (pakka med bzip) + Archiwum tar (kompresja bzip) + Pacote tar (compactado com bzip) + Arhivă Tar (comprimată bzip) + архив TAR (Ñжатый BZIP) + Archív tar (komprimovaný pomocou bzip) + Datoteka arhiva Tar (stisnjen z bzip) + Arkiv tar (i kompresuar me bzip) + Tar-arkiv (bzip-komprimerat) + архів tar (ÑтиÑнений bzip) + Kho nén tar (đã nén bzip) + Tar 归档文件(bzip 压缩) + Tar å°å­˜æª” (bzip æ ¼å¼å£“縮) + + + + + + + + + + PDF document (bzip-compressed) + مستند PDF (مضغوط-bzip) + Dakument PDF (bzip-skampresavany) + Документ — PDF, компреÑиран Ñ bzip + document PDF (comprimit amb bzip) + Dokument PDF (komprimovaný pomocí bzip) + PDF-dokument (bzip-komprimeret) + PDF-Dokument (bzip-komprimiert) + εÌγγÏαφο PDF (συμπιεσμεÌνο με bzip) + PDF document (bzip-compressed) + documento PDF (comprimido con bzip) + PostScript dokumentua (bzip-ekin konprimitua) + PDF-asiakirja (bzip-pakattu) + PDF skjal (bzip-stappað) + document PDF (compressé bzip) + cáipéis PDF (comhbhrúite le bzip) + documento PDF (comprimido en bzip) + מסמך PDF (מכווץ ×¢"×™ bzip) + PDF dokumentum (bzip-tömörítésű) + Dokumen PDF (terkompresi bzip) + Documento PDF (compresso con bzip) + PDF ドキュメント (bzip 圧縮) + PDF құжаты (bzip-пен Ñығылған) + PDF 문서 (BZIP 압축) + PDF dokumentas (suglaudintas su bzip) + PDF dokuments (saspiests ar bzip) + PDF-dokument (bzip-komprimert) + PDF-document (ingepakt met bzip) + PDF-dokument (pakka med bzip) + Dokument PDF (kompresja bzip) + Documento PDF (compactado com bzip) + Document PDF (comprimat bzip) + документ PDF (Ñжатый bzip) + Dokument PDF (komprimovaný pomocou bzip) + Dokument PDF (stisnjen z bzip) + Dokument PDF (i kompresuar me bzip) + PDF-dokument (bzip-komprimerat) + PDF belgesi (bzip ile sıkıştırılmış) + документ PDF (ÑтиÑнений bzip) + Tài liệu PDF (đã nén bzip) + PDF 文档(bzip 压缩) + PDF 文件 (bzip æ ¼å¼å£“縮) + + + + + + PostScript document (bzip-compressed) + مستند PostScript (مضغوط-bzip) + Dakument PostScript (bzip-skampresavany) + Документ — PostScript, компреÑиран Ñ bzip + document PostScript (comprimit amb bzip) + Dokument PostScript (komprimovaný pomocí bzip) + PostScript-dokument (bzip-komprimeret) + PostScript-Dokument (bzip-komprimiert) + εÌγγÏαφο PostScript (συμπιεσμεÌνο με bzip) + PostScript document (bzip-compressed) + documento PostScript (comprimido con bzip) + PostScript dokumentua (bzip-ekin konprimitua) + PostScript-asiakirja (bzip-pakattu) + PostScript skjal (bzip-stappað) + document PostScript (compressé bzip) + cáipéis PostScript (comhbhrúite le bzip) + documento PostScript (comprimido con bzip) + מסמך PostDcript (מכווץ ×¢"×™ bzip) + PostScript dokumentum (bzip-tömörítésű) + Dokumen PostScript (terkompresi bzip) + Documento PostScript (compresso con bzip) + PostScript ドキュメント (bzip 圧縮) + PostScript құжаты (bzip-пен Ñығылған) + í¬ìŠ¤íŠ¸ìŠ¤í¬ë¦½íŠ¸ 문서 (BZIP 압축) + PostScript dokumentas (suglaudintas su bzip) + PostScript dokuments (saspiests ar bzip) + PostScript-dokument (bzip-komprimert) + PostScript-document (ingepakt met bzip) + PostScript-dokument (pakka med bzip) + Dokument Postscript (kompresja bzip) + Documento PostScript (compactado com bzip) + Document PostScript (comprimat bzip) + документ PostScript (Ñжатый bzip) + Dokument PostScript (komprimovaný pomocou bzip) + Dokument PostScript (stisnjen z bzip) + Dokument PostScript (i kompresuar me bzip) + Postscript-dokument (bzip-komprimerat) + документ PostScript (ÑтиÑнене bzip) + Tài liệu PostScript (đã nén bzip) + PostScript 文档(bzip 压缩) + PostScript 文件 (bzip æ ¼å¼å£“縮) + + + + + + comic book archive + أرشي٠comic book + archiÅ­ komiksaÅ­ + Ðрхив — комикÑи + arxiu comic book + Archiv knihy komiksů + comic book-arkiv + Comic-Book-Archiv + συμπιεσμένο αÏχείο κόμικ + comic book archive + archivador de libro de cómic + komiki artxiboa + sarjakuva-arkisto + teknisøgubóka skjalasavn + archive Comic Book + cartlann chartúin + ficheiro de libro de banda deseñada + ×רכיון ספר קומי + képregényarchívum + arsip buku komik + Archivio comic book + コミックブックアーカイブ + комикÑтар архиві + 만화책 압축 íŒŒì¼ + komiksų knygos archyvas + komiksu grÄmatas arhÄ«vs + Tegneseriearkiv + stripboek-archief + teikneseriearkiv + Archiwum komiksu + Pacote de livro de revista em quadrinhos + arhivă benzi desenate + архив комикÑов + Archív knihy komiksov + Datoteka arhiva stripov + Arkiv comic book + serietidningsarkiv + архів комікÑів + Kho nén sách tranh chuyện vui + Comic Book 归档文件 + 漫畫書å°å­˜æª” + + + + + + comic book archive + أرشي٠comic book + archiÅ­ komiksaÅ­ + Ðрхив — комикÑи + arxiu comic book + Archiv knihy komiksů + comic book-arkiv + Comic-Book-Archiv + συμπιεσμένο αÏχείο κόμικ + comic book archive + archivador de libro de cómic + komiki artxiboa + sarjakuva-arkisto + teknisøgubóka skjalasavn + archive Comic Book + cartlann chartúin + ficheiro de libro de banda deseñada + ×רכיון ספר קומי + képregényarchívum + arsip buku komik + Archivio comic book + コミックブックアーカイブ + комикÑтар архиві + 만화책 압축 íŒŒì¼ + komiksų knygos archyvas + komiksu grÄmatas arhÄ«vs + Tegneseriearkiv + stripboek-archief + teikneseriearkiv + Archiwum komiksu + Pacote de livro de revista em quadrinhos + arhivă benzi desenate + архив комикÑов + Archív knihy komiksov + Datoteka arhiva stripov + Arkiv comic book + serietidningsarkiv + архів комікÑів + Kho nén sách tranh chuyện vui + Comic Book 归档文件 + 漫畫書å°å­˜æª” + + + + + + comic book archive + أرشي٠comic book + archiÅ­ komiksaÅ­ + Ðрхив — комикÑи + arxiu comic book + Archiv knihy komiksů + comic book-arkiv + Comic-Book-Archiv + συμπιεσμένο αÏχείο κόμικ + comic book archive + archivador de libro de cómic + komiki artxiboa + sarjakuva-arkisto + teknisøgubóka skjalasavn + archive Comic Book + cartlann chartúin + ficheiro de libro de banda deseñada + ×רכיון ספר קומי + képregényarchívum + arsip buku komik + Archivio comic book + コミックブックアーカイブ + комикÑтар архиві + 만화책 압축 íŒŒì¼ + komiksų knygos archyvas + komiksu grÄmatas arhÄ«vs + Tegneseriearkiv + stripboek-archief + teikneseriearkiv + Archiwum komiksu + Pacote de livro de revista em quadrinhos + arhivă benzi desenate + архив комикÑов + Archív knihy komiksov + Datoteka arhiva stripov + Arkiv comic book + serietidningsarkiv + архів комікÑів + Kho nén sách tranh chuyện vui + Comic Book 归档文件 + 漫畫書å°å­˜æª” + + + + + + comic book archive + أرشي٠comic book + archiÅ­ komiksaÅ­ + Ðрхив — комикÑи + arxiu comic book + Archiv knihy komiksů + comic book-arkiv + Comic-Book-Archiv + συμπιεσμένο αÏχείο κόμικ + comic book archive + archivador de libro de cómic + komiki artxiboa + sarjakuva-arkisto + teknisøgubóka skjalasavn + archive Comic Book + cartlann chartúin + ficheiro de libro de banda deseñada + ×רכיון ספר קומי + képregényarchívum + arsip buku komik + Archivio comic book + コミックブックアーカイブ + комикÑтар архиві + 만화책 압축 íŒŒì¼ + komiksų knygos archyvas + komiksu grÄmatas arhÄ«vs + Tegneseriearkiv + stripboek-archief + teikneseriearkiv + Archiwum komiksu + Pacote de livro de revista em quadrinhos + arhivă benzi desenate + архив комикÑов + Archív knihy komiksov + Datoteka arhiva stripov + Arkiv comic book + serietidningsarkiv + архів комікÑів + Kho nén sách tranh chuyện vui + Comic Book 归档文件 + 漫畫書å°å­˜æª” + + + + + + Lrzip archive + أرشي٠Lrzip + Ðрхив — lrzip + arxiu lrzip + Archiv Lrzip + Lrzip-arkiv + Lrzip-Archiv + συμπιεσμένο αÏχείο Lrzip + Lrzip archive + Lrzip-arkivo + archivador Lrzip + Lrzip-arkisto + Lrzip skjalasavn + archive lrzip + cartlann Lrzip + arquivo Lrzip + ×רכיון Lrzip + Lrzip arhiva + Lrzip archívum + Arsip Lrzip + Archivio Lrzip + Lrzip アーカイブ + Lrzip архиві + LRZIP 압축 íŒŒì¼ + Lrzip archyvas + Lrzip arhÄ«vs + Lrzip archief + Archiwum lrzip + Pacote Lrzip + Arhivă Lrzip + архив LRZIP + Archív Lrzip + Datoteka arhiva Lrzip + Lrzip-arkiv + архів lrzip + Lrzip 归档文件 + Lrzip å°å­˜æª” + + + + + + + + Tar archive (lrzip-compressed) + أرشي٠Tar (مضغوط-lrzip) + Ðрхив — tar, компреÑиран Ñ lrzip + arxiu tar (comprimit amb lrzip) + Archiv tar (komprimovaný pomocí lrzip) + Tar-arkiv (lrzip-komprimeret) + Tar-Archiv (lrzip-komprimiert) + αÏχειÌο Tar (συμπιεσμεÌνο με lrzip) + Tar archive (lrzip-compressed) + archivador Tar (comprimido con lrzip) + Tar-arkisto (lrzip-pakattu) + Tar skjalasavn (lrzip-stappað) + archive tar (compressée lrzip) + cartlann Tar (comhbhrúite le lrzip) + arquivo Tar (comprimido con lrzip) + ×רכיון Tar (מכווץ ×¢"×™ lrzip) + Tar arhiva (komprimirana lrzip-om) + Tar archívum (lrzip-pel tömörítve) + Arsip Tar (terkompresi lrzip) + Archivio tar (compresso con lrzip) + Tar アーカイブ (lrzip 圧縮) + Tar архиві (lrzip-пен Ñығылған) + TAR ë¬¶ìŒ íŒŒì¼ (LRZIP 압축) + Tar archyvas (suglaudintas su lrzip) + Tar arhÄ«vs (saspiests ar lrzip) + Tar archief (lrzip-compressed) + Archiwum tar (kompresja lrzip) + Pacote tar (compactado com lrzip) + Arhivă Tar (comprimată lrzip) + архив TAR (Ñжатый LRZIP) + Archív tar (komprimovaný pomocou lrzip) + Datoteka arhiva Tar (stisnjen z lrzip) + Tar-arkiv (lrzip-komprimerat) + архів tar (ÑтиÑнений lrzip) + Tar 归档文件 (lrzip 压缩) + Tar å°å­˜æª” (lrzip æ ¼å¼å£“縮) + + + + + + + Apple disk image + ДиÑк — Apple + imatge de disc d'Apple + Obraz disku Apple + Apple-diskaftryk + Apple-Datenträgerabbild + εικόνα δίσκου Apple + Apple disk image + imagen de disco de Apple + Apple-levytiedosto + image disque Apple + imaxe de disco de Appl + תמונת כונן Apple + Apple snimka diska + Apple lemezkép + Image disk Apple + Immagine disco Apple + Apple ディスクイメージ + Apple-ის სáƒáƒ“ისკრგáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ Apple диÑк бейнеÑÑ– + 애플 ë””ìŠ¤í¬ ì´ë¯¸ì§€ + Apple diska attÄ“ls + Apple disk image + Obraz dysku Apple + Imagem de disco Apple + образ диÑка Apple Mac OS X + Obraz disku Apple + Odtis diska Apple + Apple-skivavbild + Apple disk görüntüsü + образ диÑка Apple + Apple ç£ç›˜é•œåƒ + Apple ç£ç¢Ÿæ˜ åƒ + + + + Raw disk image + + + + + Raw disk image (XZ-compressed) + + + + + + raw CD image + صورة CD خامة + suvoraja vyjava CD + Изображение — raw CD + imatge de CD en cru + Surový obraz CD + rÃ¥ cd-aftryk + CD-Roh-Abbild + εικόνα πεÏιεχομένου ÏˆÎ·Ï†Î¹Î±ÎºÎ¿Ï Î´Î¯ÏƒÎºÎ¿Ï… + raw CD image + kruda lumdiskbildo + imagen de CD en bruto + CD gordinaren irudia + raaka CD-vedos + rá CD mynd + image CD brute + amhíomhá dhlúthdhiosca + imaxe de CD en bruto + תמונת דיסק גולמית + nyers CD-lemezkép + citra CD mentah + Immagine raw CD + 生 CD イメージ + өңделмеген CD бейнеÑÑ– + CD ì´ë¯¸ì§€ + raw CD atvaizdis + CD jÄ“lattÄ“ls + Imej CD mentah + rÃ¥tt CD-bilde + ruw CD-beeldbestand + rÃ¥tt CD-bilete + Surowy obraz CD + imagem em bruto de CD + Imagem bruta de CD + imagine de CD brută + образ компакт-диÑка + Surový obraz CD + surovi CD odtis + Imazh raw CD + Ñирови отиÑак ЦД-а + rÃ¥ cd-avbild + образ raw CD + ảnh Ä‘Ä©a CD thô + 原始 CD æ˜ åƒ + 原生 CD æ˜ åƒ + + + + + + + CD Table Of Contents + جدول محتويات الـ CD + ŹmieÅ›civa CD + Съдържание на CD + taula de continguts de CD + Obsah CD + Cd-indholdsfotegnelse + CD-Inhaltsverzeichnis + Πίνακας ΠεÏιεχομένων CD + CD Table Of Contents + Ãndice de contenidos de CD + CDaren edukien aurkibidea + CD-sisällysluettelo + CD innihaldsyvurlit + table des matières de CD + clár ábhar dlúthdhiosca + táboa de contidos de CD + תוכן ×¢× ×™×™× ×™× ×©×œ דיסק + CD sadržaj + CD tartalomjegyzék + Tabel Isi CD + Indice CD + CD Table Of Contents + CD құрама кеÑтеÑÑ– + CD ë‚´ìš© ëª©ë¡ + CD turinys + CD satura rÄdÄ«tÄjs + Innholdsfortegnelse for CD + CD-inhoudsopgave + CD innhaldsliste + Plik zawartoÅ›ci pÅ‚yty CD + Sumário de CD + Tabel conÈ›inut CD + таблица ÑÐ¾Ð´ÐµÑ€Ð¶Ð°Ð½Ð¸Ñ CD + Obsah CD + Kazalo vsebine CD nosilca + Tregues CD + Cd-innehÃ¥llsförteckning + зміÑÑ‚ CD + Mục Lục của Ä‘Ä©a CD + CD 索引 + CD 內容目錄 + + + + + + + + + + + + + + + PGN chess game notation + تدوينة لعبة الشطرنج PGN + Zaciem ab Å¡achmatnaj partyi PGN + Игра шах — PGN + notació de joc d'escacs PGN + Å achová notace PGN + PGN-skakspilsnotation + PGN-Schachspielnotation + σημειογÏαφία Ï€Î±Î¹Ï‡Î½Î¹Î´Î¹Î¿Ï ÏƒÎºÎ±ÎºÎ¹Î¿Ï PGN + PGN chess game notation + notación para juegos de ajedrez PGN + PGN xake jokoaren notazioa + PGN-Å¡akkipelinotaatio + PGN talv teknskipan + notation de jeu d'échecs PGN + nodaireacht chluiche ficheall PGN + Notación de xogo de xadrez PGN + סימון משחק שח PGN + PGN sakkfeljegyzés + Notasi permainan catur PGN + Notazione partita a scacchi PGN + PGN ãƒã‚§ã‚¹ã‚²ãƒ¼ãƒ è¨˜éŒ² + PGN шахмат ойыны + PGN 체스게임 기보 + PGN Å¡achmatų žaidimo žymÄ—jimas + PGN Å¡aha spÄ“les notÄcija + PGN sjakkspillnotasjon + PGN-schaakspelnotatie + PGN-sjakkspelnotasjon + Plik PGN notacji gry w szachy + Notação de jogo de xadrez PGN + NotaÈ›ie joc È™ah PGN + ÑˆÐ°Ñ…Ð¼Ð°Ñ‚Ð½Ð°Ñ Ð¿Ð°Ñ€Ñ‚Ð¸Ñ PGN + Å achová notácia PGN + Datoteka opomb Å¡ahovske igre PGN + Njoftim loje shahu PGN + PGN-schackpartinotation + Ð·Ð°Ð¿Ð¸Ñ Ð³Ñ€Ð¸ у шахи PGN + Cách ghi lượt chÆ¡i cá» PGN + PGN 象棋游æˆæ³¨è®° + PGN 國際象棋棋譜 + + + + + + + + + CHM document + مستند CHM + Dakument CHM + Документ — CHM + document CHM + Dokument CHM + CHM-dokument + CHM-Dokument + έγγÏαφο CHM + CHM document + CHM-dokumento + documento CHM + CHM dokumentua + CHM-asiakirja + CHM skjal + document CHM + cáipéis CHM + documento CHM + מסמך CHM + CHM dokument + CHM dokumentum + Dokumen CHM + Documento CHM + CHM ドキュメント + CHM დáƒáƒ™áƒ£áƒ›áƒ”ნტი + CHM құжаты + CHM 문서 + CHM dokumentas + CHM dokuments + CHM-dokument + CHM-document + CHM-dokument + Dokument CHM + Documento CHM + Document CHM + документ CHM + Dokument CHM + Dokument CHM + Dokument CHM + CHM-dokument + документ CHM + Tài liệu CHM + CHM 文档 + CHM 文件 + CHM + Compiled Help Modules + + + + + + Java byte code + رمز بايت الـJava + Java bayt kodu + Bajtavy kod Java + Байт код за Java + codi byte de Java + Bajtový kód Java + Côd beit Java + Javabytekode + Java-Bytecode + συμβολοκώδικας Java + Java byte code + Java-bajtkodo + bytecode Java + Java byte-kodea + Java-tavukoodi + Java býtkota + code Java binaire + beartchód Java + byte code de Java + קוד Java byte + Java-bájtkód + Kode bita Java + Bytecode Java + Java ãƒã‚¤ãƒˆã‚³ãƒ¼ãƒ‰ + Java байт коды + ìžë°” ë°”ì´íŠ¸ì½”ë“œ + Java baitinis kodas + Java bitu kods + Kod bait Java + Java-bytekode + Java-bytecode + Jave byte-kode + Kod bajtowy Java + 'byte-code' Java + Código compilado Java + Bytecode Java + байт-код Java + Bajtový kód Java + Datoteka bitne kode Java + Byte code Java + Јава бајтни ко̂д + Java-bytekod + Байт-код Java + Mã byte Java + Java å­—èŠ‚ç  + Java ä½å…ƒçµ„碼 + + + UNIX-compressed file + مل٠يونكس-مضغوط + Skampresavany UNIX-fajÅ‚ + Файл — компреÑиран за UNIX + fitxer comprimit UNIX + Soubor komprimovaný v Unixu + UNIX-komprimeret fil + UNIX-komprimierte Datei + αÏχείο συμπιεσμένο με compress + UNIX-compressed file + UNIX-kunpremita dosiero + archivo comprimido de Unix + UNIX-en konprimitutako fitxategia + UNIX-pakattu tiedosto + UNIX-stappað fíla + fichier compressé UNIX + comhad UNIX-comhbhrúite + ficheiro comprimido de UNIX + קובץ מכווץ של UNIX + UNIX-komprimirana datoteka + Tömörített UNIX-fájl + Berkas terkompresi UNIX + File compresso-UNIX + UNIX-compress ファイル + файл (UNIX-Ñығылған) + UNIX 압축 íŒŒì¼ + UNIX suglaudintas failas + UNIX saspiesta datne + Fail termampat-UNIX + UNIX-komprimert fil + UNIX-ingepakt bestand + UNIX-komprimert fil + Skompresowany plik systemu UNIX + ficheiro comprimido UNIX + Arquivo compactado do UNIX + FiÈ™ier comprimat UNIX + файл (UNIX-Ñжатый) + Súbor komprimovaný v Unixe + SkrÄena Unix datoteka + File i kompresuar UNIX + UNIX-компреÑована датотека + UNIX-komprimerad fil + UNIX-sıkıştırılmış dosyası + ÑтиÑнений файл UNIX + Tập tin đã nén UNIX + UNIX 压缩文件 + UNIX æ ¼å¼å£“縮檔 + + + + + + + + Tar archive (gzip-compressed) + أرشي٠Tar (مضغوط-gzip) + ArchiÅ­ tar (gzip-skampresavany) + Ðрхив — tar, компреÑиран Ñ gzip + arxiu tar (comprimit amb gzip) + Archiv tar (komprimovaný pomocí gzip) + Tar-arkiv (gzip-komprimeret) + Tar-Archiv (gzip-komprimiert) + αÏχειÌο Tar (συμπιεσμεÌνο με gzip) + Tar archive (gzip-compressed) + archivador Tar (comprimido con gzip) + Tar artxiboa (gzip-ekin konprimitua) + Tar-arkisto (gzip-pakattu) + Tar skjalasavn (gzip-stappað) + archive tar (compressée gzip) + cartlann Tar (comhbhrúite le gzip) + arquivo Tar (comprimido con gzip) + ×רכיון Tar (מכווץ ×¢"×™ gzip) + Tar arhiva (komprimirana gzip-om) + Tar archívum (gzip-pel tömörítve) + Arsip Tar (terkompresi gzip) + Archivio tar (compresso con gzip) + Tar アーカイブ (gzip 圧縮) + Tar архиві (gzip-пен Ñығылған) + TAR ë¬¶ìŒ íŒŒì¼ (GZIP 압축) + Tar archyvas (suglaudintas su gzip) + Tar arhÄ«vs (saspiests ar gzip) + Tar-arkiv (gzip-komprimert) + Tar-archief (ingepakt met gzip) + Tar-arkiv (pakka med gzip) + Archiwum tar (kompresja gzip) + Pacote tar (compactado com gzip) + Arhivă Tar (comprimată gzip) + архив TAR (Ñжатый GZIP) + Archív tar (komprimovaný pomocou gzip) + Datoteka arhiva Tar (stisnjen z gzip) + Arkiv tar (i kompresuar me gzip) + Tar-arkiv (gzip-komprimerat) + архів tar (ÑтиÑнений gzip) + Kho nén tar (đã nén gzip) + Tar 归档文件(gzip 压缩) + Tar å°å­˜æª” (gzip æ ¼å¼å£“縮) + + + + + + + program crash data + معلومات انهيار البرنامج + źviestki zÅ‚amanaj prahramy + Данни от забиване на програма + dades de fallada de programa + Data o pádu programu + programnedbrudsdata + Daten zu Programmabsturz + δεδομένα από την κατάÏÏευση Ï€ÏογÏάμματος + program crash data + datumo pri kraÅo de programo + datos de cuelgue de programa + programaren kraskaduraren datuak + ohjelman kaatumistiedot + forrits sordáta + données de plantage de programme + sonraí thuairt ríomhchláir + datos de colgue do programa + מידע מקריסת תוכנה + podaci o ruÅ¡enju programa + összeomlott program adatai + data program macet + Dati crash di applicazione + プログラムクラッシュデータ + апатты аÑқтаудың мәліметтері + 프로그램 ë¹„ì •ìƒ ì¢…ë£Œ ë°ì´í„° + programos nulūžimo duomenys + programmas avÄrijas dati + Data program musnah + krasjdata fra program + programma-crashgegevens + data om programkrasj + Dane awarii programu + dados de estoiro de aplicação + Dados de travamento de programa + date eroare program + данные аварийного Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ + Údaje o páde programu + podatki sesutja programa + Të dhëna nga programi i bllokuar + подаци о кркљавини програма + programkraschdata + аварійні дані про програму + dữ liệu sụp đổ chÆ°Æ¡ng trình + 程åºå´©æºƒæ•°æ® + 程å¼ç•¶æŽ‰è³‡æ–™ + + + + + + + + + + + + + + + + + + + CPIO archive + أرشي٠CPIO + CPIO arxivi + ArchiÅ­ CPIO + Ðрхив — CPIO + arxiu CPIO + Archiv CPIO + Archif CPIO + CPIO-arkiv + CPIO-Archiv + αÏχείο CPIO + CPIO archive + CPIO-arkivo + archivador CPIO + CPIO artxiboa + CPIO-arkisto + CPIO skjalasavn + archive CPIO + cartlann CPIO + arquivo CPIO + ×רכיון CPIO + CPIO arhiva + CPIO-archívum + Arsip CPIO + Archivio CPIO + CPIO アーカイブ + CPIO áƒáƒ áƒ¥áƒ˜áƒ•áƒ˜ + CPIO архиві + CPIO ë¬¶ìŒ íŒŒì¼ + CPIO archyvas + CPIO arhÄ«vs + Arkib CPIO + CPIO-arkiv + CPIO-archief + CPIO-arkiv + Archiwum CPIO + arquivo CPIO + Pacote CPIO + Arhivă CPIO + архив CPIO + Archív CPIO + Datoteka arhiva CPIO + Arkiv CPIO + CPIO архива + CPIO-arkiv + архів CPIO + Kho nén CPIO + CPIO 归档文件 + CPIO å°å­˜æª” + + + + + + + + + + + CPIO archive (gzip-compressed) + أرشي٠CPIO (مضغوط-gzip) + CPIO arxivi (gzip ilÉ™ sıxışdırılmış) + ArchiÅ­ CPIO (gzip-skampresavany) + Ðрхив — CPIO, компреÑиран Ñ gzip + arxiu CPIO (comprimit amb gzip) + Archiv CPIO (komprimovaný pomocí gzip) + Archif CPIO (gywasgwyd drwy gzip) + CPIO-arkiv (gzip-komprimeret) + CPIO-Archiv (gzip-komprimiert) + αÏχείο CPIO (συμπιεσμένο με gzip) + CPIO archive (gzip-compressed) + CPIO-arkivo (kunpremita per gzip) + archivador CPIO (comprimido con gzip) + CPIO artxiboa (gzip-ekin konprimitua) + CPIO-arkisto (gzip-pakattu) + CPIO skjalasavn (gzip-stappað) + archive CPIO (compressé gzip) + cartlann CPIO (comhbhrúite le gzip) + arquivo CPIO (comprimido con gzip) + ×רכיון CPIO (מכווץ ×¢"×™ gzip) + CPIO arhiva (komprimirana gzip-om) + CPIO-archívum (gzip-pel tömörítve) + Arsip CPIO (terkompresi gzip) + Archivio CPIO (compresso con gzip) + CPIO (gzip 圧縮) アーカイブ + CPIO áƒáƒ áƒ¥áƒ˜áƒ•áƒ˜ (gzip-ით შეკუმშული) + CPIO архиві (gzip-пен Ñығылған) + CPIO ë¬¶ìŒ íŒŒì¼ (GZIP 압축) + CPIO archyvas (suglaudintas su gzip) + CPIO arhÄ«vs (saspiests ar gzip) + Arkib CPIO (dimampatkan-gzip) + CPIO-arkiv (gzip-komprimert) + CPIO-archief (ingepakt met gzip) + CPIO-arkiv (gzip-pakka) + Archiwum CPIO (kompresja gzip) + arquivo CPIO (comprimido com gzip) + Pacote CPIO (compactado com gzip) + Arhivă CPIO (compresie gzip) + архив CPIO (Ñжатый GZIP) + Archív CPIO (komprimovaný pomocou gzip) + Datoteka arhiva CPIO (skrÄena z gzip) + Arkiv CPIO (kompresuar me gzip) + CPIO архива (компреÑована gzip-ом) + CPIO-arkiv (gzip-komprimerat) + архів CPIO (ÑтиÑнений gzip) + Kho nén CPIO (đã nén gzip) + CPIO 归档文件(gzip 压缩) + CPIO å°å­˜æª” (gzip æ ¼å¼å£“縮) + + + + + + C shell script + سكربت Ø´ÙÙ„ سي + C qabıq skripti + Skrypt abaÅ‚onki C + Скрипт — обвивка C + script en C + Skript shellu C + Sgript plisgyn C + C-skalprogram + C-Shell-Skript + Ï€ÏόγÏαμμα εντολών Ï†Î»Î¿Î¹Î¿Ï C + C shell script + skripto de C-Åelo + script en C shell + C shell script-a + Csh-komentotiedosto + C skel boðrøð + script C shell + script bhlaosc C + script de C shell + תסריט מעטפת C + C skripta + C héj-parancsfájl + Skrip shell C + Script C shell + C シェルスクリプト + C shell Ñценарийі + C ì…¸ 스í¬ë¦½íŠ¸ + C shell scenarijus + C Äaulas skripts + Skrip shell C + C-skallskript + C-shellscript + C-skalskript + Skrypt powÅ‚oki C + 'script' de consola C + Script de shell C + Script C shell + Ñценарий C shell + Skript shellu C + Skriptna datoteka lupine C + Script shell C + C Ñкрипта окружења + Skalskript (csh) + C kabuk betiÄŸi + Ñкрипт оболонки C + Văn lệnh trình bao C + C shell 脚本 + C shell 指令稿 + + + + + + + + + + + + + Xbase document + مستند Xbase + Dakument Xbase + Документ — Xbase + document Xbase + Dokument Xbase + Xbasedokument + Xbase-Dokument + έγγÏαφο Xbase + Xbase document + Xbase-dokumento + documento Xbase + Xbase dokumentua + Xbase-asiakirja + Xbase skjal + document Xbase + cáipéis Xbase + documento Xbase + מסמך Xbase + Xbase dokumentum + Dokumen Xbase + Documento Xbase + Xbase ドキュメント + Xbase құжаты + Xbase 문서 + Xbase dokumentas + Xbase dokuments + Xbase-dokument + Xbase-document + Xbase-dokument + Dokument Xbase + Documento do Xbase + Document Xbase + документ Xbase + Dokument Xbase + Dokument Xbase + Dokument Xbase + Xbase-dokument + Xbase belgesi + документ Xbase + Tài liệu Xbase + Xbase 文档 + Xbase 文件 + + + + + + + + ECMAScript program + برنامج ECMAScript + Prahrama ECMAScript + Програма — ECMAScript + programa ECMAScript + Program ECMAScript + ECMA-program + ECMAScript-Programm + Ï€ÏόγÏαμμα ECMAScript + ECMAScript program + programa en ECMAScript + ECMAScript programa + ECMAScript-ohjelma + ECMAScript forrit + programme ECMAScript + ríomhchlár ECMAScript + programa en ECMAScript + תכנית EMCAScript + ECMAScript program + ECMAScript program + Program ECMAScript + Programma ECMAScript + ECMAScript プログラム + ECMAScript პრáƒáƒ’რáƒáƒ›áƒ + ECMAScript программаÑÑ‹ + ECMA스í¬ë¦½íŠ¸ 프로그램 + ECMAScript programa + ECMAScript programma + ECMAScript-program + ECMAScript-programma + ECMAScript-program + Pogram ECMAScript + Programa ECMAScript + Program ECMAScript + программа ECMAScript + Program ECMAScript + Programska datoteka ECMAScript + Program ECMAScript + ECMAScript-program + ECMAScript programı + програма мовою ECMAScript + ChÆ°Æ¡ng trình ECMAScript + ECMAScript ç¨‹åº + ECMAScript ç¨‹å¼ + + + + + + + Dreamcast ROM + Dreamcast ROM + Dreamcast ROM + ROM — Dreamcast + ROM de Dreamcast + ROM pro Dreamcast + Dreamcast-rom + Dreamcast-ROM + εικόνα μνήμης ROM Dreamcast + Dreamcast ROM + Dreamcast-NLM + ROM de Dreamcast + Dreamcast-en ROM + Dreamcast-ROM + Dreamcast ROM + ROM Dreamcast + ROM Dreamcast + ROM de Dreamcast + ROM של Dreamcast + Dreamcast ROM + Dreamcast ROM + Memori baca-saja Dreamcast + ROM Dreamcast + Dreamcast ROM + Dreamcast-ის ROM + Dreamcast ROM + 드림ìºìŠ¤íŠ¸ 롬 + Dreamcast ROM + Dreamcast ROM + ROM Dreamcast + Dreamcast-ROM + Dreamcast-ROM + Dreamcast-ROM + Plik ROM konsoli Dreamcast + ROM Dreamcast + ROM do Dreamcast + ROM Dreamcast + Dreamcast ROM + ROM pre Dreamcast + Bralni pomnilnik Dreamcast + ROM Dreamcast + Dreamcast ROM + Dreamcast-rom + ППП Dreamcast + ROM Dreamcast + Dreamcast ROM + Dreamcast ROM + + + + + Nintendo DS ROM + Nintendo DS ROM + Nintendo DS ROM + ROM — Nintendo DS + ROM de Nintendo DS + ROM pro Nintendo DS + Nintendo DS-rom + Nintendo-DS-ROM + εικόνα μνήημης ROM Nintendo DS + Nintendo DS ROM + ROM de Nintendo DS + Nintendo DS-ko ROMa + Nintendo DS-ROM + Nintendo DS ROM + ROM Nintendo DS + ROM Nintendo DS + ROM de Nintendo DS + ROM של Nintendo + Nintendo DS ROM + Nintendo DS ROM + Memori baca-saja Nintendo DS + ROM Nintendo DS + Nintendo DS ROM + Nintendo DS ROM + ë‹Œí…ë„ DS 롬 + Nintendo DS ROM + Nintendo DS ROM + Nintendo DS-ROM + Nintendo-DS-ROM + Nintendo DS-ROM + Plik ROM konsoli Nintendo DS + ROM do Nintendo DS + ROM Nintendo DS + Nintendo DS ROM + ROM pre Nintendo DS + Bralni pomnilnik Nintendo DS + ROM Nintendo DS + Nintendo DS-rom + Nintendo DS ROM + ППП Nintendo + ROM DS Nintendo + Nintendo DS ROM + 任天堂 DS ROM + + + + + Debian package + حزمة ديبيان + Debian paketi + Pakunak Debian + Пакет — Debian + paquet Debian + BalíÄek Debianu + Pecyn Debian + Debianpakke + Debian-Paket + πακέτο Debian + Debian package + Debian-pakaĵo + paquete Debian + Debian paketea + Debian-paketti + Debian pakki + paquet Debian + pacáiste Debian + paquete de Debian + חבילת דבי×ן + Debian paket + Debian-csomag + Paket Debian + Pacchetto Debian + Debian パッケージ + Debian-ის პáƒáƒ™áƒ”ტი + Debian деÑтеÑÑ– + ë°ë¹„안 패키지 + Debian paketas + Debian pakotne + Pakej Debian + Debian pakke + Debian-pakket + Debian pakke + Pakiet Debiana + pacote Debian + Pacote Debian + Pachet Debian + пакет Debian + BalíÄek Debianu + Datoteka paketa Debian + Paketë Debian + Debian пакет + Debianpaket + Debian paketi + пакунок Debian + Gói Debian + Debian 软件包 + Debian 套件 + + + + + + + + + + + Qt Designer file + مل٠Qt Designer + FajÅ‚ Qt Designer + Файл — Qt Designer + fitxer de Qt Designer + Soubor Qt Designer + Qt Designer-fil + Qt-Designer-Datei + αÏχείο Qt Designer + Qt Designer file + dosiero de Qt Designer + archivo de Qt Designer + Qt Designer Fitxategia + Qt Designer -tiedosto + Qt Designer fíla + fichier Qt Designer + comhad Qt Designer + ficheiro de Qt Designer + קובץ של Qt Designer + Qt Designer-fájl + Berkas Qt Designer + File Qt Designer + Qt Designer ファイル + Qt Designer файлы + Qt ë””ìžì´ë„ˆ íŒŒì¼ + Qt Designer failas + Qt Designer datne + Fail Qt Designer + Qt Designer-fil + Qt Designer-bestand + Qt Designer-fil + Plik Qt Designer + ficheiro do Qt Designer + Arquivo do Qt Designer + FiÈ™ier Qt Designer + файл Qt Designer + Súbor Qt Designer + Datoteka Qt Designer + File Qt Designer + Qt Designer датотека + Qt Designer-fil + файл програми Qt-дизайнер + Tập tin thiết kế Qt Designer + Qt Designer 文件 + Qt Designer 檔案 + + + + + + + + + + Qt Markup Language file + Файл — Qt Markup + fitxer de llenguatge de marcadors Qt + Soubor Qt Markup Language + Qt Markup Language-fil + Qt-Auszeichnungssprachendatei + αÏχείο Qt Markup Language + Qt Markup Language file + Archivo de lenguaje de marcado Qt + fichier Qt Markup Language + ficheiro de linguaxe de marcado Qt + קובץ שפת סימון של Qt + Qt jelölÅ‘nyelvű fájl + Berkas Bahasa Markup Qt + File Qt Markup Language + Qt マークアップ言語ファイル + Qt Markup Language файлы + Qt 마í¬ì—… 언어 íŒŒì¼ + Qt marÄ·Ä“Å¡anas valodas datne + Qt Markup Tallbestand + Plik jÄ™zyka znaczników Qt + Arquivo de Qt Markup Language + файл Qt Markup Language + Datoteka oznaÄevalnega jezika Qt + файл мови розмітки Qt + Qt + Qt 標記語言檔 + + + + + + + desktop configuration file + مل٠تضبيط سطح المكتب + kanfihuracyjny fajÅ‚ asiarodździa + Файл Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° Ñ€Ð°Ð±Ð¾Ñ‚Ð½Ð¸Ñ Ð¿Ð»Ð¾Ñ‚ + fitxer de configuració d'escriptori + Soubor nastavení pracovní plochy + skrivebordskonfigurationsfil + Desktop-Konfigurationsdatei + Ïυθμίσεις επιφάνειας εÏγασίας + desktop configuration file + dosiero de agordoj de labortablo + archivo de configuración del escritorio + Mahaigainaren konfigurazio-fitxategia + työpöydän asetustiedosto + skriviborðssamansetingarfíla + fichier de configuration desktop + comhad chumraíocht deisce + ficheiro de configuración de escritorio + קובץ הגדרות של שולחן העבודה + datoteka postavki radne povrÅ¡ine + asztalbeállító fájl + berkas konfigurasi destop + File configurazione desktop + デスクトップ設定ファイル + Ð¶Ò±Ð¼Ñ‹Ñ Ò¯Ñтел баптаулар файлы + ë°ìŠ¤í¬í†± 설정 íŒŒì¼ + darbastalio konfigÅ«racijos failas + darbvirsmas konfigurÄcijas datne + Fail konfigurasi desktop + konfigurasjonsfil for skrivebordet + bureaublad-configuratiebestand + skrivebordsoppsettfil + Plik konfiguracji Å›rodowiska + ficheiro de configuração de área de trabalho + Arquivo de configuração de área de trabalho + fiÈ™ier de configurare al desktopului + файл наÑтроек рабочего Ñтола + Súbor nastavení pracovnej plochy + nastavitvena datoteka namizja + File konfigurimi desktop + датотека за подешавања радне површи + skrivbordskonfigurationsfil + файл конфігурації Ñтільниці + tập tin cấu hình môi trÆ°á»ng + æ¡Œé¢é…置文件 + æ¡Œé¢çµ„態檔 + + + + + + + + + + + + + + + FictionBook document + مستند FictionBook + Документ — FictionBook + document FictionBook + Dokument FictionBook + FictionBook-dokument + FictionBook-Dokument + έγγÏαφο FictionBook + FictionBook document + FictionBook-dokumento + documento FictionBook + FictionBook dokumentua + FictionBook-asiakirja + FictionBook skjal + document FictionBook + cáipéis FictionBook + documento de FictionBook + מסמך FictionBook + FictionBook dokument + FictionBook-dokumentum + Dokumen FictionBook + Documento FictionBook + FictionBook ドキュメント + FictionBook-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + FictionBook құжаты + FictionBook 문서 + FictionBook dokumentas + FictionBook dokuments + FictionBook-document + Dokument FictionBook + Documento FictionBook + Document FictionBook + документ FictionBook + Dokument FictionBook + Dokument FictionBook + FictionBook-dokument + FictionBook belgesi + документ FictionBook + Tài liệu FictionBook + FictionBook 文档 + FictionBook 文件 + + + + + + + + + + Dia diagram + خطاطة Dia + Dia diaqramı + Dyjahrama Dia + Диаграма — Dia + diagrama de Dia + Diagram Dia + Diagram Dia + Dia-diagram + Dia-Diagramm + διάγÏαμμα Dia + Dia diagram + Dia-diagramo + diagrama de Dia + Dia diagrama + Dia-kaavio + Dia ritmynd + diagramme Dia + léaráid Dia + diagrama de Dia + גרף של Dia + Dia dijagram + Dia-diagram + Diagram Dia + Diagramma Dia + Dia ダイアグラム + Dia-ის დიáƒáƒ’რáƒáƒ›áƒ + Dia диаграммаÑÑ‹ + Dia ë„í‘œ + Dia diagrama + Dia diagramma + Diagram Dia + Dia-diagram + Dia-diagram + Dia diagram + Diagram Dia + diagrama Dia + Diagrama do Dia + Diagramă Dia + диаграмма Dia + Diagram Dia + Datoteka diagrama Dia + Diagramë Dia + Диа дијаграм + Dia-diagram + діаграма Dia + Biểu đồ Dia + Dia 图表 + Dia 圖表 + + + + + + + + + + Dia shape + شكل Dia + Фигура — Dia + forma del Dia + Tvary Dia + Dia-figur + Dia-Form + σχήμα Dia + Dia shape + forma de Dia + Dia-ren forma + Dia skapur + forme Dia + cruth Dia + forma de Dia + צורה של Dia + Dia oblik + Dia alakzat + Shape Dia + Sagoma Dia + Dia 図形 + Dia ÑызбаÑÑ‹ + Dia 그림 + Dia forma + Dia forma + Diavorm + KsztaÅ‚t Dia + Formato Dia + Figură Dia + фигура Dia + Datoteka oblik Dia + Dia-figur + форма Dia + Dia 形状 + Dia 形狀 + + + + + + + + + + TeX DVI document + مستند TeX DVI + Dakument TeX DVI + Документ — TeX DVI + document TeX DVI + Dokument TeX DVI + TeX DVI-dokument + TeX-DVI-Dokument + έγγÏαφο TeX DVI + TeX DVI document + DVI-dokumento de TeX + documento TeX DVI + TeX DVI dokumentua + TeX DVI -asiakirja + TeX DVI skjal + document TeX DVI + cáipéis DVI TeX + documento TeX DVI + מסמך מסוג TeX DVI + TeX DVI dokument + TeX DVI-dokumentum + Dokumen TeX DVI + Documento TeX DVI + TeX DVI ドキュメント + TeX DVI құжаты + TeX DVI 문서 + TeX DVI dokumentas + TeX DVI dokuments + Dokumen TeX DVI + TeX DVI-dokument + TeX DVI-document + TeX DVI-dokument + Dokument TeX DVI + documento TeX DVI + Documento DVI TeX + Document Tex DVI + документ TeX DVI + Dokument TeX DVI + Dokument TeX DVI + Dokument TeX DVI + ТеХ ДВИ документ + TeX DVI-dokument + документ TeX DVI + Tài liệu DVI Tex + TeX DVI 文档 + TeX DVI 文件 + DVI + Device independent file format + + + + + + + + Enlightenment theme + سمة Enlightenment + Enlightenment örtüyü + MatyÅ­ Enlightenment + Тема — Enlightenment + tema d'Enlightenment + Motiv Enlightenment + Thema Enlightenment + Enlightenmenttema + Enlightenment-Thema + Θέμα Enlightenment + Enlightenment theme + etoso de Enlightenment + tema de Enlightenment + Enlightenment gaia + Enlightenment-teema + Enlightenment tema + thème Enlightenment + téama Enlightenment + tema de Enlightenment + ערכת × ×•×©× ×©×œ Enlightenment + Enlightenment tema + Enlightenment-téma + Tema Enlightenment + Tema Enlightenment + Enlightenment テーマ + Enlightenment-ის თემრ+ Enlightenment темаÑÑ‹ + ì¸ë¼ì´íŠ¼ë¨¼íŠ¸ 테마 + Enlightenment tema + Enlightenment motÄ«vs + Tema Enlightenment + Enlightenment tema + Enlightenment-thema + Enlightenment-tema + Motyw Enlightenment + tema Enlightenment + Tema do Enlightenment + Temă Enlightenment + тема Enlightenment + Motív Enlightenment + Datoteka teme Enlightenment + Tema Enlightenment + Enlightenment тема + Enlightenment-tema + Enlightenment teması + тема Enlightenment + Sắc thái Enlightenment + Enlightenment 主题 + Enlightenment 佈景主題 + + + + Egon Animator animation + تحريكة محرك Egon + Animacyja Egon Animator + ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ â€” Egon Animator + animació d'Egon Animator + Animace Egon Animator + Egon Animator-animation + Egon-Animator-Animation + κινοÏμενα σχέδια Egon Animator + Egon Animator animation + animacio de Egon Animator + animación de Egon Animator + Egon Animator-eko animazioa + Egon Animator -animaatio + Egon Animator teknimyndagerð + animation Egon Animator + beochan Egon Animator + animación de Egon Animator + ×נימצייה של Egon Animator + Egon Animator animacija + Egon Animator-animáció + Animasi Egon Animator + Animazione Egon Animator + Egon Animator アニメーション + Egon Animator-ის áƒáƒœáƒ˜áƒ›áƒáƒªáƒ˜áƒ + Egon Animator анимациÑÑÑ‹ + Egon 애니메ì´í„° 애니메ì´ì…˜ + Egon Animator animacija + Egon Animator animÄcija + Animasi Egon Animator + Egon animator-animasjon + Egon Animator-animatie + Egon Animator-animasjon + Animacja Egon Animator + animação Egon Animator + Animação do Egon Animator + AnimaÈ›ie Egon Animator + Ð°Ð½Ð¸Ð¼Ð°Ñ†Ð¸Ñ Egon Animator + Animácia Egon Animator + Datoteka animacije Egon Animator + Animim Egon Animator + Егон аниматор анимација + Egon Animator-animering + Ð°Ð½Ñ–Ð¼Ð°Ñ†Ñ–Ñ Egon Animator + Hoạt ảnh Egon Animator + Egon Animator 动画 + Egon Animator å‹•ç•« + + + + + executable + تنÙيذي + vykonvalny fajÅ‚ + Изпълним файл + executable + Spustitelný soubor + kørbar + Programm + εκτελέσιμο + executable + plenumebla + ejecutable + exekutagarria + suoritettava ohjelma + inningarfør + exécutable + comhad inrite + executábel + קובץ הרצה + izvrÅ¡na datoteka + futtatható + dapat dieksekusi + Eseguibile + 実行ファイル + орындалатын + 실행 íŒŒì¼ + vykdomasis failas + izpildÄmais + Bolehlaksana + kjørbar + uitvoerbaar bestand + køyrbar + Program + executável + Executável + executabil + иÑполнÑемый + Spustiteľný súbor + izvedljiva datoteka + I ekzekutueshëm + извршна + körbar fil + çalıştırılabilir + виконуваний файл + thá»±c hiện được + å¯æ‰§è¡Œæ–‡ä»¶ + å¯åŸ·è¡Œæª” + + + + + + + + + + + + + + + + + + + + + FLTK Fluid file + مل٠FLTK Fluid + FajÅ‚ FLTK Fluid + Ð˜Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ â€” FLTK Fluid + fitxer Fluid FLTK + Soubor FLTK Fluid + FLTK Fluid-fil + FLTK-Fluid-Datei + FLTK Fluid file + archivo FLTK Fluid + FLTK Fluid fitxategia + FLTK Fluid -tiedosto + FLTK Fluid fíla + fichier Fluid FLTK + comhad FLTK Fluid + ficheiro FLTK Fluid + קובץ FLTK Fluid + FLTK Fluid datoteka + FLTK Fluid fájl + Berkas FLTK Fluid + File FLTK Fluid + FLTK Fluid ファイル + FLTK Fluid-ის ფáƒáƒ˜áƒšáƒ˜ + FLTK Fluid файлы + FLTK Fluid íŒŒì¼ + FLTK Fluid failas + FLTK Fluid datne + FLTK Fluid-fil + FLTK FLUID-bestand + FLTK Fluid-fil + Plik Fluid FLTK + Arquivo Fluid do FLTK + FiÈ™ier FLTK Fluid + файл FLTK Fluid + Súbor FLTK Fluid + Datoteka FLTK Fluid + File FLTK Fluid + FLTK Fluid-fil + FLTK Fluid dosyası + файл FLTK Fluid + Tập tin Fluid FLTK + FLTK æµä½“文档 + FLTK Fluid 檔 + FLTK + Fast Light Toolkit + + + + + + + + + WOFF font + WOFF + Web Open Font Format + + + + + + + + Postscript type-1 font + خط Postscript type-1 + Å ryft Postscript type-1 + Шрифт — Postscript Type 1 + tipus de lletra Postscript type-1 + Písmo Postscript type-1 + PostScript type-1-skrifttype + Postscript-Typ-1-Schrift + Postscript type-1 font + tipografía PostScript tipo-1 + PostScript type-1 letra-tipoa + PostScript tyyppi-1 -asiakirja + Postscript type-1 stavasnið + police Postscript Type 1 + cló Postscript type-1 + tipo de letra PostScript tipo-1 + גופן של Postscript type-1 + Postscript type-1 betűkészlet + Fonta tipe-1 Postscript + Tipo carattere Postscript type-1 + PostScript type-1 フォント + Postscript type-1 қарібі + í¬ìŠ¤íŠ¸ìŠ¤í¬ë¦½íŠ¸ Type-1 글꼴 + Postscript type-1 Å¡riftas + Postscript 1-tipa fonts + Postscript type-1 skrift + PostScript type-1-lettertype + PostScript type 1-skrifttype + Czcionka PostScript Type-1 + Fonte PostScript tipo-1 + Font Postscript type-1 + шрифт PostScript Type-1 + Písmo Postscript type-1 + Datoteka pisave Postscript vrste-1 + Lloj gërmash Postscript type-1 + Postscript type-1-typsnitt + шрифт Postscript type-1 + Phông kiểu 1 PostScript + Postscript type-1 字体 + Postscript type-1 å­—åž‹ + + + + + + + + + + + + + + + + Adobe font metrics + مقاييس خط أدوبي + Adobe yazı növü metriklÉ™ri + Metryka Å¡ryftu Adobe + Шрифтова метрика — Adobe + mètrica de tipus de lletra Adobe + Metrika písma Adobe + Metrigau Ffont Adobe + Adobe skrifttypefil + Adobe-Schriftmetriken + μετÏικά γÏαμματοσειÏάς Adobe + Adobe font metrics + metrikoj de Adobe-tiparo + métricas de tipografía Adobe + Adobe letra-tipoen neurriak + Adobe-kirjasinmitat + métriques de police Adobe + meadarachtaí cló Adobe + métricas de fonte de Adobe + מדדי גופן של Adobe + Adobe mjere fonta + Adobe-betűmetrika + Metrik fonta Adobe + Metriche tipo carattere Adobe + Adobe フォントメトリック + Adobe қаріп метрикалары + ì–´ë„비 글꼴 메트릭 + Adobe Å¡riftų metrika + Adobe fonta metrika + Metrik font Adobe + Adobe skrifttypefil + Adobe-lettertype-metrieken + Adobe skrifttypemetrikk + Metryka czcionki Adobe + métrica de tipos de letra Adobe + Métricas de fonte Adobe + Dimensiuni font Adobe + метрика шрифта Adobe + Metrika písma Adobe + Matrika pisave Adobe + Metrik lloj gërmash Adobe + Adobe метрика фонта + Adobe-typsnittsmetrik + метрики шрифту Adobe + Cách Ä‘o phông chữ Adobe + Adobe 字体å‚æ•° + Adobe å­—åž‹æ述檔 + + + + + BDF font + خط BDF + BDF yazı növü + Å ryft BDF + Шрифт — BDF + tipus de lletra BDF + Písmo BDF + Ffont BDF + BDF-skrifttype + BDF-Schrift + γÏαμματοσειÏά BDF + BDF font + BDF-tiparo + tipografía BDF + BDF letra-tipoa + BDF-kirjasin + BDF stavasnið + police BDF + cló BDF + tipo de fonte BDF + גופן BDF + BDF font + BDF-betűkészlet + Fonta BDF + Tipo carattere BDF + BDF フォント + BDF қарібі + BDF 글꼴 + BDF Å¡riftas + BDF fonts + Font BDF + BDF-skrifttype + BDF-lettertype + BDF-skrifttype + Czcionka BDF + tipo de letra BDF + Fonte BDF + Font BDF + шрифт BDF + Písmo BDF + Datoteka pisave BDF + Lloj gërme BDF + BDF фонт + BDF-typsnitt + BDF fontu + шрифт BDF + Phông chữ BDF + BDF 字体 + BDF å­—åž‹ + + + + + + + + DOS font + خط DOS + DOS yazı növü + Å ryft DOS + Шрифт — DOS + tipus de lletra DOS + Písmo pro DOS + Ffont DOS + DOS-skrifttype + DOS-Schrift + γÏαμματοσειÏά DOS + DOS font + DOS-tiparo + tipografía DOS + DOS letra-tipoa + DOS-kirjasin + DOS stavasnið + police DOS + cló DOS + tipo de fonte de DOS + גופן DOS + DOS font + DOS-betűkészlet + Fonta DOS + Tipo carattere DOS + DOS フォント + DOS қарібі + DOS 글꼴 + DOS Å¡riftas + DOS fonts + Font DOS + DOS-skrifttype + DOS-lettertype + DOS-skrifttype + Czcionka DOS + tipo de letra DOS + Fonte do DOS + Font DOS + шрифт DOS + Písmo pre DOS + Datoteka pisave DOS + Gërmë DOS + DOS фонт + DOS-typsnitt + DOS fontu + шрифт DOS + Phông chữ DOS + DOS 字体 + DOS å­—åž‹ + + + + + + + + + Adobe FrameMaker font + خط أدوبي الصانع للإطارات + Adobe FrameMaker yazı növü + Å ryft Adobe FrameMaker + Шрифт — Adobe FrameMaker + tipus de lletra d'Adobe FrameMaker + Písmo Adobe FrameMaker + Ffont Adobe FrameMaker + Adobe FrameMaker-skrifttype + Adobe-FrameMaker-Schrift + γÏαμματοσειÏά Adobe FrameMaker + Adobe FrameMaker font + Tiparo de Adobe FrameMaker + tipografía de Adobe FrameMaker + Adobe FrameMaker-en letra-tipoa + Adobe FrameMaker -kirjasin + Adobe FrameMaker stavasnið + police Adobe FrameMaker + cló Adobe FrameMaker + tipo de fonte de Adobe FrameMaker + גופן של Adobe FrameMaker + Adobe FrameMaker font + Adobe FrameMaker-betűkészlet + Fonta Adobe FrameMaker + Tipo carattere Adobe FrameMaker + Adobe FrameMaker フォント + Adobe FrameMaker қарібі + ì–´ë„비 프레임메ì´ì»¤ 글꼴 + Adobe FrameMaker Å¡riftas + Adobe FrameMaker fonts + Font Adobe FrameMaker + Adobe FrameMaker skrifttype + Adobe FrameMaker-lettertype + Adobe FrameMaker-skrifttype + Czcionka Adobe FrameMaker + tipo de letra Adobe FrameMaker + Fonte do Adobe FrameMaker + Font Adobe FrameMaker + шрифт Adobe FrameMaker + Písmo Adobe FrameMaker + Datoteka pisave Adobe FrameMaker + Gërma Adobe FrameMaker + Adobe FrameMaker фонт + Adobe FrameMaker-typsnitt + шрифт Adobe FrameMaker + Phông chữ Adobe FrameMaker + Adobe FrameMaker 字体 + Adobe FrameMaker å­—åž‹ + + + + + + + LIBGRX font + خط LIBGRX + LIBGRX yazı növü + Å ryft LIBGRX + Шрифт — LIBGRX + tipus de lletra LIBGRX + Písmo LIBGRX + Ffont LIBGRX + LIBGRX-skrifttype + LIBGRX-Schrift + γÏαμματοσειÏά LIBGRX + LIBGRX font + LIBGRX-tiparo + tipografía LIBGRX + LIBGRX letra-tipoa + LIBGRX-kirjasin + LIBGRX stavasnið + police LIBGRX + cló LIBGRX + tipo de fonte en LIBGRX + גופן LIBGRX + LIBGRX font + LIBGRX-betűkészlet + Fonta LIBGRX + Tipo carattere LIBGRX + LIBGRX フォーマット + LIBGRX қарібі + LIBGRX 글꼴 + LIBGRX Å¡riftas + LIBGRX fonts + Font LIBGRX + LIBGRX-skrifttype + LIBGRX-lettertype + LIBGRX skrifttype + Czcionka LIBGRX + tipo de letra LIBGRX + Fonte LIBGRX + Font LIBGRX + шрифт LIBGRX + Písmo LIBGRX + Datoteka pisave LIBGRX + Lloj gërme LIBGRX + LIBGRX фонт + LIBGRX-typsnitt + LIBGRX fontu + шрифт LIBGRX + Phông chữ LIBGRX + LIBGRX 字体 + LIBGRX å­—åž‹ + + + + + + + Linux PSF console font + خط كونسول PSF لينكس + Linux PSF konsol yazı növü + Kansolny Å¡ryft PSF dla Linuksa + Шрифт — PSF, за конзолата на Ð›Ð¸Ð½ÑƒÐºÑ + tipus de lletra de consola Linux PSF + Písmo PSF pro konzolu Linuxu + Ffont Linux PSF + Linux PSF-konsolskrifttype + Linux-PSF-Konsolenschrift + γÏαμματοσειÏά κονσόλας PSF Linux + Linux PSF console font + PSF-tiparo de Linux-konzolo + tipografía de consola Linux PSF + Linux PSF kontsolako letra-tipoa + Linux PSF -konsolikirjasin + Linux PSF stýristøðs stavasnið + police console Linux PSF + cló chonsól Linux PSF + tipo de fonte de consola Linux PSF + גופן לקונסול מסוג Linux PSF + Linux PSF konzolni font + Linux PSF konzolos betűkészlet + Fonta konsol Linux PSF + Tipo carattere console Linux PSF + Linux PSF コンソールフォント + Linux PSF конÑольдік қарібі + 리눅스 PSF 콘솔 글꼴 + Linux PSF konsolÄ—s Å¡riftas + Linux PSF konsoles fonts + Font konsol PSF Linux + Linux PSF konsollskrifttype + Linux PSF-console-lettertype + Linux PSF konsoll-skrifttype + Czcionka konsoli PSF Linux + tipo de letra de consola Linux PSF + Fonte de console Linux PSF + Font consolă Linux PSF + конÑольный шрифт Linux PSF + Písmo PSF pre konzolu Linuxu + Datoteka pisave konzole Linux PSF + Lloj gërme për konsolë Linux PSF + Ð›Ð¸Ð½ÑƒÐºÑ PSF конзолни фонт + Linux PSF-konsolltypsnitt + Linux PSF konsol fontu + конÑольний шрифт Linux PSF + Phông chữ bàn giao tiếp PSF Linux + Linux PSF 控制å°å­—体 + Linux PSF console å­—åž‹ + + + + + + + + Linux PSF console font (gzip-compressed) + خط كونسول PSF لينكس (مضغوط-gzip) + Kansolny Å¡ryft PSF dla Linuksa (gzip-skampresavany) + Шрифт — Linux PSF, компреÑиран Ñ gzip + tipus de lletra de consola Linux PSF (comprimida amb gzip) + Písmo PSF pro konzolu Linuxu (komprimované pomocí gzip) + Linux PSF-konsolskrifttype (gzip-komprimeret) + Linux-PSF-Konsolenschrift (gzip-komprimiert) + γÏαμματοσειÏά κονσόλας PSF Linux (συμπιεσμένη με gzip) + Linux PSF console font (gzip-compressed) + tipografía de consola Linux PSF (comprimida con gzip) + Linux PSF kontsolako letra-tipoa (gzip-ekin konprimitua) + Linux PSF -konsolikirjasin (gzip-pakattu) + Linux PSF stýristøðs stavasnið (gzip-stappað) + police console Linux PSF (compressée gzip) + cló chonsól Linux PSF (comhbhrúite le gzip) + tipo de fonte de consola Linux PSF (comprimida con gzip) + גופן לקונסול מסוג Linux PSF (מכווץ ×¢"×™ gzip) + Linux PSF konzolni font (komprimiran gzip-om) + Linux PSF konzolos betűkészlet (gzip-tömörítésű) + Fonta konsol Linux PSF (terkompresi gzip) + Tipo carattere console Linux PSF (compresso con gzip) + Linux PSF コンソールフォント (gzip 圧縮) + Linux PSF конÑольдік қарібі (gzip-пен Ñығылған) + 리눅스 PSF 콘솔 글꼴 (GZIP 압축) + Linux PSF konsolÄ—s Å¡riftas (suglaudintas su gzip) + Linux PSF konsoles fonts (saspiests ar gzip) + Linux PSF konsollskrifttype (gzip-komprimert) + Linux PSF-console-lettertype (ingepakt met gzip) + Linux PSF konsoll-skrifttype (gzip-pakka) + Czcionka konsoli PSF Linux (kompresja gzip) + Fonte de console Linux PSF (compactada com gzip) + Font consolă Linux PSF (compresie gzip) + конÑольный шрифт Linux PSF (Ñжатый gzip) + Písmo PSF pre konzolu Linuxu (komprimované pomocou gzip) + Datoteka pisave konzole Linux PSF (skrÄena z gzip) + Lloj gërme për konsolë Linux PSF (komresuar me gzip) + Linux PSF-konsolltypsnitt (gzip-komprimerat) + Linux PSF konsol fontu (gzip ile sıkıştırılmış) + конÑольний шрифт Linux PSF (ÑтиÑнений gzip) + Phông chữ bàn giao tiếp PSF Linux (đã nén gzip) + Linux PSF 控制å°å­—体(gzip 压缩) + Linux PSF console å­—åž‹ (gzip æ ¼å¼å£“縮) + + + + + + PCF font + خط PCF + PCF yazı növü + Å ryft PCF + Шрифт — PCF + tipus de lletra PCF + Písmo PCF + Ffont PCF + PCF-skrifttype + PCF-Schrift + γÏαμματοσειÏά PCF + PCF font + PCF-tiparo + tipografía PCF + PCF letra-tipoa + PCF-kirjasin + PCF stavasnið + police PCF + cló PCF + tipo de letra PCF + פונט PCF + PCF-betűkészlet + Fonta PCF + Tipo carattere PCF + PCF フォント + PCF қарібі + PCF 글꼴 + PCF Å¡riftas + PCF fonts + Font PCF + PCF-skrifttype + PCF-lettertype + PCF-skrifttype + Czcionka PCF + tipo de letra PCF + Fonte PCF + Font PCF + шрифт PCF + Písmo PCF + Datoteka pisave PCF + Gërma PCF + PCF фонт + PCF-typsnitt + PCF fontu + шрифт PCF + Phông chữ PCF + PCF 字体 + PCF å­—åž‹ + + + + + + + + + + OpenType font + خط OpenType + OpenType yazı növü + Å ryft OpenType + Шрифт — OpenType + tipus de lletra OpenType + Písmo OpenType + Ffont OpenType + OpenType-skrifttype + OpenType-Schrift + γÏαμματοσειÏά OpenType + OpenType font + OpenType-tiparo + tipografía de OpenType + OpenType letra-tipoa + OpenType-kirjasin + OpenType stavasnið + police OpenType + cló OpenType + tipo de fonte OpenType + גופן של OpenType + OpenType-betűkészlet + Fonta OpenType + Tipo carattere OpenType + OpenType フォント + OpenType қарібі + 오픈타입 글꼴 + OpenType Å¡riftas + OpenType fonts + Font OpenType + OpenType-skrifttype + OpenType-lettertype + OpenType-skrifttype + Czcionka OpenType + tipo de letra OpenType + Fonte OpenType + Font OpenType + шрифт OpenType + Písmo OpenType + Datoteka pisave OpenType + Gërma OpenType + OpenType фонт + OpenType-typsnitt + OpenType fontu + шрифт OpenType + Phông chữ OpenType + OpenType 字体 + OpenType å­—åž‹ + + + + + + + + Speedo font + خط Speedo + Speedo yazı növü + Å ryft Speedo + Шрифт — Speedo + tipus de lletra Speedo + Písmo Speedo + Ffont Speedo + Speedoskrifttype + Speedo-Schrift + γÏαμματοσειÏά Speedo + Speedo font + Speedo-tiparo + tipografía Speedo + Speedo letra-tipoa + Speedo-kirjasin + Speedo stavasnið + police Speedo + cló Speedo + tipo de letra Speedo + גופן של Speedo + Speedo font + Speedo-betűkészlet + Fonta Speedo + Tipo carattere Speedo + Speedo フォント + Speedo қарібі + Speedo 글꼴 + Speedo Å¡riftas + Speedo fonts + Font Speedo + Speedo-skrifttype + Speedo-lettertype + Speedo-skrifttype + Czcionka Speedo + tipo de letra Speedo + Fonte Speedo + Font Speedo + шрифт Speedo + Písmo Speedo + Datoteka pisave Speedo + Gërma Speedo + Speedo фонт + Speedo-typsnitt + Speedo fontu + шрифт Speedo + Phông chữ Speedo + Speedo 字体 + Speedo å­—åž‹ + + + + + + + + SunOS News font + خط SunOS News + SunOS News yazı növü + Å ryft SunOS News + Шрифт — SunOS News + tipus de lletra SunOS News + Písmo SunOS News + Ffont SunOS News + SunOS News-skrifttype + SunOS-News-Schrift + γÏαμματοσειÏά SunOS News + SunOS News font + tiparo de SunOS News + tipografía SunOS News + SunOs News letra-tipoa + SunOS News -kirjasin + SunOS News stavasnið + police SunOS News + cló SunOS News + tipo de letra SunOS News + גופן של SunOS News + SunOS News font + SunOS News-betűkészlet + Fonta SunOS News + Tipo carattere SunOS News + SunOS News フォント + SunOS News қарібі + SunOS News 글꼴 + SunOS News Å¡riftas + SunOS News fonts + Font News SunOS + SunOS News-skrifttype + SunOS News-lettertype + SunOS NEWS-skrifttype + Czcionka SunOS News + tipo de letra SunOS News + Fonte SunOS News + Font SunOS News + шрифт SunOS News + Písmo SunOS News + Datoteka pisave SunOS News + Gërma SunOS News + SunOS News фонт + SunOS News-typsnitt + шрифт SunOS News + Phông chữ SunOS News + SunOS News 字体 + SunOS News å­—åž‹ + + + + + + + + + TeX font + خط TeX + TeX yazı növü + Å ryft TeX + Шрифт — TeX + tipus de lletra TeX + Písmo TeX + Ffont TeX + TeX-skrifttype + TeX-Schrift + γÏαμματοσειÏά TeX + TeX font + TeX-tiparo + tipografía de TeX + TeX letra-tipoa + TeX-kirjasin + TeX stavasnið + police TeX + cló TeX + tipo de letra de TeX + גופן TeX + TeX font + TeX-betűkészlet + Fonta TeX + Tipo carattere TeX + TeX フォント + TeX қарібі + TeX 글꼴 + TeX Å¡riftas + TeX fonts + Font TeX + TeX-skrift + TeX-lettertype + TeX-skrifttype + Czcionka TeX + tipo de letra TeX + Fonte TeX + Font TeX + шрифт TeX + Písmo TeX + Datoteka pisave TeX + Gërma TeX + ТеХ фонт + TeX-typsnitt + TeX fontu + шрифт TeX + Phông chữ TeX + TeX 字体 + TeX å­—åž‹ + + + + + + + + + TeX font metrics + مقاييس خط TeX + TeX yazı növü metriklÉ™ri + Metryka Å¡ryftu TeX + Шрифтова метрика — TeX + mètrica de tipus de lletra TeX + Metrika písma TeX + Metrigau Ffont TeX + TeX-skrifttypeinformation + TeX-Schriftmetriken + μετÏικά γÏαμματοσειÏάς TeX + TeX font metrics + metrikoj de TeX-tiparo + métricas de tipografía de TeX + TeX letra-tipoen neurriak + TeX-kirjasinmitat + métriques de police TeX + meadarachtaí cló TeX + Métricas de tipo de letra de TeX + גופן מטריקס של TeX + TeX mjere fonta + TeX-betűmetrika + Fonta metrik TeX + Metriche tipo carattere TeX + TeX フォントメトリック + TeX қаріп метрикалары + Tex 글꼴 메트릭 + TeX Å¡riftų metrika + TeX fonta metrikas + Metrik font TeX + TeX skrifttypemetrikk + TeX-lettertype-metrieken + TeX skrifttypemetrikk + Metryki czcionki TeX + métricas de tipo de letra TeX + Métrica de fonte TeX + Dimensiuni font TeX + метрика шрифта TeX + Metrika písma TeX + Matrika pisave Tex + Gërma TeX metrics + ТеХ метрика фонта + TeX-typsnittsmetrik + метрики шрифту TeX + Cách Ä‘o phông chữ TeX + TeX 字体å‚æ•° + TeX å­—åž‹æ述檔 + + + + + + + + TrueType font + خط TrueType + Å ryft TrueType + Шрифт — TrueType + tipus de lletra TrueType + Písmo TrueType + TrueType-skrifttype + TrueType-Schrift + γÏαμματοσειÏά TrueType + TrueType font + TrueType-tiparo + tipografía TrueType + TrueType letra-tipoa + TrueType-kirjasin + TrueType stavasnið + police Truetype + cló TrueType + tipo de letra TrueType + גופן מסוג TrueType + TrueType font + TrueType-betűkészlet + Fonta TrueType + Tipo carattere TrueType + TrueType フォント + TrueType қарібі + 트루타입 글꼴 + TrueType Å¡riftas + TrueType fonts + Font TrueType + TrueType-skrift + TrueType-lettertype + TrueType-skrifttype + Czcionka TrueType + tipo de letra TrueType + Fonte TrueType + Font TrueType + шрифт TrueType + Písmo TrueType + Datoteka pisave TrueType + Lloj gërme TrueType + Трутајп фонт + Truetype-typsnitt + TrueType fontu + шрифт TrueType + Phông chữ TrueType + TrueType 字体 + TrueType å­—åž‹ + + + + + + + + + + + TrueType XML font + خط TrueType XML + Å ryft TrueType XML + Шрифт — TrueType XML + tipus de lletra TrueType XML + Písmo TrueType XML + TrueType XML-skrifttype + TrueType-XML-Schrift + γÏαμματοσειÏά XML TrueType + TrueType XML font + tipografía TrueType XML + TrueType XML letra-tipoa + TrueType-XML-kirjasin + TrueType XML stavasnið + police Truetype XML + cló XML TrueType + tipo de letra TrueType XML + גופן XML מסוג TrueType + TrueType XML font + TrueType XML betűkészlet + Fonta TrueType XML + Tipo carattere TrueType XML + TrueType XML フォント + TrueType XML қарібі + 트루타입 XML 글꼴 + TrueType XML Å¡riftas + TrueType XML fonts + TrueType XML-skrift + TrueType XML-lettertype + TrueType XML-skrifttype + Czcionka TrueType XML + Fonte TrueType XML + Font XML TrueType + шрифт TrueType XML + Písmo TrueType XML + Datoteka pisave TrueType XML + Lloj gërme TrueType XML + Truetype XML-typsnitt + TrueType XML fontu + шрифт TrueType XML + Phông chữ XML TrueType + TrueType XML 字体 + TrueType XML å­—åž‹ + + + + + + + + + V font + خط V + V yazı növü + Å ryft V + Шрифт — V + tipus de lletra V + Písmo V + Ffont V + V-skrifttype + V-Schrift + γÏαμματοσειÏά V + V font + V-tiparo + tipografía V + V letra-tipoa + V-kirjasin + V stavasnið + police V + cló V + tipo de letra V + גופן של V + V font + V-betűkészlet + Fonta V + Tipo carattere V + V フォント + V font қарібі + V 글꼴 + V Å¡riftas + V fonts + Font V + V-skrift + V-lettertype + V-skrifttype + Czcionka V + tipo de letra V + Fonte V + Font V + шрифт V font + Písmo V + Datoteka pisave V + Gërmë V + V фонт + V-typsnitt + V fontu + V-шрифт + Phông chữ V + V 字体 + V å­—åž‹ + + + + + + + Adobe FrameMaker document + مستند أدوبي الصانع للإطارات + Dakument Adobe FrameMaker + Документ — Adobe FrameMaker + document FrameMaker d'Adobe + Dokument Adobe FrameMaker + Adobe FrameMaker-dokument + Adobe-FrameMaker-Dokument + αÏχειÌο Adobe FrameMaker + Adobe FrameMaker document + Dokumento de Adobe FrameMaker + documento de Adobe FrameMaker + Adobe FrameMaker-en dokumentua + Adobe FrameMaker -asiakirja + Adobe FrameMaker skjal + document Adobe FrameMaker + cáipéis Adobe FrameMaker + documento de Adobe FrameMaker + מסמך Adobe FrameMaker + Adobe FrameMaker dokument + Adobe FrameMaker-dokumentum + Dokumen Adobe FrameMaker + Documento Adobe FrameMaker + Adobe FrameMaker ドキュメント + Adobe FrameMaker-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + Adobe FrameMaker құжаты + ì–´ë„비 프레임메ì´ì»¤ 문서 + Adobe FrameMaker dokumentas + Adobe FrameMaker dokuments + Adobe FrameMaker-dokument + Adobe FrameMaker-document + Adobe FrameMaker-dokument + Dokument Adobe FrameMaker + Documento do Adobe FrameMaker + Document Adobe FrameMaker + документ Adobe FrameMaker + Dokument Adobe FrameMaker + Dokument Adobe FrameMaker + Dokument Adobe FrameMaker + Adobe FrameMaker-dokument + документ Adobe FrameMaker + Tài liệu Adobe FrameMaker + Adobe FrameMaker 文档 + Adobe FrameMaker 文件 + + + + + + + + + + + + + Game Boy ROM + Game Boy ROM + Game Boy ROM + ROM — Game Boy + ROM de Game Boy + ROM pro Game Boy + Game Boy-rom + Game-Boy-ROM + εικόνα μνήμης ROM GameBoy + Game Boy ROM + NLM de Game Boy + ROM de Game Boy + Game Boy-eko ROMa + Game Boy -ROM + Game Boy ROM + ROM Game Boy + ROM Game Boy + ROM de Game Boy + ROM של Game Boy + Game Boy ROM + Game Boy ROM + Memori baca-saja Game Boy + ROM Game Boy + ゲームボーイ ROM + Game Boy-ის ROM + Game Boy ROM + ê²Œìž„ë³´ì´ ë¡¬ + Game Boy ROM + Game Boy ROM + ROM Game Boy + Game Boy-ROM + Game Boy-ROM + Game Boy-ROM + Plik ROM konsoli Game Boy + ROM Game Boy + ROM do Game Boy + ROM Game Boy + Game Boy ROM + ROM pre Game Boy + Bralni pomnilnik Game Boy + ROM Game Boy + Гејмбој РОМ + Game Boy-rom + ППП Game Boy + ROM Game Boy + Game Boy ROM + Game Boy ROM + + + + + Game Boy Advance ROM + Game Boy Advance ROM + Game Boy Advance ROM + ROM — Game Boy Advance + ROM de Game Boy Advance + ROM pro Game Boy Advance + Game Boy Advance-rom + Game-Boy-Advance-ROM + εικόνα μνήμης Game Boy Advance + Game Boy Advance ROM + ROM de Game Boy Advance + Game Boy Advance-ko ROMa + Game Boy Advance -ROM + Game Boy Advance ROM + ROM Game Boy Advance + ROM Game Boy Advance + ROM de Game Boy Advance + ROM של Game Boy Advance + Game Boy Advance ROM + Game Boy Advance ROM + Memori baca-saja Game Boy Advance + ROM Game Boy Advance + ゲームボーイアドãƒãƒ³ã‚¹ ROM + Game Boy Advance-ის ROM + Game Boy Advance ROM + ê²Œìž„ë³´ì´ ì–´ë“œë°´ìŠ¤ 롬 + Game Boy Advance ROM + Game Boy Advance ROM + Game Boy Advance-ROM + Game Boy Advance-ROM + Game Boy Advance-ROM + Plik ROM konsoli Game Boy Advance + ROM do Game Boy Advance + ROM Game Boy Advance + Game Boy Advance ROM + ROM pre Game Boy Advance + Bralni pomnilnik Game Boy Advance + ROM Game Boy Advance + Game Boy Advance-rom + розширений ППП Game Boy + ROM Game Boy Advance + Game Boy Advance ROM + Game Boy Advance ROM + + + + + GDBM database + قاعدة بيانات GDBM + Baza źviestak GDBM + База от данни — GDBM + base de dades GDBM + Databáze GDBM + GDBM-database + GDBM-Datenbank + βάση δεδομένων GDBM + GDBM database + GDBM-datumbazo + base de datos GDBM + GDBM datu-basea + GDBM-tietokanta + GDBM dátustovnur + base de données GDBM + bunachar sonraí GDBM + base de datos GDBM + בסיס × ×ª×•× ×™× GDBM + GDBM baza podataka + GDBM adatbázis + Basis data GDBM + Database GDBM + GDBM データベース + GDBM მáƒáƒœáƒáƒªáƒ”მთრბáƒáƒ–რ+ GDBM дерекқоры + GDBM ë°ì´í„°ë² ì´ìŠ¤ + GDBM duomenų bazÄ— + GDBM datubÄze + GDBM-database + GDBM-gegevensbank + GDBM-database + Baza danych GDBM + Banco de dados GDBM + Bază de date GDBM + база данных GDBM + Databáza GDBM + Podatkovna zbirka GDBM + Bazë me të dhëna GDBM + GDBM-databas + GDBM veritabanı + база даних GDBM + CÆ¡ sở dữ liệu GDBM + GDBM æ•°æ®åº“ + GDBM 資料庫 + GDBM + GNU Database Manager + + + + + + + + + Genesis ROM + Genesis ROM + Genesis ROM + ROM — Genesis + ROM de Genesis + ROM pro Genesis + Genesis-rom + Genesis-ROM + εικόνα μνήμης ROM Genesis + Genesis ROM + Genesis-NLM + ROM de Genesis (Mega Drive) + Genesis-eko ROMa + Genesis-ROM + Genesis ROM + ROM Mega Drive/Genesis + ROM Genesis + ROM xenérica + ROM של Genesis + Genesis ROM + Genesis ROM + Memori baca-saja Genesis + ROM Megadrive + メガドライブ ROM + Genesis ROM + 제네시스 롬 + Genesis ROM + Genesis ROM + ROM Genesis + Genesis-ROM + Mega Drive + Genesis-ROM + Plik ROM konsoli Mega Drive + ROM Genesis + ROM do Gênesis (Mega Drive) + ROM Genesis + Genesis ROM + ROM pre Megadrive + Bralni pomnilnik Genesis + ROM Genesis + Genesis РОМ + Genesis-rom + ППП Genesis + ROM Genesis + Genesis ROM + Genesis ROM + + + + + + + + + + translated messages (machine-readable) + رسائل مترجمة (مقروءة آليا) + pierakÅ‚adzienyja paviedamleÅ„ni (dla ÄytaÅ„nia kamputaram) + Преведени ÑÑŠÐ¾Ð±Ñ‰ÐµÐ½Ð¸Ñ â€” машинен формат + missatges traduïts (llegible per màquina) + PÅ™eložené zprávy (strojovÄ› Äitelné) + oversatte meddelelser (maskinlæsbare) + Ãœbersetzte Meldungen (maschinenlesbar) + μεταφÏασμένα μηνÏματα (για μηχανική ανάγνωση) + translated messages (machine-readable) + tradukitaj mesaÄoj (maÅinlegebla) + mensajes traducidos (legibles por máquinas) + itzulitako mezuak (ordenagailuek irakurtzeko) + käännetyt viestit (koneluettava) + týdd boð (maskin-lesifør) + messages traduits (lisibles par machine) + teachtaireachtaí aistrithe (inléite ag meaisín) + mensaxes traducidos (lexíbeis por máquinas) + מסר ×ž×ª×•×¨×’× (מובן ×¢"×™ מכונה) + prevedene poruke (strojno Äitljive) + lefordított üzenetek (gépi kód) + pesan diterjemahkan (dapat dibaca mesin) + Messaggi tradotti (leggibili da macchina) + 翻訳メッセージ (マシン用) + ნáƒáƒ—áƒáƒ áƒ’მნი შეტყáƒáƒ‘ინებები (მáƒáƒœáƒ¥áƒáƒœáƒ˜áƒ¡áƒ—ვის გáƒáƒœáƒ™áƒ£áƒ—ვნილი) + аударылған хабарламалар (машиналық түрде) + 번역 메시지 (컴퓨터 사용 형ì‹) + iÅ¡versti užraÅ¡ai (kompiuteriniu formatu) + pÄrtulkotie ziņojumi (maÅ¡Ä«nlasÄms) + Mesej diterjemah (bolehdibaca-mesin) + oversatte meldinger (maskinlesbar) + vertaalde berichten (machine-leesbaar) + oversette meldingar (maskinlesbare) + PrzetÅ‚umaczone komunikaty (czytelne dla komputera) + mensagens traduzidas (leitura pelo computador) + Mensagens traduzidas (legível pelo computador) + mesaje traduse (citite de calculator) + переводы Ñообщений (откомпилированые) + Preložené správy (strojovo Äitateľné) + prevedena sporoÄila (strojni zapis) + Mesazhe të përkthyer (të lexueshëm nga makina) + преведене поруке (машинама читљиво) + översatta meddelanden (maskinläsbara) + перекладені Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ (у машинній формі) + thông Ä‘iệp đã dịch (máy Ä‘á»c được) + 消æ¯ç¿»è¯‘(机读) + ç¿»è­¯è¨Šæ¯ (程å¼è®€å–æ ¼å¼) + + + + + + + + + GTK+ Builder + + + + + + + + + Glade project + مشروع Glade + Glade layihÉ™si + Prajekt Glade + Проект — Glade + projecte de Glade + Projekt Glade + Prosiect Glade + Gladeprojekt + Glade-Projekt + έÏγο Glade + Glade project + Glade-projekto + proyecto de Glade + Glade proiektua + Glade-projekti + Glade verkætlan + projet Glade + tionscadal Glade + proxecto de Glade + ×ž×™×–× Glade + Glade projekt + Glade-projekt + Proyek Glade + Progetto Glade + Glade プロジェクト + Glade жобаÑÑ‹ + Glade 프로ì íŠ¸ + Glade projektas + Glade projekts + Projek Glade + Glade prosjekt + Glade-project + Glade prosjekt + Projekt Glade + projecto Glade + Projeto do Glade + Proiect Glade + проект Glade + Projekt Glade + Datoteka projekta Glade + Projekt Glade + Глејд пројекат + Glade-projekt + проект Glade + Dá»± án Glade + Glade 工程 + Glade 專案 + + + + + + + + + GMC link + وصلة GMC + GMC körpüsü + SpasyÅ‚ka GMC + Връзка — GMC + enllaç GMC + Odkaz GMC + Cyswllt GMC + GMC-henvisning + GMC-Verweis + σÏνδεσμος GMC + GMC link + GMC-ligilo + enlace GMC + GMC esteka + GMC-linkki + GMC leinkja + lien GMC + nasc GMC + ligazón GMC + קישור GMC + GMC veza + GMC-link + Taut GMC + Collegamento GMC + GMC リンク + GMC ბმული + GMC ÑілтемеÑÑ– + GMC ì—°ê²° + GMC nuoroda + GMC saite + Pautan GMC + GMC-lenke + GMC-verwijzing + GMC-lenkje + OdnoÅ›nik GMC + 'link' GMC + Link GMC + Legătură GMC + ÑÑылка GMC + Odkaz GMC + Datoteka povezave GMC + Lidhje GMC + GMC веза + GMC-länk + GMC baÄŸlantısı + поÑÐ¸Ð»Ð°Ð½Ð½Ñ GMC + Liên kết GMC + GMC 链接 + GMC éˆçµ + + + + + + + GnuCash financial data + معلومات GnuCash المالية + ФинанÑови данни — GnuCash + dades financeres del GnuCash + FinanÄní data GnuCash + Finansielle data til GnuCash + GnuCash-Finanzdaten + οικονομικά στοιχεία GnuCash + GnuCash financial data + datos financieros GnuCash + GnuCash finantzako datuak + GnuCash-taloustiedot + GnuCash fíggjarligar dátur + données financières GnuCash + sonraí airgeadúla GnuCash + datos financeiros de GNUCash + מידע כלכלי של GnuCash + GnuCash financijski podaci + GnuCash pénzügyi adatok + Data keuangan GnuCash + Dati finanziari GnuCash + GnuCash 会計データ + GnuCash қаржы ақпараты + GnuCash 재정 ìžë£Œ + GnuCash finansiniai duomenys + GnuCash finanÅ¡u dati + GnuCash financiële gegevens + Dane finansowe GnuCash + Dados financeiros do GnuCash + Date financiare GnuCash + финанÑовые данные GnuCash + FinanÄné údaje GnuCash + Datoteka finanÄnih podatkov GnuCash + GnuCash-finansdata + фінанÑові дані GnuCash + Dữ liệu tài chính GnuCash + GnuCash è´¢åŠ¡æ•°æ® + GnuCash 財務資料 + + + + + + + Gnumeric spreadsheet + جدول Gnumeric + Raźlikovy arkuÅ¡ Gnumeric + Таблица — Gnumeric + full de càlcul de Gnumeric + SeÅ¡it Gnumeric + Gnumeric-regneark + Gnumeric-Tabelle + Λογιστικό φÏλλο Gnumeric + Gnumeric spreadsheet + Gnumeric-kalkultabelo + hoja de cálculo de Gnumeric + Gnumeric kalkulu-orria + Gnumeric-taulukko + Gnumeric rokniark + feuille de calcul Gnumeric + scarbhileog Gnumeric + folla de cálculo de Gnumeric + גליון עבודה Gnumeric + Gnumeric proraÄunska tablica + Gnumeric-munkafüzet + Lembar sebar Gnumeric + Foglio di calcolo Gnumeric + Gnumeric スプレッドシート + Gnumeric Ñлектрондық кеÑтеÑÑ– + Gnumeric 스프레드시트 + Gnumeric skaiÄialentÄ— + Gnumeric izklÄjlapa + Hamparan Gnumeric + Gnumeric-regneark + Gnumeric-rekenblad + Gnumeric-rekneark + Arkusz Gnumeric + folha de cálculo Gnumeric + Planilha do Gnumeric + Foaie de calcul Gnumeric + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° Gnumeric + ZoÅ¡it Gnumeric + Razpredelnica Gnumeric + Fletë llogaritjesh Gnumeric + Гнумерик табеларни рачун + Gnumeric-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Gnumeric + Bảng tính Gnumeric. + Gnumeric 工作簿 + Gnumeric 試算表 + + + + + + + + + Gnuplot document + مستند Gnuplot + Dakument Gnuplot + Документ — Gnuplot + document gnuplot + Dokument Gnuplot + Gnuplotdokument + Gnuplot-Dokument + έγγÏαφο Gnuplot + Gnuplot document + Gnuplot-dokumento + documento de Gnuplot + Gnuplot dokumentua + Gnuplot-asiakirja + Gnuplot skjal + document Gnuplot + cáipéis Gnuplot + documento de Gnuplot + מסמך Gnuplot + Gnuplot dokument + Gnuplot dokumentum + Dokumen Gnuplot + Documento Gnuplot + Gnuplot ドキュメント + Gnuplot құжаты + Gnuplot 문서 + Gnuplot dokumentas + Gnuplot dokuments + Gnuplot-dokument + Gnuplot-document + Gnuplot-dokument + Dokument Gnuplot + Documento do Gnuplot + Document Gnuplot + документ Gnuplot + Dokument Gnuplot + Dokument Gnuplot + Dokument Gnuplot + Gnuplot-dokument + документ Gnuplot + Tài liệu Gnuplot + Gnuplot 文档 + Gnuplot 文件 + + + + + + + + Graphite scientific graph + مبيان الجراÙيت العلمي + Navukovy hrafik Graphite + Графика — Graphite + gràfic científic Graphite + VÄ›decký graf Graphite + Graphite videnskabelig graf + Wissenschaftlicher Graphite-Graph + επιστημονικό γÏάφημα Graphite + Graphite scientific graph + scienca grafikaĵo de Graphite + gráfica científica de Graphite + Graphite - grafiko zientifikoak + Graphite- tieteellinen graafi + Grapite vísindarlig ritmynd + graphe Graphite scientific + graf eolaíoch Graphite + gráfica científica de Graphite + גרך מדעי של Graphite + Graphite znanstveni grafikon + Graphite tudományos grafikon + Grafik sains Graphite + Grafico scientifico Graphite + Graphite scientific グラフ + Graphite ғылыми кеÑкіні + Graphite 과학 그래프 + Graphite mokslinÄ— diagrama + Graphite zinÄtniskais grafiks + Graf saintifik Graphite + Vitenskapelig graf fra Graphite + Graphite wetenschappelijke grafiek + Graphite vitskaplege graf + Wykres naukowy Graphite + gráfico científico Graphite + Gráfico científico do Graphite + Grafic È™tiinÈ›ific Graphite + Ð½Ð°ÑƒÑ‡Ð½Ð°Ñ Ð´Ð¸Ð°Ð³Ñ€Ð°Ð¼Ð¼Ð° Graphite + Vedecký graf Graphite + Datoteka znanstvenega grafa Graphite + Grafik shkencor Graphite + Graphite научни графикони + Vetenskaplig Graphite-grafer + наукова графіка Graphite + Biểu đồ khoa há»c Graphite + Graphite 科学图形 + Graphite 科學圖表 + + + + + GTKtalog catalog + كتالوج GTKtalog + Kataloh GTKtalog + Каталог — Gtktalog + catàleg de GTKtalog + Katalog GTKtalog + GTKtalog-katalog + GTKtalog-Katalog + Κατάλογος GTKtalog + GTKtalog catalogue + katalogo de GTKtalog + catálogo de GTKtalog + Gtktalog katalogoa + GTKtalog-luettelo + GTKtalog skrá + catalogue Gtktalog + catalóg GTKtalog + catálogo de GTKtalog + קטלוג GTKtalog + GTKtalog katalog + GTKtalog-katalógus + Katalog GTKtalog + Catalogo GTKtalog + GTKtalog カタログ + GTKtalog-ის კáƒáƒ¢áƒáƒšáƒáƒ’ი + GTKtalog каталогы + GTKtalog 카탈로그 + GTKtalog katalogas + GTKtalog katalogs + Katalog GTKtalog + GTKtalog-katalog + GTKtalog-catalogus + GTKtalog-katalog + Katalog programu GTKtalog + catálogo GTKtalog + Catálogo GTKtalog + Catalog GTKalog + каталог GTKtalog + Katalóg GTKtalog + Datoteka kataloga GTKtalog + Katallog GTKtalog + Гткталог каталог + GTKtalog-katalog + каталог GTKtalog + Phân loại GTKtalog + GTKtalog 目录 + GTKtalog 光碟目錄 + + + + + + + TeX DVI document (gzip-compressed) + مستند TeX DVI (مضغوط-gzip) + Dakument TeX DVI (gzip-skampresavany) + Документ — TeX DVI, компреÑиран Ñ gzip + document TeX DVI (comprimit amb gzip) + Dokument TeX DVI (komprimovaný pomocí gzip) + TeX DVI-dokument (gzip-komprimeret) + TeX-DVI-Dokument (gzip-komprimiert) + αÏχειÌο TeX DVI (συμπιεσμεÌνο με gzip) + TeX DVI document (gzip-compressed) + documento DVI de TeX (comprimido con gzip) + TeX DVI dokumentua (gzip-ekin konprimitua) + TeX DVI -asiakirja (gzip-pakattu) + TeX DVI skjal (gzip-stappað) + document DVI TeX (compressé gzip) + cáipéis DVI TeX (comhbhrúite le gzip) + documento DVI de TeX (comprimido con gzip) + מסמך מסוג TeX DVI (מכווץ ×¢"×™ gzip) + TeX DVI dokument (komprimiran gzip-om) + TeX DVI dokumentum (gzip-pel tömörítve) + Dokumen TeX DVI (terkompresi gzip) + Documento Tex DVI (compresso con gzip) + Tex DVI ドキュメント (gzip 圧縮) + TeX DVI құжаты (gzip-пен Ñығылған) + TeX DVI 문서 (GZIP 압축) + TeX DVI dokumentas (suglaudintas su gzip) + TeX DVI dokuments (saspiests ar gzip) + TeX DVI-dokument (gzip-komprimert) + TeX DVI-document (ingepakt met gzip) + TeX DVI-dokument (pakka med gzip) + Dokument TeX DVI (kompresja gzip) + Documento DVI TeX (compactado com gzip) + Document TeX DVI (comprimat gzip) + документ TeX DVI (Ñжатый gzip) + Dokument TeX DVI (komprimovaný pomocou gzip) + Dokument TeX DVI (stisnjen z gzip) + Dokument TeX DVI (i kompresuar me gzip) + TeX DVI-dokument (gzip-komprimerat) + TeX DVI belgesi (gzip ile sıkıştırılmış) + документ TeX DVI (ÑтиÑнений gzip) + Tài liệu DVI TeX (đã nén gzip) + TeX DVI 文档(gzip 压缩) + TeX DVI 文件 (gzip æ ¼å¼å£“縮) + + + + + + Gzip archive + أرشي٠Gzip + ArchiÅ­ gzip + Ðрхив — gzip + arxiu gzip + Archiv gzip + Gzip-arkiv + Gzip-Archiv + συμπιεσμεÌνο αÏχειÌο Gzip + Gzip archive + Gzip-arkivo + archivador Gzip + Gzip artxiboa + Gzip-arkisto + Gzip skjalasavn + archive gzip + cartlann Gzip + arquivo Gzip + ×רכיון Gzip + Gzip arhiva + Gzip archívum + Arsip Gzip + Archivio gzip + Gzip アーカイブ + Gzip архиві + GZIP 압축 íŒŒì¼ + Gzip archyvas + Gzip arhÄ«vs + Gzip-arkiv + Gzip-archief + Gzip-arkiv + Archiwum gzip + Pacote Gzip + Arhivă Gzip + архив GZIP + Archív gzip + Datoteka arhiva Gzip + Arkiv gzip + Gzip-arkiv + архів gzip + Kho nén gzip + Gzip 归档文件 + Gzip å°å­˜æª” + + + + + + + + + PDF document (gzip-compressed) + مستند PDF (مضغوط-gzip) + Dakument PDF (gzip-skampresavany) + Документ — PDF, компреÑиран Ñ gzip + document PDF (comprimit amb gzip) + Dokument PDF (komprimovaný pomocí gzip) + PDF-dokument (gzip-komprimeret) + PDF-Dokument (gzip-komprimiert) + εÌγγÏαφο PDF (συμπιεσμεÌνο με gzip) + PDF document (gzip-compressed) + documento PDF (comprimido con gzip) + PDF dokumentua (gzip-ekin konprimitua) + PDF-asiakirja (gzip-pakattu) + PDF skjal (gzip-stappað) + document PDF (compressé gzip) + cáipéis PDF (comhbhrúite le gzip) + documento PDF (comprimido en gzip) + מסמך PDF (מכווץ ×¢"×™ gzip) + PDF dokumentum (gzip-tömörítésű) + Dokumen PDF (terkompresi gzip) + Documento PDF (compresso con gzip) + PDF ドキュメント (gzip 圧縮) + PDF құжаты (gzip-пен Ñығылған) + PDF 문서 (GZIP 압축) + PDF dokumentas (suglaudintas su gzip) + PDF dokuments (saspiests ar gzip) + PDF-dokument (gzip-komprimert) + PDF-document (ingepakt met gzip) + PDF-dokument (pakka med gzip) + Dokument PDF (kompresja gzip) + Documento PDF (compactado com gzip) + Document PDF (comprimat gzip) + документ PDF (Ñжатый gzip) + Dokument PDF (komprimovaný pomocou gzip) + Dokument PDF (stisnjen z gzip) + Dokument PDF (i kompresuar me gzip) + PDF-dokument (gzip-komprimerat) + PDF belgesi (gzip ile sıkıştırılmış) + документ PDF (ÑтиÑнений gzip) + Tài liệu PDF (đã nén gzip) + PDF 文档(gzip 压缩) + PDF 文件 (gzip æ ¼å¼å£“縮) + + + + + + PostScript document (gzip-compressed) + مستند PostScript (مضغوط-gzip) + Dakument PostScript (gzip-skampresavany) + Документ — PostScript, компреÑиран Ñ gzip + document PostScript (comprimit amb gzip) + Dokument PostScript (komprimovaný pomocí gzip) + PostScript-dokument (gzip-komprimeret) + PostScript-Dokument (gzip-komprimiert) + έγγÏαφο PostScript (συμπιεσμένο με gzip) + PostScript document (gzip-compressed) + PostScript-dokumento (kunpremita per gzip) + documento PostScript (comprimido con gzip) + PostScript dokumentua (gzip-konprimitua) + PostScript-asiakirja (gzip-pakattu) + PostScript skjal (gzip-stappað) + document PostScript (compressé gzip) + cáipéis PostScript (comhbhrúite le gzip) + documento PostScript (comprimido con gzip) + מסמך PostScript (מכוות ×¢"×™ gzip) + PostScript-dokumentum (gzip-pel tömörítve) + Dokumen PostScript (terkompresi gzip) + Documento PostScript (compresso con gzip) + PostScript ドキュメント (gzip 圧縮) + PostScript құжаты (gzip-пен Ñығылған) + í¬ìŠ¤íŠ¸ìŠ¤í¬ë¦½íŠ¸ 문서 (GZIP 압축) + PostScript dokumentas (suglaudintas su gzip) + PostScript dokuments (saspiests ar gzip) + Dokumen PostScript (dimampatkan-gzip) + PostScript-dokument (gzip-komprimert) + PostScript-document (ingepakt met gzip) + PostScript-dokument (pakka med gzip) + Dokument Postscript (kompresja gzip) + documento PostScript (comprimido com gzip) + Documento PostScript (compactado com gzip) + Document PostScript (comprimat gzip) + документ PostScript (Ñжатый gzip) + Dokument PostScript (komprimovaný pomocou gzip) + Dokument PostScript (stisnjen z gzip) + Dokument PostScript (i kompresuar me gzip) + ПоÑÑ‚Ñкрипт документ (компреÑована gzip-ом) + Postscript-dokument (gzip-komprimerat) + документ PostScript (ÑтиÑнене gzip) + Tài liệu PostScript (đã nén gzip) + PostScript 文档(gzip 压缩) + PostScript 文件 (gzip æ ¼å¼å£“縮) + + + + + + HDF document + مستند HDF + HDF sÉ™nÉ™di + Dakument HDF + Документ — HDF + document HDF + Dokument HDF + Dogfen HDF + HDF-dokument + HDF-Dokument + έγγÏαφο HDF + HDF document + HDF-dokumento + documento HDF + HDF dokumentua + HDF-asiakirja + HDF skjal + document HDF + cáipéis HDF + documento HDF + מסמך HDF + HDF dokument + HDF-dokumentum + Dokumen HDF + Documento HDF + HDF ドキュメント + HDF құжаты + HDF 문서 + HDF dokumentas + HDF dokuments + Dokumen HDF + HDF-dokument + HDF-document + HDF-dokument + Dokument HDF + documento HDF + Documento HDF + Document HDF + документ HDF + Dokument HDF + Dokument HDF + Dokument HDF + HDF документ + HDF-dokument + документ HDF + Tài liệu HDF + HDF 文档 + HDF 文件 + HDF + Hierarchical Data Format + + + + + + + + + + + + + IFF file + IFF + Interchange File Format + + + + + + iPod firmware + برنامج عتاد الـiPod + Firmware iPod + Фърмуер за iPod + microprogramari d'iPod + Firmware iPod + iPod-styreprogram + iPod-Firmware + εικόνα μνήμης firmware iPod + iPod firmware + iPod-mikroprogramaro + firmware de iPod + iPod firmwarea + iPod-laiteohjelmisto + iPod fastbúnaður + firmware iPod + dochtearraí iPod + firmware de iPod + קושחת ipod + iPod-firmware + peranti tegar iPod + Firmware iPod + iPod ファームウェア + iPod микробағдарламаÑÑ‹ + iPod 펌웨어 + iPod programinÄ— įranga + iPod aparÄtprogrammatÅ«ra + Firmware iPod + iPod-firmware + iPod-firmware + iPod-firmvare + Oprogramowanie wewnÄ™trzne iPod + 'firmware' iPod + Firmware do iPod + Firmware iPod + микропрограмма iPod + Firmware iPod + Programska strojna oprema iPod + Firmware iPod + iPod програм + fast iPod-program + мікропрограма iPod + phần vững iPod + iPod 固件 + iPod 韌體 + + + + + + Java archive + أرشي٠Java + ArchiÅ­ Java + Ðрхив — Java + arxiu Java + Archiv Java + Javaarkiv + Java-Archiv + αÏχείο Java + Java archive + Java-arkivo + archivador Java + Java artxiboa + Java-arkisto + Java skjalasavn + archive Java + cartlann Java + arquivo Java + ×רכיון Java + Java arhiva + Java-archívum + Arsip Java + Archivio Java + Java アーカイブ + Java архиві + ìžë°” ë¬¶ìŒ íŒŒì¼ + Java archyvas + Java arhÄ«vs + Arkib Java + Java-arkiv + Java-archief + Java-arkiv + Archiwum Java + arquivo Java + Pacote Java + Arhivă Java + архив Java + Archív Java + Datoteka arhiva Java + Arkiv Java + Јава архива + Java-arkiv + Java arÅŸivi + архів Java + Kho nén Java + Java 归档文件 + Java å°å­˜æª” + + + + + + + + Java class + صن٠java + Klasa Java + ÐšÐ»Ð°Ñ Ð½Ð° Java + classe Java + Třída Java + Javaklasse + Java-Klasse + κλάση Java + Java class + Java-klaso + clase Java + Java-ko klasea + Java-luokka + Java flokkur + classe Java + aicme Java + clase de Java + מחלקת Java + Java klasa + Java-osztály + Kelas Java + Classe Java + Java クラス + Java клаÑÑ‹ + ìžë°” í´ëž˜ìŠ¤ + Java klasÄ— + Java klase + Kelas Java + Java-klasse + Java-klasse + Java-klasse + Klasa Java + classe Java + Classe Java + Clasă Java + клаÑÑ Java + Trieda Java + Datoteka razreda Java + Klasë Java + Јава клаÑа + Java-klass + Java sınıfı + ÐºÐ»Ð°Ñ Java + Hạng Java + Java ç±» + Java class + + + + + + + + + + + + JNLP file + مل٠JNLP + FajÅ‚ JNLP + Файл — JNLP + fitxer JNLP + Soubor JNLP + JNPL-fil + JNLP-Datei + αÏχείο JNLP + JNLP file + JNLP-dosiero + archivo JNPL + JNLP fitxategia + JNLP-tiedosto + JNLP fíla + fichier JNLP + comhad JNLP + ficheiro JNLP + קובץ JNLP + JNLP datoteka + JNLP fájl + Berkas JNLP + File JNPL + JNLP ファイル + JNLP файлы + JNLP íŒŒì¼ + JNLP failas + JNLP datne + JNLP-fil + JNLP-bestand + JNLP-fil + Plik JNLP + Arquivo JNLP + FiÈ™ier JNLP + файл JNLP + Súbor JNLP + Datoteka JNLP + File JNLP + JNLP-fil + JNLP dosyası + файл JNLP + Tập tin JNLP + JNLP 文件 + JNLP 檔案 + JNLP + Java Network Launching Protocol + + + + + + + + + Java keystore + مخزن Ù…Ùاتيح جاÙا + Ключодържател — Java + magatzem de claus Java + Java keystore + Javanøglelager + Java-Schlüsselbund + χώÏος αποθήκευσης κλειδιών Java + Java keystore + almacén de claves de Java + Java-ren gako-biltegia + Java-avainvarasto + Java lyklagoymsla + stockage de clés Java + eochairstór Java + almacén de chaves de Java + הקשת מקלדת של Java + Java kulcstároló + Penyimpanan kunci Java + Keystore Java + Java キーストア + Java Ñақталымы + ìžë°” 키 저장소 + Java raktų saugykla + Java keystore + Java keystore + Baza kluczy Java + Keystore de Java + Stocare chei Java + хранилище ключей Java + Úložisko kľúÄov Java + Datoteka tipkovne razporeditve Java + Java-nyckellager + Ñховище ключів Java + Java 密钥库 + Java 金鑰儲存 + + + + + + + + + Java JCE keystore + مخزن Ù…Ùاتيح Java JCE + Ключодържател — Java JCE + magatzem de claus JCE Java + Java JCE keystore + Java JCE-nøglelager + Java JCE-Schlüsselbund + Java JCE keystore + almacén de claves JCE de Java + Java JCE-ren gako-biltegia + Java JCE -avainvarasto + Java JCE lyklagoymsla + stockage de clés Java JCE + eochairstór Java JCE + almacén de chves JCE de Java + הקשה מסוג Java JCE + Java JCE kulcstároló + Penyimpanan kunci Java JCE + Keystore Java JCE + Java JCE キーストア + Java JCE Ñақталымы + ìžë°” JCE 키 저장소 + Java JCE raktų saugykla + Java JCE keystore + Java JCE keystore + Baza kluczy Java JCE + Keystore JCE do Java + Stocare chei Java JCE + хранилище ключей Java JCE + Úložisko kľúÄov Java JCE + Datoteka tipkovne razporeditve Java JCE + Java JCE-nyckellager + Ñховище ключів JCE Java + Java JCE 密钥库 + Java JCE 金鑰儲存 + JCE + Java Cryptography Extension + + + + + + + Pack200 Java archive + أرشي٠Pack200 Java + ArchiÅ­ Pack200 Java + Ðрхив — Java Pack200 + arxiu Java Pack200 + Archiv Java Pack200 + Pack200 Java-arkiv + Pack200-Java-Archiv + αÏχείο Java Pack200 + Pack200 Java archive + archivador Pack200 Java + Pack2000 Java artxiboa + Pack200-Java-arkisto + Pack200 Java skjalasavn + archive Java Pack200 + cartlann Java Pack200 + arquivo Pack200 Java + ×רכיון מסוג Pack200 Java + Pack200 Java-archívum + Arsip Pack200 Java + Archivio Pack200 Java + Pack200 Java アーカイブ + Pack200 Java архиві + Pack200 ìžë°” 압축 íŒŒì¼ + Pack200 Java archyvas + Pack200 Java arhÄ«vs + Pack200 Java-arkiv + Pack200 Java-archief + Pack200 Java-arkiv + Archiwum Java Pack200 + Pacote Java Pack200 + Arhivă Java Pack2000 + архив Java Pack200 + Archív Java Pack200 + Datoteka arhiva Pack200 Java + Arkiv Java Pack200 + Pack200 Java-arkiv + Pack200 Java arÅŸivi + архів Java Pack200 + Kho nén Java Pack200 + Pack200 Java 归档文件 + Pack200 Java å°å­˜æª” + + + + + + + + JavaScript program + برنامج جاÙاسكربت + Prahrama JavaScript + Програма на JavaScript + programa JavaScript + Program v JavaScriptu + JavaScript-program + JavaScript-Programm + Ï€ÏόγÏαμμα JavaScript + JavaScript program + JavaScript-programo + programa en JavaScript + JavaScript programa + JavaScript-ohjelma + JavaScript forrit + programme JavaScript + ríomhchlár JavaScript + programa JavaScript + תכנית JavaScript + JavaScript program + JavaScript-program + Program JavaScript + Programma JavaScript + JavaScript プログラム + JavaScript бағдарламаÑÑ‹ + ìžë°”스í¬ë¦½íŠ¸ 프로그램 + JavaScript programa + JavaScript programma + Program JavaScript + JavaScript-program + JavaScript-programma + JavaScript-program + Pogram JavaScript + Programa JavaScript + Program JavaScript + Ñценарий JavaScript + Program jazyka JavaScript + Programska datoteka JavaScript + Program JavaScript + JavaScript-program + JavaScript programı + програма мовою JavaScript + ChÆ°Æ¡ng trình JavaScript + Javascript ç¨‹åº + JavaScript ç¨‹å¼ + + + + + + + + JBuilder project + مشروع JBuilder + Prajekt JBuilder + Проект — JBuilder + projecte de JBuilder + Projekt JBuilder + JBuilder-projekt + JBuilder-Projekt + έÏγο JBuilder + JBuilder project + JBuilder-projekto + proyecto JBuilder + JBuilder proiektua + JBuilder-projekti + JBuilder verkætlan + projet JBuilder + tionscadal JBuilder + proxecto de JBuilder + ×ž×™×–× JBuilder + JBuilder projekt + JBuilder-projekt + Proyek JBuilder + Progetto JBuilder + JBuilder プロジェクト + JBuilder жобаÑÑ‹ + JBuilder 프로ì íŠ¸ + JBuilder projektas + JBuilder projekts + Projek JBuilder + JBuilder-prosjekt + JBuilder-project + JBuilder-prosjekt + Projekt JBuilder + projecto JBuilder + Projeto do JBuilder + Proiect JBuilder + проект JBuilder + Projekt JBuilder + Datoteka projekta JBuilder + Projekt JBuilder + JBuilder пројекат + JBuilder-projekt + JBuilder projesi + проект JBuilder + Dá»± án JBuilder + JBuilder 工程 + JBuilder 專案 + + + + + + Karbon14 drawing + تصميم Karbon14 + Rysunak Karbon14 + Чертеж — Karbon14 + dibuix de Karbon14 + Kresba Karbon14 + Karbon14-tegning + Karbon14-Zeichnung + σχέδιο Karbon14 + Karbon14 drawing + Karbon14-grafikaĵo + dibujo de Karbon14 + Karbon14 marrazkia + Karbon14-piirros + Karbon14 tekning + dessin Karbon14 + líníocht Karbon14 + debuxo de Karbon14 + ציור Karbon14 + Karbon14 crtež + Karbon14-rajz + Gambar Karbon14 + Disegno Karbon14 + Karbon14 ドロー + Karbon14 Ñуреті + Karbon14 그림 + Karbon14 pieÅ¡inys + Karbon14 zÄ«mÄ“jums + Lukisan Karbon14 + Karbon14-tegning + Karbon14-tekening + Karbon14-teikning + Rysunek Karbon14 + desenho Karbon14 + Desenho do Karbon14 + Desen Karbon14 + изображение Karbon14 + Kresba Karbon14 + Datoteka risbe Karbon14 + Vizatim Karbon14 + Karbon14 цртеж + Karbon14-teckning + Karbon14 çizimi + малюнок Karbon14 + Bản vẽ Karbon14 + Karbon14 绘图 + Karbon14 繪圖 + + + + + + + + + + + + + + + + + KChart chart + رسم بياني KChart + Hrafik KChart + Диаграма — KChart + diagrama de KChart + Graf Chart + KChart-diagram + KChart-Diagramm + γÏάφημα KChart + KChart chart + KChart-diagramo + gráfica de KChart + KChart diagrama + KChart-kaavio + KChart strikumynd + graphique KChart + cairt KChart + gráfica de KChart + ×ª×¨×©×™× KChart + KChart grafikon + KChart-grafikon + Bagan KChart + Grafico KChart + KChart ãƒãƒ£ãƒ¼ãƒˆ + KChart диаграммаÑÑ‹ + KChart 차트 + KChart diagrama + KChart diagramma + Carta KChart + KChart-graf + KChart-grafiek + KChart-diagram + Wykres KChart + gráfico KChart + Gráfico do KChart + Diagramă KChart + диаграмма KChart + Graf KChart + Datoteka grafikona KChart + Grafik KChart + KChart графикон + KChart-diagram + діаграма KChart + SÆ¡ đồ KChart + KChart 图表 + KChart 圖表 + + + + + + + + + + + + + + + + + Kexi settings for database server connection + إعدادات Kexi للإتصال بخادم قاعدة البيانات + Връзка към база от данни — Kexi + configuració del Kexi per a la connexió al servidor de bases de dades + Nastavení Kexi ke spojení s databázovým serverem + Kexiopsætning til forbindelsen for databaseserveren + Kexi-Einstellungen für Verbindung zum Datenbankserver + Ïυθμίσεις Kexi για σÏνδεση με εξυπηÏετητή βάσεων δεδομένων + Kexi settings for database server connection + configuración de Kexi para la conexión con el servidor de bases de datos + Kexi-ren ezarpenak datu-basearen zerbitzariarekin konektatzeko + Kexi-tietokantayhteysasetukset + Kexi stillingar fyri dátustovnsambætara sambinding + paramètres Kexi pour connexion au serveur de base de données + socruithe Kexi do cheangal le freastalaí bunachair sonraí + configuración de Kexi para conexión con servidor de base de datos + הגדרות של Kexi עבור חיבור שרת לבסיס × ×ª×•× ×™× + Kexi beállítások adatbáziskiszolgáló-kapcsolathoz + Tatanan Kexi bagi koneksi server basis data + Impostazioni Kexi per connessione a server di database + データベースサーãƒæŽ¥ç¶šç”¨ã® Kexi 設定 + Дерекқор Ñерверге Ð±Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ Kexi баптаулары + Kexi ë°ì´í„°ë² ì´ìŠ¤ 서버 ì—°ê²° 설정 + Kexi duomenų bazÄ—s ryÅ¡io su serveriu parametrai + Kexi iestatÄ«jumi datubÄzes servera savienojumam + Kexi instellingen voor database server connectie + Ustawienia Kexi dla poÅ‚Ä…czenia serwera bazy danych + Configurações do Kexi para conexão a servidor de banco de dados + Configurări Kexi pentru conexiunea la serverul de baze de date + параметры Kexi Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Ñерверу БД + Nastavenia Kexi pre pripojenie k databázovému serveru + StrežniÅ¡ka povezava do nastavitvene datoteke Kexi. + Kexi-inställningar för anslutning till databasserver + параметри Kexi Ð´Ð»Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· Ñервером бази даних + Kexi æ•°æ®åº“æœåŠ¡å™¨è¿žæŽ¥è®¾ç½® + Kexi 設定值 (資料庫伺æœå™¨é€£ç·šç”¨) + + + + shortcut to Kexi project on database server + اختصار لمشروع Kexi على خادم قاعدة بيانات + Връзка към проект — Kexi + drecera a projecte del Kexi en un servidor de base de dades + Zástupce projektu Kexi na databázovém serveru + genvej til Kexiprojekt pÃ¥ databaseserver + Schnellzugriff zum Kexi-Projekt auf dem Datenbankserver + συντόμευση σε έÏγο Kexi στον εξυπηÏετητή βάσης δεδομένων + shortcut to Kexi project on database server + acceso directo a proyecto Kexi en el servidor de bases de datos + lasterbidea datu-basearen zerbitzariko Kexi proiekturako + snarvegur til Kexi verkætlan á dátustovnsambætara + raccourci vers projet Kexi sur serveur de base de données + aicearra go tionscadal Kexi ar fhreastalaí bunachair sonraí + acceso directo a proxecto Kexi no servidor de bases de datos + קיצור דרך לפרוירט Kexi בשרת × ×ª×•× ×™× + preÄac za Kexi projekt na poslužitelju baze podataka + indítóikon adatbázis-kiszolgálón lévÅ‘ Kexi projektre + pintasan ke projek Kexi pada server basis data + Scorciatoia a progetto Kexi su server di database + データベースサーãƒã® Kexi プロジェクトã¸ã®ã‚·ãƒ§ãƒ¼ãƒˆã‚«ãƒƒãƒˆ + дерекқор Ñерверіндегі Kexi жобаÑына Ñілтеме + ë°ì´í„°ë² ì´ìŠ¤ ì„œë²„ì˜ Kexi 프로ì íŠ¸ 바로 가기 + nuoroda į Kexi projektÄ… duomenų bazÄ—s serveryje + Ä«sceļš uz Kexi projektu datubÄzes serverÄ« + shortcut naar Kexi project op database server + Skrót do projektu Kexi na serwerze bazy danych + Atalho para projeto Kexi no servidor de banco de dados + scurtătură către un proiect Kexi pe un server de baze de date + ÑÑылка на проект Kexi на Ñервере БД + bližnjica do Kexi projekta na podatkovnem strežniku + genväg till Kexi-projekt pÃ¥ databasserver + ÑÐºÐ¾Ñ€Ð¾Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ Kexi на Ñервері бази даних + æ•°æ®åº“æœåŠ¡å™¨ä¸Š Kexi 项目的快æ·æ–¹å¼ + 資料庫伺æœå™¨ä¸Š Kexi 專案的æ·å¾‘ + + + + Kexi database file-based project + مشروع قاعدة بيانات Kexi يعتمد على ملÙات + Проект Ñ Ð±Ð°Ð·Ð° от данни — Kexi + projecte basat en fitxer de base de dades del Kexi + Projekt založený na souboru databáze Kexi + Filbaseret projekt for Kexidatabase + Dateibasiertes Kexi-Datenbankprojekt + Kexi database file-based project + proyecto basado en el archivo-base de datos Kexi + Kexi datu-baseko fitxategian oinarritutako proiektua + Kexi dátustovns fílugrundað verkætlan + projet de base de données Kexi en mode fichier + tionscadal bunachair sonraí Kexi bunaithe ar chomhaid + proxecto baseado no ficheiro-base de datos Kexi + פרויקט בסיס × ×ª×•× ×™× ×ž×‘×•×¡×¡-קובץ של Kexi + Kexi adatbázisfájl-alapú projekt + Projek berbasis berkas basis data Kexi + Progetto su file di database Kexi + Kexi データベース ファイルベースプロジェクト + Файл негізінде жоба үшін Kexi дерекқоры + Kexi ë°ì´í„°ë² ì´ìŠ¤ íŒŒì¼ ê¸°ë°˜ 프로ì íŠ¸ + Kexi duomenų bazÄ—s failo tipo projektas + Kexi datubÄzes datnes balstÄ«ts projekts + Kexi database bestandgebaseerd project + Projekt bazy danych Kexi oparty na pliku + Projeto de banco de dados baseado em arquivo do Kexi + Proiect bazat pe fiÈ™iere al bazei de date Kexi + файловый проект базы данных Kexi + Datoteka projekta podatkovne zbirke Kexi + Kexi-databas för filbaserat projekt + проект файлової бази даних Kexi + Kexi 基于文件的数æ®åº“项目 + Kexi 資料庫檔案基礎專案 + + + + + Kexi database file-based project + مشروع قاعدة بيانات Kexi يعتمد على ملÙات + Проект Ñ Ð±Ð°Ð·Ð° от данни — Kexi + projecte basat en fitxer de base de dades del Kexi + Projekt založený na souboru databáze Kexi + Filbaseret projekt for Kexidatabase + Dateibasiertes Kexi-Datenbankprojekt + Kexi database file-based project + proyecto basado en el archivo-base de datos Kexi + Kexi datu-baseko fitxategian oinarritutako proiektua + Kexi dátustovns fílugrundað verkætlan + projet de base de données Kexi en mode fichier + tionscadal bunachair sonraí Kexi bunaithe ar chomhaid + proxecto baseado no ficheiro-base de datos Kexi + פרויקט בסיס × ×ª×•× ×™× ×ž×‘×•×¡×¡-קובץ של Kexi + Kexi adatbázisfájl-alapú projekt + Projek berbasis berkas basis data Kexi + Progetto su file di database Kexi + Kexi データベース ファイルベースプロジェクト + Файл негізінде жоба үшін Kexi дерекқоры + Kexi ë°ì´í„°ë² ì´ìŠ¤ íŒŒì¼ ê¸°ë°˜ 프로ì íŠ¸ + Kexi duomenų bazÄ—s failo tipo projektas + Kexi datubÄzes datnes balstÄ«ts projekts + Kexi database bestandgebaseerd project + Projekt bazy danych Kexi oparty na pliku + Projeto de banco de dados baseado em arquivo do Kexi + Proiect bazat pe fiÈ™iere al bazei de date Kexi + файловый проект базы данных Kexi + Datoteka projekta podatkovne zbirke Kexi + Kexi-databas för filbaserat projekt + проект файлової бази даних Kexi + Kexi 基于文件的数æ®åº“项目 + Kexi 資料庫檔案基礎專案 + + + + + + + KFormula formula + صيغة KFormula + FormuÅ‚a KFormula + Формула — KFormula + fórmula de KFormula + Vzorec KFormula + KFormula-formel + KFormula-Formel + μαθηματικός Ï„Ïπος KFormula + KFormula formula + KFormula-formulo + fórmula de KFormula + KFormula formula + KFormula-kaava + KFormula frymil + formule KFormula + foirmle KFormula + fórmula de KFormula + נוסחת KFormula + KFormula formula + KFormula-képlet + Formula KFormula + Formula KFormula + KFormula è¨ˆç®—å¼ + KFormula формулаÑÑ‹ + KFormula ìˆ˜ì‹ + KFormula formulÄ— + KFormula formula + Formula KFormula + KFormula-formel + KFormula-formule + KFormula-formel + FormuÅ‚a KFormula + fórmula KFormula + Fórmula do KFormula + Formulă KFormula + формула KFormula + Vzorec KFormula + Datoteka formule KFormula + Formulë KFormula + KFormula формула + KFormula-formel + KFormula formülü + формула KFormula + Công thức KFormula + KFormula å…¬å¼ + KFormula å…¬å¼ + + + + + + + + + + + + + + + + + KIllustrator drawing + تصميم KIllustrator + Rysunak KIllustrator + Чертеж — KIllustrator + dibuix de KIllustrator + Kresba KIllustrator + KIllustrator-tegning + KIllustrator-Zeichnung + σχέδιο KIllustrator + KIllustrator drawing + KIllustrator-grafikaĵo + dibujo de KIllustrator + KIllustrator marrazkia + KIllustrator-piirros + KIllustrator tekning + dessin KIllustrator + líníocht KIllustrator + debuxo de KIllustrator + ציור KIllustrator + KIllustrator crtež + KIllustrator-rajz + Gambar KIllustrator + Disegno KIllustrator + KIllustrator ドロー + KIllustrator Ñуреті + KIllustrator 그림 + KIllustrator pieÅ¡inys + KIllustrator zÄ«mÄ“jums + Lukisan KIllustrator + KIllustrator-tegning + KIllustrator-tekening + KIllustrator-teikning + Rysunek KIllustrator + desenho KIllustrator + Desenho do KIllustrator + Desen KIllustrator + изображение KIllustrator + Kresba KIllustrator + Datoteka risbe KIllustrator + Vizatim KIllustrator + KIllustrator цртеж + KIllustrator-teckning + KIllustrator çizimi + малюнок KIllustrator + Bản vẽ KIllustrator + KIllustrator 绘图 + KIllustrator 繪圖 + + + + + + + + + + + + Kivio flowchart + قائمة تدÙÙ‚ Kivio + Blok-schiema Kivio + Диаграма — Kivio + diagrama de flux de Kivio + Vývojový diagram Kivio + Kiviorutediagram + Kivio-Flussdiagramm + διάγÏαμμα Ïοής Kivio + Kivio flowchart + Kivo-fluskemo + diagrama de flujo de Kivio + Kivio diagrama + Kivio-vuokaavio + Kivio leiðarit + diagramme de flux Kivio + sreabhchairt Kivio + gráfica de fluxo de Kivio + ×ª×¨×©×™× ×–×¨×™×ž×” של Kivio + Kivio dijagram toka + Kivio-folyamatábra + Bagan Kivio + Diagramma di flusso Kivio + Kivio フローãƒãƒ£ãƒ¼ãƒˆ + Kivio диаграммаÑÑ‹ + Kivio íë¦„ë„ + Kivio eigos diagrama + Kivio blokshÄ“ma + Cartalir Kivio + Kivio-flytdiagram + Kivio-stroomschema + Kivio-flytdiagram + Diagram przepÅ‚ywów Kivio + gráfico de fluxo Kivio + Fluxograma do Kivio + Diagramă Kivio + диаграмма Kivio + Vývojový diagram Kivio + Datoteka grafikona Kivio + Diagramë fluksi Kivio + Kivio дијаграм + Kivio-flödesschema + блок-Ñхема Kivio + Lược đồ Kivio + Kivio æµç¨‹å›¾ + Kivio 圖表 + + + + + + + + + + + + + + + + + Kontour drawing + تصميم Kontour + Rysunak Kontour + Чертеж — Kontour + dibuix de Kontour + Kresba Kontour + Kontourtegning + Kontour-Zeichnung + σχέδιο Kontour + Kontour drawing + Kontour-grafikaĵo + dibujo de Kontour + Kontour marrazkia + Kontour-piirros + Kontour tekning + dessin Kontour + líníocht Kontour + debuxo de Kontour + ציור Kontour + Kontour crtež + Kontour-rajz + Gambar Kontour + Disegno Kontour + Kontour ドロー + Kontour Ñуреті + Kontour 그림 + Kontour pieÅ¡inys + Kontour zÄ«mÄ“jums + Lukisan Kontour + Kontour-tegning + Kontour-tekening + Kontour-teikning + Rysunek Kontour + desenho Kontour + Desenho do Kontour + Desen Kontour + изображение Kontour + Kresba Kontour + Datoteka risbe Kontour + Vizatim Kontour + Kontour цртеж + Kontour-teckning + Kontour çizimi + малюнок Kontour + Bản vẽ Kontour + Kontour 绘图 + Kontour 繪圖 + + + + + + + + + + + + + + + + + KPovModeler scene + مشهد KPovModeler + Scena KPovModeler + Сцена — KPovModeler + escena de KPovModeler + Scéna KPovModeler + KPovModeler-scene + KPovModeler-Szene + σκηνή KPovModeler + KPovModeler scene + KPovModeler-sceno + escena de KPovModeler + KPovModeler eszena + KPovModeler-näkymä + KPovModeler leikmynd + scène KPovModeler + radharc KPovModeler + escena de KPovModeler + סצנת KPovModeler + KPovModeler scena + KPovModeler-jelenet + Scene KPovModeler + Scena KPovModeler + KPovModeler シーン + KPovModeler ÑахнаÑÑ‹ + KPovModeler 장면 + KPovModeler scena + KPovModeler aina + Babak KPovModeler + KPovModeler-scene + KPovModeler-scène + KPovModeler-scene + Scena KPovModeler + cenário KPovModeler + Cena do KPovModeler + Scenă KPovModeler + Ñцена KPovModeler + Scéna KPovModeler + Datoteka scene KPovModeler + Skenë KPovModeler + KPovModeler Ñцена + KPovModeler-scen + Ñцена KPovModeler + Cảnh KPovModeler + KPovModeler 场景 + KPovModeler 場景 + + + + + KPresenter presentation + عرض تقديمي KPresenter + Prezentacyja KPresenter + ÐŸÑ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ â€” KPresenter + presentació de KPresenter + Prezentace KPresenter + KPresenter-præsentation + KPresenter-Präsentation + παÏουσίαση KPresenter + KPresenter presentation + KPresenter-prezentaĵo + presentación de KPresenter + Kpresenter aurkezpena + KPresenter-esitys + KPresenter framløga + présentation KPresenter + láithreoireacht KPresenter + presentación de KPresenter + מצגת KPresenter + KPresenter prezentacija + KPresenter-bemutató + Presentasi KPresenter + Presentazione KPresenter + KPresenter プレゼンテーション + KPresenter презентациÑÑÑ‹ + KPresenter 프리젠테ì´ì…˜ + KPresenter pateiktis + KPresenter prezentÄcija + Persembahan Kpresenter + KPresenter-presentasjon + KPresenter-presentatie + KPresenter-presentasjon + Prezentacja KPresenter + apresentação KPresenter + Apresentação do KPresenter + Prezentare KPresenter + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ KPresenter + Prezentácia KPresenter + Predstavitev KPresenter + Prezantim i KPresenter + KPresenter презентација + KPresenter-presentation + KPresenter sunum dosyası + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ KPresenter + Trình diá»…n KPresenter + KPresenter 演示文稿 + KPresenter 簡報檔 + + + + + + + + + + + + + + + + + + Krita document + مستند Krita + Dakument Krita + Документ — Krita + document de Krita + Dokument Krita + Kritadokument + Krita-Dokument + έγγÏαφο Krita + Krita document + Krita-dokumento + documento de Krita + Krita dokumentua + Krita-asiakirja + Krita skjal + document Krita + cáipéis Krita + documento de Krita + מסמך Krita + Krita dokument + Krita-dokumentum + Dokumen Krita + Documento Krita + Krita ドキュメント + Krita құжаты + Krita 문서 + Krita dokumentas + Krita dokuments + Dokumen Krita + Krita-dokument + Krita-document + Krita-dokument + Dokument Krita + documento Krita + Documento do Krita + Document Krita + документ Krita + Dokument Krita + Dokument Krita + Dokument Krita + Krita документ + Krita-dokument + Krita belgesi + документ Krita + Tài liệu Krita + Krita 文档 + Krita 文件 + + + + + + + + + + + + + + + + + KSpread spreadsheet + جدول KSpread + Raźlikovy arkuÅ¡ KSpread + Таблица — KSpread + full de càlcul de KSpread + SeÅ¡it KSpread + KSpread-regneark + KSpread-Tabelle + λογιστικό φÏλλο KSpread + KSpread spreadsheet + KSpread-kalkultabelo + hoja de cálculo de KSpread + KSpread kalkulu-orria + KSpread-taulukko + KSpread rokniark + feuille de calcul KSpread + scarbhileog KSpread + folla de cálculo de KSpread + גליון × ×ª×•× ×™× ×©×œ Kspread + KSpread proraÄunska tablica + KSpread-munkafüzet + Lembar sebar KSpread + Foglio di calcolo KSpread + KSpread スプレッドシート + KSpread Ñлектрондық кеÑтеÑÑ– + KSpread 스프레드시트 + KSpread skaiÄialentÄ— + KSpread izklÄjlapa + Hamparan KSpread + KSpread-regneark + KSpread-rekenblad + KSpread-rekneark + Arkusz KSpread + folha de cálculo KSpread + Planilha do KSpread + Foaie de calcul KSpread + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° KSpread + ZoÅ¡it KSpread + Preglednica KSpread + Fletë llogaritjesh KSpread + KSpread табеларни прорачун + KSpread-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ KSpread + Bảng tính KSpread + KSpread 工作簿 + KSpread 試算表 + + + + + + + + + + + + + + + + + KSpread spreadsheet (encrypted) + جدول KSpread (مشÙر) + Raźlikovy arkuÅ¡ KSpread (zaÅ¡yfravany) + Таблица — KSpread, шифрирана + full de càlcul de KSpread (xifrat) + SeÅ¡it KSpread (Å¡ifrovaný) + KSpread-regneark (krypteret) + KSpread-Tabelle (verschlüsselt) + λογιστικό φÏλλο KSpread (κÏυπτογÏαφημένο) + KSpread spreadsheet (encrypted) + KSpread-kalkultabelo (ĉifrita) + hoja de cálculo de KSpread (cifrada) + KSpread kalkulu-orria (enkriptatua) + KSpread-taulukko (salattu) + KSpread rokniark (bronglað) + feuille de calcul KSpread (chiffrée) + scarbhileog KSpread (criptithe) + folla de cálculo de KSpread (cifrada) + גליון × ×ª×•× ×™× ×©×œ KSpread (מוצפן) + KSpread proraÄunska tablica (Å¡ifrirana) + KSpread-munkafüzet (titkosított) + Lembar sebar KSpread (terenkripsi) + Foglio di calcolo KSpread (cifrato) + KSpread (æš—å·åŒ–) スプレッドシート + KSpread Ñлектрондық кеÑтеÑÑ– (шифрленген) + ì•”í˜¸í™”ëœ KSpread 스프레드시트 + KSpread skaiÄialentÄ— (užšifruota) + KSpread izklÄjlapa (Å¡ifrÄ“ta) + Hampatan KSpread (terenkripsi) + KSpread-regneark (kryptert) + KSpread-rekenblad (versleuteld) + Kryptert KSpread-rekneark + Arkusz KSpread (zaszyfrowany) + folha de cálculo KSpread (cifrada) + Planilha do KSpread (criptografada) + Foaie de calcul KSpread (criptat) + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° KSpread (зашифрованнаÑ) + ZoÅ¡it KSpread (Å¡ifrovaný) + Preglednica KSpread (Å¡ifrirana) + Fletë llogaritjesh KSpread (e kriptuar) + KSpread табеларни прорачун (шифровани) + KSpread-kalkylblad (krypterat) + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ KSpread (зашифрована) + Bảng tính KSpread (đã mật mã) + KSpread 加密工作簿 + KSpread 試算表 (已加密) + + + + + + + KSysV init package + حزمة KSysV init + Inicyjalny pakunak KSysV + Пакет — KSysV init + paquet d'inici KSysV + BalíÄek init KSysV + KSsV init-pakke + KSysV-Init-Paket + KSysV init package + paquete de configuración de init para KSysV + KSysV hasieratzeko paketea + KSysV init -paketti + KSysV init pakki + paquet d'initialisation KSysV + pacáiste thosú KSysV + paquete de KsysV init + חבילת KSysV init + KSysV init paket + KSysV init csomag + Paket init KSysV + Pacchetto init KSysV + KSysV init パッケージ + KSysV Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð´ÐµÑтеÑÑ– + KSysV init 패키지 + KSysV init paketas + KSysV inicializÄcijas pakotne + KSysV init-pakke + KSysV-init-pakket + KSysV init-pakke + Pakiet KSysV init + Pacote init do KSysV + Pachet KSysV init + пакет инициализации KSysV + BalíÄek KSysV init + Datoteka paketa KSysV init + Paketë init KSysV + KSysV init-paket + пакунок KSysV init + Gói sở khởi KSysV + KSysV init 软件包 + KSysV init 套件 + + + + + + + + + Kugar document + مستند Kugar + Dakument Kugar + Документ — Kugar + document de Kugar + Dokument Kugar + Kugardokument + Kugar-Dokument + έγγÏαφο Kugar + Kugar document + Kugar-dokumento + documento de Kugar + Kugar dokumentua + Kugar-asiakirja + Kugar skjal + document Kugar + cáipéis Kugar + documento de Kugar + מסמך Kugar + Kugar dokument + Kugar-dokumentum + Dokumen Kugar + Documento Kugar + KuKrita ドキュメント + Kugar құжаты + Kugar 문서 + Kugar dokumentas + Kugar dokuments + Dokumen Kugar + Kugar-dokument + Kugar-document + Kugar-dokument + Dokument Kuguar + documento Kugar + Documento do Kugar + Document Kugar + документ Kugar + Dokument Kugar + Dokument Kugar + Dokument Kugar + Kugar документ + Kugar-dokument + Kugar belgesi + документ Kugar + Tài liệu Kugar + Kugar 文档 + Kugar 文件 + + + + + KWord document + مستند KWord + Dakument KWord + Документ — KWord + document de KWord + Dokument KWord + Dogfen KWord + KWord-dokument + KWord-Dokument + έγγÏαφο KWord + KWord document + KWord-dokumento + documento de KWord + KWord dokumentua + KWord-asiakirja + KWord skjal + document KWord + cáipéis KWord + documento de KWord + מסמך KWord + KWord dokument + KWord-dokumentum + Dokumen KWord + Documento KWord + KWord ドキュメント + KWord құжаты + KWord 문서 + KWord dokumentas + KWord dokuments + Dokumen KWord + KWord-dokument + KWord-document + KWord-dokument + Dokument KWord + documento KWord + Documento do KWord + Document KWord + документ KWord + Dokument KWord + Dokument KWord + Dokument KWord + KWord документ + KWord-dokument + KWord belgesi + документ KWord + Tài liệu KWord + KWord 文档 + KWord 文件 + + + + + + + + + + + + + + + + + + KWord document (encrypted) + مستند KWord (مشÙر) + Dakument KWord (zaÅ¡yfravany) + Документ — KWord, шифриран + document de KWord (xifrat) + Dokument KWord (Å¡ifrovaný) + KWord-dokument (krypteret) + KWord-Dokument (verschlüsselt) + έγγÏαφο KWord (κÏυπτογÏαφημένο) + KWord document (encrypted) + KWord-dokumento (ĉifrita) + documento de KWord (cifrado) + KWord dokumentua (enkriptatua) + KWord-asiakirja (salattu) + KWord skjal (bronglað) + document KWord (chiffré) + cáipéis KWord (criptithe) + documento de KWord (cifrado) + מסמך KWord (מוצפן) + KWord dokument (Å¡ifriran) + KWord-dokumentum (titkosított) + Dokumen KWord (terenkripsi) + Documento KWord (cifrato) + KWord (æš—å·åŒ–) ドキュメント + KWord құжаты (шифрленген) + ì•”í˜¸í™”ëœ KWord 문서 + KWord dokumentas (užšifruotas) + KWord dokuments (Å¡ifrÄ“ts) + Dokumen Kword (terenkripsi) + KWord-dokument (kryptert) + KWord-document (versleuteld) + Kryptert KWord-dokument + Dokument KWord (zaszyfrowany) + documento KWord (cifrado) + Documento do KWord (criptografado) + Document KWord (criptat) + документ KWord (зашифрованный) + Dokument KWord (Å¡ifrovaný) + Dokument KWord (Å¡ifriran) + Dokument KWord (i kriptuar) + KWord документ (шифровани) + KWord-dokument (krypterat) + KWord belgesi (ÅŸifreli) + документ KWord (зашифрований) + Tài liệu KWord (đã mật mã) + KWord 加密文档 + KWord 文件 (已加密) + + + + + + + LHA archive + أرشي٠LHA + LHA arxivi + ArchiÅ­ LHA + Ðрхив — LHA + arxiu LHA + Archiv LHA + Archif LHA + LHA-arkiv + LHA-Archiv + αÏχείο LHA + LHA archive + LHA-arkivo + archivador LHA + LHA artxiboa + LHA-arkisto + LHA skjalasavn + archive LHA + cartlann LHA + arquivo LHA + ×רכיון LHA + LHA arhiva + LHA-archívum + Arsip LHA + Archivio LHA + LHA アーカイブ + LHA архиві + LHA 압축 íŒŒì¼ + LHA archyvas + LHA arhÄ«vs + Arkib LHA + LHA-arkiv + LHA-archief + LHA-arkiv + Archiwum LHA + arquivo LHA + Pacote LHA + Arhivă LHA + архив LHA + Archív LHA + Datoteka arhiva LHA + Arkiv LHA + LHA архива + LHA-arkiv + LHA arÅŸivi + архів LHA + Kho nén LHA + LHA 归档文件 + LHA å°å­˜æª” + + + + + + + + + + + + + + + + + + + + + LHZ archive + أرشي٠LHZ + ArchiÅ­ LHZ + Ðрхив — LHZ + arxiu LHZ + Archiv LHZ + LHZ-arkiv + LHZ-Archiv + αÏχείο LHZ + LHZ archive + LHZ-arkivo + archivador LHZ + LHZ artxiboa + LHZ-arkisto + LHZ skjalasavn + archive LHZ + cartlann LHZ + arquivo LHZ + ×רכיון LHZ + LHZ arhiva + LHZ-archívum + Arsip LHZ + Archivio LHZ + LHZ アーカイブ + LHZ архиві + LHZ 압축 íŒŒì¼ + LHZ archyvas + LHZ arhÄ«vs + Arkib LHZ + LHZ-arkiv + LHZ-archief + LHZ-arkiv + Archiwum LHZ + arquivo LHZ + Pacote LHZ + Arhivă LHZ + архив LHZ + Archív LHZ + Datoteka arhiva LHZ + Arkiv LHZ + LHZ архива + LHZ-arkiv + LHZ arÅŸivi + архів LHZ + Kho nén LHZ (LHA đã nén) + LHZ 归档文件 + LHZ å°å­˜æª” + + + + + message catalog + كتالوج الرسالة + kataloh paviedamleÅ„niaÅ­ + Каталог ÑÑŠÑ ÑÑŠÐ¾Ð±Ñ‰ÐµÐ½Ð¸Ñ + catàleg de missatges + Katalog zpráv + meddelelseskatalog + Nachrichtenkatalog + κατάλογος μηνυμάτων + message catalogue + katalogo de mesaÄoj + catálogo de mensajes + mezuen katalogoa + viestiluettelo + boðskrá + catalogue de messages + catalóg theachtaireachtaí + catálogo de mensaxes + קטלוג הודעות + katalog poruka + üzenetkatalógus + katalog pesan + Catalogo di messaggi + メッセージカタログ + мәлімдемелер каталогы + 메시지 카탈로그 + laiÅ¡kų katalogas + ziņojumu katalogs + Katalog mesej + meldingskatalog + berichtencatalogus + meldingskatalog + Katalog wiadomoÅ›ci + catálogo de mensagens + Catálogo de mensagens + catalog de mesaje + каталог Ñообщений + Katalóg správ + katalogov sporoÄil + Katallog mesazhesh + каталог порука + meddelandekatalog + каталог повідомлень + phân loại thông Ä‘iệp + 消æ¯åº“ + 訊æ¯ç›®éŒ„ + + + + + + + + + LyX document + مستند LyX + Dakument LyX + Документ — LyX + document de LyX + Dokument LyX + LyX-dokument + LyX-Dokument + έγγÏαφο LyX + LyX document + LyX-dokumento + documento de LyX + LyX dokumentua + LyX-asiakirja + LyX skjal + document LyX + cáipéis LyX + documento LyX + מסמך Lyx + LyX dokument + LyX-dokumentum + Dokumen LyX + Documento LyX + LyX ドキュメント + LyX құжаты + LyX 문서 + LyX dokumentas + LyX dokuments + Dokumen LyX + LyX-dokument + LyX-document + LyX-dokument + Dokument LyX + documento LyX + Documento LyX + Document LyX + документ LyX + Dokument LyX + Dokument LyX + Dokument LyX + LyX документ + LyX-dokument + документ LyX + Tài liệu LyX + LyX 文档 + LyX 文件 + + + + + + + + + + Lzip archive + أرشي٠Lzip + Ðрхив — lzip + arxiu lzip + Archiv Lzip + Lzip-arkiv + Lzip-Archiv + συμπιεσμένο αÏχείο Lzip + Lzip archive + Lzip-arkivo + archivador Lzip + Lzip artxiboa + Lzip-arkisto + Lzip skjalasavn + archive lzip + cartlann Lzip + arquivo Lzip + ×רכיון Lzip + Lzip arhiva + Lzip archívum + Arsip Lzip + Archivio Lzip + Lzip アーカイブ + Lzip архиві + LZIP 압축 íŒŒì¼ + Lzip archyvas + Lzip arhÄ«vs + Lzip archief + Archiwum lzip + Pacote Lzip + Arhivă Lzip + архив LZIP + Archív Lzip + Datoteka arhiva Lzip + Lzip-arkiv + архів lzip + Lzip 归档文件 + Lzip å°å­˜æª” + + + + + + + + LZMA archive + أرشي٠LZMA + ArchiÅ­ LZMA + Ðрхив — LZMA + arxiu LZMA + Archiv LZMA + LZHA-arkiv + LZMA-Archiv + συμπιεσμένο αÏχείο LZMA + LZMA archive + LZMA-arkivo + archivador LZMA + LZMA artxiboa + LZMA-arkisto + LZMA skjalasavn + archive LZMA + cartlann LZMA + arquivo LZMA + ×רכיון LZMA + LZMA arhiva + LZMA-archívum + Arsip LZMA + Archivio LZMA + LZMA アーカイブ + LZMA архиві + LZMA 압축 íŒŒì¼ + LZMA archyvas + LZMA arhÄ«vs + LZMA-arkiv + LZMA-archief + LZMA-arkiv + Archiwum LZMA + Pacote LZMA + Arhivă LZMA + архив LZMA + Archív LZMA + Datoteka arhiva LZMA + Arkiv LZMA + LZMA-arkiv + LZMA arÅŸivi + архів LZMA + Kho nén LZMA + LZMA 归档文件 + LZMA å°å­˜æª” + LZMA + Lempel-Ziv-Markov chain-Algorithm + + + + + Tar archive (LZMA-compressed) + أرشي٠Tar (مضغوط-LZMA) + ArchiÅ­ tar (LZMA-skampresavany) + Ðрхив — tar, компреÑиран Ñ LZMA + arxiu tar (comprimit amb LZMA) + Archiv tar (komprimovaný pomocí LZMA) + Tar-arkiv (LZMA-komprimeret) + Tar-Archiv (LZMA-komprimiert) + αÏχείο Tar (συμπιεσμένο με LZMA) + Tar archive (LZMA-compressed) + archivador Tar (comprimido con LZMA) + Tar artxiboa (LZMA-rekin konprimitua) + Tar-arkisto (LZMA-pakattu) + Tar skjalasavn (LZMA-stappað) + archive tar (compression LZMA) + cartlann Tar (comhbhrúite le LZMA) + arquivo Tar (comprimido con LZMA) + ×רכיון Tar (מכווץ ×¢"×™ LZMA) + Tar arhiva (komprimirana LZMA-om) + Tar archívum (LZMA-val tömörítve) + Arsip Tar (terkompresi LZMA) + Archivio tar (compresso con LZMA) + Tar アーカイブ (LZMA 圧縮) + Tar архиві (LZMA-мен Ñығылған) + TAR ë¬¶ìŒ íŒŒì¼ (LZMA 압축) + Tar archyvas (suglaudintas su LZMA) + Tar arhÄ«vs (saspiests ar LZMA) + Tar-arkiv (LZMA-komprimert) + Tar-archief (ingepakt met LZMA) + Tar-arkiv (pakka med LZMA) + Archiwum tar (kompresja LZMA) + Pacote tar (compactado com LZMA) + Arhivă Tar (comprimată LZMA) + архив TAR (Ñжатый LZMA) + Archív tar (komprimovaný pomocou LZMA) + Datoteka arhiva Tar (stisnjen z LZMA) + Arkiv tar (i kompresuar me LZMA) + Tar-arkiv (LZMA-komprimerat) + архів tar (ÑтиÑнений LZMA) + Kho nén tar (đã nén LZMA) + Tar 归档文件 (LZMA 压缩) + Tar å°å­˜æª” (LZMA æ ¼å¼å£“縮) + + + + + + + LZO archive + أرشي٠LZO + ArchiÅ­ LZO + Ðрхив — LZO + arxiu LZO + Archiv LZO + LZO-arkiv + LZO-Archiv + αÏχείο LZO + LZO archive + LZO-arkivo + archivador LZO + LZO artxiboa + LZO-arkisto + LZO skjalasavn + archive LZO + cartlann LZO + arquivo LZO + ×רכיון LZO + LZO arhiva + LZO-archívum + Arsip LZO + Archivio LZO + LZO アーカイブ + LZO архиві + LZO 압축 íŒŒì¼ + LZO archyvas + LZO arhÄ«vs + Arkib LZO + LZO-arkiv + LZO-archief + LZO-arkiv + Archiwum LZO + arquivo LZO + Pacote LZO + Arhivă LZO + архив LZO + Archív LZO + Datoteka arhiva LZO + Arkiv LZO + LZO архива + LZO-arkiv + LZO arÅŸivi + архів LZO + Kho nén LZO + LZO 归档文件 + LZO å°å­˜æª” + LZO + Lempel-Ziv-Oberhumer + + + + + + + + MagicPoint presentation + عرض تقديمي MagicPoint + Prezentacyja MagicPoint + ÐŸÑ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ â€” MagicPoint + presentació de MagicPoint + Prezentace MagicPoint + Cyflwyniad MagicPoint + MagicPoint-præsentation + MagicPoint-Präsentation + παÏουσίαση MagicPoint + MagicPoint presentation + MagicPoint-prezentaĵo + presentación de MagicPoint + MagicPoint aurkezpena + MagicPoint-esitys + MagicPoint framløga + présentation MagicPoint + láithreoireacht MagicPoint + presentación de MagicPoint + מצגת MagicPoint + MagicPoint prezentacija + MagicPoint-bemutató + Presentasi MagicPoint + Presentazione MagicPoint + MagicPoint プレゼンテーション + MagicPoint-ის პრეზენტáƒáƒªáƒ˜áƒ + MagicPoint презентациÑÑÑ‹ + MagicPoint 프리젠테ì´ì…˜ + MagicPoint pateiktis + MagicPoint prezentÄcija + Persembahan MagicPoint + MagicPoint-presentasjon + MagicPoint-presentatie + MagicPoint-presentasjon + Prezentacja programu MagicPoint + apresentação MagicPoint + Apresentação do MagicPoint + Prezentare MagicPoint + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ MagicPoint + Prezentácia MagicPoint + Predstavitev MagicPoint + Prezantim MagicPoint + MagicPoint презентација + MagicPoint-presentation + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ MagicPoint + Trình diá»…n MagicPoint + MagicPoint 演示文稿 + MagicPoint 簡報檔 + + + + + + Macintosh MacBinary file + مل٠Macintosh MacBinary + FajÅ‚ Macintosh MacBinary + Файл — MacBinary + fitxer MacBinary de Macintosh + Soubor MacBinary pro Macintosh + Macintosh MacBinary-fil + Macintosh-MacBinary-Datei + εκτελέσιμο Macintosh MacBinary + Macintosh MacBinary file + MacBinary-dosiero de Macintosh + archivo de Macintosh MacBinary + Macintosh MacBinary fitxategia + Macintosh MacBinary -tiedosto + Macintosh MacBinary fíla + fichier Macintosh MacBinary + comhad Macintosh MacBinary + ficheiro MacBinary de Macintosh + קובץ בינ×רי של מקינטוש + Macintosh MacBinary datoteka + Macintosh MacBinary-fájl + Berkas Macintosh MacBinary + File Macintosh MacBinary + MacBinary MacBinary ファイル + Macintosh MacBinary файлы + MacBinary íŒŒì¼ + Macintosh MacBinary failas + Macintosh MacBinary datne + Fail MacBinary Macintosh + Macintosh MacBinary-fil + Macintosh MacBinary-bestand + Macintosh MacBinary-fil + Plik MacBinary Macintosh + ficheiro MacBinary de Macintosh + Arquivo do Macintosh MacBinary + FiÈ™ier Macintosh MacBinary + файл Macintosh MacBinary + Súbor pre Macintosh MacBinary + Izvedljiva dvojiÅ¡ka datoteka Macintosh MacBinary + File MacBinary Macintosh + Мекинтош MacBinary датотека + Macintosh MacBinary-fil + файл Macintosh MacBinary + Tập tin nhị phân MacBinary của Macintosh + Macintosh MacBinary 文件 + Macintosh MacBinary 檔 + + + + + + + Matroska stream + دÙÙ‚ Matroska + PÅ‚yÅ„ Matroska + Поток — Matroska + flux Matroska + Proud Matroska + Matroskastrøm + Matroska-Datenstrom + Ïοή Matroska + Matroska stream + flujo Matroska + Matroska korrontea + Matroska-virta + Matroska streymur + flux Matroska + sruth Matroska + fluxo de Matroska + זרימת Matroska + Matroska adatfolyam + Stream Matroska + Stream Matroska + Matroska ストリーム + Matroska-ის ნáƒáƒ™áƒáƒ“ი + Matroska ағымы + Matroska 스트림 + Matroska srautas + Matroska straume + Matroska-stream + Matroska-straum + StrumieÅ„ Matroska + Transmissão do Matroska + Flux Matroska + поток Matroska + Stream Matroska + PretoÄni vir Matroska + Stream Matroska + Matroska-ström + потік даних Matroska + Luồng Matroska + Matroska æµ + Matroska ä¸²æµ + + + + + + + + + + + + + + Matroska video + Matroska مرئي + Videa Matroska + Видео — Matroska + vídeo Matroska + Video Matroska + Matroskavideo + Matroska-Video + βίντεο Matroska + Matroska video + Matroska-video + vídeo Matroska + Matroska bideoa + Matroska-video + Matroska video + vidéo Matroska + físeán Matroska + vídeo de Matroska + ויד×ו Matroska + Matroska video + Matroska-videó + Video Matroska + Video Matroska + Matroska å‹•ç”» + Matroska-ის ვიდერ+ Matroska видеоÑÑ‹ + Matroska 비디오 + Matroska vaizdo įraÅ¡as + Matroska video + Video Matroska + Matroska-film + Matroska-video + Matroska-video + Plik wideo Matroska + vídeo Matroska + Vídeo Matroska + Video Matroska + видео Matroska + Video Matroska + Video datoteka Matroska + Video Matroska + Матрошка видео + Matroska-video + відеокліп Matroska + Ảnh Ä‘á»™ng Matroska + Matroska 视频 + Matroska 視訊 + + + + + Matroska 3D video + + + + + Matroska audio + سمعي Matroska + AÅ­dyjo Matroska + Ðудио — Matroska + àudio Matroska + Zvuk Matroska + Matroskalyd + Matroska-Audio + ήχος Matroska + Matroska audio + Matroska-sondosiero + sonido Matroska + Matroska audioa + Matroska-ääni + Matroska ljóður + audio Matroska + fuaim Matroska + son de Matroska + שמע Matroska + Matroska audio + Matroska hang + Audio Matroska + Audio Matroska + Matroska オーディオ + Matroska-ის áƒáƒ£áƒ“ირ+ Matroska аудиоÑÑ‹ + Matroska 오디오 + Matroska garso įraÅ¡as + Matroska audio + Matroska-lyd + Matroska-audio + Matroska-lyd + Plik dźwiÄ™kowy Matroska + Ãudio Matroska + Audio Matroska + аудио Matroska + Zvuk Matroska + ZvoÄna datoteka Matroska + Audio Matroska + Matroska-ljud + звук Matroska + Âm thanh Matroska + Matroska 音频 + Matroska 音訊 + + + + + WebM video + WebM مرئي + Видео — WebM + vídeo WebM + Video WebM + WebM-video + WebM-Video + βίντεο WebM + WebM video + WebM-video + vídeo WebM + WebM-video + WebM video + vidéo WebM + físeán WebM + vídeo WebM + ויד×ו WebM + WebM video + WebM videó + Video WebM + Video WebM + WebM å‹•ç”» + WebM видеоÑÑ‹ + WebM 비디오 + WebM vaizdo įraÅ¡as + WebM video + WebM video + Plik wideo WebM + Vídeo WebM + Video WebM + видео WebM + Video WebM + Video datoteka WebM + WebM-video + відео WebM + WebM 视频 + WebM 視訊 + + + + + + + + + + + + + + WebM audio + WebM سمعي + Ðудио — WebM + àudio WebM + Zvuk WebM + WebM-lyd + WebM-Audio + ήχος WebM + WebM audio + WebM-sondosiero + sonido WebM + WebM-ääni + WebM ljóður + audio WebM + fuaim WebM + son WebM + שמע WebM + WebM audio + WebM hang + Audio WebM + Audio WebM + WebM オーディオ + WebM аудиоÑÑ‹ + WebM 오디오 + WebM garso įraÅ¡as + WebM audio + WebM audio + Plik dźwiÄ™kowy WebM + Ãudio WebM + Audio WebM + аудио WebM + Zvuk WebM + ZvoÄna datoteka WebM + WebM-ljud + звук WebM + WebM 音频 + WebM 音訊 + + + + MHTML web archive + MHTML + MIME HTML + + + + + + MXF video + MXF مرئي + Видео — MXF + vídeo MXF + Video MXF + MXF-video + MXF-Video + βίντεο MXF + MXF video + MXF-video + vídeo MXF + MXF bideoa + MXF-video + MXF video + vidéo MXF + físeán MXF + vídeo MXF + ויד×ו MXF + MXF video + MXF videó + Video MXF + Video MXF + MXF å‹•ç”» + MXF ვიდერ+ MXF видеоÑÑ‹ + MXF 비디오 + MXF vaizdo įraÅ¡as + MXF video + MXF video + Plik wideo MXF + Vídeo MXF + Video MXF + видео MXF + Video MXF + Video datoteka MXF + MXF-video + відеокліп MXF + MXF 视频 + MXF 視訊 + MXF + Material Exchange Format + + + + + + + + OCL file + مل٠OCL + FajÅ‚ OCL + Файл — OCL + fitxer OCL + Soubor OCL + OCL-fil + OCL-Datei + αÏχείο OCL + OCL file + OCL-dosiero + archivo OCL + OCL fitxategia + OCL-tiedosto + OCL fíla + fichier OCL + comhad OCL + ficheiro OCL + קובץ OCL + OCL datoteka + OCL fájl + Berkas OCL + File OCL + OCL ファイル + OCL файлы + OCL íŒŒì¼ + OCL failas + OCL datne + OCL-fil + OCL-bestand + OCL-fil + Plik OCL + Arquivo OCL + FiÈ™ier OCL + файл OCL + Súbor OCL + Datoteka OCL + File OCL + OCL-fil + OCL dosyası + файл OCL + Tập tin OCL + OCL 文件 + OCL 檔 + OCL + Object Constraint Language + + + + + COBOL source file + Изходен код — COBOL + codi font en COBOL + Zdrojový soubor COBOL + COBOL-kildefil + COBOL-Quelldatei + πηγαιÌο αÏχειÌο COBOL + COBOL source file + COBOL-fontdosiero + Archivo fuente de COBOL + COBOL-lähdekoodi + fichier source COBOL + ficheiro fonte de COBOL + קובץ מקור של COBOL + COBOL izvorna datoteka + COBOL forrásfájl + Berkas sumber COBOL + File sorgente COBOL + COBOL ソースファイル + COBOL-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ ფáƒáƒ˜áƒšáƒ˜ + COBOL баÑтапқы коды + COBOL 소스 íŒŒì¼ + COBOL pirmkods + COBOL bronbestand + Plik źródÅ‚owy COBOL + Arquivo de código-fonte em COBOL + файл иÑходного кода на COBOL + Izvorna koda COBOL + COBOL-källkodsfil + вихідний код мовою COBOL + COBOL æº + COBOL æºæª” + COBOL + COmmon Business Oriented Language + + + + + + Mobipocket e-book + Е-книга — Mobipocket + llibre electrònic Mobipocket + Elektronická kniha Mobipocket + Mobipocket e-bog + Mobipocket E-Book + ηλεκτÏονικό βιβλίο Mobipocket + Mobipocket e-book + Libro electrónico Mobipocket + Mobipocket e-kirja + livre numérique Mobipocket + E-book Mobipocket + ספר ×לקטרוני של Mobipocket + Mobipocket e-knjiga + Mobipocket e-könyv + e-book Mobipocket + E-book Mobipocket + Mobipocket é›»å­æ›¸ç± + Mobipocket-ის ელწიგნი + Mobipocket Ñл. кітабы + Mobipocket ì „ìžì±… + Mobipocket e-grÄmata + Mobipocket e-book + E-book Mobipocket + E-book Mobipocket + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ ÐºÐ½Ð¸Ð³Ð° Mobipocket + e-knjiga Mobipocket + електронна книга Mobipocket + Mobipocket 电å­ä¹¦ + Mobipocket e-book + + + + + + + + + + + + + + Adobe FrameMaker MIF document + مستند أدوبي الصانع للإطارات MIF + Dakument Adobe FrameMaker MIF + Документ — Adobe FrameMaker MIF + document de FrameMaker MIF d'Adobe + Dokument Adobe FrameMaker MIF + Adobe FrameMaker MIF-dokument + Adobe-FrameMaker-MIF-Dokument + αÏχειÌο MIF του Adobe FrameMaker + Adobe FrameMaker MIF document + MIF-dokumento de Adobe FrameMaker + documento MIF de Adobe FrameMaker + Adobe FrameMaker-en MIF dokumentua + Adobe FrameMaker MIF -asiakirja + Adobe FrameMaker MIF skjal + document MIF Adobe FrameMaker + cáipéis MIF Adobe FrameMaker + documento MIF de Adobe FrameMaker + מסמך MIF של Adobe FrameMaker + Adobe FrameMaker MIF dokument + Adobe FrameMaker MIF-dokumentum + Dokumen Adobe FrameMaker MIF + Documento MIF Adobe FrameMaker + Adobe FrameMaker MIF ドキュメント + Adobe FrameMaker-ის MIF დáƒáƒ™áƒ£áƒ›áƒ”ნტი + Adobe FrameMaker MIF құжаты + ì–´ë„비 프레임메ì´ì»¤ MIF 문서 + Adobe FrameMaker MIF dokumentas + Adobe FrameMaker MIF dokuments + Adobe FrameMaker MIF-dokument + Adobe FrameMaker MIF-document + Adobe FrameMaker MIF-dokument + Dokument MIF Adobe FrameMaker + Documento MIF do Adobe FrameMaker + Document Adobe FrameMaker MIF + документ Adobe FrameMaker MIF + Dokument Adobe FrameMaker MIF + Dokument Adobe FrameMaker MIF + Dokument MIF Adobe FrameMaker + Adobe FrameMaker MIF-dokument + документ Adobe FrameMaker MIF + Tài liệu Adobe FrameMaker MIF + Adobe FrameMaker MIF 文档 + Adobe FrameMaker MIF 文件 + + + + Mozilla bookmarks + علامات موزيلا + ZakÅ‚adki Mozilla + Отметки — Mozilla + llista d'adreces d'interès de Mozilla + Záložky Mozilla + Mozillabogmærker + Mozilla-Lesezeichen + σελιδοδείκτες Mozilla + Mozilla bookmarks + Mozilla-legosignoj + marcadores de Mozilla + Mozillako laster-markak + Mozilla-kirjanmerkit + Mozilla bókamerki + marque-pages Mozilla + leabharmharcanna Mozilla + Marcadores de Mozilla + סמניה של Mozilla + Mozilla knjižne oznake + Mozilla-könyvjelzÅ‘k + Bookmark Mozilla + Segnalibri Mozilla + Mozilla ブックマーク + Mozilla бетбелгілері + ëª¨ì§ˆë¼ ì±…ê°ˆí”¼ + Mozilla žymelÄ—s + Mozilla grÄmatzÄ«mes + Tandabuku Mozilla + Mozilla-bokmerker + Mozilla-bladwijzers + Mozilla-bokmerker + ZakÅ‚adki Mozilla + marcadores do Mozilla + Marcadores do Mozilla + Semne de carte Mozilla + закладки Mozilla + Záložky Mozilla + Datoteka zaznamkov Mozilla + Libërshënues Mozilla + Mozilla обележивачи + Mozilla-bokmärken + закладки Mozilla + Liên kết đã lÆ°u Mozilla + Mozilla 书签 + Mozilla 書籤 + + + + + + + + + DOS/Windows executable + تنÙيذي DOS/Windows + Vykonvalny fajÅ‚ DOS/Windows + Изпълним файл — DOS/Windows + executable de DOS/Windows + Spustitelný soubor pro DOS/Windows + DOS-/Windowskørbar + DOS/Windows-Programm + εκτελέσιμο DOS/Windows + DOS/Windows executable + DOS/Windows-plenumebla + ejecutable de DOS/Windows + DOS/Windows-eko exekutagarria + DOS/Windows-ohjelma + DOS/Windows inningarfør + exécutable DOS/Windows + comhad inrite DOS/Windows + executábel de DOS/Windows + קובץ בר־הרצה של DOS/חלונות + DOS/Windows izvrÅ¡na datoteka + DOS/Windows futtatható + DOS/Windows dapat dieksekusi + Eseguibile DOS/Windows + DOS/Windows 実行ファイル + DOS/Windows გáƒáƒ¨áƒ•áƒ”ბáƒáƒ“ი ფáƒáƒ˜áƒšáƒ˜ + DOS/Windows орындалатын файлы + DOS/Windows 실행 íŒŒì¼ + DOS/Windows vykdomasis failas + DOS/Windows izpildÄmais + Bolehlaksana DOS/Windows + Kjørbar fil for DOS/Windows + DOS/Windows-uitvoerbaar bestand + DOS/Windows køyrbar fil + Program DOS/Windows + executável DOS/Windows + Executável do DOS/Windows + Executabil DOS/Windows + иÑполнÑемый файл DOS/Windows + Spustiteľný súbor pre DOS/Windows + Izvedljiva datoteka DOS/Windows + I ekzekutueshëm DOS/Windows + ДОС/Виндоуз извршна датотека + Körbar DOS/Windows-fil + DOS/Windows çalıştırılabilir + виконуваний файл DOS/Windows + Tập tin có thá»±c hiện được DOS/Windows + DOS/Windows å¯æ‰§è¡Œæ–‡ä»¶ + DOS/Windows å¯åŸ·è¡Œæª” + + + + + + + + Internet shortcut + اختصار الإنترنت + SieciÅ­naja spasyÅ‚ka + ÐÐ´Ñ€ÐµÑ Ð² Интернет + drecera d'Internet + Odkaz do Internetu + Internetgenvej + Internet-Verweis + συντόμευση διαδικτÏου + Internet shortcut + acceso directo a Internet + Interneteko lasterbidea + Internet-pikakuvake + Alnetssnarvegur + raccourci Internet + aicearra Idirlín + atallo de Internet + קיצור דרך של ×”×ינטרנט + Internetski preÄac + Internetes indítóikon + Jalan pintas Internet + Scorciatoia Internet + インターãƒãƒƒãƒˆã‚·ãƒ§ãƒ¼ãƒˆã‚«ãƒƒãƒˆ + Интернет ÑілтемеÑÑ– + ì¸í„°ë„· 바로 가기 + Interneto nuoroda + Interneta Ä«sceļš + Internettsnarvei + internetkoppeling + Internett-snarveg + Skrót internetowy + Atalho da internet + Scurtătură Internet + Интернет-ÑÑылка + Internetový odkaz + Internetna bližnjica + Shkurtim internet + Internetgenväg + інтернет-поÑÐ¸Ð»Ð°Ð½Ð½Ñ + Lối tắt Internet + Internet å¿«æ·æ–¹å¼ + 網際網路æ·å¾‘ + + + + + + + + + + WRI document + مستند WRI + Dakument WRI + Документ — WRI + document WRI + Dokument WRI + WRI-dokument + WRI-Dokument + έγγÏαφο WRI + WRI document + WRI-dokumento + documento WRI + WRI dokumentua + WRI-asiakirja + WRI skjal + document WRI + cáipéis WRI + documento WRI + מסמך WRI + WRI dokument + WRI dokumentum + Dokumen WRI + Documento WRI + WRI ドキュメント + WRI құжаты + WRI 문서 + WRI dokumentas + WRI dokuments + WRI-dokument + WRI-document + WRI-dokument + Dokument WRI + Documento WRI + Document WRI + документ WRI + Dokument WRI + Dokument WRI + Dokument WRI + WRI-dokument + WRI belgesi + документ WRI + Tài liệu WRI + WRI 文档 + WRI 文件 + + + + + MSX ROM + MSX ROM + MSX ROM + ROM — MSX + ROM de MSX + ROM pro MSX + ROM MSX + MSX-rom + MSX-ROM + εικόνα μνήμης ROM MSX + MSX ROM + MSX-NLM + ROM de MSX + MSX-ko ROMa + MSX-ROM + MSX ROM + ROM MSX + ROM MSX + ROM de MSX + MSX ROM + MSX ROM + MSX ROM + Memori baca-saja MSX + ROM MSX + MSX ROM + MSX-ის ROM + MSX ROM + MSX 롬 + MSX ROM + MSX ROM + ROM MSX + MSX-ROM + MSX-ROM + MSX-ROM + Plik ROM konsoli MSX + ROM MSX + ROM do MSX + ROM MSX + MSX ROM + ROM pre MSX + Bralni pomnilnik MSX + ROM MSX + MSX ром + MSX-rom + ППП MSX + ROM MSX + MSX ROM + MSX ROM + + + + + M4 macro + M4 macro + Makras M4 + МакроÑи — M4 + macro M4 + Makro M4 + M4-makro + M4-Makro + μακÏÎ¿ÎµÎ½Ï„Î¿Î»Î·Ì m4 + M4 macro + macro M4 + M4 makroa + M4-makro + M4 fjølvi + macro M4 + macra M4 + macro M4 + מ×קרו M4 + M4 makro + M4 makró + Makro M4 + Macro M4 + M4 マクロ + M4 макроÑÑ‹ + M4 매í¬ë¡œ + M4 macro + M4 makross + M4-makro + M4-macro + M4-makro + Makro M4 + Macro M4 + Macro M4 + Ð¼Ð°ÐºÑ€Ð¾Ñ M4 + Makro M4 + Makro datoteka M4 + Macro M4 + M4-makro + Ð¼Ð°ÐºÑ€Ð¾Ñ M4 + VÄ© lệnh M4 + M4 å® + M4 巨集 + + + + + + Nintendo64 ROM + Nintendo64 ROM + Nintendo64 ROM + ROM — Nintendo64 + ROM de Nintendo64 + ROM pro Nintendo64 + Nintendo64-rom + Nintendo64-ROM + εικόνα μνήμης ROM Nintendo64 + Nintendo64 ROM + Nintendo64-NLM + ROM de Nintendo64 + Nintendo64-ko ROMa + Nintendo64-ROM + Nintendo64 ROM + ROM Nintendo64 + ROM Nintendo64 + ROM de Nintendo64 + ROM של Nןמ×קמג×64 + Nintendo64 ROM + Nintendo64 ROM + Memori baca-saja Nintendo64 + ROM Nintendo64 + Nintendo64 ROM + Nintendo64 ROM + ë‹Œí…ë„ 64 롬 + Nintendo64 ROM + Nintendo64 ROM + ROM Nintendo64 + Nintendo64-ROM + Nintendo64-ROM + Nintendo64-ROM + Plik ROM konsoli Nintendo64 + ROM Nintendo64 + ROM do Nintendo64 + ROM Nintendo64 + Nintendo64 ROM + ROM pre Nintendo64 + Bralni pomnilnik Nintendo64 + ROM Nintendo64 + Ðинтендо64 РОМ + Nintendo64-rom + Nintendo64 ROM + ППП Nintendo64 + ROM Nintendo64 + Nintendo64 ROM + Nintendo64 ROM + + + + + Nautilus link + وصلة Nautilus + Nautilus körpüsü + SpasyÅ‚ka Nautilus + Връзка — Nautilus + enllaç de Nautilus + Odkaz Nautilus + Cyswllt Nautilus + Nautilus-henvisning + Nautilus-Verknüpfung + σÏνδεσμος Nautilus + Nautilus link + Nautilus-ligilo + enlace de Nautilus + Nautilus esteka + Nautilus-linkki + Nautilus leinkja + lien Nautilus + nasc Nautilus + ligazón de nautilus + קישור של Nautilus + Nautilus veza + Nautilus-link + Taut Nautilus + Collegamento Nautilus + Nautilus リンク + Nautilus ÑілтемеÑÑ– + 노틸러스 바로 가기 + Nautilus nuoroda + Nautilus saite + Pautan Nautilus + Nautilus-lenke + Nautilus-verwijzing + Nautilus-lenke + OdnoÅ›nik Nautilus + atalho Nautilus + Link do Nautilus + Legătură Nautilus + ÑÑылка Nautilus + Odkaz Nautilus + Datoteka povezave Nautilus + Lidhje Nautilus + ÐÐ°ÑƒÑ‚Ð¸Ð»ÑƒÑ Ð²ÐµÐ·Ð° + Nautiluslänk + Nautilus baÄŸlantısı + поÑÐ¸Ð»Ð°Ð½Ð½Ñ Nautilus + Liên kết Nautilus + Nautilus 链接 + Nautilus éˆçµ + + + + + + + + + NES ROM + NES ROM + NES ROM + ROM — NES + ROM de NES + ROM pro NES + ROM NES + NES-rom + NES-ROM + εικόνα μνήμης ROM NES + NES ROM + NES-NLM + ROM de NES + NES-eko ROMa + NES-ROM + NES ROM + ROM NES + ROM NES + ROM de NES + ROM של NES + NES ROM + NES ROM + Memori baca-saja NES + ROM NES + ファミコン ROM + NES ROM + NES 롬 + NES ROM + NES ROM + ROM NES + NES ROM + Nintendo + NES-ROM + Plik ROM konsoli NES + ROM NES + ROM do NES + ROM NES + NES ROM + ROM pre NES + Bralni pomnilnik NES + ROM NES + NES ром + NES-rom + NES ROM + ППП NES + ROM NES + NES ROM + 任天堂 ROM + + + + + Unidata NetCDF document + مستند Unidata NetCDF + Dakument Unidata NetCDF + Документ — Unidata NetCDF + document Unidata NetCDF + Dokument Unidata NetCDF + Unidata NetCDF-dokument + Unidata-NetCDF-Dokument + έγγÏαφο Unidata NetCDF + Unidata NetCDF document + dokumento en NetCDF-formato de Unidata + documento de Unidata NetCDF + Unidata NetCDF dokumentua + Unidata NetCDF -asiakirja + Unidata NetCDF skjal + document Unidata NetCDF + cáipéis Unidata NetCDF + Documentno de Unixdata NetCDF + מסמך של Unidata NetCDF + Unidata NetCDF dokument + Unidata NetCDF-dokumentum + Dokumen Unidata NetCDF + Documento Unidata NetCDF + Unidata NetCDF ドキュメント + Unidata NetCDF құжаты + Unidata NetCDF 문서 + Unidata NetCDF dokumentas + Unidata NetCDF dokuments + Dokumen Unidata NetCDF + Unidata NetCDF-dokument + Unidata NetCDF-document + Unidata netCDF-dokument + Dokument Unidata NetCDF + documento Unidata NetCDF + Documento do Unidata NetCDF + Document Unidata NetCDF + документ Unidata NetCDF + Dokument Unidata NetCDF + Dokument Unidata NetCDF + Dokument Unidata NetCDF + Unidata NetCDF документ + Unidata NetCDF-dokument + Unidata NetCDF belgesi + документ Unidata NetCDF + Tài liệu NetCDF Unidata + Unidata NetCDF 文档 + Unidata NetCDF 文件 + NetCDF + Network Common Data Form + + + + + + NewzBin usenet index + Ð˜Ð½Ð´ÐµÐºÑ â€” Usenet, NewzBin + índex d'Usenet NewzBin + Index NewzBin diskuzních skupin Usenet + NewzBin-brugernetindex + NewzBin-Usenet-Index + ευÏετήÏιο usenet NewzBin + NewzBin usenet index + Ãndice NewzBin de usenet + index usenet + Ãndice de usenet NEwzBin + ×ינדקס שרתי חדשות NewzBin + NewzBin usenet index + Indeks usenet NewzBin + Indice Usenet NewzBiz + NewzBin Usenet インデックス + NewzBin usenet индекÑÑ– + NewzBin 유즈넷 ì¸ë±ìŠ¤ + NewzBin usenet rÄdÄ«tÄjs + NewzBin usenet index + Indeks grup dyskusyjnych NewzBin + Ãndice de usenet NewzBin + Ð¸Ð½Ð´ÐµÐºÑ usenet NewzBin + Kazalo usenet NewzBin + покажчик usenet NewzBin + NewzBin usenet 索引 + NewzBin usenet 索引 + + + + + + + + object code + رمز الكائن + abjektny kod + Обектен код + codi objecte + Objektový kód + objektkode + Objekt-Code + μεταφÏασμένος κώδικας + object code + celkodo + código objeto + objektu kodea + objektikoodi + code objet + cód réada + código obxecto + קוד ×ובייקט + kod objekta + tárgykód + kode object + Codice oggetto + オブジェクトコード + объектті коды + 개체 코드 + objektinis kodas + objekta kods + Kod objek + objektkode + objectcode + objektkode + Kod obiektowy + código de objecto + Código-objeto + cod sursă obiect + объектный код + Objektový kód + predmetna koda + Kod objekti + објектни ко̂д + objektkod + об'єктний код + mã đối tượng + ç›®æ ‡ä»£ç  + 目的碼 + + + + + + + + + + + + + + + + + Annodex exchange format + صيغة Annodex البديلة + Формат за обмÑна — Annodex + format d'intercanvi Annodex + VýmÄ›nný formát Annodex + Udvekslingsformat for Annodex + Annodex-Wechselformat + μοÏφή ανταλλαγής Annodex + Annodex exchange format + formato de intercambio Annodex + Annodex trukatze-formatua + Annodex-siirtomuoto + Annodex umbýtingarsnið + format d'échange Annodex + formáid mhalairte Annodex + formato intercambiábel de Annodex + פורמט החלפת Annodex + Annodex oblik za razmjenu + Annodex csereformátum + Format pertukaran Annodex + Formato di scambio Annodex + Annodex 交æ›ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆ + Annodex-ის გáƒáƒªáƒ•áƒšáƒ˜áƒ—ი ფáƒáƒ áƒ›áƒáƒ¢áƒ˜ + Annodex алмаÑу пішімі + Annodex êµí™˜ í˜•ì‹ + Annodex mainų formatas + Annodex apmaiņas formÄts + Annodex-exchange + Format wymiany Annodex + Formato de troca Annodex + Format schimb Annodex + формат обмена Annodex + Formát pre výmenu Annodex + Izmenjalna datoteka Annodex + Annodex-utväxlingsformat + формат обміну даними Annodex + Äịnh dạng trao đổi Annodex + Annodex 交æ¢æ ¼å¼ + Annodex 交æ›æ ¼å¼ + + + + + + + + + + + + + Annodex Video + Annodex مرئي + Видео — Annodex + Annodex Video + Annodex Video + Annodexvideo + Annodex-Video + βίντεο Annodex + Annodex Video + Annodex-video + vídeo Annodex + Annodex bideoa + Annodex-video + Annodex video + vidéo Annodex + físeán Annodex + vídeo de Annodex + ויד×ו Annodex + Annodex Video + Annodex videó + Video Annodex + Video Annodex + Annodex å‹•ç”» + Annodex-ის ვიდერ+ Annodex видеоÑÑ‹ + Annodex 비디오 + Annodex vaizdo įraÅ¡as + Annodex video + Annodex Video + Plik wideo Annodex + Vídeo Annodex + Video Annodex + видео Annodex + Video Annodex + Video datoteka Annodex + Annodex-video + відеокліп Annodex + Ảnh Ä‘á»™ng Annodex + Annodex 视频 + Annodex 視訊 + + + + + + + + + + + + + Annodex Audio + Annodex سمعي + Ðудио — Annodex + Annodex Audio + Annodex Audio + Annodexlyd + Annodex-Audio + ήχος Annodex + Annodex Audio + Annodex-sondosiero + sonido Annodex + Annodex audioa + Annodex-ääni + Annodex ljóður + audio Annodex + fuaim Annodex + son de Annodex + שמע Annodex + Annodex Audio + Annodex hang + Audio Annodex + Audio Annodex + Annodex オーディオ + Annodex-ის áƒáƒ£áƒ“ირ+ Annodex аудиоÑÑ‹ + Annodex 오디오 + Annodex garso įraÅ¡as + Annodex audio + Annodex Audio + Plik dźwiÄ™kowy Annodex + Ãudio Annodex + Audio Annodex + аудио Annodex + Zvuk Annodex + ZvoÄna datoteka Annodex + Annodex-ljud + звук Annodex + Âm thanh Annodex + Annodex 音频 + Annodex 音訊 + + + + + + + + + + + + + Ogg multimedia file + مل٠وسائط متعددة Ogg + Multymedyjny fajÅ‚ Ogg + ÐœÑƒÐ»Ñ‚Ð¸Ð¼ÐµÐ´Ð¸Ñ â€” Ogg + fitxer Ogg multimèdia + Soubor multimédií Ogg + Ogg multimedie-fil + Ogg-Multimediadatei + ΑÏχειÌο πολυμεÌσων Ogg + Ogg multimedia file + archivo multimedia Ogg + Ogg multimediako fitxategia + Ogg-multimediatiedosto + Ogg margmiðlafíla + fichier multimédia Ogg + comhad ilmheán Ogg + ficheiro multimedia Ogg + קובץ מולטימדיה Ogg + Ogg multimédiafájl + Berkas multimedia Ogg + File multimediale Ogg + Ogg マルãƒãƒ¡ãƒ‡ã‚£ã‚¢ãƒ•ã‚¡ã‚¤ãƒ« + Ogg-ის მულტიმედირფáƒáƒ˜áƒšáƒ˜ + Ogg мультимедиа файлы + Ogg 멀티미디어 íŒŒì¼ + Ogg multimedijos failas + Ogg multimediju datne + Ogg-multimediafil + Ogg-multimediabestand + Ogg multimediafil + Plik multimedialny Ogg + Arquivo multimídia Ogg + FiÈ™ier multimedia Ogg + мультимедийный файл Ogg + Súbor multimédií Ogg + VeÄpredstavnostna datoteka Ogg + File multimedial Ogg + Ogg-multimediafil + мультимедійний файл Ogg + Tập tin Ä‘a phÆ°Æ¡ng tiện Ogg + Ogg 多媒体文件 + Ogg 多媒體檔案 + + + + + + + + + Ogg Audio + Ogg سمعي + AÅ­dyjo Ogg + Ðудио — Ogg + àudio Ogg + Zvuk Ogg + Ogg-lyd + Ogg-Audio + ήχος Ogg + Ogg Audio + sonido Ogg + Ogg audioa + Ogg-ääni + Ogg ljóður + audio Ogg + fuaim Ogg + son Ogg + שמע Ogg + Ogg hang + Audio Ogg + Audio Ogg + Ogg オーディオ + Ogg-ის áƒáƒ£áƒ“ირ+ Ogg аудиоÑÑ‹ + Ogg 오디오 + Ogg garso įraÅ¡as + Ogg audio + Ogg lyd + Ogg-audio + Ogg-lyd + Plik dźwiÄ™kowy Ogg + Ãudio Ogg + Audio Ogg + аудио Ogg + Zvuk Ogg + ZvoÄna datoteka Ogg + Audio Ogg + Ogg-ljud + звук ogg + Âm thanh Ogg + Ogg 音频 + Ogg 音訊 + + + + + + + + + + Ogg Video + Ogg مرئي + Videa Ogg + Видео — Ogg + vídeo Ogg + Video Ogg + Ogg-video + Ogg-Video + βίντεο Ogg + Ogg Video + vídeo Ogg + Ogg bideoa + Ogg-video + Ogg Video + vidéo Ogg + físeán Ogg + vídeo Ogg + ויד×ו Ogg + Ogg videó + Video Ogg + Video Ogg + Ogg å‹•ç”» + Ogg ვიდერ+ Ogg видеоÑÑ‹ + Ogg 비디오 + Ogg vaizdo įraÅ¡as + Ogg video + Ogg video + Ogg-video + Ogg-video + Plik wideo Ogg + Vídeo Ogg + Video Ogg + видео Ogg + Video Ogg + Video datoteka Ogg + Video Ogg + Ogg-video + відеокліп ogg + Ảnh Ä‘á»™ng Ogg + Ogg 视频 + Ogg 視訊 + + + + + + + + + + Ogg Vorbis audio + Ogg Vorbis سمعي + Ogg Vorbis audio faylı + AÅ­dyjo Ogg Vorbis + Ðудио — Ogg Vorbis + àudio Ogg Vorbis + Zvuk Ogg Vorbis + Sain Ogg Vorbis + Ogg Vorbis-lyd + Ogg-Vorbis-Audio + ήχος Ogg Vobris + Ogg Vorbis audio + Ogg-Vorbis-sondosiero + sonido Ogg Vorbis + Ogg Vorbis audioa + Ogg Vorbis -ääni + Ogg Vorbis ljóður + audio Ogg Vorbis + fuaim Ogg Vorbis + son Ogg Vorbis + שמע Ogg Vorbis + Ogg Vorbis hang + Audio Ogg Vorbis + Audio Ogg Vorbis + Ogg Vorbis オーディオ + Ogg Vorbis áƒáƒ£áƒ“ირ+ Ogg Vorbis аудиоÑÑ‹ + Ogg Vorbis 오디오 + Ogg Vorbis garso įraÅ¡as + Ogg Vorbis audio + Audio Ogg Vorbis + Ogg Vorbis lyd + Ogg Vorbis-audio + Ogg Vorbis-lyd + Plik dźwiÄ™kowy Ogg Vorbis + áudio Ogg Vorbis + Ãudio do Ogg Vorbis + Audio Ogg Vorbis + аудио Ogg Vorbis + Zvuk Ogg Vorbis + ZvoÄna datoteka Ogg Vorbis + Audio Ogg Vorbis + Ог-Ð²Ð¾Ñ€Ð±Ð¸Ñ Ð·Ð²ÑƒÑ‡Ð½Ð¸ Ð·Ð°Ð¿Ð¸Ñ + Ogg Vorbis-ljud + звук ogg Vorbis + Âm thanh Vorbis Ogg + Ogg Vorbis 音频 + Ogg Vorbis 音訊 + + + + + + + + + + + + + Ogg FLAC audio + Ogg FLAC سمعي + AÅ­dyjo Ogg FLAC + Ðудио — Ogg FLAC + àudio Ogg FLAC + Zvuk Ogg FLAC + Ogg FLAC-lyd + Ogg-FLAC-Audio + ήχος Ogg FLAC + Ogg FLAC audio + sonido Ogg FLAC + Ogg FLAC audioa + Ogg FLAC -ääni + Ogg FLAC ljóður + audio Ogg FLAC + fuaim Ogg FLAC + son Ogg FLAC + שמע Ogg FLAC + Ogg FLAC hang + Audio Ogg FLAC + Audio Ogg FLAC + Ogg FLAC オーディオ + Ogg FLAC áƒáƒ£áƒ“ირ+ Ogg FLAC аудиоÑÑ‹ + Ogg FLAC 오디오 + Ogg FLAC garso įraÅ¡as + Ogg FLAC audio + Ogg FLAC-lyd + Ogg FLAC-audio + Ogg FLAC-lyd + Plik dźwiÄ™kowy Ogg FLAC + Ãudio FLAC Ogg + Audio Ogg FLAC + аудио Ogg FLAC + Zvuk Ogg FLAC + ZvoÄna datoteka Ogg FLAC + Audio Ogg FLAC + Ogg FLAC-ljud + звук ogg FLAC + Âm thanh FLAC Ogg + Ogg FLAC 音频 + Ogg FLAC 音訊 + + + + + + + + + + + + + + + Ogg Speex audio + Ogg Speex سمعي + AÅ­dyjo Ogg Speex + Ðудио — Ogg Speex + àudio Ogg Speex + Zvuk Ogg Speex + Ogg Speex-lyd + Ogg-Speex-Audio + ηÌχος Ogg Speex + Ogg Speex audio + sonido Ogg Speex + Ogg Speex audioa + Ogg Speex -ääni + Ogg Speex ljóður + audio Ogg Speex + fuaim Ogg Speex + son Ogg Speex + שמע Ogg Speex + Ogg Speex hang + Audio Ogg Speex + Audio Ogg Speex + Ogg Speex オーディオ + Ogg Speex áƒáƒ£áƒ“ირ+ Ogg Speex аудиоÑÑ‹ + Ogg Speex 오디오 + Ogg Speex garso įraÅ¡as + Ogg Speex audio + Ogg Speex lyd + Ogg Speex-audio + Ogg Speex-lyd + Plik dźwiÄ™kowy Ogg Speex + Ãudio Speex Ogg + Audio Ogg Speex + аудио Ogg Speex + Zvuk Ogg Speex + ZvoÄna datoteka Ogg Speex + Audio Ogg Speex + Ogg Speex-ljud + звук ogg Speex + Âm thanh Speex Ogg + Ogg Speex 音频 + Ogg Speex 音訊 + + + + + + + + + + + Speex audio + Speex سمعي + AÅ­dyjo Speex + Ðудио — Speex + àudio Speex + Zvuk Speex + Speexlyd + Speex-Audio + ήχος Speex + Speex audio + sonido Speex + Speex audioa + Speex-ääni + Speex ljóður + audio Speex + fuaim Speex + son Speex + שמע של Speex + Speex audio + Speex hang + Audio Speex + Audio Speex + Speex オーディオ + Speex аудиоÑÑ‹ + Speex 오디오 + Speex garso įraÅ¡as + Speex audio + Speex lyd + Speex-audio + Speex-lyd + Plik dźwiÄ™kowy Speex + Ãudio Speex + Audio Speex + аудио Speex + Zvuk Speex + ZvoÄna datoteka Speex + Audio Speex + Speex-ljud + звук Speex + Âm thanh Speex + Speex 音频 + Speex 音訊 + + + + + + + Ogg Theora video + Ogg Theora مرئي + Videa Ogg Theora + Видео — Ogg Theora + vídeo Ogg Theora + Video Ogg Theora + Ogg Theora-video + Ogg-Theora-Video + βίντεο Ogg Theora + Ogg Theora video + vídeo Ogg Theora + Ogg Theora bideoa + Ogg Theora -video + Ogg Theora video + vidéo Ogg Theora + físeán Ogg Theora + vídeo Ogg Theora + שמע Ogg Theora + Ogg Theora videó + Video Ogg Theora + Video Ogg Theora + Ogg Theora å‹•ç”» + Ogg Theora ვიდერ+ Ogg Theora видеоÑÑ‹ + Ogg Theora 비디오 + Ogg Theora vaizdo įraÅ¡as + Ogg Theora video + Ogg Theora video + Ogg Theora-video + Ogg Theora-video + Plik wideo Ogg Theora + Vídeo do Ogg Theora + Video Ogg Theora + видео Ogg Theora + Video Ogg Theora + Video datoteka Ogg Theora + Video Ogg Theora + Ogg Theora-video + відеокліп ogg Theora + Ảnh Ä‘á»™ng Theora Ogg + Ogg Theora 视频 + Ogg Theora 視訊 + + + + + + + + + + + OGM video + OGM مرئي + Videa OGM + Видео — OGM + vídeo OGM + Video OGM + OGM-video + OGM-Video + βίντεο OGM + OGM video + OGM-video + vídeo OGM + OGM bideoa + OGM-video + OGM video + vidéo OGM + físeán OGM + vídeo OGM + ויד×ו OGM + OGM video + OGM-videó + Video OGM + Video OGM + OGM å‹•ç”» + OGM ვიდერ+ OGM видеоÑÑ‹ + OGM 비디오 + OGM vaizdo įraÅ¡as + OGM video + OGM-film + OGM-video + OGM-video + Plik wideo OGM + Vídeo OGM + Video OGM + видео OGM + Video OGM + Video datoteka OGM + Video OGM + OGM-video + відеокліп OGM + Ảnh Ä‘á»™ng OGM + OGM 视频 + OGM 視訊 + + + + + + + + + + + + OLE2 compound document storage + تخزين مجمع مستند OLE2 + SchoviÅ¡Äa dla kampanentaÅ­ dakumentu OLE2 + СъÑтавен документ-хранилище — OLE2 + emmagatzematge de documents composats OLE2 + ÚložiÅ¡tÄ› složeného dokumentu OLE2 + OLE2-sammensat dokumentlager + OLE2-Verbunddokumentenspeicher + αÏχείο συμπαγοÏÏ‚ αποθήκευσης εγγÏάφων OLE2 + OLE2 compound document storage + OLE2-deponejo de parentezaj dokumentoj + almacenamiento de documentos compuestos OLE2 + OLE2 konposatutako dokumentu-bilduma + OLE2-yhdisteasiakirjatallenne + OLE2 samansett skjalagoymsla + document de stockage composé OLE2 + stóras cháipéisí comhshuite OLE2 + almacenamento de documento composto OLE2 + ×חסון מסמך משותף OLE2 + OLE2 összetett dokumentumtároló + penyimpan dokumen kompon OLE2 + Memorizzazione documento composto OLE2 + OLE2 複åˆãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ + OLE2 құрама құжаттар қоймаÑÑ‹ + OLE2 복합 문서 + OLE2 sudÄ—tinių dokumentų laikmena + OLE2 savienoto dokumentu glabÄtuve + Storan dokumen halaman OLE2 + OLE-lager for sammensatte dokumenter + OLE2-samengestelde documentopslag + OLE2 lager for samansett dokument + Magazyn dokumentu zÅ‚ożonego OLE2 + armazenamento de documento composto OLE2 + Armazenamento de documento composto OLE2 + Document de stocare compus OLE2 + хранилище ÑоÑтавных документов OLE2 + Úložisko zloženého dokumentu OLE2 + Združeni dokument OLE2 + Arkiv dokumenti i përbërë OLE2 + ОЛЕ2 Ñједињени документ + Sammansatt OLE2-dokumentlager + Ñховище Ñкладних документів OLE2 + Kho lÆ°u tài liệu ghép OLE2 + OLE2 组åˆæ–‡æ¡£å­˜å‚¨ + OLE2 複åˆæ–‡ä»¶å„²å­˜ + + + + + + + + Microsoft Publisher document + + + + + Windows Installer package + حزمة مثبّت ويندوز + Pakunak Windows Installer + Пакет — инÑÑ‚Ð°Ð»Ð°Ñ†Ð¸Ñ Ð·Ð° Windows + paquet de Windows Installer + BalíÄek Windows Installer + Windows Installer-pakke + Windows Installationspaket + πακέτο Windows Installer + Windows Installer package + paquete de instalación de Windows + Windows-eko pakete instalatzailea + Windows-asennuspaketti + Windows innleggingarpakki + paquet d'installation Windows + pacáiste Windows Installer + paquete de instalación de Windows + חבילה של Windows Installer + Windows Installer paket + Windows Installer csomag + Paket Windows Installer + Pacchetto Windows Installer + Windodws インストーラパッケージ + Windows Installer деÑтеÑÑ– + Windows 설치 패키지 + Windows Installer paketas + Windows Installer pakotne + Windows-installatiepakket + Windows Installer-pakke + Pakiet instalatora Windows + Pacote do instalador do Windows + Pachet instalator Windows + пакет Windows Installer + Balík Windows Installer + Datoteka paketa Windows namestilnika + Paketë Windows Installer + Windows Installer-paket + Windows Installer paketi + пакунок Windows Installer + Gói cài đặt Windows + Windows 程åºå®‰è£…包 + Windows Installer 套件 + + + + + GNU Oleo spreadsheet + جدول جنو Oleo + Raźlikovy arkuÅ¡ GNU Oleo + Таблица — GNU Oleo + full de càlcul de GNU Oleo + SeÅ¡it GNU Oleo + GNU Oleo-regneark + GNU-Oleo-Tabelle + λογιστικό φÏλλο GNU Oleo + GNU Oleo spreadsheet + Kalkultabelo de GNU Oleo + hoja de cálculo de GNU Oleo + GNU Oleo kalkulu-orria + GNU Oleo -taulukko + GNU Oleo rokniark + feuille de calcul GNU Oleo + scarbhileog GNU Oleo + folla de cálculo de Oleo GNU + גליון × ×ª×•× ×™× ×©×œ GNU Oleo + GNU Oleo proraÄunska tablica + GNU Oleo-munkafüzet + Lembar sebar GNU Oleo + Foglio di calcolo GNU Oleo + GNU Oleo スプレッドシート + GNU Oleo ცხრილი + GNU Oleo Ñлектрондық кеÑтеÑÑ– + GNU Oleo 스프레드시트 + GNU Oleo skaiÄialentÄ— + GNU Oleo izklÄjlapa + Hamparan GNU Oleo + GNU Oleo regneark + GNU Oleo-rekenblad + GNU Oleo-rekneark + Arkusz GNU Oleo + folha de cálculo GNU Oleo + Planilha do GNU Oleo + Foaie de calcul GNU Oleo + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° GNU Oleo + ZoÅ¡it GNU Oleo + Preglednica GNU Oleo + Fletë llogaritje GNU Oleo + ГÐУ Oleo табеларни прорачун + GNU Oleo-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ GNU Oleo + Bảng tính Oleo của GNU + GNU Oleo 工作簿 + GNU Oleo 試算表 + + + + + + + + PAK archive + أرشي٠PAK + ArchiÅ­ PAK + Ðрхив — PAK + arxiu PAK + Archiv PAK + PAK-arkiv + PAK-Archiv + συμπιεσμένο αÏχείο PAK + PAK archive + PAK-arkivo + archivador PAK + PAK artxiboa + PAK-arkisto + PAK skjalasavn + archive PAK + cartlann PAK + arquivo PAK + ×רכיון PAK + PAK-archívum + Arsip PAK + Archivio PAK + PAK アーカイブ + PAK áƒáƒ áƒ¥áƒ˜áƒ•áƒ˜ + PAK архиві + PAK 압축 íŒŒì¼ + PAK archyvas + PAK arhÄ«vs + PAK-arkiv + PAK-archief + PAK-arkiv + Archiwum PAK + Pacote PAK + Arhivă PAK + архив PAK + Archív PAK + Datoteka arhiva PAK + Arkiv PAK + PAK-arkiv + PAK arÅŸivi + архів PAK + Kho nén PAK + AR 归档文件 + PAK å°å­˜æª” + + + + + + + + Palm OS database + قاعدة بيانات Palm OS + Palm OS mÉ™'lumat bazası + Baza źviestak Palm OS + База от данни — Palm OS + base de dades Palm OS + Databáze Palm OS + Cronfa Ddata Palm OS + Palm OS-database + Palm-OS-Datenbank + βάση δεδομένων Palm OS + Palm OS database + datumbazo de Palm OS + base de datos de Palm OS + Palm OS datu-basea + Palm OS -tietokanta + Palm OS dátustovnur + base de données Palm OS + bunachar sonraí Palm OS + base de datos de Palm OS + מסד × ×ª×•× ×™× ×©×œ Palm OS + Palm OS-adatbázis + Basis data Palm OS + Database Palm OS + Palm OS データベース + Palm OS дерекқоры + Palm OS ë°ì´í„°ë² ì´ìŠ¤ + Palm OS duomenų bazÄ— + Palm OS datubÄze + Pangkalandata PalmOS + Palm OS-database + Palm OS-gegevensbank + Palm OS-database + Baza danych Palm OS + base de dados do Palm OS + Banco de dados do Palm OS + Bază de date Palm OS + база данных Palm OS + Databáza Palm OS + Podatkovna zbirka Palm OS + Bankë me të dhëna Palm OS + Palm OS база података + Palm OS-databas + Palm OS veritabanı + база даних Palm OS + CÆ¡ sở dữ liệu PalmOS + Palm OS æ•°æ®åº“ + Palm OS 資料庫 + + + + + + + + Parchive archive + أرشي٠Parchive + ArchiÅ­ Parchive + Ðрхив — parchive + arxiu Parchive + Archiv Parchive + Parchive-arkiv + Parchive-Archiv + συμπιεσμένο αÏχείο Parchive + Parchive archive + archivador Parchive + Parchive artxiboa + Parchive-arkisto + Parchive skjalasavn + archive Parchive + cartlann Parchive + arquivo Parchive + ×רכיון של Parchive + Parchive archívum + Arsip Parchive + Archivio Parchive + Parchive アーカイブ + Parchive архиві + Parchive 압축 íŒŒì¼ + Parchive archyvas + Parchive arhÄ«vs + Parchive-arkiv + Parchive-archief + Parchive-arkiv + Archiwum parchive + Pacote Parchive + Arhivă Parchive + архив Parchive + Archív Parchive + Datoteka arhiva Parchive + Arkiv Parchive + Parchive-arkiv + Parchive arÅŸivi + архів Parchive + Kho nén Parchive + Parchive 归档文件 + Parchive å°å­˜æª” + Parchive + Parity Volume Set Archive + + + + + + + + + PEF executable + PEF تنÙيذي + Vykonvalny fajÅ‚ PEF + Изпълним файл — PEF + executable PEF + Spustitelný soubor PEF + PEF-kørbar + PEF-Programm + εκτελέσιμο PEF + PEF executable + PEF-plenumebla + ejecutable PEF + PEF exekutagarria + PEF-ohjelma + PEF inningarfør + exécutable PEF + comhad inrite PEF + Executábel PEF + קובץ הרצה PEF + PEF futtatható + PEF dapat dieksekusi + Eseguibile PEF + PEF 実行ファイル + PEF орындалатын файлы + PEF 실행 íŒŒì¼ + PEF vykdomasis failas + PEF izpildÄmais + Bolehlaksana PEF + PEF-kjørbar + PEF-uitvoerbaar bestand + Køyrbar PEF-fil + Program PEF + executável PEF + Executável PEF + Executabil PEF + иÑполнÑемый файл PEF + Spustiteľný súbor PEF + Izvedljiva datoteka PEF + E ekzekutueshme PEF + PEF извршна + Körbar PEF-fil + PEF çalıştırılabilir + виконуваний файл PEF + Tập tin thá»±c hiện được PEF + PEF å¯æ‰§è¡Œæ–‡ä»¶ + PEF å¯åŸ·è¡Œæª” + + + + + + + Perl script + سكربت بيرل + Skrypt Perl + Скрипт — Perl + script Perl + Skript v Perlu + Sgript Perl + Perlprogram + Perl-Skript + Ï€ÏόγÏαμμα εντολών Perl + Perl script + Perl-skripto + script en Perl + Perl script-a + Perl-komentotiedosto + Perl boðrøð + script Perl + script Perl + Script de Perl + תסריט מעטפת של Perl + Perl-parancsfájl + Skrip Perl + Script Perl + Perl スクリプト + Perl Ñценарийі + 펄 스í¬ë¦½íŠ¸ + Perl scenarijus + Perl skripts + Skrip Perl + Perl skript + Perl-script + Perl-skript + Skrypt Perl + 'script' Perl + Script Perl + Script Perl + Ñценарий Perl + Skript jazyka Perl + Skriptna datoteka Perl + Script Perl + Перл Ñкрипта + Perlskript + Perl betiÄŸi + Ñкрипт на Perl + Văn lệnh Perl + Perl 脚本 + Perl 指令稿 + + + + + + + + + + + + + + + + + + + + + + + + + + + + PHP script + سكربت PHP + PHP skripti + Skrypt PHP + Скрипт — PHP + script PHP + Skript PHP + Sgript PHP + PHP-program + PHP-Skript + Ï€ÏόγÏαμμα εντολών PHP + PHP script + PHP-skripto + script en PHP + PHP script-a + PHP-komentotiedosto + PHP boðrøð + script PHP + script PHP + Script de PHP + תסריט מעטפת של PHP + PHP-parancsfájl + Skrip PHP + Script PHP + PHP スクリプト + PHP Ñценарийі + PHP 스í¬ë¦½íŠ¸ + PHP scenarijus + PHP skripts + Skrip PHP + PHP-skript + PHP-script + PHP-skript + Skrypt PHP + 'script' PHP + Script PHP + Script PHP + Ñценарий PHP + Skript PHP + Skriptna datoteka PHP + Script PHP + PHP Ñкрипта + PHP-skript + PHP betiÄŸi + Ñкрипт PHP + Văn lệnh PHP + PHP 脚本 + PHP 指令稿 + + + + + + + + + + + + + PKCS#7 certificate bundle + رزمة الشهادة PKCS#7 + Сбор ÑÑŠÑ Ñертификати — PKCS#7 + conjunt de certificats PKCS#7 + Svazek certifikátů PKCS#7 + PKCS#7-certifikatbundt + PKCS#7-Zertifikatspaket + πακέτο ψηφιακών πιστοποιητικών PKCS#7 + PKCS#7 certificate bundle + lote de certificados PCKS#7 + PKCS#7 zertifikazio sorta + PKCS#7-varmennenippu + PKCS#7 váttanar bundi + lot de certificats PKCS#7 + cuach theastas PKCS#7 + paquete de certificado PKCS#7 + בקשה מוסמכת PKCS#7 + PKCS#7-tanúsítványcsomag + Bundel sertifikat PKCS#7 + Bundle certificato PKCS#7 + PKCS#7 証明書 + PKCS#7 Ñертификаттар деÑтеÑÑ– + PKCS#7 ì¸ì¦ì„œ ë¬¶ìŒ + PKCS#7 liudijimų ryÅ¡ulys + PKCS#7 sertifikÄtu saiÅ¡Ä·is + PKCS#7-certificaatbundel + Pakiet certyfikatu PKCS#7 + Pacote de certificados PKCS#7 + Pachet certificat PKCS#7 + пакет Ñертификатов PKCS#7 + Zväzok certifikátov PKCS#7 + Datoteka potrdila PKCS#7 + PKCS#7-certifikatsamling + комплект Ñертифікатів PKCS#7 + Bó chứng nhận PKCS#7 + PKCS#7 è¯ä¹¦æŸ + PKCS#7 憑證ç¶åŒ… + PKCS + Public-Key Cryptography Standards + + + + + PKCS#12 certificate bundle + رزمة الشهادة PKCS#12 + Viazka sertyfikataÅ­ PKCS#12 + Сбор ÑÑŠÑ Ñертификати — PKCS#12 + conjunt de certificats PKCS#12 + Svazek certifikátů PKCS#12 + PKCS#12-certifikatbundt + PKCS#12-Zertifikatspaket + πακέτο ψηφιακών πιστοποιητικών PKCS#12 + PKCS#12 certificate bundle + ligaĵo de PKCS#12-atestiloj + lote de certificados PCKS#12 + PKCS#12 zertifikazio sorta + PKCS#12-varmennenippu + PKCS#12 váttanar bundi + lot de certificats PKCS#12 + cuach theastas PKCS#12 + paquete de certificado PKCS#12 + בקשה מוסמכת PKCS#12 + PKCS#12-tanúsítványcsomag + Bundel sertifikat PKCS#12 + Bundle certificato PKCS#12 + PKCS#12 証明書 + PKCS#12 Ñертификаттар деÑтеÑÑ– + PKCS#12 ì¸ì¦ì„œ ë¬¶ìŒ + PKCS#12 liudijimų ryÅ¡ulys + PKCS#12 sertifikÄtu saiÅ¡Ä·is + Sijil PKCS#12 + PKCS#12 sertifikathaug + PKCS#12-certificaatbundel + PKCS#12-sertifikatbunt + Pakiet certyfikatu PKCS#12 + conjunto de certificados PKCS#12 + Pacote de certificados PKCS#12 + Certificat împachetat PKCS#12 + пакет Ñертификатов PKCS#12 + Zväzok certifikátov PKCS#12 + Datoteka potrdila PKCS#12 + Bundle çertifikate PKCS#12 + PKCS#12 пакет Ñертификата + PKCS#12-certifikatsamling + комплект Ñертифікатів PKCS#12 + Bó chứng nhận PKCS#12 + PKCS#12 è¯ä¹¦æŸ + PKCS#12 憑證檔 + PKCS + Public-Key Cryptography Standards + + + + + PlanPerfect spreadsheet + جدول PlanPerfect + Raźlikovy arkuÅ¡ PlanPerfect + Таблица — PlanPerfect + full de càlcul de PlanPerfect + SeÅ¡it PlanPerfect + PlanPerfect-regneark + PlanPerfect-Tabelle + φυÌλλο εÏγασιÌας PlanPerfect + PlanPerfect spreadsheet + hoja de cálculo de PlanPerfect + PlanPerfect kalkulu-orria + PlanPerfect-taulukko + PlanPerfect rokniark + feuille de calcul PlanPerfect + scarbhileog PlanPerfect + folla de cálculo de PlanPerfect + גליון × ×ª×•× ×™× ×©×œ PlanPerfect + PlanPerfect táblázat + Lembar sebar PlanPerfect + Foglio di calcolo PlanPerfect + PlanPerfect スプレッドシート + PlanPerfect Ñлектрондық кеÑтеÑÑ– + PlanPerfect 스프레드시트 + PlanPerfect skaiÄialentÄ— + PlanPerfect izklÄjlapa + PlanPerfect-regneark + PlanPerfect-rekenblad + PlanPerfect-rekneark + Arkusz PlanPerfect + Planilha do PlanPerfect + Foaie de calcul PlanPerfect + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° PlanPerfect + ZoÅ¡it PlanPerfect + Preglednica PlanPerfect + Fletë llogaritjesh PlanPerfect + PlanPerfect-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ PlanPerfect + Bảng tính PlanPerfect + PlanPerfect 工作簿 + PlanPerfect 試算表 + + + + + Pocket Word document + مستند Pocket Word + Документ — Pocket Word + document Pocket Word + Dokument Pocket Word + Pocket Word-dokument + Pocket-Word-Dokument + έγγÏαφο Pocket Word + Pocket Word document + documento de Pocket Word + Pocket Word dokumentua + Pocket Word -asiakirja + Pocket Word skjal + document Pocket Word + cáipéis Pocket Word + documento de Pocket Word + מסמך של Pocket Word + Pocket Word dokumentum + Dokumen Pocket Word + Documento Pocket Word + Pocket Word ドキュメント + Pocket Word құжаты + Pocket Word 문서 + Pocket Word dokumentas + Pocket Word dokuments + Pocket Word-document + Dokument Pocket Word + Documento do Pocket Word + Document Pocket Word + документ Pocket Word + Dokument Pocket Word + Dokument Pocket Word + Pocket Word-dokument + Pocket Word belgesi + документ Pocket Word + Tài liệu Pocket Word + Pocket Word 文档 + Pocket Word 文件 + + + + + + + + profiler results + نتائج المحلل + profiler nÉ™ticÉ™lÉ™ri + vyniki profilera + Резултати от анализатора + resultats del perfilador + Výsledky profiler + canlyniadau proffeilio + profileringsresultater + Profiler-Ergebnisse + αποτελέσματα μετÏήσεων για την εκτέλεση Ï€ÏογÏάμματος + profiler results + resultoj de profililo + resultados del perfilador + profiler-aren emaitzak + profilointitulokset + résultats de profileur + torthaí próifíleora + resultados do perfilador + תוצ×ות מ×בחן + profilírozó-eredmények + hasil profiler + Risultati profiler + プロファイラーçµæžœ + прифильдеу нәтижелері + 프로파ì¼ëŸ¬ ê²°ê³¼ + profiliklio rezultatai + profilÄ“tÄja rezultÄti + Hasil pemprofil + profileingsresultat + profiler-resultaten + profileringsresultat + Wyniki profilowania + resultados do 'profiler' + Resultados do profiler + rezultate profiler + результаты Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ + Výsledky profilera + rezultati profilirnika + Rezultate të profiluesit + резултати профилатора + profilerarresultat + результати Ð¿Ñ€Ð¾Ñ„Ñ–Ð»ÑŽÐ²Ð°Ð½Ð½Ñ + kết quả nét hiện trạng + profiler 结果 + 硬體資訊產生器æˆæžœ + + + + + + Pathetic Writer document + مستند Pathetic Writer + Dakument Pathetic Writer + Документ — Pathetic Writer + document de Pathetic Writer + Dokument Pathetic Writer + Pathetic Writer-dokument + Pathetic-Writer-Dokument + έγγÏαφο Pathetic Writer + Pathetic Writer document + dokumento de Pathetic Writer + documento de Pathetic Writer + Pathetic Writer dokumentua + Pathetic Writer -asiakirja + Pathetic Writer skjal + document Pathetic Writer + cáipéis Pathetic Writer + documento de Pathetic Writer + מסמך של Pathetic Writer + Pathetic Writer-dokumentum + Dokumen Pathetic Writer + Documento Pathetic Writer + Pathetic Writer ドキュメント + Pathetic Writer құжаты + Pathetic Writer 문서 + Pathetic Writer dokumentas + Pathetic Writer dokuments + Dokumen Pathetic Writer + Pathetic Writer-dokument + Pathetic Writer-document + Pathetic Writer-dokument + Dokument Pathetic Writer + documento do Pathetic Writer + Documento do Pathetic Writer + Document Pathetic Writer + документ Pathetic Writer + Dokument Pathetic Writer + Dokument Pathetic Writer + Dokument Pathetic Writer + Документ Патетичног пиÑца + Pathetic Writer-dokument + Pathetic Writer belgesi + документ Pathetic Writer + Tài liệu Pathetic Writer + Pathetic Writer 文档 + Pathetic Writer 文件 + + + + + Python bytecode + Python bytecode + Python bayt kodu + Bajtavy kod Python + Байт код — Python + bytecode de Python + Bajtový kód Python + Côd beit Python + Pythonbytekode + Python-Bytecode + συμβολοκώδικας Python + Python bytecode + Python-bajtkodo + bytecode Python + Python byte-kodea + Python-tavukoodi + Python býtkota + bytecode Python + beartchód Python + bytecode de Python + Bytecode של Python + Python-bájtkód + Kode bita Python + Bytecode Python + Python ãƒã‚¤ãƒˆã‚³ãƒ¼ãƒ‰ + Python байткоды + 파ì´ì¬ ë°”ì´íŠ¸ì½”ë“œ + Python baitinis kodas + Python bitkods + Kodbait Python + Python-bytekode + Python-bytecode + Python-bytekode + Kod bajtowy Python + código binário Python + Código compilado Python + Bytecode Python + байт-код Python + Bajtový kód Python + Datoteka bitne kode Python + Bytecode Python + Питонов бајт ко̂д + Python-bytekod + байт-код Python + Mã byte Python + Python å­—èŠ‚ç  + Python ä½å…ƒçµ„碼 + + + + + + + + QtiPlot document + + + + + + + + + + Quattro Pro spreadsheet + جدول Quattro Pro + Raźlikovy arkuÅ¡ Quattro Pro + Таблица — Quattro Pro + full de càlcul de Quattro Pro + SeÅ¡it Quattro Pro + Quattro Pro-regneark + Quattro-Pro-Tabelle + λογιστικό φÏλλο Quattro Pro + Quattro Pro spreadsheet + sterntabelo de Quattro Pro + hoja de cálculo Quattro Pro + Quattro Pro kalkulu-orria + Quattro Pro -taulukko + Quattro Pro rokniark + feuille de calcul Quattro Pro + scarbhileog Quattro Pro + folla de cálculo Quattro Pro + גליון × ×ª×•× ×™× ×©×œ Quattro Pro + Quattro Pro proraÄunska tablica + Quattro Pro-munkafüzet + Lembar sebar Quattro Pro + Foglio di calcolo Quattro Pro + Quattro Pro スプレッドシート + Quattro Pro Ñлектрондық кеÑтеÑÑ– + Quattro Pro 스프레드시트 + Quattro Pro skaiÄialentÄ— + Quattro Pro izklÄjlapa + Hamparan Quatro Pro + Quattro Pro-regneark + Quattro Pro-rekenblad + Quattro Pro-rekneark + Arkusz Quattro Pro + folha de cálculo Quattro Pro + Planilha do Quattro Pro + Foaie de calcul Quattro Pro + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° Quattro Pro + ZoÅ¡it Quattro Pro + Preglednica Quattro Pro + Fletë llogaritjesh Quattro Pro + Quattro Pro табеларни рачун + Quattro Pro-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Quattro Pro + Bảng tính Quattro Pro + Quattro Pro 工作簿 + Quattro Pro 試算表 + + + + + + + QuickTime metalink playlist + قائمة تشغيل QuickTime metalink + Å›pis metaspasyÅ‚ak na pieÅ›ni QuickTime + СпиÑък за изпълнение — QuickTime + llista de reproducció de metaenllaços QuickTime + Seznam skladeb metalink QuickTime + QuickTime metalink-afspilningsliste + QuickTime-Metalink-Wiedergabeliste + λίστα αναπαÏαγωγής metalinks QuickTime + QuickTime metalink playlist + lista de reproducción de metaenlaces QuickTime + QuickTime meta-esteken erreprodukzio-zerrenda + QuickTime metalink -soittolista + QuickTime metaleinkju avspælingarlisti + liste de lecture metalink QuickTime + seinmliosta meiteanasc QuickTime + lista de reprodución de metaligazóns QuickTime + רשימת השמעה מקושרת של QuickTime + QuickTime metalink lejátszólista + Senarai berkas taut meta QuickTime + Scaletta metalink QuickTime + QuickTime メタリンクå†ç”Ÿãƒªã‚¹ãƒˆ + QuickTime метаÑілтемелер ойнау тізімі + 퀵타임 메타ë§í¬ ìž¬ìƒ ëª©ë¡ + QuickTime metanuorodos grojaraÅ¡tis + QuickTime metasaites repertuÄrs + QuickTime metalink-spilleliste + QuickTime metalink-afspeellijst + QuickTime metalink-speleliste + Lista odtwarzania metaodnoÅ›ników QuickTime + Lista de reprodução metalink do QuickTime + Listă cu metalegături QuickTime + ÑпиÑок воÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¼ÐµÑ‚Ð°-ÑÑылок QuickTime + Zoznam skladieb metalink QuickTime + Seznam predvajanja QuickTime + Listë titujsh metalink QuickTime + QuickTime-metalänkspellista + ÑпиÑок Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ QuickTime metalink + Danh mục nhạc siêu liên kết Quicktime + QuickTime 元链接播放列表 + QuickTime metalink 播放清單 + + + + + + + + + + + + + + + Quicken document + مستند Quicken + Quicken sÉ™nÉ™di + Dakument Quicken + Документ — Quicken + document de Quicken + Dokument Quicken + Dogfen Quicken + Quickendokument + Quicken-Dokument + έγγÏαφο Quicken + Quicken document + Quicken-dokumento + documento de Quicken + Quicken dokumentua + Quicken-asiakirja + Quicken skjal + document Quicken + cáipéis Quicken + documento de Quicken + מסמך של Quicken + Quicken dokument + Quicken-dokumentum + Dokumen Quicken + Documento Quicken + Quicken ドキュメント + Quicken құжаты + Quicken 문서 + Quicken dokumentas + Quicken dokuments + Dokumen Quicken + Quicken-dokument + Quicken-document + Quicken-dokument + Dokument Quicken + documento Quicken + Documento do Quicken + Document Quicken + документ Quicken + Dokument Quicken + Dokument Quicken + Dokument Quicken + Quicken документ + Quicken-dokument + документ Quicken + Tài liệu Quicken + Quicken 文档 + Quicken 文件 + + + + + RAR archive + أرشي٠RAR + ArchiÅ­ RAR + Ðрхив — RAR + arxiu RAR + Archiv RAR + Archif RAR + RAR-arkiv + RAR-Archiv + αÏχείο RAR + RAR archive + RAR-arkivo + archivador RAR + RAR artxiboa + RAR-arkisto + RAR skjalasavn + archive RAR + cartlann RAR + ficheiro RAR + ×רכיון RAR + RAR arhiva + RAR-archívum + Arsip RAR + Archivio RAR + RAR アーカイブ + RAR архиві + RAR 압축 íŒŒì¼ + RAR archyvas + RAR arhÄ«vs + Arkib RAR + RAR-arkiv + RAR-archief + RAR-arkiv + Archiwum RAR + arquivo RAR + Pacote RAR + Arhivă RAR + архив RAR + Archív RAR + Datoteka arhiva RAR + Arkiv RAR + РÐР архива + RAR-arkiv + архів RAR + Kho nén RAR + RAR 归档文件 + RAR å°å­˜æª” + RAR + Roshal ARchive + + + + + + + + + DAR archive + أرشي٠DAR + ArchiÅ­ DAR + Ðрхив — DAR + arxiu DAR + Archiv DAR + DAR-arkiv + DAR-Archiv + συμπιεσμένο αÏχείο DAR + DAR archive + DAR-arkivo + archivador DAR + DAR artxiboa + DAR-arkisto + DAR skjalasavn + archive DAR + cartlann DAR + arquivo DAR + ×רכיון DAR + DAR arhiva + DAR archívum + Arsip DAR + Archivio DAR + DAR アーカイブ + DAR áƒáƒ áƒ¥áƒ˜áƒ•áƒ˜ + DAR архиві + DAR ë¬¶ìŒ íŒŒì¼ + DAR archyvas + DAR arhÄ«vs + DAR-arkiv + DAR-archief + DAR-arkiv + Archiwum DAR + Pacote DAR + Arhivă DAR + архив DAR + Archív DAR + Datoteka arhiva DAR + Arkiv DAR + DAR-arkiv + архів DAR + Kho nén DAR + DAR 归档文件 + DAR å°å­˜æª” + + + + + + + + Alzip archive + أرشي٠Alzip + ArchiÅ­ Alzip + Ðрхив — alzip + arxiu Alzip + Archiv Alzip + Alziparkiv + Alzip-Archiv + Alzip archive + Alzip-arkivo + archivador Alzip + Alzip artxiboa + Alzip-arkisto + Alsip skjalasavn + archive alzip + cartlann Alzip + arquivo Alzip + ×רכיון Alzip + Alzip arhiva + Alzip archívum + Arsip Alzip + Archivio Alzip + Alzip アーカイブ + Alzip áƒáƒ áƒ¥áƒ˜áƒ•áƒ˜ + Alzip архиві + 알집 압축 íŒŒì¼ + Alzip archyvas + Alzip arhÄ«vs + Alzip-arkiv + Alzip-archief + Alzip-arkiv + Archiwum alzip + Pacote Alzip + Arhivă Alzip + архив ALZIP + Archív Alzip + Datoteka arhiva Alzip + Arkiv Alzip + Alzip-arkiv + Alzip arÅŸivi + архів Alzip + Kho nén Alzip + Alzip 归档文件 + Alzip å°å­˜æª” + + + + + + + + rejected patch + رقعة مرÙوضة + niepryniaty patch + Отхвърлен файл Ñ ÐºÑ€ÑŠÐ¿ÐºÐ° + pedaç rebutjat + Odmítnutá záplata + afvist tekstlap + Abgelehnter Patch + μπάλωμα που αποÏÏίφθηκε + rejected patch + reĵeta flikaĵo + parche rechazado + baztertutako bide-izena + hylättyjen muutosten tiedosto + vrakað rætting + correctif rejeté + paiste diúltaithe + parche rexeitado + תל××™ שנדחה + odbijena zakrpa + visszautasított folt + patch ditolak + Patch rifiutata + æ‹’å¦ã•ã‚ŒãŸãƒ‘ッム+ алынбаған патч + ê±°ë¶€ëœ íŒ¨ì¹˜ íŒŒì¼ + atmestas lopas + noraidÄ«tais ceļš + Tampungan ditolak + avvist patchfil + verworpen patch + avvist programfiks + Odrzucona Å‚ata + ficheiro de patch rejeitado + Arquivo de patch rejeitado + petec respsins + отвергнутый патч + Odmietnutá záplata + zavrnjen popravek + Patch i kthyer mbrapsht + одбијена закрпа + avvisad programfix + відхилена латка + đắp vá bị từ chối + æ‹’ç»çš„è¡¥ä¸ + 回絕的修補 + + + + + + + RPM package + حزمة RPM + Pakunak RPM + Пакет — RPM + paquet RPM + BalíÄek RPM + RPM-pakke + RPM-Paket + πακέτο RPM + RPM package + RPM-pakaĵo + paquete RPM + RPM paketea + RPM-paketti + RPM pakki + paquet RPM + pacáiste RPM + paquete RFM + חבילת RPM + RPM paket + RPM-csomag + Paket RPM + Pacchetto RPM + RPM パッケージ + RPM деÑтеÑÑ– + RPM 패키지 + RPM paketas + RPM pakotne + Pakej RPM + RPM-pakke + RPM-pakket + RPM-pakke + Pakiet RPM + pacote RPM + Pacote RPM + Pachet RPM + пакет RPM + Balík RPM + Datoteka paketa RPM + Paketë RPM + RPM пакет + RPM-paket + пакунок RPM + Gói RPM + RPM 软件包 + RPM 套件 + + + + + + + + + Source RPM package + + + + + + + Ruby script + سكربت روبي + Skrypt Ruby + Скрипт — Ruby + script Ruby + Skript v Ruby + Rubyprogram + Ruby-Skript + Ï€ÏόγÏαμμα εντολών Ruby + Ruby script + Ruby-skripto + script en Ruby + Ruby script-a + Ruby-komentotiedosto + Ruby boðrøð + script Ruby + script Ruby + Script de Ruby + תסריט Ruby + Ruby skripta + Ruby-parancsfájl + Skrip Ruby + Script Ruby + Ruby スクリプト + Ruby Ñценарийі + 루비 스í¬ë¦½íŠ¸ + Ruby scenarijus + Ruby skripts + Skrip Ruby + Ruby-skript + Ruby-script + Ruby-skript + Skrypt Ruby + 'script' Ruby + Script Ruby + Script Ruby + Ñценарий Ruby + Skript Ruby + Skriptna datoteka Ruby + Script Ruby + Руби Ñкрипта + Ruby-skript + Ruby betiÄŸi + Ñкрипт Ruby + Văn lệnh Ruby + Ruby 脚本 + Ruby 指令稿 + + + + + + + + + + + Markaby script + سكربت Markaby + Skrypt Markaby + Скрипт — Markaby + script Markaby + Skript Markaby + Markabyprogram + Markaby-Skript + δέσμη εντολών Markaby + Markaby script + Markaby-skripto + script en Markaby + Markaby script-a + Markaby-komentotiedosto + Markaby boðrøð + script Markaby + script Markaby + Script de Markaby + תסריט Markby + Markaby skripta + Markaby parancsfájl + Skrip Markaby + Script Markaby + Markaby スクリプト + Markaby-ის სცენáƒáƒ áƒ˜ + Markaby Ñценарийі + Markaby 스í¬ë¦½íŠ¸ + Markaby scenarijus + Markaby skripts + Markaby-skript + Markaby-script + Markaby-skript + Skrypt Markaby + Script Markaby + Script Markaby + Ñценарий Markaby + Skript Markaby + Skriptna datoteka Markaby + Script Markaby + Markaby-skript + Markaby betiÄŸi + Ñкрипт Markaby + Văn lệnh Markaby + RMarkaby 脚本 + Markaby 指令稿 + + + + + + SC/Xspread spreadsheet + جدول SC/Xspread + Raźlikovy arkuÅ¡ SC/Xspread + Таблица — SC/Xspread + full de càlcul de SC/Xspread + SeÅ¡it SC/Xspread + SC/Xspread-regneark + SX/Xspread-Tabelle + φυÌλλο εÏγασιÌας SC/Xspread + SC/Xspread spreadsheet + SC/Xspread-kalkultabelo + hoja de cálculo SC/Xspread + SC/Xspread kalkulu-orria + SC/Xspread-taulukko + SC/Xspread rokniark + feuille de calcul SC/Xspread + scarbhileog SC/Xspread + folla de cálculo SC/Xspread + גליון נתונית של SC/Xspread + SC/Xspread proraÄunska tablica + SC/Xspread táblázat + Lembar sebar SC/Xspread + Foglio di calcolo SC/Xspread + SC/Xspread スプレッドシート + SC/Xspread Ñлектрондық кеÑтеÑÑ– + SC/Xspread 스프레드시트 + SC/Xspread skaiÄialentÄ— + SC/Xspread izklÄjlapa + SC/Xspread-regneark + SC/Xspread-rekenblad + SC/Xspread-rekneark + Arkusz SC/Xspread + Planilha do SC/Xspread + Foaie de calcul SC/Xspread + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° SC/Xspread + ZoÅ¡it SC/Xspread + Preglednica SC/Xspread + Fletë llogaritjesh SC/Xspread + SC/Xspread-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ SC/Xspread + Bảng tính SC/Xspread + SC/Xspread 工作簿 + SC/Xspread 試算表 + + + + + + + shell archive + أرشي٠شÙÙ„ + qabıq arxivi + archiÅ­ abaÅ‚onki + Ðрхив на обвивката + arxiu d'intèrpret d'ordres + Archiv shellu + archif plisgyn + skalarkiv + Shell-Archiv + αÏχείο Ï†Î»Î¿Î¹Î¿Ï (SHAR) + shell archive + Åel-arkivo + archivador shell + shell artxiboa + komentotulkkiarkisto + skel savn + archive shell + cartlann bhlaoisce + ficheiro shell + ×רכיון מעטפת + arhiva ljuske + héjarchívum + arsip shell + Archivio shell + シェルアーカイブ + қоршам архиві + ì…¸ 압축 íŒŒì¼ + shell archyvas + Äaulas arhÄ«vs + Arkib shell + skallarkiv + shell-archief + skal-arkiv + Archiwum powÅ‚oki + arquivo de consola + Pacote shell + arhivă shell + архив оболочки UNIX + Archív shellu + lupinski arhiv + Arkiv shell + Ðрхива љуÑке (SHAR) + skalarkiv + архів оболонки + kho trình bao + shell 归档文件 + shell å°å­˜æª” + + + + + libtool shared library + مكتبة libtool المشتركة + supolnaja biblijateka libtool + Споделена библиотека — libtool + biblioteca compartida libtool + Sdílená knihovna libtool + libtool delt bibliotek + Gemeinsame libtool-Bibliothek + κοινόχÏηστη βιβλιοθήκη libtool + libtool shared library + biblioteca compartida de libtool + libtool partekatutako liburutegia + jaettu libtool-kirjasto + libtool felagssavn + bibliothèque partagée libtool + comhleabharlann libtool + biblioteca compartida de libtool + ספריה משותפת של libtool + libtool dijeljena biblioteka + libtool osztott programkönyvtár + pustaka bersama libtool + Libreria condivisa libtool + libtool 共有ライブラリ + libtool ортақ жинағы + libtool 공유 ë¼ì´ë¸ŒëŸ¬ë¦¬ + libtool bendroji biblioteka + libtool koplietotÄ bibliotÄ“ka + libtool delt bibliotek + gedeelde libtool-bibliotheek + libtool delt bibliotek + Biblioteka współdzielona libtool + Biblioteca compartilhada libtool + bibliotecă partajată libtool + разделÑÐµÐ¼Ð°Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñ‚ÐµÐºÐ° libtool + Zdieľaná knižnica libtool + Souporabna knjižnica libtool + Librari e përbashkët libtool + delat libtool-bibliotek + Ñпільна бібліотека libtool + thÆ° viện dùng chung libtool + libtool 共享库 + libtool 共享函å¼åº« + + + + + + shared library + مكتبة مشتركة + bölüşülmüş kitabxana + supolnaja biblijateka + Споделена библиотека + biblioteca compartida + Sdílená knihovna + llyfrgell wedi ei rhannu + delt bibliotek + Gemeinsame Bibliothek + αÏχείο κοινόχÏηστης βιβλιοθήκης + shared library + dinamike bindebla biblioteko + biblioteca compartida + partekatutako liburutegia + jaettu kirjasto + felagssavn + bibliothèque partagée + comhleabharlann + biblioteca compartida + ספרייה משותפת + dijeljena biblioteka + osztott programkönyvtár + pustaka bersama + Libreria condivisa + 共有ライブラリ + бөліÑетін библиотека + 공유 ë¼ì´ë¸ŒëŸ¬ë¦¬ + bendroji biblioteka + koplietotÄ bibliotÄ“ka + Pustaka terkongsi + delt bibliotek + gedeelde bibliotheek + delt bibliotek + Biblioteka współdzielona + biblioteca partilhada + Biblioteca compartilhada + bibliotecă partajată + разделÑÐµÐ¼Ð°Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñ‚ÐµÐºÐ° + Zdieľaná knižnica + souporabljena knjižnica + Librari e përbashkët + дељена библиотека + delat bibliotek + Ñпільна бібліотека + thÆ° viện dùng chung + 共享库 + 共享函å¼åº« + + + + + + + + + + + + + + + + + + + + shell script + سكربت Ø´ÙÙ„ + qabıq skripti + skrypt abaÅ‚onki + Скрипт на обвивката + script d'intèrpret d'ordres + Skript shellu + sgript plisgyn + skalprogram + Shell-Skript + αÏχείο εντολών Ï†Î»Î¿Î¹Î¿Ï + shell script + Åelskripto + script en shell + shell script-a + komentotulkin komentotiedosto + skel boðrøð + script shell + script bhlaoisce + script de shell + תסריט מעטפת + skripta ljuske + héj-parancsfájl + skrip shell + Script shell + シェルスクリプト + қоршам Ñценарийі + ì…¸ 스í¬ë¦½íŠ¸ + shell scenarijus + Äaulas skripts + Skrip shell + skallskript + shellscript + skalskript + Skrypt powÅ‚oki + 'script' de consola + Script shell + script shell + Ñценарий оболочки UNIX + Skript shellu + lupinski skript + Script shell + Ñкрипта љуÑке + skalskript + Ñкрипт оболонки + văn lệnh trình bao + shell 脚本 + shell 指令稿 + + + + + + + + + + + + + + + + + + + + + Shockwave Flash file + مل٠Shockwave Flash + FajÅ‚ Shockwave Flash + Файл — Shockwave Flash + fitxer Shockwave Flash + Soubor Shockwave Flash + Shockwave Flash-fil + Shockwave-Flash-Datei + αÏχείο Shockwave Flash + Shockwave Flash file + dosiero de Shockwave Flash + archivo Shockwave Flash + Shockwave Flash fitxategia + Shockwave Flash -tiedosto + Shockwave Flash fíla + fichier Shockwave Flash + comhad Shockwave Flash + ficheiro sockwave Flash + קובץ של Shockwave Flash + Shockwave Flash datoteka + Shockwave Flash-fájl + Berkas Shockwave Flash + File Shockwave Flash + Shockwave Flash ファイル + Shockwave Flash файлы + Shockwave 플래시 íŒŒì¼ + Shockwave Flash failas + Shockwave Flash datne + Fail Shockwave Flash + Shockwave Flash-fil + Shockwave Flash-bestand + Shockwave Flash-fil + Plik Shockwave Flash + ficheiro Shockwave Flash + Arquivo Shockwave Flash + FiÈ™ier Shockwave Flash + файл Shockwave Flash + Súbor Shockwave Flash + Datoteka Shockwave Flash + File Flash Shockwave + Шоквејв Флеш датотека + Shockwave Flash-fil + файл Shockwave Flash + Tập tin Flash Shockwave + Shockwave Flash 文件 + Shockwave Flash 檔 + + + + + + + + + + + + + Shorten audio + Shorten سمعي + AÅ­dyjo Shorten + Ðудио — Shorten + àudio Shorten + Zvuk Shorten + Shortenlyd + Shorten-Audio + ήχος Shorten + Shorten audio + Shorten-sondosiero + sonido Shorten + Shorten audioa + Shorten-ääni + Shorten ljóður + audio Shorten + fuaim Shorten + son Shorten + שמע של Shorten + Shorten audio + Shorten hang + Audio Shorten + Audio Shorten + Shorten オーディオ + Shorten аудиоÑÑ‹ + Shorten 오디오 + Shorten garso įraÅ¡as + Shorten audio + Shorten lyd + Shorten-audio + Shorten-lyd + Plik dźwiÄ™kowy Shorten + Ãudio Shorten + Audio Shorten + аудио Shorten + Zvuk Shorten + ZvoÄna datoteka Shorten + Audio Shorten + Shorten-ljud + звук Shorten + Âm thanh Shorten + Shorten 音频 + Shorten 音訊 + + + + + + + + Siag spreadsheet + جدول Siag + Raźlikovy arkuÅ¡ Siag + Таблица — Siag + full de càlcul Siag + SeÅ¡it Siag + Siagregneark + Siag-Tabelle + λογιστικό φÏλλο Siag + Siag spreadsheet + Siag-kalkultabelo + hoja de cálculo de Siag + Siag kalkulu-orria + Siag-taulukko + Siag rokniark + feuille de calcul Siag + scarbhileog Siag + folla de cálculo de Siag + גליון × ×ª×•× ×™× ×©×œ Siag + Siag proraÄunska tablica + Siag-munkafüzet + Lembar sebar Siag + Foglio di calcolo Siag + Siag スプレッドシート + Siag Ñлектрондық кеÑтеÑÑ– + Siag 스프레드시트 + Siag skaiÄialentÄ— + Siag izklÄjlapa + Hamparan Siag + Siag-regneark + Siag-rekenblad + Siag-rekneark + Arkusz Siag + folha de cálculo Siag + Planilha do Siag + Foaie de calcul Siag + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° Siag + ZoÅ¡it Siag + Preglednica Siag + Fletë llogaritjesh Siag + Siag табеларни прорачун + Siag-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Siag + Bảng tính Slag + Siag 工作簿 + Siag 試算表 + + + + + Skencil document + مستند Skencil + Dakument Skencil + Документ — Skencil + document Skencil + Dokument Skencil + Skencildokument + Skencil-Dokument + έγγÏαφο Skencil + Skencil document + Skencil-dokumento + documento Skencil + Skencil dokumentua + Skencil-asiakirja + Skencil skjal + document Skencil + cáipéis Skencil + documento Skencil + מסמך Skencil + Skencil dokument + Skencil-dokumentum + Dokumen Skencil + Documento Skencil + Skencil ドキュメント + Skencil құжаты + Skencil 문서 + Skencil dokumentas + Skencil dokuments + Skencil-document + Skencil-dokument + Dokument Skencil + Documento do Skencil + Document Skencil + документ Skencil + Dokument Skencil + Dokument Skencil + Dokument Skencil + Skencil-dokument + Skencil belgesi + документ Skencil + Tài liệu Skencil + Skencil 文档 + Skencil 文件 + + + + + + + + Stampede package + حزمة Stampede + Stampede paketi + Pakunak Stampede + Пакет — Stampede + paquet Stampede + BalíÄek Stampede + Pecyn Stampede + Stampedepakke + Stampede-Paket + πακέτο Stampede + Stampede package + Stampede-pakaĵo + paquete Stampede + Stampede paketea + Stampede-paketti + Stampede pakki + paquet Stampede + pacáiste Stampede + paquete Stampede + חבילה של Stampede + Stampede paket + Stampede-csomag + Paket Stampede + Pacchetto Stampede + Stampede パッケージ + Stampede деÑтеÑÑ– + Stampete 패키지 + Stampede paketas + Stampede pakotne + Pakej Stampede + Stampede-pakke + Stampede-pakket + Stampede-pakke + Pakiet Stampede + pacote Stampede + Pacote Stampede + Pachet Stampede + пакет Stampede + BalíÄek Stampede + Datoteka paketa Stampede + Paketë Stampede + Stampede пакет + Stampede-paket + Stampede paketi + пакунок Stampede + Gói Stampede + Stampede 软件包 + Stampede 套件 + + + + Sega Master System/Game Gear ROM + ROM الخاص بدولاب لعبة/نظام سيجا ماستر + Sega Master System/Game Gear ROM + ROM — Sega Master System/Game Gear + ROM de Sega Master System/Game Gear + ROM pro Sega Master System/Game Gear + Sega Master System/Game Gear-rom + Sega-Master-System/Game-Gear-ROM + Εικόνα μνήμης ROM Sega Master System/Game Gear + Sega Master System/Game Gear ROM + ROM de Sega Master System/Game Gear + Sega Master System/Game Gear-eko ROMa + Sega Master System/Game Gear -ROM + Sega Master System/Game Gear ROM + ROM Sega Master System/Game Gear + ROM Sega Master System/Game Gear + ROM de Sega Master System/Game Gear + Sega Master System/Game Gear של ROM + Sega Master System/Game Gear ROM + Sega Master System/Game Gear ROM + Memori baca-saja Sega Master System/Game Gear + ROM Sega Master System/Game Gear + セガ マスターシステム/ゲームギア ROM + Sega Master System/Game Gear ROM + 세가 마스터 시스템/게임 기어 롬 + Sega Master System/Game Gear ROM + Sega Master System/Game Gear ROM + Sega Master System/Game Gear-ROM + Sega Master System/Game Gear-ROM + Sega Master System/Game Gear-ROM + Plik ROM konsoli SMS/Game Gear + ROM do Sega Master System/Game Gear + ROM Sega Master System/Game Gear + Sega Master System/Game Gear ROM + ROM pre Sega Master System/Game Gear + Bralni pomnilnik Sega Master System/Game Gear + ROM Sega Master System/Game Gear + Sega Master System/Game Gear-rom + ППП Sega Master System/Game Gear + ROM Sega Master System/Game Gear + Sega Master System/Game Gear ROM + Sega Master System/Game Gear ROM + + + + + + + Super NES ROM + Super NES ROM + Super Nintendo ROM + ROM — Super NES + ROM de Super NES + ROM pro Super Nintendo + Super NES-rom + Super-NES-ROM + εικοÌνα μνηÌημης ROM Super NES + Super NES ROM + ROM de Super NES + Super Nintendo-ko ROMa + Super Nintendo -ROM + Super NES ROM + ROM Super Nintendo + ROM Super NES + ROM de Super NES + ROM של Super NES + Super NES ROM + Super NES ROM + Memori baca-saja Super Nintendo + ROM Super Nintendo + スーパーファミコン ROM + Super NES ROM + ìˆ˜í¼ NES 롬 + Super NES ROM + Super NES ROM + Super Nintendo ROM + Super Nintendo + Super NES-ROM + Plik ROM konsoli SNES + ROM do Super Nintendo + ROM Super Nintendo + Super NES ROM + ROM pre Super Nintendo + Bralni pomnilnik Super NES + ROM Super NES + Super NES-rom + ППП Super NES + ROM Super Nintendo + Super NES ROM + 超級任天堂 ROM + + + + + + + StuffIt archive + أرشي٠StuffIt + ArchiÅ­ StuffIt + Ðрхив — StuffIt + arxiu StuffIt + Archiv StuffIt + StuffIt-arkiv + StuffIt-Archiv + συμπιεσμένο αÏχείο StuffIt + StuffIt archive + StuffIt-arkivo + archivador StuffIt + StuffIt artxiboa + StuffIt-arkisto + StuffIt skjalasavn + archive StuffIt + cartlann StuffIt + arquivo StuffIt + ×רכיון של S××•×›×›×Ÿ× + StuffIt arhiva + StuffIt-archívum + Arsip StuffIt + Archivio StuffIt + StuffIt アーカイブ + StuffIt архиві + StuffIt 압축 íŒŒì¼ + StuffIt archyvas + StuffIt arhÄ«vs + StuffIt arkiv + StuffIt-archief + StuffIt-arkiv + Archiwum StuffIt + Pacote StuffIt + Arhivă StuffIt + архив StuffIt + Archív StuffIt + Datoteka arhiva StuffIt + Arkiv StuffIt + StuffIt архива + StuffIt-arkiv + StuffIt arÅŸivi + архів StuffIt + Kho nén Stuffit + Macintosh StuffIt 归档文件 + StuffIt å°å­˜æª” + + + + + + + + + + + SubRip subtitles + ترجمات SubRip + Subtytry SubRip + Субтитри — SubRip + subtítols SubRip + Titulky SubRip + SubRip-undertekster + SubRip-Untertitel + υπότιτλοι SubRip + SubRip subtitles + SubRip-subtekstoj + subtítulos SubRip + SubRip azpitituluak + SubRip-tekstitykset + SubRip undirtekstir + sous-titres SubRip + fotheidil SubRip + subtítulos SubRip + כתוביות של SubRip + SubRip titlovi + SubRip feliratok + Subjudul SubRip + Sottotitoli SubRip + SubRip 字幕 + SubRip Ñубтитрлары + SubRip ìžë§‰ íŒŒì¼ + SubRip subtitrai + SubRip subtitri + SubRip undertekst + SubRip-ondertitels + SubRip-teksting + Napisy SubRip + Legendas SubRip + Subtitrare SubRip + Ñубтитры SubRip + Titulky SubRip + Datoteka podnapisov SubRip + Nëntituj SubRip + SubRip-undertexter + SubRip altyazıları + Ñубтитри SubRip + Phụ Ä‘á» SubRip + SubRip 字幕 + SubRip 字幕 + + + + + + + + + + + + WebVTT subtitles + Субтитри — WebVTT + subtítols WebVTT + Titulky WebVTT + WebVTT-undertekster + WebVTT-Untertitel + υπότιτλοι WebVTT + WebVTT subtitles + Subtítulos WebVTT + WebVTT-tekstitykset + sous-titres WebVTT + subtítulos WebVTT + כתוביות WebVTT + WebVTT titlovi + WebVTT feliratok + Subtitel WebVTT + Sottotitoli WebVTT + WebVTT サブタイトル + WebVTT ქვეტიტრები + WebVTT Ñубтитрлары + WebVTT ìžë§‰ + WebVTT subtitri + WebVTT ondertitels + Napisy WebVTT + Legendas WebVTT + Ñубтитры WebVTT + Podnapisi WebVTT + WebVTT-undertexter + Ñубтитри WebVTT + WebVTT 字幕 + WebVTT 字幕 + VTT + Video Text Tracks + + + + + + + + + SAMI subtitles + ترجمات SAMI + Subtytry SAMI + Субтитри — SAMI + subtítols SAMI + Titulky SAMI + SAMI-undertekster + SAMI-Untertitel + υπότιτλοι SAMI + SAMI subtitles + SAMI-subtekstoj + subtítulos SAMI + SAMI azpitituluak + SAMI-tekstitykset + SAMI undirtekstir + sous-titres SAMI + fotheidil SAMI + subtítulos SAMI + כתוביות SAMI + SAMI titlovi + SAMI feliratok + Subjudul SAMI + Sottotitoli SAMI + SAMI 字幕 + SAMI Ñубтитрлары + SAMI ìžë§‰ íŒŒì¼ + SAMI subtitrai + SAMI subtitri + SAMI undertekst + SAMI-ondertitels + SAMI teksting + Napisy SAMI + Legendas SAMI + Subtitrări SAMI + Ñубтитры SAMI + Titulky SAMI + Datoteka podnapisov SAMI + Nëntituj SAMI + SAMI-undertexter + SAMI altyazıları + Ñубтитри SAMI + Phụ Ä‘á» SAMI + SAMI 字幕 + SAMI 字幕 + SAMI + Synchronized Accessible Media Interchange + + + + + + + + + + MicroDVD subtitles + ترجمات MicroDVD + Subtytry MicroDVD + Субтитри — MicroDVD + subtítols MicroDVD + Titulky MicroDVD + MicroDVD-undertekster + MicroDVD-Untertitel + υπότιτλοι MicroDVD + MicroDVD subtitles + MicroDVD-subtekstoj + subtítulos MicroDVD + MicroDVD azpitituluak + MicroDVD-tekstitykset + MicroDVD undirtekstir + sous-titres MicroDVD + fotheidil MicroDVD + subtítulos de MicroDVD + כתוביות של MicroDVD + MicroDVD titlovi + MicroDVD feliratok + Subjudul MicroDVD + Sottotitoli MicroDVD + MicroDVD 字幕 + MicroDVD-ის ქვეტიტრები + MicroDVD Ñубтитрлары + MicroDVD ìžë§‰ íŒŒì¼ + MicroDVD subtitrai + MicroDVD subtitri + MicroDVD undertekst + MicroDVD-ondertitels + MicroDVD-teksting + Napisy MicroDVD + Legendas MicroDVD + Subtitrări MicroDVD + Ñубтитры MicroDVD + Titulky MicroDVD + Datoteka podnapisov MicroDVD + Nëntituj MicroDVD + MicroDVD-undertexter + MicroDVD altyazısı + Ñубтитри MicroDVD + Phụ Ä‘á» MicroDVD + MicroDVD 字幕 + MicroDVD 字幕 + + + + + + + + + + MPSub subtitles + ترجمات MPSub + Subtytry MPSub + Субтитри — MPSub + subtítols MPSub + Titulky MPSub + MPSub-undertekster + MPSub-Untertitel + υπότιτλοι MPSub + MPSub subtitles + MPSub-subtekstoj + subtítulos MPSub + MPSub azpitituluak + MPSub-tekstitykset + MPSub undirtekstir + sous-titres MPSub + fotheidil MPSub + subtítulos MPSub + כתוביות MPSub + MPSub titlovi + MPSub feliratok + Subjudul MPSub + Sottotitoli MPSub + MPSub サブタイトル + MPSub ქვეტიტრები + MPSub Ñубтитрлары + MPSub ìžë§‰ íŒŒì¼ + MPSub subtitrai + MPSub subtitri + MPSub undertekst + MPSub-ondertitels + MPSub-undertekstar + Napisy MPSub + Legendas MPSub + Subtitrări MPSub + Ñубтитры MPSub + Titulky MPSub + Datoteka podnapisov MPSub + Nëntituj MPSub + MPSub-undertexter + Ñубтитри MPSub + Phụ Ä‘á» MPSub + MPSub 字幕 + MPSub 字幕 + MPSub + MPlayer Subtitle + + + + + + + + SSA subtitles + ترجمات SSA + Subtytry SSA + Субтитри — SSA + subtítols SSA + Titulky SSA + SSA-undertekster + SSA-Untertitel + υπότιτλοι SSA + SSA subtitles + SSA-subtekstoj + subtítulos SSA + SSA azpitituluak + SSA-tekstitykset + SSA undirtekstir + sous-titres SSA + fotheidil SSA + Subtitulos SSA + כתובית SSA + SSA titlovi + SSA feliratok + Subjudul SSA + Sottotitoli SSA + SSA 字幕 + SSA Ñубтитрлары + SSA ìžë§‰ íŒŒì¼ + SSA subtitrai + SSA subtitri + SSA undertekst + SSA-ondertitels + SSA-teksting + Napisy SSA + Legendas SSA + Subtitrări SSA + Ñубтитры SSA + Titulky SSA + Datoteka podnapisov SSA + Nëntituj SSA + SSA-undertexter + SSA altyazıları + Ñубтитри SSA + Phụ Ä‘á» SSA + SSA 字幕 + SSA 字幕 + SSA + SubStation Alpha + + + + + + + + + + SubViewer subtitles + ترجمات SubViewer + Subtytry SubViewer + Субтитри — SubViewer + subtítols SubViewer + Titulky SubViewer + SubViewer-undertekster + SubViewer-Untertitel + υπότιτλοι SubViewer + SubViewer subtitles + SubViewer-subtekstoj + subtítulos SubViewer + SubViewer azpitituluak + SubViewer-tekstitykset + SubViewer undirtekstir + sous-titres SubViewer + fotheidil SubViewer + subtítulos SubViewer + כתוביות של SubViewe + SubViewer titlovi + SubViewer feliratok + Subjudul SubViewer + Sottotitoli SubViewer + SubViewer 字幕 + SubViewer Ñубтитрлары + SubViewer ìžë§‰ íŒŒì¼ + SubViewer subtitrai + SubViewer subtitri + SubViewer undertekst + SubViewer-ondertitels + SubViewer-teksting + Napisy SubViewer + Legendas SubViewer + Subtitrare SubViewer + Ñубтитры SubViewer + Titulky SubViewer + Datoteka podnapisov SubViewer + Nëntituj SubViewer + SubViewer-undertexter + Ñубтитри SubViewer + Phụ Ä‘á» SubViewer + SubViewer 字幕 + SubViewer 字幕 + + + + + + + + iMelody ringtone + نغمة iMelody + Rington iMelody + Ðудио — iMelody + to de trucada iMelody + VyzvánÄ›cí melodie iMelody + iMelody-ringetone + iMelody-Klingelton + ringtone iMelody + iMelody ringtone + tono de llamada iMelody + iMelody doinua + iMelody-soittoääni + iMelody ringitóni + sonnerie iMelody + ton buailte iMelody + Melodía de iMelody + רינגטון של iMelody + iMelody ton zvonjenja + iMelody csengÅ‘hang + nada dering iMelody + Suoneria iMelody + iMelody リングトーン + iMelody әуені + iMelody 벨소리 + iMelody skambuÄio melodija + iMelody melodija + iMelody ringetone + iMelody-beltoon + iMelody-ringetone + Dzwonek iMelody + Toque de celular do iMelody + Sonerie iMelody + Ð¼ÐµÐ»Ð¾Ð´Ð¸Ñ iMelody + Vyzváňacie melódie iMelody + Zvonjenje iMelody + Zile iMelody + iMelody-ringsignal + рінгтон iMelody + tiếng réo iMelody + iMelody 铃声 + iMelody éˆ´è² + + + + + + + + + + SMAF audio + SMAF سمعي + AÅ­dyjo SMAF + Ðудио — SMAF + àudio SMAF + Zvuk SMAF + SMAF-lyd + SMAF-Audio + ήχος SMAF + SMAF audio + SMAF-sondosiero + sonido SMAF + SMAF audioa + SMAF-ääni + SMAF ljóður + audio SMAF + fuaim SMAF + son SMAF + שמע SMAF + SMAF audio + SMAF hang + Audio SMAF + Audio SMAF + SMAF オーディオ + SMAF аудиоÑÑ‹ + SMAF 오디오 + SMAF garso įraÅ¡as + SMAF audio + SMAF-lyd + SMAF-audio + SMAF-lyd + Plik dźwiÄ™kowy SMAF + Ãudio SMAF + Audio SMAF + аудио SMAF + Zvuk SMAF + ZvoÄna datoteka SMAF + Audio SMAF + SMAF-ljud + звук SMAF + Âm thanh SMAF + SMAF 音频 + SMAF 音訊 + SMAF + Synthetic music Mobile Application Format + + + + + + + + + + MRML playlist + قائمة تشغيل MRML + Åšpis piesieÅ„ MRML + СпиÑък за изпълнение — MRML + llista de reproducció MRML + Seznam skladeb MRML + MRML-afspilningsliste + MRML-Wiedergabeliste + λίστα αναπαÏαγωγής MRML + MRML playlist + MRML-ludlisto + lista de reproducción MRML + MRML erreprodukzio-zerrenda + MRML-soittolista + MRML avspælingarlisti + liste de lecture MRML + seinmliosta MRML + lista de reprodución MRML + רשימת השמעה MRML + MRML popis za reprodukciju + MRML-lejátszólista + Senarai putar MRML + Scaletta MRML + MPML å†ç”Ÿãƒªã‚¹ãƒˆ + MRML რეპერტუáƒáƒ áƒ˜ + MRML ойнау тізімі + MRML ìž¬ìƒ ëª©ë¡ + MRML grojaraÅ¡tis + MRML repertuÄrs + MRML-spilleliste + MRML-afspeellijst + MRML-speleliste + Lista odtwarzania MRML + Lista de reprodução do MRML + Listă redare MRML + ÑпиÑок воÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ MRML + Zoznam skladieb MRML + Seznam predvajanja MRML + Listë titujsh MRML + MRML-spellista + ÑпиÑок Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ MRML + Danh mục nhạc MRML + MRML 播放列表 + MRML 播放清單 + MRML + Multimedia Retrieval Markup Language + + + + + + + + XMF audio + XMF سمعي + AÅ­dyjo XMF + Ðудио — XMF + àudio XMF + Zvuk XMF + XMF-lyd + XMF-Audio + ήχος XMF + XMF audio + XMF-sondosiero + sonido XMF + XMF audioa + XMF-ääni + XMF ljóður + audio XMF + fuaim XMF + son XMF + שמע XMF + XMF audio + XMF hang + Audio XMF + Audio XMF + XMF オーディオ + XMF аудиоÑÑ‹ + XMF 오디오 + XMF garso įraÅ¡as + XMF audio + XMF-lyd + XMF-audio + XMF-lyd + Plik dźwiÄ™kowy XMF + Ãudio XMF + Audio XMF + аудио XMF + Zvuk XMF + ZvoÄna datoteka XMF + Audio XMF + XMF-ljud + звук XMF + Âm thanh XMF + XMF 音频 + XMF 音訊 + XMF + eXtensible Music Format + + + + + + + + + + SV4 CPIO archive + أرشي٠SV4 CPIO + SV4 CPIO arxivi + ArchiÅ­ SV4 CPIO + Ðрхив — SV4 CPIO + arxiu CPIO SV4 + Archiv SV4 CPIO + Archif CPIO SV4 + SV4 CPIO-arkiv + SV4-CPIO-Archiv + αÏχείο SV4 CPIO + SV4 CPIO archive + SV4-CPIO-arkivo + archivador SV4 CPIO + SV4 CPIO artxiboa + SV4 CPIO -arkisto + SV4 CPIO skjalasavn + archive SV4 CPIO + cartlann SV4 CPIO + arquivo SV4 CPIO + ×רכיון של SV4 SPIO + SV4 CPIO arhiva + SV4 CPIO-archívum + Arsip SV4 CPIO + Archivio SV4 CPIO + SV4 CPIO アーカイブ + SV4 CPIO архиві + SV4 CPIO ë¬¶ìŒ íŒŒì¼ + SV4 CPIO archyvas + SV4 CPIO arhÄ«vs + Arkib CPIO SV4 + SV4 CPIO-arkiv + SV4 CPIO-archief + SV4 CPIO-arkiv + Archiwum SV4 CPIO + ficheiro SV4 CPIO + Pacote SV4 CPIO + Arhivă SV4 CPIO + архив SV4 CPIO + Archív SV4 CPIO + Datoteka arhiva SV4 CPIO + Arkiv SV4 CPIO + SV4 CPIO архива + SV4 CPIO-arkiv + SV4 CPIO arÅŸivi + архів SV4 CPIO + Kho nén CPIO SV4 + SV4 CPIO 归档文件 + SV4 CPIO å°å­˜æª” + + + + + SV4 CPIO archive (with CRC) + أرشي٠SV4 CPIO (مع CRC) + ArchiÅ­ SV4 CPIO (z CRC) + Ðрхив — SV4 CPIO, проверка за грешки CRC + arxiu CPIO SV4 (amb CRC) + Archiv SV4 CPIO (s CRC) + SV4 CPIO-arkiv (med CRC) + SV4-CPIO-Archiv (mit CRC) + αÏχείο SV4 CPIO (με CRC) + SV4 CPIO archive (with CRC) + SV4-CPIO-arkivo (kun CRC) + archivador SV4 CPIO (con CRC) + SV4 CPIO artxiboa (CRC-rekin) + SV4 CPIO -arkisto (CRC:llä) + SV4 CPIO skjalasavn (við CRC) + archive SV4 CPIO (avec CRC) + cartlann SV4 CPIO (le CRC) + Arquivador SV4 CPIO (con CRC) + ×רכיון של SV4 SPIO (×¢× CRC) + SV4 CPIO arhiva (s CRC-om) + SV4 CPIO-archívum (CRC-vel) + Arsip SV4 CPIO (dengan CRC) + Archivio SV4 CPIO (con CRC) + SV4 CPIO アーカイブ (CRC 有り) + SV4 CPIO архиві (CRC бар) + SV4 CPIO ë¬¶ìŒ íŒŒì¼ (CRC í¬í•¨) + SV4 CPII archyvas (su CRC) + SV4 CPIO arhÄ«vs (ar CRC) + Arkib CPIO SV4 (dengan CRC) + SV4 CPIO-arkiv (med CRC) + SV4 CPIO-archief (met CRC) + SV4 CPIO arkiv (med CRC) + Archiwum SV4 CPIO (z sumÄ… kontrolnÄ…) + Pacote SV4 CPIO (com CRC) + Arhivă SV4 CPIO (cu CRC) + архив SV4 CPIP (Ñ CRC) + Archív SV4 CPIO (s CRC) + Datoteka arhiva SV4 CPIO (z razprÅ¡ilom CRC) + Arkiv SV4 CPIO (me CRC) + SV4 CPIO-arkiv (med CRC) + SV4 CPIO arÅŸivi (CRC ile) + архів SV4 CPIO (з CRC) + Kho nén CPIO SV4 (vá»›i CRC) + SV4 CPIP 归档文件(带有 CRC) + SV4 CPIO å°å­˜æª” (具有 CRC) + + + + + Tar archive + أرشي٠Tar + Tar arxivi + ArchiÅ­ tar + Ðрхив — tar + arxiu tar + Archiv tar + Archif tar + Tar-arkiv + Tar-Archiv + συμπιεσμεÌνο αÏχειÌο Tar + Tar archive + archivador Tar + Tar artxiboa + Tar-arkisto + Tar skjalasavn + archive tar + cartlann Tar + arquivo Tar + ×רכיון Tar + Tar arhiva + Tar archívum + Arsip Tar + Archivio tar + Tar アーカイブ + Tar архиві + TAR ë¬¶ìŒ íŒŒì¼ + Tar archyvas + Tar arhÄ«vs + Arkib Tar + Tar-arkiv + Tar-archief + Tar-arkiv + Archiwum tar + Pacote tar + Arhivă Tar + архив TAR + Archív tar + Datoteka arhiva Tar + Arkiv tar + Тар архива + Tar-arkiv + архів tar + Kho nén tar + Tar 归档文件 + Tar å°å­˜æª” + + + + + + + + + + + + Tar archive (compressed) + أرشي٠Tar (مضغوط) + ArchiÅ­ tar (skampresavany) + Ðрхив — tar, компреÑиран + arxiu tar (comprimit) + Archiv tar (komprimovaný) + Tar-arkiv (komprimeret) + Tar-Archiv (komprimiert) + αÏχειÌο Tar (συμπιεσμεÌνο) + Tar archive (compressed) + archivador Tar (comprimido) + Tar artxiboa (konprimitua) + Tar-arkisto (pakattu) + Tar skjalasavn (stappað) + archive tar (compressée) + cartlann Tar (comhbhrúite) + arquivo Tar (comprimido) + ×רכיון Tar (מכווץ) + Tar arhiva (komprimirana) + Tar archívum (tömörített) + Arsip Tar (terkompresi) + Archivio tar (compresso) + Tar アーカイブ (compress 圧縮) + Tar архиві (Ñығылған) + TAR ë¬¶ìŒ íŒŒì¼ (압축) + Tar archyvas (suglaudintas) + Tar arhÄ«vs (saspiests) + Tar-arkiv (komprimert) + Tar-archief (ingepakt) + Tar-arkiv (pakka) + Archiwum tar (skompresowane) + Pacote tar (compactado) + Arhivă Tar (comprimată) + архив TAR (Ñжатый) + Archív tar (komprimovaný) + Datoteka arhiva Tar (stisnjen) + Arkiv tar (i kompresuar) + Tar-arkiv (komprimerat) + архів tar (ÑтиÑнений) + Kho nén tar (đã nén) + Tar 归档文件(压缩) + Tar å°å­˜æª” (UNIX æ ¼å¼å£“縮) + + + + + + + generic font file + مل٠الخط العام + zvyÄajny fajÅ‚ Å¡ryftu + Шрифт + fitxer genèric de tipus de lletra + Obecný soubor písma + general skrifttypefil + Allgemeine Schriftdatei + γενικό αÏχείο γÏαμματοσειÏάς + generic font file + genera tipara dosiero + tipografía genérico + letra-tipo orokorra + yleinen kirjasintiedosto + felagsstavasniðsfíla + fichier de polices générique + comhad cló ginearálta + ficheiro de tipo de fonte xenérica + קובץ גופן גנרי + općenita datoteka fonta + általános betűkészletfájl + berkas fonta generik + File tipo carattere generico + 一般フォントファイル + қаріп файлы + ì¼ë°˜ 글꼴 íŒŒì¼ + bendras Å¡rifto failas + vispÄrÄ“ja fonta datne + Fail font generik + vanlig skriftfil + algemeen lettertypebestand + vanleg skrifttypefil + ZwykÅ‚y plik czcionki + ficheiro genérico de tipo de letra + Arquivo de fonte genérico + fiÈ™ier de font generic + файл шрифта + ObyÄajný súbor písma + izvorna datoteka pisave + File lloj gërme i përgjithshëm + општа датотека фонта + allmän typsnittsfil + загальний файл шрифту + tập tin phông giống loài + 通用字体文件 + 通用字型檔 + + + + + packed font file + مل٠الخط المرزم + zapakavany fajÅ‚ Å¡ryftu + Шрифт — компреÑиран + fitxer empaquetat de tipus de lletra + Komprimovaný soubor písma + pakket skrifttypefil + Gepackte Schriftdatei + αÏχείο συμπιεσμένης γÏαμματοσειÏάς + packed font file + pakigita tipara dosiero + archivo de tipografía empaquetada + Letra-tipo fitxategi paketatua + pakattu kirjasintiedosto + pakkað stavasniðsfíla + fichier de polices empaquetées + comhad cló pacáilte + ficheiro de fonte empaquetada + קובץ גופן ×רוז + pakirana datoteka fonta + packed font-fájl + berkas fonta terkemas + File tipo carattere condensato + パックã•ã‚ŒãŸãƒ•ã‚©ãƒ³ãƒˆãƒ•ã‚¡ã‚¤ãƒ« + қаріп файлы (деÑтеленген) + 글꼴 ë¬¶ìŒ íŒŒì¼ + supakuotas Å¡rifto failas + sapakota fonta datne + Fail font dipek + pakket skriftfil + ingepakt lettertypebestand + pakka skrifttypefil + Plik ze spakowanÄ… czcionkÄ… + ficheiro de fontes empacotadas + Arquivo de fonte empacotado + fiÈ™ier font împachetat + Ñжатый файл шрифта + Komprimovaný súbor písma + pakirana datoteka pisave + File lloj gërmash i kondensuar + пакована датотека Ñа фонтом + packad typsnittsfil + запакований файл шрифту + tập tin phông chữ đã đóng gói + 打包的字体文件 + 包è£å­—型檔 + + + + + TGIF document + مستند TGIF + Dakument TGIF + Документ — TGIF + document TGIF + Dokument TGIF + TGIF-dokument + TGIF-Dokument + Σχέδιο TGIF + TGIF document + TGIF-dokumento + documento TGIF + TGIF dokumentua + TGIF-asiakirja + TGIF skjal + document TGIF + cáipéis TGIF + documento TGIF + מסמך TGIF + TGIF dokument + TGIF-dokumentum + Dokumen TGIF + Documento TGIF + TGIF ドキュメント + TGIF құжаты + TGIF 문서 + TGIF dokumentas + TGIF dokuments + Dokumen TGIF + TGIF-dokument + TGIF-document + TGIF-dokument + Dokument TGIF + documento TGIF + Documento TGIF + Document TGIF + документ TGIF + Dokument TGIF + Dokument TGIF + Dokument TGIF + TGIF документ + TGIF-dokument + документ TGIF + Tài liệu TGIF + TGIF 文档 + TGIF 文件 + + + + + + + + theme + سمة + örtük + matyÅ­ + Тема + tema + Motiv + thema + tema + Thema + Θέμα + theme + etoso + tema + gaia + teema + tema + thème + téama + tema + ערכת × ×•×©× + tema + téma + tema + Tema + テーマ + თემრ+ тема + 테마 + tema + motÄ«vs + Tema + tema + thema + drakt + Motyw + tema + Tema + temă + тема + Motív + tema + Temë + тема + tema + тема + sắc thái + 主题 + 佈景主題 + + + + + + ToutDoux document + مستند ToutDoux + ToutDoux sÉ™nÉ™di + Dakument ToutDoux + Документ — ToutDoux + document ToutDoux + Dokument ToutDoux + Dogfen ToutDoux + ToutDoux-dokument + ToutDoux-Dokument + έγγÏαφο ToutDoux + ToutDoux document + ToutDoux-dokumento + documento de ToutDoux + ToutDoux dokumentua + ToutDoux-asiakirja + ToutDoux skjal + document ToutDoux + cáipéis ToutDoux + documento de ToutDoux + משמך של ToutDoux + ToutDoux dokument + ToutDoux-dokumentum + Dokumen ToutDoux + Documento ToutDoux + ToutDoux ドキュメント + ToutDoux құжаты + ToutDoux 문서 + ToutDoux dokumentas + ToutDoux dokuments + Dokumen ToutDoux + ToutDoux-dokument + ToutDoux-document + ToutDoux-dokument + Dokument ToutDoux + documento ToutDoux + Documento do ToutDoux + Document ToutDoux + документ ToutDoux + Dokument ToutDoux + Dokument ToutDoux + Dokument ToutDoux + ToutDoux документ + ToutDoux-dokument + ToutDoux belgesi + документ ToutDoux + Tài liệu ToutDoux + ToutDoux 文档 + ToutDoux 文件 + + + + backup file + مل٠النسخ الاحتياطي + zapasny fajÅ‚ + Резервно копие + fitxer de còpia de seguretat + Záložní soubor + sikkerhedskopi + Sicherungsdatei + αντίγÏαφο ασφαλείας + backup file + restaÅ­rkopio + archivo de respaldo + babes-kopiako fitxategia + varmuuskopio + trygdarritsfíla + fichier de sauvegarde + comhad cúltaca + ficheiro de copia de seguridade + קובץ גיבוי + biztonsági mentés + berkas cadangan + File di backup + ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ファイル + резервті көшірмеÑÑ– + 백업 íŒŒì¼ + atsarginis failas + dublÄ“juma datne + Fail backup + sikkerhetskopi + reservekopiebestand + tryggleikskopi + Plik zapasowy + cópia de segurança + Arquivo de backup + fiÈ™ier de backup + Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ + Záložný súbor + varnostna kopija datoteke + File backup + резервна копија + säkerhetskopia + yedek dosyası + резервна ÐºÐ¾Ð¿Ñ–Ñ + tập tin sao lÆ°u + 备份文件 + 備份檔 + + + + + + + + Troff document + مستند Troff + Troff sÉ™nÉ™di + Dakument Troff + Документ — Troff + document Troff + Dokument troff + Dogfen troff + Troffdokument + Troff-Dokument + έγγÏαφο troff + Troff document + Troff-dokumento + documento troff + Troff dokumentua + Troff-asiakirja + Troff skjal + document Troff + cáipéis Troff + documento Troff + מסמך Troff + Troff dokument + Troff-dokumentum + Dokumen Troff + Documento Troff + Troff 入力ドキュメント + Troff құжаты + Troff 문서 + Troff dokumentas + Troff dokuments + Dokumen Troff + Troff-dokument + Troff-document + Troff-dokument + Dokument Troff + documento Troff + Documento troff + Document Troff + документ Troff + Dokument troff + Dokument Troff + Dokument Troff + Troff документ + Troff-dokument + Troff belgesi + документ Troff + Tài liệu Troff + Troff 文档 + Troff 文件 + + + + + + + + + + + + + + + Troff document (with manpage macros) + مستند Troff (مع اختصارات صÙحة المساعدة) + Dakument Troff (z makrasam man-staronak) + Документ — Troff, Ñ Ð¼Ð°ÐºÑ€Ð¾Ñи за Ñправочни Ñтраници + document Troff (amb macros de pàgines de manual) + Dokument troff (s makry pro manuálové stránky) + Troffdokument (med manualsidemakroer) + Troff-Dokument (mit man-Seitenmakros) + έγγÏαφο troff (με μακÏοεντολές manpage) + Troff document (with manpage macros) + Troff-dokumento (kun manpaÄaj makrooj) + documento troff (con macros de páginas de manual) + Troff dokumentua (manpage makroekin) + Troff-asiakirja (man-sivu-makroilla) + Troff skjal (við manpage fjølvi) + document Troff (avec macros manpage) + cáipéis Troff (le macraí manpage) + documento Troff (con macros de páxinas de manual) + מסמך של Troff (×¢× ×ž×קרו בmanpage) + Troff dokument (s makro naredbama priruÄnika) + Troff-dokumentum (manpage-makrókkal) + Dokumen Troff (dengan makro halaman manual) + Documento Troff (con macro per manpage) + Troff 入力ドキュメント (man ページマクロ有り) + Troff құжаты (әдіÑтемелік парақтар макроÑтарымен) + Troff 문서 (man 페ì´ì§€ 매í¬ë¡œ í¬í•¨) + Troff dokumentas (su žin. puslapių makrokomandomis) + Troff dokuments (ar manpage makrosiem) + Dokumen Troff (dengan macros halaman man) + Troff-dokument (med manualsidemakroer) + Troff-document (met man-macro's) + Troff-dokument med manualside-makroar + Dokument Troff (z makrami stron pomocy) + documento Troff (com macros manpage) + Documento troff (com macros de páginas de manual) + Document Troff (cu macro-uri manpage) + документ Troff (Ñ Ð¼Ð°ÐºÑ€Ð¾Ñами Ñтраниц руководÑтва) + Dokument troff (s makrami pre manuálové stránky) + Dokument Troff (z makroji manpage) + Dokumet Troff (me makro për manpage) + Troff документ (Ñа макроима за ман Ñтранице) + Troff-dokument (med manualsidemakron) + документ Troff (з макроÑами manpage) + Tài liệu Troff (có vÄ© lệnh trang hÆ°á»›ng dẫn) + Troff 文档(带 Man 手册å®) + Troff 文件 (å«æœ‰æ‰‹å†Šé é¢å·¨é›†) + + + + + + manual page (compressed) + صÙحة المساعدة (مضغوطة) + man sÉ™hifÉ™si (sıxışdırılmış) + staronka dapamohi (skampresavanaja) + Страница от Ñправочника, компреÑирана + pàgina de manual (comprimida) + Manuálová stránka (komprimovaná) + tudalen llawlyfr (wedi ei gywasgu) + manualside (komprimeret) + Handbuchseite (komprimiert) + σελίδα οδηγιών (συμπιεσμένη) + manual page (compressed) + manpaÄo (kunpremita) + página de manual (comprimida) + eskuliburu orria (konprimitua) + manuaalisivu (pakattu) + handbókasíða (stappað) + page de manuel (compressée) + leathanach lámhleabhair (comhbhrúite) + páxina de manual (comprimida) + דף עזר (מכווץ) + stranica priruÄnika (komprimirana) + kézikönyvoldal (tömörített) + halaman manual (terkompresi) + Pagina di manuale (compressa) + (圧縮) man ページ + әдіÑтемелік парағы (Ñығылған) + man 페ì´ì§€ (압축) + žinyno puslapis (suglaudintas) + rokasgrÄmatas lapa (saspiesta) + Halaman manual (termampat) + manualside (komprimert) + handleidingspagina (ingepakt) + manualside (pakka) + Strona podrÄ™cznika (skompresowana) + página de manual (comprimida) + Página de manual (compactada) + pagină de manual (comprimată) + Ñтраница руководÑтва (ÑжатаÑ) + Manuálová stránka (komprimovaná) + stran priroÄnika (stisnjena) + Faqe manuali (e kompresuar) + Ñтрана упутÑтва (компреÑована) + manualsida (komprimerad) + Ñторінка поÑібника (ÑтиÑнена) + trang hÆ°á»›ng dẫn (đã nén) + 手册页 (压缩) + 手冊é é¢ (壓縮版) + + + + Tar archive (LZO-compressed) + أرشي٠Tar (مضغوط-LZO) + ArchiÅ­ tar (LZO-skampresavany) + Ðрхив — tar, компреÑиран Ñ LZO + arxiu tar (comprimit amb LZO) + Archiv tar (komprimovaný pomocí LZO) + Tar-arkiv (LZO-komprimeret) + Tar-Archiv (LZO-komprimiert) + αÏχειÌο Tar (συμπιεσμεÌνο με LZO) + Tar archive (LZO-compressed) + archivador Tar (comprimido con LZO) + Tar artxiboa (LZO-rekin konprimitua) + Tar-arkisto (LZO-pakattu) + Tar skjalasavn (LZO-stappað) + archive tar (compression LZO) + cartlann Tar (comhbhrúite le LZO) + arquivo Tar (comprimido con LZO) + ×רכיון Tar (מכווץ ×¢"×™ LZO) + Tar arhiva (komprimirana LZO-om) + Tar archívum (LZO-val tömörítve) + Arsip Tar (terkompresi LZO) + Archivio tar (compresso con LZO) + Tar アーカイブ (LZO 圧縮) + Tar архиві (LZO-мен Ñығылған) + TAR ë¬¶ìŒ íŒŒì¼ (LZO 압축) + Tar archyvas (suglaudintas su LZO) + Tar arhÄ«vs (saspiests ar LZO) + Tar-arkiv (LZO-komprimert) + Tar-archief (ingepakt met LZO) + Tar-arkiv (pakka med LZO) + Archiwum tar (kompresja LZO) + Pacote tar (compactado com LZO) + Arhivă Tar (comprimată LZO) + архив TAR (Ñжатый LZO) + Archív tar (komprimovaný pomocou LZO) + Datoteka arhiva Tar (stisnjen z LZO) + Arkiv tar (i kompresuar me LZO) + Tar-arkiv (LZO-komprimerat) + архів tar (ÑтиÑнений LZO) + Kho nén tar (đã nén LZO) + Tar 归档文件(LZO 压缩) + Tar å°å­˜æª” (LZO æ ¼å¼å£“縮) + + + + + + + XZ archive + أرشي٠XZ + Ðрхив — XZ + arxiu XZ + Archiv XZ + XZ-arkiv + XZ-Archiv + συμπιεσμένο αÏχείο XZ + XZ archive + XZ-arkivo + archivador XZ + XZ artxiboa + XZ-arkisto + XZ skjalasavn + archive XZ + cartlann XZ + ficheiro XZ + ×רכיון XZ + XZ-archívum + Arsip XZ + Archivio XZ + XZ アーカイブ + XZ архиві + XZ 압축 íŒŒì¼ + XZ archyvas + XZ arhÄ«vs + XZ archief + Archiwum XZ + Pacote XZ + Arhivă XZ + архив XZ + Archív XZ + Datoteka arhiva XZ + XZ-arkiv + XZ arÅŸivi + архів XZ + XZ 归档文件 + XZ å°å­˜æª” + + + + + + + + Tar archive (XZ-compressed) + أرشي٠Tar (مضغوط-XZ) + Ðрхив — tar, компреÑиран Ñ XZ + arxiu tar (comprimit amb XZ) + Archiv tar (komprimovaný pomocí XZ) + Tar-arkiv (XZ-komprimeret) + Tar-Archiv (XZ-komprimiert) + αÏχειÌο Tar (συμπιεσμεÌνο με XZ) + Tar archive (XZ-compressed) + archivador Tar (comprimido con XZ) + Tar artxiboa (XZ-rekin konprimitua) + Tar-arkisto (XZ-pakattu) + Tar skjalasavn(XZ-stappað) + archive tar (compression XZ) + cartlann Tar (comhbhrúite le XZ) + arquivo Tar (comprimido con XZ) + ×רכיון Tar (מכווץ ×¢"×™ XZ) + Tar arhiva (komprimirana XZ-om) + Tar archívum (XZ-vel tömörítve) + Arsip Tar (terkompresi XZ) + Archivio tar (compresso con XZ) + Tar アーカイブ (XZ 圧縮) + Tar архиві (XZ-мен Ñығылған) + TAR ë¬¶ìŒ íŒŒì¼ (XZ 압축) + Tar archyvas (suglaudintas su XZ) + Tar arhÄ«vs (saspiests ar XZ) + Tar archief (XZ-compressed) + Archiwum tar (kompresja XZ) + Pacote tar (compactado com XZ) + Arhivă Tar (comprimată XZ) + архив TAR (Ñжатый XZ) + Archív tar (komprimovaný pomocou XZ) + Datoteka arhiva Tar (stisnjen z XZ) + Tar-arkiv (XZ-komprimerat) + архів tar (ÑтиÑнений XZ) + Tar 归档文件(XZ 压缩) + Tar å°å­˜æª” (XZ æ ¼å¼å£“縮) + + + + + + + PDF document (XZ-compressed) + Документ — PDF, компреÑиран Ñ XZ + document PDF (comprimit amb XZ) + Dokument PDF (komprimovaný pomocí XZ) + PDF-dokument (XZ-komprimeret) + PDF-Dokument (XZ-komprimiert) + έγγÏαφο PDF (συμπιεσμένο με XZ) + PDF document (XZ-compressed) + Documento PDF (comprimido en XZ) + PDF-asiakirja (XZ-pakattu) + document PDF (compressé XZ) + documento PDF (comprimido en XZ) + מסמך PDF (בדחיסת XZ) + PDF dokument (komprimiran XZ-om) + PDF dokumentum (XZ-vel tömörített) + Dokumen PDF (terkompresi XZ) + Documento PDF (compresso con XZ) + PDF 文書(XZ 圧縮) + PDF დáƒáƒ™áƒ£áƒ›áƒ”ნტი (XZ-ით შეკუმშული) + PDF құжаты (XZ-мен Ñығылған) + PDF 문서 (XZ 압축) + PDF dokuments (saspiests ar XZ) + PDF document (XZ-compressed) + Dokument PDF (kompresja XZ) + Documento PDF (compactado com XZ) + документ PDF (Ñжатый XZ) + Dokument PDF (XZ-stisnjen) + PDF-dokument (XZ-komprimerad) + документ PDF (ÑтиÑнений xz) + PDF 文档(XZ) + PDF 文件 (XZ æ ¼å¼å£“縮) + + + + + + Ustar archive + أرشي٠Ustar + ArchiÅ­ ustar + Ðрхив — ustar + arxiu ustar + Archiv ustar + Ustararkiv + Ustar-Archiv + συμπιεσμένο αÏχείο Ustar + Ustar archive + Ustar-arkivo + archivador Ustar + Ustar artxiboa + Ustar-arkisto + Ustar skjalasavn + archive Ustar + cartlann Ustar + arquivo Ustar + ×רכיון Ustar + Ustar arhiva + Ustar archívum + Arsip Ustar + Archivio ustar + Ustar アーカイブ + Ustar архиві + Ustar 압축 íŒŒì¼ + Ustar archyvas + Ustar arhÄ«vs + Ustar-arkiv + Ustar-archief + Ustar-arkiv + Archiwum ustar + Pacote Ustar + Arhivă Ustar + архив Ustar + Archív ustar + Datoteka arhiva Ustar + Arkiv Ustar + Ustar-arkiv + Ustar arÅŸivi + архів ustar + Kho nén ustar + Ustar 归档文件 + Ustar å°å­˜æª” + + + + + WAIS source code + Ø´Ùرة مصدر WAIS + WAIS mÉ™nbÉ™ faylı + KryniÄny kod WAIS + Изходен код — WAIS + codi font en WAIS + Zdrojový kód WAIS + Ffynhonnell Rhaglen WAIS + WAIS-kildekode + WAIS-Quelltext + πηγαίος κώδικας WAIS + WAIS source code + WAIS-fontkodo + código fuente WAIS + WAIS iturburu-kodea + WAIS-lähdekoodi + WAIS keldukota + code source WAIS + cód foinseach WAIS + código fonte WAIS + קוד מקור של WAIS + WAIS izvorni kod + WAIS-forráskód + Kode program WAIS + Codice sorgente WAIS + WAIS ソースコード + WAIS баÑтапқы коды + WAIS 소스 코드 + WAIS pradinis kodas + WAIS pirmkods + Kod sumber WAIS + WAIS-kildekode + WAIS-broncode + WAIS-kjeldekode + Plik źródÅ‚owy WAIS + código fonte WAIS + Código-fonte WAIS + Cod sursă WAIS + иÑходный код WAIS + Zdrojový kód WAIS + Datoteka izvorne kode WAIS + Kod burues WAIS + WAIS изворни ко̂д + WAIS-källkod + WAIS kaynak kodu + вихідний код мовою WAIS + Mã nguồn WAIS + WAIS æºä»£ç  + WAIS æºç¢¼ + + + + + WordPerfect/Drawperfect image + صورة WordPerfect/Drawperfect + Vyjava WordPerfect/Drawperfect + Изображение — WordPerfect/Drawperfect + imatge de WordPerfect/Drawperfect + Obrázek WordPerfect/Drawperfect + WordPerfect/Drawperfect-billede + WordPerfect/DrawPerfect-Bild + εικόνα WordPerfect/Drawperfect + WordPerfect/Drawperfect image + WordPerfect/Drawperfect-bildo + imagen de WordPerfect/Drawperfect + WordPerfect/Drawperfect irudia + WordPerfect/Drawperfect-kuva + WordPerfect/Drawperfect mynd + image WordPerfect/DrawPerfect + íomhá WordPerfect/Drawperfect + imaxe de WordPerfect/DrawPerfect + תמונה של WordPerfect/Drawperfect + WordPerfect/Drawperfect slika + WordPerfect/Drawperfect-kép + Gambar WordPerfect/Drawperfect + Immagine WordPerfect/Drawperfect + WordPerfect/Drawperfect ç”»åƒ + WordPerfect/Drawperfect Ñуреті + 워드í¼íŽ™íŠ¸/드로í¼íŽ™íŠ¸ 그림 + WordPerfect/Drawperfect paveikslÄ—lis + WordPerfect/Drawperfect attÄ“ls + Imej WordPerfect/Drawperfect + WordPerfect-/Drawperfect-bilde + WordPerfect/Drawperfect-afbeelding + WordPerfect/DrawPerfect-bilete + Obraz WordPerfect/DrawPerfect + imagem do WordPerfect/Drawperfect + Imagem do WordPerfect/Drawperfect + Imagine WordPerfect/Drawperfect + изображение WordPerfect/Drawperfect + Obrázok WordPerfect/Drawperfect + Slikovna datoteka Drawperfect + Figurë WordPerfect/Drawperfect + WordPerfect/Drawperfect Ñлика + WordPerfect/Drawperfect-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ WordPerfect/Drawperfect + Ảnh WordPerfect/Drawperfect + WordPerfect/Drawperfect å›¾åƒ + WordPerfect/Drawperfect å½±åƒ + + + + + DER/PEM/Netscape-encoded X.509 certificate + شهادة DER/PEM/Netscape-encoded X.509 + Sertyfikat X.509, zakadavany Å­ DER/PEM/Netscape + Сертификат — DER/PEM/Netscape X.509 + certificat X.509 codificat com DER/PEM/Netscape + Certifikát X.509 kódovaný jako DER/PEM/Netscape + DER-/PEM-/Netscapekodet X.509-certifikat + DER/PEM/Netscape-kodiertes X.509-Zertifikat + ψηφιακό πιστοποιητικό X.509 κωδικοποιημένο κατά DER/PEM/Netscape + DER/PEM/Netscape-encoded X.509 certificate + DER/PEM/Netscape-kodigita X.509-atestilo + certificado X.509 codificado con DER/PEM/Netscape + X.509rekin kodetutako DER, PEM edo Netscape zertifikatua + DER/PEM/Netscape-koodattu X.509-varmenne + DER/PEM/Netscape-encoded X.509 váttan + certificat X.509 codé DER/PEM/Netscape + teastas X.509 ionchódaithe le DER/PEM/Netscape + certificado X.509 codificado con DER/PEM/Netscape + ×ישור מסוג X.509 של DER/PEM/Netscape-encoded + DER/PEM/Netscape-kodiran X.509 certifikat + DER/PEM/Netscape formátumú X.509-tanúsítvány + Sertifikat DER/PEM/Netscape-tersandi X.509 + Certificato DER/PEM/Netscape-encoded X.509 + DER/PEM/Netscape エンコード X.509 証明書 + DER/PEM/Netscape კáƒáƒ“ირებული X.509 სერტიფიკáƒáƒ¢áƒ˜ + X.509 Ñертификаты (DER/PEM/Netscape кодталған) + DER/PEM/넷스케ì´í”„ë¡œ ì¸ì½”ë”©ëœ X.509 ì¸ì¦ì„œ + DER/PEM/Netscape-encoded X.509 liudijimas + DER/PEM/Netscape-encoded X.509 sertifikÄts + Sijil X.509 dienkod /DER/PEM/Netscape + DER/PEM/Netscape-kodet X.509-sertifikat + DER/PEM/Netscape-gecodeerd X.509-certificaat + DER/PEM/Netscape-koda X.509-sertifikat + Zakodowany w DER/PEM/Netscape certyfikat X.509 + certificado X.509 codificado com DER/PEM/Netscape + Certificado X.509 codificado com DER/PEM/Netscape + Certificat DER/PEM/Netscape-codat X.509 + Ñертификат X.509 (DER/PEM/Netscape-закодированный) + Certifikát X.509 kódovaný ako DER/PEM/Netscape + Datoteka potrdila DER/PEM/Netscape X.509 + Çertifikatë DER/PEM/Netscape-encoded X.509 + DER, PEM или ÐетÑкејп кодирани Ñертификат X.509 + DER/PEM/Netscape-kodat X.509-certifikat + Ñертифікат X.509 у форматі DER/PEM/Netscape + Chứng nhận X.509 mã hoá bằng Netscape/PEM/DER + DER/PEM/Netscape-encoded X.509 è¯ä¹¦ + DER/PEM/Netscape 編碼的 X.509 憑證 + + + + + + + + empty document + مستند Ùارغ + pusty dakument + Празен документ + document buit + Prázdný dokument + tomt dokument + Leeres Dokument + κενό έγγÏαφο + empty document + malplena dokumento + documento vacío + dokumentu hutsa + tyhjä asiakirja + tómt skjal + document vide + cáipéis fholamh + documeto baleiro + מסמך ריק + prazan dokument + üres dokumentum + dokumen kosong + Documento vuoto + 空ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆ + Ð±Ð¾Ñ Ò›Ò±Ð¶Ð°Ñ‚ + 빈 문서 + tuÅ¡Äias dokumentas + tukÅ¡s dokuments + Dokumen kosong + tomt dokument + leeg document + tomt dokument + Pusty dokument + documento vazio + Documento vazio + document gol + пуÑтой документ + Prázdny dokument + prazen dokument + Dokument bosh + празан документ + tomt dokument + boÅŸ belge + порожній документ + tài liệu rá»—ng + 空文档 + 空白文件 + + + Zoo archive + أرشي٠Zoo + Zoo arxivi + ArchiÅ­ zoo + Ðрхив — zoo + arxiu zoo + Archiv zoo + Archif zoo + Zooarkiv + Zoo-Archiv + συμπιεσμένο αÏχείο Zoo + Zoo archive + Zoo-arkivo + archivador Zoo + Zoo artxiboa + Zoo-arkisto + Zoo skjalasavn + archive zoo + cartlann Zoo + ficheiro Zoo + ×רכיון Zoo + Zoo archívum + Arsip Zoo + Archivio zoo + Zoo アーカイブ + Zoo архиві + ZOO 압축 íŒŒì¼ + Zoo archyvas + Zoo arhÄ«vs + Zoo-arkiv + Zoo-archief + Zoo-arkiv + Archiwum zoo + Pacote Zoo + Arhivă Zoo + архив ZOO + Archív zoo + Datoteka arhiva ZOO + Arkiv zoo + Zoo-arkiv + Zoo arÅŸivi + архів zoo + Kho nén zoo + Zoo 归档文件 + Zoo å°å­˜æª” + + + + + + + + XHTML page + صÙحة XHTML + Staronka XHTML + Страница — XHTML + pàgina XHTML + Stránka XHTML + XHTML-side + XHTML-Seite + σελίδα XHTML + XHTML page + XHTML-paÄo + página XHTML + XHTML orria + XHTML-sivu + XHTML síða + page XHTML + leathanach XHTML + Páxina XHTML + דף XHTML + XHTML stranica + XHTML-oldal + Halaman XHTML + Pagina XHTML + XHTML ページ + XHTML парағы + XHTML 페ì´ì§€ + XHTML puslapis + XHTML lapa + Laman XHTML + XHTML-side + XHTML-pagina + XHTML-side + Strona XHTML + página XHTML + Página XHTML + Pagină XHTML + Ñтраница XHTML + Stránka XHTML + Datoteka spletne strani XHTML + Faqe XHTML + XHTML Ñтрана + XHTML-sida + Ñторінка XHTML + Trang XHTML + XHTML é¡µé¢ + XHTML ç¶²é  + XHTML + Extensible HyperText Markup Language + + + + + + + Zip archive + أرشي٠Zip + Zip arxivi + ArchiÅ­ zip + Ðрхив — zip + arxiu zip + Archiv ZIP + Archif ZIP + Ziparkiv + Zip-Archiv + συμπιεσμένο αÏχείο Zip + Zip archive + Zip-arkivo + archivador Zip + Zip artxiboa + Zip-arkisto + Zip skjalasavn + archive zip + cartlann Zip + ficheiro Zip + ×רכיון Zip + Zip archívum + Arsip Zip + Archivio zip + Zip アーカイブ + Zip архиві + ZIP 압축 íŒŒì¼ + Zip archyvas + Zip arhÄ«vs + Zip-arkiv + Zip-archief + Zip-arkiv + Archiwum ZIP + Pacote Zip + Arhivă zip + архив ZIP + Archív ZIP + Datoteka arhiva ZIP + Arkiv zip + Zip-arkiv + Zip arÅŸivi + архів zip + Kho nén zip + Zip 归档文件 + Zip å°å­˜æª” + + + + + + + + + + Windows Imaging Format Disk Image + ДиÑк — Windows Imaging + imatge de disc «Windows Imaging Format» + Windows Imaging Format Disk Image + Windows Imaging Format-diskaftryk + Windows-Imaging-Format-Datenträgerabbild + εικόνα δίσκου Windows Image Format + Windows Imaging Format Disk Image + imagen de disco de Windows Imaging Format + image disque Windows Imaging Format + imaxe de disco de Windows Imaging Format + מבנה תמונת כונן של Windows Imaging + Windows Imaging Format lemezkép + Image Disk Windows Imaging Format + Immagine disco formato Windows Imaging + Windows ã‚¤ãƒ¡ãƒ¼ã‚¸ãƒ³ã‚°å½¢å¼ ãƒ‡ã‚£ã‚¹ã‚¯ã‚¤ãƒ¡ãƒ¼ã‚¸ + Windows Imaging Format Disk бейнеÑÑ– + Windows ì´ë¯¸ì§€ í¬ë§· ë””ìŠ¤í¬ ì´ë¯¸ì§€ + Windows Imaging Format diska attÄ“ls + Windows Imaging Format Disk Image + Obraz dysku Windows Imaging Format + Imagem de Disco de Formato Windows Imaging + Imagine de disc „Windows Imaging Format†+ образ диÑка Windows + Odtis slike Windows Imaging + Windows Imaging Format Disk-avbild + формат образів диÑків Windows Imaging + Windows Imaging æ ¼å¼ç£ç›˜é•œåƒ + Windows Imaging Format Disk æ˜ åƒ + + + + + + + + Dolby Digital audio + Dolby Digital سمعي + Dolby Digital audio + AÅ­dyjo Dolby Digital + Ðудио — Dolby Digital + àudio Dolby Digital + Zvuk Dolby Digital + Sain Dolby Digital + Dolby Ditital-lyd + Dolby-Digital-Audio + ψηφιακός Ήχος Dolby + Dolby Digital audio + Sondosiero en Dolby Digital + sonido Dolby Digital + Dolby audio digitala + Dolby Digital -ääni + Dolby Digital ljóður + audio Dolby Digital + fuaim Dolby Digital + son Dolby Digital + שמע Dolby Digital + Dolby Digital audio + Dolby Digital hang + Audio Dolby Digital + Audio Dolby Digital + ドルビーデジタルオーディオ + Dolby Digital-ის áƒáƒ£áƒ“ირ+ Dolby Digital аудиоÑÑ‹ + ëŒë¹„ 디지털 오디오 + Dolby Digital garso įraÅ¡as + Dolby Digital audio + Audio Digital Dolby + Dolby digital lyd + Dolby Digital-audio + Dolby Digital lyd + Plik dźwiÄ™kowy Dolby Digital + áudio Dolby Digital + Ãudio Dolby Digital + Audio Dolby Digital + аудио Dolby Digital + Zvuk Dolby Digital + ZvoÄna datoteka Dolby Digital + Audio Dolby Digital + Дигитални Dolby звучни Ð·Ð°Ð¿Ð¸Ñ + Dolby Digital-ljud + звук Dolby Digital + Âm thanh Dolby Digital + æœæ¯”数字音频 + æœæ¯”數ä½éŸ³è¨Š + + + + + + + DTS audio + + + + + + + + + + + DTSHD audio + + + + + + + + + AMR audio + AMR سمعي + AÅ­dyjo AMR + Ðудио — AMR + àudio AMR + Zvuk AMR + AMR-lyd + AMR-Audio + ήχος AMR + AMR audio + AMR-sondosiero + sonido AMR + AMR audioa + AMR-ääni + AMR ljóður + audio AMR + fuaim AMR + son AMR + שמע AMR + AMR audio + AMR hang + Audio AMR + Audio AMR + AMR オーディオ + AMR áƒáƒ£áƒ“ირ+ AMR аудиоÑÑ‹ + AMR 오디오 + AMR garso įraÅ¡as + AMR audio + AMR-lyd + AMR-audio + AMR-lyd + Plik dźwiÄ™kowy AMR + Ãudio AMR + Audio AMR + аудио AMR + Zvuk AMR + ZvoÄna datoteka AMR + Audio AMR + AMR-ljud + звук AMR + Âm thanh AMR + AMR 音频 + AMR 音訊 + AMR + Adaptive Multi-Rate + + + + + + + + AMR-WB audio + AMR-WB سمعي + AÅ­dyjo AMR-WB + Ðудио — AMR-WB + àudio AMR-WB + Zvuk AMR-WB + AMR-WB-lyd + AMR-WB-Audio + ήχος AMR-WB + AMR-WB audio + AMR-WB-sondosiero + sonido AMR-WB + AMR-WB audioa + AMR-WB-ääni + AMR-WB ljóður + audio AMR-WB + fuaim AMR-WB + son AMR-WB + שמע AMR-WN + AMR-WB audio + AMR-WB hang + Audio AMR-WB + Audio AMR-WB + AMR-WB オーディオ + AMR-WB áƒáƒ£áƒ“ირ+ AMR-WB аудиоÑÑ‹ + AMR-WB 오디오 + AMR-WB garso įraÅ¡as + AMR-WB audio + AMR-WB-lyd + AMR-WB-audio + AMR-WB-lyd + Plik dźwiÄ™kowy AMR-WB + Ãudio AMR-WB + Audio AMR-WB + аудио AMR-WB + Zvuk AMR-WB + ZvoÄna datoteka AMR-WB + Audio AMR-WB + AMR-WB-ljud + звук AMR-WB + Âm thanh AMR-WB + AMR-WB 音频 + AMR-WB 音訊 + AMR-WB + Adaptive Multi-Rate Wideband + + + + + + + + ULAW (Sun) audio + ULAW (صن) سمعي + ULAW (Sun) audio faylı + AÅ­dyjo ULAW (Sun) + Ðудио — ULAW, Sun + àudio ULAW (Sun) + Zvuk ULAW (Sun) + Sain ULAW (Sun) + ULAW-lyd (Sun) + ULAW-Audio (Sun) + ήχος ULAW (Sun) + ULAW (Sun) audio + ULAW-sondosiero (Sun) + sonido ULAW (Sun) + ULAW (sun) audioa + ULAW (Sun) -ääni + ULAW (Sun) ljóður + audio ULAW (Sun) + fuaim ULAW (Sun) + son ULAW (Sun) + שמע ULAW (של Sun) + ULAW (Sun) hang + Audio ULAW (Sun) + Audio ULAW (Sun) + ULAW (Sun) オーディオ + ULAW (Sun) аудиоÑÑ‹ + ULAW (Sun) 오디오 + ULAW (Sun) garso įraÅ¡as + ULAW (Sun) audio + Audio ULAW (Sun) + ULAW-lyd (Sun) + (Sun) ULAW-audio + ULAW (Sun)-lyd + Plik dźwiÄ™kowy ULAW (Sun) + áudio ULAW (Sun) + Ãudio ULAW (Sun) + FiÈ™ier audio ULAW (Sun) + аудио ULAW (Sun) + Zvuk ULAW (Sun) + ZvoÄna datoteka ULAW (Sun) + Audio ULAW (Sun) + ULAW (Sun) звучни Ð·Ð°Ð¿Ð¸Ñ + ULAW-ljud (Sun) + звук ULAW (Sun) + Âm thanh ULAW (Sun) + ULAW (Sun) 音频 + ULAW (Sun) 音訊 + + + + + + + + Commodore 64 audio + Commodore 64 سمعي + AÅ­dyjo Commodore 64 + Ðудио — Commodore 64 + àudio Commodore 64 + Zvuk Commodore 64 + Commodore 64-lyd + Commodore-64-Audio + ήχος Commodore 64 + Commodore 64 audio + Sondosiero de Commodore 64 + sonido de Commodore 64 + Commodore 64 Audioa + Commodore 64 -ääni + Commodore 64 ljóð + audio Commodore 64 + fuaim Commodore 64 + son de Commodore 64 + שמע של Commodore 64 + Commodore 64 audio + Commodore 64 hang + Audio Commodore 64 + Audio Commodore 64 + Commodore 64 オーディオ + Commodore 64-ის áƒáƒ£áƒ“ირ+ Commodore 64 аудиоÑÑ‹ + Commodore 64 오디오 + Commodore 64 garso įraÅ¡as + Commodore 64 audio + Audio Commodore 64 + Commodore 64-lyd + Commodore 64-audio + Commodore 64-lyd + Plik dźwiÄ™kowy Commodore 64 + áudio Commodore 64 + Ãudio Commodore 64 + Audio Commodore 64 + аудио Commodore 64 + Zvuk Commodore 64 + ZvoÄna datoteka Commodore 64 + Audio Commodore 64 + Комодор 64 звучни Ð·Ð°Ð¿Ð¸Ñ + Commodore 64-ljud + звук Commodore 64 + Âm thanh Commodore 64 + Commodore 64 音频 + Commodore 64 音訊 + + + + + + + + PCM audio + سمعي PCM + PCM audio faylı + AÅ­dyjo PCM + Ðудио — PCM + àudio PCM + Zvuk PCM + Sain PCM + PCM-lyd + PCM-Audio + ήχος PCM + PCM audio + PCM-sondosiero + sonido PCM + PCM audioa + PCM-ääni + PCM ljóður + audio PCM + fuaim PCM + son PCM + שמע PCM + PCM hang + Audio PCM + Audio PCM + PCM オーディオ + PCM аудиоÑÑ‹ + PCM 오디오 + PCM garso įraÅ¡as + PCM audio + Audio PCM + PCM-lyd + PCM-audio + PCM-lyd + Plik dźwiÄ™kowy PCM + áudio PCM + Ãudio PCM + Audio PCM + аудио PCM + Zvuk PCM + ZvoÄna datoteka PCM + Audio PCM + PCM звучни Ð·Ð°Ð¿Ð¸Ñ + PCM-ljud + звук PCM + Âm thanh PCM + PCM 音频 + PCM 音訊 + + + + + + + + + + + + + + + + + + AIFC audio + AIFC سمعي + AIFC audio faylı + AÅ­dyjo AIFC + Ðудио — AIFC + àudio AIFC + Zvuk AIFC + Sain AIFC + AIFC-lyd + AIFC-Audio + ήχος AIFC + AIFC audio + AIFC-sondosiero + sonido AIFC + AIFC audioa + AIFC-ääni + AIFC ljóður + audio AIFC + fuaim AIFC + son AIFC + שמע AIFC + AIFC audio + AIFC hang + Audio AIFC + Audio AIFC + AIFC オーディオ + AIFC áƒáƒ£áƒ“ირ+ AIFC аудиоÑÑ‹ + AIFC 오디오 + AIFC garso įraÅ¡as + AIFC audio + Audio AIFC + AIFC-lyd + AIFC-audio + AIFC-lyd + Plik dźwiÄ™kowy AIFC + áudio AIFC + Ãudio AIFC + FiÈ™ier audio AIFC + аудио AIFC + Zvuk AIFC + ZvoÄna datoteka AIFC + Audio AIFC + AIFC звучни Ð·Ð°Ð¿Ð¸Ñ + AIFC-ljud + звук AIFC + Âm thanh AIFC + AIFC 音频 + AIFC 音訊 + AIFC + Audio Interchange File format Compressed + + + + + + + + + + AIFF/Amiga/Mac audio + AIFF/Amiga/Mac سمعي + AIFF/Amiga/Mac audio faylı + AÅ­dyjo AIFF/Amiga/Mac + Ðудио — AIFF/Amiga/Mac + àudio AIFF/Amiga/Mac + Zvuk AIFF/Amiga/Mac + Sain AIFF/Amiga/Mac + AIFF-/Amiga-/Maclyd + AIFF/Amiga/Mac-Audio + ήχος AIFF/Amiga/Mac + AIFF/Amiga/Mac audio + AIFF/Amiga/Mac-sondosiero + sonido AIFF/Amiga/Mac + AIFF/Amiga/Mac audioa + AIFF/Amiga/Mac-ääni + AIFF/Amiga/Mac ljóður + audio AIFF/Amiga/Mac + fuaim AIFF/Amiga/Mac + son AIFF/Amiga/Mac + שמע AIFF/Amiga/Mac + AIFF/Amiga/Mac audio + AIFF/Amiga/Mac hang + Audio AIFF/Amiga/Mac + Audio AIFF/Amiga/Mac + AIFF/Amiga/Mac オーディオ + AIFF/Amiga/Mac áƒáƒ£áƒ“ირ+ AIFF/Amiga/Mac аудиоÑÑ‹ + AIFF/Amiga/Mac 오디오 + AIFF/Amiga/Mac garso įraÅ¡as + AIFF/Amiga/Mac audio + Audio AIFF/Amiga/Mac + AIFF/Amiga/Mac-lyd + AIFF/Amiga/Mac-audio + AIFF/Amiga/Mac-lyd + Plik dźwiÄ™kowy AIFF/Amiga/Mac + áudio AIFF/Amiga/Mac + Ãudio AIFF/Amiga/Mac + Audio AIFF/Amiga/Mac + аудио AIFF/Amiga/Mac + Zvuk AIFF/Amiga/Mac + ZvoÄna datoteka AIFF/Amiga/Mac + Audio AIFF/Amiga/Mac + AIFF/Ðмига/Мекинтош звучни Ð·Ð°Ð¿Ð¸Ñ + AIFF/Amiga/Mac-ljud + звук AIFF/Amiga/Mac + Âm thanh AIFF/Amiga/Mac + AIFF/Amiga/Mac 音频 + AIFF/Amiga/Mac 音訊 + AIFF + Audio Interchange File Format + + + + + + + + + + Monkey's audio + Monkey سمعي + AÅ­dyjo Monkey's + Ðудио — Monkey + àudio Monkey + Zvuk Monkey's + Monkeys lyd + Monkey's-Audio + ήχος Monkey's + Monkey's audio + sonido Monkey + Monkey audioa + Monkey's Audio -ääni + Monkey's ljóður + audio Monkey + fuaim Monkey's + son de Monkey + שמע של Monkey's + Monkey hang + Audio Monkey + Audio Monkey's + Monkey's オーディオ + Monkey аудиоÑÑ‹ + Monkey's 오디오 + Monkey garso įraÅ¡as + Monkey's audio + Monkey's-lyd + Monkey's-audio + Monkey's Audio-lyd + Plik dźwiÄ™kowy Monkey's Audio + Ãudio Monkey's + Audio Monkey's + аудио Monkey's + Zvuk Monkey's + ZvoÄna datoteka Monkey + Audio Monkey's + Monkey's audio + звук Monkey's + Âm thanh cua Monkey + Monkey's audio 音频 + Monkey's 音訊 + + + + + + + Impulse Tracker audio + Impulse Tracker سمعي + Impulse Tracker audio faylı + AÅ­dyjo Impulse Tracker + Ðудио — Impulse Tracker + àudio d'Impulse Tracker + Zvuk Impulse Tracker + Sain Impulse Tracker + Impulse Tracker-lyd + Impulse-Tracker-Audio + ήχος Impulse Tracker + Impulse Tracker audio + Sondosiero de Impulse Tracker + sonido Impulse Tracker + Impulse Tracker audioa + Impulse Tracker -ääni + Impulse Tracker ljóður + audio Impulse Tracker + fuaim Impulse Tracker + son de Impulse Tracker + שמע של Impulse Tracker + Impulse Tracker audio + Impulse Tracker hang + Audio Impulse Tracker + Audio Impulse Tracker + Impulse Tracker オーディオ + Impulse Tracker аудиоÑÑ‹ + Impulse Tracker 오디오 + Impulse Tracker garso įraÅ¡as + Impulse Tracker audio + Audio Impulse Tracker + Impulse Tracker-lyd + Impulse Tracker-audio + Impulse Tracker lyd + Plik dźwiÄ™kowy Impulse Tracker + áudio Impulse Tracker + Ãudio Impulse Tracker + Audio Impulse Tracker + аудио Impulse Tracker + Zvuk Impulse Tracker + ZvoÄna datoteka Impulse Tracker + Audio Impulse Tracker + Impulse Tracker звучни Ð·Ð°Ð¿Ð¸Ñ + Impulse Tracker-ljud + звук Impulse Tracker + Âm thanh Impulse Tracker + Impulse Tracker 音频 + Impulse Tracker 音訊 + + + + + + + FLAC audio + FLAC سمعي + AÅ­dyjo FLAC + Ðудио — FLAC + àudio FLAC + Zvuk FLAC + FLAC-lyd + FLAC-Audio + Ήχος FLAC + FLAC audio + FLAC-sondosiero + sonido FLAC + FLAC audioa + FLAC-ääni + FLAC ljóður + audio FLAC + fuaim FLAC + son FLAC + קובץ שמע מסוג FLAC + FLAC audio + FLAC hang + Audio FLAC + Audio FLAC + FLAC オーディオ + FLAC áƒáƒ£áƒ“ირ+ FLAC аудиоÑÑ‹ + FLAC 오디오 + FLAC garso įraÅ¡as + FLAC audio + Audio FLAC + FLAC-lyd + FLAC-audio + FLAC-lyd + Plik dźwiÄ™kowy FLAC + áudio FLAC + Ãudio FLAC + Audio FLAC + аудио FLAC + Zvuk FLAC + ZvoÄna datoteka Flac + Audio FLAC + FLAC звучни Ð·Ð°Ð¿Ð¸Ñ + FLAC-ljud + звук FLAC + Âm thanh FLAC + FLAC 音频 + FLAC 音訊 + + + + + + + + WavPack audio + WavPack سمعي + AÅ­dyjo WavPack + Ðудио — WavPack + àudio WavPack + Zvuk WavPack + WavPack-lyd + WavPack-Audio + ήχος WavePack + WavPack audio + WavPack-sondosiero + sonido WavPack + WavPack audioa + WavPack-ääni + WavPack ljóður + audio WavPack + fuaim WavPack + son WavPack + שמע WavPack + WavPack audio + WavPack hang + Audio WavPack + Audio WavPack + WavPack オーディオ + WavPack аудиоÑÑ‹ + WavPack 오디오 + WavPack garso įraÅ¡as + WavPack audio + WavPack-lyd + WavPack-audio + WavPack-lyd + Plik dźwiÄ™kowy WavPack + Ãudio WavPack + Audio WavPack + аудио WavPack + Zvuk WavPack + ZvoÄna datoteka WavPack + Audio WavPack + WavPack-ljud + звук WavPack + Âm thanh WavPack + WavPack 音频 + WavPack 音訊 + + + + + + + + WavPack audio correction file + مل٠تصحيح WavPack السمعي + FajÅ‚ aÅ­dyjokarekcyi WavPack + Файл за корекции на аудио — WavPack + fitxer de correcció d'àudio WavPack + Opravný zvukový soubor WavPack + WavPack-lydkorrektionsfil + WavPack-Audiokorrekturdatei + αÏχείο διόÏθωσης ήχου WavePack + WavPack audio correction file + archivo de corrección de sonido WavPack + WavPack audio-zuzenketaren fitxategia + WavPack-äänikorjaustiedosto + WavPack ljóðrættingarfíla + fichier de correction audio WavPack + comhad cheartú fhuaim WavPack + ficheiro de corrección de son WavPack + קובץ תיקון שמע של WavPack + WavPack hangjavítási fájl + Berkas koreksi audio WavPack + File correzione audio WavPack + WavPack オーディオコレクションファイル + WavPack аудио түзету файлы + WavPack 오디오 êµì • íŒŒì¼ + WavPack garso korekcijos failas + WavPack audio korekciju datne + WavPack lydkorrigeringsfil + WavPack-audio-correctiebestand + WawPack lydopprettingsfil + Plik korekcji dźwiÄ™ku WavPack + Arquivo de correção de áudio WavPack + FiÈ™ier audio de corecÈ›ie WavPack + файл коррекции аудио WavPack + Opravný zvukový súbor WavPack + popravljalna zvoÄna datoteka WavPack + File korrigjgimi audio WavPack + WavPack-ljudkorrigeringsfil + файл корекції звуку WavPack + Tập tin sá»­a chữa âm thanh WavPack + WavPack 音频校正文档 + WavPack 音訊校正檔 + + + + + + + MIDI audio + MIDI سمعي + MIDI audio faylı + AÅ­dyjo MIDI + Ðудио — MIDI + àudio MIDI + Zvuk MIDI + Sain MIDI + MIDI-lyd + MIDI-Audio + ήχος MIDI + MIDI audio + MIDI-sondosiero + sonido MIDI + MIDI audioa + MIDI-ääni + MIDI ljóður + audio MIDI + fuaim MIDI + son MIDI + שמע MIDI + MIDI audio + MIDI hang + Audio MIDI + Audio MIDI + MIDI オーディオ + MIDI аудиоÑÑ‹ + 미디 오디오 + MIDI garso įraÅ¡as + MIDI audio + Audio MIDI + MIDI-lyd + MIDI-audio + MIDI-lyd + Plik dźwiÄ™kowy MIDI + áudio MIDI + Ãudio MIDI + Audio MIDI + аудио MIDI + Zvuk MIDI + ZvoÄna datoteka MIDI + Audio MIDI + MIDI звучни Ð·Ð°Ð¿Ð¸Ñ + MIDI-ljud + звук MIDI + Âm thanh MIDI + MIDI 音频 + MIDI 音訊 + + + + + + + + + + compressed Tracker audio + Tracker سمعي مضغوط + aÅ­dyjo skampresavanaha Trackera + Ðудио — Tracker, компреÑирано + àudio Tracker comprimit + Komprimovaný zvuk Tracker + Trackerkomprimeret lyd + Komprimiertes Tracker-Audio + συμπιεσμένος ήχος Tracker + compressed Tracker audio + tracker de sonido comprimido + konprimitutako Tracker audioa + pakattu Tracker-ääni + stappað Tracker ljóður + audio Tracker compressé + fuaim chomhbhrúite Tracker + son comprimido de Tracker + שמע גשש מכווץ + komprimirani Tracker audio + tömörített Tracker hang + audio Tracker terkompresi + Audio compresso Tracker + 圧縮 Tracker オーディオ + Ñығылған Tracker аудиоÑÑ‹ + ì••ì¶•ëœ Tracker 오디오 + suglaudintas Tracker garso įraÅ¡as + saspiests Tracker audio + ingepakte Tracker-audio + komprimert Tracker-lyd + Skompresowany plik dźwiÄ™kowy Tracker + Ãudio Tracker compactado + Tracker audio comprimat + аудио Tracker (Ñжатое) + Komprimovaný zvuk Tracker + SkrÄena zvoÄna datoteka Tracker + Audio Tracker e kompresuar + komprimerat Tracker-ljud + ÑтиÑнутий звук Tracker + âm thanh Tracker đã nén + 压缩的 Tracker 音频 + 壓縮版 Tracker 音訊 + + + + + + + AAC audio + AAC + Advanced Audio Coding + + + + + + + + MPEG-4 audio + MPEG-4 سمعي + AÅ­dyjo MPEG-4 + Ðудио — MPEG-4 + àudio MPEG-4 + Zvuk MPEG-4 + MPEG4-lyd + MPEG-4-Audio + ήχος MPEG-4 + MPEG-4 audio + MPEG4-sondosiero + sonido MPEG-4 + MPEG-4 audioa + MPEG-4-ääni + MPEG-4 ljóður + audio MPEG-4 + fuaim MPEG-4 + son MPEG-4 + שמע MPEG-4 + MPEG-4 audio + MPEG-4 hang + Audio MPEG-4 + Audio MPEG-4 + MPEG-4 オーディオ + MPEG-4 áƒáƒ£áƒ“ირ+ MPEG-4 аудиоÑÑ‹ + MPEG-4 오디오 + MPEG-4 garso įraÅ¡as + MPEG-4 audio + MPEG-4-lyd + MPEG4-audio + MPEG-4-lyd + Plik dźwiÄ™kowy MPEG-4 + Ãudio MPEG-4 + Audio MPEG-4 + аудио MPEG-4 + Zvuk MPEG-4 + ZvoÄna datoteka MPEG-4 + Audio MPEG-4 + MPEG-4-ljud + звук MPEG-4 + Âm thanh MPEG-4 + MPEG-4 音频 + MPEG-4 音訊 + + + + + + + + + MPEG-4 video + MPEG-4 مرئي + Videa MPEG-4 + Видео — MPEG-4 + vídeo MPEG-4 + Video MPEG-4 + MPEG4-video + MPEG-4-Video + βίντεο MPEG-4 + MPEG-4 video + MPEG-4-video + vídeo MPEG-4 + MPEG-4 bideoa + MPEG-4-video + MPEG-4 video + vidéo MPEG-4 + físeán MPEG-4 + vídeo MPEG-4 + ויד×ו MPEG-4 + MPEG-4 video + MPEG-4 videó + Video MPEG-4 + Video MPEG-4 + MPEG-4 å‹•ç”» + MPEG-4 ვიდერ+ MPEG-4 видеоÑÑ‹ + MPEG-4 비디오 + MPEG-4 vaizdo įraÅ¡as + MPEG-4 video + MPEG-4-film + MPEG4-video + MPEG-4-video + Plik wideo MPEG-4 + Vídeo MPEG-4 + Video MPEG-4 + видео MPEG-4 + Video MPEG-4 + Video datoteka MPEG-4 + Video MPEG-4 + MPEG-4-video + відеокліп MPEG-4 + Ảnh Ä‘á»™ng MPEG-4 + MPEG-4 视频 + MPEG-4 視訊 + + + + + + + + + + + + + + + MPEG-4 audio book + كتاب MPEG-4 السمعي + AÅ­dyjokniha MPEG-4 + Ðудио книга — MPEG-4 + llibre d'àudio MPEG-4 + Zvuková kniha MPEG-4 + MPEG4-lydbog + MPEG-4-Hörbuch + ηχητικό βιβλίο MPEG-4 + MPEG-4 audio book + MPEG-4-sonlibro + audiolibro en MPEG-4 + MPEG-4 audio-liburua + MPEG-4-äänikirja + MPEG-4 ljóðbók + livre audio MPEG-4 + leabhar fhuaim MPEG-4 + sonlibro de MPEG-4 + ספר דיגיטלי MPEG-4 + MPEG-4 audio knjiga + MPEG-4 hangoskönyv + Buku audio MPEG-4 + Audiolibro MPEG-4 + MPEG-4 オーディオブック + MPEG-4 áƒáƒ£áƒ“იáƒáƒ¬áƒ˜áƒ’ნი + MPEG-4 аудио кітабы + MPEG-4 ì˜¤ë””ì˜¤ë¶ + MPEG-4 garso knyga + MPEG-4 audio grÄmata + MPEG-4-lydbok + MPEG4-audioboek + MPEG-4-lydbok + Książka dźwiÄ™kowa MPEG-4 + Ãudio livro MPEG-4 + Carte audio MPEG-4 + аудиокнига MPEG-4 + Zvuková kniha MPEG-4 + ZvoÄna knjiga MPEG-4 + Audiolibër MPEG-4 + MPEG-4-ljudbok + аудіокнига MPEG-4 + Sách âm thanh MPEG-4 + MPEG-4 有声书 + MPEG-4 音訊書 + + + + + + + + + 3GPP multimedia file + مل٠وسائط متعددة 3GPP + Multymedyjny fajÅ‚ 3GPP + ÐœÑƒÐ»Ñ‚Ð¸Ð¼ÐµÐ´Ð¸Ñ â€” 3GPP + fitxer multimèdia 3GPP + Soubor multimédií 3GPP + 3GPP multimedie-fil + 3GPP-Multimediadatei + αÏχείο πολυμέσων 3GPP + 3GPP multimedia file + archivo multimedia 3GPP + 3GPP multimediako fitxategia + 3GPP-multimediatiedosto + 3GGP margmiðlafíla + fichier multimédia 3GPP + comhad ilmheán 3GPP + ficheiro multimedia 3GPP + קובץ מולטימדיה מסוג 3GPP + 3GPP multimedijska datoteka + 3GPP multimédiafájl + Berkas multimedia 3GPP + File multimediale 3GPP + 3GPP マルãƒãƒ¡ãƒ‡ã‚£ã‚¢ãƒ•ã‚¡ã‚¤ãƒ« + 3GPP მულტიმედიური ფáƒáƒ˜áƒšáƒ˜ + 3GPP мультимедиÑлық файлы + 3GPP 멀티미디어 íŒŒì¼ + 3GPP multimedijos failas + 3GPP multimediju datne + 3GPP-multimediafil + 3GPP-multimediabestand + 3GPP-multimediafil + Plik multimedialny 3GPP + Arquivo multimídia 3GPP + FiÈ™ier multimedia 3GPP + мультимедийный файл 3GPP + Súbor multimédií 3GPP + VeÄpredstavnostna datoteka 3GPP + File multimedial 3GPP + 3GPP-multimediafil + 3GPP multimedya dosyası + файл мультимедійних даних 3GPP + Tập tin Ä‘a phÆ°Æ¡ng tiện 3GPP + 3GPP 多媒体文件 + 3GPP 多媒體檔案 + 3GPP + 3rd Generation Partnership Project + + + + + + + + + + + + + + + + + + + + + + + + + 3GPP2 multimedia file + ÐœÑƒÐ»Ñ‚Ð¸Ð¼ÐµÐ´Ð¸Ñ â€” 3GPP2 + fitxer multimèdia 3GPP2 + Soubor multimédií 3GPP2 + 3GPP2 multimedie-fil + 3GPP2-Multimediadatei + αÏχείο πολυμέσων 3GPP2 + 3GPP2 multimedia file + archivo multimedia 3GPP2 + 3GPP2-multimediatiedosto + 3GGP2 margmiðlafíla + fichier multimédia 3GPP2 + comhad ilmheán 3GPP2 + ficheiro multimedia 3GPP2 + קובץ מולטימדיה 3GPP2 + 3GPP2 multimedijska datoteka + 3GPP2 multimédiafájl + Berkas multimedia 3GPP2 + File multimediale 3GPP2 + 3GPP2 マルãƒãƒ¡ãƒ‡ã‚£ã‚¢ãƒ•ã‚¡ã‚¤ãƒ« + 3GPP2 მულტიმედიური ფáƒáƒ˜áƒšáƒ˜ + 3GPP2 мультимедиÑлық файлы + 3GPP2 멀티미디어 íŒŒì¼ + 3GPP2 multimediju datne + 3GPP2 multimedia bestand + Plik multimedialny 3GPP2 + Arquivo multimídia 3GPP2 + FiÈ™ier multimedia 3GPP2 + мультимедийный файл 3GPP2 + Súbor multimédií 3GPP2 + VeÄpredstavnostna datoteka 3GPP2 + 3GPP2-multimediafil + 3GPP2 multimedya dosyası + файл мультимедійних даних 3GPP2 + 3GPP2 多媒体文件 + 3GPP2 多媒體檔案 + 3GPP2 + 3rd Generation Partnership Project 2 + + + + + + + + + + + Amiga SoundTracker audio + مقتÙÙŠ صوت Amiga السمعي + AÅ­dyjo Amiga SoundTracker + Ðудио — Amiga SoundTracker + àudio Amiga SoundTracker + Zvuk Amiga SoundTracker + Amiga SoundTracker-lyd + Amiga-SoundTracker-Audio + ήχος Amiga SoundTracker + Amiga SoundTracker audio + Sondosiero de Amiga SoundTracker + sonido de Amiga SoundTracker + Amiga soundtracker audioa + Amiga SoundTracker -ääni + Amiga SoundTracker ljóður + audio SoundTracker Amiga + fuaim Amiga SoundTracker + son de Amiga SoundTracker + קובץ שמע של Amiga SoundTracker + Amiga SoundTracker audio + Amiga SoundTracker hang + Audio Amida SoundTracker + Audio Amiga SoundTracker + Amiga SoundTracker オーディオ + Amiga SoundTracker-ის áƒáƒ£áƒ“ირ+ Amiga SoundTracker аудиоÑÑ‹ + Amiga SoundTracker 오디오 + Amiga SoundTracker garso įraÅ¡as + Amiga SoundTracker audio + Audio Amiga Soundtracker + Amiga SoundTracker-lyd + Amiga SoundTracker-audio + Amiga soundtracker-lyd + Plik dźwiÄ™kowy Amiga SoundTracker + áudio SoundTracker do Amiga + Ãudio Amiga SoundTracker + Audio Amiga SoundTracker + аудио Amiga SoundTracker + Zvuk Amiga SoundTracker + ZvoÄna datoteka Amiga SoundTracker + Audio Amiga SoundTracker + Ðмига soundtracker звук + Amiga SoundTracker-ljud + звук Amiga SoundTracker + Âm thanh Amiga SoundTracker + Amiga SoundTracker 音频 + Amiga SoundTracker 音訊 + + + + + + + + + + MP2 audio + MP2 سمعي + AÅ­dyjo MP2 + Ðудио — MP2 + àudio MP2 + Zvuk MP2 + MP2-lyd + MP2-Audio + ήχος MP2 + MP2 audio + MP2-sondosiero + sonido MP2 + MP2 audioa + MP2-ääni + MP2 ljóður + audio MP2 + fuaim MP2 + son MP2 + שמע MP2 + MP2 audio + MP2 hang + Audio MP2 + Audio MP2 + MP2 オーディオ + MP2 аудиоÑÑ‹ + MP2 오디오 + MP2 garso įraÅ¡as + MP2 audio + MP2-lyd + MP2-audio + MP2-lyd + Plik dźwiÄ™kowy MP2 + Ãudio MP2 + Audio MP2 + аудио MP2 + Zvuk MP2 + ZvoÄna datoteka MP2 + Audio MP2 + MP2-ljud + звук MP2 + Âm thanh MP2 + MP2 音频 + MP2 音訊 + + + + + MP3 audio + MP3 سمعي + MP3 audio faylı + AÅ­dyjo MP3 + Ðудио — MP3 + àudio MP3 + Zvuk MP3 + Sain MP3 + MP3-lyd + MP3-Audio + ήχος MP3 + MP3 audio + MP3-sondosiero + sonido MP3 + MP3 audioa + MP3-ääni + MP3 ljóður + audio MP3 + fuaim MP3 + son MP3 + שמע MP3 + MP3 audio + MP3 hang + Audio MP3 + Audio MP3 + MP3 オーディオ + MP3 áƒáƒ£áƒ“ირ+ MP3 аудиоÑÑ‹ + MP3 오디오 + MP3 garso įraÅ¡as + MP3 audio + Audio MP3 + MP3-lyd + MP3-audio + MP3-lyd + Plik dźwiÄ™kowy MP3 + áudio MP3 + Ãudio MP3 + Audio MP3 + аудио MP3 + Zvuk MP3 + ZvoÄna datoteka MP3 + Audio MP3 + MP3 звучни Ð·Ð°Ð¿Ð¸Ñ + MP3-ljud + звук MP3 + Âm thanh MP3 + MP3 音频 + MP3 音訊 + + + + + + + + + + + + MP3 audio (streamed) + MP3 سمعي (تدÙÙ‚) + AÅ­dyjo MP3 (pÅ‚yÅ„) + Ðудио — MP3, поточно + àudio MP3 (flux) + Zvuk MP3 (proud) + MP3-lyd (strøm) + MP3-Audio (Stream) + ήχος MP3 (εκπεμπόμενος) + MP3 audio (streamed) + MP3-sondosiero (fluigate) + sonido MP3 (en flujo) + MP3 audioa (korrontea) + MP3-ääni (virtaus) + MP3 ljóður (streymað) + audio MP3 (flux) + fuaim MP3 (sruthaithe) + son MP3 (en stream) + שמע MP3 (מוזר×) + MP3 hang (sugárzott) + Audio MP3 (stream) + Audio MP3 (in streaming) + MP3 オーディオ (ストリーム) + MP3 áƒáƒ£áƒ“ირ(ნáƒáƒ™áƒáƒ“ი) + MP3 аудиоÑÑ‹ (ағымдық) + MP3 오디오 (스트림) + MP3 garso įraÅ¡as (transliuojamas) + MP3 audio (straumÄ“ts) + Audio MP3 (aliran) + MP3-lyd (streaming) + MP3-audio (gestreamd) + Strauma MP3-lyd + DźwiÄ™k MP3 (strumieÅ„) + áudio MP3 (em fluxo) + Ãudio MP3 (em fluxo) + Audio MP3 (flux) + аудио MP3 (потоковое) + Zvuk MP3 (streamovaný) + ZvoÄna datoteka MP3 (pretoÄna) + Audio MP3 (streamed) + MP3 звучни Ð·Ð°Ð¿Ð¸Ñ (непрекидан) + MP3-ljud (flöde) + звук MP3 (потоковий) + Âm thanh MP3 (chạy luồng) + MP3 æµéŸ³é¢‘ + MP3 音訊 (串æµ) + + + + + + + + + + + + + + + HTTP Live Streaming playlist + قائمة بث HTTP حية + СпиÑък за изпълнение — поток по HTTP + llista de reproducció en temps real HTTP + Seznam skladeb HTTP Live Streaming + Afspilningsliste til HTTP-livestrøm + HTTP Live-Streaming-Wiedergabeliste + HTTP Live Streaming playlist + lista de reproducción de flujo en directo HTTP + HTTP zuzeneko korrontearen erreprodukzio-zerrenda + HTTP beinleiðis streymaður avspælingarlisti + liste de lecture de flux HTTP Live + seinmliosta sruthaithe bheo HTTP + lista de reprodución de fluxo HTTP + רשימת השמעה הזרימה של HTTP + HTTP élÅ‘ lejátszólista + Daftar putar HTTP Live Streaming + Scaletta Live Steaming HTTP + HTTP ライブストリーミングå†ç”Ÿãƒªã‚¹ãƒˆ + HTTP тірі ағым ойнау тізімі + HTTP ë¼ì´ë¸Œ ìŠ¤íŠ¸ë¦¬ë° ìž¬ìƒ ëª©ë¡ + HTTP tiesioginio transliavimo grojaraÅ¡tis + HTTP dzÄ«vÄs straumÄ“Å¡anas repertuÄrs + HTTP Live Streaming afspeellijst + Lista odtwarzania strumieniowego na żywo HTTP + Lista de Reprodução Streaming ao Vivo de HTTP + Listă de redare difuzată ca flux HTTP + ÑпиÑок воÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ HTTP-потока + Seznam predvajanja živega pretoka HTTP + HTTP Live Streaming-spellista + ÑпиÑок Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ HTTP Live Streaming + HTTP ç›´æ’­æµæ’­æ”¾åˆ—表 + HTTP å³æ™‚串æµæ’­æ”¾æ¸…å–® + + + + + + + + + + + Microsoft ASX playlist + قائمة تشغيل مايكروسوÙت ASX + Åšpis Microsoft ASX + СпиÑък за изпълнение — Microsoft ASX + llista de reproducció ASX de Microsoft + Seznam skladeb Microsoft ASX + Microsoft ASX-afspilningsliste + Microsoft-ASX-Wiedergabeliste + λίστα αναπαÏαγωγής Microsoft ASX + Microsoft ASX playlist + lista de reproducción ASX de Microsoft + Microsoft ASX erreprodukzio-zerrenda + Microsoft ASX -soittolista + Microsoft ASX avspælingarlisti + liste de lecture Microsoft ASX + seinmliosta Microsoft ASX + lista de reprodución Microsoft ASX + רשימת השמעה ASX (מיקרוסופט) + Microsoft ASX popis za reprodukciju + Microsoft ASX lejátszólista + Senarai putar Microsoft ASX + Scaletta Microsoft ASX + Microsoft ASX å†ç”Ÿãƒªã‚¹ãƒˆ + Microsoft-ის ASX რეპერტუáƒáƒ áƒ˜ + Microsoft ASX ойнау тізімі + 마ì´í¬ë¡œì†Œí”„트 ASX ìž¬ìƒ ëª©ë¡ + Microsoft ASX grojaraÅ¡tis + Microsoft ASX repertuÄrs + Microsoft ASX-spilleliste + Microsoft ASX-afspeellijst + Microsoft ASX-speleliste + Lista odtwarzania Microsoft ASX + Lista de reprodução do Microsoft ASX + Listă redare Microsoft ASX + ÑпиÑок воÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Microsoft ASX + Zoznam skladieb Microsoft ASX + Seznam predvajanja Microsoft ASX + Listë titujsh Microsoft ASF + Microsoft ASX-spellista + ÑпиÑок Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ASX Microsoft + Danh mục nhạc Microsoft ASX + Microsoft ASX 播放列表 + 微軟 ASX 播放清單 + + + + + + + + + + + + + + + + + PSF audio + PSF سمعي + AÅ­dyjo PSF + Ðудио — PSF + àudio PSF + Zvuk PSF + PSF-lyd + PSF-Audio + ήχος PSF + PSF audio + PSF-sondosiero + sonido PSF + PSF audioa + PSF-ääni + PSF ljóður + audio PSF + fuaim PSF + son PSF + שמע PSF + PSF hang + Audio PSF + Audio PSF + PSF オーディオ + PSF аудиоÑÑ‹ + PSF 오디오 + PSF garso įraÅ¡as + PSF audio + PSF-lyd + PSF-audio + PSF-lyd + Plik dźwiÄ™kowy PSF + Ãudio PSF + Audio PSF + аудио PSF + Zvuk PSF + ZvoÄna datoteka PSF + Audio PSF + PSF-ljud + звук PSF + Âm thanh PSF + PSF 音频 + PSF 音訊 + PSF + Portable Sound Format + + + + + + + MiniPSF audio + MiniPSF سمعي + AÅ­dyjo MiniPSF + Ðудио — MiniPSF + àudio MiniPSF + Zvuk MiniPSF + MiniPSF-lyd + MiniPSF-Audio + ήχος MiniPSF + MiniPSF audio + MiniPSF-sondosiero + sonido MiniPSF + MiniPSF audioa + MiniPSF-ääni + MiniPSF ljóður + audio MiniPSF + fuaim MiniPSF + son MiniPSF + שמע של MiniPSP + MiniPSF audio + MiniPSF hang + Audio MiniPSF + Audio MiniPSF + MiniPSF オーディオ + MiniPSF-ის áƒáƒ£áƒ“ირ+ MiniPSF аудиоÑÑ‹ + MiniPSF 오디오 + MiniPSF garso įraÅ¡as + MiniPSF audio + MiniPSF-lyd + MiniPSF-audio + MiniPSF-lyd + Plik dźwiÄ™kowy MiniPSF + Ãudio MiniPSF + Audio MiniPSF + аудио MiniPSF + Zvuk MiniPSF + ZvoÄna datoteka MiniPSF + Audio MiniPSF + MiniPSF-ljud + звук MiniPSF + Âm thanh MiniPSF + MiniPSF 音频 + MiniPSF 音訊 + MiniPSF + Miniature Portable Sound Format + + + + + PSFlib audio library + مكتبة PSFlib السمعية + AÅ­dyjobiblijateka PSFlib + Ðудио библиотека — PSFlib + biblioteca d'àudio PSFlib + Zvuková knihovna PSFlib + PSFlib-lydbibliotek + PSFlib-Audiobibliothek + βιβλιοθήκη ήχου PSFlib + PSFlib audio library + biblioteca de sonido PSFlib + PSFlib audioaren liburutegia + PSFlib-äänikirjasto + PSFlib ljóðsavn + bibliothèque audio PSFlib + leabharlann fhuaim PSFlib + Biblioteca de son PSFlib + ספריית שמע PSFlib + PSFlib hanggyűjtemény + Pustaka audio PSFlib + Libreria audio PSFlib + PSFlib オーディオライブラリ + PSFlib аудио жинағы + PSFlib 오디오 ë¼ì´ë¸ŒëŸ¬ë¦¬ + PSFlib garso biblioteka + PSFlib fonotÄ“ka + PSFlib-lydbibliotek + PSFlib-audiobibliotheek + PSFlib lydbibliotek + Biblioteka dźwiÄ™kowa PSFlib + Biblioteca de áudio PSFlib + Bibliotecă audio PSFlib + фонотека PSFlib + Zvuková knižnica PSFlib + ZvoÄna knjižnica PSFlib + Librari audio PSFlib + PSFlib-ljudbibliotek + аудіобібліотека PSFlib + ThÆ° viện âm thanh PSFlib + PSFlib 音频库文件 + PSFlib 音訊庫 + PSFlib + Portable Sound Format Library + + + + + Windows Media audio + Windows Media سمعي + AÅ­dyjo Windows Media + Ðудио — Windows Media + àudio Windows Media + Zvuk Windows Media + Windows Media-lyd + Windows-Media-Audio + ήχος Windows Media + Windows Media audio + sonido de Windows Media + Windows Media audioa + Windows Media -ääni + Windows Media ljóður + audio Windows Media + fuaim Windows Media + son de Windows Media + שמע של Windows Media + Windows Media audio + Windows Media hang + Audio Windows Media + Audio Windows Media + Windows Media オーディオ + Windows Media аудиоÑÑ‹ + Windows 미디어 오디오 + Windows Media garso įraÅ¡as + Windows Media audio + Windows Media lyd + Windows Media-audio + Windows Media-lyd + Plik dźwiÄ™kowy Windows Media + Ãudio do Windows Media + Audio Windows Media + аудио Windows Media + Zvuk Windows Media + ZvoÄna datoteka Windows Media + Audio Windows Media + Windows Media-ljud + звук Windows Media + Âm thanh Windows Media + Windows Media 音频 + Windows Media 音訊 + + + + + + Musepack audio + Musepack سمعي + AÅ­dyjo Musepack + Ðудио — Musepack + àudio Musepack + Zvuk Musepack + Musepacklyd + Musepack-Audio + ήχος Musepack + Musepack audio + sonido Musepack + Musepack audioa + Musepack-ääni + Musepack ljóður + audio Musepack + fuaim Musepack + son de Musepack + שמע של Musepack + Musepack audio + Musepack hang + Audio Musepack + Audio Musepack + Musepack オーディオ + Musepack аудиоÑÑ‹ + Musepack 오디오 + Musepack garso įraÅ¡as + Musepack audio + Musepack-lyd + Musepack-audio + Musepack-lyd + Plik dźwiÄ™kowy Musepack + Ãudio Musepack + Audio Musepack + аудио Musepack + Zvuk Musepack + ZvoÄna datoteka Musepack + Audio Musepack + Musepack-ljud + звук Musepack + Âm thanh Musepack + Musepack 音频 + Musepack 音訊 + + + + + + + + + RealAudio document + مستند RealAudio + Dakument RealAudio + Документ — RealAudio + document RealAudio + Dokument RealAudio + RealAudio-dokument + RealAudio-Dokument + έγγÏαφο RealAudio + RealAudio document + RealAudio-dokumento + documento RealAudio + RealAudio dokumentua + RealAudio-asiakirja + RealAudio skjal + document RealAudio + cáipéis RealAudio + documento Realson + מסמך של RealAudio + RealAudio dokument + RealAudio dokumentum + Dokumen RealAudio + Documento RealAudio + RealAudio ドキュメント + RealAudio құжаты + RealAudio 문서 + RealAudio dokumentas + RealAudio dokuments + RealAudio-dokument + RealAudio-document + RealAudio-dokument + Dokument RealAudio + Documento RealAudio + Document RealAudio + документ RealAudio + Dokument RealAudio + Dokument RealAudio + Dokument RealAudio + RealAudio-dokument + документ RealAudio + Tài liệu âm thanh RealAudio + RealAudio 文档 + RealAudio 文件 + + + + + + + RealMedia Metafile + مل٠تعري٠RealMedia + MetafajÅ‚ RealMedia + Метафайл — RealMedia + metafitxer RealMedia + RealMedia Metafile + RealMedia-metafil + RealMedia-Metadatei + Metafile RealMedia + RealMedia Metafile + metarchivo RealMedia + RealMedia metafitxategia + RealMedia-metatiedosto + RealMedia metafíla + métafichier RealMedia + meiteachomhad RealMedia + Metaficheiro RealMedia + קובץ ×ž×˜× ×©×œ RealMedia + RealMedia metafájl + RealMedia Metafile + Metafile RealMedia + RealMedia メタファイル + RealMedia метафайлы + RealMedia ë©”íƒ€íŒŒì¼ + RealMedia metafailas + RealMedia metadatne + RealMedia-metafil + RealMedia-metabestand + RealMedia-metafil + Metaplik RealMedia + Meta arquivo do RealMedia + MetafiÈ™ier RealMedia + мета-файл RealMedia + RealMedia Metafile + Metadatoteka RealMedia + Metafile RealMedia + RealMedia-metafil + метафайл RealMedia + Siêu tập tin RealMedia + RealMedia 元文件 + RealMedia 中介檔 + + + + RealVideo document + مستند RealVideo + Dakument RealVideo + Документ — RealVideo + document RealVideo + Dokument RealVideo + RealAudio-dokument + RealVideo-Dokument + έγγÏαφο RealVideo + RealVideo document + RealVideo-dokumento + documento RealVideo + RealVideo dokumentua + RealVideo-asiakirja + RealVideo skjal + document RealVideo + cáipéis RealVideo + documento RealVideo + מסמך של RealVideo + RealVideo dokument + RealVideo dokumentum + Dokumen RealVideo + Documento RealVideo + RealVideo ドキュメント + RealVideo құжаты + RealVideo 문서 + RealVideo dokumentas + RealVideo dokuments + RealAudio-dokument + RealVideo-document + RealVideo-dokument + Dokument RealVideo + Documento RealVideo + Document RealVideo + документ RealVideo + Dokument RealVideo + Video datoteka RealVideo + Dokument RealVideo + RealVideo-dokument + документ RealVideo + Tài liệu ảnh Ä‘á»™ng RealVideo + RealAudio 文档 + RealVideo 文件 + + + + + + RealMedia document + مستند RealMedia + Dakument RealMedia + Документ — RealMedia + document RealMedia + Dokument RealMedia + RealMedia-dokument + RealMedia-Dokument + έγγÏαφο RealMedia + RealMedia document + RealMedia-dokumento + documento RealMedia + RealMedia dokumentua + RealMedia-asiakirja + RealMedia skjal + document RealMedia + cáipéis RealMedia + documento RealMedia + מסמך של RealMedia + RealMedia dokument + RealMedia dokumentum + Dokumen RealMedia + Documento RealMedia + RealMedia ドキュメント + RealMedia құжаты + RealMedia 문서 + RealMedia dokumentas + RealMedia dokuments + RealMedia-dokument + RealMedia-document + RealMedia-dokument + Dokument RealMedia + Documento RealMedia + Document RealMedia + документ RealMedia + Dokument RealMedia + Dokument RealMedia + Dokument RealMedia + RealMedia-dokument + документ RealMedia + Tài liệu RealMedia + RealMedia 文档 + RealMedia 文件 + + + + + + + + + + + + + RealPix document + مستند RealPix + Dakument RealPix + Документ — RealPix + document RealPix + Dokument RealPix + RealPix-dokument + RealPix-Dokument + έγγÏαφο RealPix + RealPix document + RealPix-dokumento + documento RealPix + RealPix dokumentua + RealPix-asiakirja + RealPix skjal + document RealPix + cáipéis RealPix + documento RealPix + מסמך של RealPix + RealPix dokument + RealPix dokumentum + Dokumen RealPix + Documento RealPix + RealPix ドキュメント + RealPix құжаты + RealPix 문서 + RealPix dokumentas + RealPix dokuments + RealPix-dokument + RealPix-document + RealPix-dokument + Dokument RealPix + Documento RealPix + Document RealPix + документ RealPix + Dokument RealPix + Dokument RealPix + Dokument RealPix + RealPix-dokument + документ RealPix + Tài liệu ảnh RealPix + RealPix 文档 + RealPix 文件 + + + + RealText document + مستند RealText + Dakument RealText + Документ — RealText + document RealText + Dokument RealText + RealText-dokument + RealText-Dokument + έγγÏαφο RealText + RealText document + RealText-dokumento + documento RealText + RealText dokumentua + RealText-asiakirja + RealText skjal + document RealText + cáipéis RealText + documento RealText + מסמך של RealText + RealText dokument + RealText dokumentum + Dokumen RealText + Documento RealText + RealText ドキュメント + RealText құжаты + RealText 문서 + RealText dokumentas + RealText dokuments + RealText-dokument + RealText-document + RealText-dokument + Dokument RealText + Documento RealText + Document RealText + документ RealText + Dokument RealText + Dokument RealText + Dokument RealText + RealText-dokument + документ RealText + Tài liệu văn bản RealText + RealText 文档 + RealText 文件 + + + + RIFF audio + RIFF سمعي + RIFF audio faylı + AÅ­dyjo RIFF + Ðудио — RIFF + àudio RIFF + Zvuk RIFF + Sain RIFF + RIFF-lyd + RIFF-Audio + ήχος RIFF + RIFF audio + RIFF-sondosiero + sonido RIFF + RIFF audioa + RIFF-ääni + RIFF ljóð + audio RIFF + fuaim RIFF + son RIFF + שמע RIFF + RIFF audio + RIFF-kép + Audio RIFF + Audio RIFF + RIFF オーディオ + RIFF аудиоÑÑ‹ + RIFF 오디오 + RIFF garso įraÅ¡as + RIFF audio + Audio RIFF + RIFF-lyd + RIFF-audio + RIFF-lyd + Plik dźwiÄ™kowy RIFF + áudio RIFF + Ãudio RIFF + Audio RIFF + аудио RIFF + Zvuk RIFF + ZvoÄna datoteka RIFF + Audio RIFF + RIFF звучни Ð·Ð°Ð¿Ð¸Ñ + RIFF-ljud + звук RIFF + Âm thanh RIFF + RIFF 音频 + RIFF 音訊 + + + + + + + Scream Tracker 3 audio + Scream Tracker 3 سمعي + Scream Tracker 3 audio faylı + AÅ­dyjo Scream Tracker 3 + Ðудио — Scream Tracker 3 + àudio de Scream Tracker 3 + Skladba Scream Tracker 3 + Sain Scream Tracker 3 + Scream Tracker 3-lyd + Scream-Tracker-3-Audio + ήχος Scream Tracker 3 + Scream Tracker 3 audio + Sondosiero de Scream Tracker 3 + sonido Scream Tracker 3 + Scream Tracker 3 audioa + Scream Tracker 3 -ääni + Scream Tracker 3 ljóður + audio Scream Tracker 3 + fuaim Scream Tracker 3 + son Scream Tracker 3 + שמע של Scream Tracker 3 + Scream Tracker 3 audio + Scream Tracker 3 hang + Audio Scream Tracker 3 + Audio Scream Tracker 3 + Scream Tracker 3 オーディオ + Scream Tracker 3 аудиоÑÑ‹ + Scream Tracker 3 오디오 + Scream Tracker 3 garso įraÅ¡as + Scream Tracker 3 audio + Audio Scream Tracker 3 + Scream Tracker 3-lyd + Scream Tracker 3-audio + Sream Tracker 3 lyd + Plik dźwiÄ™kowy Scream Tracker 3 + áudio Scream Tracker 3 + Ãudio Scream Tracker 3 + Audio Scream Tracker 3 + аудио Scream Tracker 3 + Skladba Scream Tracker 3 + ZvoÄna datoteka Scream Tracker 3 + Audio Scream Tracker 3 + Scream Tracker 3 звучни Ð·Ð°Ð¿Ð¸Ñ + Scream Tracker 3-ljud + звук Scream Tracker 3 + Âm thanh Scream Tracker 3 + Scheme Tracker 3 音频 + Scream Tracker 3 音訊 + + + + + + + MP3 ShoutCast playlist + قائمة تشغيل MP3 ShoutCast + Åšpis piesieÅ„ dla tranÅ›lacyi MP3 + СпиÑък за изпълнение — MP3 ShoutCast + llista de reproducció MP3 ShoutCast + Seznam skladeb MP3 ShoutCast + MP3 ShoutCast-afspilningsliste + MP3-ShoutCast-Wiedergabeliste + Λίστα αναπαÏαγωγής MP3 ShoutCast + MP3 ShoutCast playlist + MP3-ludlisto de ShoutCast + lista de reproducción MP3 ShoutCast + MP3 ShoutCast erreprodukzio-zerrenda + MP3 ShoutCast -soittolista + MP3 ShoutCast avspælingarlisti + liste de lecture MP3 ShoutCast + seinmliosta MP3 ShoutCast + lista de reprodución MP3 de ShoutCast + רשימת השמעה MP3 של ShoutCast + MP3 ShoutCast popis za reprodukciju + MP3 ShoutCast-lejátszólista + Senarai putar MP3 ShoutCast + Scaletta MP3 ShoutCast + MP3 ShoutCast å†ç”Ÿãƒªã‚¹ãƒˆ + MP3 ShoutCast ойнау тізімі + MP3 ShoutCast ìž¬ìƒ ëª©ë¡ + MP3 ShoutCast grojaraÅ¡tis + MP3 ShoutCast repertuÄrs + Senaraimain ShoutCast MP3 + MP3 ShoutCast-spilleliste + MP3 ShoutCast-afspeellijst + MP3 ShoutCast-speleliste + Lista odtwarzania MP3 ShoutCast + lista de reprodução MP3 ShoutCast + Lista de reprodução MP3 ShoutCast + Listă MP3 ShoutCast + ÑпиÑок воÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ MP3 ShoutCast + Zoznam skladieb MP3 ShoutCast + Seznam predvajanja MP3 ShoutCast + Listë titujsh MP3 ShoutCast + MP3 ShoutCast ÑпиÑак пеÑама + MP3 ShoutCast-spellista + ÑпиÑок Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð²Ð°Ð½Ð½Ñ MP3 ShoutCast + Danh mục nhạc MP3 ShoutCast + MP3 ShoutCast 播放列表 + MP3 ShoutCast 播放清單 + + + + + + + + + + Scream Tracker audio + Scream Tracker سمعي + Scream Tracker audio faylı + AÅ­dyjo Scream Tracker + Ðудио — Scream Tracker + àudio de Scream Tracker + Skladba Scream Tracker + Sain Scream Tracker + Scream Tracker-lyd + Scream-Tracker-Audio + ήχος Scream Tracker + Scream Tracker audio + Sondosiero de Scream Tracker + sonido Scream Tracker + Scream Tracker audioa + Scream Tracker -ääni + Scream Tracker ljóður + audio Scream Tracker + fuaim Scream Tracker + son Scream Tracker + שמע של Scream Tracker + Scream Tracker audio + Scream Tracker hang + Audio Scream Tracker + Audio Scream Tracker + Scream Tracker オーディオ + Scream Tracker аудиоÑÑ‹ + Scream Tracker 오디오 + Scream Tracker garso įraÅ¡as + Scream Tracker audio + Audio Scream Tracker + Scream Tracker-lyd + Scream Tracker-audio + Scream Tracker lyd + Plik dźwiÄ™kowy Scream Tracker + áudio Scream Tracker + Ãudio Scream Tracker + Audio Scream Tracker + аудио Scream Tracker + Skladba Scream Tracker + ZvoÄna datoteka Scream Tracker + Audio Scream Tracker + Scream Tracker звучни Ð·Ð°Ð¿Ð¸Ñ + Scream Tracker-ljud + звук Scream Tracker + Âm thanh Scream Tracker + Scream Tracker 音频 + Scream Tracker 音訊 + + + + + + + + + VOC audio + VOC سمعي + VOC audio faylı + AÅ­dyjo VOC + Ðудио — VOC + àudio VOC + Zvuk VOC + Sain VOC + VOC-lyd + VOC-Audio + ήχος VOC + VOC audio + VOC-sondosiero + sonido VOC + VOC audioa + VOC-ääni + VOC ljóður + audio VOC + fuaim VOC + son VOC + שמע VOC + VOC audio + VOC hang + Audio VOC + Audio VOC + VOC オーディオ + VOC аудиоÑÑ‹ + VOC 오디오 + VOC garso įraÅ¡as + VOC audio + Audio VOC + VOC-lyd + VOC-audio + VOC-lyd + Plik dźwiÄ™kowy VOC + áudio VOC + Ãudio VOC + Audio VOC + аудио VOC + Zvuk VOC + ZvoÄna datoteka VOC + Audio VOC + VOC звучни Ð·Ð°Ð¿Ð¸Ñ + VOC-ljud + звук VOC + Âm thanh VOC + VOC 音频 + VOC 音訊 + + + + WAV audio + WAV سمعي + WAV audio faylı + AÅ­dyjo WAV + Ðудио — WAV + àudio WAV + Zvuk WAV + Sain WAV + WAV-lyd + WAV-Audio + ήχος WAV + WAV audio + WAV-sonkodo + sonido WAV + WAV audioa + WAV-ääni + WAV ljóður + audio WAV + fuaim WAV + son WAV + שמע WAV + WAV audio + WAV hang + Audio WAV + Audio WAV + WAV オーディオ + WAV аудиоÑÑ‹ + WAV 오디오 + WAV garso įraÅ¡as + WAV audio + Audio VOC + WAV-lyd + WAV-audio + WAV-lyd + Plik dźwiÄ™kowy WAV + áudio WAV + Ãudio WAV + Audio WAV + аудио WAV + Zvuk WAV + ZvoÄna datoteka WAV + Audio WAV + WAV звучни Ð·Ð°Ð¿Ð¸Ñ + WAV-ljud + звук WAV + Âm thanh WAV + WAV 音频 + WAV 音訊 + + + + + + + + + + Scream Tracker instrument + آلة Scream Tracker + Scream Tracker instrumenti + Instrument Scream Tracker + ИнÑтрумент — Scream Tracker + instrument de Scream Tracker + Nástroj pro Scream Tracker + Offeryn Scream Tracker + Scream Tracker-instrument + Scream-Tracker-Instrument + μουσικό ÏŒÏγανο Scream Tracker + Scream Tracker instrument + instrumento de Scream Tracker + instrumento Scream Tracker + Scream Tracker instrumentua + Scream Tracker -soitin + Scream Tracker ljóðføri + instrument Scream Tracker + ionstraim Scream Tracker + Instrumento Scream Tracker + כלי של Scream Tracker + Scream Tracker instrument + Scream Tracker hangszer + Instrumen Scream Tracker + Strumento Scream Tracker + Scream Tracker インストゥルメント + Scream Tracker Ñайманы + Scream Tracker 악기 + Scream Tracker instrumentas + Scream Tracker instrumenti + Instrumen Scream Tracker + Scream Tracker-instrument + Scream Tracker-instrument + Scream Tracker instrument + Instrument Scream Tracker + instrumento Scream Tracker + Instrumento Scream Tracker + Instrument Scream Tracker + инÑтрумент Scream Tracker + Nástroj pre Scream Tracker + Datoteka zvoka glasbila Scream Tracker + Instrument Scream Tracker + Scream Tracker инÑтрумент + Scream Tracker-instrument + інÑтрумент Scream Tracker + Nhạc khí Scream Tracker + Scream Tracker ä¹å™¨ + Scream Tracker 樂器檔 + + + + + + + FastTracker II audio + FastTracker II سمعي + FastTracker II audio faylı + AÅ­dyjo FastTracker II + Ðудио — FastTracker II + àudio de FastTracker II + Zvuk FastTracker II + Sain FastTracker II + FastTracker II-lyd + FastTracker-II-Audio + ήχος FastTracker II + FastTracker II audio + Sondosiero de FastTracker II + sonido FastTracker II + FastTracker II.ren audioa + FastTracker II -ääni + FastTracker II ljóður + audio FastTracker II + fuaim FastTracker II + son de FastTracker II + שמע FastTracker II + FastTracker II audio + FastTracker II hang + Audio FastTracker II + Audio FastTracker II + FastTracker II オーディオ + FastTracker II-ის áƒáƒ£áƒ“ირ+ FastTracker II аудиоÑÑ‹ + FastTracker II 오디오 + FastTracker II garso įraÅ¡as + FastTracker II audio + Audio FastTracker II + FastTracker II-lyd + FastTracker II-audio + FastTracker II lyd + Plik dźwiÄ™kowy FastTracker II + áudio FastTracker II + Ãudio FastTracker II + Audio FastTracker II + аудио FastTracker II + Zvuk FastTracker II + ZvoÄna datoteka FastTracker II + Audio FastTracker II + FastTracker II аудио Ð·Ð°Ð¿Ð¸Ñ + FastTracker II-ljud + звук FastTracker II + Âm thanh FastTracker II + FastTracker II 音频 + FastTracker II 音訊 + + + + + + + TrueAudio audio + TrueAudio سمعي + AÅ­dyjo TrueAudio + Ðудио — TrueAudio + àudio TrueAudio + Zvuk TrueAudio + TrueAudio-lyd + TrueAudio-Audio + ήχος TrueAudio + TrueAudio audio + TrueAudio-sondosiero + sonido TrueAudio + TrueAudio audioa + TrueAudio-ääni + TrueAudio ljóður + audio TrueAudio + fuaim TrueAudio + son Trueson + שמע TrueAudio + TrueAudio audio + TrueAudio hang + Audio TrueAudio + Audio TrueAudio + TrueAudio オーディオ + TrueAudio аудиоÑÑ‹ + TrueAudio 오디오 + TrueAudio garso įraÅ¡as + TrueAudio audio + TrueAudio-lyd + TrueAudio-audio + TrueAudio-lyd + Plik dźwiÄ™kowy TrueAudio + Ãudio TrueAudio + Audio TrueAudio + аудио TrueAudio + Zvuk TrueAudio + ZvoÄna datoteka TrueAudio + Audio TrueAudio + TrueAudio-ljud + звук TrueAudio + Âm thanh TrueAudio + TrueAudio 音频 + TrueAudio 音訊 + + + + + + + + Windows BMP image + صورة Windows BMP + Windows BMP rÉ™smi + Vyjava Windows BMP + Изображение — Windows BMP + imatge BMP de Windows + Obrázek Windows BMP + Delwedd BMP Windows + Windows BMP-billede + Windows-BMP-Bild + εικόνα Windows BMP + Windows BMP image + BMP-bildo de Vindozo + imagen BMP de Windows + Windows BMP irudia + Windows BMP -kuva + Windows BMP mynd + image Windows BMP + íomhá BMP Windows + imaxe BMP de Windows + תמונת BMP של Windows + Windows BMP slika + Windows BMP-kép + Citra Windows BMP + Immagine Windows BMP + Windows BMP ç”»åƒ + Windows BMP Ñуреті + Windows BMP 그림 + Windows BMP paveikslÄ—lis + Windows BMP attÄ“ls + Imej BMP Windows + Windows BMP-bilde + Windows BMP-afbeelding + Windows BMP-bilete + Obraz BMP Windows + imagem BMP Windows + Imagem BMP do Windows + Imagine Windows BMP + изображение Windows BMP + Obrázok Windows BMP + Slikovna datoteka Windows BMP + Figurë Windows BMP + Windows BMP Ñлика + Windows BMP-bild + Windows BMP görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Windows BMP + Ảnh BMP Windows + Windows BMP å›¾åƒ + Windows BMP å½±åƒ + + + + + + + + + + + + + + WBMP image + صورة WBMP + Vyjava WBMP + Изображение — WBMP + imatge WBMP + Obrázek WBMP + WBMP-billede + WBMP-Bild + εικόνα WBMP + WBMP image + WBMP-bildo + imagen WBMP + WBMP irudia + WBMP-kuva + WBMP mynd + image WBMP + íomhá WBMP + imaxe WBMP + תמונת WBMP + WBMP slika + WBMP kép + Citra WBMP + Immagine WBMP + WBMP ç”»åƒ + WBMP Ñуреті + WBMP 그림 + WBMP paveikslÄ—lis + WBMP attÄ“ls + WBMP-bilde + WBMP-afbeelding + WBMP-bilete + Obraz WBMP + Imagem WBMP + Imagine WBMP + изображение WBMP + Obrázok WBMP + Slikovna datoteka WBMP + Figurë WBMP + WBMP-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ WBMP + Ảnh WBMP + WBMP å›¾åƒ + WBMP å½±åƒ + WBMP + WAP bitmap + + + + Computer Graphics Metafile + مل٠تعري٠رسوميات الحاسوب + Kompüter Qrafikası Meta Faylı + MetafajÅ‚ Computer Graphics + Метафайл — Computer Graphics + metafitxer de Computer Graphics + Computer Graphics Metafile + Delwedd ffurf CGM + Computer Graphics-metafil + CGM-Datei + αÏχείο Computer Graphics Metafile + Computer Graphics Metafile + metaarchivo de Computer Graphics + Ordenagailuko grafikoen meta-fitxategia + Computer Graphics -metatiedosto + Teldugrafikk metafíla + métafichier Computer Graphics + meiteachomhad Grafaicí Ríomhaire + metaficheiro de Computer Graphics + קובץ-מטה מסוג Computer Graphics + Computer Graphics-metafájl + Computer Graphics Metafile + Computer Graphics Metafile + コンピューターグラフィックメタファイル + компьютерлік графика метафайлы + 컴퓨터 그래픽스 ë©”íƒ€íŒŒì¼ + Computer Graphics metafailas + Datorgrafikas metadatne + Failmeta Grafik Komputer + Computer Graphics Metafile + Computer Graphics-metabestand + Computer Graphics Metafile + Metaplik grafiki komputerowej (CGM) + Computer Graphics Metafile + Meta-arquivo do Computer Graphics + MetafiÈ™ier Computer Graphics + метафайл компьютерной графики + Computer Graphics Metafile + Metadatoteka raÄunalniÅ¡ke grafike (CGM) + Metafile Computer Graphics + Метадатотека Ñа рачунарÑком графиком (CGM) + Computer Graphics Metafil + метафайл комп'ютерної графіки + Siêu tập tin đồ há»a máy tính (CMF) + CGM 计算机图åƒå…ƒæ–‡ä»¶ + CGM å½±åƒ + + + + CCITT G3 fax + Ùاكس CCITT G3 + Faks CCITT G3 + Ð¤Ð°ÐºÑ â€” CCITT G3 + fax CCITT G3 + Fax CCITT G3 + CCITT G3-fax + CCITT-G3-Fax + φαξ σε μοÏφή CCITT G3 + CCITT G3 fax + G3-fakso de CCITT + fax de CCITT G3 + CCITT G3 faxa + CCITT G3 -faksi + CCITT G3 telefaks + télécopie G3 CCITT + facs CCITT G3 + fax de CCITT G3 + פקס של CCITT G3 + CCITT G3 faks + CCITT G3-fax + Faks CCITT G3 + Fax CCITT G3 + CCITT G3 FAX + CCITT G3 ფáƒáƒ¥áƒ¡áƒ˜ + CCITT G3 факÑÑ– + CCITT G3 팩스 + CCITT G3 faksas + CCITT G3 fakss + Faks g3 CCITT + CCITT G3-faks + CCITT G3-fax + CCITT G3-fax + Faks CCITT G3 + fax CCITT G3 + Fax do CCITT G3 + Fax CCITT G3 + Ñ„Ð°ÐºÑ CCITT G3 + Fax CCITT G3 + Datoteka faksimila CCITT G3 + Fax CCITT G3 + CCITT g3 Ñ„Ð°ÐºÑ + CCITT G3-fax + Ñ„Ð°ÐºÑ CCITT G3 + Äiện thÆ° G3 CCITT + CCITT G3 传真 + CCITT G3 傳真檔 + + + + G3 fax image + صورة Ùاكس G3 + G3 faks rÉ™smi + Faksavaja vyjava G3 + Изображение — Ñ„Ð°ÐºÑ G3 + imatge de fax G3 + Obrázek fax G3 + Delwedd Ffacs G3 + G3-faxbillede + G3-Faxbild + εικόνα φαξ G3 + G3 fax image + G3-faksbildo + imagen de fax G3 + G3 fax-irudia + G3-faksikuva + G3 fax mynd + image de télécopie G3 + íomhá fhacs G3 + imaxe de fax G3 + תמונת פקס של G3 + G3-faxkép + Citra faks G3 + Immagine fax G3 + G3 FAX ç”»åƒ + G3 fax გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ G3 Ñ„Ð°ÐºÑ Ñуреті + G3 팩스 그림 + G3 fax paveikslÄ—lis + G3 faksa attÄ“ls + Imej fax G3 + G3-faksbilde + G3 faxafbeelding + G3 faksbilete + Obraz faksowy G3 + imagem de fax G3 + Imagem de fax G3 + Imagine fax G3 + факÑовое изображение G3 + Obrázok fax G3 + Slikovna datoteka G3 fax + Figurë Fax G3 + G3 Ñ„Ð°ÐºÑ Ñлика + G3-faxbild + G3 fax görüntüsü + Ñ„Ð°ÐºÑ G3 + Ảnh Ä‘iện thÆ° G3 + G3 传真文档 + G3 傳真圖 + + + GIF image + صورة GIF + GIF rÉ™smi + Vyjava GIF + Изображение — GIF + imatge GIF + Obrázek GIF + Delwedd GIF + GIF-billede + GIF-Bild + εικόνα GIF + GIF image + GIF-bildo + imagen GIF + GIF irudia + GIF-kuva + GIF mynd + image GIF + íomhá GIF + imaxe GIF + תמונת GIF + GIF slika + GIF-kép + Citra GIF + Immagine GIF + GIF ç”»åƒ + GIF გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ GIF Ñуреті + GIF 그림 + GIF paveikslÄ—lis + GIF attÄ“ls + Imej GIF + GIF-bilde + GIF-afbeelding + GIF-bilete + Obraz GIF + imagem GIF + Imagem GIF + Imagine GIF + изображение GIF + Obrázok GIF + Slikovna datoteka GIF + Figurë GIF + GIF Ñлика + GIF-bild + GIF görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ GIF + Ảnh GIF + GIF å›¾åƒ + GIF å½±åƒ + + + + + + + IEF image + صورة IEF + IEF rÉ™smi + Vyjava IEF + Изображение — IEF + imatge IEF + Obrázek IEF + Delwedd IEF + IEF-billede + IEF-Bild + εικόνα IEF + IEF image + IEF-bildo + imagen IEF + IEF irudia + IEF-kuva + IEF mynd + image IEF + íomhá IEF + imaxe IEF + תמונת IEF + IEF slika + IEF-kép + Citra IEF + Immagine IEF + IEF ç”»åƒ + IEF Ñуреті + IEF 그림 + IEF paveikslÄ—lis + IEF attÄ“ls + Imej IEF + IEF-bilde + IEF-afbeelding + IEF-bilete + Obraz IEF + imagem IEF + Imagem IEF + Imagine IEF + изображение IEF + Obrázok IEF + Slikovna datoteka IEF + Figurë IEF + IEF Ñлика + IEF-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ IEF + Ảnh IEF + IEF å›¾åƒ + IEF å½±åƒ + + + + JPEG image + صورة JPEG + JPEG rÉ™smi + Vyjava JPEG + Изображение — JPEG + imatge JPEG + Obrázek JPEG + Delwedd JPEG + JPEG-billede + JPEG-Bild + εικόνα JPEG + JPEG image + JPEG-bildo + imagen JPEG + JPEG irudia + JPEG-kuva + JPEG mynd + image JPEG + íomhá JPEG + imaxe JPEG + תמונת JPEG + JPEG slika + JPEG-kép + Citra JPEG + Immagine JPEG + JPEG ç”»åƒ + JPEG Ñуреті + JPEG 그림 + JPEG paveikslÄ—lis + JPEG attÄ“ls + Imej JPEG + JPEG-bilde + JPEG-afbeelding + JPEG-bilete + Obraz JPEG + imagem JPEG + Imagem JPEG + Imagine JPEG + изображение JPEG + Obrázok JPEG + Slikovna datoteka JPEG + Figurë JPEG + JPEG Ñлика + JPEG-bild + JPEG görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ JPEG + Ảnh JPEG + JPEG å›¾åƒ + JPEG å½±åƒ + + + + + + + + + + + JPEG-2000 image + صورة JPEG-2000 + Vyjava JPEG-2000 + Изображение — JPEG-2000 + imatge JPEG-2000 + Obrázek JPEG-2000 + JPEG2000-billede + JPEG-2000-Bild + εικόνα JPEG-2000 + JPEG-2000 image + JPEG-2000-bildo + imagen JPEG-2000 + JPEG-2000 irudia + JPEG-2000-kuva + JPEG-2000 mynd + image JPEG-2000 + íomhá JPEG-2000 + imaxe JPEG-2000 + תמונת JPEG-2000 + JPEG-2000 slika + JPEG-2000 kép + Citra JPEG-2000 + Immagine JPEG-2000 + JPEG-2000 ç”»åƒ + JPEG-2000 Ñуреті + JPEG-2000 그림 + JPEG-2000 paveikslÄ—lis + JPEG-2000 attÄ“ls + Imej JPEG-2000 + JPEG-2000-bilde + JPEG-2000-afbeelding + JPEG-2000-bilete + Obraz JPEG-2000 + imagem JPEG-2000 + Imagem JPEG-2000 + Imagine JPEG-2000 + изображение JPEG-2000 + Obrázok JPEG-2000 + Slikovna datoteka JPEG-2000 + Figurë JPEG-2000 + JPEG-2000 Ñлика + JPEG-2000-bild + JPEG-2000 görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ JPEG-2000 + Ảnh JPEG-2000 + JPEG-2000 å›¾åƒ + JPEG-2000 å½±åƒ + + + + + + + + + + + + + + + + OpenRaster archiving image + صورة أرشي٠OpenRaster + Изображение — OpenRaster + imatge d'arxivat OpenRaster + ArchivaÄní obraz OpenRaster + OpenRaster-arkivaftryk + OpenRaster-Archivierungsbild + εικόνα αÏχειοθέτησης OpenRaster + OpenRaster archiving image + imagen de archivado de OpenRaster + OpenRaster artxiboaren irudia + OpenRaster goymslumynd + image d'archive OpenRaster + íomhá chartlannaithe OpenRaster + imaxe arquivada de OpenRaster + תמונת ×רכיון של OpenRaster + OpenRaster archiválási kép + Gambar pengarsipan OpenRaster + Immagine archiviazione OpenRaster + OpenRaster アーカイブイメージ + OpenRaster-ის სáƒáƒáƒ áƒ¥áƒ˜áƒ•áƒ გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ OpenRaster архивтеу Ñуреті + OpenRaster 압축 ì´ë¯¸ì§€ + OpenRaster archyvavimo paveikslÄ—lis + OpenRaster arhivÄ“Å¡anas attÄ“ls + OpenRaster archiverings-image + Archiwalny obraz OpenRaster + Imagem de arquivamento OpenRaster + Arhivă imagine OpenRaster + архивное изображение OpenRaster + Odtis arhiva OpenRaster + OpenRaster-arkivbild + архівоване Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ OpenRaster + OpenRaster å½’æ¡£æ˜ åƒ + OpenRaster å°å­˜å½±åƒ + + + + + + + + + + + DirectDraw surface + مساحة DirectDraw + Pavierchnia DirectDraw + Изображение — повърхноÑÑ‚ на DirectDraw + superfície DirectDraw + Plocha DirectDraw + DirectDraw-overflade + DirectDraw-Oberfläche + επιφάνεια DirectDraw + DirectDraw surface + superficie DirectDraw + DirectDraw gainazala + DirectDraw-piirtoalue + DirectDraw yvirflata + surface DirectDraw + dromchla DirectDraw + superficie de DirectDraw + משטח של DirectDraw + DirectDraw ploha + DirectDraw felület + Permukaan DirectDraw + Superficie DirectDraw + DirectDraw サーフェイス + DirectDraw-ის ზედáƒáƒžáƒ˜áƒ áƒ˜ + DirectDraw жазықтығы + DirectDraw 서피스 + DirectDraw pavirÅ¡ius + DirectDraw virsma + DirectDraw-overflate + DirectDraw-oppervlak + DirectDraw-overflate + Powierzchnia DirectDraw + Superfície do DirectDraw + Suprafață DirectDraw + плоÑкоÑÑ‚ÑŒ DirectDraw + Plocha DirectDraw + Datoteka predmeta DirectDraw + Superfaqe DirectDraw + DirectDraw-yta + Ð¿Ð¾Ð²ÐµÑ€Ñ…Ð½Ñ DirectDraw + Mặt DirectDraw + DirectDraw è¡¨é¢ + DirectDraw è¡¨é¢ + + + + + + + X11 cursor + مؤشر X11 + Kursor X11 + КурÑор — X11 + cursor X11 + Kurzor X11 + X11-markør + X11-Zeiger + δείκτης X11 + X11 cursor + cursor X11 + X11 kurtsorea + X11-osoitin + X11 vísi + curseur X11 + cúrsóir X11 + Cursor X11 + סמן של X11 + X11 kursor + X11 kurzor + Kursor X11 + Cursore X11 + X11 カーソル + X11 курÑоры + X11 커서 + X11 žymiklis + X11 kursors + X11-markør + X11-muisaanwijzer + X11-peikar + Kursor X11 + Cursor do X11 + Cursor X11 + курÑор X11 + Kurzor X11 + Datoteka kazalke X11 + Kursor X11 + X11-muspekare + курÑор X11 + Con chạy X11 + X11 指针 + X11 滑鼠游標 + + + + + + EXR image + صورة EXR + Vyjava EXR + Изображение — EXR + imatge EXR + Obrázek EXR + EXR-billede + EXR-Bild + εικόνα EXR + EXR image + EXR-bildo + imagen EXR + EXR irudia + EXR-kuva + EXR mynd + image EXR + íomhá EXR + imaxe EXR + תמונת EXR + EXR slika + EXR kép + Citra EXR + Immagine EXR + EXR ç”»åƒ + EXR გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ EXR Ñуреті + EXR 그림 + EXR paveikslÄ—lis + EXR attÄ“ls + EXR-bilde + EXR-afbeelding + EXR-bilete + Obraz EXR + Imagem EXR + Imagine EXR + изображение EXR + Obrázok EXR + Slikovna datoteka EXR + Figurë EXR + EXR-bild + EXR görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ EXR + Ảnh EXR + EXR å›¾åƒ + EXR å½±åƒ + + + + + + + Macintosh Quickdraw/PICT drawing + رسمة ماكنتوش Quickdraw/PICT + Rysunak Macintosh Quickdraw/PICT + Чертеж — Macintosh Quickdraw/PICT + dibuix Quickdraw/PICT de Macintosh + Kresba Macintosh Quickdraw/PICT + Macintosh Quickdraw/PICT-tegning + Macintosh-Quickdraw/PICT-Zeichnung + σχέδιο Macintosh Quickdraw/PICT + Macintosh Quickdraw/PICT drawing + Quickdraw/PICT-grafikaĵo de Macintosh + dibujo de Macintosh Quickdraw/PICT + Macintosh Quickdraw/PICT marrazkia + Macintosh Quickdraw/PICT -piirros + Macintosh Quickdraw/PICT tekning + dessin Macintosh Quickdraw/PICT + líníocht Macintosh Quickdraw/PICT + debuxo de Macintosh Quickdraw/PICT + ציור של Macintosh Quickdraw/PICT + Macintosh Quickdraw/PICT crtež + Macintosh Quickdraw/PICT-rajz + Gambar Macintosh Quickdraw/PICT + Disegno Macintosh Quickdraw/PICT + Macintosh Quickdraw/PICT ドロー + Macintosh Quickdraw/PICT Ñуреті + 매킨토시 Quickdraw/PICT 그림 + Macintosh Quickdraw/PICT pieÅ¡inys + Macintosh Quickdraw/PICT zÄ«mÄ“jums + Lukisan Macintosh Quickdraw/PICT + Macintosh Quickdraw/PICT-tegning + Macintosh Quickdraw/PICT-tekening + Macintosh Quickdraw/PICT-teikning + Rysunek Quickdraw/PICT Macintosh + desenho Quickdraw/PICT de Macintosh + Desenho do Macintosh Quickdraw/PICT + Desen Macintosh Quickdraw/PICT + риÑунок Macintosh Quickdraw/PICT + Kresba Macintosh QuickDraw/PICT + Datoteka risbe Macintosh Quickdraw/PICT + Vizatim Macintosh Quickdraw/PICT + Мекинтош Quickdraw/PICT цртеж + Macintosh Quickdraw/PICT-teckning + малюнок Macintosh Quickdraw/PICT + Bản vẽ Quickdraw/PICT của Macintosh + Macintosh Quickdraw/PICT 绘图 + Macintosh Quickdraw/PICT 繪圖 + + + + + + + + + + + + + + + + + + + + + + + + + UFRaw ID image + صورة UFRaw ID + Vyjava UFRaw ID + Изображение — UFRaw ID + imatge ID UFRaw + Obrázek ID UFRaw + UFRaw ID-billede + UFRaw-Bildbeschreibungsdatei + ταυτότητα UFRaw + UFRaw ID image + imagen de identificación UFRaw + UFRaw ID irudia + UFRaw ID -kuva + UFRaw ID mynd + image ID UFRaw + íomhá aitheantais UFRaw + imaxe de identificación UFRaw + תמונה של UFRaw ID + UFRaw azonosítófájl + Citra UFRaw ID + Immagine UFRaw ID + UFRaw ID イメージ + UFRaw ID Ñуреті + UFRaw ID 그림 + UFRaw ID paveikslÄ—lis + UFRaw ID attÄ“ls + UFRaw ID-bilde + UFRaw ID-afbeelding + UFRaw ID-bilete + Obraz UFRaw ID + Imagem ID do UFRaw + ID imagine UFRaw + изображение UFRaw ID + Obrázok ID UFRaw + Slikovna datoteka UFRaw ID + Figurë UFRaw ID + UFRaw ID-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ UFRaw ID + Ảnh ID UFRaw + UFRaw ID å›¾åƒ + UFRaw ID å½±åƒ + UFRaw + Unidentified Flying Raw + + + + + + digital raw image + صورة رقمية خامة + suvoraja liÄbavaja vyjava + Изображение — digital raw + imatge digital en cru + Digitální surový obrázek + digitalt rÃ¥billede + Digitales Rohbild + ανεπεξέÏγαστη ψηφιακή εικόνα + digital raw image + imagen digital en bruto + irudi gordin digitala + digitaalinen raakakuva + talgild rámynd + image brute numérique + amhíomhá digiteach + imaxe en bruto dixital + תמונה דיגטלית גולמית + digitális nyers kép + citra mentah digital + Immagine raw digitale + デジタル raw ç”»åƒ + өңделмеген Ñандық Ñуреттер + 디지털 ì›ë³¸ ì´ë¯¸ì§€ + skaitmeninis neapdorotas paveikslÄ—lis + digitÄls jÄ“lattÄ“ls + digitalt raw-bilde + onbewerkt digitaal beeld + digitalt rÃ¥bilete + Surowy obraz cyfrowy + Imagem digital bruta + imagine digitală brută + необработанные цифровые Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ + Digitálny surový obrázok + surova digitalna slika + Figurë raw dixhitale + digital rÃ¥bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ñ†Ð¸Ñ„Ñ€Ð¾Ð²Ð¾Ð³Ð¾ негатива + ảnh thô số + æ•°å­—åŒ–åŽŸå§‹å›¾åƒ + 數ä½åŽŸç”Ÿå½±åƒ + + + Adobe DNG negative + Adobe DNG negative + Adobe DNG Negative + Изображение — Adobe DNG negative + negatiu DNG d'Adobe + Adobe Digital Negative (DNG) + Adobe DNG-negativ + Adobe Digitales Negativ + αÏÎ½Î·Ï„Î¹ÎºÎ¿Ì Adobe DNG + Adobe DNG negative + negativo digital de Adobe (ADN) + Adobe DNG negatiboa + Adobe-DNG-negatiivi + Adobe DNG negativ + négatif DNG Adobe + claonchló DNG Adobe + negativo DNG de Adobe + תשליל Adobe DNG + Adobe DNG negativ + Adobe DNG negatív + Negatif Adobe DNG + Negativo Adobe DNG + Adobe DNG ãƒã‚¬ + Adobe DNG-ის ნეგáƒáƒ¢áƒ˜áƒ•áƒ˜ + Adobe DNG негативі + ì–´ë„비 DNG 네거티브 + Adobe DNG negatyvas + Adobe DNG negatÄ«vs + Adobe DNG-negativ + Adobe DNG-negatief + Adobe DNG-negativ + Negatyw DNG Adobe + Negativo DNG da Adobe + Negativ Adobe DNG + негатив Adobe DNG + Adobe Digital Negative (DNG) + Datoteka negativa Adobe DNG + Negativ Adobe DNG + Adobe DNG-negativ + цифровий негатив DNG Adobe + Âm bản Adobe DNG + Adobe DNG 负片 + Adobe DNG 負片 + DNG + Digital Negative + + + + + + + + Canon CRW raw image + صورة Canon CRW خامة + Suvoraja vyjava Canon CRW + Изображение — Canon CRW raw + imatge en cru de Canon CRW + Surový obrázek Canon CRW + Canon CRW-rÃ¥billede + Canon-CRW-Rohbild + ανεπεξεÌÏγαστη εικοÌνα Canon CRW + Canon CRW raw image + imagen en bruto CRW de Canon + Canon CRW irudi gordina + Canon-CRW-raakakuva + Canon CRW rámynd + image brute CRW Canon + amhíomhá Canon CRW + imaxe en bruto de Canon CRW + תמונה גולמית של Canon CRW + Canon CRW nyers kép + Citra mentah Canon CRW + Immagine raw Canon CRW + Canon CRW raw ç”»åƒ + Canon CRW raw გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ Canon CRW өңделмеген Ñуреті + ìºë…¼ CRW ì›ë³¸ ì´ë¯¸ì§€ + Canon CRW neapdorotas paveikslÄ—lis + Canon CRW jÄ“lattÄ“ls + Canon CRW raw-bilde + onbewerkt Canon CRW-beeld + Canon CRW rÃ¥bilete + Surowy obraz CRW Canon + Imagem bruta CRW da Canon + Imagine brută Canon CRW + необработанное изображение Canon CRW + Surový obrázok Canon CRW + Surova slikovna datoteka Canon CRW + Figurë raw Canon CRW + Canon CRW-rÃ¥bild + цифровий негатив CRW Canon + Ảnh thô Canon CRW + Canon CRW åŽŸå§‹å›¾åƒ + Canon CRW åŽŸç”Ÿå½±åƒ + CRW + Canon RaW + + + + + + + + + Canon CR2 raw image + صورة Canon CR2 خامة + Suvoraja vyjava Canon CR2 + Изображение — Canon CR2 raw + imatge en cru de Canon CR2 + Surový obrázek Canon CR2 + Canon CR2-rÃ¥billede + Canon-CR2-Rohbild + ανεπεξέÏγαστη εικόνα Canon CR2 + Canon CR2 raw image + imagen en bruto CR2 de Canon + Canon CR2 irudi gordina + Canon-CR2-raakakuva + Canon CR2 rámynd + image brute CR2 Canon + amhíomhá Canon CR2 + imaxe en bruto de Canon CR2 + תמונה גולמית של Canon CR2 + Canon CR2 nyers kép + Citra mentah Canon CR2 + Immagine raw Canon CR2 + Canon CR2 raw ç”»åƒ + Canon CR2 raw გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ Canon CR2 өңделмеген Ñуреті + ìºë…¼ CR2 ì›ë³¸ ì´ë¯¸ì§€ + Canon CR2 neapdorotas paveikslÄ—lis + Canon CR2 jÄ“lattÄ“ls + Canon CR2 raw-bilde + onbewerkt Canon CR2-beeld + Canon CR2 rÃ¥bilete + Surowy obraz CR2 Canon + Imagem bruta CR2 da Canon + Imagine brută Canon CR2 + необработанное изображение Canon CR2 + Surový obrázok Canon CR2 + Surova slikovna datoteka Canon CR2 + Figurë raw Canon CR2 + Canon CR2-rÃ¥bild + цифровий негатив CR2 Canon + Ảnh thô Canon CR2 + Canon CR2 åŽŸå§‹å›¾åƒ + Canon CR2 åŽŸç”Ÿå½±åƒ + CR2 + Canon Raw 2 + + + + + + Fuji RAF raw image + صورة Fuji RAF خامة + Suvoraja vyjava Fuji RAF + Изображение — Fuji RAF raw + imatge en cru de Fuji RAF + Surový obrázek Fuji RAF + Fuji RAF-rÃ¥billede + Fuji-RAF-Rohbild + ανεπεξεÌÏγαστη εικοÌνα Fuji RAF + Fuji RAF raw image + imagen en bruto RAF de Fuji + Fuji RAF irudi gordina + Fuji-RAF-raakakuva + Fuji RAF raw mynd + image brute RAF Fuji + amhíomhá Fuji RAF + imaxe en bruto de Fuji RAF + תמונה גולמית של Fuji RAF + Fuji RAF nyers kép + Citra mentah Fuji RAF + Immagine raw Fuji RAF + Fuji RAF raw ç”»åƒ + Fuji RAF-ის raw გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ Fuji RAF өңделмеген Ñуреті + 후지 RAF ì›ë³¸ ì´ë¯¸ì§€ + Fuji RAF neapdorotas paveikslÄ—lis + Fuji RAF jÄ“lattÄ“ls + Fuji RAF raw-bilde + onbewerkt Fuji RAF-beeld + Fuji RAF rÃ¥tt bilete + Surowy obraz RAF Fuji + Imagem bruta RAF da Fuji + Imagine brută Fuji RAF + необработанное изображение Fuji RAF + Surový obrázok Fuji RAF + Surova slikovna datoteka Fuji RAF + Figurë raw Fuji RAF + Fuji RAF-rÃ¥bild + Цифровий негатив RAF Fuji + Ảnh thô Fuji RAF + 富士RAF åŽŸå§‹å›¾åƒ + Fuji RAF åŽŸç”Ÿå½±åƒ + RAF + RAw Format + + + + + + + + Kodak DCR raw image + صورة Kodak DCR خامة + Suvoraja vyjava Kodak DCR + Изображение — Kodak DCR raw + imatge en cru de Kodak DCR + Surový obrázek Kodak DCR + Kodak DCR-rÃ¥billede + Kodak-DCR-Rohbild + ανεπεξέÏγαστη εικόνα Kodak DCR + Kodak DCR raw image + imagen en bruto DCR de Kodak + Kodak DCR irudi gordina + Kodak-DCR-raakakuva + Kodak DCR rámynd + image brute DCR Kodak + amhíomhá Kodak DCR + imaxe en bruto de Kodad DCR + תמונה גולמית של Kodak DCR + Kodak DCR nyers kép + Citra mentah Kodak DCR + Immagine raw Kodak DCR + Kodak DCR raw ç”»åƒ + Kodak DCR өңделмеген Ñуреті + 코닥 DCR ì›ë³¸ ì´ë¯¸ì§€ + Kodak DCR neapdorotas paveikslÄ—lis + Kodak DCR jÄ“lattÄ“ls + Kodak DCR raw-bilde + onbewerkt Kodak DCR-beeld + Kodak DCR rÃ¥bilete + Surowy obraz DCR Kodak + Imagem bruta DCR da Kodak + Imagine brută Kodak DCR + необработанное изображение Kodak DCR + Surový obrázok Kodak DCR + Surova slikovna datoteka Kodak DCR + Figurë raw Kodak DCR + Kodak DCR-rÃ¥bild + цифровий негатив DCR Kodak + Ảnh thô Kodak DCR + Kodak DCR åŽŸå§‹å›¾åƒ + Kodak DCR åŽŸç”Ÿå½±åƒ + DCR + Digital Camera Raw + + + + + + Kodak K25 raw image + صورة Kodak K25 خامة + Suvoraja vyjava Kodak K25 + Изображение — Kodak K25 raw + imatge en cru de Kodak K25 + Surový obrázek Kodak K25 + Kodak K25-rÃ¥billede + Kodak-K25-Rohbild + ανεπεξεÌÏγαστη εικοÌνα Kodak K25 + Kodak K25 raw image + imagen en bruto K25 de Kodak + Kodak K25 raw image + Kodak-K25-raakakuva + Kodak K25 rámynd + image brute K25 Kodak + amhíomhá Kodak K25 + imaxe en bruto de Kodad K25 + תמונה גולמית של Kodak K25 + Kodak K25 nyers kép + Citra mentah Kodak K25 + Immagine raw Kodak K25 + Kodak K25 raw ç”»åƒ + Kodak K25 өңделмеген Ñуреті + 코닥 K25 ì›ë³¸ ì´ë¯¸ì§€ + Kodak K25 neapdorotas paveikslÄ—lis + Kodak K25 jÄ“lattÄ“ls + Kodak K25 raw-bilde + onbewerkt Kodak K25-beeld + Kodak K25 rÃ¥bilete + Surowy obraz K25 Kodak + Imagem bruta K25 da Kodak + Imagine brută Kodak K25 + необработанное изображение Kodak K25 + Surový obrázok Kodak K25 + Surova slikovna datoteka Kodak K25 + Figurë raw Kodak K25 + Kodak K25-rÃ¥bild + цифровий негатив K25 Kodak + Ảnh thô Kodak K25 + Kodak K25 åŽŸå§‹å›¾åƒ + Kodak K25 åŽŸç”Ÿå½±åƒ + K25 + Kodak DC25 + + + + + + Kodak KDC raw image + صورة Kodak KDC خامة + Suvoraja vyjava Kodak KDC + Изображение — Kodak KDC raw + imatge en cru de Kodak KDC + Surový obrázek Kodak KDC + Kodak KDC-rÃ¥billede + Kodak-KDC-Rohbild + ανεπεξεÌÏγαστη εικοÌνα Kodak KDC + Kodak KDC raw image + imagen en bruto KDC de Kodak + Kodak KDC irudi gordina + Kodak-KDC-raakakuva + Kodak KDC rámynd + image brute KDC Kodak + amhíomhá Kodak KDC + imaxe en bruto de Kodad KDC + תמונה גולמית של Kodak KDC + Kodak KDC nyers kép + Citra mentah Kodak KDC + Immagine raw Kodak KDC + Kodak KDC raw ç”»åƒ + Kodak KDC өңделмеген Ñуреті + 코닥 KDC ì›ë³¸ ì´ë¯¸ì§€ + Kodak KDC neapdorotas paveikslÄ—lis + Kodak KDC jÄ“lattÄ“ls + Kodak KDC raw-bilde + onbewerkt Kodak KDC-beeld + Kodak KDC rÃ¥bilete + Surowy obraz KDC Kodak + Imagem bruta KDC da Kodak + Imagine brută Kodak KDC + необработанное изображение Kodak KDC + Surový obrázok Kodak KDC + Surova slikovna datoteka Kodak KDC + Figurë raw Kodak KDC + Kodak KDC-rÃ¥bild + цифровий негатив KDC Kodak + Ảnh thô Kodak KDC + Kodak KDC åŽŸå§‹å›¾åƒ + Kodak KDC åŽŸç”Ÿå½±åƒ + KDC + Kodak Digital Camera + + + + + + + + + Minolta MRW raw image + صورة Minolta MRW خامة + Suvoraja vyjava Minolta MRW + Изображение — Minolta MRW raw + imatge en cru de Minolta MRW + Surový obrázek Minolta MRW + Minolta MRW-rÃ¥billede + Minolta-MRW-Rohbild + ανεπεξέÏγαστη εικόνα Minolta MRW + Minolta MRW raw image + imagen en bruto MRW de Minolta + Minolta MRW irudi gordina + Minolta-MRW-raakakuva + Minolta MRW rámynd + image brute MRW Minolta + amhíomhá Minolta MRW + imaxe RAW de Minolta MRW + תמונה גולמית של Minolta MRW + Minolta MRW nyers kép + Citra mentah Minolta MRW + Immagine raw Minolta MRW + Minolta MRW raw ç”»åƒ + Minolta MRW өңделмеген Ñуреті + 미놀타 MRW ì›ë³¸ ì´ë¯¸ì§€ + Minolta MRW neapdorotas paveikslÄ—lis + Minolta MRW jÄ“lattÄ“ls + Minolta MRW raw-bilde + onbewerkt Minolta MRW-beeld + Minolta MRW rÃ¥bilete + Surowy obraz MRW Minolta + Imagem bruta MRW do Minolta + Imagine brută Minolta MRW + необработанное изображение Minolta MRW + Surový obrázok Minolta MRW + Surova slikovna datoteka Minolta MRW + Figurë raw Minolta MRW + Minolta MRW-rÃ¥bild + цифровий негатив MRW Minolta + Ảnh thô Minolta MRW + Minolta MRW åŽŸå§‹å›¾åƒ + Minolta MRW åŽŸç”Ÿå½±åƒ + MRW + Minolta RaW + + + + + + + + Nikon NEF raw image + صورة Nikon NEF خامة + Suvoraja vyjava Nikon NEF + Изображение — Nikon NEF raw + imatge en cru de Nikon NEF + Surový obrázek Nikon NEF + Nikon NEF-rÃ¥billede + Nikon-NEF-Rohbild + ανεπεξεÌÏγαστη εικοÌνα Nikon NEF + Nikon NEF raw image + imagen en bruto NEF de Nikon + Nikon NEF irudi gordina + Nikon-NEF-raakakuva + Nikon NEF rámynd + image brute NEF Nikon + amhíomhá Nikon NEF + imaxe RAW NEF Nikon + תמונה גולמית של Nikon NEF + Nikon NEF nyers kép + Citra mentah Nikon NEF + Immagine raw Nikon NEF + Nikon NEF raw イメージ + Nikon NEF өңделмеген Ñуреті + 니콘 NEF ì›ë³¸ ì´ë¯¸ì§€ + Nikon NEF neapdorotas paveikslÄ—lis + Nikon NEF jÄ“lattÄ“ls + Nikon NEF raw-bilde + onbewerkt Nikon NEF-beeld + Nikon NEF rÃ¥bilete + Surowy obraz NEF Nikon + Imagem bruta NEF da Nikon + Imagine brută Nikon NEF + необработанное изображение Nikon NEF + Surový obrázok Nikon NEF + Surova slikovna datoteka Nikon NEF + Figurë raw Nikon NEF + Nikon NEF-rÃ¥bild + цифровий негатив NEF Nikon + Ảnh thô Nikon NEF + Nikon NEF åŽŸå§‹å›¾åƒ + Nikon NEF åŽŸç”Ÿå½±åƒ + NEF + Nikon Electronic Format + + + + + + Olympus ORF raw image + صورة Olympus ORF خامة + Suvoraja vyjava Olympus ORF + Изображение — Olympus ORF raw + imatge en cru d'Olympus ORF + Surový obrázek Olympus ORF + Olympus ORF-rÃ¥billede + Olympus-ORF-Rohbild + ανεπεξεÌÏγαστη εικοÌνα Olympus ORF + Olympus ORF raw image + imagen en bruto ORF de Olympus + Olympus ORF irudi gordina + Olympus-ORF-raakakuva + Olympus ORF rámynd + image brute ORF Olympus + amhíomhá Olympus ORF + imaxe en bruto de Olympus ORF + תמונה גולמית של Olympus ORF + Olympus ORF nyers kép + Citra mentah Olympus ORF + Immagine raw Olympus ORF + Olympus ORF raw ç”»åƒ + Olympus ORF-ის raw გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ Olympus ORF өңделмеген Ñуреті + 올림푸스 ORF ì›ë³¸ ì´ë¯¸ì§€ + Olympus ORF neapdorotas paveikslÄ—lis + Olympus ORF jÄ“lattÄ“ls + Olympus ORF raw-bilde + onbewerkt Olympus ORF-beeld + Olympus ORF rÃ¥bilete + Surowy obraz Olympus ORF + Imagem bruta ORF da Olympus + Imagine brută Olympus ORF + необработанное изображение Olympus ORF + Surový obrázok Olympus ORF + Surova slikovna datoteka Olympus ORF + Figurë raw Olympus ORF + Olympus ORF-rÃ¥bild + цифровий негатив ORF Olympus + Ảnh thô Olympus ORF + Olympus ORF åŽŸå§‹å›¾åƒ + Olympus ORF åŽŸç”Ÿå½±åƒ + ORF + Olympus Raw Format + + + + + + + + + + + + + Panasonic raw image + صورة Panasonic خامة + Suvoraja vyjava Panasonic + Изображение — Panasonic raw + imatge en cru de Panasonic + Surový obrázek Panasonic + PanasonicrÃ¥billede (raw) + Panasonic-Rohbild + Panasonic raw image + imagen en bruto de Panasonic + Panasonic irudi gordina + Panasonic-raakakuva + Panasonic rámynd + image brute Panasonic + amhíomhá Panasonic + imaxe en bruto de Panasonic + תמונה גולמית של Panasonic + Panasonic nyers kép + Citra mentah Panasonic + Immagine raw Panasonic + Panasonic raw ç”»åƒ + Panasonic өңделмеген Ñуреті + 파나소닉 ì›ë³¸ ì´ë¯¸ì§€ + Panasonic neapdorotas paveikslÄ—lis + Panasonic jÄ“lattÄ“ls + Panasonic raw-bilde + onbewerkt Panasonic-beeld + Panasonic rÃ¥bilete + Obraz raw Panasonic + Imagem bruta da Panasonic + Imagine brută Panasonic + необработанное изображение Panasonic + Surový obrázok Panasonic + Surova slikovna datoteka Panasonic + Figurë raw Panasonic + Panasonic-rÃ¥bild + цифровий негатив Panasonic + Ảnh thô Panasonic + Panasonic åŽŸå§‹å›¾åƒ + Panasonic åŽŸç”Ÿå½±åƒ + + + + + + + + + Panasonic raw2 image + Изображение — Panasonic raw2 + imatge «RAW2» de Panasonic + Surový obrázek Panasonic raw2 + Panasonic-rÃ¥2-billede (raw) + Panasonic raw2-Bild + Panasonic raw2 image + imagen en bruto raw2 de Panasonic + Panasonic raw2 -kuva + image raw2 Panasonic + imaxe en bruto raw2 de Panasonic + תמונת raw2 של Panasonic + Panasonic raw2 kép + Image Panasonic raw2 + Immagine raw2 Panasonic + Panasonic raw2 ç”»åƒ + Panasonic raw2 Ñуреті + 파나소닉 ì›ë³¸ ì´ë¯¸ì§€ 2 + Panasonic raw2 jÄ“lattÄ“ls + Panasonic raw2 image + Obraz raw2 Panasonic + Imagem raw2 da Panasonic + необработанное изображение Panasonic RAW 2 + Surový obrázok Panasonic raw2 + Slikovna datoteka Panasonic raw2 + Panasonic raw2-bild + Panasonic raw2 görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ñƒ raw2 Panasonic + Panasonic raw2 å›¾åƒ + Panasonic raw2 å½±åƒ + + + + + + + + + Pentax PEF raw image + صورة Pentax PEF خامة + Suvoraja vyjava Pentax PEF + Изображение — Pentax PEF raw + imatge en cru de Pentax PEF + Surový obrázek Pentax PEF + Pentax PEF-rÃ¥billede + Pentax-PEF-Rohbild + ανεπεξεÌÏγαστη εικοÌνα Pentax PEF + Pentax PEF raw image + imagen en bruto PEF de Pentax + Pentax PEF irudi gordina + Pentax-PEF-raakakuva + Pentax PEF rámynd + image brute PEF Pentax + amhíomhá Pentax PEF + imaxe en bruto PEF de Pentax + תמונה גולמית של Pentax PEF + Pentax PEF nyers kép + Citra mentah Pentax PEF + Immagine raw Pentax PEF + Pentax PEF raw ç”»åƒ + Pentax PEF өңделмеген Ñуреті + 펜íƒìŠ¤ PEF ì›ë³¸ ì´ë¯¸ì§€ + Pentax PEF neapdorotas paveikslÄ—lis + Pentax PEF jÄ“lattÄ“ls + Pentax PEF raw-bilde + onbewerkt Pentax PEF-beeld + Pentax PEF rÃ¥bilete + Surowy obraz Pentax PEF + Imagem bruta PEF da Pentax + Imagine brută Pentax PEF + необработанное изображение Pentax PEF + Surový obrázok Pentax PEF + Surova slikovna datoteka Pentax PEF + Figurë raw Pentax PEF + Pentax PEF-rÃ¥bild + цифровий негатив PEF Pentax + Ảnh thô Pentax PEF + Pentax PEF åŽŸå§‹å›¾åƒ + Pentax PEF åŽŸç”Ÿå½±åƒ + PEF + Pentax Electronic Format + + + + + + Sigma X3F raw image + صورة Sigma X3F خامة + Suvoraja vyjava Sigma X3F + Изображение — Sigma X3F raw + imatge en cru de Sigma X3F + Surový obrázek Sigma X3F + Sigma X3F-rÃ¥billede + Sigma-X3F-Rohbild + ανεπεξέÏγαστη εικόνα Sigma X3F + Sigma X3F raw image + imagen en bruto X3F de Sigma + Sigma X3F irudi gordina + Sigma-X3F-raakakuva + Sigma X3F rámynd + image brute X3F Sigma + amhíomhá Sigma X3F + imaxe en bruto X3F de Sigma + תמונה גולמית של Sigma X3F + Sigma XF3 nyers kép + Citra mentah Sigma X3F + Immagine raw Sigma X3F + Sigma X3F raw ç”»åƒ + Sigma X3F өңделмеген Ñуреті + 시그마 X3F ì›ë³¸ ì´ë¯¸ì§€ + Sigma X3F neapdorotas paveikslÄ—lis + Sigma X3F jÄ“lattÄ“ls + Sigma X3F raw-bilde + onbewerkt Sigma X3F-beeld + Sigma X3F rÃ¥bilete + Surowy obraz X3F Sigma + Imagem bruta X3F da Sigma + Imagine brută Sigma X3F + необработанное изображение Sigma X3F + Surový obrázok Sigma X3F + Surova slikovna datoteka Sigma X3F + Fifurë raw Sigma X3F + Sigma X3F-rÃ¥bild + цифровий негатив X3F Sigma + Ảnh thô Sigma X3F + Sigma X3F åŽŸå§‹å›¾åƒ + Sigma X3F åŽŸç”Ÿå½±åƒ + X3F + X3 Foveon + + + + + + + + + + + + Sony SRF raw image + صورة Sony SRF خامة + Suvoraja vyjava Sony SRF + Изображение — Sony SRF raw + imatge en cru de Sony SRF + Surový obrázek Sony SRF + Sony SRF-rÃ¥billede + Sony-SRF-Rohbild + ανεπεξεÌÏγαστη εικοÌνα Sony SRF + Sony SRF raw image + imagen en bruto SRF de Sony + Sony SRF irudi gordina + Sony-SRF-raakakuva + Sony SRF rámynd + image brute SRF Sony + amhíomhá Sony SRF + imaxe en bruto SRF de sony + תמונה גולמית של Sony SRF + Sony SRF nyers kép + Citra mentah Sony SRF + Immagine raw Sony SRF + Sony SRF raw ç”»åƒ + Sony SRF өңделмеген Ñуреті + 소니 SRF ì›ë³¸ ì´ë¯¸ì§€ + Sony SRF neapdorotas paveikslÄ—lis + Sony SRF jÄ“lattÄ“ls + Sony SRF raw-bilde + onbewerkt Sony SRF-beeld + Sony SRF rÃ¥bilete + Surowy obraz SRF Sony + Imagem bruta SRF da Sony + Imagine brută Sony SRF + необработанное изображение Sony SRF + Surový obrázok Sony SRF + Surova slikovna datoteka Sony SRF + Figurë raw Sony SRF + Sony SRF-rÃ¥bild + цифровий негатив SRF Sony + Ảnh thô Sony SRF + Sony SRF åŽŸå§‹æ˜ åƒ + Sony SRF åŽŸç”Ÿå½±åƒ + SRF + Sony Raw Format + + + + + + Sony SR2 raw image + صورة Sony SR2 خامة + Suvoraja vyjava Sony SR2 + Изображение — Sony SR2 raw + imatge en cru de Sony SR2 + Surový obrázek Sony SR2 + Sony SR2-rÃ¥billede + Sony-SR2-Rohbild + ανεπεξεÌÏγαστη εικοÌνα Sony SR2 + Sony SR2 raw image + imagen en bruto SR2 de Sony + Sony SR2 irudi gordina + Sony-SR2-raakakuva + Sony SR2 rámynd + image brute SR2 Sony + amhíomhá Sony SR2 + imaxe en bruto SR2 de sony + תמונה גולמית של Sony SR2 + Sony SR2 nyers kép + Citra mentah Sony SR2 + Immagine raw Sony SR2 + Sony SR2 raw ç”»åƒ + Sony SR2 өңделмеген Ñуреті + 소니 SR2 ì›ë³¸ ì´ë¯¸ì§€ + Sony SR2 neapdorotas paveikslÄ—lis + Sony SR2 jÄ“lattÄ“ls + Sony SR2 raw-bilde + onbewerkt Sony SR2-beeld + Sony SR2 rÃ¥bilete + Surowy obraz SR2 Sony + Imagem bruta SR2 da Sony + Imagine brută Sony SR2 + необработанное изображение Sony SR2 + Surový obrázok Sony SR2 + Surova slikovna datoteka Sony SR2 + Figurë raw Sony SR2 + Sony SR2-rÃ¥bild + цифровий негатив SR2 Sony + Ảnh thô Sony SR2 + Sony SR2 åŽŸå§‹æ˜ åƒ + Sony SR2 åŽŸç”Ÿå½±åƒ + SR2 + Sony Raw format 2 + + + + + + Sony ARW raw image + صورة Sony ARW خامة + Suvoraja vyjava Sony ARW + Изображение — Sony ARW raw + imatge en cru de Sony ARW + Surový obrázek Sony ARW + Sony ARW-rÃ¥billede + Sony-ARW-Rohbild + ανεπεξέÏγαστη εικόνα Sony ARW + Sony ARW raw image + imagen en bruto ARW de Sony + Sony ARW irudi gordina + Sony-ARW-raakakuva + Sony ARW rámynd + image brute ARW Sony + amhíomhá Sony ARW + imaxe en bruto ARW de sony + תמונה גולמית של Sony ARW + Sony ARW nyers kép + Citra mentah Sony ARW + Immagine raw Sony ARW + Sony ARW raw ç”»åƒ + Sony ARW өңделмеген Ñуреті + 소니 ARW ì›ë³¸ ì´ë¯¸ì§€ + Sony ARW neapdorotas paveikslÄ—lis + Sony ARW jÄ“lattÄ“ls + Sony ARW raw-bilde + onbewerkt Sony ARW-beeld + Sony ARW rÃ¥bilete + Surowy obraz ARW Sony + Imagem bruta ARW da Sony + Imagine brută Sony ARW + необработанное изображение Sony ARW + Surový obrázok Sony ARW + Surova slikovna datoteka Sony ARW + Figurë raw Sony ARW + Sony ARW-rÃ¥bild + цифровий негатив ARW Sony + Ảnh thô Sony ARW + Sony ARW åŽŸå§‹æ˜ åƒ + Sony ARW åŽŸç”Ÿå½±åƒ + ARW + Alpha Raw format + + + + + + PNG image + صورة PNG + PNG rÉ™smi + Vyjava PNG + Изображение — PNG + imatge PNG + Obrázek PNG + Delwedd PNG + PNG-billede + PNG-Bild + εικόνα PNG + PNG image + PNG-bildo + imagen PNG + PNG irudia + PNG-kuva + PNG mynd + image PNG + íomhá PNG + imaxe PNG + תמונת PNG + PNG-kép + Citra PNG + Immagine PNG + PNG ç”»åƒ + PNG Ñуреті + PNG 그림 + PNG paveikslÄ—lis + PNG attÄ“ls + Imej PNG + PNG-bilde + PNG-afbeelding + PNG-bilete + Obraz PNG + imagem PNG + Imagem PNG + Imagine PNG + изображение PNG + Obrázok PNG + Slikovna datoteka PNG + Figurë PNG + PNG Ñлика + PNG-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ PNG + Ảnh PNG + PNG å›¾åƒ + PNG å½±åƒ + + + + + + + Apple optimised PNG image + + + + + + + + + Run Length Encoded bitmap image + تشغيل صورة نقطية طولية الترميز + Bitmapnaja vyjava, zakadavanaja Å­ Run Length + Изображение — RLE Bitmap + imatge de mapa de bits «Run Lenght Encoded» + Obrázek bitové mapy Run Length Encoded + Run Length Encoded-bitmapbillede + Lauflängenkodiertes Bitmap-Bild + Run Length Encoded bitmap image + mapa de bits con codificación del tamaño durante la ejecución + 'Run Lenght Encoded' bitmap irudia + RLE-koodattu bittikartta + image matricielle Run Length Encoded + íomhá mhapa giotáin Run Length Encoded + mapa de bits con codificación do tamaño durante a execución + מקודד מפת סיביות של Run Length + Run Length Encoded bitkép + Citra peta bit Run Length Encoded + Immagine bitmap RLE (Run Length Encoded) + ランレングス符å·åŒ–ãƒ“ãƒƒãƒˆãƒžãƒƒãƒ—ç”»åƒ + RLE Ñығылған раÑтрлік Ñуреті + RLE ì¸ì½”ë”©ëœ ë¹„íŠ¸ë§µ 그림 + Run Length Encoded rastrinis paveikslÄ—lis + SecÄ«go atkÄrtojumu kodÄ“ts bitkartes attÄ“ls + Run Length Encoded bitmap bilde + RLE-gecodeerde bitmap-afbeelding + Run Length Encoded punktgrafikk + Obraz bitmapy RLE + Classe de comprimento imagem bitmap codificada + Imagine bitmap codată RLE + раÑтровое изображение (Ñжатое RLE) + Bitmapový obrázok Run Length Encoded + Zaporedno kodirana bitna slika (RLE) + Figurë bitmap RLE (Run Length Encoded) + Körlängdskodad bitmappbild + раÑтрове Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ RLE + Ảnh mảng mã hóa chiá»u dài chạy (RLE) + 游程编ç ä½å›¾ + Run Length Encoded é»žé™£å½±åƒ + + + + SVG image + صورة SVG + Vyjava SVG + Изображение — SVG + imatge SVG + Obrázek SVG + SVG-billede + SVG-Bild + εικόνα SVG + SVG image + SVG-bildo + imagen SVG + SVG irudia + SVG-kuva + SVG mynd + image SVG + íomhá SVG + imaxe SVG + תמונת SVG + SVG slika + SVG kép + Citra SVG + Immagine SVG + SVG ç”»åƒ + SVG Ñуреті + SVG 그림 + SVG paveikslÄ—lis + SVG attÄ“ls + SVG-bilde + SVG-afbeelding + SVG-bilete + Obraz SVG + Imagem SVG + Imagine SVG + изображение SVG + Obrázok SVG + Slikovna vektorska datoteka SVG + Figurë SVG + SVG-bild + SVG görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ SVG + Ảnh SVG + SVG å›¾åƒ + SVG å½±åƒ + SVG + Scalable Vector Graphics + + + + + + + + + + compressed SVG image + صورة SVG مضغوطة + skampresavanaja vyjava SVG + Изображение — SVG, компреÑирано + imatge SVG comprimida + Komprimovaný obrázek SVG + SVG-komprimeret billede + Komprimiertes SVG-Bild + συμπιεσμένη εικόνα SVG + compressed SVG image + imagen SVG comprimida + konprimitutako SVG irudia + pakattu SVG-kuva + stappað SVG mynd + image SVG compressée + íomhá SVG comhbhrúite + imaxe SVG comprimida + תמונת SVG מכוצת + komprimirana SVG slika + tömörített SVG kép + Citra SVG terkompresi + Immagine SVG compressa + 圧縮 SVG ç”»åƒ + Ñығылған SVG Ñуреті + ì••ì¶•ëœ SVG 그림 + suglaudintas SVG paveikslÄ—lis + saspiests SVG attÄ“ls + komprimert SVG-bilde + ingepakte SVG-afbeelding + komprimert SVG-bilete + Skompresowany obraz SVG + Imagem compactada SVG + imagine comprimată SVG + Ñжатое изображение SVG + Komprimovaný obrázok SVG + Slikovna datoteka SVG (stisnjena) + Figurë SVG e kompresuar + komprimerad SVG-bild + ÑтиÑнене Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ SVG + ảnh SVG đã nén + 压缩的 SVG å›¾åƒ + 壓縮版 SVG å½±åƒ + SVG + Scalable Vector Graphics + + + + + TIFF image + صورة TIFF + Vyjava TIFF + Изображение — TIFF + imatge TIFF + Obrázek TIFF + TIFF-billede + TIFF-Bild + εικόνα TIFF + TIFF image + TIFF-bildo + imagen TIFF + TIFF irudia + TIFF-kuva + TIFF mynd + image TIFF + íomhá TIFF + imaxe TIFF + תמונת TIFF + TIFF slika + TIFF-kép + Citra TIFF + Immagine TIFF + TIFF ç”»åƒ + TIFF Ñуреті + TIFF 그림 + TIFF paveikslÄ—lis + TIFF attÄ“ls + Imej TIFF + TIFF-bilde + TIFF-afbeelding + TIFF-bilete + Obraz TIFF + imagem TIFF + Imagem TIFF + Imagine TIFF + изображение TIFF + Obrázok TIFF + Slikovna datoteka TIFF + Figurë TIFF + TIFF Ñлика + TIFF-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ TIFF + Ảnh TIFF + TIFF å›¾åƒ + TIFF å½±åƒ + TIFF + Tagged Image File Format + + + + + + + + + AutoCAD image + صورة AutoCAD + AutoCAD rÉ™smi + Vyjava AutoCAD + Изображение — AutoCAD + imatge d'AutoCAD + Obrázek AutoCAD + Delwedd AutoCAD + AutoCAD-billede + AutoCAD-Bild + εικόνα AutoCAD + AutoCAD image + AutoCAD-bildo + imagen de AutoCAD + AutoCAD-eko irudia + AutoCAD-kuva + AutoCAD mynd + image AutoCAD + íomhá AutoCAD + imaxe de AutoCAD + תמונה של AutoCAD + AutoCAD slika + AutoCAD-kép + Citra AutoCAD + Immagine AutoCAD + AutoCAD ç”»åƒ + AutoCAD-ის გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ AutoCAD Ñуреті + AutoCAD 그림 + AutoCAD paveikslÄ—lis + AutoCAD attÄ“ls + Imej AutoCAD + AutoCAD-bilde + AutoCAD-afbeelding + AutoCAD-bilete + Obraz AutoCAD + imagem AutoCAD + Imagem do AutoCAD + Imagine AutoCAD + изображение AutoCAD + Obrázok AutoCAD + Slikovna datoteka AutoCAD + Figurë AutoCAD + AutoCAD Ñлика + AutoCAD-bild + AutoCAD görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ AutoCAD + Ảnh AutoCAD + AutoCAD å›¾åƒ + AutoCAD å½±åƒ + + + + DXF vector image + صورة DXF نقطية + Vektarnaja vyjava DXF + Изображение — DXF + imatge vectorial DXF + Vektorový obrázek DXF + DXF-vektorbillede + DXF-Vektorbild + ανυσματική εικόνα DXF + DXF vector image + vektora DXF-bildo + imagen vectorial DXF + DXF bektore-grafikoa + DXF-vektorikuva + DXF vektormynd + image vectorielle DXF + íomhá veicteoir DXF + imaxe de vector DXF + תמונת DXF וקטורית + DXF vektorska slika + DXF-vektorkép + Citra vektor DXF + Immagine vettoriale DXF + DXF ãƒ™ã‚¯ã‚¿ãƒ¼ç”»åƒ + DXF ვექტáƒáƒ áƒ£áƒšáƒ˜ გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ DXF векторлық Ñуреті + DXF 벡터 그림 + DXF vektorinis paveikslÄ—lis + DXF vektora attÄ“ls + Imej vektor DXF + DXF-vektorgrafikk + DXF-vectorafbeelding + DXF-vektorgrafikk + Obraz wektorowy DXF + imagem de vectores DXF + Imagem vetorial DXF + Imagine vectorială DXF + векторное изображение DXF + Vektorový obrázok DXF + Slikovna vektorska datoteka DXF + Figurë vektoriale DFX + DXF векторÑка графика + DXF-vektorbild + векторне Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ DXF + Ảnh véc-tÆ¡ DXF + DXF 矢é‡å›¾åƒ + DXF å‘é‡åœ– + + + + + + + + Microsoft Document Imaging format + صيغة مستند تصوير مايكروسوÙت + Изображение — Microsoft Document Imaging + format Microsoft Document Imaging + Formát Microsoft Document Imaging + Microsofts dokumentbilledformat + Microsoft-Document-Imaging-Bildformat + μοÏφή Microsoft Document Imaging + Microsoft Document Imaging format + formato de imagen de Microsoft Document + Microsoft Document Imaging formatua + Microsoft Document Imaging -muoto + Microsoft Document Imaging snið + format Document Imaging Microsoft + formáid Microsoft Document Imaging + formato de Microsoft Document Imaging + פורמט של Microsoft Document Imaging + Microsoft Document Imaging formátum + Format Microsoft Document Imaging + Formato MDI (Microsoft Document Imaging) + Microsoft ドキュメントイメージフォーマット + Microsoft Document Imaging пішімі + 마ì´í¬ë¡œì†Œí”„트 문서 ì´ë¯¸ì§€ í˜•ì‹ + Microsoft Document Imaging formatas + Microsoft dokumentu attÄ“loÅ¡anas formÄts + Microsoft Document Imaging + Format Microsoft Document Imaging + Formato do Microsoft Document Imaging + Format Microsoft Document Imaging + формат Microsoft Document Imaging + Formát Microsoft Document Imaging + Zapis Microsoft Document Imaging + Microsoft Document Imaging-format + формат Microsoft Document Imaging + Äịnh dạng tạo ảnh tài liệu Microsoft + Microsoft Document Imaging 扫æå›¾åƒ + 微軟文件影åƒæ ¼å¼ + MDI + Microsoft Document Imaging + + + + + + + 3D Studio image + صورة استديو ثلاثية الأبعاد + 3D Studio rÉ™smi + Vyjava 3D Studio + Изображение — 3D Studio + imatge de 3D Studio + Obrázek 3D Studio + Delwedd "3D Studio" + 3D Studio-billede + 3D-Studio-Bild + εικόνα 3D Studio + 3D Studio image + bildo de 3D Studio + imagen de 3D Studio + 3D Studio-ko irudia + 3D Studio -kuva + 3D Studio mynd + image 3D Studio + íomhá 3D Studio + imaxe de 3D Studio + תמונת 3D Studio + 3D Studio slika + 3D Studio-kép + Citra 3D Studio + Immagine 3D Studio + 3D Studio ç”»åƒ + 3D Studio-ის გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ 3D Studio Ñуреті + 3D Studio 그림 + 3D Studio paveikslÄ—lis + 3D Studio attÄ“ls + Imej 3D Studio + 3D Studio-bilde + 3D-Studio-afbeelding + 3D Studio-bilete + Obraz 3D Studio + imagem 3D Studio + Imagem do 3D Studio + Imagine 3D Studio + Ñцена 3D Studio + Obrázok 3D Studio + Slikovna datoteka 3D Studio + Figurë 3D Studio + 3D Studio Ñлика + 3D Studio-bild + 3D Studio görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ 3D Studio + Ảnh xuởng vẽ 3D + 3D Studio å›¾åƒ + 3D Studio å½±åƒ + + + + Applix Graphics image + صورة رسوميات Applix + Vyjava Applix Graphics + Изображение — Applix Graphics + imatge d'Applix Graphics + Obrázek Applix Graphics + Applix Graphics-billede + Applix-Graphics-Bild + εικόνα Applix Graphics + Applix Graphics image + bildo de Applix Graphics + imagen de Applix Graphics + Applix Graphics irudia + Applix Graphics -kuva + Applix Graphics mynd + image Applix Graphics + íomhá Applix Graphics + imaxe de Applix Graphics + תמונה של Applix Graphics + Applix Graphics slika + Applix Graphics-kép + Citra Applix Graphics + Immagine Applix Graphics + Applix Graphics ç”»åƒ + Applix Graphics-ის გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ Applix Graphics Ñуреті + Applix Graphics 그림 + Applix Graphics paveikslÄ—lis + Applix Graphics attÄ“ls + Imej Applix Graphics + Applix Graphics-dokument + Applix Graphics-afbeelding + Applix Graphics-dokument + Obraz Applix Graphics + imagem Applix Graphics + Imagem do Applix Graphics + Imagine Applix Graphics + изображение Applix Graphics + Obrázok Applix Graphics + Slikovna datoteka Applix Graphics + Figurë Applix Graphics + Applix графички документ + Applix Graphics-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Applix Graphics + Ảnh Applix Graphics + Applix Graphics å›¾åƒ + Applix Graphics å½±åƒ + + + + + + + + + EPS image (bzip-compressed) + صورة EPS (مضغوط-bzip) + Vyjava EPS (bzip-skampresavanaja) + Изображение — EPS, компреÑирано Ñ bzip + imatge EPS (comprimida amb bzip) + Obrázek EPS (komprimovaný pomocí bzip) + EPS-billede (bzip-komprimeret) + EPS-Bild (bzip-komprimiert) + EPS image (bzip-compressed) + imagen EPS (comprimida con bzip) + EPS irudia (bzip-ekin konprimitua) + EPS-kuva (bzip-pakattu) + EPS mynd (bzip-stappað) + image EPS (compressée bzip) + íomhá EPS (comhbhrúite le bzip) + imaxe EPS (comprimida con bzip) + תמונת EPS (מכווץ בbzip) + EPS slika (komprimirana bzip-om) + EPS kép (bzip-tömörítésű) + Citra EPS (terkompresi bzip) + Immagine EPS (compressa con bzip) + EPS ç”»åƒ (bzip 圧縮) + EPS გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ(bzip-ით შეკუმშული) + EPS Ñуреті (bzip-пен Ñығылған) + EPS 그림 (BZIP 압축) + EPS paveikslÄ—lis (suglaudintas su bzip) + EPS attÄ“ls (saspiests ar bzip) + EPS-bilde (bzip-komprimert) + EPS-afbeelding (ingepakt met bzip) + EPS-bilete (pakka med bzip) + Obraz EPS (kompresja bzip) + Imagem EPS (compactada com bzip) + Imagine EPS (compresie bzip) + изображение EPS (Ñжатое bzip) + Obrázok EPS (komprimovaný pomocou bzip) + Slikovna datoteka EPS (stisnjena z bzip) + Figurë EPS (e kompresuar me bzip) + EPS-bild (bzip-komprimerad) + EPS görüntüsü (bzip ile sıkıştırılmış) + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ EPS (ÑтиÑнене bzip) + Ảnh EPS (đã nén bzip) + EPS 图åƒ(bzip 压缩) + EPS å½±åƒ (bzip æ ¼å¼å£“縮) + + + + + + + CMU raster image + صورة CMU نقطية + CMU raster rÉ™smi + Rastravaja vyjava CMU + Изображение — CMU raster + imatge ràster CMU + Rastrový obrázek CMU + Delwedd raster CMU + CMU-rasterbillede + CMU-Rasterbild + εικόνα ÏÎ¬ÏƒÏ„ÎµÏ CMU + CMU raster image + rastruma bildo de CMU + imagen ráster CMU + CMU bilbe-irudia + CMU-rasterikuva + CMU raster mynd + image raster CMU + íomhá rastar CMU + imaxe raster CMU + תמונת סריקה CMU + CMU-raszterkép + Citra raster CMU + Immagine raster CMU + CMU ãƒ©ã‚¹ã‚¿ãƒ¼ç”»åƒ + CMU-ის რáƒáƒ¡áƒ¢áƒ áƒ£áƒšáƒ˜ გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ CMU раÑтрлық Ñуреті + CMU 래스터 그림 + CMU rastrinis paveikslÄ—lis + CMU rastra attÄ“ls + Imej raster CMU + CMU-rasterbilde + CMU-rasterafbeelding + CMU rasterbilete + Obraz rastrowy CMU + imagem rasterizada CMU + Imagem raster CMU + Imagine raster CMU + раÑтровое изображение CMU + Rastrový obrázok CMU + Slikovna rastrska datoteka CMU + Figurë raster CMU + CMU раÑтерÑка Ñлика + CMU-rasterbild + раÑтрове Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ CMU + Ảnh mành CMU + CMU 矢é‡å›¾åƒ + CMU raster å½±åƒ + + + + compressed GIMP image + صورة GIMP مضغوطة + skampresavanaja vyjava GIMP + Изображение — GIMP, компреÑирано + imatge GIMP comprimida + Komprimovaný obrázek GIMP + komprimeret GIMP-billede + Komprimiertes GIMP-Bild + συμπιεσμένη εικόνα GIMP + compressed GIMP image + imagen GIMP comprimida + konprimitutako GIMP irudia + pakattu GIMP-kuva + stappað GIMP mynd + image GIMP compressée + íomhá GIMP comhbhrúite + imaxe de GIMP comprimida + תמונת GIMP מכווצת + tömörített GIMP kép + Citra GIMP terkompresi + Immagine GIMP compressa + 圧縮 GIMP ç”»åƒ + Ñығылған GIMP Ñуреті + ì••ì¶•ëœ GIMP 그림 + suglaudintas GIMP paveikslÄ—lis + saspiests GIMP attÄ“ls + komprimert GIMP-bilde + ingepakte GIMP-afbeelding + komprimert GIMP-bilete + Skompresowany obraz GIMP + Imagem compactada do GIMP + imagine comprimată GIMP + Ñжатое изображение GIMP + Komprimovaný obrázok GIMP + Slikovna datoteka GIMP (stisnjena) + Figurë GIMP e kompresuar + komprimerad GIMP-bild + ÑтиÑнене Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ GIMP + ảnh GIMP đã nén + 压缩的 GIMP å›¾åƒ + 壓縮版 GIMP å½±åƒ + + + + + DICOM image + صورة DICOM + Vyjava DICOM + Изображение — DICOM + imatge DICOM + Obrázek DICOM + DICOM-billede + DICOM-Bild + εικόνα DICOM + DICOM image + DICOM-bildo + imagen DICOM + DICOM irudia + DICOM-kuva + DICOM mynd + image DICOM + íomhá DICOM + imaxe DICOM + תמונת DICOM + DICOM slika + DICOM kép + Citra DICOM + Immagine DICOM + DICOM ç”»åƒ + DICOM გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ DICOM Ñуреті + DICOM 그림 + DICOM paveikslÄ—lis + DICOM attÄ“ls + DICOM-bilde + DICOM-afbeelding + DICOM-bilete + Obraz DICOM + Imagem DICOM + Imagine DICOM + изображение DICOM + Obrázok DICOM + Slikovna datoteka DICOM + Figurë DICOM + DICOM-bild + DICOM görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ DICOM + Ảnh DICOM + DICOM å›¾åƒ + DICOM å½±åƒ + DICOM + Digital Imaging and Communications in Medicine + + + + + + + + + DocBook document + مستند DocBook + Dakument DocBook + Документ — DocBook + document DocBook + Dokument DocBook + DocBook-dokument + DocBook-Dokument + έγγÏαφο DocBook + DocBook document + DocBook-dokumento + documento DocBook + DocBook dokumentua + DocBook-asiakirja + DocBook skjal + document DocBook + cáipéis DocBook + documento de DocBook + מסמך DocBook + DocBook dokument + DocBook dokumentum + Dokumen DocBook + Documento DocBook + DocBook ドキュメント + DocBook-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + DocBook құжаты + DocBook 문서 + DocBook dokumentas + DocBook dokuments + DocBook-dokument + DocBook-document + DocBook-dokument + Dokument DocBook + Documento DocBook + Document DocBook + документ DocBook + Dokument DocBook + Dokument DocBook + Dokument DocBook + DocBook-dokument + DocBook belgesi + документ DocBook + Tài liệu DocBook + DocBook 文档 + DocBook 文件 + + + + + + + + + + + + + + DIB image + صورة DIB + Vyjava DIB + Изображение — DIB + imatge DIB + Obrázek DIB + DIB-billede + DIB-Bild + εικόνα DIB + DIB image + DIB-bildo + imagen DIB + DIB irudia + DIB-kuva + DIB mynd + image DIB + íomhá DIB + imaxe DIB + תמונת DIB + DIB slika + DIB kép + Citra DIB + Immagine DIB + DIB ç”»åƒ + DIB გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ DIB Ñуреті + DIB 그림 + DIB paveikslÄ—lis + DIB attÄ“ls + DIB-bilde + DIB-afbeelding + DIB-bilete + Obraz DIB + Imagem DIB + Imagine DIB + изображение DIB + Obrázok DIB + Slikovna datoteka DIB + Figurë DIB + DIB-bild + DIB görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ DIB + Ảnh DIB + DIB å›¾åƒ + DIB å½±åƒ + DIB + Device Independent Bitmap + + + + + + DjVu image + صورة DjVu + Vyjava DjVu + Изображение — DjVu + imatge DjVu + Obrázek DjVu + DjVu-billede + DjVu-Bild + εικόνα DjVu + DjVu image + DjVu-bildo + imagen DjVu + DjVU-ko irudia + DjVu-kuva + DjVu mynd + image DjVu + íomhá DjVu + imaxe de DjVu + תמונת DjVu + DjVu slika + DjVu-kép + Citra DjVu + Immagine DjVu + DjVu ç”»åƒ + DjVu გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ DjVu Ñуреті + DjVu 그림 + DjVu paveikslÄ—lis + DjVu attÄ“ls + Imej DjVu + DjVu-bilde + DjVu-afbeelding + DjVu-bilete + Obraz DjVu + imagem DjVu + Imagem DjVu + Imagine DjVu + изображение DjVu + Obrázok DjVu + Slikovna datoteka DjVu + Figurë DjVu + DjVu Ñлика + DjVu-bild + DjVu görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ DjVu + Ảnh DjVu + DjVu å›¾åƒ + DjVu å½±åƒ + + + + + + + + + + + + + + + + + DPX image + صورة DPX + Vyjava DPX + Изображение — DPX + imatge DPX + Obrázek DPX + DPX-billede + DPX-Bild + εικόνα DPX + DPX image + DPX-bildo + imagen DPX + DPX irudia + DPX-kuva + DPX mynd + image DPX + íomhá DPX + imaxe DPX + תמונת DPX + DPX slika + DPX kép + Citra DPX + Immagine DPX + DPX ç”»åƒ + DPX გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ DPX Ñуреті + DPX 그림 + DPX paveikslÄ—lis + DPX attÄ“ls + DPX-bilde + DPX-afbeelding + DPX-bilete + Obraz DPX + Imagem DPX + Imagine DPX + изображение DPX + Obrázok DPX + Slikovna datoteka DPX + Figurë DPX + DPX-bild + DPX görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ DPX + Ảnh DPX + DPX å›¾åƒ + DPX å½±åƒ + DPX + Digital Moving Picture Exchange + + + + + + EPS image + صورة EPS + Vyjava EPS + Изображение — EPS + imatge EPS + Obrázek EPS + EPS-billede + EPS-Bild + εικόνα EPS + EPS image + EPS-bildo + imagen EPS + EPS irudia + EPS-kuva + EPS mynd + image EPS + íomhá EPS + imaxe EPS + תמונת EPS + EPS slika + EPS kép + Citra EPS + Immagine EPS + EPS ç”»åƒ + EPS გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ EPS Ñуреті + EPS 그림 + EPS paveikslÄ—lis + EPS attÄ“ls + EPS-bilde + EPS-afbeelding + EPS-bilete + Obraz EPS + Imagem EPS + Imagine EPS + изображение EPS + Obrázok EPS + Slikovna datoteka EPS + Figurë EPS + EPS-bild + EPS görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ EPS + Ảnh EPS + EPS å›¾åƒ + EPS å½±åƒ + EPS + Encapsulated PostScript + + + + + + + + + + + + + + + + FITS document + مستند FITS + Dakument FITS + Документ — FITS + document FITS + Dokument FITS + FITS-dokument + FITS-Dokument + έγγÏαφο FITS + FITS document + FITS-dokumento + documento FITS + FITS dokumentua + FITS-asiakirja + FITS skjal + document FITS + cáipéis FITS + documento FICT + מסמך FITS + FITS dokument + FITS dokumentum + Dokumen FITS + Documento FITS + FITS ドキュメント + FITS დáƒáƒ™áƒ£áƒ›áƒ”ნტი + FITS құжаты + FITS 문서 + FITS dokumentas + FITS dokuments + FITS-dokument + FITS-document + FITS-dokument + Dokument FITS + Documento FITS + Document FITS + документ FITS + Dokument FITS + Dokument FITS + Dokument FITS + FITS-dokument + документ FITS + Tài liệu FITS + FITS 文档 + FITS 文件 + FITS + Flexible Image Transport System + + + + + + + + FPX image + صورة FPX + Vyjava FPX + Изображение — FPX + imatge FPX + Obrázek FPX + FPX-billede + FPX-Bild + εικόνα FPX + FPX image + FPX-bildo + imagen FPX + FPX irudia + FPX-kuva + FPX mynd + image FPX + íomhá FPX + imaxe FPX + תמונת FPX + FPX slika + FPX kép + Citra FPX + Immagine FPX + FPX ç”»åƒ + FPX გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ FPX Ñуреті + FPX 그림 + FPX paveikslÄ—lis + FPX attÄ“ls + FPX-bilde + FPX-afbeelding + FPX-bilete + Obraz FPX + Imagem FPX + Imagine FPX + изображение FPX + Obrázok FPX + Slikovna datoteka FPX + Figurë FPX + FPX-bild + FPX görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ FPX + Ảnh FPX + FPX å›¾åƒ + FPX å½±åƒ + FPX + FlashPiX + + + + + + EPS image (gzip-compressed) + صورة EPS (مضغوط-gzip) + Vyjava EPS (gzip-skampresavanaja) + Изображение — EPS, компреÑирано Ñ gzip + imatge EPS (comprimida amb gzip) + Obrázek EPS (komprimovaný pomocí gzip) + EPS-billede (gzip-komprimeret) + EPS-Bild (gzip-komprimiert) + EPS image (gzip-compressed) + imagen EPS (comprimida con gzip) + EPS irudia (gzip-ekin konprimitua) + EPS-kuva (gzip-pakattu) + EPS mynd (gzip-stappað) + image EPS (compressée gzip) + íomhá EPS (comhbhrúite le gzip) + imaxe EPS (comprimida con gzip) + תמונת EPS (מכווץ בgzip) + EPS slika (komprimirana gzip-om) + EPS kép (gzip-tömörítésű) + Citra EPS (terkompresi gzip) + Immagine EPS (compressa con gzip) + EPS ç”»åƒ (gzip 圧縮) + EPS გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ(gzip-ით შეკუმშული) + EPS Ñуреті (gzip-пен Ñығылған) + EPS 그림 (GZIP 압축) + EPS paveikslÄ—lis (suglaudintas su gzip) + EPS attÄ“ls (saspiests ar gzip) + EPS-bilde (gzip-komprimert) + EPS-afbeelding (ingepakt met gzip) + EPS-bilete (pakka med gzip) + Obraz EPS (kompresja gzip) + Imagem EPS (compactada com gzip) + Imagine EPS (compresie gzip) + изображение EPS (Ñжатое gzip) + Obrázok EPS (komprimovaný pomocou gzip) + Slikovna datoteka EPS (stisnjena z gzip) + Figurë EPS (e kompresuar me gzip) + EPS-bild (gzip-komprimerad) + EPS görüntüsü (gzip ile sıkıştırılmış) + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ EPS (ÑтиÑнене gzip) + Ảnh EPS (đã nén gzip) + EPS 图åƒ(gzip 压缩) + EPS å½±åƒ (gzip æ ¼å¼å£“縮) + + + + + + + Microsoft icon + أيقونة مايكروسوÙت + Икона — Microsoft + icona de Microsoft + Ikona Microsoft + Microsoftikon + Microsoft-Symbol + εικονίδιο Microsoft + Microsoft icon + Microsoft-piktogramo + icono de Microsoft + Microsoft ikonoa + Microsoft-kuvake + Microsoft ímynd + icône Microsoft + deilbhín Microsoft + Icona de microsoft + ×ייקון של Microsofr + Microsoft ikona + Microsoft ikon + Ikon Microsoft + Icona Microsoft + Microsoft アイコン + Microsoft-ის ხáƒáƒ¢áƒ£áƒšáƒ + Microsoft таңбашаÑÑ‹ + 마ì´í¬ë¡œì†Œí”„트 ì•„ì´ì½˜ + Microsoft piktograma + Microsoft ikona + Microsoft pictogram + Ikona Microsoft + Ãcone da Microsoft + Iconiță Microsoft + значок Microsoft + Ikona Microsoft + Datoteka ikone Microsoft Windows + Microsoft-ikon + піктограма Microsoft + Biểu tượng Microsoft + Microsoft 图标 + 微軟圖示 + + + + + + + + + + + + + + + MacOS X icon + أيقونة MacOS X + Ikona MacOS X + Икона — MacOS X + icona MacOS X + Ikona MacOS X + MacOS X-ikon + MacOS-X-Symbol + εικονίδιο MacOS X + MacOS X icon + MacOS-X-piktogramo + icono de MacOS X + MacOS X ikonoa + MacOS X -kuvake + MacOS X ímynd + icône MacOS X + deilbhín MacOS X + Icona de MacOS X + ×ייקון של MacOS X + MacOS X ikona + MacOS X ikon + Ikon MacOS X + Icona MacOS X + MacOS X アイコン + MacOS X-ის ხáƒáƒ¢áƒ£áƒšáƒ + MacOS X таңбашаÑÑ‹ + MacOS X ì•„ì´ì½˜ + MacOS X piktograma + MacOS X ikona + MacOS X-ikon + MacOS-X-pictogram + MacOS X-ikon + Ikona Mac OS X + Ãcone do MacOS X + Iconiță MacOS X + значок MacOS X + Ikona MacOS X + Datoteka ikone MacOS X + Ikonë MacOS X + MacOS X-ikon + піктограма MacOS X + Biểu tượng MacOS X + MacOS X 图标 + MacOS X 圖示 + + + + + + + ILBM image + صورة ILBM + ILBM rÉ™smi + Vyjava ILBM + Изображение — ILBM + imatge ILBM + Obrázek ILMB + Delwedd ILBM + ILBM-billede + ILBM-Bild + εικόνα ILBM + ILBM image + ILBM-bildo + imagen ILBM + ILBM irudia + ILBM-kuva + ILBM mynd + image ILBM + íomhá ILBM + imaxe ILBM + תמונת ILBM + ILBM slika + ILBM-kép + Citra ILBM + Immagine ILBM + ILBM ç”»åƒ + ILBM Ñуреті + ILBM 그림 + ILBM paveikslÄ—lis + ILBM attÄ“ls + Imej ILBM + ILBM-bilde + ILBM-afbeelding + ILMB-bilete + Obraz ILBM + imagem ILBM + Imagem ILBM + Imagine ILBM + изображение ILBM + Obrázok ILMB + Slikovna datoteka ILBM + Figurë ILBM + ILBM Ñлика + ILBM-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ ILBM + Ảnh ILBM + ILBM å›¾åƒ + ILBM å½±åƒ + ILBM + InterLeaved BitMap + + + + + + + + + + + + JNG image + صورة JNG + JNG rÉ™smi + Vyjava JNG + Изображение — JNG + imatge JNG + Obrázek JNG + Delwedd JNG + JNG-billede + JNG-Bild + εικόνα JNG + JNG image + JNG-bildo + imagen JNG + JNG irudia + JNG-kuva + JNG mynd + image JNG + íomhá JNG + imaxe JNG + תמונת JNG + JNG slika + JNG-kép + Citra JNG + Immagine JNG + JNG ç”»åƒ + JNG Ñуреті + JNG 그림 + JNG paveikslÄ—lis + JNG attÄ“ls + Imej PNG + JNG-bilde + JNG-afbeelding + JNG-bilete + Obraz JNG + imagem JNG + Imagem JNG + Imagine JNG + изображение JNG + Obrázok JNG + Slikovna datoteka JNG + Figurë JNG + JNG Ñлика + JNG-bild + JNG görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ JNG + Ảnh JNG + JNG å›¾åƒ + JNG å½±åƒ + JNG + JPEG Network Graphics + + + + LightWave object + كائن LightWave + LightWave cismi + Abjekt LightWave + Обект — LightWave + objecte de LightWave + Objekt LightWave + Gwrthrych LightWave + LightWave-objekt + LightWave-Objekt + αντικείμενο LightWave + LightWave object + LightWave-objekto + objeto LightWave + LightWave objektua + LightWave-esine + LightWave lutur + objet LightWave + réad LightWave + obxecto de LightWave + ×¢×¦× LightWave + LightWave objekt + LightWave-objektum + Proyek LightWave + Oggetto LightWave + LightWave オブジェクト + LightWave объекті + LightWave 개체 + LightWave objektas + LightWave objekts + Objek LightWave + LightWave-objekt + LightWave-object + LightWave-objekt + Obiekt LightWave + Objecto LightWave + Objeto LightWave + Obiect LightWave + объект LightWave + Objekt LightWave + Datoteka predmeta LightWave + Objekt LightWave + LightWave објекат + LightWave-objekt + LightWave nesnesi + об'єкт LightWave + Äối tượng LightWave + LightWave 对象 + LightWave 物件 + + + + + LightWave scene + مشهد LightWave + LightWave sÉ™hnÉ™si + Scena LightWave + Сцена — LightWave + escena de LightWave + Scéna LightWave + Golygfa LightWave + LightWave-scene + LightWave-Szene + σκηνή LightWave + LightWave scene + LightWave-sceno + escena LightWave + LightWave eszena + LightWave-maisema + LightWave leikmynd + scène LightWave + radharc LightWave + escena de LightWave + סצנה של LightWave + LightWave scena + LightWave-jelenet + Scene LightWave + Scena LightWave + LightWave シーン + LightWave ÑахнаÑÑ‹ + LightWave 장면 + LightWave scena + LightWave aina + Babak LightWave + LightWave-scene + LightWave-scène + LightWave-scene + Scena Lightwave + cenário LightWave + Cena LightWave + Scenă LightWave + Ñцена LightWave + Scéna LightWave + Datoteka scene LightWave + Skenë LightWave + LightWave Ñцена + LightWave-scen + Ñцена LightWave + Cảnh LightWave + LightWave 场景 + LightWave 場景 + + + + MacPaint Bitmap image + صورة MacPaint Bitmap + Bitmapnaja vyjava MacPaint + Изображение — MacPaint Bitmap + imatge de mapa de bits MacPaint + Obrázek MacPaint Bitmap + MacPaint BitMap-billede + MacPaint-Bitmap-Datei + εικόνα Bitmap MacPaint + MacPaint Bitmap image + imagen en mapa de bits de MacPaint + MacPaint Bitmap irudia + MacPaint-bittikartta + MacPaint Bitmap mynd + image matricielle MacPaint + íomhá MacPaint Bitmap + imaxe de mapa de bits MacPaint + תמונת מפת-סיביות של MacPaint + MacPaint bitkép + Citra MacPaint Bitmap + Immagine Bitmap MacPaint + MacPaint ãƒ“ãƒƒãƒˆãƒžãƒƒãƒ—ç”»åƒ + MacPaint раÑтрлық Ñуреті + MacPaint 비트맵 그림 + MacPaint rastrinis paveikslÄ—lis + MacPaint bitkartes attÄ“ls + MacPaint Bitmap-bilde + MacPaint-bitmap-afbeelding + MacPaint punktbilete + Obraz bitmapowy MacPaint + Imagem de bitmap do MacPaint + Imagine MacPaint Bitmap + раÑтровое изображение MacPaint + Obrázok MacPaint Bitmap + Slikovna bitna datoteka MacPaint + Figurë BitMap MacPaint + MacPaint Bitmap-bild + раÑтрове Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ MacPaint + Ảnh mảng MacPaint + MacPaint ä½å›¾ + MacPaint é»žé™£å½±åƒ + + + + Office drawing + تصميم أوÙيس + Ofisny rysunak + Чертеж — Office + dibuix d'Office + Kresba Office + Officetegning + Office-Zeichnung + σχέδιο Office + Office drawing + dibujo de Office + Office marrazkia + Office-piirros + Office tekning + dessin Office + líníocht Office + debuxo de Office + ציור של Office + Office rajz + Gambar Office + Disegno Office + Office ドロー + Office Ñуреті + 오피스 드로잉 + Office pieÅ¡inys + Office zÄ«mÄ“jums + Office-tegning + Office-tekening + Office-teikning + Rysunek Office + Desenho do Office + Desen Office + изображение Office + Kresba Office + Datoteka risbe Office + Vizatim Office + Office-teckning + малюнок Office + Bản vẽ Office + Microsoft Office 绘图 + Office 繪圖 + + + + NIFF image + صورة NIFF + Vyjava NIFF + Изображение — NIFF + imatge NIFF + Obrázek NIFF + NIFF-billede + NIFF-Bild + εικόνα NIFF + NIFF image + NIFF-bildo + imagen NIFF + NIFF irudia + NIFF-kuva + NIFF mynd + image NIFF + íomhá NIFF + imaxe NIFF + תמונת NIFF + NIFF slika + NIFF kép + Citra NIFF + Immagine NIFF + NIFF ç”»åƒ + NIFF Ñуреті + NIFF 그림 + NIFF paveikslÄ—lis + NIFF attÄ“ls + NIFF-bilde + NIFF-afbeelding + NIFF-bilete + Obraz NIFF + Imagem NIFF + Imagine NIF + изображение NIFF + Obrázok NIFF + Slikovna datoteka NIFF + Figurë NIFF + NIFF-bild + NIFF görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ NIFF + Ảnh NIFF + NIFF å›¾åƒ + NIFF å½±åƒ + + + + + + PCX image + صورة PCX + Vyjava PCX + Изображение — PCX + imatge PCX + Obrázek PCX + PCX-billede + PCX-Bild + εικόνα PCX + PCX image + PCX-bildo + imagen PCX + PCX irudia + PCX-kuva + PCX mynd + image PCX + íomhá PCX + imaxe PCX + תמונת PCX + PCX kép + Citra PCX + Immagine PCX + PCX ç”»åƒ + PCX Ñуреті + PCX 그림 + PCX paveikslÄ—lis + PCX attÄ“ls + PCX-bilde + PCX-afbeelding + PCX-bilete + Obraz PCX + Imagem PCX + Imagine PCX + изображение PCX + Obrázok PCX + Slikovna datoteka PCX + Figurë PCX + PCX-bild + PCX görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ PCX + Ảnh PCX + PCX å›¾åƒ + PCX å½±åƒ + PCX + PiCture eXchange + + + + + + + + + + + + PCD image + صورة PCD + Vyjava PCD + Изображение — PCD + imatge PCD + Obrázek PCD + PCD-billede + PCD-Bild + εικόνα PCD + PCD image + PCD-bildo + imagen PCD + PCD irudia + PCD-kuva + PCD mynd + image PCD + íomhá PCD + imaxe PCD + תמונת PCD + PCD kép + Citra PCD + Immagine PCD + PCD ç”»åƒ + PCD გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ PCD Ñуреті + PCD 그림 + PCD paveikslÄ—lis + PCD attÄ“ls + PCD-bilde + PCD-afbeelding + PCD-bilete + Obraz PCD + Imagem PCD + Imagine PCD + изображение PCD + Obrázok PCD + Slikovna datoteka PCD + Figurë PCD + PCD-bild + PCD görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ PCD + Ảnh PCD + PCD å›¾åƒ + PCD å½±åƒ + PCD + PhotoCD + + + + PNM image + صورة PNM + PNM rÉ™smi + Vyjava PNM + Изображение — PNM + imatge PNM + Obrázek PNM + Delwedd PNM + PNM-billede + PNM-Bild + εικόνα PNM + PNM image + PNM-bildo + imagen PNM + PNM irudia + PNM-kuva + PNM mynd + image PNM + íomhá PNM + imaxe PNM + תמונת PNM + PNM-kép + Citra PNM + Immagine PNM + PNM ç”»åƒ + PNM Ñуреті + PNM 그림 + PNM paveikslÄ—lis + PNM attÄ“ls + Imej PNM + PNM-bilde + PNM-afbeelding + PNM-bilete + Obraz PNM + imagem PNM + Imagem PNM + Imagine PNM + изображение PNM + Obrázok PNM + Slikovna datoteka PNM + Figurë PNM + PNM Ñлика + PNM-bild + PNM görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ PNM + Ảnh PNM + PNM å›¾åƒ + PNM å½±åƒ + + + + PBM image + صورة PBM + Vyjava PBM + Изображение — PBM + imatge PBM + Obrázek PBM + Delwedd PBM + PBM-billede + PBM-Bild + εικόνα PBM + PBM image + PBM-bildo + imagen PBM + PBM irudia + PBM-kuva + PBM mynd + image PBM + íomhá PBM + imaxe PBM + תמונת PBM + PBM kép + Citra PBM + Immagine PBM + PBM ç”»åƒ + PBM გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ PBM Ñуреті + PBM 그림 + PBM paveikslÄ—lis + PBM attÄ“ls + PBM-bilde + PBM-afbeelding + PBM-bilete + Obraz PBM + Imagem PBM + Imagine PBM + изображение PBM + Obrázok PBM + Slikovna datoteka PBM + Figurë PBM + PBM Ñлика + PBM-bild + PBM görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ PBM + Ảnh PBM + PBM å›¾åƒ + PBM å½±åƒ + PBM + Portable BitMap + + + + + + + + + + + + + + + + + + + PGM image + صورة PGM + Vyjava PGM + Изображение — PGM + imatge PGM + Obrázek PGM + Delwedd PGM + PGM-billede + PGM-Bild + εικόνα PGM + PGM image + PGM-bildo + imagen PGM + PGM irudia + PGM-kuva + PGM mynd + image PGM + íomhá PGM + imaxe PGM + תמונת PGM + PGM kép + Citra PGM + Immagine PGM + PGM ç”»åƒ + PGM Ñуреті + PGM 그림 + PGM paveikslÄ—lis + PGM attÄ“ls + PGM-bilde + PGM-afbeelding + PGM-bilete + Obraz PGM + Imagem PGM + Imagine PGM + изображение PGM + Obrázok PGM + Slikovna datoteka PGM + Figurë PGM + PGM-bild + PGM görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ PGM + Ảnh PGM + PGM å›¾åƒ + PGM å½±åƒ + PGM + Portable GrayMap + + + + + + + + + + + + + + + + + + + PPM image + صورة PPM + Vyjava PPM + Изображение — PPM + imatge PPM + Obrázek PPM + Delwedd PPM + PPM-billede + PPM-Bild + εικόνα PPM + PPM image + PPM-bildo + imagen PPM + PPM irudia + PPM-kuva + PPM mynd + image PPM + íomhá PPM + imaxe PPM + תמונת PPM + PPM kép + Citra PPM + Immagine PPM + PPM ç”»åƒ + PPM Ñуреті + PPM 그림 + PPM paveikslÄ—lis + PPM attÄ“ls + PPM-bilde + PPM-afbeelding + PPM-bilete + Obraz PPM + Imagem PPM + Imagine PPM + изображение PPM + Obrázok PPM + Slikovna datoteka PPM + Figurë PPM + PPM Ñлика + PPM-bild + PPM görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ PPM + Ảnh PPM + PPM å›¾åƒ + PPM å½±åƒ + PPM + Portable PixMap + + + + + + + + + + + + + + + + + + + Photoshop image + صورة Ùوتوشوب + Изображение — Photoshop + imatge de Photoshop + Obrázek Photoshop + Photoshop-billede + Photoshop-Bild + εικόνα Photoshop + Photoshop image + Photoshop-bildo + imagen de Photoshop + Photoshop irudia + Photoshop-kuva + Photoshop mynd + image Photoshop + íomhá Photoshop + imaxe de Photoshop + תמונת Photoshop + Photoshop-kép + Citra Photoshop + Immagine Photoshop + Photoshop ç”»åƒ + изображение Photoshop + í¬í† ìƒµ ì´ë¯¸ì§€ + Photoshop paveikslÄ—lis + Photoshop attÄ“ls + Imej Photoshop + Photoshop-afbeelding + Obraz Photoshop + imagem do Photoshop + Imagem do Photoshop + Imagine Photoshop + изображение Photoshop + Obrázok Photoshop + Slikovna datoteka Photoshop + Фотошоп Ñлика + Photoshop-bild + Photoshop görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Photoshop + Ảnh Photoshop + Photoshop å›¾åƒ + Photoshop å½±åƒ + + + + + + + + + + + + + RGB image + صورة RGB + RGB rÉ™smi + Vyjava RGB + Изображение — RGB + imatge RGB + Obrázek RGB + Delwedd RGB + RGB-billede + RGB-Bild + εικόνα RGB + RGB image + RGB-bildo + imagen RGB + RGB irudia + RGB-kuva + RGB mynd + image RGB + íomhá RGB + imaxe RGB + תמונת RGB + RGB slika + RGB-kép + Citra RGB + Immagine RGB + RGB ç”»åƒ + RGB Ñуреті + RGB 그림 + RGB paveikslÄ—lis + RGB attÄ“ls + Imej RGB + RGB-bilde + RGB-afbeelding + RGB-bilete + Obraz RGB + imagem RGB + Imagem RGB + Imagine RGB + изображение RGB + Obrázok RGB + Slikovna datoteka RGB + Figurë RGB + RGB Ñлика + RGB-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ RGB + Ảnh kiểu RGB + RGB å›¾åƒ + RGB å½±åƒ + + + + SGI image + صورة SGI + Vyjava SGI + Изображение — SGI + imatge SGI + Obrázek SGI + SGI-billede + SGI-Bild + εικόνα SGI + SGI image + SGI-bildo + imagen SGI + SGI irudia + SGI-kuva + SGI mynd + image SGI + íomhá SGI + imaxe SGI + תמונת SGI + SGI slika + SGI kép + Citra SGI + Immagine SGI + SGI ç”»åƒ + SGI Ñуреті + SGI 그림 + SGI paveikslÄ—lis + SGI attÄ“ls + SGI-bilde + SGI-afbeelding + SGI-bilete + Obraz SGI + Imagem SGI + Imagine SGI + изображение SGI + Obrázok SGI + Slikovna datoteka SGI + Figurë SGI + SGI-bild + SGI görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ SGI + Ảnh SGI + SGI å›¾åƒ + SGI å½±åƒ + + + + Sun raster image + صورة Sun raster + Rastravaja vyjava Sun + Изображение — Sun raster + imatge ràster Sun + Rastrový obrázek Sun + Sun rasterbillede + Sun-Rasterbild + εικόνα Sun raster + Sun raster image + imagen ráster de Sun + Sun raster irudia + Sun-rasterikuva + Sun raster mynd + image raster Sun + íomhá rastar Sun + imaxe ráster de Sun + תמונה סרוקה של Sun + SUN raszterkép + Citra raster Sun + Immagine raster Sun + Sun ãƒ©ã‚¹ã‚¿ç”»åƒ + Sun раÑтрлық Ñуреті + Sun 래스터 그림 + Sun rastrinis paveikslÄ—lis + Sun rastra attÄ“ls + Sun rasterbilde + Sun-rasterafbeelding + Sun rasterbilete + Obraz rastrowy Sun + Imagem raster da Sun + Imagine rasterizată Sun + раÑтровое изображение Sun + Rastrový obrázok Sun + Slikovna rastrska datoteka Sun + Figurë raster Sun + Sun-rasterbild + раÑтрове Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Sun + Ảnh mành Sun + Sun å…‰æ …å›¾åƒ + Sun raster å½±åƒ + + + + + + + TGA image + صورة TGA + Vyjava TGA + Изображение — TGA + imatge TGA + Obrázek TGA + TGA-billede + TGA-Bild + εικόνα TGA + TGA image + TGA-bildo + imagen TGA + TGA irudia + TGA-kuva + TGA mynd + image TGA + íomhá TGA + imaxe TGA + תמונת TGA + TGA slika + TGA kép + Citra TGA + Immagine TGA + TGA ç”»åƒ + TGA Ñуреті + TGA 그림 + TGA paveikslÄ—lis + TGA attÄ“ls + TGA-bilde + TGA-afbeelding + TGA-bilete + Obraz TGA + Imagem TGA + Imagine TGA + изображение TGA + Obrázok TGA + Slikovna datoteka TGA + Figurë TGA + TGA-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ TGA + Ảnh TGA + TGA å›¾åƒ + TGA å½±åƒ + TGA + Truevision Graphics Adapter + + + + + + + + + + + + + + + + + + + + + + + + Windows cursor + مؤشر ويندوز + Kursor Windows + КурÑор — Windows + cursor de Windows + Kurzor Windows + Windowsmarkør + Windows-Cursor + δείκτης παÏαθυÏÎ¹ÎºÎ¿Ï Ï€ÎµÏιβάλλοντος + Windows cursor + Windows-kursoro + cursor de Windows + Windows kurtsorea + Windows-osoitin + Windows vísi + curseur Windows + cúrsóir Windows + Cursor de Windows + סמן של Windows + Windows kursor + Windows-kurzor + Kursor Windows + Cursore Windows + Windows カーソル + Windows курÑоры + Windows 커서 + Windows žymiklis + Windows kursors + Kursor Windows + Windows-markør + Windows-muisaanwijzer + Windows-peikar + Kursor Windows + cursor Windows + Cursor do Windows + Cursor Windows + курÑор Windows + Kurzor Windows + Datoteka kazalke Windows + Kursor Windows + Виндуз курзор + Windows-muspekare + курÑор Windows + Con chạy Windows + Windows 光标 + Windows 滑鼠指標 + + + + + + + + + Windows animated cursor + مؤشر ويندوز المتحرك + Animavany kursor Windows + КурÑор — Windows, анимиран + cursor animat de Windows + Animovaný kurzor Windows + Windowsanimeret markør + Animierter Windows-Cursor + κινοÏμενος δÏομέας Windows + Windows animated cursor + cursor animado de Windows + Windows-eko kurtsore animatua + animoitu Windows-osoitin + Windows livindaigjørdur vísi + curseur animé Windows + cúrsóir beo Windows + Cursor animado de Windows + סמן מונפש של Windows + Windows animirani kursor + Windows animált kurzor + Kursor animasi Windows + Cursore animato Windows + Windows アニメーションカーソル + Windows анимациÑÑÑ‹ бар курÑор + Windows 움ì§ì´ëŠ” 커서 + Animuotas Windows žymiklis + Windows animÄ“ts kursors + geanimeerde Windows-muisaanwijzer + Windows animert peikar + Animowany kursor Windows + Cursor animado do Windows + Cursor animat Windows + анимированный курÑор Windows + Animovaný kurzor Windows + Datoteka animirane kazalke Windows + Kursor i animuar Windows + Animerad Windows-muspekare + анімований курÑор Windows + Con chạy hoạt há»a Windows + Windows 动画光标 + Windows 滑鼠動畫游標 + + + + + + + + + EMF image + صورة EMF + Vyjava EMF + Изображение — EMF + imatge EMF + Obrázek EMF + EMF-billede + EMF-Bild + εικόνα EMF + EMF image + EMF-bildo + imagen EMF + EMF irudia + EMF-kuva + EMF mynd + image EMF + íomhá EMF + imaxe EMF + תמונת EMF + EMF slika + EMF kép + Citra EMF + Immagine EMF + EMF ç”»åƒ + EMF გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ EMF Ñуреті + EMF 그림 + EMF paveikslÄ—lis + EMF attÄ“ls + EMF-bilde + EMF-afbeelding + EMF-bilete + Obraz EMF + Imagem EMF + Imagine EMF + изображение EMF + Obrázok EMF + Slikovna datoteka EMF + Figurë EMF + EMF-bild + EMF görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ EMF + Ảnh EMF + EMF å›¾åƒ + EMF å½±åƒ + EMF + Enhanced MetaFile + + + + + + + + + + + + + + + + WMF image + صورة WMF + Vyjava WMF + Изображение — WMF + imatge WMF + Obrázek WMF + WMF-billede + WMF-Bild + εικόνα WML + WMF image + WMF-bildo + imagen WMF + WMF irudia + WMF-kuva + WMF mynd + image WMF + íomhá WMF + imaxe WMF + תמונת WMF + WMF slika + WMF kép + Citra WMF + Immagine WMF + WMF ç”»åƒ + WMF Ñуреті + WMF 그림 + WMF paveikslÄ—lis + WMF attÄ“ls + WMF-bilde + WMF-afbeelding + WMF-bilete + Obraz WMF + Imagem WMF + Imagine WMF + изображение WMF + Obrázok WMF + Slikovna datoteka WMF + Figurë WMF + WMF-bild + WMF görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ WMF + Ảnh WMF + WMF å›¾åƒ + WMF å½±åƒ + WMF + Windows Metafile + + + + + + + + + + + + + + + + + + + + + + XBM image + صورة XBM + Vyjava XBM + Изображение — XBM + imatge XBM + Obrázek XBM + XBM-billede + XBM-Bild + εικόνα XBM + XBM image + XBM-bildo + imagen XBM + XBM irudia + XBM-kuva + XBM mynd + image XBM + íomhá XBM + imaxe XBM + תמונת XBM + XBM slika + XBM-kép + Citra XBM + Immagine XBM + XBM ç”»åƒ + XBM Ñуреті + XBM 그림 + XBM paveikslÄ—lis + XBM attÄ“ls + XBM-bilde + XBM-afbeelding + XBM-bilete + Obraz XBM + Imagem XBM + Imagine XBM + изображение XBM + Obrázok XBM + Slikovna datoteka XBM + Figurë XBM + XBM-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ XBM + Ảnh XBM + XBM å›¾åƒ + XBM å½±åƒ + XBM + X BitMap + + + + GIMP image + صورة GIMP + Vyjava GIMP + Изображение — GIMP + imatge del GIMP + Obrázek GIMP + GIMP-billede + GIMP-Bild + εικόνα GIMP + GIMP image + GIMP-bildo + imagen del GIMP + GIMP irudia + GIMP-kuva + GIMP mynd + image GIMP + íomhá GIMP + imaxe de GIMP + תמונת GIMP + GIMP slika + GIMP-kép + Citra GIMP + Immagine GIMP + GIMP ç”»åƒ + GIMP გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბრ+ GIMP Ñуреті + GIMP 그림 + GIMP paveikslÄ—lis + GIMP attÄ“ls + Imej GIMP + GIMP-bilde + GIMP-afbeelding + GIMP-bilete + Obraz GIMP + imagem do GIMP + Imagem do GIMP + Imagine GIMP + изображение GIMP + Obrázok GIMP + Slikovna datoteka GIMP + Figurë GIMP + Гимп Ñлика + GIMP-bild + GIMP görüntüsü + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ GIMP + Ảnh GIMP + GIMP å›¾åƒ + GIMP å½±åƒ + + + + + + + + + XFig image + صورة XFig + Vyjava XFig + Изображение — XFig + imatge de XFig + Obrázek XFig + XFig-billede + XFig-Bild + εικόνα XFig + XFig image + XFig-bildo + imagen de XFig + XFig irudia + XFig-kuva + XFig mynd + image XFig + íomhá XFig + imaxe de XFig + תמונת XFig + XFig slika + XFig-kép + Citra XFig + Immagine XFig + XFig ç”»åƒ + XFig Ñуреті + XFig 그림 + XFig paveikslÄ—lis + XFig attÄ“ls + Imej XFig + XFig-bilde + XFig-afbeelding + XFig-bilete + Obraz XFig + imagem XFig + Imagem do XFig + Imagine XFig + изображение XFig + Obrázok XFig + Slikovna datoteka XFig + Figurë XFig + XFig Ñлика + XFig-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ XFig + Ảnh XFig + XFig å›¾åƒ + XFig å½±åƒ + + + + + + + XPM image + صورة XPM + Vyjava XPM + Изображение — XPM + imatge XPM + Obrázek XPM + Delwedd XPM + XPM-billede + XPM-Bild + εικόνα XPM + XPM image + XPM-bildo + imagen XPM + XPM irudia + XPM-kuva + XPM mynd + image XPM + íomhá XPM + imaxe XPM + תמונת XPM + XPM slika + XPM kép + Citra XPM + Immagine XPM + XPM ç”»åƒ + XPM Ñуреті + XPM 그림 + XPM paveikslÄ—lis + XPM attÄ“ls + XPM-bilde + XPM-afbeelding + XPM-bilete + Obraz XPM + Imagem XPM + Imagine XPM + изображение XPM + Obrázok XPM + Slikovna datoteka XPM + Figurë XPM + XPM-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ XPM + Ảnh XPM + XPM å›¾åƒ + XPM å½±åƒ + XPM + X PixMap + + + + + + + + X window image + صورة X window + X window rÉ™smi + Vyjava vakna X + Изображение — X Window + imatge de X window + Obrázek X window + Delwedd ffenest X + X-billede + X-Window-Bild + εικόνα πεÏιβάλλοντος X + X window image + bildo de X window + imagen de X window + X window irudia + X-ikkunakuva + X vindeyga mynd + image X window + íomhá fhuinneog X + imaxe de X Window + תמונת חלון של X + X window slika + X window-kép + Citra X window + Immagine X window + X window ç”»åƒ + X window Ñуреті + X ìœˆë„ ê·¸ë¦¼ + X window paveikslÄ—lis + X window attÄ“ls + Imej tetingkap X + X-Windows skjermbilde + X-window-afbeelding + X window bilete + Obraz X Window + imagem de janela X + Imagem de janela do X + Imagine X window + изображение X window + Obrázok X window + slika X oken + Figurë X window + X прозор Ñлика + X-fönsterbild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ X window + Ảnh cá»­a sổ X + X window å›¾åƒ + X window å½±åƒ + + + + block device + جهاز كتلي + blokavaja pryÅ‚ada + Блоково уÑтройÑтво + dispositiu de blocs + Blokové zařízení + blokenhed + Blockorientiertes Gerät + συσκευή block + block device + bloka disponaĵo + dispositivo de bloques + bloke-gailua + laitetiedosto + blokka tóleind + périphérique de blocs + gléas bloc + dispositivo de bloque + התקן בלוק + blokkos eszköz + blok divais + Device a blocchi + ブロックデãƒã‚¤ã‚¹ + блоктық құрылғыÑÑ‹ + ë¸”ë¡ ìž¥ì¹˜ + blokinis įrenginys + bloka ierÄ«ce + Peranti blok + blokkenhet + blok-apparaat + blokk-eining + UrzÄ…dzenie blokowe + dispositivo de bloco + Dispositivo de bloco + dispozitiv bloc + блочное уÑтройÑтво + Blokové zariadenie + bloÄna naprava + device me blloqe + блок уређај + blockenhet + blok aygıtı + блоковий приÑтрій + thiết bị khối + å—设备 + å€å¡Šè£ç½® + + + character device + جهاز حرÙÙŠ + znakavaja pryÅ‚ada + Символно уÑтройÑтво + dispositiu de caràcters + Znakové zařízení + tegnenhed + Zeichenorientiertes Gerät + συσκευή χαÏακτήÏων + character device + signa disponaĵo + dispositivo de caracteres + karaktereen gailua + merkkilaite + stavatóleind + périphérique de caractères + gléas carachtar + dispositivo de caracter + התקן תכונה + karakteres eszköz + karakter divais + Device a caratteri + キャラクタデãƒã‚¤ã‚¹ + Ñимволдық құрылғыÑÑ‹ + ë¬¸ìž ìž¥ì¹˜ + simbolinis įrenginys + rakstzÄ«mju ierÄ«ce + Peranti aksara + tegnenhet + byte-apparaat + teikneining + UrzÄ…dzenie znakowe + dispositivo de caracteres + Dispositivo de caractere + dispozitiv caracter + Ñимвольное уÑтройÑтво + Znakové zariadenie + znakovna naprava + device me karaktere + знаковни уређај + teckenenhet + karakter aygıtı + Ñимвольний приÑтрій + thiết bị ký tá»± + 字符设备 + å­—å…ƒè£ç½® + + + folder + مجلّد + kataloh + Папка + carpeta + Složka + mappe + Ordner + φάκελος + folder + dosierujo + carpeta + karpeta + kansio + mappa + dossier + fillteán + cartafol + תיקייה + direktorij + mappa + folder + Cartella + フォルダー + бума + í´ë” + aplankas + mape + Folder + mappe + map + mappe + Katalog + pasta + Pasta + dosar + папка + PrieÄinok + mapa + Kartelë + директоријум + mapp + dizin + тека + thÆ° mục + 文件夹 + 資料夾 + + + + pipe + إنبوب + kanvejer + Конвейер + conducte + Roura + datakanal + Pipe + σωλήνωση + pipe + dukto + tubería + kanalizazioa + putki + rør + tube + píopa + tubería + צינור + adatcsatorna + pipa + Pipe + パイプ + арна + 파ì´í”„ + konvejeris + programmkanÄls + Paip + rør + pijp + røyr + Potok + canal + Pipe + canal pipe + канал + Rúra + cev + Pipe + цев + rör + канал + ống dẫn + ç®¡é“ + 管線 + + + mount point + نقطة الوصْل + punkt mantavaÅ„nia + Точка на монтиране + punt de muntatge + Místo pÅ™ipojení + monteringspunkt + Einhängepunkt + σημείο Ï€ÏοσάÏτησης + mount point + surmetingo + punto de montaje + muntatze-puntua + liitospiste + ísetingarpunkt + point d'accès + pointe feistithe + punto de montaxe + נקודת עיגון + toÄka montiranja + csatolási pont + titik mount + Punto di mount + マウントãƒã‚¤ãƒ³ãƒˆ + тіркеу нүктеÑÑ– + 마운트 위치 + prijungimo taÅ¡kas + montÄ“Å¡anas punkts + Titik lekapan + monteringspunkt + aankoppelingspunt + monteringspunkt + Punkt montowania + ponto de montagem + Ponto de montagem + loc montare + точка Ð¼Ð¾Ð½Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ + Miesto pripojenia + priklopna toÄka + Pikë montimi + тачка прикључења + monteringspunkt + точка Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ + Ä‘iểm lắp + 挂载点 + 掛載點 + + + + socket + مقبس + sokiet + Гнездо + sòcol + Socket + sokkel + Socket + υποδοχή + socket + kontaktoskatolo + socket + socketa + pistoke + sokkul + connecteur réseau + soicéad + socket + נקודת חיבור + utiÄnica + illesztÅ‘pont + soket + Socket + ソケット + Ñокет + 소켓 + lizdas + sokets + Soket + plugg + socket + sokkel + Gniazdo + 'socket' + Socket + socket + Ñокет + Soket + vtiÄ + Socket + Ñокет + uttag + Ñокет + ổ cắm + 套接字 + socket + + + symbolic link + وصلة رمزية + simvolik körpü + symbalnaja spasyÅ‚ka + Символна връзка + enllaç simbòlic + Symbolický odkaz + cyswllt symbolaidd + symbolsk henvisning + Symbolische Verknüpfung + συμβολικός σÏνδεσμος + symbolic link + simbola ligilo + enlace simbólico + esteka sinbolikoa + symbolinen linkki + tykislig leinkja + lien symbolique + nasc siombalach + ligazón simbólica + קישור סימבולי + simboliÄka veza + szimbolikus link + taut simbolik + Collegamento simbolico + シンボリックリンク + სიმბáƒáƒšáƒ£áƒ áƒ˜ ბმული + Ñимволдық Ñілтеме + 심볼릭 ë§í¬ + simbolinÄ— nuoroda + simboliskÄ saite + Pautan simbolik + symbolsk lenke + symbolische koppeling + symbolsk lenkje + DowiÄ…zanie symboliczne + ligação simbólica + Ligação simbólica + legătură simbolică + ÑÐ¸Ð¼Ð²Ð¾Ð»ÑŒÐ½Ð°Ñ ÑÑылка + Symbolický odkaz + simbolna povezava + Lidhje simbolike + Ñимболичка веза + symbolisk länk + Ñимволічне поÑÐ¸Ð»Ð°Ð½Ð½Ñ + liên kết tượng trÆ°ng + 符å·é“¾æŽ¥ + 符號éˆçµ + + + mail delivery report + تقرير تسليم البريد + poçt yollama raportu + rapart ab dastaÅ­cy poÅ¡ty + Отчет за приÑтигналата поща + informe de lliurament de correu + Zpráva o doruÄení poÅ¡ty + Adroddiad trosgludo post + postleveringsrapport + E-Mail-Zustellungsbericht + αναφοÏά παÏάδοσης μηνÏματος + mail delivery report + raporto pri transdono de retpoÅto + informe de entrega de correo + posta banaketako txostena + viestin jakeluilmoitus + post útberingarfrásøgn + rapport de livraison de courriels + tuairisc sheachadadh poist + informe de entrega de correo + דוח העברת דו×ר + izvjeÅ¡taj dostave poÅ¡te + jelentés levélkézbesítésrÅ‘l + laporan pengantaran surat + Rapporto di consegna posta + メールé…é€ãƒãƒ¼ãƒˆ + пошта жеткізілгені туралы отчет + ë©”ì¼ ë°°ë‹¬ ë³´ê³ ì„œ + paÅ¡to pristatymo ataskaita + pasta piegÄdes atskaite + Laporan penghantaran mel + e-postleveranserapport + e-mail-bezorgingsbericht + e-post-leveringsrapport + Raport z dostarczenia poczty + relatório de entrega de e-mail + Relatório de entrega de correspondência + raport de trimitere email + отчёт о доÑтавке ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ + Správa o doruÄení poÅ¡ty + poroÄilo dostave poÅ¡te + Raport mbi dorëzimin e mesazhit + извештај доÑтаве поруке + e-postleveransrapport + звіт про доÑтавку пошти + thông báo phát thÆ° + 邮件投递报告 + 郵件寄é€å›žå ± + + + + + mail disposition report + تقرير ترتيب البريد + poçt qayıtma raportu + rapart ab raźmiaÅ¡ÄeÅ„ni poÅ¡ty + Отчет за ÑÑŠÑтоÑнието на пощата + informe de disposició de correu + Zpráva o pÅ™edání poÅ¡ty + adroddiad ffurf post + postdisponeringsrapport + E-Mail-Ãœbertragungsbericht + αναφοÏά διάθεσης μηνÏματος + mail disposition report + raporto pri dispono de retpoÅto + informe de disposición de correo + posta joerako txostena + viestin kuittausilmoitus + post avhendingarfrásøgn + rapport de disposition de courriels + tuairisc chóiriú poist + informe de disposición de correo + דוח ×ספקת דו×ר + jelentés levélkidobásról + laporan disposisi surat + Rapporto di disposizione posta + メールåœæ­¢ãƒ¬ãƒãƒ¼ãƒˆ + пошта жылжытылғаны туралы отчет + ë©”ì¼ ì²˜ë¦¬ ë³´ê³ ì„œ + paÅ¡to charakteristikos ataskaita + pasta izvietojuma atskaite + Laporan pelupusan mel + e-postdispositionsrapport + e-mail-plaatsingsbericht + e-post-disposisjonsrapport + Raport z wysyÅ‚ania poczty + relatório de disposição de e-mail + Relatório de disposição de correspondência + confirmare primire email + отчёт о перемещении почты + Správa o odovzdaní poÅ¡ty + poroÄilo razporeditve poÅ¡te + Raport mbi njoftimin e mesazhit + извештај Ñлања поруке + e-postdispositionsrapport + звіт про Ñ€Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾ÑˆÑ‚Ð¸ + thông báo chuyển nhượng thÆ° + 邮件接收报告 + 郵件處置回報 + + + + + reference to remote file + مرجع إلى مل٠بعيد + uzaq fayla göstÉ™riÅŸ + spasyÅ‚ka da addalenaha fajÅ‚u + Препратка към отдалечен файл + referència a fitxer remot + Odkaz na vzdálený soubor + cyfeiriad at ffeil bell + reference til fjern fil + Verweis auf entfernte Datei + αναφοÏά σε απόμακÏο αÏχείο + reference to remote file + referenco al fora dosiero + referencia a un archivo remoto + erreferentzia urruneko fitxategiari + viittaus etätiedostoon + tilvísing til fjarfílu + référence au fichier distant + tagairt do chomhad cianda + referencia a un ficheiro remoto + התיחסות לקובץ מרוחק + referenca na udaljenu datoteku + hivatkozás távoli fájlra + referensi ke berkas jarak jauh + Riferimento a file remoto + リモートファイルã¸ã®å‚ç…§ + қашықтағы файлға Ñілтеме + ì›ê²© íŒŒì¼ ì°¸ì¡° + nuoroda į nutolusį failÄ… + norÄde uz attÄlinÄtu datni + Rujukan ke fail jauh + referanse til ekstern fil + verwijzing naar bestand op afstand + referanse til fil over nettverk + OdwoÅ‚anie do pliku zdalnego + referência a um ficheiro remoto + Referência a um arquivo remoto + referință fiÈ™ier la distanță + ÑÑылка на удалённый файл + Odkaz na vzdialený súbor + sklic do oddaljene datoteke + Referim për tek file në distancë + референца на удаљену датотеку + referens till fjärrfil + поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° віддалений файл + tham chiếu đến tập tin ở xa + 到远程文件的引用 + é ç«¯æª”案的åƒç…§ + + + + Usenet news message + رسالة أخبار Usenet + Usenet xÉ™bÉ™rlÉ™r ismarışı + Navina Usenet + Съобщение — Usenet + missatge de notícies Usenet + PříspÄ›vek do diskusních skupin Usenet + Neges newyddion Usenet + Usenetnyhedsmeddelelse + Usenet-News-Nachricht + μήνυμα ομάδων συζητήσεων Usenet + Usenet news message + novaĵmesaÄo de Usenet + mensaje de noticias de Usenet + Usenet berrien mezua + nyyssiviesti + Usenet news boð + message de groupe d'échange Usenet + teachtaireacht nuacht Usenet + mensaxes de noticias de Usenet + הודעת חדשות של Usenet + Usenet poruka novosti + USENET-hírcsoportüzenet + Pesan berita Usenet + Messaggio news Usenet + Usenet news メッセージ + Usenet жаңалық мәлімдемеÑÑ– + 유즈넷 뉴스 메시지 + Usenet naujienų žinutÄ— + Usenet jaunumu ziņojums + Mesej berita USENET + Usenet nyhetsmelding + Usenet-nieuwsbericht + USENET diskusjonsmelding + Wiadomość grupy dyskusyjnej + mensagem de notícias Usenet + Mensagem de notícias da Usenet + Mesaj Usenet de È™tiri + новоÑтное Ñообщение Usenet + Príspevok do diskusných skupín Usenet + noviÄarsko sporoÄilo Usenet + Mesazh lajmesh Usenet + Порука Ñа диÑкуÑионе групе + Usenet-diskussionsgruppsmeddelande + Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ð¾Ð²Ð¸Ð½ Usenet + Thông Ä‘iệp tin tức USENET + Usenet 新闻信 + Usenet æ–°èžè¨Šæ¯ + + + + + + + + + + partial email message + رسالة البريد الإلكتروني الجزئية + qismi poçt ismarışı + niapoÅ­ny list email + ЧаÑÑ‚ от електронно пиÑмо + missatge de correu electrònic parcial + ČásteÄná e-mailová zpráva + darn o neges e-bost + delvis postmeddelelse + E-Mail-Nachrichtenfragment + τμηματικό ηλ. μήνυμα + partial email message + parta retpoÅta mesaÄo + mensaje de correo electrónico parcial + posta mezu partziala + osittainen sähköpostiviesti + message partiel de courriel + teachtaireacht ríomhphoist neamhiomlán + mensaxe de correo electrónico parcial + מסר דו×"ל חלקי + djelomiÄna poruka e-poÅ¡te + részleges elektronikus levél + pesan email sebagian + Messaggio email parziale + 部分メールメッセージ + Ñлектронды поштаның үзінді мәлімдемеÑÑ– + ë¶€ë¶„ì  ì „ìž ìš°íŽ¸ 메시지 + nepilnas el. laiÅ¡kas + daļēja e-pasta vÄ“stule + Bahagian mesej emel + del av e-postmelding + gedeeltelijk e-mailbericht + del av e-post-melding + Częściowa wiadomość e-mail + mensagem parcial de e-mail + Mensagem de e-mail parcial + mesaj de email parÈ›ial + фрагмент ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñлектронной почты + ÄŒiastoÄná e-mailová správa + delno elektronsko sporoÄilo + Mesazh poste i pjesëshëm + делимична е-порука + del av e-postmeddelande + чаÑткове поштове Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ + thÆ° Ä‘iện tá»­ riêng phần + 部分电å­é‚®ä»¶ + 部份電å­éƒµä»¶è¨Šæ¯ + + + + + email message + رسالة البريد الإلكتروني + list email + Съобщение по електронната поща + missatge de correu electrònic + E-mailová zpráva + postmeddelelse + E-Mail-Nachricht + ηλ. μήνυμα + email message + retpoÅta mesaÄo + mensaje de correo electrónico + helbide elektronikoen mezua + sähköpostiviesti + t-post boð + message de courriel + teachtaireacht ríomhphoist + mensaxe de correo electrónico + הודעת דו×ר ×לקטרוני + poruka e-poÅ¡te + elektronikus levél + pesan email + Messaggio email + メール本文 + пошталық мәлімдеме + ì „ìž ìš°íŽ¸ 본문 + el. laiÅ¡kas + e-pasta vÄ“stule + Mesej emel + e-postmelding + e-mailbericht + e-postmelding + Wiadomość e-mail + mensagem de e-mail + Mensagem de e-mail + mesaj email + почтовое Ñообщение + E-mailová správa + sporoÄilo elektronske poÅ¡te + Mesazh poste + е-порука + e-postmeddelande + Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ email + thÆ° Ä‘iện tá»­ + 电å­é‚®ä»¶ + é›»å­éƒµä»¶å…§å®¹ + + + + + + + + + + + + + + + + + + GNU mail message + رسالة بريد جنو + GNU poçt ismarışı + List GNU + Съобщение — GNU mail + missatge de GNU mail + Zpráva GNU mail + Neges E-Bost GNU + GNU-postmeddelelse + GNU-Mail-Nachricht + μήνυμα αλληλογÏαφίας GNU + GNU mail message + mesaÄo de GNU mail + mensaje de GNU mail + GNU posta mezua + GNU-postiviesti + GNU mail boð + message de courriel GNU + teachtaireacht phost GNU + mensaxe de correo electrónico de GNU + הודעת דו×ר של GNU + GNU poruka poÅ¡te + GNU elektronikus levél + Pesan surat GNU + Messaggio GNU mail + GNU メールメッセージ + GNU mail შეტყáƒáƒ‘ინებრ+ GNU пошта хабарламаÑÑ‹ + GNU ë©”ì¼ ë©”ì‹œì§€ + GNU paÅ¡to žinutÄ— + GNU pasta vÄ“stule + Mesej emel GNU + GNU e-postmelding + GNU-mailbericht + GNU e-postmelding + Wiadomość pocztowa GNU + mensagem de e-mail GNU + Mensagem de correio GNU + Mesaj GNU mail + почтовое Ñообщение GNU + Správa GNU mail + SporoÄilo poÅ¡te GNU + Mesazh GNU mail + ГÐУ е-пиÑмо + GNU-epostmeddelande + поштове Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ GNU + ThÆ° Ä‘iện tá»­ của GNU + GNU mail 信件 + GNU éƒµä»¶è¨Šæ¯ + + + + + VRML document + مستند VRML + VRML sÉ™nÉ™di + Dakument VRML + Документ — VRML + document VRML + Dokument VRML + Dogfen VRML + VRML-dokument + VRML-Dokument + έγγÏαφο VRML + VRML document + VRML-dokumento + documento VRML + VRML dokumentua + VRML-asiakirja + VRML skjal + document VRML + cáipéis VRML + documento VRML + מסמך VRML + VRML dokument + VRML-dokumentum + Dokumen VRML + Documento VRML + VRML ドキュメント + VRML құжаты + VRML 문서 + VRML dokumentas + VRML dokuments + Dokumen VRML + VRML-dokument + VRML-document + VRML-dokument + Dokument VRML + documento VRML + Documento VRML + Document VRML + документ VRML + Dokument VRML + Dokument VRML + Dokument VRML + VRML документ + VRML-dokument + VRML belgesi + документ VRML + Tài liệu VRML + VRML 文档 + VRML 文件 + VRML + Virtual Reality Modeling Language + + + + + + + + message in several formats + رسالة ÙÙŠ عدة صيغ + verici formatlarında ismarış + paviedamleÅ„nie Å­ niekalkich farmatach + Съобщение в нÑколко формата + missatge en varis formats + Zpráva v nÄ›kolika formátech + neges mewn sawl fformat + meddelelse i flere formater + Nachricht in mehreren Formaten + μήνυμα σε διάφοÏες μοÏφές + message in several formats + mesaÄo en pluraj formatoj + mensaje en varios formatos + hainbat formatuko mezua + viesti useissa muodoissa + boð í fleiri sniðum + message en formats divers + teachtaireacht i roinnt fhormáidí + mensaxe en varios formatos + הודעה במספר ×¤×•×¨×ž×˜×™× + poruka u nekoliko oblika + többféle formátumú üzenet + pesan dalam beberapa format + Messaggio in diversi formati + ã„ãã¤ã‹ã®å½¢å¼ã§ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ + бірнеше пішімдегі мәлімдеме + 여러가지 형ì‹ì˜ 메시지 + laiÅ¡kas keletu formatų + ziņojums dažÄdos formÄtos + Mesej dalam beberapa format + melding i flere formater + bericht in meerdere opmaken + melding i fleire format + Wiadomość w wielu formatach + mensagem em vários formatos + Mensagem em vários formatos + mesaj în diferite formate + Ñообщение в неÑкольких форматах + Správa v niekoľkých formátoch + sporoÄilo v veÄ zapisih + Mesazh në formate të ndryshëm + поруке у више запиÑа + meddelande i flera format + Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñƒ кількох форматах + thông Ä‘iệp có vài định dạng + å„ç§æ ¼å¼çš„æ¶ˆæ¯ + 多種格å¼çš„è¨Šæ¯ + + + Macintosh AppleDouble-encoded file + مل٠Macintosh AppleDouble مشÙر + Macintosh AppleDouble-kodlanmış fayl + FajÅ‚ Macintosh, AppleDouble-zakadavany + Файл — кодиран Ñ Macintosh AppleDouble + fitxer codificat AppleDouble de Macintosh + Soubor kódovaný pomocí Macintosh AppleDouble + Ffeil AppleDouble-amgodedig Macintosh + Macintosh AppleDouble-kodet fil + Macintosh-Datei (AppleDouble-kodiert) + αÏχείο Macintosh κωδικοποίησης AppleDouble + Macintosh AppleDouble-encoded file + dosiero kodigita laÅ­ Macintosh AppleDouble + archivo Macintosh codificado con AppleDouble + Macintosh AppleDouble-rekin kodetutako fitxategia + Macintosh AppleDouble -koodattu tiedosto + Macintosh AppleDouble-bronglað fíla + fichier codé Macintosh AppleDouble + comhad ionchódaithe le Macintosh AppleDouble + ficheiro de Macintosh codificado con AppleDouble + קובץ מסוג Macintosh AppleDouble-encoded + Macintosh AppleDouble-kodirana datoteka + Macintosh AppleDouble kódolású fájl + Berkas tersandi Macintosh AppleDouble + File Macintosh codificato AppleDouble + Macintosh AppleDouble エンコードファイル + Macintosh AppleDouble кодталған файлы + 매킨토시 AppleDouble ì¸ì½”ë”©ëœ íŒŒì¼ + Macintosh AppleDouble-encoded failas + Macintosh AppleDouble-kodÄ“ts datne + Fail terenkod-AppleDouble Macintosh + dokument kodet med Macintosh AppleDouble + Macintosh AppleDouble-gecodeerd bestand + Macintosh AppleDouble-koda fil + Zakodowany w AppleDouble plik Macintosh + ficheiro codificado em AppleDouble de Macintosh + Arquivo do Macintosh codificado com AppleDouble + FiÈ™ier codat Macintosh AppleDouble + файл (закодированный Macintosh AppleDouble) + Súbor kódovaný pomocou Macintosh AppleDouble + Kodirana datoteka Macintosh (AppleDouble) + File Macintosh i kodifikuar AppleDouble + Мекинтош AppleDouble-encoded датотека + Macintosh AppleDouble-kodad fil + файл закодований Macintosh AppleDouble + Tập tin đã mã hoá Apple-Double của Macintosh + Macintosh AppleDouble ç¼–ç çš„文件 + Macintosh AppleDouble 編碼檔 + + + message digest + خلاصة الرسالة + ismarış daycesti + digest paviedamleÅ„niaÅ­ + Извадка от Ñъобщение + recopilació de missatges + PÅ™ehled zpráv + crynodeb negeseuon + meddelelsessammendrag + Nachrichtensammlung + πεÏίληψη μηνÏματος + message digest + mesaÄaro + recopilación de mensajes + mezu laburra + viestikokoelma + boð samandráttur + condensé de message + achoimre theachtaireachtaí + recompilación de mensaxe + תקציר ההודעה + ömlesztett üzenet + pesan digest + Digest di messaggi + メッセージダイジェスト + мәлімдеме профилі + 메시지 ë¬¶ìŒ + laiÅ¡kų santrauka + ziņojumu apkopojums + Jilid mesej + medldingssamling + berichtenbundel + meldingsamandrag + Wiadomość przetwarzania + 'digest' de mensagens + Resumo de mensagem + colecÈ›ie mesaje email + профиль ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ + Prehľad správ + povzetek sporoÄila + Shpërndarje mesazhesh + гомила порука + meddelandesamling + збірка повідомлень + bản tóm tắt thông Ä‘iệp + 消æ¯æ‘˜è¦ + 訊æ¯æ‘˜è¦ + + + encrypted message + رسالة مشÙرة + ÅŸifrÉ™lÉ™nmiÅŸ ismarış + zaÅ¡yfravanaje paviedamleÅ„nie + Шифрирано Ñъобщение + missatge xifrat + ZaÅ¡ifrovaná zpráva + Neges wedi ei hamgryptio + krypteret meddelelse + Verschlüsselte Nachricht + κÏυπτογÏαφημένο μήνυμα + encrypted message + ĉifrita mesaÄo + mensaje cifrado + mezu enkriptatua + salattu viesti + bronglað boð + message chiffré + teachtaireacht chriptithe + mensaxe cifrado + הודעה מוצפנת + Å¡ifrirana poruka + titkosított üzenet + pesan terenkripsi + Messaggio cifrato + æš—å·åŒ–メッセージ + шифрленген мәлімдеме + ì•”í˜¸í™”ëœ ë©”ì‹œì§€ + užšifruotas laiÅ¡kas + Å¡ifrÄ“ta vÄ“stule + Mesej terenkripsi + kryptert melding + versleuteld bericht + kryptert melding + Wiadomość zaszyfrowana + mensagem cifrada + Mensagem criptografada + mesaj criptat + зашифрованное Ñообщение + ZaÅ¡ifrovaná správa + Å¡ifrirano sporoÄilo + Mesazh i kriptuar + шифрована порука + krypterat meddelande + ÅŸifrelenmiÅŸ mesaj + шифроване Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ + thông Ä‘iệp đã mật mã + 加密信件 + åŠ å¯†è¨Šæ¯ + + + compound documents + مستندات مركبة + skÅ‚adanyja dakumenty + СъÑтавни документи + documents composats + Složené dokumenty + sammensatte dokumenter + Verbunddokumente + σÏνθετα έγγÏαφα + compound documents + parentezaj dokumentoj + documentos compuestos + konposatutako dokumentuak + yhdisteasiakirjat + samansett skjøl + documents composés + cáipéisí comhshuite + documentos compostos + ×ž×¡×ž×›×™× ×ž×•×¨×›×‘×™× + összetett dokumentumok + dokumen kompon + Documenti composti + 複åˆãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆ + құрама құжаттары + 복합 문서 + sudurtiniai dokumentai + salikti dokumenti + Dokumen halaman + sammensatte dokumenter + samengestelde documenten + samansette dokument + Dokumenty zÅ‚ożone + documentos compostos + Documentos compostos + documente compuse + ÑоÑтавные документы + Zložené dokumenty + združeni dokumenti + dokumente të përbërë + Ñједињени документи + sammansatta dokument + Ñкладні документи + tài liệu ghép + 组åˆæ–‡æ¡£ + 複åˆæ–‡ä»¶ + + + compound document + مستند مركب + birləşik sÉ™nÉ™d + skÅ‚adany dakument + СъÑтавен документ + document composat + Složený dokument + dogfen gyfansawdd + sammensat dokument + Verbunddokument + σÏνθετο έγγÏαφο + compound document + parenteza dokumento + documento compuesto + konposatutako dokumentua + yhdisteasiakirja + samansett skjal + document composé + cáipéis comhshuite + documento composto + מסמך מורכב + összetett dokumentum + dokumen kompon + Documento composto + 複åˆãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆ + құрама құжаты + 복합 문서 + sudurtinis dokumentas + salikts dokuments + Dokumen halaman + sammensatt dokument + samengesteld document + samansett dokument + Dokument zÅ‚ożony + documento composto + Documento composto + document compus + ÑоÑтавной документ + Zložený dokument + združeni dokument + dokumet i përbërë + Ñједињени документ + sammansatt dokument + Ñкладний документ + tài liệu ghép + 组åˆæ–‡æ¡£ + 複åˆæ–‡ä»¶ + + + mail system report + تقرير نظام البريد + poçt sistemi raportu + rapart paÅ¡tovaj systemy + Отчет за пощенÑката ÑиÑтема + informe de sistema de correu + Zpráva poÅ¡tovního systému + adroddiad system bost + postsystemrapport + E-Mail-Systembericht + αναφοÏά συστήματος ηλ. ταχυδÏομείου + mail system report + raporto de retpoÅta sistemo + informe del sistema de correo + posta sistemako txostena + viestijärjestelmän ilmoitus + postkervisfrásøgn + rapport système de courriels + tuairisc chóras poist + informe do sistema de correo + דו"×— של מערכת הדו×ר + levelezÅ‘rendszer jelentése + laporan sistem surat + Rapporto di sistema posta + メールシステムレãƒãƒ¼ãƒˆ + пошта жүйеÑінің мәлімдемеÑÑ– + ë©”ì¼ ì‹œìŠ¤í…œ ë³´ê³ ì„œ + paÅ¡to sistemos ataskaita + pasta sistÄ“mas atskaite + Laporan sistem mel + e-postsystemrapport + e-mail-systeembericht + e-post-systemrapport + Raport systemu pocztowego + relatório de sistema de e-mail + Relatório do sistema de correspondência + raport sistem email + отчёт почтовой ÑиÑтемы + Správa poÅ¡tového systému + poroÄilo poÅ¡tnega sistema + Raport i sistemit të postës + извештај поштанÑког ÑиÑтема + e-postsystemrapport + звіт поштової ÑиÑтеми + thông báo hệ thống thÆ° + 邮件系统报告 + 郵件系統回報 + + + signed message + رسالة موقّعة + imzalanmış ismarış + padpisanaje paviedamleÅ„nie + ПодпиÑано Ñъобщение + missatge signat + Podepsaná zpráva + neges lofnodwyd + signeret meddelelse + Signierte Nachricht + υπογεγÏαμμένο μήνυμα + signed message + pruvita mesaÄo + mensaje firmado + sinatutako mezua + allekirjoitettu viesti + undirskrivað boð + message signé + teachtaireacht sínithe + mensaxe firmado + הודעה חתומה + potpisana poruka + aláírt üzenet + pesan ditandatangani + Messaggio firmato + ç½²å付ãメッセージ + қолтаңбаÑÑ‹ бар мәлімдеме + ì„œëª…ëœ ë©”ì‹œì§€ + pasiraÅ¡ytas laiÅ¡kas + parakstÄ«ta ziņa + Mesej ditandatangani + signert melding + ondertekend bericht + signert melding + Podpisana wiadomość + mensagem assinada + Mensagem assinada + mesaj semnat + подпиÑанное Ñообщение + Podpísaná správa + podpisano sporoÄilo + Mesazh i firmosur + потпиÑана порука + signerat meddelande + підпиÑане Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ + thông Ä‘iệp đã ký + ç­¾å信件 + ç°½ç½²çš„è¨Šæ¯ + + + stream of data (server push) + دÙÙ‚ بيانات (دÙع خادم) + pÅ‚yÅ„ źviestak (ad servera) + Поток от данни, от Ñтрана на Ñървър + flux de dades (enviat pel servidor) + Proud dat (posílaný serverem) + datastrøm (serverskubbet) + Datenstrom (Server-Push) + χείμαÏÏος δεδομένων (στελλόμενα από τον εξυπηÏετητή) + stream of data (server push) + datumstrio (puÅata per servilo) + flujo de datos (por iniciativa del servidor) + datu-korrontea (zerbitzari igortzailea) + tietovirta (palvelin työntää) + streymur av dáta (ambætara skump) + flux de données (émis par le serveur) + sruth sonraí (brú freastalaí) + fluxo de datos (por iniciativa do servidor) + מידע בזרימה (דחיפה ×¢"×™ השרת) + sugárzott adatfolyam (kiszolgálóról) + arus data (dorongan server) + Flusso di dati (server push) + データストリーム (サーãƒãƒ¼ãƒ—ッシュ型) + мәліметтер ағымы (server push) + ë°ì´í„° 스트림 (서버 푸시) + duomenų srautas (iÅ¡ serverio) + datu straume (servera grÅ«sta) + Aliran dara (paksaan pelayan) + datastrøm (server push) + gegevensstroom (server duwt) + datastraum (dytta av tenaren) + StrumieÅ„ danych (wymuszenie serwera) + fluxo de dados (empurrados pelo servidor) + Fluxo de dados (por iniciativa do servidor) + flux de date (de la server) + поток данных (server push) + Prúd dát (posielaný serverom) + pretok podatkov (strežniÅ¡ki) + Fluks me të dhëna (server push) + проток података (гурање Ñа Ñервера) + dataflöde (serverutsändning) + потік даних (від Ñервера) + luồng dữ liệu (trình phục vụ đẩy) + æ•°æ®æµ(æœåŠ¡å™¨æŽ¨é€) + è³‡æ–™ä¸²æµ (server push) + + + VCS/ICS calendar + سجل VCS/ICS + Kalandar VCS/ICS + Календар — VCS/ICS + calendari VCS/ICS + Kalendář VCS/ICS + VCS/ICS-kalender + VCS/ICS-Kalender + ημεÏολόγιο VCS/ICS + VCS/ICS calendar + VCS/ICS-kalendaro + calendario VCS/ICS + VCS/ICS egutegia + VCS/ICS-kalenteri + VCS/ICS kalendari + calendrier VCS/ICS + féilire VCS/ICS + Calendario VCS/ICS + לוח שנה VCS/ICS + VCS/ICS kalendar + VCS/ICS naptár + Kalender VCS/ICS + Calendario VCS/ICS + VCS/ICS カレンダー + VCS/ICS күнтізбеÑÑ– + VCS/ICS 달력 + VCS/ICS kalendorius + VCS/ICS kalendÄrs + VCS/ICS-kalender + VCS/ICS-kalender + VCS/ICS-kalender + Kalendarz VCS/ICS + Calendário VCS/ICS + Calendar VCS/ICS + календарь VCS/ICS + Kalendár VCS/ICS + Datoteka koledarja VCS/ICS + Kalendar VCS/ICS + VCS/ICS-kalender + VCS/ICS takvimi + календар VCS/ICS + Lịch VCS/ICS + VCS/ICS 日历 + VCS/ICS 行事曆 + VCS/ICS + vCalendar/iCalendar + + + + + + + + + + + + CSS stylesheet + نمط CSS + ArkuÅ¡ stylaÅ­ CSS + Стилове — CSS + llista d'estil CSS + Styl CSS + CSS-stilark + CSS-Stilvorlage + φÏλο στυλ CSS + CSS stylesheet + CSS-stilfolio + hoja de estilo CSS + CSS estilo-orria + CSS-tyylitiedosto + CSS sniðark + feuille de style CSS + stílbhileog CSS + folla de estilos CSS + גליון עיצוב CSS + CSS stilska tablica + CSS stíluslap + Lembar gaya CSS + Foglio di stile CSS + CSS スタイルシート + CSS სტილი + CSS Ñтильдер кеÑтеÑÑ– + CSS 스타ì¼ì‹œíŠ¸ + CSS stiliaus apraÅ¡as + CSS stilu saraksts + CSS-stilark + CSS-stijlblad + CSS-stilark + Arkusz stylów CSS + Folha de estilo CSS + Pagină de stil CSS + таблица Ñтилей CSS + Å týly CSS + Slogovna predloga CSS + Fletë stili CSS + CSS-stilmall + Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Ñтилів CSS + Tá» kiểu dáng CSS + CSS æ ·å¼è¡¨ + CSS 樣å¼è¡¨ + CSS + Cascading Style Sheets + + + + + + electronic business card + بطاقة أعمال إلكترونية + elektronnaja biznes-kartka + Електронна визитна картичка + targeta de visita electrònica + Elektronická navÅ¡tívenka + elektronisk visitkort + Elektronische Visitenkarte + ηλεκτÏονική επαγγελματική κάÏτα + electronic business card + elektronika vizitkarto + tarjeta de visita electrónica + enpresako txartel elektronikoa + sähköinen käyntikortti + elektroniskt handilskort + carte de visite électronique + cárta gnó leictreonach + tarxeta de negocio electrónica + כרטיס ביקור ×לקטרוני + elektroniÄka posjetnica + elektronikus névjegykártya + kartu bisnis elektronik + Biglietto da visita elettronico + é›»å­å刺 + Ñлектронда визит карточкаÑÑ‹ + ì „ìž ëª…í•¨ + elektroninÄ— vizitinÄ— kortelÄ— + elektroniskÄ biznesa kartiņa + elektronisch visitekaartje + elektronisk visittkort + Wizytówka elektroniczna + cartão de visita electrónico + Cartão de visitas eletrônico + carte de vizită electronică + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð²Ð¸Ð·Ð¸Ñ‚Ð½Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¾Ñ‡ÐºÐ° + Elektronická vizitka + elektronska poslovna vizitka + Skedë elektronike biznesi + elektroniskt visitkort + електронна бізнеÑ-картка + danh thiếp Ä‘iện tá»­ + 电å­å•†åŠ¡å¡ + é›»å­å•†å‹™å片 + + + + + + + + + + + + + + txt2tags document + مستند txt2tags + dakument txt2tags + Документ — txt2tags + document txt2tags + Dokument txt2tags + txt2tags-dokument + txt2tags-Dokument + αÏχείο txt2tags + txt2tags document + txt2tags-dokumento + documento txt2tags + txt2tags dokumentua + txt2tags-asiakirja + txt2tags skjal + document txt2tags + cáipéis txt2tags + documento txt2tags + מסמך txt2tags + txt2tags dokument + txt2tags dokumentum + dokumen txt2tags + Documento txt2tags + txt2tags ドキュメント + txt2tags დáƒáƒ™áƒ£áƒ›áƒ”ნტი + txt2tags құжаты + txt2tags 문서 + txt2tags dokumentas + txt2tags dokuments + txt2tags-dokument + txt2tags-document + txt2tags-dokument + Dokument txt2tags + Documento do txt2tags + document txt2tags + документ txt2tags + Dokument txt2tags + Dokument txt2tags + Dokument txt2tags + txt2tags-dokument + документ txt2tags + tài liệu txt2tags + txt2tags 文档 + txt2tags 文件 + + + + + + + + + Verilog source code + Изходен код — Verilog + codi font en Verilog + Zdrojový kód Verilog + Verilog-kildekode + Verilog-Quellcode + πηγαίος κώδικας Verilog + Verilog source code + Verilog-fontkodo + código fuente en Verilog + Verilog-lähdekoodi + code source Verilog + código fonte en Verilog + קוד מקור של + Verilog izvorni kod + Verilog-forráskód + Kode sumber Verilog + Codice sorgente Verilog + Verilog ソースコード + Verilog баÑтапқы коды + Verilog 소스 코드 + Verilog pirmkods + Verilog broncode + Kod źródÅ‚owy Verilog + Código-fonte Verilog + иÑходный код Verilog + Zdrojový kód Verilog + Datoteka izvorne kode Verilog + Verilog-källkod + Verilog kaynak kodu + вихідний код мовою Verilog + Verilog æºä»£ç  + Verilog æºç¢¼ + + + + + SystemVerilog header + Заглавен файл — SystemVerilog + capçalera de SystemVerilog + Záhlaví SystemVerilog + SystemVerilog-teksthoved + SystemVerilog-Header + κεφαλίδα SystemVerilog + SystemVerilog header + cabeceras de SystemVerilog + SystemVerilog-otsake + en-tête + Cabeceiras de SystemVerilog + כותרת SystemVerilog + SystemVerilog zaglavlje + SystemVerilog fejléc + Header SystemVerilog + Header SystemVerilog + SystemVerilog ヘッダー + SystemVerilog тақырыптамаÑÑ‹ + SystemVerilog í—¤ë” + SystemVerilog galvene + SystemVerilog header + Nagłówek SystemVerilog + Cabeçalho de SystemVerilog + заголовочный файл SystemVerilog + HlaviÄky SystemVerilog + Datoteka glave SystemVerilog + SystemVerilog-headerfil + заголовки SystemVerilog + SystemVerilog 头 + SystemVerilog 標頭 + + + + + SystemVerilog source code + Изходен код — SystemVerilog + codi font en SystemVerilog + Zdrojový kód SystemVerilog + SystemVerilog-kildekode + SystemVerilog-Quellcode + πηγαίος κώδικας SystemVerilog + SystemVerilog source code + código fuente en SystemVerilog + SystemVerilog-lähdekoodi + code source + código fonte en SystemVerilog + קוד מקור של SystemVerilog + SystemVerilog izvorni kod + SystemVerilog-forráskód + Kode sumber SystemVerilog + Codice sorgente + SystemVerilog ソースコード + SystemVerilog баÑтапқы коды + SystemVerilog 소스 코드 + SystemVerilog pirmkods + SystemVerilog broncode + Kod źródÅ‚owy SystemVerilog + Código-fonte de SystemVerilog + иÑходный код SystemVerilog + Zdrojový kód SystemVerilog + Datoteka izvorne kode SystemVerilog + SystemVerilog-källkod + вихідний файл мовою SystemVerilog + SystemVerilog æºä»£ç  + SystemVerilog æºç¢¼ + + + + + VHDL source code + Изходен код — VHDL + codi font en VHDL + Zdrojový kód VHDL + VHDL-kildekode + VHDL-Quellcode + πηγαίος κώδικας VHDL + VHDL source code + VHDL-fontkodo + código fuente en VHDL + VHDL-lähdekoodi + code source VHDL + código fonte en VHDL + קוד מקור של VHDL + VHDL izvorni kod + VHDL-forráskód + Kode sumber VHDL + Codice sorgente VHDL + VHDL ソースコード + VHDL баÑтапқы коды + VHDL 소스 코드 + VHDL pirmkods + VHDL broncode + Kod źródÅ‚owy VHDL + Código-fonte VHDL + иÑходный код VHDL + Zdrojový kód VHDL + Datoteka izvorne kode VHDL + VHDL-källkod + VHDL kaynak kodu + вихідний код мовою VHDL + VHDL æºä»£ç  + VHDL æºç¢¼ + VHDL + Very-High-Speed Integrated Circuit Hardware Description Language + + + + + + enriched text document + مستند نصي مغنى + zÉ™ngin mÉ™tn sÉ™nÉ™di + azdobleny tekstavy dakument + Документ Ñ Ð¾Ð±Ð¾Ð³Ð°Ñ‚ÐµÐ½ текÑÑ‚ + document de text enriquit + Rozšířený textový dokument + Dogfen testun wedi ei gyfoethogi + beriget tekstdokument + Angereichertes Textdokument + εγγÏαφο εμπλουτισμένου κειμένου + enriched text document + riĉigita teksta dokumento + documento de texto enriquecido + aberastutako testu dokumentua + rikastettu tekstiasiakirja + ríkað tekstskjal + document texte enrichi + cáipéis téacs saibhrithe + documento de texto enriquecido + מסמך טקסט מועשר + obogaćeni tekstualni dokument + enriched text dokumentum + dokumen teks diperkaya + Documento testo arricchito + リッãƒãƒ†ã‚­ã‚¹ãƒˆãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆ + пішімделген мәтіндік құжаты + í™•ìž¥ëœ í…스트 문서 + praturtinto teksto dokumentas + bagÄtinÄta teksta formÄts + Dokumen teks diperkaya + riktekst-dokument + verrijkt tekstdocument + rik tekst tekstdokument + Wzbogacony dokument tekstowy + documento de texto rico + Documento de texto enriquecido + document text îmbogățit + форматированный текÑтовый документ + Rozšírený textový dokument + dokument z obogatenim besedilom + Dokument teksti i pasuruar + обогаћени текÑтуални документ + berikat textdokument + форматований текÑтовий документ + tài liệu văn bản có kiểu dáng + 富文本文档 + è±å¯ŒåŒ–文字文件 + + + + help page + صÙحة المساعدة + yardım sÉ™hifÉ™si + staronka dapamohi + Страница от помощта + pàgina d'ajuda + Stránka nápovÄ›dy + tudalen gymorth + hjælpeside + Hilfeseite + σελίδα βοήθειας + help page + help-paÄo + página de ayuda + laguntzako orria + ohjesivu + hjálparsíða + page d'aide + leathanach cabhrach + páxina de axuda + דף עזרה + stranica pomoći + súgóoldal + halaman bantuan + Pagina di aiuto + ヘルプページ + анықтама парағы + ë„ì›€ë§ íŽ˜ì´ì§€ + žinyno puslapis + palÄ«dzÄ«bas lapa + Halaman bantuan + hjelpside + hulppagina + hjelpeside + Strona pomocy + página de ajuda + Página de ajuda + pagină de ajutor + Ñтраница Ñправки + Stránka Pomocníka + stran pomoÄi + Faqe ndihme + Ñтрана помоћи + hjälpsida + yardım sayfası + Ñторінка довідки + trang trợ giúp + å¸®åŠ©é¡µé¢ + 幫助é é¢ + + + + plain text document + مستند نصي مجرد + prosty tekstavy dakument + Документ Ñ Ð½ÐµÑ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð°Ð½ текÑÑ‚ + document de text pla + Prostý textový dokument + rent tekstdokument + Einfaches Textdokument + έγγÏαφο Î±Ï€Î»Î¿Ï ÎºÎµÎ¹Î¼Î­Î½Î¿Ï… + plain text document + plata teksta dokumento + documento de texto sencillo + testu soileko dokumentua + perustekstiasiakirja + document texte brut + cáipéis ghnáth-théacs + documento de texto sinxelo + מסמך טקסט פשוט + obiÄan tekstualni dokument + egyszerű szöveg + dokumen teks biasa + Documento in testo semplice + 平文テキストドキュメント + мәтіндік құжаты + ì¼ë°˜ í…스트 문서 + paprastas tekstinis dokumentas + vienkÄrÅ¡s teksta dokuments + Dokumen teks jernih + vanlig tekstdokument + plattetekst-document + vanleg tekstdokument + ZwykÅ‚y dokument tekstowy + documento em texto simples + Documento somente texto + document text simplu + текÑтовый документ + ObyÄajný textový dokument + obiÄajna besedilna datoteka + Dokument në tekst të thjeshtë + обичан текÑтуални документ + vanligt textdokument + звичайний текÑтовий документ + tài liệu nhập thô + 纯文本文档 + 純文字文件 + + + + + + + + + + RDF file + مل٠RDF + FajÅ‚ RDF + Файл — RDF + fitxer RDF + Soubor RDF + RDF-fil + RDF-Datei + αÏχείο RDF + RDF file + RDF-dosiero + archivo RDF + RDF fitxategia + RDF-tiedosto + RDF fíla + fichier RDF + comhad RDF + ficheiro RDF + קובץ RDF + RDF datoteka + RDF fájl + Arsip RDF + File RDF + RDF ファイル + RDF файлы + RDF íŒŒì¼ + RDF failas + RDF datne + RDF-fil + RDF-bestand + RDF-fil + Plik RDF + Arquivo RDF + FiÈ™ier RDF + файл RDF + Súbor RDF + Datoteka RDF + File RDF + RDF-fil + файл RDF + Tập tin RDF + RDF 文件 + RDF 檔 + RDF + Resource Description Framework + + + + + + + + + email headers + ترويسة البريد الإلكتروني + epoçt baÅŸlıqları + paÅ¡tovyja zahaÅ‚oÅ­ki + Заглавни чаÑти на електронни пиÑма + capçaleres de correu electrònic + Záhlaví e-mailu + penawdau e-bost + posthoveder + E-Mail-Kopfzeilen + κεφαλίδες ηλ. μηνυμάτων + email headers + retpoÅtaj ĉapoj + cabeceras de correo electrónico + helbide elektronikoen goiburuak + sähköpostiotsakkeet + t-post tekshøvd + en-têtes de courriel + ceanntásca ríomhphoist + cabeceiras de correo electrónico + כותרת דו×"ל + zaglavlja e-poÅ¡te + levélfejléc + tajuk email + Intestazioni email + メールヘッダー + пошталық тақырыптамалары + ì „ìž ìš°íŽ¸ í—¤ë” + el. laiÅ¡ko antraÅ¡tÄ—s + e-pasta galvene + Pengepala emel + e-posthode + e-mail-kopregels + e-post-hovud + Nagłówki wiadomoÅ›ci e-mail + cabeçalhos de e-mail + Cabeçalhos de e-mail + antete email + почтовые заголовки + HlaviÄky e-mailu + glava elektronske poÅ¡te + Header email + заглавља е-порука + e-posthuvuden + eposta baÅŸlığı + заголовки email + dòng đầu thÆ° Ä‘iện tá»­ + 电å­é‚®ä»¶å¤´ + é›»å­éƒµä»¶æ¨™é ­ + + + + rich text document + مستند نصي غني + zÉ™ngin mÉ™tn sÉ™nÉ™di + azdobleny tekstavy dakument + Документ — rich text + document de text enriquit + Textový dokument RTF + dogfen testun gyfoethog (rtf) + richtekstdokument + RTF-Textdokument + έγγÏαφο εμπλουτισμένου κειμένου (RTF) + rich text document + riĉteksta dokumento + documento de texto enriquecido + aberastutako testu formatua + RTF-asiakirja + document « rich text » + cáipéis mhéith-théacs + documento do texto enriquecido + מסמך טקסט עשיר + obogaćeni tekstualni dokument + rich text-dokumentum + dokumen teks kaya + Documento rich text + リッãƒãƒ†ã‚­ã‚¹ãƒˆãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆ + пішімделген мәтіні бар құжаты + ì„œì‹ìžˆëŠ” í…스트 문서 + praturtinto teksto dokumentas + bagÄtÄ teksta dokuments + Dokumen teks diperkaya + rik tekst-dokument + opgemaakt tekstdocument + rik tekst-dokument + Dokument Rich Text + documento em texto rico + Documento rich text + document text îmbogățit + документ Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ñ‹Ð¼ текÑтом + Textový dokument RTF + dokument z oblikovanim besedilom + Dokument rich text + обогаћени текÑтуални документ + RTF-textdokument + форматований текÑтовий документ + tài liệu văn bản có kiểu dáng (RTF) + RTF 丰富文本文档 + è±å¯Œæ–‡å­—文件 + + + + + RSS summary + ملخص RSS + Karotki ahlad RSS + Обобщение за Ñайтове — RSS + resum RSS + Souhrn RSS + RSS-sammendrag + RSS-Zusammenfassung + σÏνοψη RSS + RSS summary + resumen RSS + RSS laburpena + RSS-tiivistelmä + RSS samandráttur + résumé RSS + achoimre RSS + Resumo RSS + תקציר RSS + RSS sažetak + RSS összefoglaló + Ringkasan RSS + Sommario RSS + RSS サマリ + RSS жинақталғаны + RSS 요약 + RSS santrauka + RSS kopsavilkums + RSS-sammendrag + RSS-samenvatting + RSS-samandrag + Podsumowanie RSS + Resumo RSS + Rezumat RSS + Ñводка RSS + Súhrn RSS + Datoteka povzetek RSS + Përmbledhje RSS + RSS-sammanfattning + Ð·Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ñайту RSS + Bản tóm tắt RSS + RSS æ‘˜è¦ + RSS æ‘˜è¦ + RSS + RDF Site Summary + + + + + + + + + + + Atom syndication feed + مروج تغذية Atom + Syndykacyjny kanaÅ‚ navinaÅ­ Atom + ЕмиÑÐ¸Ñ â€” Atom + canal de sindicació Atom + Kanál Atom + Atom syndication-feed + Atom-Nachrichtenquelle + Atom syndication feed + proveedor de noticias Atom + Atom harpidetze-iturria + Atom-yhdistevirta + fil de syndication Atom + fotha sindeacáitithe Atom + fonte de sindicación Atom + ×”×–× ×” דרך הרשת של Atom + Atom egyesítÅ‘folyam + Umpan sindikasi Atom + Feed di distribuzione Atom + Atom é…信フィード + Atom жаңалықтар таÑпаÑÑ‹ + Atom ë™ê¸°í™” 피드 + Atom sindikacijos kanalas + Atom sindikÄta barotne + Atom syndikeringsstrøm + Atom-syndicatie-feed + Atom-kjelde + KanaÅ‚ Atom + Fonte de notícias Atom + Flux agregare Atom + лента новоÑтей Atom + Kanál Atom + Sindikalni vir Atom + Feed për përhapje Atom + Atom-syndikeringskanal + транÑлÑÑ†Ñ–Ñ Ð¿Ð¾Ð´Ð°Ñ‡ Atom + Nguồn tin tức Atom + Atom æ›´æ–°ç§å­ + Atom è¯åˆä¾›ç¨¿é¥‹æµ + + + + + + + + + + OPML syndication feed + مروج تغذية OPML + Syndykacyjny kanaÅ‚ OPML + ЕмиÑÐ¸Ñ â€” OPML + canal de sindicació OPML + Kanál OPML + OPML-syndikeringsfeed + OPML-Nachrichtenquelle + Ïοή φοÏέα OPML + OPML syndication feed + proveedor de noticias OPML + OPML harpidetze-iturria + OPML-yhdistevirta + fil de syndication OPML + fotha sindeacáitithe OPML + fonte de sindicación OPML + ×”×–× ×” דרך הרשת OPML + OPML egyesítÅ‘folyam + Umpan sindikasi OPML + Feed di distribuzione OPML + OPML é…信フィード + OPML жаңалықтар таÑпаÑÑ‹ + OPML ë¬¶ìŒ feed + OPML sindikacijos kanalas + OPML sindikÄta barotne + OPML syndikeringsstrøm + OPML-syndicatie-feed + OPML-kjelde + KanaÅ‚ OPML + Fonte de notícias OPML + Flux OPML syndication + лента новоÑтей OPML + Kanál OPML + Sindikalni vir OPML + Feed për përhapje OPML + OPML-syndikeringskanal + транÑлÑÑ†Ñ–Ñ Ð¿Ð¾Ð´Ð°Ñ‡ OPML + Nguồn tin tức OPML + OPML èšåˆç§å­ + OPML è¯åˆä¾›ç¨¿é¥‹æµ + + + + + + + + + + SGML document + مستند SGML + Dakument SGML + Документ — SGML + document SGML + Dokument SGML + Dogfen SGML + SGML-dokument + SGML-Dokument + έγγÏαφο SGML + SGML document + SGML-dokumento + documento SGML + SGML dokumentua + SGML-asiakirja + SGML skjal + document SGML + cáipéis SGML + documento SGML + מסמך SGML + SGML dokument + SGML-dokumentum + Dokumen SGML + Documento SGML + SGML ドキュメント + SGML құжаты + SGML 문서 + SGML dokumentas + SGML dokuments + Dokumen SGML + SGML-dokument + SGML-document + SGML-dokument + Dokument SGML + documento SGML + Documento SGML + Document SGML + документ SGML + Dokument SGML + Dokument SGML + Dokument SGML + SGML документ + SGML-dokument + SGML belgesi + документ SGML + Tài liệu SGML + SGML 文档 + SGML 文件 + SGML + Standard Generalized Markup Language + + + + + + spreadsheet interchange document + مستند تبادل الجدول + dakument dla abmienu raźlikovymi arkuÅ¡ami + Документ за обмÑна между програми за електронни таблици + document d'intercanvi de full de càlcul + SeÅ¡itový pÅ™enosový dokument + regnearksudvekslingsdokument + Tabellenkalkulations-Austauschdokument + έγγÏαφο ανταλλαγής Î»Î¿Î³Î¹ÏƒÏ„Î¹ÎºÎ¿Ï Ï†Ïλλου + spreadsheet interchange document + documento de intercambio de hojas de cálculo + kalkulu-orriak trukatzeko dokumentua + taulukkovälitysasiakirja + rokniarks umbýtisskjal + document d'échange de feuilles de calcul + cáipéis idirmhalartaithe scarbhileog + documento de intercambio de follas de cálculo + מסמך גליון × ×ª×•× ×™× ×ž×ª×—×œ×£ + spreadsheet-cserélhetÅ‘dokumentum + dokumen lembar sebar saling tukar + Documento di scambio per foglio di calcolo + スプレッドシート交æ›ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆ + spreadsheet interchange құжаты + 스프레드시트 êµí™˜ 문서 + skaiÄialenÄių apsikeitimo dokumentas + izklÄjlapu apmaiņas dokuments + dokument for regnearkutveksling + rekenblad-uitwisselingsdocument + Utvekslingsdokument for rekneark + Dokument wymiany arkuszy kalkulacyjnych + Documento de intercâmbio de planilhas + document schimb filă de calcul + документ Spreadsheet Interchange + ZoÅ¡itový prenosový dokument + dokument izmenjeve preglednic + Dokument shkëmbimi për fletë llogaritje + spreadsheet interchange-dokument + документ обміну ел. таблицÑми + tài liệu hoán đổi bảng tính + 电å­è¡¨æ ¼äº¤æ¢æ–‡æ¡£ + 試算表交æ›æ–‡ä»¶ + + + + + + + + + TSV document + مستند TSV + Dakument TSV + Документ — TSV + document TSV + Dokument TSV + TSV-dokument + TSV-Dokument + έγγÏαφο TSV + TSV document + documento TSV + TSV dokumentua + TSV-asiakirja + TSV skjal + document TSV + cáipéis TSV + documento TSV + מסמך TSV + TSV dokument + TSV dokumentum + Dokumen TSV + Documento TSV + TSV ドキュメント + TSV құжаты + TSV 문서 + TSV dokumentas + TSV dokuments + TSV-dokument + TSV-document + TSV-dokument + Dokument TSV + Documento TSV + Document TSV + документ TSV + Dokument TSV + Dokument TSV + Dokument TSV + TSV-dokument + документ TSV + Tài liệu TSV + TSV 文档 + TSV 文件 + TSV + Tab Separated Values + + + + + Graphviz DOT graph + مبيان Graphviz DOT + Граф — Graphviz DOT + gràfic Graphviz DOT + Graf Graphviz DOT + Graphviz DOT-graf + Graphviz-DOT-Graph + ΓÏάφημα Graphviz DOT + Graphviz DOT graph + gráfico Graphviz DOT + Graphviz DOT grafikoa + Graphviz DOT -graafi + Graphviz DOT ritmynd + graphe Graphviz DOT + graf DOT Graphviz + gráfica DOT de Graphviz + גרף של Graphviz DOT + Graphviz DOT grafikon + Graphviz DOT-grafikon + Grafik Graphviz DOT + Grafico Graphviz DOT + Graphviz DOT グラフ + Graphviz DOT ÑызбаÑÑ‹ + Graphviz DOT 그래프 + Graphviz DOT diagrama + Graphviz DOT grafiks + Graphviz wetenschappelijke grafiek + Wykres DOT Graphviz + Gráfico do Graphviz DOT + Grafic Graphviz DOT + Диаграмма Graphviz DOT + Graf Graphviz DOT + Datoteka grafikona Graphviz DOT + Graphviz DOT-graf + граф DOT Graphviz + Biểu đồ DOT Graphviz + Graphviz DOT 科学图形 + Graphviz DOT 圖 + + + + + + + + + + + + JAD document + مستند JAD + Dakument JAD + Документ — JAD + document JAD + Dokument JAD + JAD-dokument + JAD-Dokument + έγγÏαφο JAD + JAD document + JAD-dokumento + documento JAD + JAD dokumentua + JAD-asiakirja + JAD skjal + document JAD + cáipéis JAD + documento JAD + מסמך JAD + JAD dokument + JAD dokumentum + Dokumen JAD + Documento JAD + JAD ドキュメント + JAD құжаты + JAD 문서 + JAD dokumentas + JAD dokuments + JAD-dokument + JAD-document + JAD-dokument + Dokument JAD + Documento JAD + Document JAD + документ JAD + Dokument JAD + Dokument JAD + Dokument JAD + JAD-dokument + JAD belgesi + документ JAD + Tài liệu JAD + JAD 文档 + JAD 文件 + JAD + Java Application Descriptor + + + + + + + WML document + مستند WML + WML sÉ™nÉ™di + Dakument WML + Документ — WML + document WML + Dokument WML + Dogfen WML + WML-dokument + WML-Dokument + έγγÏαφο WML + WML document + WML-dokumento + documento WML + WML dokumentua + WML-asiakirja + WML skjal + document WML + cáipéis WML + documento WML + מסמך WML + WML dokument + WML-dokumentum + Dokumen WML + Documento WML + WML ドキュメント + WML құжаты + WML 문서 + WML dokumentas + WML dokuments + Dokumen XML + WML-dokument + WML-document + WML-dokument + Dokument WML + documento WML + Documento WML + Document WML + документ WML + Dokument WML + Dokument WML + Dokument WML + WML документ + WML-dokument + WML belgesi + документ WML + Tài liệu WML + WML 文档 + WML 文件 + WML + Wireless Markup Language + + + + + WMLScript program + برنامج WMLScript + Prahrama WMLScript + Програма — WMLScript + programa WMLScript + Program WMLScript + WMLScript-program + WMLScript-Programm + Ï€ÏόγÏαμμα WMLScript + WMLScript program + programa en WMLScript + WMLScript programa + WMLScript-ohjelma + WMLScript forrit + programme WMLScript + ríomhchlár WMLScript + programa en WMLScript + תוכנית של WMLScript + WMLScript program + WMLScript program + Program WMLScript + Programma WMLScript + WMLScript プログラム + WMLScript бағдарламаÑÑ‹ + WMLScript 프로그램 + WMLScript programa + WMLScript programma + WMLScript-program + WMLScript-programma + WMLScript-program + Pogram WMLScript + Programa WMLScript + Program WMLScript + Ñценарий WMLScript + Program WMLScript + Programska datoteka WMLScript + Program WMLScript + WMLScript-program + WMLScript programı + програма мовою WMLScript + ChÆ°Æ¡ng trình WMLScript + WMLScript ç¨‹åº + WMLScript ç¨‹å¼ + + + + ACE archive + أرشي٠ACE + ArchiÅ­ ACE + Ðрхив — ACE + arxiu ACE + Archiv ACE + ACE-arkiv + ACE-Archiv + αÏχείο ACE + ACE archive + ACE-arkivo + archivador ACE + ACE artxiboa + ACE-arkisto + ACE skjalasavn + archive ACE + cartlann ACE + arquivo ACE + ×רכיון ACE + ACE arhiva + ACE archívum + Arsip ACE + Archivio ACE + ACE アーカイブ + ACE áƒáƒ áƒ¥áƒ˜áƒ•áƒ˜ + ACE архиві + ACE 압축 íŒŒì¼ + ACE archyvas + ACE arhÄ«vs + ACE-arkiv + ACE-archief + ACE-arkiv + Archiwum ACE + Pacote ACE + Arhivă ACE + архив ACE + Archív ACE + Datoteka arhiva ACE + Arkiv ACE + ACE-arkiv + ACE arÅŸivi + архів ACE + Kho nén ACE + ACE 归档文件 + ACE å°å­˜æª” + + + + + + + + Ada source code + Ø´Ùرة مصدر Ada + KryniÄny kod Ada + Изходен код — Ada + codi font en Ada + Zdrojový kód v AdÄ› + Ada-kildekode + Ada-Quelltext + πηγαίος κώδικας Ada + Ada source code + Ada-fontkodo + código fuente en Ada + Ada iturburu-kodea + Ada-lähdekoodi + Ada keldukota + code source Ada + cód foinseach Ada + código fonte en Ada + קוד מקור Ada + Ada izvorni kod + Ada-forráskód + Kode program Ada + Codice sorgente Ada + Ada ソースコード + Ada-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + Ada баÑтапқы коды + Ada 소스 코드 + Ada pradinis kodas + Ada pirmkods + Kod sumber Ada + Ada-kildekode + Ada-broncode + Ada-kjeldekode + Kod źródÅ‚owy Ada + código fonte Ada + Código-fonte Ada + Cod sursă Ada + иÑходный код Ada + Zdrojový kód jazyka Ada + Datoteka izvorne kode Ada + Kod burues Ada + Ðда изворни ко̂д + Ada-källkod + Ada kaynak kodu + вихідний код мовою Ada + Mã nguồn Ada + Ada æºä»£ç  + Ada æºç¢¼ + + + + + + author list + لائحة المؤل٠+ Å›pis aÅ­taraÅ­ + СпиÑък на авторите + llista d'autors + Seznam autorů + forfatterliste + Autorenliste + κατάλογος συγγÏαφέων + author list + listo de aÅ­toroj + lista de autores + egile-zerrenda + tekijäluettelo + høvundalisti + liste d'auteurs + liosta údar + lista de autores + רשימת ×™×•×¦×¨×™× + szerzÅ‘lista + senarai penulis + Elenco autori + 著者リスト + авторлар тізімі + ì €ìž ëª©ë¡ + autorių sÄ…raÅ¡as + autoru saraksts + Senarai penulis + forfatterliste + auteurslijst + forfattarliste + Lista autorów + lista de autores + Lista de autores + listă autori + ÑпиÑок авторов + Zoznam autorov + seznam avtorjev + Lista e autorëve + ÑпиÑак аутора + författarlista + yazar listesi + перелік авторів + danh sách tác giả + 作者列表 + 作者清單 + + + + + BibTeX document + مستند BibTeX + Dakument BibTeX + Документ — BibTeX + document BibTeX + Dokument BibTeX + BibTeX-dokument + BibTeX-Dokument + έγγÏαφο BibTeX + BibTeX document + BibTeX-dokumento + documento BibTeX + BibTeX dokumentua + BibTeX-asiakirja + BibTeX skjal + document BibTeX + cáipéis BibTeX + documento BibTex + מסמך BibTeX + BibTeX dokument + BibTeX dokumentum + Dokumen BibTeX + Documento BibTeX + BibTeX ドキュメント + BibTeX-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტი + BibTeX құжаты + BibTeX 문서 + BibTeX dokumentas + BibTeX dokuments + BibTeX-dokument + BibTeX-document + BibTeX-dokument + Dokument BibTeX + Documento BibTeX + Document BibTeX + документ BibTeX + Dokument BibTeX + Dokument BibTeX + Dokument BibTeX + BibTeX-dokument + BibTeX belgesi + документ BibTeX + Tài liệu BibTeX + BibTeX 文档 + BibTeX 文件 + + + + + + + + C++ header + ترويسة سي++ + ZahaÅ‚oÅ­ny fajÅ‚ C++ + Заглавен файл — C++ + capçalera en C++ + Záhlaví v C++ + C++-posthoved + C++-Header + κεφαλίδα C++ + C++ header + cabecera de código fuente en C++ + C++ goiburua + C++-otsake + C++ tekshøvd + en-tête C++ + ceanntásc C++ + cabeceira de código fonte en C++ + כותר ++C + C++ zaglavlje + C++ fejléc + Tajuk C++ + Header C++ + C++ ヘッダー + C++-ის თáƒáƒ•áƒ¡áƒáƒ áƒ—ი + C++ тақырыптама файлы + C++ í—¤ë” + C++ antraÅ¡tÄ— + C++ galvene + C++-kildekodeheader + C++-header + C++-kjeldekode-hovud + Plik nagłówkowy C++ + Cabeçalho C++ + Antet C++ + заголовочный файл C++ + HlaviÄky jazyka C++ + Datoteka glave C++ + Header C++ + C++-huvud + файл заголовків мовою C++ + Phần đầu mã nguồn C++ + C++ æºä»£ç å¤´æ–‡ä»¶ + C++ 標頭檔 + + + + + + + + + C++ source code + Ø´Ùرة مصدر سي++ + KryniÄny kod C++ + Изходен код — C++ + codi font en C++ + Zdrojový kód v C++ + C++-kildekode + C++-Quelltext + πηγαίος κώδικας C++ + C++ source code + C++-fontkodo + código fuente en C++ + C++ iturburu-kodea + C++-lähdekoodi + C++ keldukota + code source C++ + cód foinseach C++ + código fonte de C++ + קוד מקור של C++ + C++ izvorni kod + C++-forráskód + Kode program C++ + Codice sorgente C++ + C++ ソースコード + C++-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + C++ баÑтапқы коды + C++ 소스 코드 + C++ pradinis kodas + C++ pirmkods + Kod sumber C++ + C++-kildekode + C++-broncode + C++-kjeldekode + Kod źródÅ‚owy C++ + código fonte C++ + Código-fonte C++ + Cod sursă C++ + иÑходный код C++ + Zdrojový kód jazyka C++ + Datoteka izvorne kode C++ + Kod burues C++ + C++ изворни ко̂д + C++-källkod + вихідний код мовою C++ + Mã nguồn C++ + C++ æºä»£ç  + C++ æºç¢¼ + + + + + + + + + ChangeLog document + مستند ChangeLog + Dakument zafiksavanych źmienaÅ­ ChangeLog + Дневник за промени — ChangeLog + document de registre de canvis + Dokument ChangeLog + ChangeLot-dokument + Änderungsprotokoll + έγγÏαφο ChangeLog + ChangeLog document + documento de cambios + ChangeLog dokumentua + Muutoslokiasiakirja + ChangeLog skjal + document ChangeLog + cáipéis ChangeLog + documento Changelog + מסמך של ChangeLog + ChangeLog dokumentum + Dokumen ChangeLog + Documento ChangeLog + ChangeLog ドキュメント + ChangeLog დáƒáƒ™áƒ£áƒ›áƒ”ნტი + ChangeLog құжаты + ChangeLog 문서 + ChangeLog dokumentas + ChangeLog dokuments + ChangeLog-dokument + ChangeLog-document + ChangeLog-dokument + Dokument zmian (ChangeLog) + Documento ChangeLog + Document ChangeLog + протокол изменений + Dokument ChangeLog + Dokument ChangeLog + Dokument ChangeLog + Ändringsloggsdokument + документ ChangeLog + Tài liệu ChangeLog (ghi lÆ°u thay đổi) + å˜æ›´æ—¥å¿—文档 + ChangeLog 文件 + + + + + C header + ترويسة C + ZahaÅ‚oÅ­ny fajÅ‚ C + Заглавен файл — C + capçalera en C + Záhlaví v C + C-posthoved + C-Header + κεφαλίδα C + C header + cabecera de código fuente en C + C goiburua + C-otsake + C tekshøvd + en-tête C + ceanntásc C + cabeceira de códifo fonte de C + כותר C + C zaglavlje + C fejléc + Tajuk C + Header C + C ヘッダー + C-ის თáƒáƒ•áƒ¡áƒáƒ áƒ—ი + C тақырыптама файлы + C í—¤ë” + C antraÅ¡tÄ— + C galvene + C-kildekodeheader + C-header + C-kjeldekode-hovud + Plik nagłówkowy C + Cabeçalho C + Antet C + заголовочный файл C + HlaviÄky jazyka C + Datoteka glave C + Header C + C-huvud + C baÅŸlığı + файл заголовків мовою C + Phần đầu mã nguồn C + C 程åºå¤´æ–‡ä»¶ + C 標頭檔 + + + + + CMake source code + Ø´Ùرة مصدر CMake + KryniÄny kod CMake + Изходен код — CMake + codi font en CMake + Zdrojový kód CMake + CMake-kildekode + CMake-Quelltext + πηγαίος κώδικας CMake + CMake source code + CMake-fontkodo + código fuente en CMake + CMake iturburu-kodea + CMake-lähdekoodi + CMake keldukota + code source CMake + cód foinseach CMake + código fonte de CMake + קוד מקור של CMake + CMake izvorni kod + CMake-forráskód + Kode program CMake + Codice sorgente CMake + CMake ソースコード + CMake-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + CMake баÑтапқы коды + CMake 소스 코드 + CMake pirminis tekstas + CMake pirmkods + CMake-kildekode + CMake-broncode + CMake-kjeldekode + Kod źródÅ‚owy CMake + Código-fonte CMake + Cod sursă CMake + иÑходный код CMake + Zdrojový kód CMake + Datoteka izvorne kode CMake + Kod burues CMake + CMake-källkod + вихідний код CMake + Mã nguồn CMake + CMake æºä»£ç  + CMake æºç¢¼ + + + + + + CSV document + مستند CSV + Dakument CSV + Документ — CSV + document CSV + Dokument CSV + CSV-dokument + CSV-Dokument + αÏχείο CSV + CSV document + CSV-dokumento + documento CSV + CSV dokumentua + CSV-asiakirja + CSV skjal + document CSV + cáipéis CSV + documento CSV + מסמך CSV + CSV dokument + CSV dokumentum + Dokumen CSV + Documento CSV + CSV ドキュメント + CSV დáƒáƒ™áƒ£áƒ›áƒ”ნტი + CSV құжаты + CSV 문서 + CSV dokumentas + CSV dokuments + CSV-dokument + CSV-document + CSV-dokument + Dokument CSV + Documento CSV + Document CSV + документ CSV + Dokument CSV + Dokument CSV + Dokument CSV + CSV-dokument + документ CSV + Tài liệu CSV + CSV 文档 + CSV 文件 + CSV + Comma Separated Values + + + + + + + license terms + شروط الترخيص + licenzijnyja Å­movy + Лицензни уÑÐ»Ð¾Ð²Ð¸Ñ + condicions de llicència + LicenÄní podmínky + licensbetingelser + Lizenzbedingungen + ÏŒÏοι άδειας + licence terms + términos de licencia + lizentzia baldintzak + lisenssiehdot + loyvistreytir + termes de licence + téarmaí ceadúnais + termos de licenza + תנ××™ רישיון + uvjeti licence + licencfeltételek + persyaratan lisensi + Termini di licenza + ソフトウェアライセンスæ¡é … + лицензиÑлық келіÑімі + ë¼ì´ì„ ìŠ¤ ì¡°í•­ + licencijos sÄ…lygos + licences nosacÄ«jumi + lisensbestemmelser + licentievoorwaarden + lisensvilkÃ¥r + Warunki licencji + Termos de licença + termeni de licență + лицензионное Ñоглашение + LicenÄné podmienky + pogoji in dovoljenja uporabe + Kushte liçence + licensvillkor + ліцензійні умови + Ä‘iá»u kiện giấy phép + 软件许å¯æ¡æ¬¾ + 授權æ¢æ¬¾ + + + + + author credits + شكر وتقدير المؤل٠+ zasÅ‚uhi aÅ­tara + БлагодарноÑти към авторите + atribucions d'autor + Autorské zásluhy + bidragydere + Autorendanksagung + author credits + reconocimiento de autoría + tekijöiden kiitokset + høvundaheiður + remerciements + admhálacha údar + créditos de autor + ×§×¨×“×™×˜×™× ×©×œ היוצר + szerzÅ‘k listája + kredit penulis + Riconoscimenti autori + ソフトウェア作者クレジット + бағдарлама авторлары + ì €ìž‘ìž í¬ë ˆë”§ + padÄ—kos autoriams + veidotÄji + liste med bidragsytere + auteursinformatie + forfattarliste + PodziÄ™kowania autorów programu + Créditos do autor + mulÈ›umiri autori + авторы программы + Autorské zásluhy + avtorske zasluge + Kreditë e autorëve + författarlista + подÑки авторам програми + công trạng tác giả + 软件作者致谢 + 作者致è¬åå–® + + + + + C source code + Ø´Ùرة مصدر سي + KryniÄny kod C + Изходен код — C + codi font en C + Zdrojový kód v C + C-kildekode + C-Quelltext + πηγαίος κώδικας C + C source code + C-fontkodo + código fuente en C + C iturburu-kodea + C-lähdekoodi + C keldukota + code source C + cód foinseach C + código fonte en C + קוד מקור של C + C izvorni kod + C-forráskód + Kode program C + Codice sorgente C + C ソースコード + C-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + C баÑтапқы коды + C 소스 코드 + C pradinis kodas + C pirmkods + Kod sumber C + C-kildekode + C-broncode + C-kjeldekode + Kod źródÅ‚owy C + código fonte C + Código-fonte C + Cod sursă C + иÑходный код C + Zdrojový kód jazyka C + Datoteka izvorne kode C + Kod burues C + C изворни ко̂д + C-källkod + C kaynak kodu + вихідний код мовою C + Mã nguồn C + C æºä»£ç  + C æºç¢¼ + + + + + + + + + + + C# source code + Ø´Ùرة مصدر سي# + KryniÄny kod C# + Изходен код — C# + codi font en C# + Zdrojový kód v C# + C#-kildekode + C#-Quelltext + πηγαίος κώδικας C# + C# source code + C#-fontkodo + código fuente en C# + C# iturburu-kodea + C#-lähdekoodi + C# keldukota + code source C# + cód foinseach C# + código fonte en C# + קוד מקור של C# + C# izvorni kod + C#-forráskód + Kode program C# + Codice sorgente C# + C# ソースコード + C#-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + C# баÑтапқы коды + C# 소스 코드 + C# pradinis kodas + C# pirmkods + Kod sumber C# + C#-kildekode + C#-broncode + C#-kjeldekode + Kod źródÅ‚owy C# + código fonte C# + Código-fonte C# + Cod sursă C# + иÑходный код C# + Zdrojový kód jazyka C# + Datoteka izvorne kode C# + Kod burues C# + C# изворни ко̂д + C#-källkod + C# kaynak kodu + вихідний код мовою C# + Mã nguồn C# + C# æºä»£ç  + C# æºç¢¼ + + + + + Vala source code + Ø´Ùرة مصدر Vala + KryniÄny kod Vala + Изходен код — Vala + codi font en Vala + Zdrojový kód Vala + Valakildekode + Vala-Quelltext + πηγαίος κώδικας Vala + Vala source code + Vala-fontkodo + código fuente en Vala + Vala iturburu-kodea + Vala-lähdekoodi + Vala keldukota + code source Vala + cód foinseach Vala + código fonte en Vala + קוד מקור של Vala + Vala izvorni kod + Vala forráskód + Kode program Vala + Codice sorgente Vala + Vala ソースコード + Vala баÑтапқы коды + Vala 소스 코드 + Vala pradinis kodas + Vala pirmkods + Vala-kildekode + Vala-broncode + Vala-kjeldekode + Kod źródÅ‚owy Vala + Código-fonte Vala + Cod sursă Vala + иÑходный код Vala + Zdrojový kód Vala + Datoteka izvorne kode Vala + Kod burues Vala + Vala-källkod + Vala kaynak kodu + вихідний код мовою Vala + Mã nguồn Vala + Vala æºä»£ç  + Vala æºç¢¼ + + + + + + OOC source code + Изходен код — OOC + codi font en OOC + Zdrojový kód OOC + OOC-kildekode + OOC-Quellcode + πηγαιÌος κωÌδικας OOC + OOC source code + OOC-fontkodo + Código fuente en OOC + OOC-lähdekoodi + source code OOC + código fonte de OOC + קוד מקור של OOC + OOC izvorni kod + OOC forráskód + Kode sumber OOC + Codice sorgente OOC + OOC ソースコード + OOC-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + OOC баÑтапқы коды + OOC 소스 코드 + OOC pirmkods + OOC broncode + Kod źródÅ‚owy OOC + Código-fonte OOC + иÑходный код OOC + Izvorna koda OOC + OOC-källkod + вихідний код мовою OOC + OOC + OOC æºç¢¼ + OOC + Out Of Class + + + + + DCL script + سكربت DCL + DCL skripti + Skrypt DCL + Скрипт — DCL + script DCL + Skript DCL + Sgript DCL + DCL-program + DCL-Skript + Ï€ÏόγÏαμμα εντολών DCL + DCL script + DCL-skripto + script en DCL + DCL script-a + DCL-komentotiedosto + DCL boðrøð + script DCL + script DCL + script de DCL + תסריט DCL + DCL skripta + DCL-parancsfájl + Skrip DCL + Script DCL + DCL スクリプト + DCL სცენáƒáƒ áƒ˜ + DCL Ñценарийі + DCL 스í¬ë¦½íŠ¸ + DCL scenarijus + DCL skripts + Skrip DCL + DCL-skript + DCL-script + DCL-skript + Skrypt DCL + 'script' DCL + Script DCL + Script DCL + Ñценарий DCL + Skript DCL + Skriptna datoteka DCL + Script DCL + DCL Ñкрипта + DCL-skript + DCL betiÄŸi + Ñкрипт DCL + Văn lệnh DCL + DCL 脚本 + DCL 指令稿 + DCL + Data Conversion Laboratory + + + + + DSSSL document + مستند DSSSL + DSSSL sÉ™nÉ™di + Dakument DSSSL + Документ — DSSSL + document DSSSL + Dokument DSSSL + Dogfen DSSSL + DSSSL-dokument + DSSSL-Dokument + έγγÏαφο DSSSL + DSSSL document + DSSSL-dokumento + documento DSSSL + DSSSL dokumentua + DSSSL-asiakirja + DSSSL skjal + document DSSSL + cáipéis DSSSL + documento DSSSL + מסמך DSSSL + DSSSL dokument + DSSSL-dokumentum + Dokumen DSSSL + Documento DSSSL + DSSSL ドキュメント + DSSSL დáƒáƒ™áƒ£áƒ›áƒ”ნტი + DSSSL құжаты + DSSSL 문서 + DSSSL dokumentas + DSSSL dokuments + Dokumen DSSSL + DSSSL-dokument + DSSSL-document + DSSSL-dokument + Dokument DSSSL + documento DSSSL + Documento DSSSL + Document DSSSL + документ DSSSL + Dokument DSSSL + Dokument DSSSL + Dokument DSSSL + DSSSL документ + DSSSL-dokument + DSSSL belgesi + документ DSSSL + Tài liệu DSSSL + DSSSL 文档 + DSSSL 文件 + DSSSL + Document Style Semantics and Specification Language + + + + + D source code + Ø´Ùرة مصدر D + KryniÄny kod D + Изходен код — D + codi font en D + Zdrojový kód v D + D-kildekode + D-Quelltext + πηγαίος κώδικας D + D source code + D-fontkodo + código fuente en D + D iturburu-kodea + D-lähdekoodi + D keldukota + code source D + cód foinseach D + código fonte de D + קוד מקור לשפת D + D izvorni kod + D-forráskód + Kode program D + Codice sorgente D + D ソースコード + D-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + D баÑтапқы коды + D 소스 코드 + D pradinis kodas + D pirmkods + D-kildekode + D-broncode + D-kjeldekode + Kod źródÅ‚owy D + Código-fonte D + Cod sursă D + иÑходный код D + Zdrojový kód jazyka D + Datoteka izvorne kode D + Kod burues D + D изворни ко̂д + D-källkod + вихідний код мовою D + Mã nguồn D + D æºä»£ç  + D æºç¢¼ + + + + + + DTD file + مل٠DTD + FajÅ‚ DTD + Документ — DTD + fitxer DTD + Soubor DTD + DTD-fil + DTD-Datei + αÏχείο DTD + DTD file + DTD-dosiero + archivo DTD + DTD fitxategia + DTD-tiedosto + DTD fíla + fichier DTD + comhad DTD + ficheiro DTD + מסמך DTD + DTD datoteka + DTD fájl + Berkas DTD + File DTD + DTD ファイル + DTD ფáƒáƒ˜áƒšáƒ˜ + DTD файлы + DTD íŒŒì¼ + DTD failas + DTD datne + DTD-fil + DTD-bestand + DTD-fil + Plik DTD + Arquivo DTD + FiÈ™ier DTD + файл DTD + Súbor DTD + Datoteka DTD + File DTD + DTD-fil + DTD dosyası + файл DTD + Tập tin DTD + DTD 文件 + DTD 檔 + DTD + Document Type Definition + + + + + + + Eiffel source code + Ø´Ùرة مصدر Eiffel + KryniÄny kod Eiffel + Изходен код — Eiffel + codi font en Eiffel + Zdrojový kód Eiffel + Eiffelkildekode + Eiffel-Quelltext + πηγαιÌος κωÌδικας Eiffel + Eiffel source code + Eiffel-fontkodo + código fuente en Eiffel + Eiffel iturburu-kodea + Eiffel-lähdekoodi + Eiffel keldukota + code source Eiffel + cód foinseach Eiffel + código fone de Eiffel + קוד מקור של Eiffel + Eiffel izvorni kod + Eiffel forráskód + Kode program Eiffel + Codice sorgente Eiffel + Eiffel ソースコード + Eiffel-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + Eiffel баÑтапқы коды + Eiffel 소스 코드 + Eiffel pirminis programos tekstas + Eiffel pirmkods + Eiffel-kildekode + Eiffel-broncode + Eiffel-kjeldekode + Kod źródÅ‚owy Eiffel + Código-fonte Eiffel + Cod sursă Eiffel + иÑходный код Eiffel + Zdrojový kód Eiffel + Datoteka izvorne kode Eiffel + Kod burues Eiffel + Eiffel-källkod + Eiffel kaynak kodu + вихідний код мовою Eiffel + Mã nguồn Eiffel + Eiffel æºä»£ç  + Eiffel æºç¢¼ + + + + + + Emacs Lisp source code + Ø´Ùرة مصدر Emacs Lisp + Emacs Lisp mÉ™nbÉ™ kodu + KryniÄny kod Emacs Lisp + Изходен код — Emacs Lisp + codi font en Emacs Lisp + Zdrojový kód Emacs Lisp + Ffynhonnell rhaglen EMACS LISP + Emacs Lisp-kildekode + Emacs-Lisp-Quelltext + πηγαίος κώδικας Emacs Lisp + Emacs Lisp source code + fontkodo en Emacs Lisp + código fuente en Lisp de Emacs + Emacs Lisp iturburu-kodea + Emacs Lisp -lähdekoodi + Emacs Lisp keldukota + code source Emacs Lisp + cód foinseach Emacs Lisp + código fonte de Emacs Lisp + קוד מקור של Emcas Lisp + Emacs Lisp izvorni kod + Emacs Lisp-forráskód + Kode sumber Emacs Lisp + Codice sorgente Emacs Lisp + Emacs Lisp ソースコード + Emacs-ის Lisp სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + Emacs Lisp баÑтапқы коды + Emacs Lisp 소스 코드 + Emacs Lisp pradinis kodas + Emacs Lisp pirmkods + Kod sumber Emacs Lisp + Emacs Lisp-kildekode + Emacs Lisp-broncode + Emacs Lisp kjeldekode + Plik źródÅ‚owy Emacs Lisp + código fonte Emacs Lisp + Código-fonte Lisp do Emacs + Cod sursă Emacs Lisp + иÑходный код Emacs Lisp + Zdrojový kód Emacs Lisp + Datoteka izvorne kode Emacs Lisp + Kod burues Emacs Lisp + Ð•Ð¼Ð°ÐºÑ Ð›Ð¸Ñп изворни ко̂д + Emacs Lisp-källkod + Emacs Lisp kaynak kodu + вихідний код мовою Emacs Lisp + Mã nguồn Lisp Emacs + Emacs Lisp æºä»£ç  + Emacs Lisp æºç¢¼ + + + + + + + + + Erlang source code + Ø´Ùرة مصدر Erlang + KryniÄny kod Erlang + Изходен код — Erlang + codi font en Erlang + Zdrojový kód Erlang + Erlangkildekode + Erlang-Quelltext + πηγαιÌος κωÌδικας Erlang + Erlang source code + Erlang-fontkodo + código fuente en Erlang + Erlang iturburu-kodea + Erlang-lähdekoodi + Erlang keldukota + code source Erlang + cód foinseach Erlang + código fonte de Erlang + קוד מקור של Erlang + Erlang izvorni kod + Erlang forráskód + Kode program Erlang + Codice sorgente Erlang + Erlang ソースコード + Erlang-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + Erlang баÑтапқы коды + Erlang 소스 코드 + Erlang pradinis kodas + Erlang pirmkods + Erlang-kildekode + Erlang-broncode + Erlang-kjeldekode + Kod źródÅ‚owy Erlang + Código-fonte Erlang + Cod sursă Erlang + иÑходный код Erlang + Zdrojový kód Erlang + Datoteka izvorne kode Erlang + Kod burues Erlang + Erlang-källkod + Erlang kaynak kodu + вихідний код мовою Erlang + Mã nguồn Erlang + Erlang æºä»£ç  + Erlang æºç¢¼ + + + + + Fortran source code + Ø´Ùرة مصدر Fortran + Fortran mÉ™nbÉ™ kodu + KryniÄny kod Fortran + Изходен код — Fortran + codi font en Fortran + Zdrojový kód Fortran + Ffynhonnell rhaglen FORTRAN + Fortrankildekode + Fortran-Quelltext + πηγαίος κώδικας Fortran + Fortran source code + Fotran-fontkodo + código fuente en Fortran + Fortran-en iturburu-kodea + Fortran-lähdekoodi + Fortran keldukota + code source Fortran + cód foinseach Fortran + código fonte de Fortran + קוד מקור של Fortran + Fortran izvorni kod + Fortran-forráskód + Kode program Fortran + Codice sorgente Fortran + Fortran ソースコード + Fortran-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + Fortran баÑтапқы коды + í¬íŠ¸ëž€ 소스 코드 + Fortran pradinis kodas + Fortran pirmkods + kod sumber Fortran + Fortran-kildekode + Fortran-broncode + Fortran-kjeldekode + Kod źródÅ‚owy Fortran + código fonte Fortran + Código-fonte Fortran + Cod sursă Fortran + иÑходный код Fortran + Zdrojový kód Fortran + Datoteka izvorne kode Fortran + Kod burues Fortran + Фортран изворни ко̂д + Fortran-källkod + Fortran kaynak kodu + вихідний код мовою Fortran + Mã nguồn Fortran + Fortran æºä»£ç  + Fortran æºç¢¼ + + + + + + + + translation file + مل٠الترجمة + fajÅ‚ pierakÅ‚adu + Превод + fitxer traducció + Soubor pÅ™ekladu + oversættelsesfil + Ãœbersetzungsdatei + αÏχείο μετάφÏασης + translation file + tradukad-dosiero + archivo de traducción + itzulpen-fitxategia + käännöstiedosto + týðingarfíla + fichier de traduction + comhad aistrithe + ficheiro de tradución + קובץ ×ª×¨×’×•× + datoteka prijevoda + fordítási fájl + berkas terjemahan + File traduzione + 翻訳ファイル + თáƒáƒ áƒ’მნის ფáƒáƒ˜áƒšáƒ˜ + аудармалар файлы + 번역 íŒŒì¼ + vertimo failas + tulkoÅ¡anas datne + oversettelsesfil + vertalingsbestand + omsetjingsfil + Plik tÅ‚umaczenia + Arquivo de tradução + fiÈ™ier traducere + файл переводов + Súbor prekladu + datoteka prevoda programa + File përkthimesh + översättningsfil + файл перекладу + tập tin dịch + 消æ¯ç¿»è¯‘文件 + 翻譯檔 + + + + + + + translation template + قالب الترجمة + Å¡ablon dla pierakÅ‚adu + Шаблон за преводи + plantilla de traducció + Å ablona pÅ™ekladu + oversættelsesskabelon + Ãœbersetzungsvorlage + Ï€Ïότυπο μετάφÏασης + translation template + tradukad-Åablono + plantilla de traducción + itzulpenen txantiloia + käännösmalli + týðingarformur + modèle de traduction + teimpléad aistrithe + plantilla de tradución + תבנית ×ª×¨×’×•× + predložak prijevoda + fordítási sablon + templat terjemahan + Modello di traduzione + 翻訳テンプレート + თáƒáƒ áƒ’მნის შáƒáƒ‘ლáƒáƒœáƒ˜ + аудармалар үлгіÑÑ– + 메시지 번역 ì„œì‹ + vertimo Å¡ablonas + tulkoÅ¡anas veidne + mal for oversetting + vertalingssjabloon + omsetjingsmal + Szablon tÅ‚umaczenia + Modelo de tradução + È™ablon de traducere + шаблон переводов + Å ablóna prekladu + predloga datoteke prevoda programa + Model përkthimesh + översättningsmall + шаблон перекладу + mẫu dịch + 消æ¯ç¿»è¯‘æ¨¡æ¿ + 翻譯模版 + + + + + + + + + HTML document + مستند HTML + Dakument HTML + Документ — HTML + document HTML + Dokument HTML + HTML-dokument + HTML-Dokument + έγγÏαφο HTML + HTML document + HTML-dokumento + documento HTML + HTML dokumentua + HTML-asiakirja + HTML skjal + document HTML + cáipéis HTML + documento HTML + מסמך HTML + HTML dokument + HTML dokumentum + Dokumen HTML + Documento HTML + HTML ドキュメント + HTML құжаты + HTML 문서 + HTML dokumentas + HTML dokuments + HTML-dokument + HTML-document + HTML-dokument + Dokument HTML + Documento HTML + Document HTML + документ HTML + Dokument HTML + Dokument HTML + Dokument HTML + HTML-dokument + документ HTML + Tài liệu HTML + HTML 文档 + HTML 文件 + HTML + HyperText Markup Language + + + + + + + + + + + + + + + + + + + + + + + + + Web application cache manifest + قائمة التخزين الموقت لتطبيق الويب + МанифеÑÑ‚ за кеша на уеб приложение + manifest de memòria cau d'aplicació Web + Manifest mezipamÄ›ti webové aplikace + Manifest for internetprogrammellemlager + Webanwendungscache-Manifest + Web application cache manifest + manifiesto de caché de aplicación web + Web aplikazioaren cache-aren agiria + Net nýtsluskipanarkova manifest + manifeste de cache d'application Web + lastliosta taisce d'fheidhmchlár Gréasáin + manifesto de caché de aplicativo web + הצהרה של מטמון של תוכנית ברשת + Webalkalmazás gyorsítótár-összefoglalója + Manifes singgahan aplikasi web + Manifesto cache applicazione Web + Web アプリケーションキャッシュ manifest + Веб қолданбаÑының кÑш манифеÑÑ‚Ñ– + 웹 애플리케ì´ì…˜ ìºì‹œ ì •ì˜ + Žiniatinklio programos podÄ—lio manifestas + TÄ«mekļa lietotņu keÅ¡a manifests + Webapplicatie cache manifest + Manifest pamiÄ™ci podrÄ™cznej aplikacji WWW + Manifest de cache de aplicação web + Manifest de cache pentru aplicaÈ›ii web + манифеÑÑ‚ кÑша веб-Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ + Predpomnilnik spletnega programa + Cachemanifest för webbapplikation + маніфеÑÑ‚ кешу веб-програми + 网络应用程åºç¼“å­˜æ¸…å• + 網é æ‡‰ç”¨ç¨‹å¼å¿«å–è²æ˜Ž + + + + + + + + + + + + + Google Video Pointer + مؤشر Ùيديو جوجل + Pakazalnik Google Video + Документ-указател към видео на Google + apuntador a vídeo de Google + Google Video Pointer + Google Video-peger + Google Video Pointer + Google Video Pointer + lista de reproducción de Google Video (GVP) + Google Video-ren erreprodukzio-zerrenda + Google-video-osoitin + Google Video Pointer + pointeur vidéo Google + pointeoir Google Video + punteiro de vídeo de Google + מצביע ויד×ו של Google + Google Video Pointer + Google Video Pointer + Puntatore Google Video + Google ビデオãƒã‚¤ãƒ³ã‚¿ãƒ¼ + Google Video Pointer + 구글 비디오 í¬ì¸í„° + Google Video Pointer + Google Video Pointer + Peker til Google Video + Google-videoverwijzing + Google Video-peikar + Lista odtwarzania Google Video + Ponteiro do Google Vídeo + Indicator Google Video + Google Video Pointer + Google Video Pointer + Kazalec Google Video + Puntues Google Video + Google Video-pekare + вказівник відео Google + Con trỠảnh Ä‘á»™ng Google + Google è§†é¢‘æŒ‡å‘ + Google Video Pointer + + + + + + + + + Haskell source code + Ø´Ùرة مصدر Haskell + Haskell mÉ™nbÉ™ kodu + KryniÄny kod Haskell + Изходен код на Haskell + codi font en Haskell + Zdrojový kód Haskell + Ffynhonnell rhaglen Haskell + Haskellkildekode + Haskell-Quelltext + πηγαίος κώδικας Haskell + Haskell source code + Haskell-fontkodo + código fuente en Haskell + Haskell iturburu-kodea + Haskell-lähdekoodi + Haskell keldukota + code source Haskell + cód foinseach Haskell + código fonte de Haskell + קוד מקור של Haskell + Haskell izvorni kod + Haskell-forráskód + Kode program Haskell + Codice sorgente Haskell + Haskell ソースコード + Haskell баÑтапқы коды + Haskell 소스 코드 + Haskell pradinis kodas + Haskell pirmkods + Kod sumber Haskell + Haskell-kildekode + Haskell-broncode + Haskell-kjeldekode + Kod źródÅ‚owy Haskell + código fonte Haskell + Código-fonte Haskell + Cod sursă Haskell + иÑходный код Haskell + Zdrojový kód Haskell + Datoteka izvorne kode Haskell + Kod burues Haskell + Haskell изворни ко̂д + Haskell-källkod + вихідний код мовою Haskell + Mã nguồn Haskell + Haskell æºä»£ç  + Haskell æºç¢¼ + + + + + IDL document + مستند IDL + IDL sÉ™nÉ™di + Dakument IDL + Документ — IDL + document IDL + Dokument IDL + Dogfen IDL + IDL-dokument + IDL-Dokument + έγγÏαφο IDL + IDL document + IDL-dokumento + documento IDL + IDL dokumentua + IDL-asiakirja + IDL skjal + document IDL + cáipéis IDL + documento IDL + מסמך IDL + IDL dokument + IDL-dokumentum + Dokumen IDL + Documento IDL + IDL ドキュメント + IDL құжаты + IDL 문서 + IDL dokumentas + IDL dokuments + Dokumen IDL + IDL-dokument + IDL-document + IDL-dokument + Dokument IDL + documento IDL + Documento IDL + Document IDL + документ IDL + Dokument IDL + Dokument IDL + Dokument IDL + IDL документ + IDL-dokument + документ IDL + Tài liệu IDL + IDL 文档 + IDL 文件 + IDL + Interface Definition Language + + + + + installation instructions + تعليمات التثبيت + instrukcyja dla instalavaÅ„nia + ИнÑтрукции за инÑÑ‚Ð°Ð»Ð°Ñ†Ð¸Ñ + instruccions d'instal·lació + Návod k instalaci + installationsinstruktioner + Installationsanleitung + οδηγίες εγκατάστασης + installation instructions + instrucciones de instalación + instalazioaren instrukzioak + asennusohjeet + innleggingar vegleiðing + instructions d'installation + treoracha suiteála + instrucións de instalación + הור×ות התקנה + upute za instalaciju + telepítési utasítások + instruksi instalasi + Istruzioni di installazione + ソフトウェアインストール説明 + бағдарламаны орнату нұÑқаулары + 설치 방법 + diegimo instrukcijos + instalÄcijas instrukcijas + installationsinstruksjoner + installatie-instructies + installasjonsinstruksjonar + Instrukcje instalacji + Instruções de instalação + instrucÈ›iuni de instalare + инÑтрукции по уÑтановке программы + Návod na inÅ¡taláciu + navodila namestitve + Udhëzime instalimi + installationsinstruktioner + інÑтрукції з вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ + hÆ°á»›ng dẫn cài đặt + è½¯ä»¶å®‰è£…æŒ‡å— + 安è£æŒ‡å¼• + + + + + Java source code + Ø´Ùرة مصدر Java + KryniÄny kod Java + Изходен код на Java + codi font en Java + Zdrojový kód v JavÄ› + Javakildekode + Java-Quelltext + πηγαίος κώδικας Java + Java source code + Java-fontkodo + código fuente en Java + Java iturburu-kodea + Java-lähdekoodi + Java keldukota + code source Java + cód foinseach Java + código fonte de Java + קוד מקור ב־Java + Java izvorni kod + Java-forráskód + Kode program Java + Codice sorgente Java + Java ソースコード + Java баÑтапқы коды + ìžë°” 소스 코드 + Java pradinis kodas + Java pirmkods + Kod sumber Java + Java-kildekode + Java-broncode + Java-kjeldekode + Kod źródÅ‚owy Java + código fonte Java + Código-fonte Java + Cod sursă Java + иÑходный код Java + Zdrojový kód Java + Datoteka izvorne kode Java + Kod burues Java + Јава изворни ко̂д + Java-källkod + Java kaynak kodu + вихідний код мовою Java + Mã nguồn Java + Java æºä»£ç  + Java æºç¢¼ + + + + + LDIF address book + دÙتر عناوين LDIF + Adrasnaja kniha LDIF + ÐдреÑна книга — LDIF + llibreta d'adreces LDIF + Adresář LDIF + LDIF-adressebog + LDIF-Adressbuch + διευθυνσιολόγιο LDIF + LDIF address book + LDIF-adresaro + libreta de direcciones LDIF + LDIF helbide-liburua + LDIF-osoitekirja + LDIF adressubók + carnet d'adresses LDIF + leabhar sheoltaí LDIF + lista de enderezos LDIF + ספר כתובות של LDIF + LDIF adresar + LDIF címjegyzék + Buku alamat LDIF + Rubrica LDIF + LDIF アドレス帳 + LDIF адреÑтер кітабы + LDIF ì£¼ì†Œë¡ + LDIF adresų knygelÄ— + LDIF adreÅ¡u grÄmata + LDIF-adressebok + LDIF-adresboek + LDIF-adressebok + Książka adresowa LDIF + Livro de endereços LDIF + Agendă LDIF + адреÑÐ½Ð°Ñ ÐºÐ½Ð¸Ð³Ð° LDIF + Adresár LDIF + Datoteka imenika naslovov LDIF + Rubrikë LDIF + LDIF-adressbok + LDIF adres defteri + адреÑна книга LDIF + Sổ địa chỉ LDIF + LDIF 地å€ç°¿ + LDIF 通訊錄 + LDIF + LDAP Data Interchange Format + + + + + + + + + Lilypond music sheet + صÙحة موسيقى Lilypond + MuzyÄny arkuÅ¡ Lilypond + ÐÐ¾Ñ‚Ð°Ñ†Ð¸Ñ Ð½Ð° Lilypond + full de música Lilypond + Notový papír Lilypond + Lilypondmusikkort + Lilypond-Notenblatt + παÏτιτοÏÏα Lilypond + Lilypond music sheet + partitura de LilyPond + Lilypond musika-orria + Lilypond-nuotit + Lilypond tónleika ark + partition musicale Lilypond + bileog cheoil Lilypond + folla de música de Lilypond + דף מוזיקה של Lilypond + Lilypond kotta + Lembar musik Lilypond + Partitura Lilypond + Lilypond 楽譜データ + Lilypond музыка тізімі + Lilypond ì•…ë³´ + Lilypond muzikos lapas + Lilypond mÅ«zikas lapa + Lilypond-muziekblad + Lilypond noteark + Plik partytury Lilypond + Partitura do Lilypond + Fișă muzică Lilypond + ÑпиÑок музыки Lilypond + Notový papier Lilypond + Glasbena predloga Lilypond + Partiturë Lilypond + Lilypond-notblad + нотний Ð·Ð°Ð¿Ð¸Ñ Lilypond + Bản nhạc Lilypond + Lilypond ä¹è°± + Lilypond 樂譜 + + + + + LHS source code + Ø´Ùرة مصدر LHS + KryniÄny kod LHS + Изходен код на LHS + codi font en LHS + Zdrojový kód v LHS + LHS-kildekode + LHS-Quelltext + πηγαιÌος κωÌδικας LHS + LHS source code + LHS-fontkodo + código fuente en LHS + LHS iturburu-kodea + LHS-lähdekoodi + LHS keld + code source LHS + cód foinseach LHS + código fonte en LHS + קוד מקור של LHS + LHS izvorni kod + LHS forráskód + Kode program LHS + Codice sorgente LHS + LHS ソースコード + LHS баÑтапқы коды + LHS 소스 코드 + LHS pradinis kodas + LHS pirmkods + LHS-kildekode + LHS-broncode + LHS-kjeldekode + Kod źródÅ‚owy LHS + Código-fonte LHS + Cod sursă LHS + иÑходный код LHS + Zdrojový kód LHS + Datoteka izvorne kode LHS + Kod burues LHS + LHS-källkod + LHS kaynak kodu + вихідний код LHS + Mã nguồn LHS + LHS æºä»£ç  + LHS æºç¢¼ + LHS + Literate Haskell source code + + + + + application log + سجل التطبيق + Äasopis aplikacyi + Файл-дневник на приложение + registre d'aplicació + Záznam aplikace + programlog + Anwendungsprotokoll + ημεÏολόγιο συμβάντων εφαÏμογής + application log + protokolo de aplikaĵo + registro de aplicación + aplikazio egunkaria + sovelluksen lokitiedosto + nýtsluskipan logg + journal d'application + logchomhad feidhmchláir + rexistro de aplicativo + יומן התוכנה + alkalmazás naplója + log aplikasi + Log applicazione + アプリケーションログ + мәлімдемелер журналы + 프로그램 ê¸°ë¡ + programos žurnalas + lietotnes žurnÄls + Log aplikasi + applikasjonslogg + programma-logbestand + programlogg + Dziennik programu + registo de aplicação + Registro de aplicativo + înregistrare aplicaÈ›ie + журнал Ñообщений + Záznam aplikácie + dnevnik programa + log i mesazheve të programit + дневник програма + programlogg + uygulama günlüğü + журнал програми + bản ghi ứng dụng + 应用程åºæ—¥å¿— + 程å¼ç´€éŒ„檔 + + + + + Makefile + مل٠Makefile + Ä°nÅŸa faylı + Makefile + Файл — make + Makefile + Makefile + Ffeil "make" + Bygningsfil + Makefile + Makefile + Makefile + Muntodosiero + Makefile + Makefile + Makefile + Makefile + makefile + Makefile + Makefile + Makefile + Makefile + Makefile + Makefile + Makefile + Makefile + Makefile (жинау файлы) + Makefile + Makefile + Makefile + Makefile + Makefile + Makefile + Makefile + Plik make + Makefile + Makefile (arquivo do make) + Makefile + Makefile (файл Ñборки) + Makefile + Datoteka Makefile + Makefile + Производна датотека + Makefil + файл проекту make + Tập tin tạo ứng dụng (Makefile) + Makefile + Makefile + + + + + + + + + + + + + Markdown document + Документ — Markdown + document Markdown + Dokument Markdown + Markdown-dokument + Markdown-Dokument + Markdown document + Documento de Markdown + Markdown-asiakirja + document Markdown + documento de Markdown + מסמך Markdown + Markdown dokument + Markdown dokumentum + Dokumen markdown + Documento Markdown + Markdown + Markdown құжаты + 마í¬ë‹¤ìš´ 문서 + Markdown dokuments + Markdown document + Dokument Markdown + Documento Markdown + документ Markdown + Dokument Markdown + документ Markdown + Markdown 文档 + Markdown 文件 + + + + + + + Qt MOC file + مل٠Qt MOC + FajÅ‚ Qt MOC + Файл — Qt MOC + fitxer MOC de Qt + Soubor Qt MOC + Qt MOC-fil + Qt-MOC-Datei + αÏχείο Qt MOC + Qt MOC file + archivo MOC Qt + Qt MOC fitxategia + Qt MOC -tiedosto + Qt MOC fíla + fichier Qt MOC + comhad MOC Qt + ficheiro MOC Qt + קובץ Qt MOC + Qt MOC datoteka + Qt MOC fájl + Berkas Qt MOC + File MOC Qt + Qt MOC ファイル + Qt MOC файлы + Qt MOC íŒŒì¼ + Qt MOC failas + Qt MOC datne + Qt MOC-fil + Qt MOC-bestand + Qt MOC-fil + Plik Qt MOC + Arquivo Qt MOC + FiÈ™ier Qt MOC + файл Qt MOC + Súbor Qt MOC + Datoteka Qt MOC + File Qt MOC + Qt MOC-fil + файл-метаоб'єкт Qt + Tập tin MOC của Qt + Qt 元对象编译文件 + Qt MOC 檔 + Qt MOC + Qt Meta Object Compiler + + + + + Windows Registry extract + استخراج مسجل ويندوز + Element rehistru Windows + Извадка от региÑтъра на Windows + extracte del registre de Windows + Část registrů Windows + Windows Registy-udtrækning + Windows-Registry-Auszug + αποσυμπίεση Windows Registry + Windows Registry extract + extracto del registro de Windows + Windows-eko erregistro erauzlea + Windows-rekisteritietue + Windows Registry úrdráttur + extrait de registre Windows + sliocht as Clárlann Windows + Extracto do rexistro de Windows + קובץ Registry של Windows + Windows Registry kivonat + Ekstrak Windows Registry + Estratto Windows Registry + WIndows レジストリ抽出ファイル + Windows Registry бөлігі + Windows 레지스트리 íŒŒì¼ + Windows registro iÅ¡trauka + Windows Registry izvilkums + Utdrag av Windows Registry + Windows Registry-extract + Windows Registry-utdrag + Wycinek rejestru Windows + Extrator de registro do Windows + Extras al registrului Windows + фрагмент Windows Registry + ÄŒasÅ¥ registrov Windows + izvleÄek vpisnika Windows + Pjesë Windows Registry + Windows Registry-utdrag + чаÑтина реєÑтру Windows + Bản trích Registry Windows + Windows 注册表文件 + Windows Registry 抽出 + + + + + + + + + + Managed Object Format + صيغة كائن مدار + Farmat Managed Object + УправлÑвани обекти — MOF + format d'objecte gestionat + Managed Object Format + HÃ¥ndteret objektformat + Managed Object Format + ΜοÏφή ΔιαχειÏιζόμενου Αντικειμένου + Managed Object Format + formato de objeto manejado + Kudeatutako objektu formatua + Managed Object Format + format Managed Object + formáid réada bainistithe + formato de obxecto xestionado + פורמט ניהול ×ובייקט + Felügyelt objektum (MO) formátum + Managed Object Format + Managed Object Format + 管ç†ã‚ªãƒ–ジェクトフォーマット + БаÑқарылатын объект пішімі + 관리ë˜ëŠ” 오브ì íŠ¸ í˜•ì‹ + Sutvarkytų objektų formatas + PÄrvaldÄ«tu objektu formÄts + Managed Object Format + Managed Object Format + Managed Object Format + Plik Managed Object Format + Formato de objeto gerenciado + Managed Object Format + формат управлÑемого объекта + Formát Managed Object + Datoteka Managed Object + Managed Object Format + Managed Object Format + формат ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ð°Ð¼Ð¸ + Äịnh dạng Äối tượng đã Quản lý + æ‰˜ç®¡å¯¹è±¡æ ¼å¼ + Managed Object Format + + + + + Mup publication + منشور Mup + Publikacyja Mup + Издание — Mup + publicació Mup + Publikace Mup + Mupudgivelse + Mup-Veröffentlichung + δημοσίευση Mup + Mup publication + publicación Mup + Mup publikazioa + Mup-julkaisu + Mup útgáva + publication Mup + foilseachán Mup + publicación Mup + ×¤×¨×¡×•× ×©×œ Mup + Mup publikáció + Publikasi Mup + Pubblicazione Mup + Mup 出版ファイル + Mup жариÑлымы + Mup 출íŒë¬¼ + Mup leidinys + Mup publikÄcija + Mup publikasjon + Mup-publicatie + Mup-publikasjon + Publikacja Mup + Publicação do Mup + PublicaÈ›ie Mup + Ð¿ÑƒÐ±Ð»Ð¸ÐºÐ°Ñ†Ð¸Ñ Mup + Publikácie Mup + Datoteka objave Mup + Publikim Mup + Mup-publicering + Ð¿ÑƒÐ±Ð»Ñ–ÐºÐ°Ñ†Ñ–Ñ Mup + Bản xuất Mup + Mup åº”ç”¨ç¨‹åº + Mup å‡ºç‰ˆå“ + + + + + + + + + Objective-C source code + Ø´Ùرة مصدر الهدÙ-C + KryniÄny kod Objective-C + Изходен код — Objective C + codi font en Objective-C + Zdrojový kód v Objective-C + Objektiv C-kildekode + Objective-C-Quelltext + πηγαίος κώδικας Objective-C + Objective-C source code + fontkodo en Objective-C + código fuente en Objective-C + Objective-C iturburu-kodea + Objective-C-lähdekoodi + Objective-C keldukota + code source Objective-C + cód foinseach Objective-C + código fonte de Objective-C + קוד מקור של Objective-C + Objective-C forráskód + Kode program Objective-C + Codice sorgente Objective-C + Objective-C ソースコード + Objective-C-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + Objective-C баÑтапқы коды + Objective-C 소스 코드 + Objective-C pradinis kodas + Objective-C pirmkods + Kod sumber Objective-C + Objective-C-kildekode + Objective-C-broncode + Objective-C-kjeldekode + Kod źródÅ‚owy Objective-C + código fonte Objective-C + Código-fonte Objective-C + Cod sursă Objective-C + иÑходный код Objective-C + Zdrojový kód Objective-C + Datoteka izvorne kode Objective-C + Kod burues C objekt + Објектни-C изворни ко̂д + Objective-C-källkod + вихідний код мовою Objective-C + Mã nguồn Objective-C + Objective-C æºä»£ç  + Objective-C æºç¢¼ + + + + + + + + OCaml source code + Ø´Ùرة مصدر OCaml + KryniÄny kod OCaml + Изходен код — OCaml + codi font en OCaml + Zdrojový kód OCaml + OCaml-kildekode + OCaml-Quelltext + πηγαιÌος κωÌδικας OCaml + OCaml source code + OCaml-fontkodo + código fuente en OCaml + OCaml iturburu-kodea + OCaml-lähdekoodi + OCaml keldukota + code source OCaml + cód foinseach OCaml + código fonte de OCaml + קוד מקור של OCaml + OCaml izvorni kod + OCaml forráskód + Kode program OCaml + Codice sorgente OCaml + OCaml ソースコード + OCaml баÑтапқы коды + OCaml 소스 코드 + OCaml pradinis kodas + OCaml pirmkods + OCaml-kildekode + OCaml-broncode + OCaml-kjeldekode + Kod źródÅ‚owy OCaml + Código-fonte OCaml + Cod sursă OCaml + иÑходный код OCaml + Zdrojový kód OCaml + Datoteka izvorne kode OCaml + Kod burues OCaml + OCaml-källkod + OCaml kaynak kodu + первинний код мовою OCaml + Mã nguồn OCaml + OCaml æºä»£ç  + OCaml æºç¢¼ + + + + + MATLAB script/function + سكربت/وظيÙØ© MATLAB + Skrypt/funkcyja MATLAB + Скрипт/Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ â€” MATLAB + script/funció MATLAB + Skript/funkce MATLAB + MATLAB-program/-funktion + MATLAB-Skript/-Funktion + δέσμη εντολών / συνάÏτηση MATLAB + MATLAB script/function + script/función de MATLAB + MATLAB script/funtzioa + MATLAB-komentotiedosto/funktio + MATLAB boðrøð/funka + script/fonction MATLAB + script/feidhm MATLAB + función/script de MATLAB + תסריט/פונקציית MATLAB + MATLAB skripta/funkcija + MATLAB parancsfájl/funkció + Skrip/fungsi MATLAB + Script/Funzione MATLAB + MATLAB スクリプト/関数 + MATLAB Ñценарий/функциÑÑÑ‹ + MATLAB 스í¬ë¦½íŠ¸/함수 + MATLAB scenarijus / funkcija + MATLAB skripts/funkcija + Skript/funksjon for MATLAB + MATLAB-script/functie + MATLAB-skript/funksjon + Skrypt/funkcja MATLAB + Script/função do MATLAB + FuncÈ›ie/script MATLAB + Ñценарий/Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ MATLAB + Skript/funkcia MATLAB + Skriptna datoteka MATLAB + Script/Funksion MATLAB + MATLAB-skript/funktion + Ñкрипт/Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ MATLAB + Văn lệnh/chức năng MATLAB + MATLAB 脚本/函数 + MATLAB 指令稿/å‡½å¼ + + + + + + + + + + + + + + + Modelica model + + + + + + + + + + + + + + + + + + + + Pascal source code + Ø´Ùرة مصدر باسكال + KryniÄny kod Pascal + Изходен код — Pascal + codi font en Pascal + Zdrojový kód v Pascalu + Pascalkildekode + Pascal-Quelltext + πηγαίος κώδικας Pascal + Pascal source code + Pascal-fontkodo + código fuente en Pascal + Pascal iturburu-kodea + Pascal-lähdekoodi + Pascal keldukota + code source Pascal + cód foinseach Pascal + código fonte en Pascal + קוד מקור של Pascal + Pascal-forráskód + Kode program Pascal + Codice sorgente Pascal + Pascal ソースコード + Pascal баÑтапқы коды + 파스칼 소스 코드 + Pascal pradinis kodas + Pascal pirmkods + Kod sumber Pascal + Pascal-kildekode + Pascal-broncode + Pascal-kjeldekode + Kod źródÅ‚owy Pascal + código fonte Pascal + Código-fonte Pascal + Cod sursă Pascal + иÑходный код Pascal + Zdrojový kód Pascal + Datoteka izvorne kode Pascal + Kod burues Pascal + ПаÑкал изворни ко̂д + Pascal-källkod + Pascal kaynak kodu + вихідний код мовою Pascal + Mã nguồn Pascal + Pascal æºä»£ç  + Pascal æºç¢¼ + + + + + + differences between files + الاختلاÙات بين الملÙات + adroźnieÅ„ni pamiž fajÅ‚ami + Разлики между файлове + diferències entre fitxers + Rozdíly mezi soubory + forskel mellem filer + Unterschiede zwischen Dateien + διαφοÏές Î¼ÎµÏ„Î±Î¾Ï Î±Ïχείων + differences between files + diferencoj inter dosieroj + diferencias entre archivos + fitxategien arteko ezberdintasunak + tiedostojen väliset erot + munur millum fílur + différences entre fichiers + difríochtaí idir chomhaid + diferenzas entre ficheiros + ההבדל בין ×§×‘×¦×™× + razlike izmeÄ‘u datoteka + diff-különbségfájl + perbedaan diantara berkas + Differenze tra file + ファイル間差分 + файлдар араÑындағы айырмашылықтары + íŒŒì¼ ì‚¬ì´ì˜ ì°¨ì´ì  + skirtumai tarp failų + divu datņu atÅ¡Ä·irÄ«ba + Perbezaan antara fail + forskjeller mellom filer + verschillen tussen bestanden + skilnader mellom filer + Różnica pomiÄ™dzy plikami + diferenças entre ficheiros + Diferenças entre arquivos + diferenÈ›e între fiÈ™iere + Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¼ÐµÐ¶Ð´Ñƒ файлами + Rozdiely medzi súbormi + razlike med datotekami + Diferencë midis file + разлике међу датотекама + skillnader mellan filer + Ñ€Ñ–Ð·Ð½Ð¸Ñ†Ñ Ð¼Ñ–Ð¶ файлами + khác biệt giữa các tập tin + 文件的区别 + 檔案內容差異 + + + + + + + + + + + + + + + + + + + Go source code + Изходен код — Go + codi font en Go + Zdrojový kód Go + Go-kildekode + Go-Quellcode + πηγαίος κώδικας Go + Go source code + Go-fontkodo + Ir al código fuente + Go-lähdekoodi + code source Go + código fonte de Go + קוד מקור של Go + Go izvorni kod + Go forráskód + Kode sumber Go + Codice sorgente Go + Go ソースコード + Go-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + Go баÑтапқы коды + Go 소스 코드 + Go pirmkods + Go broncode + Kod źródÅ‚owy Go + Código-fonte Go + иÑходный код Go + Izvorna koda Go + вихідний код мовою Go + Go + Go æºç¢¼ + + + + + Python script + سكربت بايثون + Skrypt Python + Скрипт — Python + script Python + Skript v Pythonu + Pythonprogram + Python-Skript + Ï€ÏόγÏαμμα εντολών Python + Python script + Python-skripto + script en Python + Python script-a + Python-komentotiedosto + Python boðrøð + script Python + script Python + Script en Python + תסריט Python + Python skripta + Python-parancsfájl + Skrip Python + Script Python + Python スクリプト + Python Ñценарийі + 파ì´ì¬ 스í¬ë¦½íŠ¸ + Python scenarijus + Python skripts + Skrip Python + Python-skript + Python-script + Python-skript + Skrypt Python + 'script' Python + Script Python + Script Python + Ñценарий Python + Skript Python + Skriptna datoteka Python + Script Python + Питон Ñкрипта + Pythonskript + Ñкрипт мовою Python + Văn lệnh Python + Python 脚本 + Python 指令稿 + + + + + + + + + + + + + + + + + + + + Lua script + سكربت Lua + Skrypt Lua + Скрипт на Lua + script Lua + Skript Lua + Luaprogram + Lua-Skript + δέσμη εντολών Lua + Lua script + Lua-skripto + script en Lua + Lua script-a + Lua-komentotiedosto + Lua boðrøð + script Lua + script Lua + script de Lua + תסריט Lua + Lua skripta + Lua parancsfájl + Skrip Lua + Script Lua + Lua スクリプト + Lua Ñценарийі + Lua 스í¬ë¦½íŠ¸ + Lua scenarijus + Lua skripts + Lua-skript + Lua-script + Lua-skript + Skrypt Lua + Script Lua + Script Lua + Ñценарий Lua + Skript Lua + Skriptna datoteka Lua + Script Lua + Lua-skript + Ñкрипт Lua + Văn lệnh Lua + Lua 脚本 + Lua 指令稿 + + + + + + + + + + + + README document + مستند README + README sÉ™nÉ™di + Dakument README + Документ — „Да Ñе прочете“ + document README + Dokument README + Dogfen README + README-dokument + README-Dokument + έγγÏαφο README + README document + README-dokumento + documento README + README dokumentua + LUEMINUT-asiakirja + README skjal + document LISEZ-MOI + cáipéis README + documento README + מסמך README + README dokument + README-dokumentum + Dokumen README + Documento README + README ドキュメント + README құжаты + README 문서 + README dokumentas + README dokuments + Dokumen README + README-dokument + LEESMIJ-document + README-dokument + Dokument README + documento LEIA-ME + Documento README + Document README + документ README + Dokument README + Dokument README + Dokument README + ПРОЧИТÐЈМЕ документ + README-dokument + документ README + Tài liệu Äá»c Äi (README) + README 文档 + README 說明文件 + + + + + NFO document + مستند NFO + Dakument NFO + Документ — NFO + document NFO + Dokument NFO + NFO-dokument + NFO-Dokument + έγγÏαφο NFO + NFO document + NFO-dokumento + documento NFO + NFO dokumentua + NFO-asiakirja + NFO skjal + document NFO + cáipéis NFO + documento NFO + מסמך NFO + NFO dokument + NFO-dokumentum + Dokumen NFO + Documento NFO + NFO ドキュメント + NFO құжаты + NFO 문서 + NFO dokumentas + NFO dokuments + NFO-dokument + NFO-document + NFO-dokument + Dokument NFO + Documento NFO + Document NFO + документ NFO + Dokument NFO + Dokument NFO + Dokument NFO + NFO-dokument + NFO belgesi + документ NFO + Tài liệu NFO + NFO 文档 + NFO 文件 + + + + + RPM spec file + مل٠مواصÙات RPM + Specyfikacyjny fajÅ‚ RPM + Файл — ÑÐ¿ÐµÑ†Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð·Ð° RPM + fitxer spec RPM + Soubor spec RPM + RPM spec-fil + RPM-Spezifikationsdatei + αÏχείο spec RPM + RPM spec file + archivo de especificaciones RPM + RPM espezifikazio fitxategia + RPM spec -tiedosto + RPM tøknilýsingarfíla + fichier de spécification RPM + comhad spec RPM + ficheiro de especificacións RPM + קובץ מפרט RPM + RPM spec fájl + Berkas spesifikasi RPM + File specifica RPM + RPM spec ファイル + RPM анықтама файлы + RPM spec íŒŒì¼ + RPM spec failas + RPM specifikÄcijas datne + RPM-spesifikasjonsfil + RPM-spec-bestand + RPM spec-fil + Plik spec RPM + Arquivo de especificação RPM + FiÈ™ier RPM spec + файл опиÑÐ°Ð½Ð¸Ñ RPM + Súbor RPM spec + DoloÄilna datoteka RPM + File specifikimi RPM + RPM spec-fil + spec-файл RPM + Tập tin đặc tả RPM + RPM spec 文件 + RPM spec è¦æ ¼æª” + RPM + Red Hat Package Manager + + + + + + + + + Scala source code + Изходен код — Scala + codi font en Scala + Zdrojový kód Scala + Scala-kildekode + Scala-Quellcode + πηγαίος κώδικας Scala + Scala source code + Código fuente en Scala + Scala-lähdekoodi + code source Scala + código fnote en Scala + קוד מקור של Scala + Scala izvorni kod + Scala forráskód + Kode sumber Scala + Codice sorgente Scala + Scala ソースコード + Scala-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ კáƒáƒ“ი + Scala баÑтапқы коды + Scala 소스 코드 + Scala pirmkods + Scala broncode + Kod źródÅ‚owy Scala + Código-fonte Scala + иÑходный код Scala + Izvorna koda Scala + Scala-källkod + вихідний код мовою Scala + Scala æºä»£ç  + Scala æºç¢¼ + + + + + Scheme source code + Ø´Ùرة مصدر Scheme + Sxem mÉ™nbÉ™ kodu + KryniÄny kod Scheme + Изходен код — Scheme + codi font en Scheme + Zdrojový kód Scheme + Ffynhonnell Rhaglen Scheme + Schemekildekode + Scheme-Quelltext + πηγαίος κώδικας Scheme + Scheme source code + Scheme-fontkodo + código fuente en Scheme + Scheme iturburu-kodea + Scheme-lähdekoodi + Scheme keldukota + code source Scheme + cód foinseach Scheme + código fonte en Scheme + קוד מקור של Scheme + Scheme izvorni kod + Scheme-forráskód + Kode program Scheme + Codice sorgente Scheme + Scheme ソースコード + Scheme баÑтапқы коды + Scheme 소스 코드 + Scheme pradinis kodas + Scheme pirmkods + Kod sumber Scheme + Scheme-kildekode + Scheme-broncode + Scheme-kjeldekode + Kod źródÅ‚owy Scheme + código fonte Scheme + Código-fonte Scheme + Cod sursă Scheme + иÑходный код Scheme + Zdrojový kód Scheme + Datoteka izvorne kode Scheme + Kod burues Scheme + Scheme изворни ко̂д + Scheme-källkod + Scheme kaynak kodu + вихідний файл мовою Scheme + Mã nguồn Scheme + Scheme æºä»£ç  + Scheme æºç¢¼ + + + + + + Setext document + مستند Setext + Setext sÉ™nÉ™di + Dakument Setext + Документ — Setext + document Setext + Dokument Setext + Dogfen Setext + Setextdokument + Setext-Dokument + έγγÏαφο Setext + Setext document + Setext-dokumento + documento Setext + Setext dokumentua + Setext-asiakirja + Setext skjal + document Setext + cáipéis Setext + documento Settext + מסמך של Setext + Setext dokument + Setext-dokumentum + Dokumen Setext + Documento Setext + Setext ドキュメント + Setext құжаты + Setext 문서 + Setext dokumentas + Setext dokuments + Dokumen Setext + Setext-dokument + Setext-document + Setext-dokument + Dokument Setext + documento Setext + Documento Setext + Document Setext + документ Setext + Dokument Setext + Dokument Setext + Dokument Setext + Setext документ + Setext-dokument + Setext belgesi + документ Setext + Tài liệu Setext + Setext 文档 + Setext 文件 + + + + + SQL code + Ø´Ùرة SQL + SQL kodu + Kod SQL + Код — SQL + codi en SQL + Kód SQL + Côd SQL + SQL-kode + SQL-Befehle + κώδικας SQL + SQL code + SQL-kodo + código SQL + SQL kodea + SQL-koodi + SQL kota + code SQL + cód SQL + código SQL + קוד SQL + SQL kod + SQL-kód + Kode SQL + Codice SQL + SQL コード + SQL коды + SQL 코드 + SQL kodas + SQL kods + Kod SQL + SQL-kildekode + SQL-code + SQL-kode + Kod SQL + código SQL + Código SQL + Cod SQL + код SQL + Kód SQL + Datoteka kode SQL + Kod SQL + SQL ко̂д + SQL-kod + SQL kodu + код SQL + Mã SQL + SQL ä»£ç  + SQL 代碼 + + + + + + Tcl script + سكربت Tcl + Skrypt Tcl + Скрипт — Tcl + script Tcl + Skript v Tcl + Tcl-program + Tcl-Skript + Ï€ÏόγÏαμμα εντολών Tcl + Tcl script + Tcl-skripto + script en Tcl + Tcl script-a + Tcl-komentotiedosto + Tcl boðrøð + script Tcl + script Tcl + Script en Tcl + תסריט Tcl + Tcl skripta + Tcl-parancsfájl + Skrip Tcl + Script Tcl + Tcl スクリプト + Tcl Ñценарийі + Tcl 스í¬ë¦½íŠ¸ + Tcl scenarijus + Tcl skripts + Skrip Tcl + Tcl-skript + Tcl-script + Tcl-skript + Skrypt Tcl + 'script' Tcl + Script Tcl + Script Tcl + Ñценарий Tcl + Skript Tcl + Skriptna datoteka Tcl + Script Tcl + Tcl Ñкрипта + Tcl-skript + Ñкрипт Tcl + Văn lệnh Tcl + Tcl 脚本 + Tcl æ述語言檔 + + + + + + TeX document + مستند TeX + Dakument TeX + Документ — TeX + document TeX + Dokument TeX + Dogfen TeX + TeX-dokument + TeX-Dokument + έγγÏαφο TeX + TeX document + TeX-dokumento + documento TeX + TeX dokumentua + TeX-asiakirja + TeX skjal + document TeX + cáipéis TeX + documenton TeX + מסמך TeX + TeX dokument + TeX-dokumentum + Dokumen TeX + Documento TeX + TeX ドキュメント + TeX құжаты + TeX 문서 + TeX dokumentas + TeX dokuments + Dokumen TeX + TeX-dokument + TeX-document + TeX-dokument + Dokument TeX + documento TeX + Documento TeX + Document TeX + документ TeX + Dokument TeX + Dokument TeX + Dokument TeX + ТеХ документ + TeX-dokument + TeX belgesi + документ TeX + Tài liệu TeX + TeX 文档 + TeX 文件 + + + + + + + + + + + + + + + + + + TeXInfo document + مستند TeXInfo + TeXInfo sÉ™nÉ™di + Dakument TeXInfo + Документ — TeXInfo + document TeXInfo + Dokument TeXInfo + Dogfen TeXInfo + TeXInfo-dokument + TeXInfo-Dokument + έγγÏαφο TeXInfo + TeXInfo document + TeXInfo-dokumento + documento TeXInfo + TeXInfo dokumentua + TeXInfo-asiakirja + TeXInfo skjal + document TeXInfo + cáipéis TeXInfo + documento TeXInfo + מסמך של TeXInfo + TeXInfo dokument + TeXInfo-dokumentum + Dokumen TeXInfo + Documento TeXInfo + TeXInfo ドキュメント + TeXInfo құжаты + TeXInfo 문서 + TeXInfo dokumentas + TeXInfo dokuments + Dokumen TeXInfo + TeXInfo-dokument + TeXInfo-document + TeXInfo-dokument + Dokument TeXInfo + documento TeXInfo + Documento TeXInfo + Document TexInfo + документ TeXInfo + Dokument TeXInfo + Dokument TeXInfo + Dokument TeXInfo + ТеХинфо документ + TeXInfo-dokument + TeXInfo belgesi + документ TeXInfo + Tài liệu TeXInfo + TeXInfo 文档 + TeXInfo 文件 + + + + + + Troff ME input document + مستند Troff ME input + Uvodny dakument Troff ME + Изходен документ — Troff ME + document d'entrada Troff ME + Vstupní dokument Troff ME + Troff ME inddata-dokument + Troff-ME-Eingabedokument + έγγÏαφο/Ï€ÏόγÏαμμα εντολών troff ME + Troff ME input document + eniga dokumento de Troff ME + documento de entrada Troff ME + Troff ME sarrerako dokumentua + Troff ME -syöteasiakirja + Troff ME inntaksskjal + document d'entrée Troff ME + cáipéis ionchur Troff ME + documento de entrada Troff ME + מסמך קלט של Troff ME + Troff ME ulazni dokument + Troff ME bemeneti dokumentum + Dokumen masukan Troff ME + Documento di input Troff ME + Troff ME 入力ドキュメント + Troff ME ÐºÑ–Ñ€Ñ–Ñ Ò›Ò±Ð¶Ð°Ñ‚Ñ‹ + Troff ME ìž…ë ¥ 문서 + Troff ME įvesties dokumentas + Troff ME ievades dokuments + Dokumen input Troff ME + Troff ME-inndatadokument + Troff ME-invoerdocument + Troff ME inndata-dokument + Dokument wejÅ›ciowy Troff ME + documento origem Troff ME + Documento de entrada Troff ME + Document intrare Troff ME + входной документ Troff ME + Vstupný dokument Troff ME + Vnosni dokument Troff ME + Dokument i input Troff ME + Troff ME улазни документ + Troff ME-indatadokument + Troff ME girdi belgesi + вхідний документ Troff ME + Tài liệu nhập ME Troff + Troff ME 输入文档 + Troff ME 輸入文件 + + + + + Troff MM input document + مستند Troff MM input + Uvodny dakument Troff MM + Изходен документ — Troff MM + document d'entrada Troff MM + Vstupní dokument Troff MM + Troff MM inddata-dokument + Troff-MM-Eingabedokument + έγγÏαφο/Ï€ÏόγÏαμμα εντολών troff MM + Troff MM input document + eniga dokumento de Troff MM + documento de entrada Troff MM + Troff MM sarrerako dokumentua + Troff MM -syöteasiakirja + Troff MM inntaksskjal + document d'entrée Troff MM + cáipéis ionchur Troff MM + documento de entrada Troff MM + מסמך קלט של Troff MM + Troff MM ulazni dokument + Troff MM bemeneti dokumentum + Dokumen masukan Troff MM + Documento di input Troff MM + Troff MM 入力ドキュメント + Troff MM ÐºÑ–Ñ€Ñ–Ñ Ò›Ò±Ð¶Ð°Ñ‚Ñ‹ + Troff MM ìž…ë ¥ 문서 + Troff MM įvesties dokumentas + Troff MM ievades dokuments + Dokumen input Troff MM + Troff MM-inndatadokument + Troff MM-invoerdocument + Troff MM inndata-dokument + Dokument wejÅ›ciowy Troff MM + documento origem Troff MM + Documento de entrada Troff MM + Document intrare Troff MM + входной документ Troff MM + Vstupný dokument Troff MM + Vnosni dokument Troff MM + Dokument i input Troff MM + Troff MM улазни документ + Troff MM-indatadokument + Troff MM girdi belgesi + вхідний документ Troff MM + Tài liệu nhập MM Troff + Troff MM 输入文档 + Troff MM 輸入文件 + + + + + Troff MS input document + مستند Troff MS input + Uvodny dakument Troff MS + Изходен документ — Troff MS + document d'entrada Troff MS + Vstupní dokument Troff MS + Troff MS inddata-dokument + Troff-MS-Eingabedokument + έγγÏαφο/Ï€ÏόγÏαμμα εντολών troff MS + Troff MS input document + eniga dokumento de Troff MS + documento de entrada Troff MS + Troff MS sarrerako dokumentua + Troff MS -syöteasiakirja + Troff MS inntaksskjal + document d'entrée Troff MS + cáipéis ionchur Troff MS + documento de entrada Troff MS + מסמך קלט של Troff MS + Troff MS ulazni dokument + Troff MS bemeneti dokumentum + Dokumen masukan Troff MS + Documento di input Troff MS + Troff MS 入力ドキュメント + Troff MS ÐºÑ–Ñ€Ñ–Ñ Ò›Ò±Ð¶Ð°Ñ‚Ñ‹ + Troff MS ìž…ë ¥ 문서 + Troff MS įvesties dokumentas + Troff MS ievades dokuments + Dokumen input Troff MS + Troff MS-inndatadokument + Troff MS-invoerdocument + Troff MS inndata-dokument + Dokument wejÅ›ciowy Troff MS + documento origem Troff MS + Documento de entrada Troff MS + Document intrare Troff MS + входной документ Troff MS + Vstupný dokument Troff MS + Vnosni dokument Troff MS + Dokument i input Troff MS + Troff MS улазни документ + Troff MS-indatadokument + Troff MS girdi belgesi + вхідний документ Troff MS + Tài liệu nhập MS Troff + Troff MS 输入文档 + Troff MS 輸入文件 + + + + + X-Motif UIL table + جدول X-Motif UIL + Tablica X-Motif UIL + Таблица — X-Motif UIL + taula UIL de X-Motif + Tabulka X-Motif UIL + X-Motif UIL-tabel + X-Motif-UIL-Tabelle + πίνακας X-Motif UIL + X-Motif UIL table + tabla de X-Motif UIL + X-Motif UIL taula + X-Motif UIL -taulukko + X-Motif UIL talva + table X-Motif UIL + tábla X-Motif UIL + Táboa de X-Motif UIL + טבלה של X-Motif UIL + X-Motif UIL tablica + X-Motif UIL-táblázat + Tabel X-Motif UIL + Tabella UIL X-Motif + X-Motif UIL 表 + X-Motif UIL кеÑтеÑÑ– + X-Motif UIL í…Œì´ë¸” + X-Motif UIL lentelÄ— + X-Motif UIL tabula + Jadual X-Motif UIL + X-Motif UIL-tabell + X-Motif UIL-tabel + X-Motif UIL-tabell + Tabela UIL X-Motif + tabela UIL do X-Motif + Tabela UIL do X-Motif + Tabel X-Motif UIL + таблица UIL X-Motif + Tabuľka X-Motif UIL + Preglednica X-Motif UIL + Tabelë X-Motif UIL + X-Motif UIL табела + X-Motif UIL-tabell + Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ X-Motif UIL + Bảng UIL X-Motif + X-Motif UIL 表 + X-Motif UIL 表格 + + + + + resource location + موقع المورد + paÅ‚ažeÅ„nie resursu + МеÑтоположение на реÑÑƒÑ€Ñ + localització de recurs + UmístÄ›ní zdroje + resurseplacering + Ressourcenort + τοποθεσία πόÏου + resource location + loko de risurco + ubicación del recurso + baliabidearen kokalekua + resurssisijainti + tilfeingisstaður + localisation de ressource + suíomh acmhainne + localización do recurso + מיקומו של המקור + položaj resursa + erÅ‘forrás-hely + lokasi sumber daya + Posizione risorsa + リソースã®å ´æ‰€ + реÑÑƒÑ€Ñ Ð¾Ñ€Ð½Ð°Ð»Ð°Ñуы + ìžì› 위치 + resurso vieta + resursa atraÅ¡anÄs vieta + Lokasi sumber + ressurslokasjon + bronlocatie + ressursplassering + PoÅ‚ożenie zasobu + localização de recurso + Localização de recurso + locaÈ›ie de resursă + раÑположение реÑурÑа + Umiestnenie zdroja + mesto vira + Pozicion rezerve + путања реÑурÑа + resursplats + Ñ€Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÑурÑу + địa Ä‘iểm tài nguyên + 资æºä½ç½® + 資æºä½ç½® + + + + + uuencoded file + + + + + + + + + XMI file + مل٠XMI + FajÅ‚ XMI + Файл — XMI + fitxer XMI + Soubor XMI + XMI-fil + XMI-Datei + αÏχείο XML + XMI file + XMI-dosiero + archivo XMI + XMI fitxategia + XMI-tiedosto + XMI fíla + fichier XMI + comhad XMI + ficheiro XMI + קובץ XMI + XMI datoteka + XMI fájl + Berkas XMI + File XMI + XMI ファイル + XMI файлы + XMI íŒŒì¼ + XMI failas + XMI datne + XMI-fil + XMI-bestand + XMI-fil + Plik XMI + Arquivo XMI + FiÈ™ier XMI + файл XMI + Súbor XMI + Datoteka XMI + File XMI + XMI-fil + файл XMI + Tập tin XMI + XMI 文件 + XMI 檔 + XMI + XML Metadata Interchange + + + + + + + XSL FO file + مل٠XSL FO + FajÅ‚ XSL FO + Форматиращ файл — XSL FO + fitxer FO XSL + Soubor XSL FO + XML FO-fil + XSL-FO-Datei + αÏχείο XSL FO + XSL FO file + XSL-FO-dosiero + archivo XSL FO + XSL FO fitxategia + XSL FO -tiedosto + XSL FO fíla + fichier XSL FO + comhad XSL FO + ficheiro XSL FO + קובץ XSL FO + XSL FO datoteka + XSL FO fájl + Berkas XSL FO + File XSL FO + XSL FO ファイル + XSL FO файлы + XSL í¬ë§¤íŒ… 개체 íŒŒì¼ + XSL FO failas + XSL FO datne + FO-fil for XSL + XSL FO-bestand + XSL FO-fil + Plik XSL FO + Arquivo XSL FO + FiÈ™ier XSL FO + файл XSL FO + Súbor XSL FO + Datoteka XSL FO + File XSL FO + XSL FO-fil + файл XSL FO + Tập tin FO của XSL (XFO) + XSL æ ¼å¼åŒ–对象文件 + XSL FO 檔 + XSL FO + XSL Formatting Objects + + + + + + + iptables configuration file + مل٠تضبيط iptables + kanfihuracyjny fajÅ‚ iptables + ÐаÑтройки за iptables + fitxer de configuració d'iptables + Soubor nastavení iptables + iptableskonfigurationsfil + iptables-Konfigurationsdatei + αÏχείο Ïυθμίσεων iptables + iptables configuration file + archivo de configuración de iptables + iptables konfigurazio-fitxategia + iptables-asetustiedosto + iptables samansetingarfíla + fichier de configuration iptables + comhad cumraíochta iptables + ficheiro de configuración de iptables + קובץ הגדרה של iptables + iptables datoteka s postavkama + iptables beállítófájl + berkas konfigurasi iptables + File configurazione iptables + iptables 設定ファイル + iptables баптаулар файлы + iptables 설정 íŒŒì¼ + iptables konfigÅ«racijos failas + iptables konfigurÄcijas datne + konfigurasjonsfil for iptables + iptables-configuratiebestand + iptables oppsettfil + Plik konfiguracji iptables + Arquivo de configuração do iptables + fiÈ™ier configurare iptables + конфигурационный файл iptables + Súbor nastavení iptables + nastavitvena datoteka iptables + File konfigurimi iptables + iptables-konfigurationsfil + файл налаштувань iptables + tập tin cấu hình iptables + iptables 防ç«å¢™é…置文件 + iptables 組態檔 + + + + + + + + + + + + + + + + + + + + + + + + + XSLT stylesheet + نمط XSLT + ArkuÅ¡ stylaÅ­ XSLT + Стилове — XSLT + full d'estil XSLT + Styl XSLT + XSLT-stilark + XSLT-Stylesheet + φÏλλο στυλ XSLT + XSLT stylesheet + XSLT-stilfolio + hoja de estilo XSLT + XSLT estilo-orria + XSLT-tyylitiedosto + XSLT sniðark + feuille de style XSLT + stílbhileog XSLT + folla de estilo XSLT + סגנון גליון XSLT + XSLT stilska tablica + XSLT-stíluslap + Lembar gaya XSLT + Foglio di stile XSLT + XSLT スタイルシート + XSLT Ñтильдер кеÑтеÑÑ– + XSLT 스타ì¼ì‹œíŠ¸ + XSLT stiliaus apraÅ¡as + XSLT izklÄjlapa + Helaian Gaya XSLT + XSLT-stilark + XSLT-stijlblad + XSLT-stilark + Arkusz stylów XSLT + folha de estilos XSLT + Folha de estilo XSLT + Fișă de stil XSLT + таблица Ñтилей XSLT + Å týl XSLT + Slogovna predloga XSLT + Fletë stili XSLT + Датотека Ñа XSLT Ñтилом + XSLT-stilmall + Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Ñтилів XSLT + Tá» kiểu dáng XSLT + XSLT æ ·å¼è¡¨ + XSLT 樣å¼è¡¨ + XSLT + eXtensible Stylesheet Language Transformation + + + + + + + + + + + XMCD CD database + قاعدة بيانات XMCD CD + Baza źviestak ab dyskach XMCD + База от данни за CD-та — XMCD + base de dades de CD XMCD + Databáze XMCD CD + XMCD-cd-database + XMCD-CD-Datenbank + βάση δεδομένων CD XMCD + XMCD CD database + base de datos de CD XMCD + XMCD CD datu-basea + XMCD CD -tietokanta + XMCD fløgu dátustovnur + base de données de CD XMCD + bunachar sonraí XMCD CD + base de datos de CD XMCD + בסיס × ×ª×•× ×™× XMCD CD + XMCD CD baza podataka + XMCD CD-adatbázis + Basis data XMCD CD + Database XMCD CD + XMCD CD データベース + XMCD CD дерекқоры + XMCD CD ë°ì´í„°ë² ì´ìŠ¤ + XMCD CD duomenų bazÄ— + XMCD CD datubÄze + XMCD CD-database + XMCD CD-gegevensbank + XMCD CD-database + Baza danych CD XMCD + Banco de dados de CD XMCD + Bază de date XMCD CD + база данных компакт-диÑков XMCD + Databáza XMCD CD + Podatkovna zbirka XMCD CD + Bazë me të dhëna XMCD CD + XMCD cd-databas + база даних XMCD CD + CÆ¡ sở dữ liệu CD XMCD + XMCD CD æ•°æ®åº“ + XMCD CD 資料庫 + + + + + + + XML document + مستند XML + Dakument XML + Документ — XML + document XML + Dokument XML + XML-dokument + XML-Dokument + έγγÏαφο XML + XML document + XML-dokumento + documento XML + XML dokumentua + XML-asiakirja + XML skjal + document XML + cáipéis XML + documento XML + מסמך XML + XML dokument + XML dokumentum + Dokumen XML + Documento XML + XML ドキュメント + XML құжаты + XML 문서 + XML dokumentas + XML dokuments + XML-dokument + XML-document + XML-dokument + Dokument XML + Documento XML + Document XML + документ XML + Dokument XML + Dokument XML + Dokument XML + XML-dokument + документ XML + Tài liệu XML + XML 文档 + XML 文件 + XML + eXtensible Markup Language + + + + + + + + + + + + + + XML entities document + مستند كيانات XML + Dakument elementaÅ­ XML + Документ — замеÑтващи поÑледователноÑти в XML + document d'entitats XML + Dokument entit XML + XML-enhedsdokument + XML-Dokument-Entitäten + έγγÏαφο οντοτήτων XML + XML entities document + documento de entidades XML + XML entitateen dokumentua + XML-entiteettiasiakirja + XML einindisskjal + document d'entités XML + cáipéis aonán XML + documento de entidades XML + מסמך ישיות XML + XML egyeddokumentum + Dokumen entitas XML + Documento entità XML + XML エントリドキュメント + XML мәндер құжаты + XML 엔티티 문서 + XML esybių dokumentas + XML vienÄ«bu dokuments + XML-entitetsdokument + XML entiteiten-document + XML-entitet-dokument + Dokument jednostek XML + Documento de entidades XML + Document entități XML + файл ÑущноÑтей XML + Dokument entít XML + Dokument XML doloÄil + Dokument njësish XML + XML-entitetsdokument + документ об’єктів XML + Tài liệu thá»±c thể XML + XML 特å¾æ–‡æ¡£ + XML 實體文件 + XML + eXtensible Markup Language + + + + + + + DV video + DV مرئي + Videa DV + Видео — DV + vídeo DV + Video DV + DV-video + DV-Video + βίντεο DV + DV video + DV-video + vídeo DV + DV bideoa + DV-video + DV video + vidéo DV + físeán DV + vídeo DV + ויד×ו DV + DV video + DV videó + Video DV + Video DV + DV å‹•ç”» + DV ვიდერ+ DV видеоÑÑ‹ + DV 비디오 + DV vaizdo įraÅ¡as + DV video + DV-film + DV-video + DV-video + Plik wideo DV + Vídeo DV + Video DV + видео DV + Video DV + Video datoteka DV + Video DV + DV-video + відеокліп DV + Ảnh Ä‘á»™ng DV + DV 视频 + DV 視訊 + DV + Digital Video + + + + + + + ISI video + مرئي ISI + ISI video faylı + Videa ISI + Видео — ISI + vídeo ISI + Video ISI + Fideo ISI + ISI-video + ISI-Video + βίντεο ISI + ISI video + ISI-video + vídeo ISI + ISI bideoa + ISI-video + ISI video + vidéo ISI + físeán ISI + vídeo ISI + ויד×ו ISI + ISI video + ISI-videó + Video ISI + Video ISI + ISI å‹•ç”» + ISI видеоÑÑ‹ + ISI 비디오 + ISI vaizdo įraÅ¡as + ISI video + Video ISI + ISI-film + ISI-video + ISI video + Plik wideo ISI + vídeoISI + Vídeo ISI + Video ISI + видео ISI + Video ISI + Video datoteka ISI + Video ISI + ISI видео + ISI-video + відеокліп ISI + Ảnh Ä‘á»™ng ISI + ISI 视频 + ISI 視訊 + + + MPEG-2 transport stream + بث نقل MPEG-2 + Поток — транÑпорт по MPEG-2 + flux de transport MPEG-2 + PÅ™enosový proud MPEG-2 + MPEG-2-transportstrøm + MPEG-2-Transportstrom + Ïοή μεταφοÏών MPEG-2 + MPEG-2 transport stream + flujo de transporte MPEG-2 + MPEG-2 -siirtobittivirta + MPEG-2 flutningsstreymur + flux de transport MPEG-2 + Sruth aistrithe MPEG-2 + fluxo de transporte MPEG-2 + העברת זרימה של MPEG-2 + MPEG-2 átviteli adatfolyam + Stream transport MPEG-2 + Stream di trasporto MPEG-2 + MPEG-2 トランスãƒãƒ¼ãƒˆã‚¹ãƒˆãƒªãƒ¼ãƒ  + MPEG-2-ის ტრáƒáƒœáƒ¡áƒžáƒáƒ áƒ¢áƒ£áƒšáƒ˜ ნáƒáƒ™áƒáƒ“ი + MPEG-2 көліктік ағыны + MPEG-2 전송 스트림 + MPEG-2 transportavimo srautas + MPEG-2 transporta straume + MPEG-2 transport stream + StrumieÅ„ przesyÅ‚ania MPEG-2 + Fluxo de transporte de MPEG-2 + Flux transport MPEG-2 + транÑпортный поток MPEG-2 + PretoÄni vir prenosega MPEG + MPEG-2 transportström + потік Ð¿ÐµÑ€ÐµÐ´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… MPEG-2 + MPEG-2 ä¼ è¾“æµ + MPEG-2 å‚³è¼¸ä¸²æµ + MPEG-2 TS + Moving Picture Experts Group 2 Transport Stream + + + + + + + + + + + + + + + + MPEG video + MPEG مرئي + Videa MPEG + Видео — MPEG + vídeo MPEG + Video MPEG + MPEG-video + MPEG-Video + βίντεο MPEG + MPEG video + MPEG-video + vídeo MPEG + MPEG bideoa + MPEG-video + MPEG video + vidéo MPEG + físeán MPEG + vídeo MPEG + ויד×ו MPEG + MPEG video + MPEG-videó + Video MPEG + Video MPEG + MPEG å‹•ç”» + MPEG ვიდერ+ MPEG видеоÑÑ‹ + MPEG 비디오 + MPEG vaizdo įraÅ¡as + MPEG video + Video MPEG + MPEG-film + MPEG-video + MPEG-video + Plik wideo MPEG + vídeo MPEG + Vídeo MPEG + Video MPEG + видео MPEG + Video MPEG + Video datoteka MPEG + Video MPEG + MPEG видео + MPEG-video + відеокліп MPEG + Ảnh Ä‘á»™ng MPEG + MPEG 视频 + MPEG 視訊 + MPEG + Moving Picture Experts Group + + + + + + + + + + + + + + + + MPEG video (streamed) + Видео — MPEG, поточно + vídeo MPEG (flux) + Video MPEG (proud) + MPEG-video (streamet) + MPEG-Video (Datenstrom) + βίντεο MPEG (εκπεμπόμενο) + MPEG video (streamed) + Vídeo MPEG (flujo) + MPEG-video (virtaus) + vidéo MPEG (flux) + vídeo MPEG (en stream) + קובץ MPEG (בהזרמה) + MPEG videó (szórt) + Video MPEG (di-stream-kan) + Video MPEG (streamed) + MPEG ビデオ(ストリーム) + MPEG ვიდერ(ნáƒáƒ™áƒáƒ“ი) + MPEG видео (ағымдық) + MPEG 비디오 (스트리ë°) + MPEG video (straumÄ“ts) + MPEG video (streamed) + Plik wideo MPEG (strumieÅ„) + Vídeo MPEG (fluxo) + видео MPEG (потоковое) + MPEG-video (pretoÄni) + MPEG-video (strömmad) + відеокліп MPEG (потоковий) + MPEG 视频æµåª’体 + MPEG 視訊 (串æµ) + + + + + + + + + + + QuickTime video + QuickTime مرئي + Videa QuickTime + Видео — QuickTime + vídeo QuickTime + Video QuickTime + QuickTime-video + QuickTime-Video + βίντεο QuickTime + QuickTime video + QuickTime-video + vídeo QuickTime + QuickTime bideoa + QuickTime-video + QuickTime video + vidéo QuickTime + físeán QuickTime + vídeo QuickTime + ויד×ו של QuickTime + QuickTime video + QuickTime videó + Video QuickTime + Video QuickTime + QuickTime å‹•ç”» + QuickTime видеоÑÑ‹ + 퀵타임 비디오 + QuickTime vaizdo įraÅ¡as + QuickTime video + Video QuickTime + Quicktime film + QuickTime-video + QuickTime-video + Plik wideo QuickTime + vídeo QuickTime + Vídeo do QuickTime + Video QuickTime + видео QuickTime + Video QuickTime + Video datoteka QuickTime + Video QuickTime + QuickTime видео + QuickTime-video + відеокліп QuickTime + Ảnh Ä‘á»™ng QuickTime + QuickTime 视频 + QuickTime 視訊 + + + + + + + + + + + + + QuickTime image + صورة QuickTime + Vyjava QuickTime + Изображение — QuickTime + imatge QuickTime + Obrázek QuickTime + QuickTime-billede + QuickTime-Bild + εικόνα QuickTime + QuickTime image + QuickTime-bildo + imagen QuickTime + QuickTime irudia + QuickTime-kuva + QuickTime mynd + image QuickTime + íomhá QuickTime + imaxe QuickTime + תמונה של QuickTime + QuickTime slika + QuickTime kép + Citra QuickTime + Immagine QuickTime + QuickTime ç”»åƒ + QuickTime Ñуреті + 퀵타임 그림 + QuickTime paveikslÄ—lis + QuickTime attÄ“ls + Quicktime bilde + QuickTime-afbeelding + QuickTime-bilete + Obraz QuickTime + Imagem do QuickTime + Imagine QuickTime + изображение QuickTime + Obrázok QuickTime + Slikovna datoteka QuickTime + Figurë QuickTime + QuickTime-bild + Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ QuickTime + Ảnh QuickTime + QuickTime å›¾åƒ + QuickTime å½±åƒ + + + + + + + + Vivo video + Vivo مرئي + Vivo video faylı + Videa Vivo + Видео — Vivo + vídeo Vivo + Video Vivo + Fideo Vivo + Vivo-video + Vivo-Video + βίντεο Vivo + Vivo video + Vivo-video + vídeo Vivo + Vivo bideoa + Vivo-video + Vivo video + vidéo Vivo + físeán Vivo + vídeo Vivo + ויד×ו של Vivo + Vivo video + Vivo-videó + Video Vivo + Video Vivo + Vivo å‹•ç”» + Vivo видеоÑÑ‹ + Vivo 비디오 + Vivo vaizdo įraÅ¡as + Vivo video + Video Vivo + Vivo-film + Vivo-video + Vivo-film + Plik wideo Vivo + vídeo Vivo + Vídeo Vivo + Video Vivo + видео Vivo + Video Vivo + Video datoteka Vivo + Video Vivo + Vivo видео + Vivo-video + відео Vivo + Ảnh Ä‘á»™ng Vivo + Vivo 视频 + Vivo 視訊 + + + + + + Wavelet video + Wavelet مرئي + Wavelet video faylı + Videa Wavelet + Видео — Wavelet + vídeo Wavelet + Video Wavelet + Fideo Wavelet + Waveletvideo + Wavelet-Video + βίντεο Wavelet + Wavelet video + Wavelet-video + vídeo Wavelet + Wavelet bideoa + Wavelet-video + Wavelet video + vidéo Wavelet + físeán Wavelet + vídeo Wavelet + ויד×ו של Wavelet + Wavelet video + Wavelet-videó + Video Wavelet + Video Wavelet + Wavelet å‹•ç”» + Wavelet видеоÑÑ‹ + Wavelet 비디오 + Wavelet vaizdo įraÅ¡as + Wavelet video + Video Wavelet + Wavelet-film + Wavelet-video + Wavelet video + Plik wideo Wavelet + vídeo Wavelet + Vídeo Wavelet + Video Wavelet + видео Wavelet + Video Wavelet + Video datoteka Wavelet + Video Wavelet + Wavelet видео + Wavelet-video + відеокліп Wavelet + Ảnh Ä‘á»™ng Wavelet + Wavelet 视频 + Wavelet 視訊 + + + ANIM animation + تحريكة ANIM + ANIM animasiyası + Animacyja ANIM + ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ â€” ANIM + animació ANIM + Animace ANIM + Animeiddiad ANIM + ANIM-animation + ANIM-Animation + κινοÏμενο σχέδιο ANIM + ANIM animation + ANIM-animacio + animación ANIM + ANIM animazioa + ANIM-animaatio + ANIM teknmyndagerð + animation ANIM + beochan ANIM + animación ANIM + הנפשת ANIM + ANIM animacija + ANIM-animáció + Animasi ANIM + Animazione ANIM + ANIM アニメーション + ANIM áƒáƒœáƒ˜áƒ›áƒáƒªáƒ˜áƒ + ANIM анимациÑÑÑ‹ + ANIM ë™í™”ìƒ + ANIM animacija + ANIM animÄcija + Animasi ANIM + ANIM-animasjon + ANIM-animatie + ANIM-animasjon + Plik animacji ANIM + animação ANIM + Animação ANIM + AnimaÈ›ie ANIM + Ð°Ð½Ð¸Ð¼Ð°Ñ†Ð¸Ñ ANIM + Animácia ANIM + Datoteka animacije ANIM + Animim ANIM + ANIM анимација + ANIM-animering + Ð°Ð½Ñ–Ð¼Ð°Ñ†Ñ–Ñ ANIM + Hoạt ảnh ANIM + ANIM 动画 + ANIM å‹•ç•« + + + + FLIC animation + تحريكة FLIC + Animacyja FLIC + ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ â€” FLIC + animació FLIC + Animace FLIC + FLIC-animation + FLIC-Animation + κινοÏμενες εικόνες FLIC + FLIC animation + animación FLIC + FLIC animazioa + FLIC-animaatio + FLIC teknimyndagerð + animation FLIC + beochan FLIC + animación FLIC + הנפשת FLIC + FLIC animacija + FLIC animáció + Animasi FLIC + Animazione FLIC + FLIC アニメーション + FLIC áƒáƒœáƒ˜áƒ›áƒáƒªáƒ˜áƒ + FLIC анимациÑÑÑ‹ + FLIC ë™í™”ìƒ + FLIC animacija + FLIC animÄcija + FLIC-animasjon + FLIC-animatie + FLIC-animasjon + Plik animacji FLIC + Animação FLIC + AnimaÈ›ie FLIC + Ð°Ð½Ð¸Ð¼Ð°Ñ†Ð¸Ñ FLIC + Animácia FLIC + Datoteka animacije FLIC + Animim FLIC + FLIC-animering + FLIC animasyonu + Ð°Ð½Ñ–Ð¼Ð°Ñ†Ñ–Ñ FLIC + Hoạt ảnh FLIC + FLIC 动画 + FLIC å‹•ç•« + + + + + + + + + + + Haansoft Hangul document + مستند Haansoft Hangul + Dakument Haansoft Hangul + Документ — Haansoft Hangul + document Haansoft Hangul + Dokument Haansoft Hangul + Haansoft Hangul-dokument + Haansoft-Hangul-Dokument + έγγÏαφο Haansoft Hangul + Haansoft Hangul document + documento de Haansoft Hangul + Haansoft Hangul dokumentua + Haansoft Hangul -asiakirja + Haansoft Hangul skjal + document Haansoft Hangul + cáipéis Haansoft Hangul + documento de Haansoft Hangul + מסמך Haansoft Hangul + Haansoft Hangul dokument + Haansoft hangul dokumentum + Dokumen Haansoft Hangul + Documento Haansoft Hangul + Haansoft Hangul ドキュメント + Haansoft Hangul құжаты + 한소프트 한글 문서 + Haansoft Hangul dokumentas + Haansoft Hangul dokuments + Haansoft Hangul-dokument + Haansoft Hangul-document + Haansoft Hangul-dokument + Dokument Haansoft Hangul + Documento do Haansoft Hangul + Document Haansoft Hangul + документ Haansoft Hangul + Dokument Haansoft Hangul + Dokument Haansoft Hangul + Dokument Haansoft Hangul + Haansoft Hangul-dokument + документ Haansoft Hangul + Tài liệu Hangul Haansoft + Haansoft Hangul 文档 + Haansoft 韓文文件 + + + + + + + + + Haansoft Hangul document template + قالب مستند Haansoft Hangul + Å ablon dakumentu Haansoft Hangul + Шаблон за документи — Haansoft Hangul + plantilla de document Haansoft Hangul + Å ablona dokumentu Haansoft Hangul + Haansoft Hangul-dokumentskabelon + Haansoft-Hangul-Dokumentvorlage + Ï€Ïότυπο εγγÏάφου Haansoft Hangul + Haansoft Hangul document template + plantilla de documento de Haansoft Hangul + Haansoft Hangul dokumentuaren txantiloia + Haansoft Hangul -asiakirjamalli + Haansoft Hangul skjalaformur + modèle de document Haansoft Hangul + teimpléad cháipéis Haansoft Hangul + modelo de documento de Haansoft Hangul + תבנית מסמך של Haansoft Hangul + Haansoft Hangul predložak dokumenta + Haansoft hangul dokumentumsablon + Templat dokumen Haansoft Hangul + Modello documento Haansoft Hangul + Haansoft Hangul ドキュメントテンプレート + Haansoft Hangul құжат үлгіÑÑ– + 한소프트 한글 문서 ì„œì‹ + Haansoft Hangul dokumento Å¡ablonas + Haansoft Hangul dokumentu veidne + Haansoft Hangul-dokumentmal + Haansoft Hangul-documentsjabloon + Haansoft Hangul-dokumentmal + Szablon dokumentu Haansoft Hangul + Modelo de documento do Haansoft Hangul + Document È™ablon Haansoft Hangul + шаблон документа Haansoft Hangul + Å ablóna dokumentu Haansoft Hangul + Predloga dokumenta Haansoft Hangul + Model dokumenti Haansoft Hangul + Haansoft Hangul-dokumentmall + шаблон документа Haansoft Hangul + Mẫu tài liệu Hangul Haansoft + Haansoft Hangul æ–‡æ¡£æ¨¡æ¿ + Haansoft 韓文文件範本 + + + + + + MNG animation + تحريكة MNG + Animacyja MNG + ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ â€” MNG + animació MNG + Animace MNG + MNG-animation + MNG-Animation + κινοÏμενα σχέδια MNG + MNG animation + MNG-animacio + animación MNG + MNG animazioa + MNG-animaatio + MNG teknimyndagerð + animation MNG + beochan MNG + animación MNG + הנפשת MNG + MNG animacija + MNG-animáció + Animasi MNG + Animazione MNG + MNG アニメーション + MNG анимациÑÑÑ‹ + MNG ë™í™”ìƒ + MNG animacija + MNG animÄcija + Animasi MNG + MNG-animasjon + MNG-animatie + MNG-animasjon + Animacja MNG + animação MNG + Animação MNG + AnimaÈ›ie MNG + Ð°Ð½Ð¸Ð¼Ð°Ñ†Ð¸Ñ MNG + Animácia MNG + Datoteka animacije MNG + Animim MNG + MNG анимација + MNG-animering + Ð°Ð½Ñ–Ð¼Ð°Ñ†Ñ–Ñ MNG + Hoạt ảnh MNG + MNG 动画 + MNG å‹•ç•« + MNG + Multiple-Image Network Graphics + + + + + + + ASF video + ASF مرئي + Videa ASF + Видео — ASF + vídeo ASF + Video ASF + ASF-video + ASF-Video + βιÌντεο ASF + ASF video + ASF-video + vídeo ASF + ASF bideoa + ASF-video + ASF video + vidéo ASF + físeán ASF + vídeo ASF + ויד×ו ASF + ASF video + ASF videó + Video ASF + Video ASF + ASF å‹•ç”» + ASF ვიდერ+ ASF видеоÑÑ‹ + ASF 비디오 + ASF vaizdo įraÅ¡as + ASF video + ASF-film + ASF-video + ASF-video + Plik wideo ASF + Vídeo ASF + Video ASF + видео ASF + Video ASF + Video datoteka ASF + Video ASF + ASF-video + відеокліп ASF + Ảnh Ä‘á»™ng ASF + ASF 视频 + ASF 視訊 + ASF + Advanced Streaming Format + + + + + + + + + + Windows Media Station file + مل٠محطة Windows Media + FajÅ‚ Windows Media Station + Файл — Windows Media Station + fitxer Windows Media Station + Soubor Windows Media Station + Windows Media Station-fil + Windows-Media-Streamingbeschreibung + αÏχείο Windows Media Station + Windows Media Station file + archivo de emisora de Windows Media + Windows Media Station fitxategia + Windows Media Station-tiedosto + Windows Media Station fíla + fichier Windows Media Station + comhad Windows Media Station + ficheiro de emisora de Windows Media + קובץ תחנה של Windows Media + Windows Media Station fájl + Berkas Windows Media Station + File Windows Media Station + Windows Media Station ファイル + Windows Media Station файлы + Windows 미디어 방송국 íŒŒì¼ + Windows Media Station failas + Windows Media Station datne + Windows Media Station-fil + Windows Media Station-bestand + Windows Media Station-fil + Plik Windows Media Station + Arquivo de estação do Windows Media + FiÈ™ier Windows Media Station + файл Windows Media Station + Súbor Windows Media Station + Datoteka Windows Media Station + File Windows Media Station + Windows Media Station-fil + Windows Media Station dosyası + файл Windows Media Station + Tập tin Windows Media Station + Windows 媒体工作站文件 + Windows Media Station 檔 + + + + + + + + + Windows Media video + Windows Media مرئي + Videa Windows Media + Видео — Windows Media + vídeo Windows Media + Video Windows Media + Windows Medie-video + Windows-Media-Video + βίντεο Windows Media + Windows Media video + vídeo de Windows Media + Windows Media bideoa + Windows Media -video + Windows Media video + vidéo Windows Media + físeán Windows Media + vídeo de Windows Media + ויד×ו של Windows Media + Windows Media video + Windows Media videó + Video Windows Media + Video Windows Media + Windows Media å‹•ç”» + Windows Media видеоÑÑ‹ + Windows 미디어 오디오 + Windows Media vaizdo įraÅ¡as + Windows Media video + Windows Media film + Windows Media-video + Windows Media-video + Plik wideo Windows Media + Vídeo do Windows Media + Video Windows Media + видео Windows Media + Video Windows Media + Video datoteka Windows Media + Video Windows Media + Windows Media-video + відеокліп Windows Media + Ảnh Ä‘á»™ng Windows Media + Windows Media 视频 + Windows Media 視訊 + + + + + AVI video + AVI مرئي + AVI video faylı + Videa AVI + Видео — AVI + vídeo AVI + Video AVI + Fideo AVI + AVI-video + AVI-Video + βίντεο AVI + AVI video + AVI-video + vídeo AVI + AVI bideoa + AVI-video + AVI video + vidéo AVI + físeán AVI + vídeo AVI + ויד×ו AVI + AVI video + AVI-videó + Video AVI + Video AVI + AVI å‹•ç”» + AVI ვიდერ+ AVI видеоÑÑ‹ + AVI 비디오 + AVI vaizdo įraÅ¡as + AVI video + Video AVI + AVI-film + AVI-video + AVI-video + Plik wideo AVI + vídeo AVI + Vídeo AVI + Video AVI + видео AVI + Video AVI + Video datoteka AVI + Video AVI + AVI видео + AVI-video + відеокліп AVI + Ảnh Ä‘á»™ng AVI + AVI 视频 + AVI 視訊 + AVI + Audio Video Interleave + + + + + + + + + + + + + + + + + + + NullSoft video + NullSoft مرئي + Videa NullSoft + Видео — NullSoft + vídeo NullSoft + Video NullSoft + NullSoft-video + NullSoft-Video + βίντεο Nullsoft + NullSoft video + NullSoft-video + vídeo NullSoft + NullSoft bideoa + NullSoft-video + NullSoft video + vidéo NullSoft + físeán NullSoft + vídeo de NullSoft + ויד×ו של NullSot + NullSoft video + NullSoft videó + Video NullSoft + Video NullSoft + NullSoft å‹•ç”» + NullSoft видеоÑÑ‹ + ë„소프트 비디오 + NullSoft vaizdo įraÅ¡as + NullSoft video + Nullsoft-film + NullSoft-video + NullSoft-video + Plik wideo NullSoft + Vídeo do NullSoft + Video NullSoft + видео Nullsoft + Video NullSoft + Video datoteka NullSoft + Video NullSoft + NullSoft-video + відеокліп NullSoft + Ảnh Ä‘á»™ng NullSoft + Nullsoft 视频 + NullSoft 視訊 + + + + + + + SDP multicast stream file + مل٠دÙÙ‚ متعدد البث SDP + Å matadrasny pÅ‚ynievy fajÅ‚ SDP + Файл за поток — SDP multicast + fitxer de flux de multidifusió SDP + Soubor vícesmÄ›rového vysílání proudu SDP + SDP multicast-strømfil + SDP-Multicast-Datenstromdatei + SDP multicast stream file + archivo de flujo multicast SDP + SDP multicast korrontearen fitxategia + SDP-monilähetysvirran tiedosto + SDP margvarpað streymafíla + fichier de flux multidiffusion SDP + comhad shruth ilchraolacháin SDP + ficheiro de fluxo multicast SDP + קובץ שידור בזרימה SDP + SDP multicast műsorfájl + Berkas SDP multicast stream + File stream multicast SDP + SDP マルãƒã‚­ãƒ£ã‚¹ãƒˆã‚¹ãƒˆãƒªãƒ¼ãƒ ãƒ•ã‚¡ã‚¤ãƒ« + SDP мультикаÑÑ‚ ағым файлы + SDP 멀티ìºìŠ¤íŠ¸ 스트림 íŒŒì¼ + SDP daugiaadresio srauto failas + SDP multiraides straumes datne + SDP-multicaststrøm + SDP-multicast-streambestand + SDP multicast straumfil + Plik strumienia multicast SDP + Arquivo de canal multicast SDP + FiÈ™ier flux multicast SDP + файл мультикаÑÑ‚-потока SDP + Súbor viacsmerového vysielania prúdu SDP + PretoÄni vir veÄsmernega oddajanja + File stream multicast SDP + SDP multicast stream-fil + файл потокової транÑлÑції SDP + Tập tin luồng truyá»n má»™t-nhiá»u SDP + SDP 多播æµæ–‡ä»¶ + SDP multicast 串æµæª” + SDP + Session Description Protocol + + + + + + + + + + + + SGI video + SGI مرئي + SGI video faylı + Videa SGI + Видео — SGI + vídeo SGI + Video SGI + Video SGI + SGI-video + SGI-Video + βίντεο SGI + SGI video + SGI-video + vídeo SGI + SGI bideoa + SGI-video + SGI video + vidéo SGI + físeán SGI + vídeo SGI + ויד×ו SGI + SGI video + SGI-videó + Video SGI + Video SGI + SGI å‹•ç”» + SGI видеоÑÑ‹ + SGI 비디오 + SGI vaizdo įraÅ¡as + SGI video + Video SGI + SGI-film + SGI-video + SGI-video + Plik wideo SGI + vídeo SGI + Vídeo SGI + Video SGI + видео SGI + Video SGI + Video datoteka SGI + Video SGI + SGI видео + SGI-video + відеокліп SGI + Ảnh Ä‘á»™ng SGI + SGI 视频 + SGI 視訊 + + + + + + + eMusic download package + حزمة تنزيل eMusic + pakunak zahruzki eMusic + Пакет за ÑвалÑне — eMusic + paquet de descàrrega eMusic + BalíÄek stahování eMusic + eMusic-hentpakke + eMusic-Download-Paket + πακέτο eMusic + eMusic download package + paquete de descarga eMusic + eMusic deskargaren paketea + eMusic-imurointipaketti + eMusic niðurtøkupakki + paquet de téléchargement eMusic + pacáiste íosluchtú eMusic + paquete de descarga de eMusic + חבילת הורדה של eMusic + eMusic letöltési csomag + paket unduh eMusic + Pacchetto scaricamento eMusic + eMusic ダウンロードパッケージ + eMusic жүктемелер деÑтеÑÑ– + eMusic 다운로드 패키지 + eMusic atsiuntimo paketas + eMusic lejupielÄdes paciņa + eMusic nedlastingspakke + eMusic-downloadpakket + eMusic nedlastingspakke + Pobieralny pakiet eMusic + Pacote de download do eMusic + pachet descărcare eMusic + пакет загрузок eMusic + BalíÄek sÅ¥ahovania eMusic + Datoteka paketa eMusic + Paketë shkarkimi eMusic + eMusic-hämtningspaket + пакунок Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ eMusic + gói nhạc tải xuống eMusic + eMusic 下载包 + eMusic 下載套件 + + + + + + + + KML geographic data + بيانات جغراÙية KML + ГеографÑки данни — KML + dades geogràfiques KML + Geografická data KML + Geografiske data i KML-format + KML geographische Daten + γεωγÏαφικά δεδομένα KML + KML geographic data + datos geográficos KML + KML datu geografikoak + KML landafrøðilig dáta + données géographiques KML + sonraí geografacha KML + datos xeográficos KML + מידע ×’×וגרפי KML + KML geografski podaci + KML földrajzi adatok + Data geografis KML + Dati geografici KML + KML 地ç†ãƒ‡ãƒ¼ã‚¿ + KML географилық ақпараты + KML 지리 ì •ë³´ ë°ì´í„° + KML geografiniai duomenys + KML Ä£eogrÄfiskie dati + KML geographic data + Dane geograficzne KML + Dados geográficos KML + Date geografice KML + географичеÑкие данные KML + Zemepisné údaje KML + Datoteka geografskih podatkov KML + KML geografisk data + географічні дані KML + KML 地ç†æ•°æ® + KML 地ç†è³‡æ–™ + KML + Keyhole Markup Language + + + + + + KML geographic compressed data + بيانات جغراÙية مضغوطة KML + ГеографÑки данни — KML, компреÑирани + dades geogràfiques comprimides KML + Komprimovaná geografická data KML + KML-geografiske komprimerede data + KML geographische komprimierte Daten + γεωγÏαφικά συμπιεσμένα δεδομένα KML + KML geographic compressed data + datos geográficos comprimidos KML + KML datu geografiko konprimituak + KML landafrøðilig stappað dáta + données géographiques KML compressées + sonraí comhbhrúite geografacha KML + datos xeográficos KML comprimidos + מידע ×’×וגרפי דחוס KML + KML geografski komprimirani podaci + KML tömörített földrajzi adatok + Data geografis KML terkompresi + Dati geografici KML compressi + KML 地ç†åœ§ç¸®ãƒ‡ãƒ¼ã‚¿ + KML географиÑлық Ñығылған ақпарат + KML 지리 ì •ë³´ 압축 ë°ì´í„° + KML geografiniai suglaudinti duomenys + KML saspiesti Ä£eogrÄfiskie dati + KML geographic compressed data + Skompresowane dane geograficzne KML + Dados comprimidos geográficos KML + Date geografice comprimate KML + Ñжатые географичеÑкие данные KML + Komprimované zemepisné údaje KML + SkrÄeni geografski podatki KML + KML geografiskt komprimerat data + ÑтиÑнуті географічні дані KML + KML 压缩地ç†æ•°æ® + KML 地ç†å£“縮資料 + KML + Keyhole Markup Language + + + + + Citrix ICA settings file + مل٠إعدادات Citrix ICA + FajÅ‚ naÅ‚adaÅ­ Citrix ICA + ÐаÑтройки — Citrix ICA + fitxer de paràmetres de Citrix ICA + Soubor nastavení Citrix ICA + Citrix ICA-opsætningsfil + Citrix-ICA-Einstellungsdatei + αÏχείο Ïυθμίσεων Citrix ICA + Citrix ICA settings file + archivo de opciones de Citrix ICA + Citrix ICA ezarpenen fitxategia + Citrix ICA -asetustiedosto + Citrix ICA stillingarfíla + fichier de paramètres ICA Citrix + comhad socruithe Citrix ICA + ficheiro de configuracións de Citrix ICA + קובץ הגדרות של Citrix ICA + Citrix ICA datoteka postavki + Citrix ICA beállításfájl + Berkas penataan Citrix ICA + File impostazioni Citrix ICA + Citrix ICA 設定ファイル + Citrix ICA-ის პáƒáƒ áƒáƒ›áƒ”ტრების ფáƒáƒ˜áƒšáƒ˜ + Citrix ICA баптаулар файлы + 시트릭스 ICA 설정 íŒŒì¼ + Citrix ICA parametrų failas + Citrix ICA iestatÄ«jumu datne + Innstillingsfil for Citrix ICA + Citrix ICA-instellingen + Citrix ICA-innstillingsfil + Plik ustawieÅ„ Citrix ICA + Arquivo de configurações do Citrix ICA + FiÈ™ier de configurări Citrix ICA + файл наÑтроек Citrix ICA + Súbor nastavení Citrix ICA + Nastavitvena datoteka Citrix ICA + File rregullimesh Citrix ICA + Citrix ICA-inställningsfil + файл параметрів ICA Citrix + Tập tin thiết lập ICA Citrix + Citrix ICA 设置文件 + Citrix ICA 設定值檔案 + ICA + Independent Computing Architecture + + + + + + XUL interface document + مستند واجهة XUL + Interfejsny dakument XUL + Документ — Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð·Ð° XUL + document d'interfície XUL + Dokument rozhraní XUL + XUL-grænsefladedokument + XUL-Oberflächendokument + έγγÏαφο διεπαφής XUL + XUL interface document + documento de interfaz XUL + XUL interfazearen dokumentua + XUL-käyttöliittymäasiakirja + XUL markamótsskjal + document d'interface XUL + cáipéis chomhéadan XUL + documento de interface XUL + מסמך ממשק XUL + XUL-felületdokumentum + Dokumen antarmuka XUL + Documento interfaccia XUL + XUL インターフェイスドキュメント + XUL Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ò›Ò±Ð¶Ð°Ñ‚Ñ‹ + XUL ì¸í„°íŽ˜ì´ìŠ¤ 문서 + XUL sÄ…sajos dokumentas + XUL saskarnes dokuments + XUL-grensesnittdokument + XUL-interface-document + XUL-grensesnitt-dokument + Dokument interfejsu XUL + Documento de interface XUL + Document interfață XUL + документ интерфейÑа XUL + Dokument rozhrania XUL + Dokument vmesnika XUL + Dokument interfaqe XUL + XUL-gränssnittsdokument + XUL arayüz belgesi + документ інтерфейÑу XUL + Tài liệu giao diện XUL + XUL ç•Œé¢æ–‡æ¡£ + XUL 介é¢æ–‡ä»¶ + XUL + XML User interface markup Language + + + + + + + XPInstall installer module + وحدة مثبت XPInstall + Пакет — инÑÑ‚Ð°Ð»Ð°Ñ†Ð¸Ñ XPInstall + mòdul instal·lador d'XPinstall + Modul instalátoru XPInstall + XPInstall-installationsmodul + XPInstall-Installermodul + XPInstall installer module + módulo del instalador XPInstall + XPInstall instalatzailearen modulua + XPInstall-asennuspaketti + XPInstall innleggjaramótul + module d'installation XPInstall + modúl suiteála XPInstall + Módulo do instalador XPInstall + מודול התקנה של XPInstall + XPInstall telepítÅ‘modul + Modul installer XPInstall + Modulo installatore XPInstall + XPInstall インストーラモジュール + XPInstall орнату модулі + XPInstall 설치 프로그램 모듈 + XPInstall įdiegiklio modulis + XPInstall instalatora modulis + XPInstall installeer module + ModuÅ‚ instalatora XPInstall + Módulo de instalador XPInstall + Modul de instalare XPInstall + модуль уÑтановщика XPInstall + Modul inÅ¡talátora XPInstall + modul namestilnika XPInstall + XPInstall-installeringsmodul + модуль заÑобу вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ XPInstall + XPInstall å®‰è£…å·¥å…·æ¨¡å— + XPInstall 安è£ç¨‹å¼æ¨¡çµ„ + + + + + Word 2007 document + مستند Word 2007 + Документ — Word 2007 + document de Word 2007 + Dokument Word 2007 + Word 2007-dokument + Word-2007-Dokument + έγγÏαφο Word 2007 + Word 2007 document + documento de Word 2007 + Word 2007 dokumentua + Word 2007 -asiakirja + Word 2007 skjal + document Word 2007 + cáipéis Word 2007 + documento de Word 2007 + מסמך Word 2007 + Word 2007 dokument + Word 2007 dokumentum + Dokumen Word 2007 + Documento Word 2007 + Word 2007 ドキュメント + Word 2007 құжаты + 워드 2007 문서 + Word 2007 dokumentas + Word 2007 dokuments + Word 2007-document + Dokument Word 2007 + Documento do Word 2007 + Document Word 2007 + документ Word 2007 + Dokument Word 2007 + Dokument Word 2007 + Word 2007-dokument + документ Word 2007 + Tài liệu Word 2007 + Microsoft Word 2007 文档 + Word 2007 文件 + + + + + + Word 2007 document template + Шаблон за документи — Word 2007 + plantilla de document de Word 2007 + Å ablona dokumentu Word 2007 + Word 2007-dokumentskabelon + Word 2007-Dokumentvorlage + Ï€Ïότυπο έγγÏαφο Word 2007 + Word 2007 document template + Plantilla de documento de Word 2007 + Word 2007 -asiakirjamalli + modèle de document Word 2007 + Plantilla de documento de Word 2007 + תבנית מסמך של Word 2007 + Word 2007 predložak dokumenta + Word 2007 dokumentumsablon + Templat dokumen Word 2007 + Modello documento Word 2007 + Word 2007 文書テンプレート + Word 2007-ის დáƒáƒ™áƒ£áƒ›áƒ”ნტის შáƒáƒ‘ლáƒáƒœáƒ˜ + Word 2007 құжатының үлгіÑÑ– + 워드 2007 문서 ì„œì‹ + Word 2007 dokumenta veidne + Word 2007 document sjabloon + Szablon dokumentu Word 2007 + Modelo de documento do Word 2007 + шаблон документа Word 2007 + Predloga dokumenta Word 2007 + Word 2007-dokumentmall + шаблон документа Word 2007 + Word 2007 æ–‡æ¡£æ¨¡æ¿ + Word 2007 文件範本 + + + + + + PowerPoint 2007 presentation + عرض تقديمي PowerPoint 2007 + ÐŸÑ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ â€” PowerPoint 2007 + presentació de PowerPoint 2007 + Prezentace PowerPoint 2007 + PowerPoint 2007-præsentation + PowerPoint-2007-Präsentation + παÏουσίαση PowerPoint 2007 + PowerPoint 2007 presentation + presentación de PowerPoint 2007 + PowerPoint 2007 aurkezpena + PowerPoint 2007 -esitys + PowerPoint 2007 framløga + présentation PowerPoint 2007 + láithreoireacht PowerPoint 2007 + presentación de PowerPoint 2007 + מצגת של PowerPoint 2007 + PowerPoint 2007 prezentacija + PowerPoint 2007 prezentáció + Presentasi PowerPoint 2007 + Presentazione standard PowerPoint 2007 + PowerPoint 2007 プレゼンテーション + PowerPoint 2007 презентациÑÑÑ‹ + 파워í¬ì¸íŠ¸ 2007 프리젠테ì´ì…˜ + PowerPoint 2007 pateiktis + PowerPoint 2007 prezentÄcija + PowerPoint 2007-presentatie + Prezentacja PowerPoint 2007 + Apresentação do PowerPoint 2007 + Prezentare PowerPoint 2007 + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ PowerPoint 2007 + Prezentácia PowerPoint 2007 + Predstavitev Microsoft PowerPoint 2007 + PowerPoint 2007-presentation + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ PowerPoint 2007 + Trình diá»…n PowerPoint 2007 + Microsoft PowerPoint 2007 演示文稿 + PowerPoint 2007 ç°¡å ± + + + + + + PowerPoint 2007 slide + Кадър — PoerPoint 2007 + dispositiva de PowerPoint 2007 + Snímek PowerPoint 2007 + PowerPoint 2007-slide + PowerPoint 2007-Folie + σλάιντ PowerPoint 2007 + PowerPoint 2007 slide + Diapositiva de PowerPoint 2007 + diapositive PowerPoint 2007 + Diaporama de PowerPoint 2007 + שקופית של PowerPoint 2007 + PowerPoint 2007 slajd + PowerPoint 2007 dia + Slide PowerPoint 2007 + Diapositiva PowerPoint 2007 + PowerPoint 2007 スライド + PowerPoint 2007-ის სლáƒáƒ˜áƒ“ი + PowerPoint 2007 Ñлайды + 파워í¬ì¸íŠ¸ 2007 슬ë¼ì´ë“œ + PowerPoint 2007 slaids + PowerPoint 2007 dia + Slajd PowerPoint 2007 + Slide do PowerPoint 2007 + Ñлайд PowerPoint 2007 + Prosojnica PowerPoint 2007 + Ñлайд PowerPoint 2007 + PowerPoint 2007 文稿 + PowerPoint 2007 投影片 + + + + + + PowerPoint 2007 show + عرض PowerPoint 2007 + ПрезентациÑ-шоу — PowerPoint 2007 + exposició de PowerPoint 2007 + Prezentace PowerPoint 2007 + PowerPoint 2007-dias + PowerPoint-2007-Präsentation + σόου PowerPoint 2007 + PowerPoint 2007 show + exposición de PowerPoint 2007 + PowerPoint 2007 ikuskizuna + PowerPoint 2007 -diaesitys + PowerPoint 2007 framsýning + diaporama PowerPoint 2007 + taispeántas PowerPoint 2007 + Exposición de PowerPoint 2007 + תצוגה של PowerPoint 2007 + PowerPoint 2007 prezentacija + PowerPoint 2007 bemutató + Presentasi PowerPoint 2007 + Solo presentazione PowerPoint 2007 + PowerPoint 2007 プレゼンテーション + PowerPoint 2007 көрÑетілімі + 파워í¬ì¸íŠ¸ 2007 쇼 + PowerPoint 2007 pateiktis + PowerPoint 2007 slÄ«drÄde + PowerPoint 2007 show + Pokaz PowerPoint 2007 + Apresentação do PowerPoint 2007 + Prezentare PowerPoint 2007 + Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ PowerPoint 2007 + Ukážka PowerPoint 2007 + Zagonska predstavitev PowerPoint 2007 + PowerPoint 2007-visning + показ Ñлайдів PowerPoint 2007 + Microsoft PowerPoint 2007 演示文稿 + PowerPoint 2007 展示 + + + + + + PowerPoint 2007 presentation template + Шаблон за презентации — PowerPoint 2007 + plantilla de presentació de PowerPoint 2007 + Å ablona prezentace PowerPoint 2007 + PowerPoint 2007-præsentationsskabelon + PowerPoint 2007-Präsentationsvorlage + Ï€Ïότυπο παÏουσίασης PowerPoint 2007 + PowerPoint 2007 presentation template + Plantilla de presentación de PowerPoint 2007 + PowerPoint 2007 -esitysmalli + modèle de présentation PowerPoint 2007 + modelo de presentación de PowerPoint 2007 + תבנית למצגת של PowerPoint 2007 + PowerPoint 2007 predložak prezentacije + PowerPoint 2007 bemutatósablon + Templat presentasi PowerPoint 2007 + Modello presentazione PowerPoint 2007 + PowerPoint 2007 プレゼンテーションテンプレート + PowerPoint 2007-ის პრეზენტáƒáƒªáƒ˜áƒ˜áƒ¡ შáƒáƒ‘ლáƒáƒœáƒ˜ + PowerPoint 2007 Ð¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ñ‹ + 파워í¬ì¸íŠ¸ 2007 프리젠테ì´ì…˜ ì„œì‹ + PowerPoint 2007 prezentÄcijas veidne + PowerPoint 2007 presentation sjabloon + Szablon prezentacji PowerPoint 2007 + Modelo de apresentação do PowerPoint 2007 + шаблон презентации PowerPoint 2007 + Predloga predstavitve PowerPoint 2007 + PowerPoint 2007-presentationsmall + шаблон презентації PowerPoint 2007 + PowerPoint 2007 æ¼”ç¤ºæ–‡ç¨¿æ¨¡æ¿ + PowerPoint 2007 簡報範本 + + + + + + Excel 2007 spreadsheet + جدول Excel 2007 + Таблица — Excel 2007 + full de càlcul d'Excel 2007 + SeÅ¡it Excel 2007 + Excel 2007-regneark + Excel-2007-Tabelle + φÏλλο εÏγασίας Excel 2007 + Excel 2007 spreadsheet + hoja de cálculo de Excel 2007 + Excel 2007 kalkulu-orria + Excel 2007 -taulukko + Excel 2007 rokniark + feuille de calcul Excel 2007 + scarbhileog Excel 2007 + folla de cálculo de Excel 2007 + גליון × ×ª×•× ×™× ×©×œ ×קסל 2007 + Excel 2007 proraÄunska tablica + Excel 2007 táblázat + Lembar sebar Excel 2007 + Foglio di calcolo Excel 2007 + Excel 2007 スプレッドシート + Excel 2007-ის ცხრილი + Excel 2007 Ñлектрондық кеÑтеÑÑ– + ì—‘ì…€ 2007 스프레드시트 + Excel 2007 skaiÄialentÄ— + Excel 2007 izklÄjlapa + Excel 2007-rekenblad + Arkusz Excel 2007 + Planilha do Excel 2007 + Foaie de calcul Excel 2007 + ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° Excel 2007 + ZoÅ¡it Excel 2007 + Razpredelnica Microsoft Excel 2007 + Excel 2007-kalkylblad + ел. Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Excel 2007 + Bảng tính Excel 2007 + Microsoft Excel 2007 工作簿 + Excel 2007 試算表 + + + + + + Excel 2007 spreadsheet template + Шаблон за таблици — Excel 2007 + plantilla de full de càlcul d'Excel 2007 + Å ablona seÅ¡itu Excel 2007 + Excel 2007-regnearksskabelon + Excel 2007-Datenblattvorlage + Ï€Ïότυπο φÏλλου εÏγασίας Excel 2007 + Excel 2007 spreadsheet template + Plantilla de hoja de cálculo Excel 2007 + Excel 2007 -taulukkomalli + modèle de feuille de calcul Excel 2007 + modelo de folla de cálculo Excel 2007 + תבנית של גיליון × ×ª×•× ×™× ×©×œ Excel 2007 + Excel 2007 predložak proraÄunske tablice + Excel 2007 táblázatsablon + Templat lembar kerja Excel 2007 + Modello foglio di calcolo Excel 2007 + Excel 2007 スプレッドシートテンプレート + Excel 2007-ის ცხრილის შáƒáƒ‘ლáƒáƒœáƒ˜ + Excel 2007 кеÑте шаблоны + ì—‘ì…€ 2007 스프레드쉬트 + Excel 2007 izklÄjlapas veidne + Excel 2007 spreadsheet sjabloon + Szablon arkusza Excel 2007 + Modelo de planilha do Excel 2007 + шаблон Ñлектронной таблицы Excel 2007 + Predloga razpredelnice Excel 2007 + Excel 2007-kalkylarksmall + шаблон електронної таблиці Excel 2007 + Excel 2007 å·¥ä½œè¡¨æ¨¡æ¿ + Excel 2007 試算表範本 + + + + + + T602 document + مستند T602 + Dakument T602 + Документ — T602 + document T602 + Dokument T602 + T602-dokument + T602-Dokument + αÏχείο T602 + T602 document + T602-dokumento + documento T602 + T602 dokumentua + T602-asiakirja + T602 skjal + document T602 + cáipéis T602 + documento T602 + מסמך T602 + T602 dokument + T602 dokumentum + Dokumen T602 + Documento T602 + T602 ドキュメント + T602 құжаты + T602 문서 + T602 dokumentas + T602 dokuments + T602-dokument + T602-document + T602-dokument + Dokument T602 + Documento T602 + Document T602 + документ T602 + Dokument T602 + Dokument T602 + Dokument T602 + T602-dokument + документ T602 + Tài liệu T602 + T602 文档 + T602 文件 + + + + + + + + + + Cisco VPN Settings + إعدادات Cisco VPN + NaÅ‚ady Cisco VPN + ÐаÑтройки — ВЧМ на Cisco + paràmetres VPN de Cisco + Nastavení Cisco VPN + Cisco VPN-opsætning + Cisco-VPN-Einstellungen + Ïυθμίσεις Cisco VPN + Cisco VPN Settings + configuración VPN de Cisco + Cisco VPN ezarpenak + Cisco VPN -asetukset + Cisco VPN stillingar + paramètres VPN Cisco + socruithe VPN Cisco + configuracións de VPN de Cisco + הגדרות של Cisco VPN + Cisco VPN postavke + Cisco VPN beállítások + Penataan Cisco VPN + Impostazioni VPN Cisco + Cisco VPN 設定 + Cisco VPN-ის პáƒáƒ áƒáƒ›áƒ”ტრები + Cisco VPN баптаулары + Cisco VPN 설정 + Cisco VPN parametrai + Cisco VPN iestatÄ«jumi + Cisco VPN-innstillinger + Cisco VPN-instellingen + Cisco VPN-innstillingar + Ustawienia VPN Cisco + Configurações de VPN da Cisco + Configurări VPN Cisco + файл наÑтроек Cisco VPN + Nastavenia Cisco VPN + Datoteka nastavitev Cisco VPN + Rregullime VPN Cisco + Cisco VPN-inställningar + параметри VPN Cisco + Thiết lập VPN Cisco + Cisco VPN 设置 + Cisco VPN 設定值 + + + + + + + + + + ICC profile + تشكيلة OCL + Цветови профил — OCL + perfil ICC + Profil ICC + ICC-profil + ICC-Profil + Ï€Ïοφίλ ICC + ICC profile + ICC-profilo + perfil ICC + ICC profila + ICC-profiili + ICC umhvarv + profil ICC + próifíl ICC + perfíl ICC + פרופיל ICC + ICC profil + ICC profil + Profil ICC + Profilo ICC + ICC プロファイル + ICC профайлы + ICC 프로필 + ICC profilis + ICC profils + ICC profiel + Profil ICC + Perfil ICC + Profil ICC + профиль ICC + Profil farieb ICC + Datoteka profila ICC + ICC-profil + профіль ICC + ICC 文件 + ICC 設定檔 + + + + + + + + IT 8.7 color calibration file + مل٠ضبط ألوان IT 8.7 + Файл за цветово калибриране — IT 8.7 + fitxer de calibratge de color IT 8.7 + Soubor kalibrace barev IT 8.7 + IT 8.7 farvekalibreringsfil + IT 8.7 Farbkalibrierungsdatei + αÏχείο ÏÏθμισης χÏώματος ΙΤ 8.7 + IT 8.7 color calibration file + archivo de calibración de color IT 8.7 + IT 8.7 kolore-kalibrazioaren fitxategia + IT 8.7 -värikalibrointitiedosto + IT 8.7 litstillingarfíla + fichier de calibration couleur IT 8.7 + comhad calabraithe dathanna IT 8.7 + ficheiro de calibración de cor IT 8.7 + קובץ כיול צבע IT 8.7 + IT 8.7 datoteka kalibracije boja + IT 8.7 színkalibrációs fájl + Berkas kalibrasi warna IT 8.7 + File calibrazione colore IT 8.7 + IT 8.7 カラーキャリブレーションファイル + IT 8.7 Ñ‚Ò¯Ñ Ð±Ð°Ð¿Ñ‚Ð°Ñƒ файлы + IT 8.7 색 조율 íŒŒì¼ + IT 8.7 spalvų kalibravimo failas + IT 8.7 krÄsu kalibrÄcijas datne + IT 8.7 kleurcalibratie bestand + Plik kalibracji kolorów IT 8.7 + Arquivo de calibração de cor IT 8.7 + FiÈ™ier de calibrare a culorii IT 8.7 + файл калибровки цвета IT 8.7 + Umeritvena datoteka barve IT 8.7 + IT 8.7-färgkalibreringsfil + файл ÐºÐ°Ð»Ñ–Ð±Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð»ÑŒÐ¾Ñ€Ñ–Ð² IT 8.7 + IT 8.7 色彩校准文件 + IT 8.7 色彩校正檔 + + + + + + + + + CCMX color correction file + + + + + + + + + WinHelp help file + + + + + + + + + + + digital photos + الصور الرقمية + liÄbavyja zdymki + Цифрови фотографии + fotos digitals + Digitální fotografie + digitale billeder + Digitale Fotos + ψηφιακές φωτογÏαφίες + digital photos + fotos digitales + argazki digitalak + digivalokuvia + talgildar myndir + photos numériques + grianghraif dhigiteacha + fotos dixitais + תמונות דיגיטליות + digitalne fotografije + digitális fényképek + foto digital + Foto digitali + デジタルフォト + Ñандық фотоÑуреттер + 디지털 사진 + skaitmeninÄ—s nuotraukos + digitÄla fotogrÄfija + digitale foto's + digitale fotografi + ZdjÄ™cia cyfrowe + Fotos digitais + fotografii digitale + цифровые фотографии + Digitálne fotografie + digitalne fotografije + Fotografi dixhitale + digitalbilder + цифрові фотографії + ảnh chụp số + æ•°å­—åŒ–å›¾åƒ + 數ä½ç›¸ç‰‡ + + + + + + + + Video CD + Video CD + Videa CD + CD — видео + Video CD + Video CD + Video-cd + Video-CD + Video CD + Video CD + Video-KD + Video CD + Bideo CDa + Video CD + Video CD + CD vidéo + Video CD + Video CD + תקליטור ויד×ו + Video CD + Video CD + Video CD + Video CD + ビデオ CD + видео CD + 비디오 CD + Vaizdo CD + Video CD + video-CD + Video-CD + Video CD + CD de vídeo + CD video + видеодиÑк VCD + Video CD + Video CD + CD Video + Video-cd + Video CD + ÄÄ©a CD ảnh Ä‘á»™ng + VCD + Video CD + + + + + + + + Super Video CD + Super Video CD + Super Video CD + CD — Ñупер видео + Super Video CD + Super Video CD + Super Video-cd + Super-Video-CD + Super Video CD + Super Video CD + Super-Video-KD + Super Video CD + Super Bideo CDa + Super Video CD + Super Video CD + Super VCD + Super Video CD + Super vídeo CD + Super Video CD + Super Video CD + Super Video CD + Super Video CD + Super Video CD + スーパービデオ CD + Super Video CD + ìˆ˜í¼ ë¹„ë””ì˜¤ CD + Super vaizdo CD + Super Video CD + super-video-CD + Super Video-CD + Super Video CD + CD de Super Vídeo (SVCD) + Super Video CD + компакт-диÑк Super Video + Super Video CD + Super Video CD + CD Super Video + Super Video CD + Super Video CD + ÄÄ©a CD siêu ảnh Ä‘á»™ng + SVCD + Super Video CD + + + + + + + + video DVD + DVD مرئي + videa DVD + DVD — видео + vídeo DVD + DVD-Video + video-dvd + Video-DVD + βίντεο DVD + video DVD + video-DVD + DVD de vídeo + bideo DVDa + video-DVD + video DVD + DVD vidéo + DVD físe + DVD de vídeo + DVD ויד×ו + video DVD + video DVD + DVD video + DVD video + ビデオ DVD + ვიდერDVD + видео DVD + 비디오 CD + vaizdo DVD + video DVD + video-DVD + Video-DVD + DVD-Video + DVD de vídeo + DVD video + видео-DVD + DVD-Video + video DVD + DVD video + video-dvd + відео-DVD + Ä‘Ä©a DVD ảnh Ä‘á»™ng + 视频 DVD + 視訊 DVD + + + + + + + + + + + audio CD + CD سمعي + aÅ­dyjo CD + CD — аудио + CD d'àudio + Zvukové CD + lyd-cd + Audio-CD + CD ήχου + audio CD + Son-KD + CD de sonido + Audio CDa + ääni-CD + audio CD + CD audio + dlúthdhiosca fuaime + CD de son + תקליטור שמע + hang CD + CD audio + CD audio + オーディオ CD + аудио CD + 오디오 CD + garso CD + audio CD + audio-CD + lyd-CD + CD-Audio + CD de áudio + CD audio + звуковой CD + Zvukové CD + zvoÄni CD + CD audio + ljud-cd + Müzik CD'si + звуковий CD + Ä‘Ä©a CD âm thanh + 音频 CD + 音訊 CD + + + + + blank CD disc + قرص CD Ùارغ + Äysty dysk CD + CD — празно + disc CD en blanc + Prázdný disk CD + tom cd-disk + Leere CD + κενό CD + blank CD disc + disco CD virgen + CD disko hutsa + tyhjä CD-levy + blonk fløga + CD vierge + dlúthdhiosca folamh + disco de CD en brancho + תקליטור ריק + üres CD-lemez + cakram CD kosong + Disco vuoto CD + ブランク CD ディスク + таза CD диÑкі + 빈 CD ë””ìŠ¤í¬ + tuÅ¡Äias CD diskas + tukÅ¡s CD disks + blanco CD + tom CD-plate + Pusta pÅ‚yta CD + Disco CD vazio + disc gol CD + чиÑтый компакт-диÑк + Prázdny disk CD + prazen CD disk + Disk bosh CD + tom cd-skiva + boÅŸ CD diski + порожній компакт-диÑк + Ä‘Ä©a CD trống + 空 CD 光盘 + 空白 CD 光碟 + + + + + blank DVD disc + قرص DVD Ùارغ + Äysty dysk DVD + DVD — празно + disc DVD en blanc + Prázdný disk DVD + tom dvd-disk + Leere DVD + κενό DVD + blank DVD disc + disco DVD virgen + DVD disko hutsa + tyhjä DVD-levy + blonk margfløga + DVD vierge + DVD folamh + disco de DVD en branco + תקליטור DVD ריק + üres DVD-lemez + cakram DVD kosong + Disco vuoto DVD + ブランク DVD ディスク + таза DVD диÑкі + 빈 DVD ë””ìŠ¤í¬ + tuÅ¡Äias DVD diskas + tukÅ¡s DVD disks + blanco DVD + tom DVD-plate + Pusta pÅ‚yta DVD + Disco DVD vazio + disc gol DVD + чиÑтый диÑк DVD + Prázdny disk DVD + prazen DVD disk + Disk bosh DVD + tom dvd-skiva + boÅŸ DVD diski + порожній диÑк DVD + Ä‘Ä©a DVD trống + 空 DVD 光盘 + 空白 DVD 光碟 + + + + + blank Blu-ray disc + قرص بلو-راي Ùارغ + Äysty dysk Blu-ray + Blu-ray — празно + disc Blu-Ray en blanc + Prázdný disk Blu-ray + tom Blu-ray-disk + Leeres Blu-Ray-Medium + κενό Blu-ray + blank Blu-ray disc + disco Blu-ray virgen + Blu-ray disko hutsa + tyhjä Blu-ray-levy + blankur Blu-ray diskur + disque Blu-Ray vierge + diosca folamh Blu-Ray + disco Blu-ray en branco + תקליטור בלו־ריי ריק + üres Blu-Ray lemez + cakram Blu-ray kosong + Disco vuoto Blu-ray + ブランク Blu-ray ディスク + таза Blu-ray диÑкі + 빈 ë¸”ë£¨ë ˆì´ ë””ìŠ¤í¬ + tuÅ¡Äias Blu-ray diskas + tukÅ¡s Blu-ray disks + blanco Blu-ray-disk + tom Blu-Ray-plate + Pusta pÅ‚yta Blu-ray + Disco Blu-ray vazio + disc gol Blu-ray + чиÑтый диÑк Blu-ray + Prázdny disk Blu-ray + prazen Blu-Ray disk + Disk bosh Blu-ray + tom Blu-ray-skiva + boÅŸ Blue-ray diski + порожній диÑк Blu-ray + Ä‘Ä©a Blu-ray trống + 空è“å…‰ DVD + 空白 Blu-ray 光碟 + + + + + blank HD DVD disc + قرص HD DVD Ùارغ + Äysty dysk HD DVD + HD DVD — празно + disc DVD HD en blanc + Prázdný disk HD DVD + tom HD dvd-disk + Leere HD-DVD + κενό HD DVD + blank HD DVD disc + disco HD DVD virgen + HD DVD disko hutsa + tyhjä HD DVD -levy + blankur HD DVD diskur + disque HD-DVD vierge + HD DVD folamh + disco de HD DVD en branco + דיסק HD DVD ריק + üres HD DVD-lemez + cakram HD DVD kosong + Disco vuoto DVD HD + ブランク HD DVD ディスク + таза HD DVD диÑкі + 빈 HD DVD ë””ìŠ¤í¬ + tuÅ¡Äias HD DVD diskas + tukÅ¡s HD DVD disks + blanco HD-DVD + tom HD-DVD-plate + Pusta pÅ‚yta HD DVD + Disco DVD HD vazio + disc gol HD DVD + чиÑтый диÑк HD DVD + Prázdny disk HD DVD + prazen HD DVD disk + Disk bosh DVD HD + tom HD DVD-skiva + boÅŸ HD DVD diski + порожній диÑк HD DVD + Ä‘Ä©a DVD HD trống + 空 HD DVD 光盘 + 空白 HD DVD 光碟 + + + + + audio DVD + DVD سمعي + aÅ­dyjo DVD + DVD — аудио + DVD d'àudio + Zvukové DVD + lyd-dvd + Audio-DVD + DVD ήχου + audio DVD + Son-DVD + DVD de sonido + audio DVDa + ääni-DVD + Ljóð DVD + DVD audio + DVD fuaime + DVD de son + DVD שמע + hang DVD + DVD audio + DVD audio + オーディオ DVD + аудио DVD + 오디오 DVD + garso DVD + audio DVD + audio-DVD + lyd-DVD + DVD-Audio + DVD de áudio + DVD audio + звуковой DVD + Zvukové DVD + zvoÄni DVD + DVD audio + ljud-dvd + Müzik DVD'si + звуковий DVD + Ä‘Ä©a DVD âm thanh + 音频 DVD + 音訊 DVD + + + + + + + + + Blu-ray video disc + قرص بلو-راي مرئي + Videadysk Blu-ray + Blu-ray — видео + disc de vídeo Blu-Ray + Videodisk Blu-ray + Blu-ray video-disk + Blu-ray-Videoscheibe + δίσκος βίντεο Blu-ray + Blu-ray video disc + disco de vídeo Blu-ray + Blu-ray bideo-diskoa + Blu-ray-videolevy + Blu-ray diskur + disque vidéo Blu-Ray + diosca físe Blu-Ray + disco de vídeo Blu-ray + תקליטור ויד×ו מסוג בלו־ריי + Blu-ray video disk + Blu-ray videolemez + Cakram video Blu-ray + Disco video Blu-ray + Blu-ray ビデオディスク + Blu-ray ვიდერდისკი + Blu-ray видео диÑкі + ë¸”ë£¨ë ˆì´ ë¹„ë””ì˜¤ ë””ìŠ¤í¬ + Blu-ray vaizdo diskas + Blu-ray video disks + Blu-ray-videodisk + Blu-Ray videoplate + PÅ‚yta wideo Blu-ray + Disco de vídeo Blu-ray + Disc video Blu-ray + видеодиÑк Blu-ray + Videodisk Blu-ray + Blu-ray video disk + Disk video Blu-ray + Blu-ray-videoskiva + відеодиÑк Blu-ray + ÄÄ©a ảnh Ä‘á»™ng Blu-ray + è“光视频光盘 + Blu-ray 視訊光碟 + + + + + + + + + HD DVD video disc + قرص HD DVD مرئي + Videadysk HD DVD + HD DVD — видео + disc de vídeo DVD HD + Videodisk HD DVD + HD DVD-videodisk + HD-DVD-Videoscheibe + δίσκος βίντεο HD DVD + HD DVD video disc + disco de vídeo HD DVD + HD DVD bideo-diskoa + HD DVD -videolevy + HD DVD video diskur + disque vidéo HD DVD + diosca físe HD DVD + disco de vídeo HD DVD + תקליטור ויד×ו HD DVD + HD DVD video disk + HD DVD videolemez + Cakram video HD DVD + Disco video DVD HD + HD DVD ビデオディスク + HD DVD видео диÑкі + HD DVD 비디오 ë””ìŠ¤í¬ + HD DVD vaizdo diskas + HD DVD video disks + HD-DVD-videodisk + HD-DVD-videodisk + PÅ‚yta wideo HD DVD + Disco de vídeo HD DVD + Disc video HD DVD + видеодиÑк HD DVD + Videodisk HD DVD + HD DVD video disk + Disk video DVD HD + HD DVD-videoskiva + відеодиÑк HD DVD + ÄÄ©a ảnh Ä‘á»™ng DVD HD + HD DVD 视频光盘 + HD DVD 視訊光碟 + + + + + + + + + + e-book reader + Четец на е-книги + lector de llibres electrònics + ÄŒteÄka elektronických knih + e-bogslæser + E-Book-Leser + αναγνώστης ηλεκτÏονικών βιβλίων + e-book reader + lector de libros electrónicos + e-kirjan lukulaite + lecteur de livre numérique + lector de libros electrónicos + ×§×•×¨× ×¡×¤×¨×™× ××œ×§×˜×¨×•× ×™×™× + ÄitaÄ e-knjiga + e-könyvolvasó + Pembaca e-book + Lettore e-book + é›»å­æ›¸ç±ãƒªãƒ¼ãƒ€ãƒ¼ + Ñлектронды кітаптарды оқу құрылғыÑÑ‹ + ì „ìžì±… ë¦¬ë” + e-grÄmatu lasÄ«tÄjs + e-book reader + Czytnik e-booków + Leitor de e-book + уÑтройÑтво Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ñлектронных книг + Bralnik elektronskih knjig + e-book-läsare + e-kitap okuyucu + приÑтрій Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¸Ñ… книг + 电å­ä¹¦é˜…读器 + e-book 閱讀器 + + + + + + + + Picture CD + Picture CD + Picture CD + CD — Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ + Picture CD + Picture CD + Billedcd + Bild-CD + CD εικόνων + Picture CD + Picture CD + Picture CD + Picture CD + Picture CD + CD Picture + Picture CD + Picture CD + תקליטור תמונות + Picture CD + CD Gambar + Picture CD + ピクãƒãƒ£ãƒ¼ CD + Picture CD + Picture CD + PaveikslÄ—lių CD + AttÄ“lu CD + foto-CD + Bilete-CD + Picture CD + CD de Fotos + CD cu fotografii + Picture CD + Picture CD + Slikovni CD + Picture CD + Picture CD + Resim CD'si + CD з зображеннÑми + ÄÄ©a CD ảnh + 柯达 Picture CD + 圖片 CD + + + + + + + + portable audio player + مشغل الملÙات المسموعة المحمولة + pieranosny aÅ­dyjoplayer + ПреноÑим аудио плеър + reproductor d'àudio portàtil + PÅ™enosný zvukový pÅ™ehrávaÄ + bærbar lydafspiller + Portables Audio-Wiedergabegerät + φοÏητός αναπαÏαγωγέας μουσικής + portable audio player + dispositivo de sonido portable + audio erreproduzigailu eramangarria + siirrettävä äänisoitin + leysur ljóðavspælari + lecteur audio portable + seinnteoir iniompartha fuaime + dispositivo de son portábel + נגן מוזיקה נייד + prenosivi audio sviraÄ + hordozható zenelejátszó + pemutar audio portable + Lettore audio portabile + ãƒãƒ¼ã‚¿ãƒ–ルオーディオプレイヤー + таÑымалы аудио плеер + 휴대용 오디오 플레ì´ì–´ + neÅ¡iojamasis garso leistuvas + portatÄ«vais audio atskaņotÄjs + draagbare audiospeler + portable audio layer + PrzenoÅ›ny odtwarzacz dźwiÄ™ku + Reprodutor de áudio portátil + player audio portabil + портативный аудиопроигрыватель + Prenosný hudobný prehrávaÄ + prenosni predvajalnik zvoka + Lexues audio portativ + bärbar ljudspelare + портативний аудіопрогравач + bá»™ phát nhạc di Ä‘á»™ng + 便æºå¼éŸ³é¢‘播放器 + å¯æ”œå¼éŸ³è¨Šæ’­æ”¾ç¨‹å¼ + + + + + software + برنامج + prahrama + Софтуер + programari + Software + software + Software + λογισμικό + software + software + softwarea + ohjelmisto + ritbúnaður + logiciel + bogearraí + software + תכנה + softver + szoftver + peranti lunak + Software + ソフトウェア + პრáƒáƒ’რáƒáƒ›áƒ£áƒšáƒ˜ უზრუნველყáƒáƒ¤áƒ + бағдарламалық қамтама + 소프트웨어 + programinÄ— įranga + programmatÅ«ra + software + programvare + Oprogramowanie + Aplicativo + software + программное обеÑпечение + Softvér + programska oprema + Software + programvara + програмне Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ + phần má»m + 软件 + 軟體 + + + + + UNIX software + برنامج يونكس + Софтуер за UNIX + programari UNIX + Software UNIX + UNIX-programmer + UNIX Software + λογισμικό UNIX + UNIX software + software de UNIX + UNIXeko softwarea + UNIX-ohjelmisto + UNIX ritbúnaður + logiciel UNIX + bogearraí UNIX + Software de UNIX + תוכנת UNIX + UNIX softver + UNIX-szoftver + Peranti lunak UNIX + Software UNIX + UNIX ソフトウェア + UNIX бағдарламаÑÑ‹ + UNIX 소프트웨어 + UNIX programinÄ— įranga + UNIX programmatÅ«ra + UNIX software + Oprogramowanie systemu UNIX + Software UNIX + Software UNIX + программа UNIX + Softvér UNIX + Programska datoteka UNIX + UNIX-programvara + UNIX yazılımı + програмне Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ UNIX + UNIX 软件 + UNIX 軟體 + + + + + + + + + + + Windows software + برنامج ويندوز + Софтуер — Windows + programari de Windows + Software Windows + Windowsprogram + Windows-Software + λογισμικό Windows + Windows software + software de Windows + Windows-eko softwarea + Windows-ohjelmisto + Windows ritbúnaður + logiciel Windows + bogearraí Windows + Software de Windows + תוכנה לWindows + Windows softver + Windows-szoftver + Piranti lunak Windows + Software Windows + Windows ソフトウェア + Windows бағдарламаÑÑ‹ + Windows 소프트웨어 + Windows programinÄ— įranga + Windows programmatÅ«ra + Windows software + Oprogramowanie systemu Windows + Programa do Windows + Software Windows + программа Windows + Softvér Windows + Programska oprema za okolje Windows + Windows-program + програмне Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Windows + Windows 软件 + Windows 軟體 + + + + + + + + + + TriG RDF document + TriG + TriG RDF Graph Triple Language + + + + + \ No newline at end of file diff --git a/Telegram/SourceFiles/settings.cpp b/Telegram/SourceFiles/settings.cpp new file mode 100644 index 000000000..97bc10f08 --- /dev/null +++ b/Telegram/SourceFiles/settings.cpp @@ -0,0 +1,106 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "pspecific.h" +#include "settings.h" + +bool gTestMode = false; +bool gDebug = false; +bool gManyInstance = false; +QString gKeyFile; +QString gWorkingDir, gExeDir; + +QString gDialogLastPath, gDialogHelperPath; // optimize QFileDialog + +bool gSoundNotify = true; +bool gDesktopNotify = true; +bool gStartMinimized = false; +bool gAutoStart = false; +bool gAutoUpdate = true; +TWindowPos gWindowPos; +bool gFromAutoStart = false; +DBIWorkMode gWorkMode = dbiwmWindowAndTray; +DBIConnectionType gConnectionType = dbictAuto; +ConnectionProxy gConnectionProxy; +bool gSeenTrayTooltip = false; +bool gRestartingUpdate = false, gRestarting = false; +int32 gLastUpdateCheck = 0; +bool gNoStartUpdate = false; +bool gStartToSettings = false; +int32 gMaxGroupCount = 200; +DBIDefaultAttach gDefaultAttach = dbidaDocument; +bool gReplaceEmojis = true; +bool gAskDownloadPath = false; +QString gDownloadPath; + +bool gNeedConfigResave = false; + +bool gCtrlEnter = false; +bool gCatsAndDogs = true; + +uint32 gConnectionsInSession = 1; +QString gLoggedPhoneNumber; + +QByteArray gLocalSalt; +DBIScale gRealScale = dbisAuto, gScreenScale = dbisOne, gConfigScale = dbisAuto; + +DBIEmojiTab gEmojiTab = dbietPeople; +RecentEmojiPack gRecentEmojis; +RecentEmojiPreload gRecentEmojisPreload; + +QString gLangFile; + +void settingsParseArgs(int argc, char *argv[]) { + gExeDir = psCurrentExeDirectory(); + for (uint32 i = 0; i < argc; ++i) { + if (string("-release") == argv[i]) { + gTestMode = false; + } else if (string("-debug") == argv[i]) { + gDebug = true; + } else if (string("-many") == argv[i]) { + gManyInstance = true; + } else if (string("-key") == argv[i] && i + 1 < argc) { + gKeyFile = QString(argv[i + 1]); + } else if (string("-autostart") == argv[i]) { + gFromAutoStart = true; + } else if (string("-noupdate") == argv[i]) { + gNoStartUpdate = true; + } else if (string("-tosettings") == argv[i]) { + gStartToSettings = true; + } else if (string("-lang") == argv[i] && i + 1 < argc) { + gLangFile = QString(argv[i + 1]); + } + } +} + +const RecentEmojiPack &cGetRecentEmojis() { + if (cRecentEmojis().isEmpty() && !cRecentEmojisPreload().isEmpty()) { + RecentEmojiPreload p(cRecentEmojisPreload()); + cSetRecentEmojisPreload(RecentEmojiPreload()); + RecentEmojiPack r; + r.reserve(p.size()); + for (RecentEmojiPreload::const_iterator i = p.cbegin(), e = p.cend(); i != e; ++i) { + EmojiPtr ep(getEmoji(i->first)); + if (ep) { + r.push_back(qMakePair(ep, i->second)); + } + } + cSetRecentEmojis(r); + } + return cRecentEmojis(); +} diff --git a/Telegram/SourceFiles/settings.h b/Telegram/SourceFiles/settings.h new file mode 100644 index 000000000..ebb40f905 --- /dev/null +++ b/Telegram/SourceFiles/settings.h @@ -0,0 +1,133 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +extern bool gDebug; +inline bool cDebug() { +#ifdef _DEBUG + return true; +#elif defined _WITH_DEBUG + return gDebug; +#else + return false; +#endif +} +inline void cSetDebug(bool debug) { + gDebug = debug; +} + +extern bool gTestMode; +inline bool cTestMode() { +#ifdef _DEBUG + return gTestMode; +#else + return false; +#endif +} + +#define DeclareReadSetting(Type, Name) extern Type g##Name; \ +inline const Type &c##Name() { \ + return g##Name; \ +} + +#define DeclareSetting(Type, Name) DeclareReadSetting(Type, Name) \ +inline void cSet##Name(const Type &Name) { \ + g##Name = Name; \ +} + +DeclareSetting(QString, LoggedPhoneNumber); +DeclareReadSetting(uint32, ConnectionsInSession); +DeclareSetting(bool, AutoStart); +DeclareSetting(bool, StartMinimized); +DeclareReadSetting(bool, FromAutoStart); +DeclareSetting(QString, WorkingDir); +inline void cForceWorkingDir(const QString &newDir) { + cSetWorkingDir(newDir); + QDir dir; + dir.mkpath(gWorkingDir); +} +DeclareReadSetting(QString, ExeDir); +DeclareSetting(QString, DialogLastPath); +DeclareSetting(QString, DialogHelperPath); +inline const QString &cDialogHelperPathFinal() { + return cDialogHelperPath().isEmpty() ? cExeDir() : cDialogHelperPath(); +} +DeclareSetting(bool, CtrlEnter); +DeclareSetting(bool, CatsAndDogs); +DeclareSetting(bool, SoundNotify); +DeclareSetting(bool, NeedConfigResave); +DeclareSetting(bool, DesktopNotify); +DeclareSetting(bool, AutoUpdate); + +struct TWindowPos { + TWindowPos() : moncrc(0), maximized(0), x(0), y(0), w(0), h(0) { + } + int32 moncrc, maximized; + int32 x, y, w, h; +}; +DeclareSetting(TWindowPos, WindowPos); +DeclareSetting(DBIWorkMode, WorkMode); +DeclareSetting(DBIConnectionType, ConnectionType); +DeclareSetting(DBIDefaultAttach, DefaultAttach); +DeclareSetting(ConnectionProxy, ConnectionProxy); +DeclareSetting(bool, SeenTrayTooltip); +DeclareSetting(bool, RestartingUpdate); +DeclareSetting(bool, Restarting); +DeclareSetting(int32, LastUpdateCheck); +DeclareSetting(bool, NoStartUpdate); +DeclareSetting(bool, StartToSettings); +DeclareSetting(int32, MaxGroupCount); +DeclareSetting(bool, ReplaceEmojis); +DeclareReadSetting(bool, ManyInstance); +DeclareSetting(bool, AskDownloadPath); +DeclareSetting(QString, DownloadPath); +DeclareSetting(QByteArray, LocalSalt); +DeclareSetting(DBIScale, RealScale); +DeclareSetting(DBIScale, ScreenScale); +DeclareSetting(DBIScale, ConfigScale); + +inline DBIScale cEvalScale(DBIScale scale) { + return (scale == dbisAuto) ? cScreenScale() : scale; +} +inline DBIScale cScale() { + return cEvalScale(cRealScale()); +} + +DeclareSetting(DBIEmojiTab, EmojiTab); + +struct EmojiData { + EmojiData(int32 x, int32 y, uint32 code, uint32 code2, int32 len) : x(x), y(y), code(code), code2(code2), len(len) { + } + int32 x, y; + uint32 code, code2; + int32 len; +}; + +typedef const EmojiData *EmojiPtr; + +typedef QVector EmojiPack; +typedef QVector > RecentEmojiPreload; +typedef QVector > RecentEmojiPack; +DeclareSetting(RecentEmojiPack, RecentEmojis); +DeclareSetting(RecentEmojiPreload, RecentEmojisPreload); + +const RecentEmojiPack &cGetRecentEmojis(); + +DeclareReadSetting(QString, LangFile); + +void settingsParseArgs(int argc, char *argv[]); diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp new file mode 100644 index 000000000..4823d7a62 --- /dev/null +++ b/Telegram/SourceFiles/settingswidget.cpp @@ -0,0 +1,1168 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" +#include "lang.h" + +#include "settingswidget.h" +#include "mainwidget.h" +#include "application.h" +#include "boxes/photocropbox.h" +#include "boxes/connectionbox.h" +#include "boxes/addcontactbox.h" +#include "boxes/emojibox.h" +#include "boxes/confirmbox.h" +#include "boxes/downloadpathbox.h" +#include "gui/filedialog.h" + +Slider::Slider(QWidget *parent, const style::slider &st, int32 count, int32 sel) : QWidget(parent), +_count(count), _sel(snap(sel, 0, _count)), _wasSel(_sel), _st(st), _pressed(false) { + resize(_st.width, _st.bar.height()); + setCursor(style::cur_pointer); +} + +void Slider::mousePressEvent(QMouseEvent *e) { + _pressed = true; + mouseMoveEvent(e); +} + +void Slider::mouseMoveEvent(QMouseEvent *e) { + if (_pressed) { + int32 newSel = snap(qRound((_count - 1) * float64(e->pos().x() - _st.bar.width() / 2) / (width() - _st.bar.width())), 0, _count - 1); + if (newSel != _sel) { + _sel = newSel; + update(); + } + } +} + +void Slider::mouseReleaseEvent(QMouseEvent *e) { + _pressed = false; + if (_sel != _wasSel) { + emit changed(_wasSel); + _wasSel = _sel; + } +} + +int32 Slider::selected() const { + return _sel; +} + +void Slider::setSelected(int32 sel) { + if (_sel != sel) { + _sel = sel; + emit changed(_wasSel); + _wasSel = _sel; + update(); + } +} + +void Slider::paintEvent(QPaintEvent *e) { + QPainter p(this); + + p.setPen(_st.color->p); + int32 from = (height() - _st.thikness) / 2, to = from + _st.thikness; + for (int32 i = from; i < to; ++i) { + p.drawLine(0, i, width() - 1, i); + } + + int32 x = qFloor(_sel * float64(width() - _st.bar.width()) / (_count - 1)), y = (height() - _st.bar.height()) / 2; + p.drawPixmap(QPoint(x, y), App::sprite(), _st.bar); +} + +QString scaleLabel(DBIScale scale) { + switch (scale) { + case dbisOne: return qsl("100%"); + case dbisOneAndQuarter: return qsl("125%"); + case dbisOneAndHalf: return qsl("150%"); + case dbisTwo: return qsl("200%"); + } + return QString(); +} + +bool scaleIs(DBIScale scale) { + return cRealScale() == scale || cRealScale() == dbisAuto && cScreenScale() == scale; +} + +SettingsInner::SettingsInner(Settings *parent) : QWidget(parent), + _self(App::self()), + + // profile + _phoneText(_self ? App::formatPhone(_self->phone) : QString()), + _uploadPhoto(this, lang(lng_settings_upload), st::btnSetUpload), + _cancelPhoto(this, lang(lng_cancel)), + _nameOver(false), _photoOver(false), a_photo(0), _nameCache(_self ? _self->name : QString()), + + // notifications + _desktopNotify(this, lang(lng_settings_desktop_notify), cDesktopNotify()), + _soundNotify(this, lang(lng_settings_sound_notify), cSoundNotify()), + + // general + _autoUpdate(this, lang(lng_settings_auto_update), cAutoUpdate()), + _checkNow(this, lang(lng_settings_check_now)), + _restartNow(this, lang(lng_settings_update_now)), + + _workmodeTray(this, lang(lng_settings_workmode_tray), (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray)), + _workmodeWindow(this, lang(lng_settings_workmode_window), (cWorkMode() == dbiwmWindowOnly || cWorkMode() == dbiwmWindowAndTray)), + + _autoStart(this, lang(lng_settings_auto_start), cAutoStart()), + _startMinimized(this, lang(lng_settings_start_min), cStartMinimized()), + + _dpiAutoScale(this, lang(lng_settings_scale_auto).replace(qsl("{cur}"), scaleLabel(cScreenScale())), (cConfigScale() == dbisAuto)), + _dpiSlider(this, st::dpiSlider, dbisScaleCount - 1, cEvalScale(cConfigScale()) - 1), + _dpiWidth1(st::dpiFont1->m.width(scaleLabel(dbisOne))), + _dpiWidth2(st::dpiFont2->m.width(scaleLabel(dbisOneAndQuarter))), + _dpiWidth3(st::dpiFont3->m.width(scaleLabel(dbisOneAndHalf))), + _dpiWidth4(st::dpiFont4->m.width(scaleLabel(dbisTwo))), + + // chat options + _replaceEmojis(this, lang(lng_settings_replace_emojis), cReplaceEmojis()), + _viewEmojis(this, lang(lng_settings_view_emojis)), + + _enterSend(this, qsl("send_key"), 0, lang(lng_settings_send_enter), !cCtrlEnter()), + _ctrlEnterSend(this, qsl("send_key"), 1, lang(lng_settings_send_ctrlenter), cCtrlEnter()), + + _downloadPathWidth(st::linkFont->m.width(lang(lng_download_path_label))), + _dontAskDownloadPath(this, lang(lng_download_path_dont_ask), !cAskDownloadPath()), + _downloadPathEdit(this, cDownloadPath().isEmpty() ? lang(lng_download_path_temp) : st::linkFont->m.elidedText(QDir::toNativeSeparators(cDownloadPath()), Qt::ElideRight, st::setWidth - st::setVersionLeft - _downloadPathWidth)), + _downloadPathClear(this, lang(lng_download_path_clear)), + _tempDirClearingWidth(st::linkFont->m.width(lang(lng_download_path_clearing))), + _tempDirClearedWidth(st::linkFont->m.width(lang(lng_download_path_cleared))), + _tempDirClearFailedWidth(st::linkFont->m.width(lang(lng_download_path_clear_failed))), + + _catsAndDogs(this, lang(lng_settings_cats_and_dogs), cCatsAndDogs()), + + // advanced + _connectionType(this, lang(lng_connection_auto)), + _resetSessions(this, lang(lng_settings_reset)), + _resetDone(false), + _logOut(this, lang(lng_settings_logout), st::btnLogout) +{ + if (_self) { + _nameText.setText(st::setNameFont, _nameCache, _textNameOptions); + PhotoData *selfPhoto = _self->photoId ? App::photo(_self->photoId) : 0; + if (selfPhoto && selfPhoto->date) _photoLink = TextLinkPtr(new PhotoLink(selfPhoto)); + MTP::send(MTPusers_GetFullUser(_self->inputUser), rpcDone(&SettingsInner::gotFullSelf)); + + connect(App::main(), SIGNAL(peerPhotoChanged(PeerData *)), this, SLOT(peerUpdated(PeerData *))); + connect(App::main(), SIGNAL(peerNameChanged(PeerData *, const PeerData::Names &, const PeerData::NameFirstChars &)), this, SLOT(peerUpdated(PeerData *))); + } + + // profile + connect(&_uploadPhoto, SIGNAL(clicked()), this, SLOT(onUpdatePhoto())); + connect(&_cancelPhoto, SIGNAL(clicked()), this, SLOT(onUpdatePhotoCancel())); + + connect(App::app(), SIGNAL(peerPhotoDone(PeerId)), this, SLOT(onPhotoUpdateDone(PeerId))); + connect(App::app(), SIGNAL(peerPhotoFail(PeerId)), this, SLOT(onPhotoUpdateFail(PeerId))); + + // notifications + connect(&_desktopNotify, SIGNAL(changed()), this, SLOT(onDesktopNotify())); + connect(&_soundNotify, SIGNAL(changed()), this, SLOT(onSoundNotify())); + + // general + connect(&_autoUpdate, SIGNAL(changed()), this, SLOT(onAutoUpdate())); + connect(&_checkNow, SIGNAL(clicked()), this, SLOT(onCheckNow())); + connect(&_restartNow, SIGNAL(clicked()), this, SLOT(onRestartNow())); + + connect(&_workmodeTray, SIGNAL(changed()), this, SLOT(onWorkmodeTray())); + connect(&_workmodeWindow, SIGNAL(changed()), this, SLOT(onWorkmodeWindow())); + + _startMinimized.setDisabled(!_autoStart.checked()); + connect(&_autoStart, SIGNAL(changed()), this, SLOT(onAutoStart())); + connect(&_startMinimized, SIGNAL(changed()), this, SLOT(onStartMinimized())); + + connect(&_dpiAutoScale, SIGNAL(changed()), this, SLOT(onScaleAuto())); + connect(&_dpiSlider, SIGNAL(changed(int32)), this, SLOT(onScaleChange())); + + _curVersionText = lang(lng_settings_current_version).replace(qsl("{version}"), QString::fromWCharArray(AppVersionStr)) + ' '; + _curVersionWidth = st::linkFont->m.width(_curVersionText); + _newVersionText = lang(lng_settings_update_ready) + ' '; + _newVersionWidth = st::linkFont->m.width(_newVersionText); + + connect(App::app(), SIGNAL(updateChecking()), this, SLOT(onUpdateChecking())); + connect(App::app(), SIGNAL(updateLatest()), this, SLOT(onUpdateLatest())); + connect(App::app(), SIGNAL(updateDownloading(qint64,qint64)), this, SLOT(onUpdateDownloading(qint64,qint64))); + connect(App::app(), SIGNAL(updateReady()), this, SLOT(onUpdateReady())); + connect(App::app(), SIGNAL(updateFailed()), this, SLOT(onUpdateFailed())); + + // chat options + connect(&_replaceEmojis, SIGNAL(changed()), this, SLOT(onReplaceEmojis())); + connect(&_viewEmojis, SIGNAL(clicked()), this, SLOT(onViewEmojis())); + + connect(&_enterSend, SIGNAL(changed()), this, SLOT(onEnterSend())); + connect(&_ctrlEnterSend, SIGNAL(changed()), this, SLOT(onCtrlEnterSend())); + + connect(&_dontAskDownloadPath, SIGNAL(changed()), this, SLOT(onDontAskDownloadPath())); + connect(&_downloadPathEdit, SIGNAL(clicked()), this, SLOT(onDownloadPathEdit())); + connect(&_downloadPathClear, SIGNAL(clicked()), this, SLOT(onDownloadPathClear())); + switch (App::wnd()->tempDirState()) { + case Window::TempDirEmpty: _tempDirClearState = TempDirEmpty; break; + case Window::TempDirExists: _tempDirClearState = TempDirExists; break; + case Window::TempDirRemoving: _tempDirClearState = TempDirClearing; break; + } + connect(App::wnd(), SIGNAL(tempDirCleared()), this, SLOT(onTempDirCleared())); + connect(App::wnd(), SIGNAL(tempDirClearFailed()), this, SLOT(onTempDirClearFailed())); + + connect(&_catsAndDogs, SIGNAL(changed()), this, SLOT(onCatsAndDogs())); + + // advanced + connect(&_connectionType, SIGNAL(clicked()), this, SLOT(onConnectionType())); + connect(&_resetSessions, SIGNAL(clicked()), this, SLOT(onResetSessions())); + connect(&_logOut, SIGNAL(clicked()), this, SLOT(onLogout())); + + _connectionTypeText = lang(lng_connection_type) + ' '; + _connectionTypeWidth = st::linkFont->m.width(_connectionTypeText); + + if (App::main()) { + connect(App::main(), SIGNAL(peerUpdated(PeerData*)), this, SLOT(peerUpdated(PeerData*))); + } + + updateOnlineDisplay(); + + switch (App::app()->updatingState()) { + case Application::UpdatingDownload: + setUpdatingState(UpdatingDownload, true); + setDownloadProgress(App::app()->updatingReady(), App::app()->updatingSize()); + break; + case Application::UpdatingReady: setUpdatingState(UpdatingReady, true); break; + default: setUpdatingState(UpdatingNone, true); break; + } + + updateConnectionType(); + + setMouseTracking(true); +} + +void SettingsInner::peerUpdated(PeerData *data) { + if (_self && data == _self) { + if (_self->photoId) { + PhotoData *selfPhoto = App::photo(_self->photoId); + if (selfPhoto->date) { + _photoLink = TextLinkPtr(new PhotoLink(selfPhoto)); + } else { + _photoLink = TextLinkPtr(); + MTP::send(MTPusers_GetFullUser(_self->inputUser), rpcDone(&SettingsInner::gotFullSelf)); + } + } else { + _photoLink = TextLinkPtr(); + } + + if (_nameCache != _self->name) { + _nameCache = _self->name; + _nameText.setText(st::setNameFont, _nameCache, _textNameOptions); + update(); + } + } +} + +void SettingsInner::paintEvent(QPaintEvent *e) { + QPainter p(this); + + p.setClipRect(e->rect()); + + int32 top = 0; + if (_self) { + // profile + top += st::setTop; + + _nameText.drawElided(p, _uploadPhoto.x() + st::setNameLeft, top + st::setNameTop, _uploadPhoto.width() - st::setNameLeft); + if (!_cancelPhoto.isHidden()) { + p.setFont(st::linkFont->f); + p.setPen(st::black->p); + p.drawText(_uploadPhoto.x() + st::setPhoneLeft, _cancelPhoto.y() + st::linkFont->ascent, lang(lng_settings_uploading_photo)); + } + p.setFont(st::setPhoneFont->f); + p.setPen(st::setPhoneColor->p); + p.drawText(_uploadPhoto.x() + st::setPhoneLeft, top + st::setPhoneTop + st::setPhoneFont->ascent, _phoneText); + + if (_photoLink) { + p.drawPixmap(_left, top, _self->photo->pix(st::setPhotoSize)); + } else { + if (a_photo.current() < 1) { + p.drawPixmap(QPoint(_left, top), App::sprite(), st::setPhotoImg); + } + if (a_photo.current() > 0) { + p.setOpacity(a_photo.current()); + p.drawPixmap(QPoint(_left, top), App::sprite(), st::setOverPhotoImg); + p.setOpacity(1); + } + } + top += st::setPhotoSize; + + if (!_errorText.isEmpty()) { + p.setFont(st::setErrFont->f); + p.setPen(st::setErrColor->p); + p.drawText(QRect(_uploadPhoto.x(), _uploadPhoto.y() + _uploadPhoto.height() + st::setLittleSkip, _uploadPhoto.width(), st::setErrFont->height), _errorText, style::al_center); + } + + // notifications + p.setFont(st::setHeaderFont->f); + p.setPen(st::setHeaderColor->p); + p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_notify)); + top += st::setHeaderSkip; + + top += _desktopNotify.height() + st::setLittleSkip; + top += _soundNotify.height(); + } + + // general + p.setFont(st::setHeaderFont->f); + p.setPen(st::setHeaderColor->p); + p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_general)); + top += st::setHeaderSkip; + + top += _autoUpdate.height(); + QString textToDraw; + if (cAutoUpdate()) { + switch (_updatingState) { + case UpdatingNone: textToDraw = _curVersionText; break; + case UpdatingCheck: textToDraw = lang(lng_settings_update_checking); break; + case UpdatingLatest: textToDraw = lang(lng_settings_latest_installed); break; + case UpdatingDownload: textToDraw = _newVersionDownload; break; + case UpdatingReady: textToDraw = _newVersionText; break; + case UpdatingFail: textToDraw = lang(lng_settings_update_fail); break; + } + } else { + textToDraw = _curVersionText; + } + p.setFont(st::linkFont->f); + p.setPen(st::setVersionColor->p); + p.drawText(_left + st::setVersionLeft, top + st::setVersionTop + st::linkFont->ascent, textToDraw); + top += st::setVersionHeight; + + top += _workmodeTray.height() + st::setLittleSkip; + top += _workmodeWindow.height() + st::setSectionSkip; + + top += _autoStart.height() + st::setLittleSkip; + top += _startMinimized.height(); + + p.setFont(st::setHeaderFont->f); + p.setPen(st::setHeaderColor->p); + p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_scale_label)); + top += st::setHeaderSkip; + top += _dpiAutoScale.height() + st::setLittleSkip; + + top += _dpiSlider.height() + st::dpiFont4->height; + int32 sLeft = _dpiSlider.x() + _dpiWidth1 / 2, sWidth = _dpiSlider.width(); + float64 sStep = (sWidth - _dpiWidth1 / 2 - _dpiWidth4 / 2) / float64(dbisScaleCount - 2); + p.setFont(st::dpiFont1->f); + + p.setPen((scaleIs(dbisOne) ? st::dpiActive : st::dpiInactive)->p); + p.drawText(sLeft + qRound(0 * sStep) - _dpiWidth1 / 2, top - (st::dpiFont4->height - st::dpiFont1->height) / 2 - st::dpiFont1->descent, scaleLabel(dbisOne)); + p.setFont(st::dpiFont2->f); + p.setPen((scaleIs(dbisOneAndQuarter) ? st::dpiActive : st::dpiInactive)->p); + p.drawText(sLeft + qRound(1 * sStep) - _dpiWidth2 / 2, top - (st::dpiFont4->height - st::dpiFont2->height) / 2 - st::dpiFont2->descent, scaleLabel(dbisOneAndQuarter)); + p.setFont(st::dpiFont3->f); + p.setPen((scaleIs(dbisOneAndHalf) ? st::dpiActive : st::dpiInactive)->p); + p.drawText(sLeft + qRound(2 * sStep) - _dpiWidth3 / 2, top - (st::dpiFont4->height - st::dpiFont3->height) / 2 - st::dpiFont3->descent, scaleLabel(dbisOneAndHalf)); + p.setFont(st::dpiFont4->f); + p.setPen((scaleIs(dbisTwo) ? st::dpiActive : st::dpiInactive)->p); + p.drawText(sLeft + qRound(3 * sStep) - _dpiWidth4 / 2, top - (st::dpiFont4->height - st::dpiFont4->height) / 2 - st::dpiFont4->descent, scaleLabel(dbisTwo)); + p.setFont(st::linkFont->f); + + if (_self) { + // chat options + p.setFont(st::setHeaderFont->f); + p.setPen(st::setHeaderColor->p); + p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_chat)); + top += st::setHeaderSkip; + + top += _replaceEmojis.height() + st::setSectionSkip; + top += _enterSend.height() + st::setLittleSkip; + top += _ctrlEnterSend.height() + st::setSectionSkip; + + top += _dontAskDownloadPath.height(); + if (!cAskDownloadPath()) { + top += st::setLittleSkip; + p.setFont(st::linkFont->f); + p.setPen(st::black->p); + p.drawText(_left + st::setVersionLeft, top + st::linkFont->ascent, lang(lng_download_path_label)); + if (cDownloadPath().isEmpty()) { + QString clearText; + int32 clearWidth = 0; + switch (_tempDirClearState) { + case TempDirClearing: clearText = lang(lng_download_path_clearing); clearWidth = _tempDirClearingWidth; break; + case TempDirCleared: clearText = lang(lng_download_path_cleared); clearWidth = _tempDirClearedWidth; break; + case TempDirClearFailed: clearText = lang(lng_download_path_clear_failed); clearWidth = _tempDirClearFailedWidth; break; + } + if (clearWidth) { + p.drawText(_left + st::setWidth - clearWidth, top + st::linkFont->ascent, clearText); + } + } + top += _downloadPathEdit.height(); + } + top += st::setSectionSkip; + + top += _catsAndDogs.height(); + } + + // advanced + p.setFont(st::setHeaderFont->f); + p.setPen(st::setHeaderColor->p); + p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_advanced)); + top += st::setHeaderSkip; + + p.setFont(st::linkFont->f); + p.setPen(st::black->p); + p.drawText(_left + st::setHeaderLeft, _connectionType.y() + st::linkFont->ascent, _connectionTypeText); + + if (_self && _resetDone) { + p.drawText(_resetSessions.x(), _resetSessions.y() + st::linkFont->ascent, lang(lng_settings_reset_done)); + } +} + +void SettingsInner::resizeEvent(QResizeEvent *e) { + _left = (width() - st::setWidth) / 2; + + int32 top = 0; + + if (_self) { + // profile + top += st::setTop; + top += st::setPhotoSize; + _uploadPhoto.move(_left + st::setWidth - _uploadPhoto.width(), top - _uploadPhoto.height()); + _cancelPhoto.move(_left + st::setWidth - _cancelPhoto.width(), top - _uploadPhoto.height() + st::btnSetUpload.textTop + st::btnSetUpload.font->ascent - st::linkFont->ascent); + + // notifications + top += st::setHeaderSkip; + _desktopNotify.move(_left, top); top += _desktopNotify.height() + st::setLittleSkip; + _soundNotify.move(_left, top); top += _soundNotify.height(); + } + + // general + top += st::setHeaderSkip; + _autoUpdate.move(_left, top); + _checkNow.move(_left + st::setWidth - _checkNow.width(), top); top += _autoUpdate.height(); + _restartNow.move(_left + st::setWidth - _restartNow.width(), top + st::setVersionTop); + top += st::setVersionHeight; + + _workmodeTray.move(_left, top); top += _workmodeTray.height() + st::setLittleSkip; + _workmodeWindow.move(_left, top); top += _workmodeWindow.height() + st::setSectionSkip; + + _autoStart.move(_left, top); top += _autoStart.height() + st::setLittleSkip; + _startMinimized.move(_left, top); top += _startMinimized.height(); + + top += st::setHeaderSkip; + _dpiAutoScale.move(_left, top); top += _dpiAutoScale.height() + st::setLittleSkip; + _dpiSlider.move(_left, top); top += _dpiSlider.height() + st::dpiFont4->height; + + // chat options + if (_self) { + top += st::setHeaderSkip; + _viewEmojis.move(_left + st::setWidth - _viewEmojis.width(), top + st::cbDefFlat.textTop); + _replaceEmojis.move(_left, top); top += _replaceEmojis.height() + st::setSectionSkip; + _enterSend.move(_left, top); top += _enterSend.height() + st::setLittleSkip; + _ctrlEnterSend.move(_left, top); top += _ctrlEnterSend.height() + st::setSectionSkip; + _dontAskDownloadPath.move(_left, top); top += _dontAskDownloadPath.height(); + if (!cAskDownloadPath()) { + top += st::setLittleSkip; + _downloadPathEdit.move(_left + st::setVersionLeft + _downloadPathWidth, top); + if (cDownloadPath().isEmpty()) { + _downloadPathClear.move(_left + st::setWidth - _downloadPathClear.width(), top); + } + top += _downloadPathEdit.height(); + } + top += st::setSectionSkip; + _catsAndDogs.move(_left, top); top += _catsAndDogs.height(); + } + + // advanced + top += st::setHeaderSkip; + _connectionType.move(_left + st::setHeaderLeft + _connectionTypeWidth, top); top += _connectionType.height() + st::setLittleSkip; + if (_self) { + _resetSessions.move(_left, top); top += _resetSessions.height() + st::setSectionSkip; + _logOut.move(_left, top); + } +} + +void SettingsInner::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + App::wnd()->showSettings(); + } +} + +void SettingsInner::mouseMoveEvent(QMouseEvent *e) { + if (!_self) { + setCursor(style::cur_default); + } else { + bool nameOver = QRect(_uploadPhoto.x() + st::setNameLeft, st::setTop + st::setNameTop, qMin(_uploadPhoto.width() - int(st::setNameLeft), _nameText.maxWidth()), st::setNameFont->height).contains(e->pos()); + if (nameOver != _nameOver) { + _nameOver = nameOver; + } + + bool photoOver = QRect(_left, st::setTop, st::setPhotoSize, st::setPhotoSize).contains(e->pos()); + if (photoOver != _photoOver) { + _photoOver = photoOver; + if (!_photoLink) { + a_photo.start(_photoOver ? 1 : 0); + anim::start(this); + } + } + + setCursor((_nameOver || _photoOver) ? style::cur_pointer : style::cur_default); + } +} + +void SettingsInner::mousePressEvent(QMouseEvent *e) { + mouseMoveEvent(e); + if (!_self) { + return; + } + if (QRect(_uploadPhoto.x() + st::setNameLeft, st::setTop + st::setNameTop, qMin(_uploadPhoto.width() - int(st::setNameLeft), _nameText.maxWidth()), st::setNameFont->height).contains(e->pos())) { + App::wnd()->showLayer(new AddContactBox(_self)); + } else if (QRect(_left, st::setTop, st::setPhotoSize, st::setPhotoSize).contains(e->pos())) { + if (_photoLink) { + App::photo(_self->photoId)->full->load(); + _photoLink->onClick(e->button()); + } else { + onUpdatePhoto(); + } + } +} + +void SettingsInner::contextMenuEvent(QContextMenuEvent *e) { +} + +bool SettingsInner::animStep(float64 ms) { + float64 dt = ms / st::setPhotoDuration; + bool res = true; + if (dt >= 1) { + res = false; + a_photo.finish(); + } else { + a_photo.update(dt, anim::linear); + } + update(_left, st::setTop, st::setPhotoSize, st::setPhotoSize); + return res; +} + +void SettingsInner::updateSize(int32 newWidth) { + if (_logOut.isHidden()) { + resize(newWidth, _connectionType.geometry().bottom() + st::setBottom); + } else { + resize(newWidth, _logOut.geometry().bottom() + st::setBottom); + } +} + +bool SettingsInner::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + if (photo->id == _self->photoId) { + x = _left; + y = st::setTop; + w = st::setPhotoSize; + return true; + } + return false; +} + +void SettingsInner::updateOnlineDisplay() { +} + +void SettingsInner::updateConnectionType() { + switch (cConnectionType()) { + case dbictAuto: { + QString transport = MTP::dctransport(); + if (transport.isEmpty()) { + _connectionType.setText(lang(lng_connection_auto_connecting)); + } else { + _connectionType.setText(lang(lng_connection_auto).replace(qsl("{type}"), transport)); + } + } break; + case dbictHttpProxy: _connectionType.setText(lang(lng_connection_http_proxy)); break; + case dbictTcpProxy: _connectionType.setText(lang(lng_connection_tcp_proxy)); break; + } +} + +void SettingsInner::gotFullSelf(const MTPUserFull &self) { + if (!_self) return; + App::feedPhoto(self.c_userFull().vprofile_photo); + App::feedUsers(MTP_vector(QVector(1, self.c_userFull().vuser))); + PhotoData *selfPhoto = _self->photoId ? App::photo(_self->photoId) : 0; + if (selfPhoto && selfPhoto->date) { + _photoLink = TextLinkPtr(new PhotoLink(selfPhoto)); + } else { + _photoLink = TextLinkPtr(); + } +} + +void SettingsInner::showAll() { + // profile + if (_self) { + if (App::app()->isPhotoUpdating(_self->id)) { + _cancelPhoto.show(); + _uploadPhoto.hide(); + } else { + _cancelPhoto.hide(); + _uploadPhoto.show(); + } + } else { + _uploadPhoto.hide(); + _cancelPhoto.hide(); + } + + // notifications + if (_self) { + _desktopNotify.show(); + _soundNotify.show(); + } else { + _desktopNotify.hide(); + _soundNotify.hide(); + } + + // general + _autoUpdate.show(); + + _workmodeTray.show(); + _workmodeWindow.show(); + + _autoStart.show(); + setUpdatingState(_updatingState, true); + _startMinimized.show(); + _dpiSlider.show(); + + // chat options + if (_self) { + _replaceEmojis.show(); + if (cReplaceEmojis()) { + _viewEmojis.show(); + } else { + _viewEmojis.hide(); + } + _enterSend.show(); + _ctrlEnterSend.show(); + _catsAndDogs.show(); + _dontAskDownloadPath.show(); + if (cAskDownloadPath()) { + _downloadPathEdit.hide(); + _downloadPathClear.hide(); + } else { + _downloadPathEdit.show(); + if (cDownloadPath().isEmpty() && _tempDirClearState == TempDirExists) { // dir exists, not clearing right now + _downloadPathClear.show(); + } else { + _downloadPathClear.hide(); + } + } + } else { + _replaceEmojis.hide(); + _viewEmojis.hide(); + _enterSend.hide(); + _ctrlEnterSend.hide(); + _catsAndDogs.hide(); + _dontAskDownloadPath.hide(); + _downloadPathEdit.hide(); + _downloadPathClear.hide(); + } + + // advanced + if (_self) { + if (_resetDone) { + _resetSessions.hide(); + } else { + _resetSessions.show(); + } + _logOut.show(); + } else { + _resetSessions.hide(); + _logOut.hide(); + } +} + +void SettingsInner::saveError(const QString &str) { + _errorText = str; + resizeEvent(0); + update(); +} + +void SettingsInner::onUpdatePhotoCancel() { + if (_self) { + App::app()->cancelPhotoUpdate(_self->id); + } + showAll(); + update(); +} + +void SettingsInner::onUpdatePhoto() { + saveError(); + + QStringList imgExtensions(cImgExtensions()); + QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;All files (*.*)")); + + QImage img; + QString file; + QByteArray remoteContent; + if (filedialogGetOpenFile(file, remoteContent, lang(lng_choose_images), filter)) { + if (!remoteContent.isEmpty()) { + img = App::readImage(remoteContent); + } else { + if (!file.isEmpty()) { + img = App::readImage(file); + } + } + } else { + return; + } + + if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) { + saveError(lang(lng_bad_photo)); + return; + } + PhotoCropBox *box = new PhotoCropBox(img, _self->id); + connect(box, SIGNAL(closed()), this, SLOT(onPhotoUpdateStart())); + App::wnd()->showLayer(box); +} + +void SettingsInner::onLogout() { + App::logOut(); +} + +void SettingsInner::onResetSessions() { + MTP::send(MTPauth_ResetAuthorizations(), rpcDone(&SettingsInner::doneResetSessions)); +} + +void SettingsInner::doneResetSessions(const MTPBool &res) { + if (res.v) { + _resetDone = true; + showAll(); + update(); + } +} + +void SettingsInner::onAutoUpdate() { + cSetAutoUpdate(!cAutoUpdate()); + App::writeConfig(); + resizeEvent(0); + if (cAutoUpdate()) { + App::app()->startUpdateCheck(); + if (_updatingState == UpdatingNone) { + _checkNow.show(); + } else if (_updatingState == UpdatingReady) { + _restartNow.show(); + } + } else { + App::app()->stopUpdate(); + _restartNow.hide(); + _checkNow.hide(); + } + update(); +} + +void SettingsInner::onCheckNow() { + if (!cAutoUpdate()) return; + + cSetLastUpdateCheck(0); + App::app()->startUpdateCheck(); +} + +void SettingsInner::onRestartNow() { + psCheckReadyUpdate(); + if (_updatingState == UpdatingReady) { + cSetRestartingUpdate(true); + } else { + cSetRestarting(true); + } + App::quit(); +} + +void SettingsInner::onConnectionType() { + ConnectionBox *box = new ConnectionBox(); + connect(box, SIGNAL(closed()), this, SLOT(updateConnectionType()), Qt::QueuedConnection); + App::wnd()->showLayer(box); +} + +void SettingsInner::onWorkmodeTray() { + if (!_workmodeTray.checked() && !_workmodeWindow.checked()) { + _workmodeWindow.setChecked(true); + } + DBIWorkMode newMode = (_workmodeTray.checked() && _workmodeWindow.checked()) ? dbiwmWindowAndTray : (_workmodeTray.checked() ? dbiwmTrayOnly : dbiwmWindowOnly); + if (cWorkMode() != newMode && (newMode == dbiwmWindowAndTray || newMode == dbiwmTrayOnly)) { + cSetSeenTrayTooltip(false); + } + cSetWorkMode(newMode); + App::wnd()->psUpdateWorkmode(); + App::writeConfig(); +} + +void SettingsInner::onWorkmodeWindow() { + if (!_workmodeTray.checked() && !_workmodeWindow.checked()) { + _workmodeTray.setChecked(true); + } + DBIWorkMode newMode = (_workmodeTray.checked() && _workmodeWindow.checked()) ? dbiwmWindowAndTray : (_workmodeTray.checked() ? dbiwmTrayOnly : dbiwmWindowOnly); + if (cWorkMode() != newMode && (newMode == dbiwmWindowAndTray || newMode == dbiwmTrayOnly)) { + cSetSeenTrayTooltip(false); + } + cSetWorkMode(newMode); + App::wnd()->psUpdateWorkmode(); + App::writeConfig(); +} + +void SettingsInner::onAutoStart() { + _startMinimized.setDisabled(!_autoStart.checked()); + cSetAutoStart(_autoStart.checked()); + if (!_autoStart.checked() && _startMinimized.checked()) { + psAutoStart(false); + _startMinimized.setChecked(false); + } else { + psAutoStart(_autoStart.checked()); + App::writeConfig(); + } +} + +void SettingsInner::onStartMinimized() { + cSetStartMinimized(_startMinimized.checked()); + App::writeConfig(); +} + +void SettingsInner::onScaleAuto() { + DBIScale newScale = _dpiAutoScale.checked() ? dbisAuto : cEvalScale(cConfigScale()); + if (newScale == cScreenScale()) { + if (newScale != cScale()) { + newScale = cScale(); + } else { + switch (newScale) { + case dbisOne: newScale = dbisOneAndQuarter; break; + case dbisOneAndQuarter: newScale = dbisOne; break; + case dbisOneAndHalf: newScale = dbisOneAndQuarter; break; + case dbisTwo: newScale = dbisOneAndHalf; break; + } + } + } + setScale(newScale); +} + +void SettingsInner::onScaleChange() { + DBIScale newScale = dbisAuto; + switch (_dpiSlider.selected()) { + case 0: newScale = dbisOne; break; + case 1: newScale = dbisOneAndQuarter; break; + case 2: newScale = dbisOneAndHalf; break; + case 3: newScale = dbisTwo; break; + } + if (newScale == cScreenScale()) { + newScale = dbisAuto; + } + setScale(newScale); +} + +void SettingsInner::setScale(DBIScale newScale) { + if (cConfigScale() == newScale) return; + + cSetConfigScale(newScale); + App::writeConfig(); + App::wnd()->getTitle()->showUpdateBtn(); + if (newScale == dbisAuto && !_dpiAutoScale.checked()) { + _dpiAutoScale.setChecked(true); + } else if (newScale != dbisAuto && _dpiAutoScale.checked()) { + _dpiAutoScale.setChecked(false); + } + if (newScale == dbisAuto) newScale = cScreenScale(); + if (_dpiSlider.selected() != newScale - 1) { + _dpiSlider.setSelected(newScale - 1); + } + if (cEvalScale(cConfigScale()) != cEvalScale(cRealScale())) { + ConfirmBox *box = new ConfirmBox(lang(lng_settings_need_restart), lang(lng_settings_restart_now), lang(lng_settings_restart_later)); + connect(box, SIGNAL(confirmed()), this, SLOT(onRestartNow())); + App::wnd()->showLayer(box); + } +} + +void SettingsInner::onSoundNotify() { + cSetSoundNotify(_soundNotify.checked()); + App::writeUserConfig(); +} + +void SettingsInner::onDesktopNotify() { + cSetDesktopNotify(_desktopNotify.checked()); + if (!_desktopNotify.checked()) { + App::wnd()->psClearNotify(); + } + App::writeUserConfig(); +} + +void SettingsInner::onReplaceEmojis() { + cSetReplaceEmojis(_replaceEmojis.checked()); + App::writeUserConfig(); + + if (_replaceEmojis.checked()) { + _viewEmojis.show(); + } else { + _viewEmojis.hide(); + } +} + +void SettingsInner::onViewEmojis() { + App::wnd()->showLayer(new EmojiBox()); +} + +void SettingsInner::onEnterSend() { + if (_enterSend.checked()) { + cSetCtrlEnter(false); + App::writeUserConfig(); + } +} + +void SettingsInner::onCtrlEnterSend() { + if (_ctrlEnterSend.checked()) { + cSetCtrlEnter(true); + App::writeUserConfig(); + } +} + +void SettingsInner::onCatsAndDogs() { + cSetCatsAndDogs(_catsAndDogs.checked()); + App::writeUserConfig(); +} + +void SettingsInner::onDontAskDownloadPath() { + cSetAskDownloadPath(!_dontAskDownloadPath.checked()); + App::writeUserConfig(); + + showAll(); + resizeEvent(0); + update(); +} + +void SettingsInner::onDownloadPathEdit() { + DownloadPathBox *box = new DownloadPathBox(); + connect(box, SIGNAL(closed()), this, SLOT(onDownloadPathEdited())); + App::wnd()->showLayer(box); +} + +void SettingsInner::onDownloadPathEdited() { + _downloadPathEdit.setText(cDownloadPath().isEmpty() ? lang(lng_download_path_temp) : st::linkFont->m.elidedText(QDir::toNativeSeparators(cDownloadPath()), Qt::ElideRight, st::setWidth - st::setVersionLeft - _downloadPathWidth)); + showAll(); +} + +void SettingsInner::onDownloadPathClear() { + ConfirmBox *box = new ConfirmBox(lang(lng_sure_clear_downloads)); + connect(box, SIGNAL(confirmed()), this, SLOT(onDownloadPathClearSure())); + App::wnd()->showLayer(box); +} + +void SettingsInner::onDownloadPathClearSure() { + App::wnd()->hideLayer(); + App::wnd()->tempDirDelete(); + _tempDirClearState = TempDirClearing; + showAll(); + update(); +} + +void SettingsInner::onTempDirCleared() { + _tempDirClearState = TempDirCleared; + showAll(); + update(); +} + +void SettingsInner::onTempDirClearFailed() { + _tempDirClearState = TempDirClearFailed; + showAll(); + update(); +} + +void SettingsInner::setUpdatingState(UpdatingState state, bool force) { + if (_updatingState != state || force) { + _updatingState = state; + if (cAutoUpdate()) { + switch (state) { + case UpdatingNone: + case UpdatingLatest: _checkNow.show(); _restartNow.hide(); break; + case UpdatingReady: _checkNow.hide(); _restartNow.show(); break; + case UpdatingCheck: + case UpdatingDownload: + case UpdatingFail: _checkNow.hide(); _restartNow.hide(); break; + } + update(0, _restartNow.y() - 10, width(), _restartNow.height() + 20); + } else { + _checkNow.hide(); + _restartNow.hide(); + } + } +} + +void SettingsInner::setDownloadProgress(qint64 ready, qint64 total) { + qint64 readyTenthMb = (ready * 10 / (1024 * 1024)), totalTenthMb = (total * 10 / (1024 * 1024)); + QString readyStr = QString::number(readyTenthMb / 10) + '.' + QString::number(readyTenthMb % 10); + QString totalStr = QString::number(totalTenthMb / 10) + '.' + QString::number(totalTenthMb % 10); + QString res = lang(lng_settings_downloading).replace(qsl("{ready}"), readyStr).replace(qsl("{total}"), totalStr); + if (_newVersionDownload != res) { + _newVersionDownload = res; + if (cAutoUpdate()) { + update(0, _restartNow.y() - 10, width(), _restartNow.height() + 20); + } + } +} + +void SettingsInner::onUpdateChecking() { + setUpdatingState(UpdatingCheck); +} + +void SettingsInner::onUpdateLatest() { + setUpdatingState(UpdatingLatest); +} + +void SettingsInner::onUpdateDownloading(qint64 ready, qint64 total) { + setUpdatingState(UpdatingDownload); + setDownloadProgress(ready, total); +} + +void SettingsInner::onUpdateReady() { + setUpdatingState(UpdatingReady); +} + +void SettingsInner::onUpdateFailed() { + setUpdatingState(UpdatingFail); +} + +void SettingsInner::onPhotoUpdateStart() { + showAll(); + update(); +} + +void SettingsInner::onPhotoUpdateFail(PeerId peer) { + if (!_self || _self->id != peer) return; + saveError(lang(lng_bad_photo)); + showAll(); + update(); +} + +void SettingsInner::onPhotoUpdateDone(PeerId peer) { + if (!_self || _self->id != peer) return; + showAll(); + update(); +} + +Settings::Settings(Window *parent) : QWidget(parent), + _scroll(this, st::setScroll), _inner(this), _close(this, st::setClose) { + _scroll.setWidget(&_inner); + + connect(App::wnd(), SIGNAL(resized(const QSize &)), this, SLOT(onParentResize(const QSize &))); + connect(&_close, SIGNAL(clicked()), App::wnd(), SLOT(showSettings())); + + setGeometry(QRect(0, st::titleHeight, Application::wnd()->width(), Application::wnd()->height() - st::titleHeight)); + + showAll(); +} + +void Settings::onParentResize(const QSize &newSize) { + resize(newSize); +} + +void Settings::animShow(const QPixmap &bgAnimCache, bool back) { + _bgAnimCache = bgAnimCache; + + anim::stop(this); + showAll(); + _animCache = grab(rect()); + + a_coord = back ? anim::ivalue(-st::introSlideShift, 0) : anim::ivalue(st::introSlideShift, 0); + a_alpha = anim::fvalue(0, 1); + a_bgCoord = back ? anim::ivalue(0, st::introSlideShift) : anim::ivalue(0, -st::introSlideShift); + a_bgAlpha = anim::fvalue(1, 0); + + hideAll(); + anim::start(this); + show(); +} + +bool Settings::animStep(float64 ms) { + float64 fullDuration = st::introSlideDelta + st::introSlideDuration, dt = ms / fullDuration; + float64 dt1 = (ms > st::introSlideDuration) ? 1 : (ms / st::introSlideDuration), dt2 = (ms > st::introSlideDelta) ? (ms - st::introSlideDelta) / (st::introSlideDuration) : 0; + bool res = true; + if (dt2 >= 1) { + res = false; + a_bgCoord.finish(); + a_bgAlpha.finish(); + a_coord.finish(); + a_alpha.finish(); + + _animCache = _bgAnimCache = QPixmap(); + + showAll(); + _inner.setFocus(); + } else { + a_bgCoord.update(dt1, st::introHideFunc); + a_bgAlpha.update(dt1, st::introAlphaHideFunc); + a_coord.update(dt2, st::introShowFunc); + a_alpha.update(dt2, st::introAlphaShowFunc); + } + update(); + return res; +} + +void Settings::paintEvent(QPaintEvent *e) { + QRect r(e->rect()); + bool trivial = (rect() == r); + + QPainter p(this); + if (!trivial) { + p.setClipRect(r); + } + if (animating()) { + p.setOpacity(a_bgAlpha.current()); + p.drawPixmap(a_bgCoord.current(), 0, _bgAnimCache); + p.setOpacity(a_alpha.current()); + p.drawPixmap(a_coord.current(), 0, _animCache); + } else { + p.fillRect(rect(), st::setBG->b); + } +} + +void Settings::showAll() { + _scroll.show(); + _inner.show(); + _inner.showAll(); + _close.show(); +} + +void Settings::hideAll() { + _scroll.hide(); + _close.hide(); +} + +void Settings::resizeEvent(QResizeEvent *e) { + _scroll.resize(size()); + _inner.updateSize(width()); + _close.move(st::setClosePos.x(), st::setClosePos.y()); +} + +void Settings::dragEnterEvent(QDragEnterEvent *e) { + +} + +void Settings::dropEvent(QDropEvent *e) { +} + +bool Settings::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + if (_inner.getPhotoCoords(photo, x, y, w)) { + x += _inner.x(); + y += _inner.y(); + return true; + } + return false; +} + +void Settings::updateOnlineDisplay() { + _inner.updateOnlineDisplay(); +} + +void Settings::updateConnectionType() { + _inner.updateConnectionType(); +} + +Settings::~Settings() { + if (App::wnd()) App::wnd()->noSettings(this); +} diff --git a/Telegram/SourceFiles/settingswidget.h b/Telegram/SourceFiles/settingswidget.h new file mode 100644 index 000000000..1981bd170 --- /dev/null +++ b/Telegram/SourceFiles/settingswidget.h @@ -0,0 +1,256 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "gui/flatbutton.h" +#include "gui/flatcheckbox.h" +#include "sysbuttons.h" + +#include + +class Window; +class Settings; + +class Slider : public QWidget { + Q_OBJECT + +public: + + Slider(QWidget *parent, const style::slider &st, int32 count, int32 sel = 0); + + void mousePressEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + + int32 selected() const; + void setSelected(int32 sel); + + void paintEvent(QPaintEvent *e); + +signals: + + void changed(int32 oldSelected); + +private: + + int32 _count, _sel, _wasSel; + style::slider _st; + bool _pressed; + +}; + +class SettingsInner : public QWidget, public RPCSender, public Animated { + Q_OBJECT + +public: + + SettingsInner(Settings *parent); + + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void keyPressEvent(QKeyEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void contextMenuEvent(QContextMenuEvent *e); + + bool animStep(float64 ms); + + void updateSize(int32 newWidth); + bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const; + + void updateOnlineDisplay(); + + void gotFullSelf(const MTPUserFull &self); + + void showAll(); + +public slots: + + void updateConnectionType(); + + void peerUpdated(PeerData *data); + + void onUpdatePhoto(); + void onUpdatePhotoCancel(); + + void onAutoUpdate(); + void onCheckNow(); + void onRestartNow(); + + void onConnectionType(); + + void onWorkmodeTray(); + void onWorkmodeWindow(); + + void onAutoStart(); + void onStartMinimized(); + + void onScaleAuto(); + void onScaleChange(); + + void onSoundNotify(); + void onDesktopNotify(); + + void onReplaceEmojis(); + void onViewEmojis(); + + void onEnterSend(); + void onCtrlEnterSend(); + + void onDontAskDownloadPath(); + void onDownloadPathEdit(); + void onDownloadPathEdited(); + void onDownloadPathClear(); + void onDownloadPathClearSure(); + void onTempDirCleared(); + void onTempDirClearFailed(); + + void onCatsAndDogs(); + + void onUpdateChecking(); + void onUpdateLatest(); + void onUpdateDownloading(qint64 ready, qint64 total); + void onUpdateReady(); + void onUpdateFailed(); + + void onLogout(); + void onResetSessions(); + + void onPhotoUpdateDone(PeerId peer); + void onPhotoUpdateFail(PeerId peer); + void onPhotoUpdateStart(); + +private: + + void doneResetSessions(const MTPBool &res); + void saveError(const QString &str = QString()); + + void setScale(DBIScale newScale); + + UserData *_self; + int32 _left; + + // profile + Text _nameText; + QString _nameCache; + QString _phoneText; + TextLinkPtr _photoLink; + FlatButton _uploadPhoto; + LinkButton _cancelPhoto; + bool _nameOver, _photoOver; + anim::fvalue a_photo; + + QString _errorText; + + // notifications + FlatCheckbox _desktopNotify, _soundNotify; + + // general + FlatCheckbox _autoUpdate; + LinkButton _checkNow, _restartNow; + FlatCheckbox _workmodeTray, _workmodeWindow; + FlatCheckbox _autoStart, _startMinimized; + FlatCheckbox _dpiAutoScale; + Slider _dpiSlider; + int32 _dpiWidth1, _dpiWidth2, _dpiWidth3, _dpiWidth4; + + QString _curVersionText, _newVersionText; + int32 _curVersionWidth, _newVersionWidth; + + enum UpdatingState { + UpdatingNone, + UpdatingCheck, + UpdatingLatest, + UpdatingDownload, + UpdatingFail, + UpdatingReady + }; + UpdatingState _updatingState; + QString _newVersionDownload; + + // chat options + FlatCheckbox _replaceEmojis; + LinkButton _viewEmojis; + FlatRadiobutton _enterSend, _ctrlEnterSend; + FlatCheckbox _dontAskDownloadPath; + int32 _downloadPathWidth; + LinkButton _downloadPathEdit, _downloadPathClear; + int32 _tempDirClearingWidth, _tempDirClearedWidth, _tempDirClearFailedWidth; + enum TempDirClearState { + TempDirClearFailed = 0, + TempDirEmpty = 1, + TempDirExists = 2, + TempDirClearing = 3, + TempDirCleared = 4, + }; + TempDirClearState _tempDirClearState; + FlatCheckbox _catsAndDogs; + + // advanced + LinkButton _connectionType, _resetSessions; + FlatButton _logOut; + + QString _connectionTypeText; + int32 _connectionTypeWidth; + + bool _resetDone; + + void setUpdatingState(UpdatingState state, bool force = false); + void setDownloadProgress(qint64 ready, qint64 total); + +}; + +class Settings : public QWidget, public Animated { + Q_OBJECT + +public: + + Settings(Window *parent); + + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void dragEnterEvent(QDragEnterEvent *e); + void dropEvent(QDropEvent *e); + + bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const; + + void animShow(const QPixmap &bgAnimCache, bool back = false); + bool animStep(float64 ms); + + void updateOnlineDisplay(); + void updateConnectionType(); + + ~Settings(); + +public slots: + + void onParentResize(const QSize &newSize); + +private: + + void showAll(); + void hideAll(); + + QPixmap _animCache, _bgAnimCache; + anim::ivalue a_coord, a_bgCoord; + anim::fvalue a_alpha, a_bgAlpha; + + ScrollArea _scroll; + SettingsInner _inner; + IconedButton _close; +}; diff --git a/Telegram/SourceFiles/stdafx.cpp b/Telegram/SourceFiles/stdafx.cpp new file mode 100644 index 000000000..c13af45cb --- /dev/null +++ b/Telegram/SourceFiles/stdafx.cpp @@ -0,0 +1,24 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include + +#ifdef Q_OS_WIN +Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin) +Q_IMPORT_PLUGIN(AccessibleFactory) +#endif diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h new file mode 100644 index 000000000..49b2f0e36 --- /dev/null +++ b/Telegram/SourceFiles/stdafx.h @@ -0,0 +1,60 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#define __HUGE + +//#define Q_NO_TEMPLATE_FRIENDS // fix some compiler difference issues + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#if defined Q_OS_WIN +#define _NEED_WIN_GENERATE_DUMP +#endif + +#include "types.h" +#include "config.h" + +#include "mtproto/mtp.h" + +#include "gui/twidget.h" + +#include "gui/style_core.h" +#include "gui/animation.h" +#include "gui/flatinput.h" +#include "gui/flattextarea.h" +#include "gui/flatbutton.h" +#include "gui/scrollarea.h" +#include "gui/images.h" +#include "gui/text.h" +#include "gui/flatlabel.h" + +#include "app.h" diff --git a/Telegram/SourceFiles/style.h b/Telegram/SourceFiles/style.h new file mode 100644 index 000000000..54cd2c346 --- /dev/null +++ b/Telegram/SourceFiles/style.h @@ -0,0 +1,21 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include "../GeneratedFiles/style_classes.h" +#include "../GeneratedFiles/style_auto.h" diff --git a/Telegram/SourceFiles/supporttl.cpp b/Telegram/SourceFiles/supporttl.cpp new file mode 100644 index 000000000..f4d4891a0 --- /dev/null +++ b/Telegram/SourceFiles/supporttl.cpp @@ -0,0 +1,101 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "supporttl.h" + +namespace { + typedef QMap SupportTemplates; + SupportTemplates _supportTemplates; + + void saveTemplate(QStringList &keys, QString &value) { + if (!keys.isEmpty() && !value.isEmpty()) { + if (value.at(value.size() - 1) == '\n') { + value = value.mid(0, value.size() - 1); + } + for (QStringList::const_iterator i = keys.cbegin(), e = keys.cend(); i != e; ++i) { + _supportTemplates[*i] = value; + } + } + value = QString(); + } +} + +void readSupportTemplates() { + QFile f(cWorkingDir() + qsl("support_tl.txt")); + if (!f.open(QIODevice::ReadOnly)) return; + + typedef QList TemplatesLines; + TemplatesLines lines = f.readAll().split('\n'); + + f.close(); + + enum ReadingState { + ReadingNone = 0, + ReadingKeys = 1, + ReadingValue = 2, + ReadingMoreValue = 3, + }; + ReadingState state = ReadingNone; + QStringList keys; + QString value; + for (TemplatesLines::const_iterator i = lines.cbegin(), e = lines.cend(); i != e; ++i) { + QString line = QString::fromUtf8(*i).trimmed(); + QRegularExpressionMatch m = QRegularExpression(qsl("^\\{([A-Z_]+)\\}$")).match(line); + if (m.hasMatch()) { + saveTemplate(keys, value); + + QString token = m.captured(1); + if (token == qsl("KEYS")) { + keys.clear(); + state = ReadingKeys; + } else if (token == qsl("VALUE")) { + state = ReadingValue; + } else { + keys.clear(); + state = ReadingNone; + } + continue; + } + + switch (state) { + case ReadingKeys: + if (!line.isEmpty()) { + keys.push_back(line); + } + break; + + case ReadingMoreValue: + value += '\n'; + case ReadingValue: + value += line; + state = ReadingMoreValue; + break; + } + } + saveTemplate(keys, value); +} + +const QString &supportTemplate(const QString &key) { + SupportTemplates::const_iterator i = _supportTemplates.constFind(key); + if (i != _supportTemplates.cend()) { + return *i; + } + + static const QString _tmp; + return _tmp; +} diff --git a/Telegram/SourceFiles/supporttl.h b/Telegram/SourceFiles/supporttl.h new file mode 100644 index 000000000..c0dd86f3b --- /dev/null +++ b/Telegram/SourceFiles/supporttl.h @@ -0,0 +1,21 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +void readSupportTemplates(); +const QString &supportTemplate(const QString &word); diff --git a/Telegram/SourceFiles/sysbuttons.cpp b/Telegram/SourceFiles/sysbuttons.cpp new file mode 100644 index 000000000..d482d54ff --- /dev/null +++ b/Telegram/SourceFiles/sysbuttons.cpp @@ -0,0 +1,118 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" +#include "lang.h" + +#include "sysbuttons.h" +#include "window.h" +#include "application.h" + +SysBtn::SysBtn(QWidget *parent, const style::sysButton &st) : Button(parent), + _st(st), a_color(_st.color->c) { + resize(_st.size); + setCursor(style::cur_default); + connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource))); +} + +void SysBtn::onStateChange(int oldState, ButtonStateChangeSource source) { + a_color.start((_state & StateOver ? _st.overColor : _st.color)->c); + + if (source == ButtonByUser || source == ButtonByPress) { + anim::stop(this); + a_color.finish(); + update(); + } else { + anim::start(this); + } +} + +void SysBtn::paintEvent(QPaintEvent *e) { + QPainter p(this); + + int x = (width() - _st.img.width()) / 2, y = (height() - _st.img.height()) / 2; + p.fillRect(x, y, _st.img.width(), _st.img.height(), a_color.current()); + p.drawPixmap(QPoint(x, y), App::sprite(), _st.img); +} + +HitTestType SysBtn::hitTest(const QPoint &p) const { + int x(p.x()), y(p.y()), w(width()), h(height()); + if (x >= 0 && y >= 0 && x < w && y < h && isVisible()) { + return HitTestSysButton; + } + return HitTestNone; +} + +bool SysBtn::animStep(float64 ms) { + float64 dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + a_color.finish(); + res = false; + } else { + a_color.update(dt, anim::linear); + } + update(); + return res; +} + +MinimizeBtn::MinimizeBtn(QWidget *parent, Window *window) : SysBtn(parent, st::sysMin), wnd(window) { + connect(this, SIGNAL(clicked()), this, SLOT(onClick())); +} + +void MinimizeBtn::onClick() { + wnd->setWindowState(Qt::WindowMinimized); +} + +MaximizeBtn::MaximizeBtn(QWidget *parent, Window *window) : SysBtn(parent, st::sysMax), wnd(window) { + connect(this, SIGNAL(clicked()), this, SLOT(onClick())); +} + +void MaximizeBtn::onClick() { + wnd->setWindowState(Qt::WindowMaximized); +} + +RestoreBtn::RestoreBtn(QWidget *parent, Window *window) : SysBtn(parent, st::sysRes), wnd(window) { + connect(this, SIGNAL(clicked()), this, SLOT(onClick())); +} + +void RestoreBtn::onClick() { + wnd->setWindowState(Qt::WindowNoState); +} + +CloseBtn::CloseBtn(QWidget *parent, Window *window) : SysBtn(parent, st::sysCls), wnd(window) { + connect(this, SIGNAL(clicked()), this, SLOT(onClick())); +} + +void CloseBtn::onClick() { + wnd->close(); +} + +UpdateBtn::UpdateBtn(QWidget *parent, Window *window) : SysBtn(parent, st::sysUpd), wnd(window) { + connect(this, SIGNAL(clicked()), this, SLOT(onClick())); +} + +void UpdateBtn::onClick() { + psCheckReadyUpdate(); + if (App::app()->updatingState() == Application::UpdatingReady) { + cSetRestartingUpdate(true); + } else { + cSetRestarting(true); + } + App::quit(); +} diff --git a/Telegram/SourceFiles/sysbuttons.h b/Telegram/SourceFiles/sysbuttons.h new file mode 100644 index 000000000..8d08a85de --- /dev/null +++ b/Telegram/SourceFiles/sysbuttons.h @@ -0,0 +1,128 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "gui/animation.h" +#include "gui/button.h" + +class Window; + +class SysBtn : public Button, public Animated { + Q_OBJECT + +public: + + SysBtn(QWidget *parent, const style::sysButton &st); + + void paintEvent(QPaintEvent *e); + + HitTestType hitTest(const QPoint &p) const; + + bool animStep(float64 ms); + +public slots: + + void onStateChange(int oldState, ButtonStateChangeSource source); + +protected: + + style::sysButton _st; + anim::cvalue a_color; + +}; + +class MinimizeBtn : public SysBtn { + Q_OBJECT + +public: + + MinimizeBtn(QWidget *parent, Window *window); + +public slots: + + void onClick(); + +private: + + Window *wnd; +}; + +class MaximizeBtn : public SysBtn { + Q_OBJECT + +public: + + MaximizeBtn(QWidget *parent, Window *window); + +public slots: + + void onClick(); + +private: + + Window *wnd; +}; + +class RestoreBtn : public SysBtn { + Q_OBJECT + +public: + + RestoreBtn(QWidget *parent, Window *window); + +public slots: + + void onClick(); + +private: + + Window *wnd; +}; + +class CloseBtn : public SysBtn { + Q_OBJECT + +public: + + CloseBtn(QWidget *parent, Window *window); + +public slots: + + void onClick(); + +private: + + Window *wnd; +}; + +class UpdateBtn : public SysBtn { + Q_OBJECT + +public: + + UpdateBtn(QWidget *parent, Window *window); + +public slots: + + void onClick(); + +private: + + Window *wnd; +}; diff --git a/Telegram/SourceFiles/telegram.qrc b/Telegram/SourceFiles/telegram.qrc new file mode 100644 index 000000000..cc02b7f80 --- /dev/null +++ b/Telegram/SourceFiles/telegram.qrc @@ -0,0 +1,40 @@ + + + art/segoe_ui.ttf + art/segoe_ui_semibold.ttf + art/segoe_wp_semibold.ttf + art/newmsg.wav + art/bg.png + art/bg_125x.png + art/bg_150x.png + art/bg_200x.png + art/sprite.png + art/sprite_125x.png + art/sprite_150x.png + art/sprite_200x.png + art/emoji.png + art/emoji_125x.png + art/emoji_150x.png + art/emoji_200x.png + art/blank.gif + art/iconround256.png + art/ThoolikaTrditionalUnicode.ttf + + + art/chatcolor1.png + art/chatcolor2.png + art/chatcolor3.png + art/chatcolor4.png + art/usercolor1.png + art/usercolor2.png + art/usercolor3.png + art/usercolor4.png + art/usercolor5.png + art/usercolor6.png + art/usercolor7.png + art/usercolor8.png + + + qmime/freedesktop.org.xml + + diff --git a/Telegram/SourceFiles/title.cpp b/Telegram/SourceFiles/title.cpp new file mode 100644 index 000000000..b2528b795 --- /dev/null +++ b/Telegram/SourceFiles/title.cpp @@ -0,0 +1,226 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "lang.h" +#include "style.h" + +#include "title.h" +#include "mainwidget.h" +#include "window.h" +#include "application.h" +#include "boxes/contactsbox.h" +#include "boxes/aboutbox.h" + +TitleHider::TitleHider(QWidget *parent) : QWidget(parent), _level(0) { +} + +void TitleHider::paintEvent(QPaintEvent *e) { + QPainter p(this); + p.setOpacity(_level * st::layerAlpha); + p.fillRect(App::main()->dlgsWidth() - 1, 0, width() - App::main()->dlgsWidth(), height(), st::layerBG->b); +} + +void TitleHider::mousePressEvent(QMouseEvent *e) { + if (e->button() == Qt::LeftButton) { + emit static_cast(parentWidget())->hiderClicked(); + } +} + +void TitleHider::setLevel(float64 level) { + _level = level; + update(); +} + +TitleWidget::TitleWidget(Window *window) + : QWidget(window) + , wnd(window) + , availWidth(460) + , _settings(this, lang(lng_menu_settings), st::titleTextButton) + , _contacts(this, lang(lng_menu_contacts), st::titleTextButton) + , _about(this, lang(lng_menu_about), st::titleTextButton) + , _update(this, window) + , _minimize(this, window) + , _maximize(this, window) + , _restore(this, window) + , _close(this, window) + , lastMaximized(!(window->windowState() & Qt::WindowMaximized)) + , hider(0) + , hideLevel(0) { + + setGeometry(0, 0, wnd->width(), st::titleHeight); + stateChanged(); + + if (App::app()->updatingState() == Application::UpdatingReady) { + _update.show(); + } else { + _update.hide(); + } + + connect(&_settings, SIGNAL(clicked()), window, SLOT(showSettings())); + connect(&_contacts, SIGNAL(clicked()), this, SLOT(onContacts())); + connect(&_about, SIGNAL(clicked()), this, SLOT(onAbout())); + connect(wnd->windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(stateChanged(Qt::WindowState))); + connect(App::app(), SIGNAL(updateReady()), this, SLOT(showUpdateBtn())); +} + +void TitleWidget::paintEvent(QPaintEvent *e) { + QPainter p(this); + + p.fillRect(QRect(0, 0, width(), st::titleHeight), st::titleBG->b); + p.drawPixmap(st::titleIconPos, App::sprite(), st::titleIconRect); +} + +void TitleWidget::setHideLevel(float64 level) { + if (level != hideLevel) { + hideLevel = level; + if (hideLevel) { + if (!hider) { + hider = new TitleHider(this); + hider->move(0, 0); + hider->resize(size()); + hider->show(); + } + hider->setLevel(hideLevel); + } else { + if (hider) hider->deleteLater(); + hider = 0; + } + } +} + +void TitleWidget::onContacts() { + if (!App::self()) return; + App::wnd()->showLayer(new ContactsBox()); +} + +void TitleWidget::onAbout() { + App::wnd()->showLayer(new AboutBox()); +} + +TitleWidget::~TitleWidget() { + delete hider; + hider = 0; +} + +void TitleWidget::resizeEvent(QResizeEvent *e) { + QPoint p(width() - (lastMaximized ? 0 : st::sysBtnDelta), 0); + + p.setX(p.x() - _close.width()); + _close.move(p); + + p.setX(p.x() - _maximize.width()); + _restore.move(p); _maximize.move(p); + + p.setX(p.x() - _minimize.width()); + _minimize.move(p); + + if (!_update.isHidden()) { + p.setX(p.x() - _update.width()); + _update.move(p); + } + + _settings.move(st::titleMenuOffset, 0); + if (MTP::authedId()) { + _contacts.show(); + _contacts.move(_settings.x() + _settings.width(), 0); + _about.move(_contacts.x() + _contacts.width(), 0); + } else { + _contacts.hide(); + _about.move(_settings.x() + _settings.width(), 0); + } + + if (hider) hider->resize(size()); +} + +void TitleWidget::mousePressEvent(QMouseEvent *e) { + if (wnd->psHandleTitle()) return; + if (e->buttons() & Qt::LeftButton) { + wnd->wStartDrag(e); + e->accept(); + } +} + +void TitleWidget::mouseDoubleClickEvent(QMouseEvent *e) { + if (wnd->psHandleTitle()) return; + Qt::WindowStates s(wnd->windowState()); + if (s.testFlag(Qt::WindowMaximized)) { + wnd->setWindowState(s & ~Qt::WindowMaximized); + } else { + wnd->setWindowState(s | Qt::WindowMaximized); + } +} + +void TitleWidget::stateChanged(Qt::WindowState state) { + if (state == Qt::WindowMinimized) return; + maximizedChanged(state == Qt::WindowMaximized); +} + +void TitleWidget::showUpdateBtn() { + if (App::app()->updatingState() == Application::UpdatingReady || cEvalScale(cConfigScale()) != cEvalScale(cRealScale())) { + _update.show(); + } else { + _update.hide(); + } + resizeEvent(0); + update(); +} + +void TitleWidget::maximizedChanged(bool maximized) { + if (lastMaximized == maximized) return; + + lastMaximized = maximized; + if (maximized) { + _maximize.clearState(); + } else { + _restore.clearState(); + } + + _maximize.setVisible(!maximized); + _restore.setVisible(maximized); + + resizeEvent(0); +} + +HitTestType TitleWidget::hitTest(const QPoint &p) { + if (App::wnd() && App::wnd()->layerShown()) return HitTestNone; + + int x(p.x()), y(p.y()), w(width()), h(height() - st::titleShadow); + if (hider && x >= App::main()->dlgsWidth()) return HitTestNone; + + if (x >= st::titleIconPos.x() && y >= st::titleIconPos.y() && x < st::titleIconPos.x() + st::titleIconRect.width() && y < st::titleIconPos.y() + st::titleIconRect.height()) { + return HitTestIcon; + } else if (false + || (_update.hitTest(p - _update.geometry().topLeft()) == HitTestSysButton) && _update.isVisible() + || (_minimize.hitTest(p - _minimize.geometry().topLeft()) == HitTestSysButton) + || (_maximize.hitTest(p - _maximize.geometry().topLeft()) == HitTestSysButton) + || (_restore.hitTest(p - _restore.geometry().topLeft()) == HitTestSysButton) + || (_close.hitTest(p - _close.geometry().topLeft()) == HitTestSysButton) + ) { + return HitTestSysButton; + } else if (x >= 0 && x < w && y >= 0 && y < h) { + if (false + || _settings.geometry().contains(x, y) + || !_contacts.isHidden() && _contacts.geometry().contains(x, y) + || _about.geometry().contains(x, y) + ) { + return HitTestClient; + } + return HitTestCaption; + } + return HitTestNone; +} diff --git a/Telegram/SourceFiles/title.h b/Telegram/SourceFiles/title.h new file mode 100644 index 000000000..75aa58b54 --- /dev/null +++ b/Telegram/SourceFiles/title.h @@ -0,0 +1,91 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +#include +#include "sysbuttons.h" + +class Window; + +class TitleHider : public QWidget { +public: + + TitleHider(QWidget *parent); + void paintEvent(QPaintEvent *e); + void mousePressEvent(QMouseEvent *e); + void setLevel(float64 level); + +private: + + float64 _level; + +}; + +class TitleWidget : public QWidget { + Q_OBJECT + +public: + + TitleWidget(Window *parent); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + + void mousePressEvent(QMouseEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); + + void maximizedChanged(bool maximized); + + HitTestType hitTest(const QPoint &p); + + void setHideLevel(float64 level); + + ~TitleWidget(); + +public slots: + + void stateChanged(Qt::WindowState state = Qt::WindowNoState); + void showUpdateBtn(); + void onContacts(); + void onAbout(); + +signals: + + void hiderClicked(); + +private: + + Window *wnd; + + style::color statusColor; + + float64 hideLevel; + TitleHider *hider; + + FlatButton _settings, _contacts, _about; + + UpdateBtn _update; + MinimizeBtn _minimize; + MaximizeBtn _maximize; + RestoreBtn _restore; + CloseBtn _close; + + int32 availWidth; + + bool lastMaximized; + +}; diff --git a/Telegram/SourceFiles/types.cpp b/Telegram/SourceFiles/types.cpp new file mode 100644 index 000000000..1ae96b393 --- /dev/null +++ b/Telegram/SourceFiles/types.cpp @@ -0,0 +1,874 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" + +#ifdef Q_OS_MAC +#include +#endif + +#ifdef Q_OS_LINUX +#include +#endif + +#include + +// Base types compile-time check + +namespace { + template + class _TypeSizeCheckerHelper { + public: + _TypeSizeCheckerHelper() { +#ifndef Q_OS_MAC + _BadTypeSize field; +#endif + } + }; + + template + class _TypeSizeCheckerHelper { + public: + _TypeSizeCheckerHelper() { + } + }; + + template + class _TypeSizeChecker { + _TypeSizeCheckerHelper checker; + }; + + void _typesCheck() { + _TypeSizeChecker(); + _TypeSizeChecker(); + _TypeSizeChecker(); + _TypeSizeChecker(); + _TypeSizeChecker(); + _TypeSizeChecker(); + _TypeSizeChecker(); + _TypeSizeChecker(); + _TypeSizeChecker(); + _TypeSizeChecker(); + + _TypeSizeChecker(); + _TypeSizeChecker(); + _TypeSizeChecker(); + _TypeSizeChecker(); + _TypeSizeChecker(); + _TypeSizeChecker(); + } +} + +// Unixtime functions + +namespace { + QReadWriteLock unixtimeLock; + volatile int32 unixtimeDelta = 0; + volatile bool unixtimeWasSet = false; + volatile uint64 msgIdStart, msgIdLocal = 0; + uint32 _reqId = 0; +} + +int32 myunixtime() { + return (int32)time(NULL); +} + +void unixtimeSet(int32 serverTime, bool force) { + QWriteLocker locker(&unixtimeLock); + if (force) { + DEBUG_LOG(("MTP Info: forced setting client unixtime to %1").arg(serverTime)); + } else { + if (unixtimeWasSet) return; + DEBUG_LOG(("MTP Info: setting client unixtime to %1").arg(serverTime)); + } + unixtimeWasSet = true; + unixtimeDelta = serverTime + 1 - myunixtime(); +} + +int32 unixtime() { + int32 result = myunixtime(); + + QReadLocker locker(&unixtimeLock); + return result + unixtimeDelta; +} + +int32 fromServerTime(const MTPint &serverTime) { + QReadLocker locker(&unixtimeLock); + return serverTime.v - unixtimeDelta; +} + +MTPint toServerTime(const int32 &clientTime) { + QReadLocker locker(&unixtimeLock); + return MTP_int(clientTime + unixtimeDelta); +} + +// Precise timing functions / rand init + +namespace { + float64 _msFreq; + float64 _msgIdCoef; + uint64 _msStart = 0; + + class _MsInitializer { + public: + _MsInitializer() { +#ifdef Q_OS_WIN + LARGE_INTEGER li; + QueryPerformanceFrequency(&li); + _msFreq = 1000. / float64(li.QuadPart); + + // 0xFFFF0000L istead of 0x100000000L to make msgId grow slightly slower, than unixtime and we had time to reconfigure + _msgIdCoef = float64(0xFFFF0000L) / float64(li.QuadPart); + + QueryPerformanceCounter(&li); + _msStart = li.QuadPart; +#elif defined Q_OS_MAC + mach_timebase_info_data_t tb = { 0 }; + mach_timebase_info(&tb); + _msFreq = (float64(tb.numer) / tb.denom) / 1000000.; + + _msgIdCoef = _msFreq * (float64(0xFFFF0000L) / 1000.); + + _msStart = mach_absolute_time(); +#else + timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + _msStart = 1000000000 * uint64(ts.tv_sec) + uint64(ts.tv_nsec); +#endif + + srand((uint32)(_msStart & 0xFFFFFFFFL)); + if (!RAND_status()) { // should be always inited in all modern OS + char buf[16]; + memcpy(buf, &_msStart, 8); + memcpy(buf + 8, &_msFreq, 8); + uchar sha1Buffer[20]; + RAND_seed(hashSha1(buf, 16, sha1Buffer), 20); + if (!RAND_status()) { + LOG(("MTP Error: Could not init OpenSSL rand, RAND_status() is 0..")); + } + } + } + }; + + class _MsgIdInitializer { + public: + _MsgIdInitializer() { + uint32 msgIdRand; + memset_rand(&msgIdRand, sizeof(uint32)); + msgIdStart = (((uint64)((uint32)time(NULL)) << 32) | (uint64)msgIdRand); + } + }; + + void _msInitialize() { + static _MsInitializer _msInitializer; + } + + void _msgIdInitialize() { + static _MsgIdInitializer _msgIdInitializer; + } + + class _MsStarter { + public: + _MsStarter() { + getms(); + } + }; + _MsStarter _msStarter; +} + +uint64 getms() { + _msInitialize(); +#ifdef Q_OS_WIN + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + return (uint64)((li.QuadPart - _msStart) * _msFreq); +#elif defined Q_OS_MAC + uint64 msCount = mach_absolute_time(); + return (uint64)((msCount - _msStart) * _msFreq); +#else + timespec ts; + int res = clock_gettime(CLOCK_REALTIME, &ts); + if (res != 0) { + LOG(("Bad clock_gettime result: %1").arg(res)); + return 0; + } + uint64 msCount = 1000000000 * uint64(ts.tv_sec) + uint64(ts.tv_nsec); + return (uint64)((msCount - _msStart) / 1000000); +#endif +} + +uint64 msgid() { + _msInitialize(); + _msgIdInitialize(); + +#ifdef Q_OS_WIN + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + uint64 result = msgIdStart + (uint64)floor((li.QuadPart - _msStart) * _msgIdCoef); +#elif defined Q_OS_MAC + uint64 msCount = mach_absolute_time(); + uint64 result = msgIdStart + (uint64)floor((msCount - _msStart) * _msgIdCoef); +#else + uint64 result = 0; + //TODO +#endif + + result &= ~0x03L; + + QWriteLocker locker(&unixtimeLock); + return result + ((uint64)unixtimeDelta << 32) + (msgIdLocal += 4); +} + +uint32 reqid() { + QWriteLocker locker(&unixtimeLock); + return ++_reqId; +} + +// crc32 hash, taken somewhere from the internet + +namespace { + uint32 _crc32Table[256]; + class _Crc32Initializer { + public: + _Crc32Initializer() { + uint32 poly = 0x04c11db7; + for (uint32 i = 0; i < 256; ++i) { + _crc32Table[i] = reflect(i, 8) << 24; + for (uint32 j = 0; j < 8; ++j) { + _crc32Table[i] = (_crc32Table[i] << 1) ^ (_crc32Table[i] & (1 << 31) ? poly : 0); + } + _crc32Table[i] = reflect(_crc32Table[i], 32); + } + } + + private: + uint32 reflect(uint32 val, char ch) { + uint32 result = 0; + for (int i = 1; i < (ch + 1); ++i) { + if (val & 1) { + result |= 1 << (ch - i); + } + val >>= 1; + } + return result; + } + }; +} + +int32 hashCrc32(const void *data, uint32 len) { + static _Crc32Initializer _crc32Initializer; + + const uchar *buf = (const uchar *)data; + + uint32 crc(0xffffffff); + for (uint32 i = 0; i < len; ++i) { + crc = (crc >> 8) ^ _crc32Table[(crc & 0xFF) ^ buf[i]]; + } + + return crc ^ 0xffffffff; +} + +// sha1 hash, taken somewhere from the internet + +namespace{ + inline uint32 sha1Shift(uint32 v, uint32 shift) { + return ((v << shift) | (v >> (32 - shift))); + } + void sha1PartHash(uint32 *sha, uint32 *temp) + { + uint32 a = sha[0], b = sha[1], c = sha[2], d = sha[3], e = sha[4], round = 0; + + #define _shiftswap(f, v) { \ + uint32 t = sha1Shift(a, 5) + (f) + e + v + temp[round]; \ + e = d; \ + d = c; \ + c = sha1Shift(b, 30); \ + b = a; \ + a = t; \ + ++round; \ + } + #define _shiftshiftswap(f, v) { \ + temp[round] = sha1Shift((temp[round - 3] ^ temp[round - 8] ^ temp[round - 14] ^ temp[round - 16]), 1); \ + _shiftswap(f, v) \ + } + + while (round < 16) _shiftswap((b & c) | (~b & d), 0x5a827999) + while (round < 20) _shiftshiftswap((b & c) | (~b & d), 0x5a827999) + while (round < 40) _shiftshiftswap(b ^ c ^ d, 0x6ed9eba1) + while (round < 60) _shiftshiftswap((b & c) | (b & d) | (c & d), 0x8f1bbcdc) + while (round < 80) _shiftshiftswap(b ^ c ^ d, 0xca62c1d6) + + #undef _shiftshiftswap + #undef _shiftswap + + sha[0] += a; + sha[1] += b; + sha[2] += c; + sha[3] += d; + sha[4] += e; + } +} + +int32 *hashSha1(const void *data, uint32 len, void *dest) { + const uchar *buf = (const uchar *)data; + + uint32 temp[80], block = 0, end; + uint32 sha[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; + for (end = block + 64; block + 64 <= len; end = block + 64) { + for (uint32 i = 0; block < end; block += 4) { + temp[i++] = (uint32) buf[block + 3] + | (((uint32) buf[block + 2]) << 8) + | (((uint32) buf[block + 1]) << 16) + | (((uint32) buf[block]) << 24); + } + sha1PartHash(sha, temp); + } + + end = len - block; + memset(temp, 0, sizeof(uint32) * 16); + uint32 last = 0; + for (; last < end; ++last) { + temp[last >> 2] |= (uint32)buf[last + block] << ((3 - (last & 0x03)) << 3); + } + temp[last >> 2] |= 0x80 << ((3 - (last & 3)) << 3); + if (end >= 56) { + sha1PartHash(sha, temp); + memset(temp, 0, sizeof(uint32) * 16); + } + temp[15] = len << 3; + sha1PartHash(sha, temp); + + uchar *sha1To = (uchar*)dest; + + for (int32 i = 19; i >= 0; --i) { + sha1To[i] = (sha[i >> 2] >> (((3 - i) & 0x03) << 3)) & 0xFF; + } + + return (int32*)sha1To; +} + +// md5 hash, taken somewhere from the internet + +namespace { + + inline void _md5_decode(uint32 *output, const uchar *input, uint32 len) { + for (uint32 i = 0, j = 0; j < len; i++, j += 4) { + output[i] = ((uint32)input[j]) | (((uint32)input[j + 1]) << 8) | (((uint32)input[j + 2]) << 16) | (((uint32)input[j + 3]) << 24); + } + } + + inline void _md5_encode(uchar *output, const uint32 *input, uint32 len) { + for (uint32 i = 0, j = 0; j < len; i++, j += 4) { + output[j + 0] = (input[i]) & 0xFF; + output[j + 1] = (input[i] >> 8) & 0xFF; + output[j + 2] = (input[i] >> 16) & 0xFF; + output[j + 3] = (input[i] >> 24) & 0xFF; + } + } + + inline uint32 _md5_rotate_left(uint32 x, int n) { + return (x << n) | (x >> (32 - n)); + } + + inline uint32 _md5_F(uint32 x, uint32 y, uint32 z) { + return x & y | ~x & z; + } + + inline uint32 _md5_G(uint32 x, uint32 y, uint32 z) { + return x & z | y & ~z; + } + + inline uint32 _md5_H(uint32 x, uint32 y, uint32 z) { + return x ^ y ^ z; + } + + inline uint32 _md5_I(uint32 x, uint32 y, uint32 z) { + return y ^ (x | ~z); + } + + inline void _md5_FF(uint32 &a, uint32 b, uint32 c, uint32 d, uint32 x, uint32 s, uint32 ac) { + a = _md5_rotate_left(a + _md5_F(b, c, d) + x + ac, s) + b; + } + + inline void _md5_GG(uint32 &a, uint32 b, uint32 c, uint32 d, uint32 x, uint32 s, uint32 ac) { + a = _md5_rotate_left(a + _md5_G(b, c, d) + x + ac, s) + b; + } + + inline void _md5_HH(uint32 &a, uint32 b, uint32 c, uint32 d, uint32 x, uint32 s, uint32 ac) { + a = _md5_rotate_left(a + _md5_H(b, c, d) + x + ac, s) + b; + } + + inline void _md5_II(uint32 &a, uint32 b, uint32 c, uint32 d, uint32 x, uint32 s, uint32 ac) { + a = _md5_rotate_left(a + _md5_I(b, c, d) + x + ac, s) + b; + } + + static uchar _md5_padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; +} + +HashMd5::HashMd5(const void *input, uint32 length) : _finalized(false) { + init(); + if (input && length > 0) feed(input, length); +} + +void HashMd5::feed(const void *input, uint32 length) { + uint32 index = _count[0] / 8 % _md5_block_size; + + const uchar *buf = (const uchar *)input; + + if ((_count[0] += (length << 3)) < (length << 3)) { + _count[1]++; + } + _count[1] += (length >> 29); + + uint32 firstpart = 64 - index; + + uint32 i; + + if (length >= firstpart) { + memcpy(&_buffer[index], buf, firstpart); + transform(_buffer); + + for (i = firstpart; i + _md5_block_size <= length; i += _md5_block_size) { + transform(&buf[i]); + } + + index = 0; + } else { + i = 0; + } + + memcpy(&_buffer[index], &buf[i], length - i); +} + +int32 *HashMd5::result() { + if (!_finalized) finalize(); + return (int32*)_digest; +} + +void HashMd5::init() { + _count[0] = 0; + _count[1] = 0; + + _state[0] = 0x67452301; + _state[1] = 0xefcdab89; + _state[2] = 0x98badcfe; + _state[3] = 0x10325476; +} + +void HashMd5::finalize() { + if (!_finalized) { + uchar bits[8]; + _md5_encode(bits, _count, 8); + + uint32 index = _count[0] / 8 % 64, paddingLen = (index < 56) ? (56 - index) : (120 - index); + feed(_md5_padding, paddingLen); + feed(bits, 8); + + _md5_encode(_digest, _state, 16); + + _finalized = true; + } +} + +void HashMd5::transform(const uchar *block) { + uint32 a = _state[0], b = _state[1], c = _state[2], d = _state[3], x[16]; + _md5_decode(x, block, _md5_block_size); + + _md5_FF(a, b, c, d, x[0] , 7 , 0xd76aa478); + _md5_FF(d, a, b, c, x[1] , 12, 0xe8c7b756); + _md5_FF(c, d, a, b, x[2] , 17, 0x242070db); + _md5_FF(b, c, d, a, x[3] , 22, 0xc1bdceee); + _md5_FF(a, b, c, d, x[4] , 7 , 0xf57c0faf); + _md5_FF(d, a, b, c, x[5] , 12, 0x4787c62a); + _md5_FF(c, d, a, b, x[6] , 17, 0xa8304613); + _md5_FF(b, c, d, a, x[7] , 22, 0xfd469501); + _md5_FF(a, b, c, d, x[8] , 7 , 0x698098d8); + _md5_FF(d, a, b, c, x[9] , 12, 0x8b44f7af); + _md5_FF(c, d, a, b, x[10], 17, 0xffff5bb1); + _md5_FF(b, c, d, a, x[11], 22, 0x895cd7be); + _md5_FF(a, b, c, d, x[12], 7 , 0x6b901122); + _md5_FF(d, a, b, c, x[13], 12, 0xfd987193); + _md5_FF(c, d, a, b, x[14], 17, 0xa679438e); + _md5_FF(b, c, d, a, x[15], 22, 0x49b40821); + + _md5_GG(a, b, c, d, x[1] , 5 , 0xf61e2562); + _md5_GG(d, a, b, c, x[6] , 9 , 0xc040b340); + _md5_GG(c, d, a, b, x[11], 14, 0x265e5a51); + _md5_GG(b, c, d, a, x[0] , 20, 0xe9b6c7aa); + _md5_GG(a, b, c, d, x[5] , 5 , 0xd62f105d); + _md5_GG(d, a, b, c, x[10], 9 , 0x2441453); + _md5_GG(c, d, a, b, x[15], 14, 0xd8a1e681); + _md5_GG(b, c, d, a, x[4] , 20, 0xe7d3fbc8); + _md5_GG(a, b, c, d, x[9] , 5 , 0x21e1cde6); + _md5_GG(d, a, b, c, x[14], 9 , 0xc33707d6); + _md5_GG(c, d, a, b, x[3] , 14, 0xf4d50d87); + _md5_GG(b, c, d, a, x[8] , 20, 0x455a14ed); + _md5_GG(a, b, c, d, x[13], 5 , 0xa9e3e905); + _md5_GG(d, a, b, c, x[2] , 9 , 0xfcefa3f8); + _md5_GG(c, d, a, b, x[7] , 14, 0x676f02d9); + _md5_GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); + + _md5_HH(a, b, c, d, x[5] , 4 , 0xfffa3942); + _md5_HH(d, a, b, c, x[8] , 11, 0x8771f681); + _md5_HH(c, d, a, b, x[11], 16, 0x6d9d6122); + _md5_HH(b, c, d, a, x[14], 23, 0xfde5380c); + _md5_HH(a, b, c, d, x[1] , 4 , 0xa4beea44); + _md5_HH(d, a, b, c, x[4] , 11, 0x4bdecfa9); + _md5_HH(c, d, a, b, x[7] , 16, 0xf6bb4b60); + _md5_HH(b, c, d, a, x[10], 23, 0xbebfbc70); + _md5_HH(a, b, c, d, x[13], 4 , 0x289b7ec6); + _md5_HH(d, a, b, c, x[0] , 11, 0xeaa127fa); + _md5_HH(c, d, a, b, x[3] , 16, 0xd4ef3085); + _md5_HH(b, c, d, a, x[6] , 23, 0x4881d05); + _md5_HH(a, b, c, d, x[9] , 4 , 0xd9d4d039); + _md5_HH(d, a, b, c, x[12], 11, 0xe6db99e5); + _md5_HH(c, d, a, b, x[15], 16, 0x1fa27cf8); + _md5_HH(b, c, d, a, x[2] , 23, 0xc4ac5665); + + _md5_II(a, b, c, d, x[0] , 6 , 0xf4292244); + _md5_II(d, a, b, c, x[7] , 10, 0x432aff97); + _md5_II(c, d, a, b, x[14], 15, 0xab9423a7); + _md5_II(b, c, d, a, x[5] , 21, 0xfc93a039); + _md5_II(a, b, c, d, x[12], 6 , 0x655b59c3); + _md5_II(d, a, b, c, x[3] , 10, 0x8f0ccc92); + _md5_II(c, d, a, b, x[10], 15, 0xffeff47d); + _md5_II(b, c, d, a, x[1] , 21, 0x85845dd1); + _md5_II(a, b, c, d, x[8] , 6 , 0x6fa87e4f); + _md5_II(d, a, b, c, x[15], 10, 0xfe2ce6e0); + _md5_II(c, d, a, b, x[6] , 15, 0xa3014314); + _md5_II(b, c, d, a, x[13], 21, 0x4e0811a1); + _md5_II(a, b, c, d, x[4] , 6 , 0xf7537e82); + _md5_II(d, a, b, c, x[11], 10, 0xbd3af235); + _md5_II(c, d, a, b, x[2] , 15, 0x2ad7d2bb); + _md5_II(b, c, d, a, x[9] , 21, 0xeb86d391); + + _state[0] += a; + _state[1] += b; + _state[2] += c; + _state[3] += d; +} + +int32 *hashMd5(const void *data, uint32 len, void *dest) { + HashMd5 md5(data, len); + memcpy(dest, md5.result(), 16); + + return (int32*)dest; +} + +char *hashMd5Hex(const int32 *hashmd5, void *dest) { + char *md5To = (char*)dest; + const uchar *res = (const uchar*)hashmd5; + + for (int i = 0; i < 16; ++i) { + uchar ch(res[i]), high = (ch >> 4) & 0x0F, low = ch & 0x0F; + md5To[i * 2 + 0] = high + ((high > 0x09) ? ('a' - 0x0A) : '0'); + md5To[i * 2 + 1] = low + ((low > 0x09) ? ('a' - 0x0A) : '0'); + } + + return md5To; +} + +void memset_rand(void *data, uint32 len) { + _msInitialize(); + RAND_bytes((uchar*)data, len); +} + +namespace { + QMap fastRusEng; + QHash fastLetterRusEng; + QMap fastDoubleLetterRusEng; + QHash fastRusKeyboardSwitch; +} + +QString translitLetterRusEng(QChar letter, QChar next, int32 &toSkip) { + if (fastDoubleLetterRusEng.isEmpty()) { + fastDoubleLetterRusEng.insert((QString::fromUtf8("Ы").at(0).unicode() << 16) | QString::fromUtf8("й").at(0).unicode(), qsl("Y")); + fastDoubleLetterRusEng.insert((QString::fromUtf8("и").at(0).unicode() << 16) | QString::fromUtf8("Ñ").at(0).unicode(), qsl("ia")); + fastDoubleLetterRusEng.insert((QString::fromUtf8("и").at(0).unicode() << 16) | QString::fromUtf8("й").at(0).unicode(), qsl("y")); + fastDoubleLetterRusEng.insert((QString::fromUtf8("к").at(0).unicode() << 16) | QString::fromUtf8("Ñ").at(0).unicode(), qsl("x")); + fastDoubleLetterRusEng.insert((QString::fromUtf8("Ñ‹").at(0).unicode() << 16) | QString::fromUtf8("й").at(0).unicode(), qsl("y")); + fastDoubleLetterRusEng.insert((QString::fromUtf8("ÑŒ").at(0).unicode() << 16) | QString::fromUtf8("е").at(0).unicode(), qsl("ye")); + } + QMap::const_iterator i = fastDoubleLetterRusEng.constFind((letter.unicode() << 16) | next.unicode()); + if (i != fastDoubleLetterRusEng.cend()) { + toSkip = 2; + return i.value(); + } + + toSkip = 1; + if (fastLetterRusEng.isEmpty()) { + fastLetterRusEng.insert(QString::fromUtf8("Ð").at(0), qsl("A")); + fastLetterRusEng.insert(QString::fromUtf8("Б").at(0), qsl("B")); + fastLetterRusEng.insert(QString::fromUtf8("Ð’").at(0), qsl("V")); + fastLetterRusEng.insert(QString::fromUtf8("Г").at(0), qsl("G")); + fastLetterRusEng.insert(QString::fromUtf8("Ò").at(0), qsl("G")); + fastLetterRusEng.insert(QString::fromUtf8("Д").at(0), qsl("D")); + fastLetterRusEng.insert(QString::fromUtf8("Е").at(0), qsl("E")); + fastLetterRusEng.insert(QString::fromUtf8("Є").at(0), qsl("Ye")); + fastLetterRusEng.insert(QString::fromUtf8("Ð").at(0), qsl("Yo")); + fastLetterRusEng.insert(QString::fromUtf8("Ж").at(0), qsl("Zh")); + fastLetterRusEng.insert(QString::fromUtf8("З").at(0), qsl("Z")); + fastLetterRusEng.insert(QString::fromUtf8("И").at(0), qsl("I")); + fastLetterRusEng.insert(QString::fromUtf8("Ї").at(0), qsl("Yi")); + fastLetterRusEng.insert(QString::fromUtf8("І").at(0), qsl("I")); + fastLetterRusEng.insert(QString::fromUtf8("Й").at(0), qsl("J")); + fastLetterRusEng.insert(QString::fromUtf8("К").at(0), qsl("K")); + fastLetterRusEng.insert(QString::fromUtf8("Л").at(0), qsl("L")); + fastLetterRusEng.insert(QString::fromUtf8("Ðœ").at(0), qsl("M")); + fastLetterRusEng.insert(QString::fromUtf8("Ð").at(0), qsl("N")); + fastLetterRusEng.insert(QString::fromUtf8("О").at(0), qsl("O")); + fastLetterRusEng.insert(QString::fromUtf8("П").at(0), qsl("P")); + fastLetterRusEng.insert(QString::fromUtf8("Р").at(0), qsl("R")); + fastLetterRusEng.insert(QString::fromUtf8("С").at(0), qsl("S")); + fastLetterRusEng.insert(QString::fromUtf8("Т").at(0), qsl("T")); + fastLetterRusEng.insert(QString::fromUtf8("У").at(0), qsl("U")); + fastLetterRusEng.insert(QString::fromUtf8("ÐŽ").at(0), qsl("W")); + fastLetterRusEng.insert(QString::fromUtf8("Ф").at(0), qsl("F")); + fastLetterRusEng.insert(QString::fromUtf8("Ð¥").at(0), qsl("Kh")); + fastLetterRusEng.insert(QString::fromUtf8("Ц").at(0), qsl("Ts")); + fastLetterRusEng.insert(QString::fromUtf8("Ч").at(0), qsl("Ch")); + fastLetterRusEng.insert(QString::fromUtf8("Ш").at(0), qsl("Sh")); + fastLetterRusEng.insert(QString::fromUtf8("Щ").at(0), qsl("Sch")); + fastLetterRusEng.insert(QString::fromUtf8("Э").at(0), qsl("E")); + fastLetterRusEng.insert(QString::fromUtf8("Ю").at(0), qsl("Yu")); + fastLetterRusEng.insert(QString::fromUtf8("Я").at(0), qsl("Ya")); + fastLetterRusEng.insert(QString::fromUtf8("ÐŽ").at(0), qsl("W")); + fastLetterRusEng.insert(QString::fromUtf8("а").at(0), qsl("a")); + fastLetterRusEng.insert(QString::fromUtf8("б").at(0), qsl("b")); + fastLetterRusEng.insert(QString::fromUtf8("в").at(0), qsl("v")); + fastLetterRusEng.insert(QString::fromUtf8("г").at(0), qsl("g")); + fastLetterRusEng.insert(QString::fromUtf8("Ò‘").at(0), qsl("g")); + fastLetterRusEng.insert(QString::fromUtf8("д").at(0), qsl("d")); + fastLetterRusEng.insert(QString::fromUtf8("е").at(0), qsl("e")); + fastLetterRusEng.insert(QString::fromUtf8("Ñ”").at(0), qsl("ye")); + fastLetterRusEng.insert(QString::fromUtf8("Ñ‘").at(0), qsl("yo")); + fastLetterRusEng.insert(QString::fromUtf8("ж").at(0), qsl("zh")); + fastLetterRusEng.insert(QString::fromUtf8("з").at(0), qsl("z")); + fastLetterRusEng.insert(QString::fromUtf8("й").at(0), qsl("y")); + fastLetterRusEng.insert(QString::fromUtf8("Ñ—").at(0), qsl("yi")); + fastLetterRusEng.insert(QString::fromUtf8("Ñ–").at(0), qsl("i")); + fastLetterRusEng.insert(QString::fromUtf8("л").at(0), qsl("l")); + fastLetterRusEng.insert(QString::fromUtf8("м").at(0), qsl("m")); + fastLetterRusEng.insert(QString::fromUtf8("н").at(0), qsl("n")); + fastLetterRusEng.insert(QString::fromUtf8("о").at(0), qsl("o")); + fastLetterRusEng.insert(QString::fromUtf8("п").at(0), qsl("p")); + fastLetterRusEng.insert(QString::fromUtf8("Ñ€").at(0), qsl("r")); + fastLetterRusEng.insert(QString::fromUtf8("Ñ").at(0), qsl("s")); + fastLetterRusEng.insert(QString::fromUtf8("Ñ‚").at(0), qsl("t")); + fastLetterRusEng.insert(QString::fromUtf8("у").at(0), qsl("u")); + fastLetterRusEng.insert(QString::fromUtf8("Ñž").at(0), qsl("w")); + fastLetterRusEng.insert(QString::fromUtf8("Ñ„").at(0), qsl("f")); + fastLetterRusEng.insert(QString::fromUtf8("Ñ…").at(0), qsl("kh")); + fastLetterRusEng.insert(QString::fromUtf8("ц").at(0), qsl("ts")); + fastLetterRusEng.insert(QString::fromUtf8("ч").at(0), qsl("ch")); + fastLetterRusEng.insert(QString::fromUtf8("ш").at(0), qsl("sh")); + fastLetterRusEng.insert(QString::fromUtf8("щ").at(0), qsl("sch")); + fastLetterRusEng.insert(QString::fromUtf8("ÑŠ").at(0), qsl("")); + fastLetterRusEng.insert(QString::fromUtf8("Ñ").at(0), qsl("e")); + fastLetterRusEng.insert(QString::fromUtf8("ÑŽ").at(0), qsl("yu")); + fastLetterRusEng.insert(QString::fromUtf8("Ñ").at(0), qsl("ya")); + fastLetterRusEng.insert(QString::fromUtf8("Ñž").at(0), qsl("w")); + fastLetterRusEng.insert(QString::fromUtf8("Ы").at(0), qsl("Y")); + fastLetterRusEng.insert(QString::fromUtf8("и").at(0), qsl("i")); + fastLetterRusEng.insert(QString::fromUtf8("к").at(0), qsl("k")); + fastLetterRusEng.insert(QString::fromUtf8("Ñ‹").at(0), qsl("y")); + fastLetterRusEng.insert(QString::fromUtf8("ÑŒ").at(0), qsl("")); + } + QHash::const_iterator j = fastLetterRusEng.constFind(letter); + if (j != fastLetterRusEng.cend()) { + return j.value(); + } + return QString(1, letter); +} + +QString translitRusEng(const QString &rus) { + if (fastRusEng.isEmpty()) { + fastRusEng.insert(QString::fromUtf8("ÐлекÑандр"), qsl("Alexander")); + fastRusEng.insert(QString::fromUtf8("алекÑандр"), qsl("alexander")); + fastRusEng.insert(QString::fromUtf8("Филипп"), qsl("Philip")); + fastRusEng.insert(QString::fromUtf8("филипп"), qsl("philip")); + fastRusEng.insert(QString::fromUtf8("Пётр"), qsl("Petr")); + fastRusEng.insert(QString::fromUtf8("пётр"), qsl("petr")); + fastRusEng.insert(QString::fromUtf8("Гай"), qsl("Gai")); + fastRusEng.insert(QString::fromUtf8("гай"), qsl("gai")); + fastRusEng.insert(QString::fromUtf8("Ильин"), qsl("Ilyin")); + fastRusEng.insert(QString::fromUtf8("ильин"), qsl("ilyin")); + } + QMap::const_iterator i = fastRusEng.constFind(rus); + if (i != fastRusEng.cend()) { + return i.value(); + } + + QString result; + result.reserve(rus.size() * 2); + + int32 toSkip = 0; + for (QString::const_iterator i = rus.cbegin(), e = rus.cend(); i != e;) { + i += toSkip; + result += translitLetterRusEng(*i, (i + 1 == e) ? ' ' : *(i + 1), toSkip); + } + return result; +} + +QString rusKeyboardLayoutSwitch(const QString &from) { + if (fastRusKeyboardSwitch.isEmpty()) { + fastRusKeyboardSwitch.insert('Q', QString::fromUtf8("Й").at(0)); + fastRusKeyboardSwitch.insert('W', QString::fromUtf8("Ц").at(0)); + fastRusKeyboardSwitch.insert('E', QString::fromUtf8("У").at(0)); + fastRusKeyboardSwitch.insert('R', QString::fromUtf8("К").at(0)); + fastRusKeyboardSwitch.insert('T', QString::fromUtf8("Е").at(0)); + fastRusKeyboardSwitch.insert('Y', QString::fromUtf8("Ð").at(0)); + fastRusKeyboardSwitch.insert('U', QString::fromUtf8("Г").at(0)); + fastRusKeyboardSwitch.insert('I', QString::fromUtf8("Ш").at(0)); + fastRusKeyboardSwitch.insert('O', QString::fromUtf8("Щ").at(0)); + fastRusKeyboardSwitch.insert('P', QString::fromUtf8("З").at(0)); + fastRusKeyboardSwitch.insert('{', QString::fromUtf8("Ð¥").at(0)); + fastRusKeyboardSwitch.insert('}', QString::fromUtf8("Ъ").at(0)); + fastRusKeyboardSwitch.insert('A', QString::fromUtf8("Ф").at(0)); + fastRusKeyboardSwitch.insert('S', QString::fromUtf8("Ы").at(0)); + fastRusKeyboardSwitch.insert('D', QString::fromUtf8("Ð’").at(0)); + fastRusKeyboardSwitch.insert('F', QString::fromUtf8("Ð").at(0)); + fastRusKeyboardSwitch.insert('G', QString::fromUtf8("П").at(0)); + fastRusKeyboardSwitch.insert('H', QString::fromUtf8("Р").at(0)); + fastRusKeyboardSwitch.insert('J', QString::fromUtf8("О").at(0)); + fastRusKeyboardSwitch.insert('K', QString::fromUtf8("Л").at(0)); + fastRusKeyboardSwitch.insert('L', QString::fromUtf8("Д").at(0)); + fastRusKeyboardSwitch.insert(':', QString::fromUtf8("Ж").at(0)); + fastRusKeyboardSwitch.insert('"', QString::fromUtf8("Э").at(0)); + fastRusKeyboardSwitch.insert('Z', QString::fromUtf8("Я").at(0)); + fastRusKeyboardSwitch.insert('X', QString::fromUtf8("Ч").at(0)); + fastRusKeyboardSwitch.insert('C', QString::fromUtf8("С").at(0)); + fastRusKeyboardSwitch.insert('V', QString::fromUtf8("Ðœ").at(0)); + fastRusKeyboardSwitch.insert('B', QString::fromUtf8("И").at(0)); + fastRusKeyboardSwitch.insert('N', QString::fromUtf8("Т").at(0)); + fastRusKeyboardSwitch.insert('M', QString::fromUtf8("Ь").at(0)); + fastRusKeyboardSwitch.insert('<', QString::fromUtf8("Б").at(0)); + fastRusKeyboardSwitch.insert('>', QString::fromUtf8("Ю").at(0)); + fastRusKeyboardSwitch.insert('q', QString::fromUtf8("й").at(0)); + fastRusKeyboardSwitch.insert('w', QString::fromUtf8("ц").at(0)); + fastRusKeyboardSwitch.insert('e', QString::fromUtf8("у").at(0)); + fastRusKeyboardSwitch.insert('r', QString::fromUtf8("к").at(0)); + fastRusKeyboardSwitch.insert('t', QString::fromUtf8("е").at(0)); + fastRusKeyboardSwitch.insert('y', QString::fromUtf8("н").at(0)); + fastRusKeyboardSwitch.insert('u', QString::fromUtf8("г").at(0)); + fastRusKeyboardSwitch.insert('i', QString::fromUtf8("ш").at(0)); + fastRusKeyboardSwitch.insert('o', QString::fromUtf8("щ").at(0)); + fastRusKeyboardSwitch.insert('p', QString::fromUtf8("з").at(0)); + fastRusKeyboardSwitch.insert('[', QString::fromUtf8("Ñ…").at(0)); + fastRusKeyboardSwitch.insert(']', QString::fromUtf8("ÑŠ").at(0)); + fastRusKeyboardSwitch.insert('a', QString::fromUtf8("Ñ„").at(0)); + fastRusKeyboardSwitch.insert('s', QString::fromUtf8("Ñ‹").at(0)); + fastRusKeyboardSwitch.insert('d', QString::fromUtf8("в").at(0)); + fastRusKeyboardSwitch.insert('f', QString::fromUtf8("а").at(0)); + fastRusKeyboardSwitch.insert('g', QString::fromUtf8("п").at(0)); + fastRusKeyboardSwitch.insert('h', QString::fromUtf8("Ñ€").at(0)); + fastRusKeyboardSwitch.insert('j', QString::fromUtf8("о").at(0)); + fastRusKeyboardSwitch.insert('k', QString::fromUtf8("л").at(0)); + fastRusKeyboardSwitch.insert('l', QString::fromUtf8("д").at(0)); + fastRusKeyboardSwitch.insert(';', QString::fromUtf8("ж").at(0)); + fastRusKeyboardSwitch.insert('\'', QString::fromUtf8("Ñ").at(0)); + fastRusKeyboardSwitch.insert('z', QString::fromUtf8("Ñ").at(0)); + fastRusKeyboardSwitch.insert('x', QString::fromUtf8("ч").at(0)); + fastRusKeyboardSwitch.insert('c', QString::fromUtf8("Ñ").at(0)); + fastRusKeyboardSwitch.insert('v', QString::fromUtf8("м").at(0)); + fastRusKeyboardSwitch.insert('b', QString::fromUtf8("и").at(0)); + fastRusKeyboardSwitch.insert('n', QString::fromUtf8("Ñ‚").at(0)); + fastRusKeyboardSwitch.insert('m', QString::fromUtf8("ÑŒ").at(0)); + fastRusKeyboardSwitch.insert(',', QString::fromUtf8("б").at(0)); + fastRusKeyboardSwitch.insert('.', QString::fromUtf8("ÑŽ").at(0)); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Й").at(0), 'Q'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ц").at(0), 'W'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("У").at(0), 'E'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("К").at(0), 'R'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Е").at(0), 'T'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ð").at(0), 'Y'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Г").at(0), 'U'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ш").at(0), 'I'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Щ").at(0), 'O'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("З").at(0), 'P'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ð¥").at(0), '{'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ъ").at(0), '}'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ф").at(0), 'A'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ы").at(0), 'S'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ð’").at(0), 'D'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ð").at(0), 'F'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("П").at(0), 'G'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Р").at(0), 'H'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("О").at(0), 'J'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Л").at(0), 'K'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Д").at(0), 'L'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ж").at(0), ':'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Э").at(0), '"'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Я").at(0), 'Z'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ч").at(0), 'X'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("С").at(0), 'C'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ðœ").at(0), 'V'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("И").at(0), 'B'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Т").at(0), 'N'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ь").at(0), 'M'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Б").at(0), '<'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ю").at(0), '>'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("й").at(0), 'q'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("ц").at(0), 'w'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("у").at(0), 'e'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("к").at(0), 'r'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("е").at(0), 't'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("н").at(0), 'y'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("г").at(0), 'u'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("ш").at(0), 'i'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("щ").at(0), 'o'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("з").at(0), 'p'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ñ…").at(0), '['); + fastRusKeyboardSwitch.insert(QString::fromUtf8("ÑŠ").at(0), ']'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ñ„").at(0), 'a'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ñ‹").at(0), 's'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("в").at(0), 'd'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("а").at(0), 'f'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("п").at(0), 'g'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ñ€").at(0), 'h'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("о").at(0), 'j'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("л").at(0), 'k'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("д").at(0), 'l'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("ж").at(0), ';'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ñ").at(0), '\''); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ñ").at(0), 'z'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("ч").at(0), 'x'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ñ").at(0), 'c'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("м").at(0), 'v'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("и").at(0), 'b'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("Ñ‚").at(0), 'n'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("ÑŒ").at(0), 'm'); + fastRusKeyboardSwitch.insert(QString::fromUtf8("б").at(0), ','); + fastRusKeyboardSwitch.insert(QString::fromUtf8("ÑŽ").at(0), '.'); + } + + QString result; + result.reserve(from.size()); + for (QString::const_iterator i = from.cbegin(), e = from.cend(); i != e; ++i) { + QHash::const_iterator j = fastRusKeyboardSwitch.constFind(*i); + if (j == fastRusKeyboardSwitch.cend()) { + result += *i; + } else { + result += j.value(); + } + } + return result; +} diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h new file mode 100644 index 000000000..e82f71a18 --- /dev/null +++ b/Telegram/SourceFiles/types.h @@ -0,0 +1,285 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#pragma once + +//typedef unsigned char uchar; // Qt has uchar +typedef qint16 int16; +typedef quint16 uint16; +typedef qint32 int32; +typedef quint32 uint32; +typedef qint64 int64; +typedef quint64 uint64; + +#ifdef Q_OS_WIN +typedef float float32; +typedef double float64; +#else +typedef float float32; +typedef double float64; +#endif + +#include +#include + +#include + +#include + +using std::string; +using std::exception; +using std::swap; + +#include "logs.h" + +class Exception : public exception { +public: + + Exception(const QString &msg, bool isFatal = true) : _fatal(isFatal), _msg(msg) { + LOG(("Exception: %1").arg(msg)); + } + bool fatal() const { + return _fatal; + } + + virtual const char *what() const throw() { + return _msg.toUtf8().constData(); + } + virtual ~Exception() throw() { + } + +private: + bool _fatal; + QString _msg; +}; + +class MTPint; + +int32 myunixtime(); +void unixtimeSet(int32 servertime, bool force = false); +int32 unixtime(); +int32 fromServerTime(const MTPint &serverTime); +uint64 msgid(); +uint32 reqid(); + +inline QDateTime date(int32 time = -1) { + QDateTime result; + if (time >= 0) result.setTime_t(time); + return result; +} + +inline QDateTime date(const MTPint &time) { + return date(fromServerTime(time)); +} + +inline void mylocaltime(struct tm * _Tm, const time_t * _Time) { +#ifdef Q_OS_WIN + localtime_s(_Tm, _Time); +#else + localtime_r(_Time, _Tm); +#endif +} + +uint64 getms(); + +const static uint32 _md5_block_size = 64; +class HashMd5 { +public: + + HashMd5(const void *input = 0, uint32 length = 0); + void feed(const void *input, uint32 length); + int32 *result(); + +private: + + void init(); + void finalize(); + void transform(const uchar *block); + + bool _finalized; + uchar _buffer[_md5_block_size]; + uint32 _count[2]; + uint32 _state[4]; + uchar _digest[16]; + +}; + +int32 hashCrc32(const void *data, uint32 len); +int32 *hashSha1(const void *data, uint32 len, void *dest); // dest - ptr to 20 bytes, returns (int32*)dest +int32 *hashMd5(const void *data, uint32 len, void *dest); // dest = ptr to 16 bytes, returns (int32*)dest +char *hashMd5Hex(const int32 *hashmd5, void *dest); // dest = ptr to 32 bytes, returns (char*)dest +inline char *hashMd5Hex(const void *data, uint32 len, void *dest) { // dest = ptr to 32 bytes, returns (char*)dest + return hashMd5Hex(HashMd5(data, len).result(), dest); +} + +void memset_rand(void *data, uint32 len); + +class ReadLockerAttempt { +public: + + ReadLockerAttempt(QReadWriteLock *_lock) : success(_lock->tryLockForRead()), lock(_lock) { + } + ~ReadLockerAttempt() { + if (success) { + lock->unlock(); + } + } + + operator bool() const { + return success; + } + +private: + + bool success; + QReadWriteLock *lock; + +}; + +#define qsl(s) QStringLiteral(s) + +static const QRegularExpression::PatternOptions reMultiline(QRegularExpression::DotMatchesEverythingOption | QRegularExpression::MultilineOption); + +template +inline T snap(const T &v, const T &_min, const T &_max) { + return (v < _min) ? _min : ((v > _max) ? _max : v); +} + +template +class ManagedPtr { +public: + ManagedPtr() : ptr(0) { + } + ManagedPtr(T *p) : ptr(p) { + } + T *operator->() const { + return ptr; + } + T *v() const { + return ptr; + } + +protected: + + T *ptr; + typedef ManagedPtr Parent; +}; + +QString translitRusEng(const QString &rus); +QString rusKeyboardLayoutSwitch(const QString &from); + +enum DataBlockId { + dbiKey = 0, + dbiUser = 1, + dbiDcOption = 2, + dbiConfig1 = 3, + dbiMutePeer = 4, + dbiSendKey = 5, + dbiAutoStart = 6, + dbiStartMinimized = 7, + dbiSoundNotify = 8, + dbiWorkMode = 9, + dbiSeenTrayTooltip = 10, + dbiDesktopNotify = 11, + dbiAutoUpdate = 12, + dbiLastUpdateCheck = 13, + dbiWindowPosition = 14, + dbiConnectionType = 15, +// 16 reserved + dbiDefaultAttach = 17, + dbiCatsAndDogs = 18, + dbiReplaceEmojis = 19, + dbiAskDownloadPath = 20, + dbiDownloadPath = 21, + dbiScale = 22, + dbiEmojiTab = 23, + dbiRecentEmojis = 24, + dbiLoggedPhoneNumber = 25, + dbiMutedPeers = 26, +// 27 reserved + + dbiEncryptedWithSalt = 333, + dbiEncrypted = 444, + + dbiVersion = 666, +}; + +enum DBISendKey { + dbiskEnter = 0, + dbiskCtrlEnter = 1, +}; + +enum DBIWorkMode { + dbiwmWindowAndTray = 0, + dbiwmTrayOnly = 1, + dbiwmWindowOnly = 2, +}; + +enum DBIConnectionType { + dbictAuto = 0, + dbictHttpAuto = 1, // not used + dbictHttpProxy = 2, + dbictTcpProxy = 3, +}; + +enum DBIDefaultAttach { + dbidaDocument = 0, + dbidaPhoto = 1, +}; + +struct ConnectionProxy { + ConnectionProxy() : port(0) { + } + QString host; + uint32 port; + QString user, password; +}; + +enum DBIScale { + dbisAuto = 0, + dbisOne = 1, + dbisOneAndQuarter = 2, + dbisOneAndHalf = 3, + dbisTwo = 4, + + dbisScaleCount = 5, +}; + +enum DBIEmojiTab { + dbietRecent = -1, + dbietPeople = 0, + dbietNature = 1, + dbietObjects = 2, + dbietPlaces = 3, + dbietSymbols = 4, +}; + +typedef enum { + HitTestNone = 0, + HitTestClient, + HitTestSysButton, + HitTestIcon, + HitTestCaption, + HitTestTop, + HitTestTopRight, + HitTestRight, + HitTestBottomRight, + HitTestBottom, + HitTestBottomLeft, + HitTestLeft, + HitTestTopLeft, +} HitTestType; diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp new file mode 100644 index 000000000..2febf5bb3 --- /dev/null +++ b/Telegram/SourceFiles/window.cpp @@ -0,0 +1,654 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#include "stdafx.h" +#include "style.h" +#include "lang.h" + +#include "window.h" +#include "application.h" + +#include "pspecific.h" +#include "title.h" +#include "intro/intro.h" +#include "mainwidget.h" +#include "layerwidget.h" +#include "settingswidget.h" + +ConnectingWidget::ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect) : QWidget(parent), _reconnect(this, QString()), _shadow(st::boxShadow) { + set(text, reconnect); + connect(&_reconnect, SIGNAL(clicked()), this, SLOT(onReconnect())); +} + +void ConnectingWidget::set(const QString &text, const QString &reconnect) { + _text = text; + _textWidth = st::linkFont->m.width(_text) + st::linkFont->spacew; + int32 _reconnectWidth = 0; + if (reconnect.isEmpty()) { + _reconnect.hide(); + } else { + _reconnect.setText(reconnect); + _reconnect.show(); + _reconnect.move(st::connectingPadding.left() + _textWidth, st::boxShadow.height() + st::connectingPadding.top()); + _reconnectWidth = _reconnect.width(); + } + resize(st::connectingPadding.left() + _textWidth + _reconnectWidth + st::connectingPadding.right() + st::boxShadow.width(), st::boxShadow.height() + st::connectingPadding.top() + st::linkFont->height + st::connectingPadding.bottom()); + update(); +} +void ConnectingWidget::paintEvent(QPaintEvent *e) { + QPainter p(this); + + _shadow.paint(p, QRect(0, st::boxShadow.height(), width() - st::boxShadow.width(), height() - st::boxShadow.height()), QPoint(0, 0), BoxShadow::Top | BoxShadow::Right); + p.fillRect(0, st::boxShadow.height(), width() - st::boxShadow.width(), height() - st::boxShadow.height(), st::connectingBG->b); + p.setFont(st::linkFont->f); + p.setPen(st::connectingColor->p); + p.drawText(st::connectingPadding.left(), st::boxShadow.height() + st::connectingPadding.top() + st::linkFont->ascent, _text); +} + +void ConnectingWidget::onReconnect() { + MTP::restart(); +} + +TempDirDeleter::TempDirDeleter(QThread *thread) { + moveToThread(thread); + connect(thread, SIGNAL(started()), this, SLOT(onStart())); +} + +void TempDirDeleter::onStart() { + if (QDir(cTempDir()).removeRecursively()) { + emit succeed(); + } else { + emit failed(); + } +} + +Window::Window(QWidget *parent) : PsMainWindow(parent), + dragging(false), intro(0), main(0), settings(0), layer(0), layerBG(0), myIcon(QPixmap::fromImage(icon256)), _topWidget(0), + _connecting(0), _inactivePress(false), _tempDeleter(0), _tempDeleterThread(0) { + + if (objectName().isEmpty()) + setObjectName(qsl("MainWindow")); + resize(st::wndDefWidth, st::wndDefHeight); + setWindowOpacity(1); + setLocale(QLocale(QLocale::English, QLocale::UnitedStates)); + centralwidget = new QWidget(this); + centralwidget->setObjectName(qsl("centralwidget")); + setCentralWidget(centralwidget); + + QMetaObject::connectSlotsByName(this); + + _inactiveTimer.setSingleShot(true); + connect(&_inactiveTimer, SIGNAL(timeout()), this, SLOT(onInactiveTimer())); +} + +void Window::inactivePress(bool inactive) { + _inactivePress = inactive; + if (_inactivePress) { + _inactiveTimer.start(200); + } else { + _inactiveTimer.stop(); + } +} + +bool Window::inactivePress() const { + return _inactivePress; +} + +void Window::onInactiveTimer() { + inactivePress(false); +} + +void Window::init() { + psInitFrameless(); + setWindowIcon(myIcon); + + App::app()->installEventFilter(this); + + QPalette p(palette()); + p.setColor(QPalette::Window, st::wndBG->c); + setPalette(p); + + title = new TitleWidget(this); + + psInitSize(); + psUpdateWorkmode(); +} + +void Window::clearWidgets() { + layerHidden(); + if (settings) { + anim::stop(settings); + settings->hide(); + settings->deleteLater(); + settings = 0; + } + if (main) { + anim::stop(main); + main->hide(); + main->deleteLater(); + main = 0; + } + if (intro) { + anim::stop(intro); + intro->hide(); + intro->deleteLater(); + intro = 0; + } +} + +void Window::setupIntro(bool anim) { + if (intro && (intro->animating() || intro->isVisible()) && !main) return; + + QPixmap bg = grab(QRect(0, st::titleHeight, width(), height() - st::titleHeight)); + + clearWidgets(); + intro = new IntroWidget(this); + intro->move(0, st::titleHeight); + if (anim) { + intro->animShow(bg); + } + + fixOrder(); + + updateTitleStatus(); +} + +void Window::getNotifySetting(const MTPInputNotifyPeer &peer, uint32 msWait) { + MTP::send(MTPaccount_GetNotifySettings(peer), main->rpcDone(&MainWidget::gotNotifySetting, peer), main->rpcFail(&MainWidget::failNotifySetting, peer), 0, msWait); +} + +void Window::setupMain(bool anim) { + QPixmap bg = grab(QRect(0, st::titleHeight, width(), height() - st::titleHeight)); + clearWidgets(); + main = new MainWidget(this); + main->move(0, st::titleHeight); + if (anim) { + main->animShow(bg); + } else { + MTP::send(MTPusers_GetUsers(MTP_vector(QVector(1, MTP_inputUserSelf()))), main->rpcDone(&MainWidget::startFull)); + main->activate(); + } + + fixOrder(); + + updateTitleStatus(); +} + +void Window::showSettings() { + App::wnd()->hideLayer(); + if (settings) { + return hideSettings(); + } + QPixmap bg = grab(QRect(0, st::titleHeight, width(), height() - st::titleHeight)); + + if (intro) { + anim::stop(intro); + intro->hide(); + } else if (main) { + anim::stop(main); + main->hide(); + } + settings = new Settings(this); + settings->animShow(bg); + + fixOrder(); +} + +void Window::hideSettings(bool fast) { + if (!settings) return; + + if (fast) { + anim::stop(settings); + settings->hide(); + settings->deleteLater(); + settings = 0; + if (intro) { + intro->show(); + } else { + main->show(); + } + } else { + QPixmap bg = grab(QRect(0, st::titleHeight, width(), height() - st::titleHeight)); + + anim::stop(settings); + settings->hide(); + settings->deleteLater(); + settings = 0; + if (intro) { + intro->animShow(bg, true); + } else { + main->animShow(bg, true); + } + } + + fixOrder(); +} + +void Window::startMain(const MTPUser &user) { + if (main) main->start(user); + title->resizeEvent(0); +} + +void Window::mtpStateChanged(int32 dc, int32 state) { + if (dc == MTP::maindc()) { + updateTitleStatus(); + if (settings) settings->updateConnectionType(); + } +} + +void Window::updateTitleStatus() { + int32 state = MTP::dcstate(); + if (state == MTProtoConnection::Connecting || state == MTProtoConnection::Disconnected || state < 0 && state > -600) { + if (main || getms() > 5000 || _connecting) { + showConnecting(lang(lng_connecting)); + } + } else if (state < 0) { + showConnecting(lang(lng_reconnecting).arg((-state) / 1000), lang(lng_reconnecting_try_now)); + QTimer::singleShot((-state) % 1000, this, SLOT(updateTitleStatus())); + } else { + hideConnecting(); + } +} + +IntroWidget *Window::introWidget() { + return intro; +} + +MainWidget *Window::mainWidget() { + return main; +} + +Settings *Window::settingsWidget() { + return settings; +} + +void Window::showPhoto(const PhotoLink *lnk, HistoryItem *item) { + return showPhoto(lnk->photo(), item); +} + + +void Window::showPhoto(PhotoData *photo, HistoryItem *item) { + layerHidden(); + layer = new LayerWidget(this, photo, item); +} + +PhotoData *Window::photoShown() { + return layer ? layer->photoShown() : 0; +} + +/* +void Window::showVideo(const VideoOpenLink *lnk, HistoryItem *item) { + layerHidden(); + VideoData *video = App::video(lnk->video()); + layer = new LayerWidget(this, video, item); +} +/**/ +void Window::showLayer(LayeredWidget *w) { + layerHidden(); + layerBG = new BackgroundWidget(this, w); +} + +void Window::showConnecting(const QString &text, const QString &reconnect) { + if (_connecting) { + _connecting->set(text, reconnect); + } else { + _connecting = new ConnectingWidget(this, text, reconnect); + resizeEvent(0); + } +} + +void Window::hideConnecting() { + if (_connecting) { + _connecting->deleteLater(); + _connecting = 0; + } +} + +void Window::replaceLayer(LayeredWidget *w) { + if (layer) layer->deleteLater(); + layer = 0; + if (layerBG) { + layerBG->replaceInner(w); + } else { + layerBG = new BackgroundWidget(this, w); + } +} + +void Window::hideLayer() { + if (layerBG) { + layerBG->onClose(); + } +} + +bool Window::layerShown() { + return !!layerBG || !!_topWidget; +} + +bool Window::historyIsActive() const { + return psIsActive() && main && main->historyIsActive() && (!settings || !settings->isVisible()); +} + +void Window::checkHistoryActivation() { + if (main && MTP::authedId() && historyIsActive()) { + main->historyWasRead(); + } +} + +void Window::layerHidden() { + if (layer) layer->deleteLater(); + layer = 0; + if (layerBG) layerBG->deleteLater(); + layerBG = 0; + if (main) main->setInnerFocus(); +} + +QRect Window::clientRect() const { + return QRect(0, st::titleHeight, width(), height() - st::titleHeight); +} + +QRect Window::photoRect() const { + if (settings) { + return settings->geometry(); + } else if (main) { + QRect r(main->historyRect()); + r.moveLeft(r.left() + main->x()); + r.moveTop(r.top() + main->y()); + return r; + } + return QRect(0, 0, 0, 0); +} + +void Window::wStartDrag(QMouseEvent *e) { + dragStart = e->globalPos() - frameGeometry().topLeft(); + dragging = true; +} + +void Window::paintEvent(QPaintEvent *e) { +} + +HitTestType Window::hitTest(const QPoint &p) const { + int x(p.x()), y(p.y()), w(width()), h(height()); + + const uint32 raw = psResizeRowWidth(); + if (!windowState().testFlag(Qt::WindowMaximized)) { + if (y < raw) { + if (x < raw) { + return HitTestTopLeft; + } else if (x > w - raw - 1) { + return HitTestTopRight; + } + return HitTestTop; + } else if (y > h - raw - 1) { + if (x < raw) { + return HitTestBottomLeft; + } else if (x > w - raw - 1) { + return HitTestBottomRight; + } + return HitTestBottom; + } else if (x < raw) { + return HitTestLeft; + } else if (x > w - raw - 1) { + return HitTestRight; + } + } + HitTestType titleTest = title->hitTest(p - title->geometry().topLeft()); + if (titleTest && (!layer || titleTest != HitTestCaption)) { + return titleTest; + } else if (x >= 0 && y >= 0 && x < w && y < h) { + return HitTestClient; + } + return HitTestNone; +} + +bool Window::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { + if (main && main->getPhotoCoords(photo, x, y, w)) { + x += main->x(); + y += main->y(); + return true; + } else if (settings && settings->getPhotoCoords(photo, x, y, w)) { + x += main->x(); + y += main->y(); + return true; + } + return false; +} + +bool Window::getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const { + if (main && main->getVideoCoords(video, x, y, w)) { + x += main->x(); + y += main->y(); + return true; + } + return false; +} + +QRect Window::iconRect() const { + return QRect(st::titleIconPos + title->geometry().topLeft(), st::titleIconRect.size()); +} + +bool Window::eventFilter(QObject *obj, QEvent *evt) { + if (obj == App::app() && (evt->type() == QEvent::ApplicationActivate)) { + checkHistoryActivation(); + } + return PsMainWindow::eventFilter(obj, evt); +} + +void Window::mouseMoveEvent(QMouseEvent *e) { + if (e->buttons() & Qt::LeftButton) { + if (dragging) { + if (windowState().testFlag(Qt::WindowMaximized)) { + setWindowState(windowState() & ~Qt::WindowMaximized); + + dragStart = e->globalPos() - frameGeometry().topLeft(); + } else { + move(e->globalPos() - dragStart); + } + } + } else if (dragging) { + dragging = false; + } +} + +void Window::mouseReleaseEvent(QMouseEvent *e) { + dragging = false; +} + +bool Window::minimizeToTray() { + if (App::quiting() || !trayIcon) return false; + + hide(); + if (!cSeenTrayTooltip()) { + trayIcon->showMessage(QString::fromStdWString(AppName), lang(lng_tray_icon_text), QSystemTrayIcon::Information, 10000); + cSetSeenTrayTooltip(true); + App::writeConfig(); + } + if (App::main()) App::main()->setOnline(windowState()); + return true; +} + +void Window::setupTrayIcon() { + if (!trayIcon) { + if (trayIconMenu) trayIconMenu->deleteLater(); + trayIconMenu = new QMenu(this); + trayIconMenu->setFont(QFont("Tahoma")); + QAction *a; + a = trayIconMenu->addAction(lang(lng_open_from_tray), this, SLOT(showFromTray())); + a->setEnabled(true); + a = trayIconMenu->addAction(lang(lng_quit_from_tray), this, SLOT(quitFromTray())); + a->setEnabled(true); + + if (trayIcon) trayIcon->deleteLater(); + trayIcon = new QSystemTrayIcon(this); + trayIcon->setIcon(this->windowIcon()); + trayIcon->setContextMenu(trayIconMenu); + trayIcon->setToolTip(QString::fromStdWString(AppName)); + + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(toggleTray(QSystemTrayIcon::ActivationReason))); + connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showFromTray())); + } + psUpdateCounter(); + trayIcon->show(); +} + +void Window::quitFromTray() { + App::quit(); +} + +void Window::activate() { + bool wasHidden = !isVisible(); + setWindowState(windowState() & ~Qt::WindowMinimized); + setVisible(true); + activateWindow(); + if (wasHidden) { + if (main) { + main->windowShown(); + } + } +} + +void Window::noIntro(IntroWidget *was) { + if (was == intro) { + intro = 0; + } +} + +void Window::noSettings(Settings *was) { + if (was == settings) { + settings = 0; + } + checkHistoryActivation(); +} + +void Window::noMain(MainWidget *was) { + if (was == main) { + main = 0; + } +} + +void Window::noLayer(LayerWidget *was) { + if (was == layer) { + layer = 0; + } + fixOrder(); +} + +void Window::noBox(BackgroundWidget *was) { + if (was == layerBG) { + layerBG = 0; + } +} + +void Window::fixOrder() { + title->raise(); + if (layer) layer->raise(); + if (layerBG) layerBG->raise(); + if (_topWidget) _topWidget->raise(); + if (_connecting) _connecting->raise(); +} + +void Window::topWidget(QWidget *w) { + _topWidget = w; +} + +void Window::noTopWidget(QWidget *w) { + if (_topWidget == w) { + _topWidget = 0; + } +} + +void Window::showFromTray(QSystemTrayIcon::ActivationReason reason) { + if (reason != QSystemTrayIcon::Context) { + activate(); + setWindowIcon(myIcon); + psUpdateCounter(); + if (App::main()) App::main()->setOnline(windowState()); + } +} + +void Window::toggleTray(QSystemTrayIcon::ActivationReason reason) { + if (reason != QSystemTrayIcon::Context) { + if (psIsActive()) { + minimizeToTray(); + } else { + showFromTray(reason); + } + } +} + +void Window::closeEvent(QCloseEvent *e) { + if (MTP::authedId() && minimizeToTray()) { + e->ignore(); + } else { + App::quit(); + } +} + +TitleWidget *Window::getTitle() { + return title; +} + +void Window::resizeEvent(QResizeEvent *e) { + title->setGeometry(QRect(0, 0, width(), st::titleHeight + st::titleShadow)); + if (layer) layer->resize(width(), height()); + if (layerBG) layerBG->resize(width(), height()); + if (_connecting) _connecting->setGeometry(0, height() - _connecting->height(), _connecting->width(), _connecting->height()); + emit resized(QSize(width(), height() - st::titleHeight)); +} + +Window::TempDirState Window::tempDirState() { + if (_tempDeleter) { + return TempDirRemoving; + } + return QDir(cTempDir()).exists() ? TempDirExists : TempDirEmpty; +} + +void Window::tempDirDelete() { + if (_tempDeleter) return; + _tempDeleterThread = new QThread(); + _tempDeleter = new TempDirDeleter(_tempDeleterThread); + connect(_tempDeleter, SIGNAL(succeed()), this, SLOT(onTempDirCleared())); + connect(_tempDeleter, SIGNAL(failed()), this, SLOT(onTempDirClearFailed())); + _tempDeleterThread->start(); +} + +void Window::onTempDirCleared() { + _tempDeleter->deleteLater(); + _tempDeleter = 0; + _tempDeleterThread->deleteLater(); + _tempDeleterThread = 0; + emit tempDirCleared(); +} + +void Window::onTempDirClearFailed() { + _tempDeleter->deleteLater(); + _tempDeleter = 0; + _tempDeleterThread->deleteLater(); + _tempDeleterThread = 0; + emit tempDirClearFailed(); +} + +Window::~Window() { + delete _tempDeleter; + delete _tempDeleterThread; + delete _connecting; + delete trayIcon; + delete trayIconMenu; + delete intro; + delete main; + delete layer; + delete settings; +} diff --git a/Telegram/SourceFiles/window.h b/Telegram/SourceFiles/window.h new file mode 100644 index 000000000..b7ddc9140 --- /dev/null +++ b/Telegram/SourceFiles/window.h @@ -0,0 +1,206 @@ +/* +This file is part of Telegram Desktop, +an unofficial desktop messaging app, see https://telegram.org + +Telegram Desktop 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 3 of the License, or +(at your option) any later version. + +It 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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://tdesktop.com +*/ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "title.h" +#include "pspecific.h" +#include "gui/boxshadow.h" + +class TitleWidget; +class IntroWidget; +class MainWidget; +class Settings; +class LayerWidget; +class BackgroundWidget; +class LayeredWidget; + +class ConnectingWidget : public QWidget { + Q_OBJECT + +public: + + ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect); + void set(const QString &text, const QString &reconnect); + void paintEvent(QPaintEvent *e); + +public slots: + + void onReconnect(); + +private: + + BoxShadow _shadow; + QString _text; + int32 _textWidth; + LinkButton _reconnect; + +}; + +class TempDirDeleter : public QObject { + Q_OBJECT +public: + TempDirDeleter(QThread *thread); + +public slots: + void onStart(); + +signals: + void succeed(); + void failed(); + +}; + +class Window : public PsMainWindow { + Q_OBJECT + +public: + Window(QWidget *parent = 0); + ~Window(); + + void init(); + + bool eventFilter(QObject *obj, QEvent *evt); + + void inactivePress(bool inactive); + bool inactivePress() const; + + void wStartDrag(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void closeEvent(QCloseEvent *e); + + void paintEvent(QPaintEvent *e); + + void resizeEvent(QResizeEvent *e); + + void setupIntro(bool anim); + void setupMain(bool anim); + void startMain(const MTPUser &user); + void getNotifySetting(const MTPInputNotifyPeer &peer, uint32 msWait = 0); + + void mtpStateChanged(int32 dc, int32 state); + + TitleWidget *getTitle(); + + HitTestType hitTest(const QPoint &p) const; + QRect iconRect() const; + + QRect clientRect() const; + QRect photoRect() const; + + IntroWidget *introWidget(); + MainWidget *mainWidget(); + Settings *settingsWidget(); + + void showConnecting(const QString &text, const QString &reconnect = QString()); + void hideConnecting(); + + void hideSettings(bool fast = false); + void showPhoto(const PhotoLink *lnk, HistoryItem *item = 0); + void showPhoto(PhotoData *photo, HistoryItem *item = 0); +// void showVideo(const VideoOpenLink *lnk, HistoryItem *item = 0); + PhotoData *photoShown(); + void showLayer(LayeredWidget *w); + void replaceLayer(LayeredWidget *w); + void hideLayer(); + + bool layerShown(); + + bool historyIsActive() const; + void checkHistoryActivation(); + + bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const; + bool getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const; + + bool minimizeToTray(); + + void activate(); + + void noIntro(IntroWidget *was); + void noSettings(Settings *was); + void noMain(MainWidget *was); + void noLayer(LayerWidget *was); + void noBox(BackgroundWidget *was); + + void topWidget(QWidget *w); + void noTopWidget(QWidget *w); + + void fixOrder(); + + enum TempDirState { + TempDirRemoving, + TempDirExists, + TempDirEmpty, + }; + TempDirState tempDirState(); + void tempDirDelete(); + +public slots: + + void showSettings(); + void layerHidden(); + void updateTitleStatus(); + void quitFromTray(); + void showFromTray(QSystemTrayIcon::ActivationReason reason = QSystemTrayIcon::Unknown); + void toggleTray(QSystemTrayIcon::ActivationReason reason = QSystemTrayIcon::Unknown); + + void onInactiveTimer(); + + void onTempDirCleared(); + void onTempDirClearFailed(); + +signals: + + void resized(const QSize &size); + void tempDirCleared(); + void tempDirClearFailed(); + +protected: + + void setupTrayIcon(); + +private: + QWidget *centralwidget; + + TitleWidget *title; + IntroWidget *intro; + MainWidget *main; + Settings *settings; + LayerWidget *layer; + BackgroundWidget *layerBG; + + QWidget *_topWidget; // temp hack for CountrySelect + ConnectingWidget *_connecting; + + TempDirDeleter *_tempDeleter; + QThread *_tempDeleterThread; + + void clearWidgets(); + + QIcon myIcon; + + bool dragging; + QPoint dragStart; + + bool _inactivePress; + QTimer _inactiveTimer; + +}; + +#endif // MAINWINDOW_H diff --git a/Telegram/Telegram.rc b/Telegram/Telegram.rc new file mode 100644 index 000000000..cba8d6231 Binary files /dev/null and b/Telegram/Telegram.rc differ diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj new file mode 100644 index 000000000..c975cfe3d --- /dev/null +++ b/Telegram/Telegram.vcxproj @@ -0,0 +1,1018 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {B12702AD-ABFB-343A-A199-8E24837244A3} + Qt4VSv1.0 + + + + Application + v120_xp + + + Application + v120_xp + true + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)Intermediate\ + + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)Intermediate\ + + + + UNICODE;WIN32;WIN64;HAVE_STDINT_H;ZLIB_WINAPI;%(PreprocessorDefinitions) + .\..\..\Libraries\lzma\C;.\..\..\Libraries\libexif-0.6.20;.\..\..\Libraries\zlib-1.2.8;.\..\..\Libraries\OpenSSL-Win32\include;.\SourceFiles;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore;.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui;%(AdditionalIncludeDirectories) + ProgramDatabase + false + Use + stdafx.h + $(IntDir)$(TargetName).pch + MultiThreadedDebug + Disabled + + + Windows + $(OutDir)$(ProjectName).exe + .\..\..\Libraries\lzma\C\Util\LzmaLib\Debug;.\..\..\Libraries\libexif-0.6.20\win32\Debug;.\..\..\Libraries\zlib-1.2.8\contrib\vstudio\vc11\x86\ZlibStatDebug;.\..\..\Libraries\OpenSSL-Win32\lib\VC\static;$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;gdi32.lib;comdlg32.lib;oleaut32.lib;imm32.lib;winmm.lib;qtmaind.lib;glu32.lib;opengl32.lib;Strmiids.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;Qt5Networkd.lib;Qt5Multimediad.lib;Qt5PlatformSupportd.lib;platforms\qwindowsd.lib;accessible\qtaccessiblewidgetsd.lib;libeay32MTd.lib;zlibstat.lib;LzmaLib.lib;lib_exif.lib;UxTheme.lib;DbgHelp.lib;%(AdditionalDependencies) + true + + + + $(SolutionDir)$(Platform)\$(Configuration)Intermediate\$(TargetName).lib + + + + + + + + UNICODE;_WITH_DEBUG;WIN32;WIN64;HAVE_STDINT_H;ZLIB_WINAPI;QT_NO_DEBUG;NDEBUG;%(PreprocessorDefinitions) + .\..\..\Libraries\lzma\C;.\..\..\Libraries\libexif-0.6.20;.\..\..\Libraries\zlib-1.2.8;.\..\..\Libraries\OpenSSL-Win32\include;.\SourceFiles;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore;.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui;%(AdditionalIncludeDirectories) + ProgramDatabase + MultiThreaded + false + Use + stdafx.h + $(IntDir)$(TargetName).pch + AnySuitable + true + Speed + + + Windows + $(OutDir)$(ProjectName).exe + .\..\..\Libraries\lzma\C\Util\LzmaLib\Release;.\..\..\Libraries\libexif-0.6.20\win32\Release;.\..\..\Libraries\zlib-1.2.8\contrib\vstudio\vc11\x86\ZlibStatRelease;.\..\..\Libraries\OpenSSL-Win32\lib\VC\static;$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories) + kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;gdi32.lib;comdlg32.lib;oleaut32.lib;imm32.lib;winmm.lib;qtmain.lib;glu32.lib;opengl32.lib;Strmiids.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;Qt5Network.lib;Qt5Multimedia.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;accessible\qtaccessiblewidgets.lib;libeay32MT.lib;zlibstat.lib;lib_exif.lib;UxTheme.lib;DbgHelp.lib;LzmaLib.lib;%(AdditionalDependencies) + + $(SolutionDir)$(Platform)\$(Configuration)Intermediate\$(TargetName).lib + $(IntDir)$(TargetName).pgd + true + UseLinkTimeCodeGeneration + true + + + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + + + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + + + + + + + + + + Moc%27ing window.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/window.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing window.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/window.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + .\GeneratedFiles\style_classes.h + "$(SolutionDir)$(Platform)\$(Configuration)Meta\MetaStyle.exe" -classes_in ".\Resources\style_classes.txt" -classes_out ".\GeneratedFiles\style_classes.h" -styles_in ".\Resources\style.txt" -styles_out ".\GeneratedFiles\style_auto.h" + + + .\GeneratedFiles\style_auto.h + "$(SolutionDir)$(Platform)\$(Configuration)Meta\MetaStyle.exe" -classes_in ".\Resources\style_classes.txt" -classes_out ".\GeneratedFiles\style_classes.h" -styles_in ".\Resources\style.txt" -styles_out ".\GeneratedFiles\style_auto.h" + + + .\GeneratedFiles\lang.h + .\GeneratedFiles\lang.cpp + "$(SolutionDir)$(Platform)\$(Configuration)Lang\MetaLang.exe" -lang_in ".\Resources\lang.txt" -lang_out ".\GeneratedFiles\lang" + + + Moc%27ing application.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/application.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing application.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/application.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + + + + + Moc%27ing aboutbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/aboutbox.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing aboutbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/aboutbox.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing addcontactbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/addcontactbox.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing addcontactbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/addcontactbox.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing addparticipantbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/addparticipantbox.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing addparticipantbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/addparticipantbox.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing confirmbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/confirmbox.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing confirmbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/confirmbox.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing connectionbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/connectionbox.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing connectionbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/connectionbox.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing contactsbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/contactsbox.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing contactsbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/contactsbox.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing newgroupbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/newgroupbox.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing newgroupbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/newgroupbox.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing photocropbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/photocropbox.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing photocropbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/photocropbox.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing photosendbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/photosendbox.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing photosendbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/photosendbox.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing emojibox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/emojibox.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing emojibox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/emojibox.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing downloadpathbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/downloadpathbox.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing downloadpathbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/downloadpathbox.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + Moc%27ing animation.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/animation.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing animation.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/animation.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing button.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/button.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing button.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/button.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing flatbutton.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/flatbutton.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing flatbutton.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/flatbutton.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing flatinput.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/flatinput.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing flatinput.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/flatinput.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing countrycodeinput.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/countrycodeinput.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing countrycodeinput.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/countrycodeinput.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing phoneinput.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/phoneinput.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing phoneinput.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/phoneinput.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing countryinput.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/countryinput.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing countryinput.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/countryinput.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + Moc%27ing scrollarea.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/scrollarea.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing scrollarea.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/scrollarea.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing dialogswidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/dialogswidget.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing dialogswidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/dialogswidget.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing flattextarea.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/flattextarea.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing flattextarea.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/flattextarea.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing fileuploader.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/fileuploader.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing fileuploader.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/fileuploader.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing dropdown.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/dropdown.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing dropdown.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/dropdown.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + + Moc%27ing flatcheckbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/flatcheckbox.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing flatcheckbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/flatcheckbox.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + + + + + + + + + + + + + + + Moc%27ing flatlabel.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/flatlabel.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing flatlabel.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/flatlabel.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing twidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/twidget.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing twidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/twidget.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + + + Moc%27ing historywidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/historywidget.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing historywidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/historywidget.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing intro.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/intro/intro.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing intro.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/intro/intro.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing introcode.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/intro/introcode.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing introcode.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/intro/introcode.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing introphone.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/intro/introphone.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing introphone.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/intro/introphone.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing introsignup.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/intro/introsignup.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing introsignup.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/intro/introsignup.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + Moc%27ing layerwidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/layerwidget.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing layerwidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/layerwidget.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing localimageloader.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/localimageloader.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing localimageloader.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/localimageloader.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + + Moc%27ing mtpConnection.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/mtpConnection.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing mtpConnection.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/mtpConnection.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing mainwidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mainwidget.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing mainwidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mainwidget.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing mtp.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/mtp.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing mtp.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/mtp.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + Moc%27ing mtpFileLoader.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/mtpFileLoader.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing mtpFileLoader.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/mtpFileLoader.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + + Moc%27ing mtpDC.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/mtpDC.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing mtpDC.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/mtpDC.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + + Moc%27ing mtpSession.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/mtpSession.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing mtpSession.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/mtpSession.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing settingswidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/settingswidget.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing settingswidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/settingswidget.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing profilewidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profilewidget.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing profilewidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profilewidget.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing pspecific_wnd.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/pspecific_wnd.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing pspecific_wnd.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/pspecific_wnd.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + + + + + Moc%27ing sysbuttons.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/sysbuttons.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing sysbuttons.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/sysbuttons.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + Moc%27ing title.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/title.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + Moc%27ing title.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/title.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + + + + + %(FullPath);.\SourceFiles\art\icon.png;.\SourceFiles\art\segoe_ui.ttf;.\SourceFiles\art\sysicons.png;.\SourceFiles\art\iconf.png;%(AdditionalInputs) + Rcc%27ing %(Identity)... + .\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs) + "$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp + %(FullPath);.\SourceFiles\art\icon.png;.\SourceFiles\art\segoe_ui.ttf;.\SourceFiles\art\sysicons.png;.\SourceFiles\art\iconf.png;%(AdditionalInputs) + Rcc%27ing %(Identity)... + .\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs) + "$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp + Designer + + + + + true + true + + + true + true + + + + true + true + + + + + true + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters new file mode 100644 index 000000000..f5b4700fc --- /dev/null +++ b/Telegram/Telegram.vcxproj.filters @@ -0,0 +1,772 @@ + + + + + {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} + moc;h;cpp + False + + + {4e5e8958-0a60-4117-8701-cbd387932d83} + cpp;moc + False + + + {9c05f518-3867-45cb-b08c-19c0d32151c7} + cpp;moc + False + + + {93203856-b459-49ec-8097-689d0feda013} + + + {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} + qrc;* + false + + + {d01d021a-d92f-4ac3-9155-6d297fffe596} + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;cxx;c;def + + + {65fcb834-0002-4007-80c2-8bd6cbc63c93} + + + {08a48c4d-2526-4578-ad4b-db659e4eec8d} + + + + + Source Files + + + Source Files + + + Source Files + + + mtproto + + + mtproto + + + mtproto + + + Source Files + + + gui + + + gui + + + gui + + + Generated Files + + + gui + + + gui + + + gui + + + gui + + + gui + + + mtproto + + + Source Files + + + Generated Files + + + Source Files + + + Source Files + + + mtproto + + + Source Files + + + Source Files + + + Source Files + + + gui + + + gui + + + gui + + + mtproto + + + Source Files + + + Source Files + + + Source Files + + + gui + + + Source Files + + + gui + + + gui + + + Source Files + + + gui + + + Source Files + + + Source Files + + + Source Files + + + boxes + + + boxes + + + boxes + + + boxes + + + boxes + + + boxes + + + boxes + + + boxes + + + boxes + + + gui + + + boxes + + + intro + + + intro + + + intro + + + intro + + + intro + + + Source Files + + + gui + + + Source Files + + + Source Files + + + boxes + + + gui + + + Generated Files + + + Source Files + + + Source Files + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + + + Source Files + + + Source Files + + + mtproto + + + mtproto + + + mtproto + + + Source Files + + + Source Files + + + mtproto + + + Generated Files + + + Generated Files + + + Source Files + + + Source Files + + + mtproto + + + Source Files + + + Source Files + + + gui + + + Generated Files + + + gui + + + Source Files + + + gui + + + gui + + + intro + + + gui + + + Source Files + + + Generated Files + + + Source Files + + + Source Files + + + mtproto + + + + + mtproto + + + mtproto + + + mtproto + + + Source Files + + + gui + + + gui + + + gui + + + Resource Files + + + + + gui + + + gui + + + gui + + + gui + + + gui + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + gui + + + gui + + + mtproto + + + Source Files + + + Source Files + + + mtproto + + + gui + + + Source Files + + + Source Files + + + gui + + + Source Files + + + Source Files + + + Source Files + + + boxes + + + boxes + + + boxes + + + boxes + + + boxes + + + boxes + + + boxes + + + boxes + + + boxes + + + boxes + + + intro + + + intro + + + intro + + + intro + + + Source Files + + + Source Files + + + boxes + + + gui + + + + + + Resource Files + + + Resource Files + + + Resource Files + + + + + + Resource Files + + + + + + \ No newline at end of file diff --git a/Telegram/Updater.rc b/Telegram/Updater.rc new file mode 100644 index 000000000..91346eac4 Binary files /dev/null and b/Telegram/Updater.rc differ diff --git a/Telegram/Updater.vcxproj b/Telegram/Updater.vcxproj new file mode 100644 index 000000000..d7c835709 --- /dev/null +++ b/Telegram/Updater.vcxproj @@ -0,0 +1,102 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {6B4BA3BE-7B15-4B4C-B200-81ABFDEF2C76} + Win32Proj + Updater + + + + Application + true + v120_xp + Unicode + + + Application + false + v120_xp + + + + + + + + + + + + + + + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)UpdIntermediate\ + + + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)UpdIntermediate\ + + + + + + Level3 + Disabled + UNICODE;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreadedDebug + + + Windows + true + $(OutDir)$(ProjectName).exe + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Shlwapi.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + UNICODE;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreaded + + + Windows + true + true + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Shlwapi.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Telegram/Updater.vcxproj.filters b/Telegram/Updater.vcxproj.filters new file mode 100644 index 000000000..f35e8301b --- /dev/null +++ b/Telegram/Updater.vcxproj.filters @@ -0,0 +1,21 @@ + + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + Resource Files + + + + + + \ No newline at end of file diff --git a/Telegram/_qt_5_3_0_patch/qtbase/mkspecs/win32-msvc2013/qmake.conf b/Telegram/_qt_5_3_0_patch/qtbase/mkspecs/win32-msvc2013/qmake.conf new file mode 100644 index 000000000..15e77bc43 --- /dev/null +++ b/Telegram/_qt_5_3_0_patch/qtbase/mkspecs/win32-msvc2013/qmake.conf @@ -0,0 +1,99 @@ +# +# qmake configuration for win32-msvc2013 +# +# Written for Microsoft Visual C++ 2013 +# + +MAKEFILE_GENERATOR = MSBUILD +QMAKE_PLATFORM = win32 +CONFIG += incremental flat precompile_header autogen_precompile_source debug_and_release debug_and_release_target embed_manifest_dll embed_manifest_exe +DEFINES += UNICODE WIN32 +MSVC_VER = 12.0 +QMAKE_COMPILER_DEFINES += _MSC_VER=1800 _WIN32 +contains(QMAKE_TARGET.arch, x86_64) { + DEFINES += WIN64 + QMAKE_COMPILER_DEFINES += _WIN64 +} + +QMAKE_COMPILER = msvc + +QMAKE_CC = cl +QMAKE_LEX = flex +QMAKE_LEXFLAGS = +QMAKE_YACC = byacc +QMAKE_YACCFLAGS = -d +QMAKE_CFLAGS = -nologo -Zm200 -Zc:wchar_t -FS +QMAKE_CFLAGS_WARN_ON = -W3 +QMAKE_CFLAGS_WARN_OFF = -W0 +QMAKE_CFLAGS_RELEASE = -O2 -MT +QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MT -Zi +QMAKE_CFLAGS_DEBUG = -Zi -MTd +QMAKE_CFLAGS_YACC = +QMAKE_CFLAGS_LTCG = -GL +QMAKE_CFLAGS_MP = -MP +QMAKE_CFLAGS_SSE2 = -arch:SSE2 +QMAKE_CFLAGS_SSE3 = -arch:SSE2 +QMAKE_CFLAGS_SSSE3 = -arch:SSE2 +QMAKE_CFLAGS_SSE4_1 = -arch:SSE2 +QMAKE_CFLAGS_SSE4_2 = -arch:SSE2 +QMAKE_CFLAGS_AVX = -arch:AVX +QMAKE_CFLAGS_AVX2 = -arch:AVX + +QMAKE_CXX = $$QMAKE_CC +QMAKE_CXXFLAGS = $$QMAKE_CFLAGS +QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON -w34100 -w34189 +QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF +QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE +QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO +QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG +QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC +QMAKE_CXXFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG +QMAKE_CXXFLAGS_MP = $$QMAKE_CFLAGS_MP +QMAKE_CXXFLAGS_STL_ON = -EHsc +QMAKE_CXXFLAGS_STL_OFF = +QMAKE_CXXFLAGS_RTTI_ON = -GR +QMAKE_CXXFLAGS_RTTI_OFF = +QMAKE_CXXFLAGS_EXCEPTIONS_ON = -EHsc +QMAKE_CXXFLAGS_EXCEPTIONS_OFF = -D_HAS_EXCEPTIONS=0 + +QMAKE_INCDIR = + +QMAKE_RUN_CC = $(CC) -c $(CFLAGS) $(INCPATH) -Fo$obj $src +QMAKE_RUN_CC_IMP = $(CC) -c $(CFLAGS) $(INCPATH) -Fo$@ $< +QMAKE_RUN_CC_IMP_BATCH = $(CC) -c $(CFLAGS) $(INCPATH) -Fo$@ @<< +QMAKE_RUN_CXX = $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo$obj $src +QMAKE_RUN_CXX_IMP = $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo$@ $< +QMAKE_RUN_CXX_IMP_BATCH = $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo$@ @<< + +QMAKE_LINK = link +QMAKE_LFLAGS = /NOLOGO /DYNAMICBASE /NXCOMPAT +QMAKE_LFLAGS_RELEASE = /INCREMENTAL:NO +QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO = /DEBUG /OPT:REF /INCREMENTAL:NO +QMAKE_LFLAGS_DEBUG = /DEBUG +QMAKE_LFLAGS_CONSOLE = /SUBSYSTEM:CONSOLE@QMAKE_SUBSYSTEM_SUFFIX@ +QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS@QMAKE_SUBSYSTEM_SUFFIX@ +QMAKE_LFLAGS_EXE = \"/MANIFESTDEPENDENCY:type=\'win32\' name=\'Microsoft.Windows.Common-Controls\' version=\'6.0.0.0\' publicKeyToken=\'6595b64144ccf1df\' language=\'*\' processorArchitecture=\'*\'\" +QMAKE_LFLAGS_DLL = /DLL +QMAKE_LFLAGS_LTCG = /LTCG +QMAKE_EXTENSION_STATICLIB = lib + +QMAKE_LIBS_CORE = kernel32.lib user32.lib shell32.lib uuid.lib ole32.lib advapi32.lib ws2_32.lib +QMAKE_LIBS_GUI = gdi32.lib comdlg32.lib oleaut32.lib imm32.lib winmm.lib ws2_32.lib ole32.lib user32.lib advapi32.lib +QMAKE_LIBS_NETWORK = ws2_32.lib +QMAKE_LIBS_OPENGL = glu32.lib opengl32.lib gdi32.lib user32.lib +QMAKE_LIBS_OPENGL_ES2 = libEGL.lib libGLESv2.lib gdi32.lib user32.lib +QMAKE_LIBS_OPENGL_ES2_DEBUG = libEGLd.lib libGLESv2d.lib gdi32.lib user32.lib +QMAKE_LIBS_COMPAT = advapi32.lib shell32.lib comdlg32.lib user32.lib gdi32.lib ws2_32.lib + +QMAKE_LIBS_QT_ENTRY = -lqtmain + +QMAKE_IDL = midl +QMAKE_LIB = lib /NOLOGO +QMAKE_RC = rc + +include(../common/shell-win32.conf) + +VCPROJ_EXTENSION = .vcxproj +VCSOLUTION_EXTENSION = .sln +VCPROJ_KEYWORD = Qt4VSv1.0 +load(qt_config) diff --git a/Telegram/_qt_5_3_0_patch/qtbase/src/gui/kernel/qplatformdialoghelper.h b/Telegram/_qt_5_3_0_patch/qtbase/src/gui/kernel/qplatformdialoghelper.h new file mode 100644 index 000000000..567a3225d --- /dev/null +++ b/Telegram/_qt_5_3_0_patch/qtbase/src/gui/kernel/qplatformdialoghelper.h @@ -0,0 +1,451 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPLATFORMDIALOGHELPER_H +#define QPLATFORMDIALOGHELPER_H + +// +// W A R N I N G +// ------------- +// +// This file is part of the QPA API and is not meant to be used +// in applications. Usage of this API may make your code +// source and binary incompatible with future versions of Qt. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + + +class QString; +class QColor; +class QFont; +class QWindow; +class QVariant; +class QUrl; +class QColorDialogOptionsPrivate; +class QFontDialogOptionsPrivate; +class QFileDialogOptionsPrivate; +class QMessageDialogOptionsPrivate; + +class Q_GUI_EXPORT QPlatformDialogHelper : public QObject +{ + Q_OBJECT +public: + enum StyleHint { + }; + enum DialogCode { Rejected, Accepted }; + + enum StandardButton { + // keep this in sync with QDialogButtonBox::StandardButton and QMessageBox::StandardButton + NoButton = 0x00000000, + Ok = 0x00000400, + Save = 0x00000800, + SaveAll = 0x00001000, + Open = 0x00002000, + Yes = 0x00004000, + YesToAll = 0x00008000, + No = 0x00010000, + NoToAll = 0x00020000, + Abort = 0x00040000, + Retry = 0x00080000, + Ignore = 0x00100000, + Close = 0x00200000, + Cancel = 0x00400000, + Discard = 0x00800000, + Help = 0x01000000, + Apply = 0x02000000, + Reset = 0x04000000, + RestoreDefaults = 0x08000000, + + + FirstButton = Ok, // internal + LastButton = RestoreDefaults, // internal + LowestBit = 10, // internal: log2(FirstButton) + HighestBit = 27 // internal: log2(LastButton) + }; + + Q_DECLARE_FLAGS(StandardButtons, StandardButton) + + enum ButtonRole { + // keep this in sync with QDialogButtonBox::ButtonRole and QMessageBox::ButtonRole + // TODO Qt 6: make the enum copies explicit, and make InvalidRole == 0 so that + // AcceptRole can be or'ed with flags, and EOL can be the same as InvalidRole (null-termination) + InvalidRole = -1, + AcceptRole, + RejectRole, + DestructiveRole, + ActionRole, + HelpRole, + YesRole, + NoRole, + ResetRole, + ApplyRole, + + NRoles, + + RoleMask = 0x0FFFFFFF, + AlternateRole = 0x10000000, + Stretch = 0x20000000, + Reverse = 0x40000000, + EOL = InvalidRole + }; + + enum ButtonLayout { + // keep this in sync with QDialogButtonBox::ButtonLayout and QMessageBox::ButtonLayout + UnknownLayout = -1, + WinLayout, + MacLayout, + KdeLayout, + GnomeLayout, + MacModelessLayout + }; + + QPlatformDialogHelper(); + virtual ~QPlatformDialogHelper(); + + virtual QVariant styleHint(StyleHint hint) const; + + virtual void exec() = 0; + virtual bool show(Qt::WindowFlags windowFlags, + Qt::WindowModality windowModality, + QWindow *parent) = 0; + virtual void hide() = 0; + + static QVariant defaultStyleHint(QPlatformDialogHelper::StyleHint hint); + + static const int *buttonLayout(Qt::Orientation orientation = Qt::Horizontal, ButtonLayout policy = UnknownLayout); + static ButtonRole buttonRole(StandardButton button); + +Q_SIGNALS: + void accept(); + void reject(); +}; + +class Q_GUI_EXPORT QColorDialogOptions +{ +public: + enum ColorDialogOption { + ShowAlphaChannel = 0x00000001, + NoButtons = 0x00000002, + DontUseNativeDialog = 0x00000004 + }; + + Q_DECLARE_FLAGS(ColorDialogOptions, ColorDialogOption) + + QColorDialogOptions(); + QColorDialogOptions(const QColorDialogOptions &rhs); + QColorDialogOptions &operator=(const QColorDialogOptions &rhs); + ~QColorDialogOptions(); + + void swap(QColorDialogOptions &other) { qSwap(d, other.d); } + + QString windowTitle() const; + void setWindowTitle(const QString &); + + void setOption(ColorDialogOption option, bool on = true); + bool testOption(ColorDialogOption option) const; + void setOptions(ColorDialogOptions options); + ColorDialogOptions options() const; + + static int customColorCount(); + static QRgb customColor(int index); + static QRgb *customColors(); + static void setCustomColor(int index, QRgb color); + + static QRgb *standardColors(); + static QRgb standardColor(int index); + static void setStandardColor(int index, QRgb color); + +private: + QSharedDataPointer d; +}; + +Q_DECLARE_SHARED(QColorDialogOptions) + +class Q_GUI_EXPORT QPlatformColorDialogHelper : public QPlatformDialogHelper +{ + Q_OBJECT +public: + const QSharedPointer &options() const; + void setOptions(const QSharedPointer &options); + + virtual void setCurrentColor(const QColor &) = 0; + virtual QColor currentColor() const = 0; + +Q_SIGNALS: + void currentColorChanged(const QColor &color); + void colorSelected(const QColor &color); + +private: + QSharedPointer m_options; +}; + +class Q_GUI_EXPORT QFontDialogOptions +{ +public: + enum FontDialogOption { + NoButtons = 0x00000001, + DontUseNativeDialog = 0x00000002, + ScalableFonts = 0x00000004, + NonScalableFonts = 0x00000008, + MonospacedFonts = 0x00000010, + ProportionalFonts = 0x00000020 + }; + + Q_DECLARE_FLAGS(FontDialogOptions, FontDialogOption) + + QFontDialogOptions(); + QFontDialogOptions(const QFontDialogOptions &rhs); + QFontDialogOptions &operator=(const QFontDialogOptions &rhs); + ~QFontDialogOptions(); + + void swap(QFontDialogOptions &other) { qSwap(d, other.d); } + + QString windowTitle() const; + void setWindowTitle(const QString &); + + void setOption(FontDialogOption option, bool on = true); + bool testOption(FontDialogOption option) const; + void setOptions(FontDialogOptions options); + FontDialogOptions options() const; + +private: + QSharedDataPointer d; +}; + +Q_DECLARE_SHARED(QFontDialogOptions) + +class Q_GUI_EXPORT QPlatformFontDialogHelper : public QPlatformDialogHelper +{ + Q_OBJECT +public: + virtual void setCurrentFont(const QFont &) = 0; + virtual QFont currentFont() const = 0; + + const QSharedPointer &options() const; + void setOptions(const QSharedPointer &options); + +Q_SIGNALS: + void currentFontChanged(const QFont &font); + void fontSelected(const QFont &font); + +private: + QSharedPointer m_options; +}; + +class Q_GUI_EXPORT QFileDialogOptions +{ +public: + enum ViewMode { Detail, List }; + enum FileMode { AnyFile, ExistingFile, Directory, ExistingFiles, DirectoryOnly }; + enum AcceptMode { AcceptOpen, AcceptSave }; + enum DialogLabel { LookIn, FileName, FileType, Accept, Reject, DialogLabelCount }; + + enum FileDialogOption + { + ShowDirsOnly = 0x00000001, + DontResolveSymlinks = 0x00000002, + DontConfirmOverwrite = 0x00000004, + DontUseSheet = 0x00000008, + DontUseNativeDialog = 0x00000010, + ReadOnly = 0x00000020, + HideNameFilterDetails = 0x00000040, + DontUseCustomDirectoryIcons = 0x00000080 + }; + Q_DECLARE_FLAGS(FileDialogOptions, FileDialogOption) + + QFileDialogOptions(); + QFileDialogOptions(const QFileDialogOptions &rhs); + QFileDialogOptions &operator=(const QFileDialogOptions &rhs); + ~QFileDialogOptions(); + + void swap(QFileDialogOptions &other) { qSwap(d, other.d); } + + QString windowTitle() const; + void setWindowTitle(const QString &); + + void setOption(FileDialogOption option, bool on = true); + bool testOption(FileDialogOption option) const; + void setOptions(FileDialogOptions options); + FileDialogOptions options() const; + + QDir::Filters filter() const; + void setFilter(QDir::Filters filters); + + void setViewMode(ViewMode mode); + ViewMode viewMode() const; + + void setFileMode(FileMode mode); + FileMode fileMode() const; + + void setAcceptMode(AcceptMode mode); + AcceptMode acceptMode() const; + + void setSidebarUrls(const QList &urls); + QList sidebarUrls() const; + + void setNameFilters(const QStringList &filters); + QStringList nameFilters() const; + + void setMimeTypeFilters(const QStringList &filters); + QStringList mimeTypeFilters() const; + + void setDefaultSuffix(const QString &suffix); + QString defaultSuffix() const; + + void setHistory(const QStringList &paths); + QStringList history() const; + + void setLabelText(DialogLabel label, const QString &text); + QString labelText(DialogLabel label) const; + bool isLabelExplicitlySet(DialogLabel label); + + QUrl initialDirectory() const; + void setInitialDirectory(const QUrl &); + + QString initiallySelectedNameFilter() const; + void setInitiallySelectedNameFilter(const QString &); + + QList initiallySelectedFiles() const; + void setInitiallySelectedFiles(const QList &); + +private: + QSharedDataPointer d; +}; + +Q_DECLARE_SHARED(QFileDialogOptions) + +class Q_GUI_EXPORT QPlatformFileDialogHelper : public QPlatformDialogHelper +{ + Q_OBJECT +public: + virtual bool defaultNameFilterDisables() const = 0; + virtual void setDirectory(const QUrl &directory) = 0; + virtual QUrl directory() const = 0; + virtual void selectFile(const QUrl &filename) = 0; + virtual QList selectedFiles() const = 0; + virtual QByteArray selectedRemoteContent() const { return QByteArray(); } + virtual void setFilter() = 0; + virtual void selectNameFilter(const QString &filter) = 0; + virtual QString selectedNameFilter() const = 0; + + virtual bool isSupportedUrl(const QUrl &url) const; + + const QSharedPointer &options() const; + void setOptions(const QSharedPointer &options); + + static QStringList cleanFilterList(const QString &filter); + static const char *filterRegExp; + +Q_SIGNALS: + void fileSelected(const QUrl &file); + void filesSelected(const QList &files); + void currentChanged(const QUrl &path); + void directoryEntered(const QUrl &directory); + void filterSelected(const QString &filter); + +private: + QSharedPointer m_options; +}; + +class Q_GUI_EXPORT QMessageDialogOptions +{ +public: + // Keep in sync with QMessageBox::Icon + enum Icon { NoIcon, Information, Warning, Critical, Question }; + + QMessageDialogOptions(); + QMessageDialogOptions(const QMessageDialogOptions &rhs); + QMessageDialogOptions &operator=(const QMessageDialogOptions &rhs); + ~QMessageDialogOptions(); + + void swap(QMessageDialogOptions &other) { qSwap(d, other.d); } + + QString windowTitle() const; + void setWindowTitle(const QString &); + + void setIcon(Icon icon); + Icon icon() const; + + void setText(const QString &text); + QString text() const; + + void setInformativeText(const QString &text); + QString informativeText() const; + + void setDetailedText(const QString &text); + QString detailedText() const; + + void setStandardButtons(QPlatformDialogHelper::StandardButtons buttons); + QPlatformDialogHelper::StandardButtons standardButtons() const; + +private: + QSharedDataPointer d; +}; + +Q_DECLARE_SHARED(QMessageDialogOptions) + +class Q_GUI_EXPORT QPlatformMessageDialogHelper : public QPlatformDialogHelper +{ + Q_OBJECT +public: + const QSharedPointer &options() const; + void setOptions(const QSharedPointer &options); + +Q_SIGNALS: + void clicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role); + +private: + QSharedPointer m_options; +}; + +QT_END_NAMESPACE + +#endif // QPLATFORMDIALOGHELPER_H diff --git a/Telegram/_qt_5_3_0_patch/qtbase/src/gui/text/qtextlayout.h b/Telegram/_qt_5_3_0_patch/qtbase/src/gui/text/qtextlayout.h new file mode 100644 index 000000000..2209490ef --- /dev/null +++ b/Telegram/_qt_5_3_0_patch/qtbase/src/gui/text/qtextlayout.h @@ -0,0 +1,268 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QTEXTLAYOUT_H +#define QTEXTLAYOUT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + + +class QTextEngine; +class QFont; +#ifndef QT_NO_RAWFONT +class QRawFont; +#endif +class QRect; +class QRegion; +class QTextFormat; +class QPalette; +class QPainter; + +class Q_GUI_EXPORT QTextInlineObject +{ +public: + QTextInlineObject(int i, QTextEngine *e) : itm(i), eng(e) {} + inline QTextInlineObject() : itm(0), eng(0) {} + inline bool isValid() const { return eng; } + + QRectF rect() const; + qreal width() const; + qreal ascent() const; + qreal descent() const; + qreal height() const; + + Qt::LayoutDirection textDirection() const; + + void setWidth(qreal w); + void setAscent(qreal a); + void setDescent(qreal d); + + int textPosition() const; + + int formatIndex() const; + QTextFormat format() const; + +private: + friend class QTextLayout; + int itm; + QTextEngine *eng; +}; + +class QPaintDevice; +class QTextFormat; +class QTextLine; +class QTextBlock; +class QTextOption; + +class Q_GUI_EXPORT QTextLayout +{ +public: + // does itemization + QTextLayout(); + QTextLayout(const QString& text); + QTextLayout(const QString& text, const QFont &font, QPaintDevice *paintdevice = 0); + QTextLayout(const QTextBlock &b); + ~QTextLayout(); + + void setFont(const QFont &f); + QFont font() const; + +#ifndef QT_NO_RAWFONT + void setRawFont(const QRawFont &rawFont); +#endif + + void setText(const QString& string); + QString text() const; + + void setTextOption(const QTextOption &option); + const QTextOption &textOption() const; + + void setPreeditArea(int position, const QString &text); + int preeditAreaPosition() const; + QString preeditAreaText() const; + + struct FormatRange { + int start; + int length; + QTextCharFormat format; + }; + void setAdditionalFormats(const QList &overrides); + QList additionalFormats() const; + void clearAdditionalFormats(); + + void setCacheEnabled(bool enable); + bool cacheEnabled() const; + + void setCursorMoveStyle(Qt::CursorMoveStyle style); + Qt::CursorMoveStyle cursorMoveStyle() const; + + void beginLayout(); + void endLayout(); + void clearLayout(); + + QTextLine createLine(); + + int lineCount() const; + QTextLine lineAt(int i) const; + QTextLine lineForTextPosition(int pos) const; + + enum CursorMode { + SkipCharacters, + SkipWords + }; + bool isValidCursorPosition(int pos) const; + int nextCursorPosition(int oldPos, CursorMode mode = SkipCharacters) const; + int previousCursorPosition(int oldPos, CursorMode mode = SkipCharacters) const; + int leftCursorPosition(int oldPos) const; + int rightCursorPosition(int oldPos) const; + + void draw(QPainter *p, const QPointF &pos, const QVector &selections = QVector(), + const QRectF &clip = QRectF()) const; + void drawCursor(QPainter *p, const QPointF &pos, int cursorPosition) const; + void drawCursor(QPainter *p, const QPointF &pos, int cursorPosition, int width) const; + + QPointF position() const; + void setPosition(const QPointF &p); + + QRectF boundingRect() const; + + qreal minimumWidth() const; + qreal maximumWidth() const; + +#if !defined(QT_NO_RAWFONT) + QList glyphRuns(int from = -1, int length = -1) const; +#endif + + QTextEngine *engine() const { return d; } + void setFlags(int flags); +private: + QTextLayout(QTextEngine *e) : d(e) {} + Q_DISABLE_COPY(QTextLayout) + + friend class QPainter; + friend class QGraphicsSimpleTextItemPrivate; + friend class QGraphicsSimpleTextItem; + friend void qt_format_text(const QFont &font, const QRectF &_r, int tf, const QTextOption *, const QString& str, + QRectF *brect, int tabstops, int* tabarray, int tabarraylen, + QPainter *painter); + QTextEngine *d; + + friend class TextBlock; +}; + + +class Q_GUI_EXPORT QTextLine +{ +public: + inline QTextLine() : index(0), eng(0) {} + inline bool isValid() const { return eng; } + + QRectF rect() const; + qreal x() const; + qreal y() const; + qreal width() const; + qreal ascent() const; + qreal descent() const; + qreal height() const; + qreal leading() const; + + void setLeadingIncluded(bool included); + bool leadingIncluded() const; + + qreal naturalTextWidth() const; + qreal horizontalAdvance() const; + QRectF naturalTextRect() const; + + enum Edge { + Leading, + Trailing + }; + enum CursorPosition { + CursorBetweenCharacters, + CursorOnCharacter + }; + + /* cursorPos gets set to the valid position */ + qreal cursorToX(int *cursorPos, Edge edge = Leading) const; + inline qreal cursorToX(int cursorPos, Edge edge = Leading) const { return cursorToX(&cursorPos, edge); } + int xToCursor(qreal x, CursorPosition = CursorBetweenCharacters) const; + + void setLineWidth(qreal width); + void setNumColumns(int columns); + void setNumColumns(int columns, qreal alignmentWidth); + + void setPosition(const QPointF &pos); + QPointF position() const; + + int textStart() const; + int textLength() const; + + int lineNumber() const { return index; } + + void draw(QPainter *p, const QPointF &point, const QTextLayout::FormatRange *selection = 0) const; + +#if !defined(QT_NO_RAWFONT) + QList glyphRuns(int from = -1, int length = -1) const; +#endif + +private: + QTextLine(int line, QTextEngine *e) : index(line), eng(e) {} + void layout_helper(int numGlyphs); + + friend class QTextLayout; + friend class QTextFragment; + int index; + QTextEngine *eng; +}; + +QT_END_NAMESPACE + +#endif // QTEXTLAYOUT_H diff --git a/Telegram/_qt_5_3_0_patch/qtbase/src/network/socket/qnativesocketengine_win.cpp b/Telegram/_qt_5_3_0_patch/qtbase/src/network/socket/qnativesocketengine_win.cpp new file mode 100644 index 000000000..8067b89d0 --- /dev/null +++ b/Telegram/_qt_5_3_0_patch/qtbase/src/network/socket/qnativesocketengine_win.cpp @@ -0,0 +1,1565 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Prevent windows system header files from defining min/max as macros. +#define NOMINMAX 1 + +#include +#include + +#include "qnativesocketengine_p.h" + +#include +#include +#include +#include +#include + +//#define QNATIVESOCKETENGINE_DEBUG +#if defined(QNATIVESOCKETENGINE_DEBUG) +# include +# include +#endif + +QT_BEGIN_NAMESPACE + +//Some distributions of mingw (including 4.7.2 from mingw.org) are missing this from headers. +//Also microsoft headers don't include it when building on XP and earlier. +#ifndef IPV6_V6ONLY +#define IPV6_V6ONLY 27 +#endif + +#if defined(QNATIVESOCKETENGINE_DEBUG) + +void verboseWSErrorDebug(int r) +{ + switch (r) { + case WSANOTINITIALISED : qDebug("WSA error : WSANOTINITIALISED"); break; + case WSAEINTR: qDebug("WSA error : WSAEINTR"); break; + case WSAEBADF: qDebug("WSA error : WSAEBADF"); break; + case WSAEACCES: qDebug("WSA error : WSAEACCES"); break; + case WSAEFAULT: qDebug("WSA error : WSAEFAULT"); break; + case WSAEINVAL: qDebug("WSA error : WSAEINVAL"); break; + case WSAEMFILE: qDebug("WSA error : WSAEMFILE"); break; + case WSAEWOULDBLOCK: qDebug("WSA error : WSAEWOULDBLOCK"); break; + case WSAEINPROGRESS: qDebug("WSA error : WSAEINPROGRESS"); break; + case WSAEALREADY: qDebug("WSA error : WSAEALREADY"); break; + case WSAENOTSOCK: qDebug("WSA error : WSAENOTSOCK"); break; + case WSAEDESTADDRREQ: qDebug("WSA error : WSAEDESTADDRREQ"); break; + case WSAEMSGSIZE: qDebug("WSA error : WSAEMSGSIZE"); break; + case WSAEPROTOTYPE: qDebug("WSA error : WSAEPROTOTYPE"); break; + case WSAENOPROTOOPT: qDebug("WSA error : WSAENOPROTOOPT"); break; + case WSAEPROTONOSUPPORT: qDebug("WSA error : WSAEPROTONOSUPPORT"); break; + case WSAESOCKTNOSUPPORT: qDebug("WSA error : WSAESOCKTNOSUPPORT"); break; + case WSAEOPNOTSUPP: qDebug("WSA error : WSAEOPNOTSUPP"); break; + case WSAEPFNOSUPPORT: qDebug("WSA error : WSAEPFNOSUPPORT"); break; + case WSAEAFNOSUPPORT: qDebug("WSA error : WSAEAFNOSUPPORT"); break; + case WSAEADDRINUSE: qDebug("WSA error : WSAEADDRINUSE"); break; + case WSAEADDRNOTAVAIL: qDebug("WSA error : WSAEADDRNOTAVAIL"); break; + case WSAENETDOWN: qDebug("WSA error : WSAENETDOWN"); break; + case WSAENETUNREACH: qDebug("WSA error : WSAENETUNREACH"); break; + case WSAENETRESET: qDebug("WSA error : WSAENETRESET"); break; + case WSAECONNABORTED: qDebug("WSA error : WSAECONNABORTED"); break; + case WSAECONNRESET: qDebug("WSA error : WSAECONNRESET"); break; + case WSAENOBUFS: qDebug("WSA error : WSAENOBUFS"); break; + case WSAEISCONN: qDebug("WSA error : WSAEISCONN"); break; + case WSAENOTCONN: qDebug("WSA error : WSAENOTCONN"); break; + case WSAESHUTDOWN: qDebug("WSA error : WSAESHUTDOWN"); break; + case WSAETOOMANYREFS: qDebug("WSA error : WSAETOOMANYREFS"); break; + case WSAETIMEDOUT: qDebug("WSA error : WSAETIMEDOUT"); break; + case WSAECONNREFUSED: qDebug("WSA error : WSAECONNREFUSED"); break; + case WSAELOOP: qDebug("WSA error : WSAELOOP"); break; + case WSAENAMETOOLONG: qDebug("WSA error : WSAENAMETOOLONG"); break; + case WSAEHOSTDOWN: qDebug("WSA error : WSAEHOSTDOWN"); break; + case WSAEHOSTUNREACH: qDebug("WSA error : WSAEHOSTUNREACH"); break; + case WSAENOTEMPTY: qDebug("WSA error : WSAENOTEMPTY"); break; + case WSAEPROCLIM: qDebug("WSA error : WSAEPROCLIM"); break; + case WSAEUSERS: qDebug("WSA error : WSAEUSERS"); break; + case WSAEDQUOT: qDebug("WSA error : WSAEDQUOT"); break; + case WSAESTALE: qDebug("WSA error : WSAESTALE"); break; + case WSAEREMOTE: qDebug("WSA error : WSAEREMOTE"); break; + case WSAEDISCON: qDebug("WSA error : WSAEDISCON"); break; + default: qDebug("WSA error : Unknown"); break; + } + qErrnoWarning(r, "more details"); +} + +/* + Returns a human readable representation of the first \a len + characters in \a data. +*/ +static QByteArray qt_prettyDebug(const char *data, int len, int maxLength) +{ + if (!data) return "(null)"; + QByteArray out; + for (int i = 0; i < len; ++i) { + char c = data[i]; + if (isprint(int(uchar(c)))) { + out += c; + } else switch (c) { + case '\n': out += "\\n"; break; + case '\r': out += "\\r"; break; + case '\t': out += "\\t"; break; + default: + QString tmp; + tmp.sprintf("\\%o", c); + out += tmp.toLatin1().constData(); + } + } + + if (len < maxLength) + out += "..."; + + return out; +} + + +#define WS_ERROR_DEBUG(x) verboseWSErrorDebug(x); + +#else + +#define WS_ERROR_DEBUG(x) Q_UNUSED(x) + +#endif + +#ifndef AF_INET6 +#define AF_INET6 23 /* Internetwork Version 6 */ +#endif + +#ifndef SO_EXCLUSIVEADDRUSE +#define SO_EXCLUSIVEADDRUSE ((int)(~SO_REUSEADDR)) /* disallow local address reuse */ +#endif + +/* + Extracts the port and address from a sockaddr, and stores them in + \a port and \a addr if they are non-null. +*/ +static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, const qt_sockaddr *sa, quint16 *port, QHostAddress *address) +{ + if (sa->a.sa_family == AF_INET6) { + const qt_sockaddr_in6 *sa6 = &sa->a6; + Q_IPV6ADDR tmp; + for (int i = 0; i < 16; ++i) + tmp.c[i] = sa6->sin6_addr.qt_s6_addr[i]; + if (address) { + QHostAddress a; + a.setAddress(tmp); + a.setScopeId(QString::number(sa6->sin6_scope_id)); + *address = a; + } + if (port) + WSANtohs(socketDescriptor, sa6->sin6_port, port); + } else + + if (sa->a.sa_family == AF_INET) { + const sockaddr_in *sa4 = &sa->a4; + unsigned long addr; + WSANtohl(socketDescriptor, sa4->sin_addr.s_addr, &addr); + QHostAddress a; + a.setAddress(addr); + if (address) + *address = a; + if (port) + WSANtohs(socketDescriptor, sa4->sin_port, port); + } +} + + +/*! \internal + + Sets the port and address to a sockaddr. Requires that sa point to the IPv6 struct if the address is IPv6. +*/ +void QNativeSocketEnginePrivate::setPortAndAddress(sockaddr_in * sockAddrIPv4, qt_sockaddr_in6 * sockAddrIPv6, + quint16 port, const QHostAddress & address, sockaddr ** sockAddrPtr, QT_SOCKLEN_T *sockAddrSize) +{ + if (address.protocol() == QAbstractSocket::IPv6Protocol + || address.protocol() == QAbstractSocket::AnyIPProtocol + || socketProtocol == QAbstractSocket::IPv6Protocol + || socketProtocol == QAbstractSocket::AnyIPProtocol) { + memset(sockAddrIPv6, 0, sizeof(qt_sockaddr_in6)); + sockAddrIPv6->sin6_family = AF_INET6; + sockAddrIPv6->sin6_scope_id = address.scopeId().toInt(); + WSAHtons(socketDescriptor, port, &(sockAddrIPv6->sin6_port)); + Q_IPV6ADDR tmp = address.toIPv6Address(); + memcpy(&(sockAddrIPv6->sin6_addr.qt_s6_addr), &tmp, sizeof(tmp)); + *sockAddrSize = sizeof(qt_sockaddr_in6); + *sockAddrPtr = (struct sockaddr *) sockAddrIPv6; + } else + + if (address.protocol() == QAbstractSocket::IPv4Protocol + || address.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) { + memset(sockAddrIPv4, 0, sizeof(sockaddr_in)); + sockAddrIPv4->sin_family = AF_INET; + WSAHtons(socketDescriptor, port, &(sockAddrIPv4->sin_port)); + WSAHtonl(socketDescriptor, address.toIPv4Address(), &(sockAddrIPv4->sin_addr.s_addr)); + *sockAddrSize = sizeof(sockaddr_in); + *sockAddrPtr = (struct sockaddr *) sockAddrIPv4; + } else { + // unreachable + } +} + +/*! \internal + +*/ +static inline QAbstractSocket::SocketType qt_socket_getType(qintptr socketDescriptor) +{ + int value = 0; + QT_SOCKLEN_T valueSize = sizeof(value); + if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, (char *) &value, &valueSize) != 0) { + WS_ERROR_DEBUG(WSAGetLastError()); + } else { + if (value == SOCK_STREAM) + return QAbstractSocket::TcpSocket; + else if (value == SOCK_DGRAM) + return QAbstractSocket::UdpSocket; + } + return QAbstractSocket::UnknownSocketType; +} + +/*! \internal + +*/ +static inline int qt_socket_getMaxMsgSize(qintptr socketDescriptor) +{ + int value = 0; + QT_SOCKLEN_T valueSize = sizeof(value); + if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *) &value, &valueSize) != 0) { + WS_ERROR_DEBUG(WSAGetLastError()); + } + return value; +} + +QWindowsSockInit::QWindowsSockInit() +: version(0) +{ + //### should we try for 2.2 on all platforms ?? + WSAData wsadata; + + // IPv6 requires Winsock v2.0 or better. + if (WSAStartup(MAKEWORD(2,0), &wsadata) != 0) { + qWarning("QTcpSocketAPI: WinSock v2.0 initialization failed."); + } else { + version = 0x20; + } +} + +QWindowsSockInit::~QWindowsSockInit() +{ + WSACleanup(); +} + +// MS Transport Provider IOCTL to control +// reporting PORT_UNREACHABLE messages +// on UDP sockets via recv/WSARecv/etc. +// Path TRUE in input buffer to enable (default if supported), +// FALSE to disable. +#ifndef SIO_UDP_CONNRESET +# ifndef IOC_VENDOR +# define IOC_VENDOR 0x18000000 +# endif +# ifndef _WSAIOW +# define _WSAIOW(x,y) (IOC_IN|(x)|(y)) +# endif +# define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) +#endif + +bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol) +{ + + //### no ip6 support on winsocket 1.1 but we will try not to use this !!!!!!!!!!!!1 + /* + if (winsockVersion < 0x20 && socketProtocol == QAbstractSocket::IPv6Protocol) { + //### no ip6 support + return -1; + } + */ + QSysInfo::WinVersion osver = QSysInfo::windowsVersion(); + + //Windows XP and 2003 support IPv6 but not dual stack sockets + int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol + || (socketProtocol == QAbstractSocket::AnyIPProtocol && osver >= QSysInfo::WV_6_0)) ? AF_INET6 : AF_INET; + int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM; + + // MSDN KB179942 states that on winnt 4 WSA_FLAG_OVERLAPPED is needed if socket is to be non blocking + // and recomends alwasy doing it for cross windows version comapablity. + + // WSA_FLAG_NO_HANDLE_INHERIT is atomic (like linux O_CLOEXEC), but requires windows 7 SP 1 or later + // SetHandleInformation is supported since W2K but isn't atomic +#ifndef WSA_FLAG_NO_HANDLE_INHERIT +#define WSA_FLAG_NO_HANDLE_INHERIT 0x80 +#endif + + SOCKET socket = INVALID_SOCKET; + // Windows 7 or later, try the new API + if ((osver & QSysInfo::WV_NT_based) >= QSysInfo::WV_6_1) + socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED); + // previous call fails if the windows 7 service pack 1 or hot fix isn't installed. + + // Try the old API if the new one failed on Windows 7, or always on earlier versions + if (socket == INVALID_SOCKET && ((osver & QSysInfo::WV_NT_based) <= QSysInfo::WV_6_1)) { + socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_OVERLAPPED); +#ifdef HANDLE_FLAG_INHERIT + if (socket != INVALID_SOCKET) { + // make non inheritable the old way + BOOL handleFlags = SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0); +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QNativeSocketEnginePrivate::createNewSocket - set inheritable" << handleFlags; +#else + Q_UNUSED(handleFlags); +#endif + } +#endif + } + + if (socket == INVALID_SOCKET) { + int err = WSAGetLastError(); + WS_ERROR_DEBUG(err); + switch (err) { + case WSANOTINITIALISED: + //### + break; + case WSAEAFNOSUPPORT: + case WSAESOCKTNOSUPPORT: + case WSAEPROTOTYPE: + case WSAEINVAL: + setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString); + break; + case WSAEMFILE: + case WSAENOBUFS: + setError(QAbstractSocket::SocketResourceError, ResourceErrorString); + break; + default: + break; + } + + return false; + } + +#if !defined(Q_OS_WINCE) + if (socketType == QAbstractSocket::UdpSocket) { + // enable new behavior using + // SIO_UDP_CONNRESET + DWORD dwBytesReturned = 0; + int bNewBehavior = 1; + if (::WSAIoctl(socket, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior), + NULL, 0, &dwBytesReturned, NULL, NULL) == SOCKET_ERROR) { + // not to worry isBogusUdpReadNotification() should handle this otherwise + int err = WSAGetLastError(); + WS_ERROR_DEBUG(err); + } + } +#endif + + socketDescriptor = socket; + return true; + +} + +/*! \internal + + Returns the value of the socket option \a opt. +*/ +int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const +{ + Q_Q(const QNativeSocketEngine); + if (!q->isValid()) + return -1; + + int n = -1; + int level = SOL_SOCKET; // default + + switch (opt) { + case QNativeSocketEngine::ReceiveBufferSocketOption: + n = SO_RCVBUF; + break; + case QNativeSocketEngine::SendBufferSocketOption: + n = SO_SNDBUF; + break; + case QNativeSocketEngine::BroadcastSocketOption: + n = SO_BROADCAST; + break; + case QNativeSocketEngine::NonBlockingSocketOption: { + unsigned long buf = 0; + if (WSAIoctl(socketDescriptor, FIONBIO, 0,0, &buf, sizeof(buf), 0,0,0) == 0) + return buf; + else + return -1; + break; + } + case QNativeSocketEngine::AddressReusable: + n = SO_REUSEADDR; + break; + case QNativeSocketEngine::BindExclusively: + n = SO_EXCLUSIVEADDRUSE; + break; + case QNativeSocketEngine::ReceiveOutOfBandData: + n = SO_OOBINLINE; + break; + case QNativeSocketEngine::LowDelayOption: + level = IPPROTO_TCP; + n = TCP_NODELAY; + break; + case QNativeSocketEngine::KeepAliveOption: + n = SO_KEEPALIVE; + break; + case QNativeSocketEngine::MulticastTtlOption: + + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + n = IPV6_MULTICAST_HOPS; + } else + { + level = IPPROTO_IP; + n = IP_MULTICAST_TTL; + } + break; + case QNativeSocketEngine::MulticastLoopbackOption: + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + n = IPV6_MULTICAST_LOOP; + } else + { + level = IPPROTO_IP; + n = IP_MULTICAST_LOOP; + } + break; + case QNativeSocketEngine::TypeOfServiceOption: + return -1; + break; + } + +#if Q_BYTE_ORDER != Q_LITTLE_ENDIAN +#error code assumes windows is little endian +#endif + int v = 0; //note: windows doesn't write to all bytes if the option type is smaller than int + QT_SOCKOPTLEN_T len = sizeof(v); + if (getsockopt(socketDescriptor, level, n, (char *) &v, &len) == 0) + return v; + WS_ERROR_DEBUG(WSAGetLastError()); + return -1; +} + + +/*! \internal + Sets the socket option \a opt to \a v. +*/ +bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v) +{ + Q_Q(const QNativeSocketEngine); + if (!q->isValid()) + return false; + + int n = 0; + int level = SOL_SOCKET; // default + + switch (opt) { + case QNativeSocketEngine::ReceiveBufferSocketOption: + n = SO_RCVBUF; + break; + case QNativeSocketEngine::SendBufferSocketOption: + // see QTBUG-30478 SO_SNDBUF should not be used on Vista or later + if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) + return false; + n = SO_SNDBUF; + break; + case QNativeSocketEngine::BroadcastSocketOption: + n = SO_BROADCAST; + break; + case QNativeSocketEngine::NonBlockingSocketOption: + { + unsigned long buf = v; + unsigned long outBuf; + DWORD sizeWritten = 0; + if (::WSAIoctl(socketDescriptor, FIONBIO, &buf, sizeof(unsigned long), &outBuf, sizeof(unsigned long), &sizeWritten, 0,0) == SOCKET_ERROR) { + WS_ERROR_DEBUG(WSAGetLastError()); + return false; + } + return true; + break; + } + case QNativeSocketEngine::AddressReusable: + n = SO_REUSEADDR; + break; + case QNativeSocketEngine::BindExclusively: + n = SO_EXCLUSIVEADDRUSE; + break; + case QNativeSocketEngine::ReceiveOutOfBandData: + n = SO_OOBINLINE; + break; + case QNativeSocketEngine::LowDelayOption: + level = IPPROTO_TCP; + n = TCP_NODELAY; + break; + case QNativeSocketEngine::KeepAliveOption: + n = SO_KEEPALIVE; + break; + case QNativeSocketEngine::MulticastTtlOption: + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + n = IPV6_MULTICAST_HOPS; + } else + { + level = IPPROTO_IP; + n = IP_MULTICAST_TTL; + } + break; + case QNativeSocketEngine::MulticastLoopbackOption: + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + n = IPV6_MULTICAST_LOOP; + } else + { + level = IPPROTO_IP; + n = IP_MULTICAST_LOOP; + } + break; + case QNativeSocketEngine::TypeOfServiceOption: + return false; + break; + } + + if (::setsockopt(socketDescriptor, level, n, (char*)&v, sizeof(v)) != 0) { + WS_ERROR_DEBUG(WSAGetLastError()); + return false; + } + return true; +} + +/*! + Fetches information about both ends of the connection: whatever is + available. +*/ +bool QNativeSocketEnginePrivate::fetchConnectionParameters() +{ + localPort = 0; + localAddress.clear(); + peerPort = 0; + peerAddress.clear(); + + if (socketDescriptor == -1) + return false; + + qt_sockaddr sa; + QT_SOCKLEN_T sockAddrSize = sizeof(sa); + + // Determine local address + memset(&sa, 0, sizeof(sa)); + if (::getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) { + qt_socket_getPortAndAddress(socketDescriptor, &sa, &localPort, &localAddress); + // Determine protocol family + switch (sa.a.sa_family) { + case AF_INET: + socketProtocol = QAbstractSocket::IPv4Protocol; + break; + case AF_INET6: + socketProtocol = QAbstractSocket::IPv6Protocol; + break; + default: + socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; + break; + } + } else { + int err = WSAGetLastError(); + WS_ERROR_DEBUG(err); + if (err == WSAENOTSOCK) { + setError(QAbstractSocket::UnsupportedSocketOperationError, + InvalidSocketErrorString); + return false; + } + } + + // determine if local address is dual mode + DWORD ipv6only = 0; + QT_SOCKOPTLEN_T optlen = sizeof(ipv6only); + if (localAddress == QHostAddress::AnyIPv6 + && QSysInfo::windowsVersion() >= QSysInfo::WV_6_0 + && !getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, &optlen )) { + if (!ipv6only) { + socketProtocol = QAbstractSocket::AnyIPProtocol; + localAddress = QHostAddress::Any; + } + } + + memset(&sa, 0, sizeof(sa)); + if (::getpeername(socketDescriptor, &sa.a, &sockAddrSize) == 0) { + qt_socket_getPortAndAddress(socketDescriptor, &sa, &peerPort, &peerAddress); + } else { + WS_ERROR_DEBUG(WSAGetLastError()); + } + + socketType = qt_socket_getType(socketDescriptor); + +#if defined (QNATIVESOCKETENGINE_DEBUG) + QString socketProtocolStr = "UnknownProtocol"; + if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = "IPv4Protocol"; + else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = "IPv6Protocol"; + + QString socketTypeStr = "UnknownSocketType"; + if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket"; + else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket"; + + qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() localAddress == %s, localPort = %i, peerAddress == %s, peerPort = %i, socketProtocol == %s, socketType == %s", localAddress.toString().toLatin1().constData(), localPort, peerAddress.toString().toLatin1().constData(), peerPort, socketProtocolStr.toLatin1().constData(), socketTypeStr.toLatin1().constData()); +#endif + + return true; +} + + +bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quint16 port) +{ + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeConnect() to %s :: %i", address.toString().toLatin1().constData(), port); +#endif + + struct sockaddr_in sockAddrIPv4; + qt_sockaddr_in6 sockAddrIPv6; + struct sockaddr *sockAddrPtr = 0; + QT_SOCKLEN_T sockAddrSize = 0; + + setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); + + if (socketProtocol == QAbstractSocket::IPv6Protocol && address.toIPv4Address()) { + //IPV6_V6ONLY option must be cleared to connect to a V4 mapped address + if (QSysInfo::windowsVersion() >= QSysInfo::WV_6_0) { + DWORD ipv6only = 0; + ipv6only = ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) ); + } + } + + forever { + int connectResult = ::WSAConnect(socketDescriptor, sockAddrPtr, sockAddrSize, 0,0,0,0); + if (connectResult == SOCKET_ERROR) { + int err = WSAGetLastError(); + WS_ERROR_DEBUG(err); + + switch (err) { + case WSANOTINITIALISED: + //### + break; + case WSAEISCONN: + socketState = QAbstractSocket::ConnectedState; + break; + case WSAEWOULDBLOCK: { + // If WSAConnect returns WSAEWOULDBLOCK on the second + // connection attempt, we have to check SO_ERROR's + // value to detect ECONNREFUSED. If we don't get + // ECONNREFUSED, we'll have to treat it as an + // unfinished operation. + int value = 0; + QT_SOCKLEN_T valueSize = sizeof(value); + bool tryAgain = false; + bool errorDetected = false; + int tries = 0; + do { + if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_ERROR, (char *) &value, &valueSize) == 0) { + if (value == WSAECONNREFUSED) { + setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); + socketState = QAbstractSocket::UnconnectedState; + errorDetected = true; + break; + } + if (value == WSAETIMEDOUT) { + setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); + socketState = QAbstractSocket::UnconnectedState; + errorDetected = true; + break; + } + if (value == WSAEHOSTUNREACH) { + setError(QAbstractSocket::NetworkError, HostUnreachableErrorString); + socketState = QAbstractSocket::UnconnectedState; + errorDetected = true; + break; + } + if (value == WSAENETUNREACH) { + setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); + socketState = QAbstractSocket::UnconnectedState; + errorDetected = true; + break; + } + if (value == WSAEADDRNOTAVAIL) { + setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString); + socketState = QAbstractSocket::UnconnectedState; + errorDetected = true; + break; + } + if (value == NOERROR) { + // When we get WSAEWOULDBLOCK the outcome was not known, so a + // NOERROR might indicate that the result of the operation + // is still unknown. We try again to increase the chance that we did + // get the correct result. + tryAgain = !tryAgain; + } + } + tries++; + } while (tryAgain && (tries < 2)); + + if (errorDetected) + break; + // fall through + } + case WSAEINPROGRESS: + setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString); + socketState = QAbstractSocket::ConnectingState; + break; + case WSAEADDRINUSE: + setError(QAbstractSocket::NetworkError, AddressInuseErrorString); + break; + case WSAECONNREFUSED: + setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + case WSAETIMEDOUT: + setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); + break; + case WSAEACCES: + setError(QAbstractSocket::SocketAccessError, AccessErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + case WSAEHOSTUNREACH: + setError(QAbstractSocket::NetworkError, HostUnreachableErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + case WSAENETUNREACH: + setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + case WSAEINVAL: + case WSAEALREADY: + setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString); + break; + default: + break; + } + if (socketState != QAbstractSocket::ConnectedState) { +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)", + address.toString().toLatin1().constData(), port, + socketState == QAbstractSocket::ConnectingState + ? "Connection in progress" : socketErrorString.toLatin1().constData()); +#endif + return false; + } + } + break; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true", + address.toString().toLatin1().constData(), port); +#endif + + socketState = QAbstractSocket::ConnectedState; + return true; +} + + +bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &a, quint16 port) +{ + QHostAddress address = a; + DWORD ipv6only = 0; + switch (address.protocol()) { + case QAbstractSocket::IPv6Protocol: + if (address.toIPv6Address()[0] == 0xff) { + // binding to a multicast address + address = QHostAddress(QHostAddress::AnyIPv6); + } + //This is default in current windows versions, it may change in future so set it explicitly + if (QSysInfo::windowsVersion() >= QSysInfo::WV_6_0) { + ipv6only = 1; + ipv6only = ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) ); + } + break; + case QAbstractSocket::IPv4Protocol: + if ((address.toIPv4Address() & 0xffff0000) == 0xefff0000) { + // binding to a multicast address + address = QHostAddress(QHostAddress::AnyIPv4); + } + break; + case QAbstractSocket::AnyIPProtocol: + if (QSysInfo::windowsVersion() >= QSysInfo::WV_6_0) { + ipv6only = ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) ); + } else { + address = QHostAddress(QHostAddress::AnyIPv4); //xp/WS2003 and earlier don't support dual stack, so bind to IPv4 + socketProtocol = QAbstractSocket::IPv4Protocol; + } + break; + default: + break; + } + + struct sockaddr_in sockAddrIPv4; + qt_sockaddr_in6 sockAddrIPv6; + struct sockaddr *sockAddrPtr = 0; + QT_SOCKLEN_T sockAddrSize = 0; + + setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); + + + int bindResult = ::bind(socketDescriptor, sockAddrPtr, sockAddrSize); + if (bindResult == SOCKET_ERROR) { + int err = WSAGetLastError(); + WS_ERROR_DEBUG(err); + switch (err) { + case WSANOTINITIALISED: + //### + break; + case WSAEADDRINUSE: + case WSAEINVAL: + setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); + break; + case WSAEACCES: + setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString); + break; + case WSAEADDRNOTAVAIL: + setError(QAbstractSocket::SocketAddressNotAvailableError, AddressNotAvailableErrorString); + break; + default: + break; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)", + address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData()); +#endif + + return false; + } + + localPort = port; + localAddress = address; + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true", + address.toString().toLatin1().constData(), port); +#endif + socketState = QAbstractSocket::BoundState; + return true; +} + + +bool QNativeSocketEnginePrivate::nativeListen(int backlog) +{ + if (::listen(socketDescriptor, backlog) == SOCKET_ERROR) { + int err = WSAGetLastError(); + WS_ERROR_DEBUG(err); + switch (err) { + case WSANOTINITIALISED: + //### + break; + case WSAEADDRINUSE: + setError(QAbstractSocket::AddressInUseError, + PortInuseErrorString); + break; + default: + break; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)", + backlog, socketErrorString.toLatin1().constData()); +#endif + return false; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog); +#endif + + socketState = QAbstractSocket::ListeningState; + return true; +} + +int QNativeSocketEnginePrivate::nativeAccept() +{ + int acceptedDescriptor = WSAAccept(socketDescriptor, 0,0,0,0); + if (acceptedDescriptor == -1) { + int err = WSAGetLastError(); + switch (err) { + case WSAEACCES: + setError(QAbstractSocket::SocketAccessError, AccessErrorString); + break; + case WSAECONNREFUSED: + setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); + break; + case WSAECONNRESET: + setError(QAbstractSocket::NetworkError, RemoteHostClosedErrorString); + break; + case WSAENETDOWN: + setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); + case WSAENOTSOCK: + setError(QAbstractSocket::SocketResourceError, NotSocketErrorString); + break; + case WSAEINVAL: + case WSAEOPNOTSUPP: + setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString); + break; + case WSAEFAULT: + case WSAEMFILE: + case WSAENOBUFS: + setError(QAbstractSocket::SocketResourceError, ResourceErrorString); + break; + case WSAEWOULDBLOCK: + setError(QAbstractSocket::TemporaryError, TemporaryErrorString); + break; + default: + setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString); + break; + } + } else if (acceptedDescriptor != -1 && QAbstractEventDispatcher::instance()) { + // Because of WSAAsyncSelect() WSAAccept returns a non blocking socket + // with the same attributes as the listening socket including the current + // WSAAsyncSelect(). To be able to change the socket to blocking mode the + // WSAAsyncSelect() call must be cancled. + QSocketNotifier n(acceptedDescriptor, QSocketNotifier::Read); + n.setEnabled(true); + n.setEnabled(false); + } +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor); +#endif + return acceptedDescriptor; +} + +static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d, + int how6, + int how4, + const QHostAddress &groupAddress, + const QNetworkInterface &iface) +{ + int level = 0; + int sockOpt = 0; + char *sockArg; + int sockArgSize; + + struct ip_mreq mreq4; + struct ipv6_mreq mreq6; + + if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + sockOpt = how6; + sockArg = reinterpret_cast(&mreq6); + sockArgSize = sizeof(mreq6); + memset(&mreq6, 0, sizeof(mreq6)); + Q_IPV6ADDR ip6 = groupAddress.toIPv6Address(); + memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6)); + mreq6.ipv6mr_interface = iface.index(); + } else + + if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) { + level = IPPROTO_IP; + sockOpt = how4; + sockArg = reinterpret_cast(&mreq4); + sockArgSize = sizeof(mreq4); + memset(&mreq4, 0, sizeof(mreq4)); + mreq4.imr_multiaddr.s_addr = htonl(groupAddress.toIPv4Address()); + + if (iface.isValid()) { + QList addressEntries = iface.addressEntries(); + if (!addressEntries.isEmpty()) { + QHostAddress firstIP = addressEntries.first().ip(); + mreq4.imr_interface.s_addr = htonl(firstIP.toIPv4Address()); + } else { + d->setError(QAbstractSocket::NetworkError, + QNativeSocketEnginePrivate::NetworkUnreachableErrorString); + return false; + } + } else { + mreq4.imr_interface.s_addr = INADDR_ANY; + } + } else { + // unreachable + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + QNativeSocketEnginePrivate::ProtocolUnsupportedErrorString); + return false; + } + + int res = setsockopt(d->socketDescriptor, level, sockOpt, sockArg, sockArgSize); + if (res == -1) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + QNativeSocketEnginePrivate::OperationUnsupportedErrorString); + return false; + } + return true; +} + +bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface) +{ + return multicastMembershipHelper(this, + IPV6_JOIN_GROUP, + IP_ADD_MEMBERSHIP, + groupAddress, + iface); +} + +bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface) +{ + return multicastMembershipHelper(this, + IPV6_LEAVE_GROUP, + IP_DROP_MEMBERSHIP, + groupAddress, + iface); +} + +QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const +{ + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + uint v; + QT_SOCKOPTLEN_T sizeofv = sizeof(v); + if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &v, &sizeofv) == -1) + return QNetworkInterface(); + return QNetworkInterface::interfaceFromIndex(v); + } + + struct in_addr v; + v.s_addr = 0; + QT_SOCKOPTLEN_T sizeofv = sizeof(v); + if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, &sizeofv) == -1) + return QNetworkInterface(); + if (v.s_addr != 0 && sizeofv >= QT_SOCKOPTLEN_T(sizeof(v))) { + QHostAddress ipv4(ntohl(v.s_addr)); + QList ifaces = QNetworkInterface::allInterfaces(); + for (int i = 0; i < ifaces.count(); ++i) { + const QNetworkInterface &iface = ifaces.at(i); + if (!(iface.flags() & QNetworkInterface::CanMulticast)) + continue; + QList entries = iface.addressEntries(); + for (int j = 0; j < entries.count(); ++j) { + const QNetworkAddressEntry &entry = entries.at(j); + if (entry.ip() == ipv4) + return iface; + } + } + } + return QNetworkInterface(); +} + +bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface) +{ + + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + uint v = iface.isValid() ? iface.index() : 0; + return (::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &v, sizeof(v)) != -1); + } + + struct in_addr v; + if (iface.isValid()) { + QList entries = iface.addressEntries(); + for (int i = 0; i < entries.count(); ++i) { + const QNetworkAddressEntry &entry = entries.at(i); + const QHostAddress &ip = entry.ip(); + if (ip.protocol() == QAbstractSocket::IPv4Protocol) { + v.s_addr = htonl(ip.toIPv4Address()); + int r = ::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, sizeof(v)); + if (r != -1) + return true; + } + } + return false; + } + + v.s_addr = INADDR_ANY; + return (::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, sizeof(v)) != -1); +} + +qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const +{ + unsigned long nbytes = 0; + unsigned long dummy = 0; + DWORD sizeWritten = 0; + if (::WSAIoctl(socketDescriptor, FIONREAD, &dummy, sizeof(dummy), &nbytes, sizeof(nbytes), &sizeWritten, 0,0) == SOCKET_ERROR) { + WS_ERROR_DEBUG(WSAGetLastError()); + return -1; + } + + // ioctlsocket sometimes reports 1 byte available for datagrams + // while the following recvfrom returns -1 and claims connection + // was reset (udp is connectionless). so we peek one byte to + // catch this case and return 0 bytes available if recvfrom + // fails. + if (nbytes == 1 && socketType == QAbstractSocket::UdpSocket) { + char c; + WSABUF buf; + buf.buf = &c; + buf.len = sizeof(c); + DWORD flags = MSG_PEEK; + if (::WSARecvFrom(socketDescriptor, &buf, 1, 0, &flags, 0,0,0,0) == SOCKET_ERROR) + return 0; + } + return nbytes; +} + + +bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const +{ +#if !defined(Q_OS_WINCE) + // Create a sockaddr struct and reset its port number. + qt_sockaddr storage; + QT_SOCKLEN_T storageSize = sizeof(storage); + memset(&storage, 0, storageSize); + + bool result = false; + + // Peek 0 bytes into the next message. The size of the message may + // well be 0, so we check if there was a sender. + char c; + WSABUF buf; + buf.buf = &c; + buf.len = sizeof(c); + DWORD available = 0; + DWORD flags = MSG_PEEK; + int ret = ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags, &storage.a, &storageSize,0,0); + int err = WSAGetLastError(); + if (ret == SOCKET_ERROR && err != WSAEMSGSIZE) { + WS_ERROR_DEBUG(err); + if (err == WSAECONNRESET) { + // Discard error message to prevent QAbstractSocket from + // getting this message repeatedly after reenabling the + // notifiers. + flags = 0; + ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags, + &storage.a, &storageSize, 0, 0); + } + } else { + // If there's no error, or if our buffer was too small, there must be + // a pending datagram. + result = true; + } + +#else // Q_OS_WINCE + bool result = false; + fd_set readS; + FD_ZERO(&readS); + FD_SET((SOCKET)socketDescriptor, &readS); + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 5000; + int available = ::select(1, &readS, 0, 0, &timeout); + result = available > 0 ? true : false; +#endif + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeHasPendingDatagrams() == %s", + result ? "true" : "false"); +#endif + return result; +} + + +qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const +{ + qint64 ret = -1; +#if !defined(Q_OS_WINCE) + int recvResult = 0; + DWORD flags; + DWORD bufferCount = 5; + WSABUF * buf = 0; + for (;;) { + // the data written to udpMessagePeekBuffer is discarded, so + // this function is still reentrant although it might not look + // so. + static char udpMessagePeekBuffer[8192]; + + buf = new WSABUF[bufferCount]; + for (DWORD i=0; i maxLength ? maxLength : qint64(bytesRead); + } else { + WS_ERROR_DEBUG(err); + setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); + ret = -1; + } + } else { + ret = qint64(bytesRead); + } + + qt_socket_getPortAndAddress(socketDescriptor, &aa, port, address); + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %li, %s, %i) == %li", + data, qt_prettyDebug(data, qMin(ret, 16), ret).data(), maxLength, + address ? address->toString().toLatin1().constData() : "(nil)", + port ? *port : 0, ret); +#endif + + return ret; +} + + +qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, + const QHostAddress &address, quint16 port) +{ + qint64 ret = -1; + struct sockaddr_in sockAddrIPv4; + qt_sockaddr_in6 sockAddrIPv6; + struct sockaddr *sockAddrPtr = 0; + QT_SOCKLEN_T sockAddrSize = 0; + + setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); + + WSABUF buf; +#if !defined(Q_OS_WINCE) + buf.buf = len ? (char*)data : 0; +#else + char tmp; + buf.buf = len ? (char*)data : &tmp; +#endif + buf.len = len; + DWORD flags = 0; + DWORD bytesSent = 0; + if (::WSASendTo(socketDescriptor, &buf, 1, &bytesSent, flags, sockAddrPtr, sockAddrSize, 0,0) == SOCKET_ERROR) { + int err = WSAGetLastError(); + WS_ERROR_DEBUG(err); + switch (err) { + case WSAEMSGSIZE: + setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); + break; + default: + setError(QAbstractSocket::NetworkError, SendDatagramErrorString); + break; + } + ret = -1; + } else { + ret = qint64(bytesSent); + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeSendDatagram(%p \"%s\", %li, \"%s\", %i) == %li", data, + qt_prettyDebug(data, qMin(len, 16), len).data(), 0, address.toString().toLatin1().constData(), + port, ret); +#endif + + return ret; +} + + +qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) +{ + Q_Q(QNativeSocketEngine); + qint64 ret = 0; + qint64 bytesToSend = len; + + for (;;) { + WSABUF buf; + buf.buf = (char*)data + ret; + buf.len = bytesToSend; + DWORD flags = 0; + DWORD bytesWritten = 0; + + int socketRet = ::WSASend(socketDescriptor, &buf, 1, &bytesWritten, flags, 0,0); + + ret += qint64(bytesWritten); + + int err; + if (socketRet != SOCKET_ERROR) { + if (ret == len) + break; + else + continue; + } else if ((err = WSAGetLastError()) == WSAEWOULDBLOCK) { + break; + } else if (err == WSAENOBUFS) { + // this function used to not send more than 49152 per call to WSASendTo + // to avoid getting a WSAENOBUFS. However this is a performance regression + // and we think it only appears with old windows versions. We now handle the + // WSAENOBUFS and hope it never appears anyway. + // just go on, the next loop run we will try a smaller number + } else { + WS_ERROR_DEBUG(err); + switch (err) { + case WSAECONNRESET: + case WSAECONNABORTED: + ret = -1; + setError(QAbstractSocket::NetworkError, WriteErrorString); + q->close(); + break; + default: + break; + } + break; + } + + // for next send: + bytesToSend = qMin(49152, len - ret); + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %li) == %li", + data, qt_prettyDebug(data, qMin((int)ret, 16), (int)ret).data(), (int)len, (int)ret); +#endif + + return ret; +} + +qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxLength) +{ + qint64 ret = -1; + WSABUF buf; + buf.buf = data; + buf.len = maxLength; + DWORD flags = 0; + DWORD bytesRead = 0; +#if defined(Q_OS_WINCE) + WSASetLastError(0); +#endif + if (::WSARecv(socketDescriptor, &buf, 1, &bytesRead, &flags, 0,0) == SOCKET_ERROR) { + int err = WSAGetLastError(); + WS_ERROR_DEBUG(err); + switch (err) { + case WSAEWOULDBLOCK: + ret = -2; + break; + case WSAEBADF: + case WSAEINVAL: + //error string is now set in read(), not here in nativeRead() + break; + case WSAECONNRESET: + case WSAECONNABORTED: + // for tcp sockets this will be handled in QNativeSocketEngine::read + ret = 0; + break; + default: + break; + } + } else { + if (WSAGetLastError() == WSAEWOULDBLOCK) + ret = -2; + else + ret = qint64(bytesRead); + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + if (ret != -2) { + qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %li) == %li", + data, qt_prettyDebug(data, qMin((int)bytesRead, 16), (int)bytesRead).data(), (int)maxLength, (int)ret); + } else { + qDebug("QNativeSocketEnginePrivate::nativeRead(%p, %li) == -2 (WOULD BLOCK)", + data, int(maxLength)); + } +#endif + + return ret; +} + +int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const +{ + bool readEnabled = selectForRead && readNotifier && readNotifier->isEnabled(); + if (readEnabled) + readNotifier->setEnabled(false); + + fd_set fds; + + int ret = 0; + + memset(&fds, 0, sizeof(fd_set)); + fds.fd_count = 1; + fds.fd_array[0] = (SOCKET)socketDescriptor; + + struct timeval tv; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + if (selectForRead) { + ret = select(0, &fds, 0, 0, timeout < 0 ? 0 : &tv); + } else { + // select for write + + // Windows needs this to report errors when connecting a socket ... + fd_set fdexception; + FD_ZERO(&fdexception); + FD_SET((SOCKET)socketDescriptor, &fdexception); + + ret = select(0, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv); + + // ... but if it is actually set, pretend it did not happen + if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception)) + ret--; + } + + if (readEnabled) + readNotifier->setEnabled(true); + + return ret; +} + +int QNativeSocketEnginePrivate::nativeSelect(int timeout, + bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite) const +{ + bool readEnabled = checkRead && readNotifier && readNotifier->isEnabled(); + if (readEnabled) + readNotifier->setEnabled(false); + + fd_set fdread; + fd_set fdwrite; + fd_set fdexception; + + int ret = 0; + + memset(&fdread, 0, sizeof(fd_set)); + if (checkRead) { + fdread.fd_count = 1; + fdread.fd_array[0] = (SOCKET)socketDescriptor; + } + memset(&fdwrite, 0, sizeof(fd_set)); + FD_ZERO(&fdexception); + if (checkWrite) { + fdwrite.fd_count = 1; + fdwrite.fd_array[0] = (SOCKET)socketDescriptor; + + // Windows needs this to report errors when connecting a socket + FD_SET((SOCKET)socketDescriptor, &fdexception); + } + + struct timeval tv; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + +#if !defined(Q_OS_WINCE) + ret = select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv); +#else + ret = select(1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv); +#endif + + //... but if it is actually set, pretend it did not happen + if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception)) + ret--; + + if (readEnabled) + readNotifier->setEnabled(true); + + if (ret <= 0) + return ret; + + *selectForRead = FD_ISSET((SOCKET)socketDescriptor, &fdread); + *selectForWrite = FD_ISSET((SOCKET)socketDescriptor, &fdwrite); + + return ret; +} + +void QNativeSocketEnginePrivate::nativeClose() +{ +#if defined (QTCPSOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeClose()"); +#endif + // We were doing a setsockopt here before with SO_DONTLINGER. (However with kind of wrong + // usage of parameters, it wants a BOOL but we used a struct and pretended it to be bool). + // We don't think setting this option should be done here, if a user wants it she/he can + // do it manually with socketDescriptor()/setSocketDescriptor(); + ::closesocket(socketDescriptor); +} + +QT_END_NAMESPACE diff --git a/Telegram/_qt_5_3_0_patch/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/Telegram/_qt_5_3_0_patch/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp new file mode 100644 index 000000000..9b9d6e0f9 --- /dev/null +++ b/Telegram/_qt_5_3_0_patch/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -0,0 +1,2274 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#define QT_NO_URL_CAST_FROM_STRING 1 + +#define _WIN32_WINNT 0x0600 + +#include "qwindowsdialoghelpers.h" + +#include "qwindowscontext.h" +#include "qwindowswindow.h" +#include "qwindowsintegration.h" +#include "qwindowstheme.h" // Color conversion helpers + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "qtwindows_additional.h" + +#define STRICT_TYPED_ITEMIDS +#include +#include + +// #define USE_NATIVE_COLOR_DIALOG /* Testing purposes only */ + +#ifdef Q_CC_MINGW /* Add missing declarations for MinGW */ + +#ifndef __IShellLibrary_FWD_DEFINED__ + +/* Constants obtained by running the below stream operator for + * CLSID, IID on the constants in the Windows SDK libraries. */ + +static const IID IID_IFileOpenDialog = {0xd57c7288, 0xd4ad, 0x4768, {0xbe, 0x02, 0x9d, 0x96, 0x95, 0x32, 0xd9, 0x60}}; +static const IID IID_IFileSaveDialog = {0x84bccd23, 0x5fde, 0x4cdb,{0xae, 0xa4, 0xaf, 0x64, 0xb8, 0x3d, 0x78, 0xab}}; +#ifdef __MINGW64_VERSION_MAJOR +static const IID q_IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe}}; +#define IID_IShellItem q_IID_IShellItem +#else +static const IID IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe}}; +static const IID IID_IShellItemArray = {0xb63ea76d, 0x1f85, 0x456f, {0xa1, 0x9c, 0x48, 0x15, 0x9e, 0xfa, 0x85, 0x8b}}; +# define LFF_FORCEFILESYSTEM 1 +#endif +static const IID IID_IFileDialogEvents = {0x973510db, 0x7d7f, 0x452b,{0x89, 0x75, 0x74, 0xa8, 0x58, 0x28, 0xd3, 0x54}}; +static const CLSID CLSID_FileOpenDialog = {0xdc1c5a9c, 0xe88a, 0x4dde, {0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7}}; +static const CLSID CLSID_FileSaveDialog = {0xc0b4e2f3, 0xba21, 0x4773,{0x8d, 0xba, 0x33, 0x5e, 0xc9, 0x46, 0xeb, 0x8b}}; + +typedef struct _COMDLG_FILTERSPEC +{ + LPCWSTR pszName; + LPCWSTR pszSpec; +} COMDLG_FILTERSPEC; + + +#define FOS_OVERWRITEPROMPT 0x2 +#define FOS_STRICTFILETYPES 0x4 +#define FOS_NOCHANGEDIR 0x8 +#define FOS_PICKFOLDERS 0x20 +#define FOS_FORCEFILESYSTEM 0x40 +#define FOS_ALLNONSTORAGEITEMS 0x80 +#define FOS_NOVALIDATE 0x100 +#define FOS_ALLOWMULTISELECT 0x200 +#define FOS_PATHMUSTEXIST 0x800 +#define FOS_FILEMUSTEXIST 0x1000 +#define FOS_CREATEPROMPT 0x2000 +#define FOS_SHAREAWARE 0x4000 +#define FOS_NOREADONLYRETURN 0x8000 +#define FOS_NOTESTFILECREATE 0x10000 +#define FOS_HIDEMRUPLACES 0x20000 +#define FOS_HIDEPINNEDPLACES 0x40000 +#define FOS_NODEREFERENCELINKS 0x100000 +#define FOS_DONTADDTORECENT 0x2000000 +#define FOS_FORCESHOWHIDDEN 0x10000000 +#define FOS_DEFAULTNOMINIMODE 0x20000000 +#define FOS_FORCEPREVIEWPANEON 0x40000000 + +#if __MINGW64_VERSION_MAJOR < 2 +typedef int GETPROPERTYSTOREFLAGS; +#define GPS_DEFAULT 0x00000000 +#define GPS_HANDLERPROPERTIESONLY 0x00000001 +#define GPS_READWRITE 0x00000002 +#define GPS_TEMPORARY 0x00000004 +#define GPS_FASTPROPERTIESONLY 0x00000008 +#define GPS_OPENSLOWITEM 0x00000010 +#define GPS_DELAYCREATION 0x00000020 +#define GPS_BESTEFFORT 0x00000040 +#define GPS_MASK_VALID 0x0000007F +#endif + +typedef int (QT_WIN_CALLBACK* BFFCALLBACK)(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData); +// message from browser +#define BFFM_INITIALIZED 1 +#define BFFM_SELCHANGED 2 +#define BFFM_ENABLEOK (WM_USER + 101) +// Browsing for directory. +#define BIF_NONEWFOLDERBUTTON 0x0200 +#define BIF_NOTRANSLATETARGETS 0x0400 +#define BIF_BROWSEFORCOMPUTER 0x1000 +#define BIF_BROWSEFORPRINTER 0x2000 +#define BIF_BROWSEINCLUDEFILES 0x4000 +#define BIF_SHAREABLE 0x8000 + +//the enums +typedef enum { + SIATTRIBFLAGS_AND = 0x1, + SIATTRIBFLAGS_OR = 0x2, + SIATTRIBFLAGS_APPCOMPAT = 0x3, + SIATTRIBFLAGS_MASK = 0x3 +} SIATTRIBFLAGS; +#ifndef __MINGW64_VERSION_MAJOR +typedef enum { + SIGDN_NORMALDISPLAY = 0x00000000, + SIGDN_PARENTRELATIVEPARSING = 0x80018001, + SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8001c001, + SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, + SIGDN_PARENTRELATIVEEDITING = 0x80031001, + SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, + SIGDN_FILESYSPATH = 0x80058000, + SIGDN_URL = 0x80068000 +} SIGDN; +#endif +typedef enum { + FDAP_BOTTOM = 0x00000000, + FDAP_TOP = 0x00000001 +} FDAP; +typedef enum { + FDESVR_DEFAULT = 0x00000000, + FDESVR_ACCEPT = 0x00000001, + FDESVR_REFUSE = 0x00000002 +} FDE_SHAREVIOLATION_RESPONSE; +typedef FDE_SHAREVIOLATION_RESPONSE FDE_OVERWRITE_RESPONSE; + +//the structs +typedef struct { + LPCWSTR pszName; + LPCWSTR pszSpec; +} qt_COMDLG_FILTERSPEC; +typedef struct { + GUID fmtid; + DWORD pid; +} qt_PROPERTYKEY; + +typedef struct { + USHORT cb; + BYTE abID[1]; +} qt_SHITEMID, *qt_LPSHITEMID; +typedef struct { + qt_SHITEMID mkid; +} qt_ITEMIDLIST, *qt_LPITEMIDLIST; +typedef const qt_ITEMIDLIST *qt_LPCITEMIDLIST; +typedef struct { + HWND hwndOwner; + qt_LPCITEMIDLIST pidlRoot; + LPWSTR pszDisplayName; + LPCWSTR lpszTitle; + UINT ulFlags; + BFFCALLBACK lpfn; + LPARAM lParam; + int iImage; +} qt_BROWSEINFO; + +#endif // __IShellLibrary_FWD_DEFINED__ + +#ifndef __IFileDialogEvents_FWD_DEFINED__ +DECLARE_INTERFACE(IFileDialogEvents); +#endif + +#ifndef __IShellItem_INTERFACE_DEFINED__ +DECLARE_INTERFACE_(IShellItem, IUnknown) +{ + STDMETHOD(BindToHandler)(THIS_ IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppv) PURE; + STDMETHOD(GetParent)(THIS_ IShellItem **ppsi) PURE; + STDMETHOD(GetDisplayName)(THIS_ SIGDN sigdnName, LPWSTR *ppszName) PURE; + STDMETHOD(GetAttributes)(THIS_ ULONG sfgaoMask, ULONG *psfgaoAttribs) PURE; + STDMETHOD(Compare)(THIS_ IShellItem *psi, DWORD hint, int *piOrder) PURE; +}; +#endif + +#ifndef __IShellItemFilter_INTERFACE_DEFINED__ +DECLARE_INTERFACE_(IShellItemFilter, IUnknown) +{ + STDMETHOD(IncludeItem)(THIS_ IShellItem *psi) PURE; + STDMETHOD(GetEnumFlagsForItem)(THIS_ IShellItem *psi, DWORD *pgrfFlags) PURE; +}; +#endif + +#ifndef __IEnumShellItems_INTERFACE_DEFINED__ +DECLARE_INTERFACE_(IEnumShellItems, IUnknown) +{ + STDMETHOD(Next)(THIS_ ULONG celt, IShellItem **rgelt, ULONG *pceltFetched) PURE; + STDMETHOD(Skip)(THIS_ ULONG celt) PURE; + STDMETHOD(Reset)(THIS_) PURE; + STDMETHOD(Clone)(THIS_ IEnumShellItems **ppenum) PURE; +}; +#endif + +#ifndef __IShellItemArray_INTERFACE_DEFINED__ +DECLARE_INTERFACE_(IShellItemArray, IUnknown) +{ + STDMETHOD(BindToHandler)(THIS_ IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut) PURE; + STDMETHOD(GetPropertyStore)(THIS_ GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv) PURE; + STDMETHOD(GetPropertyDescriptionList)(THIS_ const qt_PROPERTYKEY *keyType, REFIID riid, void **ppv) PURE; + STDMETHOD(GetAttributes)(THIS_ SIATTRIBFLAGS dwAttribFlags, ULONG sfgaoMask, ULONG *psfgaoAttribs) PURE; + STDMETHOD(GetCount)(THIS_ DWORD *pdwNumItems) PURE; + STDMETHOD(GetItemAt)(THIS_ DWORD dwIndex, IShellItem **ppsi) PURE; + STDMETHOD(EnumItems)(THIS_ IEnumShellItems **ppenumShellItems) PURE; +}; +#endif + +#ifndef __IShellLibrary_INTERFACE_DEFINED__ + +enum LIBRARYOPTIONFLAGS {}; +enum DEFAULTSAVEFOLDERTYPE { DSFT_DETECT = 1 }; +enum LIBRARYSAVEFLAGS {}; + +DECLARE_INTERFACE_(IShellLibrary, IUnknown) +{ + STDMETHOD(LoadLibraryFromItem)(THIS_ IShellItem *psiLibrary, DWORD grfMode) PURE; + STDMETHOD(LoadLibraryFromKnownFolder)(THIS_ const GUID &kfidLibrary, DWORD grfMode) PURE; + STDMETHOD(AddFolder)(THIS_ IShellItem *psiLocation) PURE; + STDMETHOD(RemoveFolder)(THIS_ IShellItem *psiLocation) PURE; + STDMETHOD(GetFolders)(THIS_ int lff, REFIID riid, void **ppv) PURE; + STDMETHOD(ResolveFolder)(THIS_ IShellItem *psiFolderToResolve, DWORD dwTimeout, REFIID riid, void **ppv) PURE; + STDMETHOD(GetDefaultSaveFolder)(THIS_ DEFAULTSAVEFOLDERTYPE dsft, REFIID riid, void **ppv) PURE; + STDMETHOD(SetDefaultSaveFolder)(THIS_ DEFAULTSAVEFOLDERTYPE dsft, IShellItem *psi) PURE; + STDMETHOD(GetOptions)(THIS_ LIBRARYOPTIONFLAGS *plofOptions) PURE; + STDMETHOD(SetOptions)(THIS_ LIBRARYOPTIONFLAGS lofMask, LIBRARYOPTIONFLAGS lofOptions) PURE; + STDMETHOD(GetFolderType)(THIS_ GUID *pftid) PURE; + STDMETHOD(SetFolderType)(THIS_ const GUID &ftid) PURE; + STDMETHOD(GetIcon)(THIS_ LPWSTR *ppszIcon) PURE; + STDMETHOD(SetIcon)(THIS_ LPCWSTR pszIcon) PURE; + STDMETHOD(Commit)(THIS_) PURE; + STDMETHOD(Save)(THIS_ IShellItem *psiFolderToSaveIn, LPCWSTR pszLibraryName, LIBRARYSAVEFLAGS lsf, IShellItem **ppsiSavedTo) PURE; + STDMETHOD(SaveInKnownFolder)(THIS_ const GUID &kfidToSaveIn, LPCWSTR pszLibraryName, LIBRARYSAVEFLAGS lsf,IShellItem **ppsiSavedTo) PURE; +}; +#endif + +#ifndef __IModalWindow_INTERFACE_DEFINED__ +DECLARE_INTERFACE_(IModalWindow, IUnknown) +{ + STDMETHOD(Show)(THIS_ HWND hwndParent) PURE; +}; +#endif + +#ifndef __IFileDialog_INTERFACE_DEFINED__ +DECLARE_INTERFACE_(IFileDialog, IModalWindow) +{ + STDMETHOD(SetFileTypes)(THIS_ UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec) PURE; + STDMETHOD(SetFileTypeIndex)(THIS_ UINT iFileType) PURE; + STDMETHOD(GetFileTypeIndex)(THIS_ UINT *piFileType) PURE; + STDMETHOD(Advise)(THIS_ IFileDialogEvents *pfde, DWORD *pdwCookie) PURE; + STDMETHOD(Unadvise)(THIS_ DWORD dwCookie) PURE; + STDMETHOD(SetOptions)(THIS_ DWORD fos) PURE; + STDMETHOD(GetOptions)(THIS_ DWORD *pfos) PURE; + STDMETHOD(SetDefaultFolder)(THIS_ IShellItem *psi) PURE; + STDMETHOD(SetFolder)(THIS_ IShellItem *psi) PURE; + STDMETHOD(GetFolder)(THIS_ IShellItem **ppsi) PURE; + STDMETHOD(GetCurrentSelection)(THIS_ IShellItem **ppsi) PURE; + STDMETHOD(SetFileName)(THIS_ LPCWSTR pszName) PURE; + STDMETHOD(GetFileName)(THIS_ LPWSTR *pszName) PURE; + STDMETHOD(SetTitle)(THIS_ LPCWSTR pszTitle) PURE; + STDMETHOD(SetOkButtonLabel)(THIS_ LPCWSTR pszText) PURE; + STDMETHOD(SetFileNameLabel)(THIS_ LPCWSTR pszLabel) PURE; + STDMETHOD(GetResult)(THIS_ IShellItem **ppsi) PURE; + STDMETHOD(AddPlace)(THIS_ IShellItem *psi, FDAP fdap) PURE; + STDMETHOD(SetDefaultExtension)(THIS_ LPCWSTR pszDefaultExtension) PURE; + STDMETHOD(Close)(THIS_ HRESULT hr) PURE; + STDMETHOD(SetClientGuid)(THIS_ REFGUID guid) PURE; + STDMETHOD(ClearClientData)(THIS_) PURE; + STDMETHOD(SetFilter)(THIS_ IShellItemFilter *pFilter) PURE; +}; +#endif + +#ifndef __IFileDialogEvents_INTERFACE_DEFINED__ +DECLARE_INTERFACE_(IFileDialogEvents, IUnknown) +{ + STDMETHOD(OnFileOk)(THIS_ IFileDialog *pfd) PURE; + STDMETHOD(OnFolderChanging)(THIS_ IFileDialog *pfd, IShellItem *psiFolder) PURE; + STDMETHOD(OnFolderChange)(THIS_ IFileDialog *pfd) PURE; + STDMETHOD(OnSelectionChange)(THIS_ IFileDialog *pfd) PURE; + STDMETHOD(OnShareViolation)(THIS_ IFileDialog *pfd, IShellItem *psi, FDE_SHAREVIOLATION_RESPONSE *pResponse) PURE; + STDMETHOD(OnTypeChange)(THIS_ IFileDialog *pfd) PURE; + STDMETHOD(OnOverwrite)(THIS_ IFileDialog *pfd, IShellItem *psi, FDE_OVERWRITE_RESPONSE *pResponse) PURE; +}; +#endif + +#ifndef __IFileOpenDialog_INTERFACE_DEFINED__ +DECLARE_INTERFACE_(IFileOpenDialog, IFileDialog) +{ + STDMETHOD(GetResults)(THIS_ IShellItemArray **ppenum) PURE; + STDMETHOD(GetSelectedItems)(THIS_ IShellItemArray **ppsai) PURE; +}; +#endif + +#ifndef __IPropertyStore_FWD_DEFINED__ +typedef IUnknown IPropertyStore; +#endif + +#ifndef __IFileOperationProgressSink_FWD_DEFINED__ +typedef IUnknown IFileOperationProgressSink; +#endif + +#ifndef __IFileSaveDialog_INTERFACE_DEFINED__ +DECLARE_INTERFACE_(IFileSaveDialog, IFileDialog) +{ +public: + STDMETHOD(SetSaveAsItem)(THIS_ IShellItem *psi) PURE; + STDMETHOD(SetProperties)(THIS_ IPropertyStore *pStore) PURE; + STDMETHOD(SetCollectedProperties)(THIS_ IPropertyStore *pStore) PURE; + STDMETHOD(GetProperties)(THIS_ IPropertyStore **ppStore) PURE; + STDMETHOD(ApplyProperties)(THIS_ IShellItem *psi, IPropertyStore *pStore, HWND hwnd, IFileOperationProgressSink *pSink) PURE; +}; +#endif + +#endif // Q_CC_MINGW + +QT_BEGIN_NAMESPACE + +/* Output UID (IID, CLSID) as C++ constants. + * The constants are contained in the Windows SDK libs, but not for MinGW. */ +static inline QString guidToString(const GUID &g) +{ + QString rc; + QTextStream str(&rc); + str.setIntegerBase(16); + str.setNumberFlags(str.numberFlags() | QTextStream::ShowBase); + str << '{' << g.Data1 << ", " << g.Data2 << ", " << g.Data3; + str.setFieldWidth(2); + str.setFieldAlignment(QTextStream::AlignRight); + str.setPadChar(QLatin1Char('0')); + str << ",{" << g.Data4[0] << ", " << g.Data4[1] << ", " << g.Data4[2] << ", " << g.Data4[3] + << ", " << g.Data4[4] << ", " << g.Data4[5] << ", " << g.Data4[6] << ", " << g.Data4[7] + << "}};"; + return rc; +} + +inline QDebug operator<<(QDebug d, const GUID &g) +{ d.nospace() << guidToString(g); return d; } + +// Return an allocated wchar_t array from a QString, reserve more memory if desired. +static wchar_t *qStringToWCharArray(const QString &s, size_t reserveSize = 0) +{ + const size_t stringSize = s.size(); + wchar_t *result = new wchar_t[qMax(stringSize + 1, reserveSize)]; + s.toWCharArray(result); + result[stringSize] = 0; + return result; +} + +namespace QWindowsDialogs +{ +/*! + \fn eatMouseMove() + + After closing a windows dialog with a double click (i.e. open a file) + the message queue still contains a dubious WM_MOUSEMOVE message where + the left button is reported to be down (wParam != 0). + remove all those messages (usually 1) and post the last one with a + reset button state. + + \ingroup qt-lighthouse-win +*/ + +void eatMouseMove() +{ + MSG msg = {0, 0, 0, 0, 0, {0, 0} }; + while (PeekMessage(&msg, 0, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)) + ; + if (msg.message == WM_MOUSEMOVE) + PostMessage(msg.hwnd, msg.message, 0, msg.lParam); + qCDebug(lcQpaDialogs) << __FUNCTION__ << "triggered=" << (msg.message == WM_MOUSEMOVE); +} + +} // namespace QWindowsDialogs + +/*! + \class QWindowsNativeDialogBase + \brief Base class for Windows native dialogs. + + Base classes for native dialogs (using the CLSID-based + dialog interfaces "IFileDialog", etc. available from Windows + Vista on) that mimick the behaviour of their QDialog + counterparts as close as possible. + + Instances of derived classes are controlled by + QWindowsDialogHelperBase-derived classes. + + A major difference is that there is only an exec(), which + is a modal, blocking call; there is no non-blocking show(). + There 2 types of native dialogs: + + \list + \li Dialogs provided by the Comdlg32 library (ChooseColor, + ChooseFont). They only provide a modal, blocking + function call (with idle processing). + \li File dialogs are classes derived from IFileDialog. They + inherit IModalWindow and their exec() method (calling + IModalWindow::Show()) is similarly blocking, but methods + like close() can be called on them from event handlers. + \endlist + + \sa QWindowsDialogHelperBase + \internal + \ingroup qt-lighthouse-win +*/ + +class QWindowsNativeDialogBase : public QObject +{ + Q_OBJECT +public: + virtual void setWindowTitle(const QString &title) = 0; + bool executed() const { return m_executed; } + void exec(HWND owner = 0) { doExec(owner); m_executed = true; } + +signals: + void accepted(); + void rejected(); + +public slots: + virtual void close() = 0; + +protected: + QWindowsNativeDialogBase() : m_executed(false) {} + +private: + virtual void doExec(HWND owner = 0) = 0; + + bool m_executed; +}; + +/*! + \class QWindowsDialogHelperBase + \brief Helper for native Windows dialogs. + + Provides basic functionality and introduces new virtuals. + The native dialog is created in setVisible_sys() since + then modality and the state of DontUseNativeDialog is known. + + Modal dialogs are then run by exec(). Non-modal dialogs are shown using a + separate thread started in show() should they support it. + + \sa QWindowsDialogThread, QWindowsNativeDialogBase + \internal + \ingroup qt-lighthouse-win +*/ + +template +QWindowsDialogHelperBase::QWindowsDialogHelperBase() : + m_nativeDialog(0), + m_ownerWindow(0), + m_timerId(0), + m_thread(0) +{ +} + +template +void QWindowsDialogHelperBase::cleanupThread() +{ + if (m_thread) { // Thread may be running if the dialog failed to close. + if (m_thread->isRunning()) + m_thread->wait(500); + if (m_thread->isRunning()) { + m_thread->terminate(); + m_thread->wait(300); + if (m_thread->isRunning()) + qCCritical(lcQpaDialogs) <<__FUNCTION__ << "Failed to terminate thread."; + else + qCWarning(lcQpaDialogs) << __FUNCTION__ << "Thread terminated."; + } + delete m_thread; + m_thread = 0; + } +} + +template +QWindowsNativeDialogBase *QWindowsDialogHelperBase::nativeDialog() const +{ + if (m_nativeDialog.isNull()) { + qWarning("%s invoked with no native dialog present.", __FUNCTION__); + return 0; + } + return m_nativeDialog.data(); +} + +template +void QWindowsDialogHelperBase::timerEvent(QTimerEvent *) +{ + startDialogThread(); +} + +template +QWindowsNativeDialogBase *QWindowsDialogHelperBase::ensureNativeDialog() +{ + // Create dialog and apply common settings. Check "executed" flag as well + // since for example IFileDialog::Show() works only once. + if (m_nativeDialog.isNull() || m_nativeDialog->executed()) + m_nativeDialog = QWindowsNativeDialogBasePtr(createNativeDialog()); + return m_nativeDialog.data(); +} + +/*! + \class QWindowsDialogThread + \brief Run a non-modal native dialog in a separate thread. + + \sa QWindowsDialogHelperBase + \internal + \ingroup qt-lighthouse-win +*/ + +class QWindowsDialogThread : public QThread +{ +public: + typedef QSharedPointer QWindowsNativeDialogBasePtr; + + explicit QWindowsDialogThread(const QWindowsNativeDialogBasePtr &d, HWND owner) + : m_dialog(d), m_owner(owner) {} + void run(); + +private: + const QWindowsNativeDialogBasePtr m_dialog; + const HWND m_owner; +}; + +void QWindowsDialogThread::run() +{ + qCDebug(lcQpaDialogs) << '>' << __FUNCTION__; + m_dialog->exec(m_owner); + qCDebug(lcQpaDialogs) << '<' << __FUNCTION__; +} + +template +bool QWindowsDialogHelperBase::show(Qt::WindowFlags, + Qt::WindowModality windowModality, + QWindow *parent) +{ + const bool modal = (windowModality != Qt::NonModal); + if (!parent) + parent = QGuiApplication::focusWindow(); // Need a parent window, else the application loses activation when closed. + if (parent) { + m_ownerWindow = QWindowsWindow::handleOf(parent); + } else { + m_ownerWindow = 0; + } + qCDebug(lcQpaDialogs) << __FUNCTION__ << "modal=" << modal + << " modal supported? " << supportsNonModalDialog(parent) + << "native=" << m_nativeDialog.data() << "owner" << m_ownerWindow; + if (!modal && !supportsNonModalDialog(parent)) + return false; // Was it changed in-between? + if (!ensureNativeDialog()) + return false; + // Start a background thread to show the dialog. For modal dialogs, + // a subsequent call to exec() may follow. So, start an idle timer + // which will start the dialog thread. If exec() is then called, the + // timer is stopped and dialog->exec() is called directly. + cleanupThread(); + if (modal) { + m_timerId = this->startTimer(0); + } else { + startDialogThread(); + } + return true; +} + +template +void QWindowsDialogHelperBase::startDialogThread() +{ + Q_ASSERT(!m_nativeDialog.isNull()); + Q_ASSERT(!m_thread); + m_thread = new QWindowsDialogThread(m_nativeDialog, m_ownerWindow); + m_thread->start(); + stopTimer(); +} + +template +void QWindowsDialogHelperBase::stopTimer() +{ + if (m_timerId) { + this->killTimer(m_timerId); + m_timerId = 0; + } +} + +#ifndef Q_OS_WINCE +// Find a file dialog window created by IFileDialog by process id, window +// title and class, which starts with a hash '#'. + +struct FindDialogContext +{ + explicit FindDialogContext(const QString &titleIn) + : title(qStringToWCharArray(titleIn)), processId(GetCurrentProcessId()), hwnd(0) {} + + const QScopedArrayPointer title; + const DWORD processId; + HWND hwnd; // contains the HWND of the window found. +}; + +static BOOL QT_WIN_CALLBACK findDialogEnumWindowsProc(HWND hwnd, LPARAM lParam) +{ + FindDialogContext *context = reinterpret_cast(lParam); + DWORD winPid = 0; + GetWindowThreadProcessId(hwnd, &winPid); + if (winPid != context->processId) + return TRUE; + wchar_t buf[256]; + if (!RealGetWindowClass(hwnd, buf, sizeof(buf)/sizeof(wchar_t)) || buf[0] != L'#') + return TRUE; + if (!GetWindowTextW(hwnd, buf, sizeof(buf)/sizeof(wchar_t)) || wcscmp(buf, context->title.data())) + return TRUE; + context->hwnd = hwnd; + return FALSE; +} + +static inline HWND findDialogWindow(const QString &title) +{ + FindDialogContext context(title); + EnumWindows(findDialogEnumWindowsProc, reinterpret_cast(&context)); + return context.hwnd; +} +#endif // !Q_OS_WINCE + +template +void QWindowsDialogHelperBase::hide() +{ + if (m_nativeDialog) + m_nativeDialog->close(); + m_ownerWindow = 0; +} + +template +void QWindowsDialogHelperBase::exec() +{ + qCDebug(lcQpaDialogs) << __FUNCTION__; + stopTimer(); + if (QWindowsNativeDialogBase *nd = nativeDialog()) { + nd->exec(m_ownerWindow); + m_nativeDialog.clear(); + } +} + +/*! + \class QWindowsFileDialogSharedData + \brief Explicitly shared file dialog parameters that are not in QFileDialogOptions. + + Contain Parameters that need to be cached while the native dialog does not + exist yet. In addition, the data are updated by the change notifications of the + IFileDialogEvent, as querying them after the dialog has closed + does not reliably work. Provides thread-safe setters (for the non-modal case). + + \internal + \ingroup qt-lighthouse-win + \sa QFileDialogOptions +*/ + +class QWindowsFileDialogSharedData +{ +public: + QWindowsFileDialogSharedData() : m_data(new Data) {} + void fromOptions(const QSharedPointer &o); + + QUrl directory() const; + void setDirectory(const QUrl &); + QString selectedNameFilter() const; + void setSelectedNameFilter(const QString &); + QList selectedFiles() const; + void setSelectedFiles(const QList &); + QString selectedFile() const; + void setSelectedRemoteContent(const QByteArray &); + QByteArray selectedRemoteContent() const; + +private: + class Data : public QSharedData { + public: + QUrl directory; + QString selectedNameFilter; + QList selectedFiles; + QByteArray selectedRemoteContent; + QMutex mutex; + }; + QExplicitlySharedDataPointer m_data; +}; + +inline QUrl QWindowsFileDialogSharedData::directory() const +{ + m_data->mutex.lock(); + const QUrl result = m_data->directory; + m_data->mutex.unlock(); + return result; +} + +inline void QWindowsFileDialogSharedData::setDirectory(const QUrl &d) +{ + QMutexLocker (&m_data->mutex); + m_data->directory = d; +} + +inline QString QWindowsFileDialogSharedData::selectedNameFilter() const +{ + m_data->mutex.lock(); + const QString result = m_data->selectedNameFilter; + m_data->mutex.unlock(); + return result; +} + +inline void QWindowsFileDialogSharedData::setSelectedNameFilter(const QString &f) +{ + QMutexLocker (&m_data->mutex); + m_data->selectedNameFilter = f; +} + +inline QList QWindowsFileDialogSharedData::selectedFiles() const +{ + m_data->mutex.lock(); + const QList result = m_data->selectedFiles; + m_data->mutex.unlock(); + return result; +} + +inline QString QWindowsFileDialogSharedData::selectedFile() const +{ + const QList files = selectedFiles(); + return files.isEmpty() ? QString() : files.front().toLocalFile(); +} + +inline void QWindowsFileDialogSharedData::setSelectedFiles(const QList &urls) +{ + QMutexLocker (&m_data->mutex); + m_data->selectedFiles = urls; +} + +inline QByteArray QWindowsFileDialogSharedData::selectedRemoteContent() const +{ + m_data->mutex.lock(); + const QByteArray result = m_data->selectedRemoteContent; + m_data->mutex.unlock(); + return result; +} + +inline void QWindowsFileDialogSharedData::setSelectedRemoteContent(const QByteArray &c) +{ + QMutexLocker(&m_data->mutex); + m_data->selectedRemoteContent = c; +} + +inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer &o) +{ + QMutexLocker (&m_data->mutex); + m_data->directory = o->initialDirectory(); + m_data->selectedFiles = o->initiallySelectedFiles(); + m_data->selectedNameFilter = o->initiallySelectedNameFilter(); +} + +/*! + \class QWindowsNativeFileDialogEventHandler + \brief Listens to IFileDialog events and forwards them to QWindowsNativeFileDialogBase + + Events like 'folder change' that have an equivalent signal + in QFileDialog are forwarded. + + \sa QWindowsNativeFileDialogBase, QWindowsFileDialogHelper + \internal + \ingroup qt-lighthouse-win +*/ + +class QWindowsNativeFileDialogBase; + +class QWindowsNativeFileDialogEventHandler : public IFileDialogEvents +{ +public: + static IFileDialogEvents *create(QWindowsNativeFileDialogBase *nativeFileDialog); + + // IUnknown methods + IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) + { + if (riid != IID_IUnknown && riid != IID_IFileDialogEvents) { + *ppv = NULL; + return ResultFromScode(E_NOINTERFACE); + } + *ppv = this; + AddRef(); + return NOERROR; + } + + IFACEMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&m_ref); } + + IFACEMETHODIMP_(ULONG) Release() + { + const long ref = InterlockedDecrement(&m_ref); + if (!ref) + delete this; + return ref; + } + + // IFileDialogEvents methods + IFACEMETHODIMP OnFileOk(IFileDialog *); + IFACEMETHODIMP OnFolderChange(IFileDialog *) { return S_OK; } + IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *); + IFACEMETHODIMP OnHelp(IFileDialog *) { return S_OK; } + IFACEMETHODIMP OnSelectionChange(IFileDialog *); + IFACEMETHODIMP OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; } + IFACEMETHODIMP OnTypeChange(IFileDialog *); + IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; } + + QWindowsNativeFileDialogEventHandler(QWindowsNativeFileDialogBase *nativeFileDialog) : + m_ref(1), m_nativeFileDialog(nativeFileDialog) {} + virtual ~QWindowsNativeFileDialogEventHandler() {} + +private: + long m_ref; + QWindowsNativeFileDialogBase *m_nativeFileDialog; +}; + +IFileDialogEvents *QWindowsNativeFileDialogEventHandler::create(QWindowsNativeFileDialogBase *nativeFileDialog) +{ + IFileDialogEvents *result; + QWindowsNativeFileDialogEventHandler *eventHandler = new QWindowsNativeFileDialogEventHandler(nativeFileDialog); + if (FAILED(eventHandler->QueryInterface(IID_IFileDialogEvents, reinterpret_cast(&result)))) { + qErrnoWarning("Unable to obtain IFileDialogEvents"); + return 0; + } + eventHandler->Release(); + return result; +} + +/*! + \class QWindowsNativeFileDialogBase + \brief Windows native file dialog wrapper around IFileOpenDialog, IFileSaveDialog. + + Provides convenience methods. + Note that only IFileOpenDialog has multi-file functionality. + + \sa QWindowsNativeFileDialogEventHandler, QWindowsFileDialogHelper + \internal + \ingroup qt-lighthouse-win +*/ + +class QWindowsNativeFileDialogBase : public QWindowsNativeDialogBase +{ + Q_OBJECT + Q_PROPERTY(bool hideFiltersDetails READ hideFiltersDetails WRITE setHideFiltersDetails) +public: + ~QWindowsNativeFileDialogBase(); + + inline static QWindowsNativeFileDialogBase *create(QFileDialogOptions::AcceptMode am, const QWindowsFileDialogSharedData &data); + + virtual void setWindowTitle(const QString &title); + inline void setMode(QFileDialogOptions::FileMode mode, QFileDialogOptions::AcceptMode acceptMode, QFileDialogOptions::FileDialogOptions options); + inline void setDirectory(const QString &directory); + inline void updateDirectory() { setDirectory(m_data.directory().toLocalFile()); } + inline QString directory() const; + virtual void doExec(HWND owner = 0); + virtual void setNameFilters(const QStringList &f); + inline void selectNameFilter(const QString &filter); + inline void updateSelectedNameFilter() { selectNameFilter(m_data.selectedNameFilter()); } + inline QString selectedNameFilter() const; + void selectFile(const QString &fileName) const; + bool hideFiltersDetails() const { return m_hideFiltersDetails; } + void setHideFiltersDetails(bool h) { m_hideFiltersDetails = h; } + void setDefaultSuffix(const QString &s); + inline bool hasDefaultSuffix() const { return m_hasDefaultSuffix; } + inline void setLabelText(QFileDialogOptions::DialogLabel l, const QString &text); + + // Return the selected files for tracking in OnSelectionChanged(). + virtual QList selectedFiles() const = 0; + // Return the result for tracking in OnFileOk(). Differs from selection for + // example by appended default suffixes, etc. + virtual QList dialogResult() const = 0; + virtual QByteArray dialogRemoteContent() const { return QByteArray(); } + + inline void onFolderChange(IShellItem *); + inline void onSelectionChange(); + inline void onTypeChange(); + inline bool onFileOk(); + +signals: + void directoryEntered(const QUrl &directory); + void currentChanged(const QUrl &file); + void filterSelected(const QString & filter); + +public slots: + virtual void close(); + +protected: + explicit QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data); + bool init(const CLSID &clsId, const IID &iid); + void setDefaultSuffixSys(const QString &s); + inline IFileDialog * fileDialog() const { return m_fileDialog; } + static QString itemPath(IShellItem *item); + static QList libraryItemFolders(IShellItem *item); + static QString libraryItemDefaultSaveFolder(IShellItem *item); + static int itemPaths(IShellItemArray *items, QList *fileResult = 0); + static IShellItem *shellItem(const QString &path); + + const QWindowsFileDialogSharedData &data() const { return m_data; } + QWindowsFileDialogSharedData &data() { return m_data; } + +private: + IFileDialog *m_fileDialog; + IFileDialogEvents *m_dialogEvents; + DWORD m_cookie; + QStringList m_nameFilters; + bool m_hideFiltersDetails; + bool m_hasDefaultSuffix; + QWindowsFileDialogSharedData m_data; + QString m_title; +}; + +QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data) : + m_fileDialog(0), m_dialogEvents(0), m_cookie(0), m_hideFiltersDetails(false), + m_hasDefaultSuffix(false), m_data(data) +{ +} + +QWindowsNativeFileDialogBase::~QWindowsNativeFileDialogBase() +{ + if (m_dialogEvents && m_fileDialog) + m_fileDialog->Unadvise(m_cookie); + if (m_dialogEvents) + m_dialogEvents->Release(); + if (m_fileDialog) + m_fileDialog->Release(); +} + +bool QWindowsNativeFileDialogBase::init(const CLSID &clsId, const IID &iid) +{ + HRESULT hr = CoCreateInstance(clsId, NULL, CLSCTX_INPROC_SERVER, + iid, reinterpret_cast(&m_fileDialog)); + if (FAILED(hr)) { + qErrnoWarning("CoCreateInstance failed"); + return false; + } + m_dialogEvents = QWindowsNativeFileDialogEventHandler::create(this); + if (!m_dialogEvents) + return false; + // Register event handler + hr = m_fileDialog->Advise(m_dialogEvents, &m_cookie); + if (FAILED(hr)) { + qErrnoWarning("IFileDialog::Advise failed"); + return false; + } + qCDebug(lcQpaDialogs) << __FUNCTION__ << m_fileDialog << m_dialogEvents << m_cookie; + + return true; +} + +void QWindowsNativeFileDialogBase::setWindowTitle(const QString &title) +{ + m_title = title; + m_fileDialog->SetTitle(reinterpret_cast(title.utf16())); +} + +IShellItem *QWindowsNativeFileDialogBase::shellItem(const QString &path) +{ +#ifndef Q_OS_WINCE + if (QWindowsContext::shell32dll.sHCreateItemFromParsingName) { + IShellItem *result = 0; + const QString native = QDir::toNativeSeparators(path); + const HRESULT hr = + QWindowsContext::shell32dll.sHCreateItemFromParsingName(reinterpret_cast(native.utf16()), + NULL, IID_IShellItem, + reinterpret_cast(&result)); + if (SUCCEEDED(hr)) + return result; + } +#endif + qErrnoWarning("%s: SHCreateItemFromParsingName(%s)) failed", __FUNCTION__, qPrintable(path)); + return 0; +} + +void QWindowsNativeFileDialogBase::setDirectory(const QString &directory) +{ + if (!directory.isEmpty()) { + if (IShellItem *psi = QWindowsNativeFileDialogBase::shellItem(directory)) { + m_fileDialog->SetFolder(psi); + psi->Release(); + } + } +} + +QString QWindowsNativeFileDialogBase::directory() const +{ +#ifndef Q_OS_WINCE + IShellItem *item = 0; + if (m_fileDialog && SUCCEEDED(m_fileDialog->GetFolder(&item)) && item) + return QWindowsNativeFileDialogBase::itemPath(item); +#endif + return QString(); +} + +void QWindowsNativeFileDialogBase::doExec(HWND owner) +{ + qCDebug(lcQpaDialogs) << '>' << __FUNCTION__; + // Show() blocks until the user closes the dialog, the dialog window + // gets a WM_CLOSE or the parent window is destroyed. + const HRESULT hr = m_fileDialog->Show(owner); + QWindowsDialogs::eatMouseMove(); + qCDebug(lcQpaDialogs) << '<' << __FUNCTION__ << " returns " << hex << hr; + if (hr == S_OK) { + emit accepted(); + } else { + emit rejected(); + } +} + +void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode, + QFileDialogOptions::AcceptMode acceptMode, + QFileDialogOptions::FileDialogOptions options) +{ + DWORD flags = FOS_PATHMUSTEXIST | FOS_FORCESHOWHIDDEN; + if (options & QFileDialogOptions::DontResolveSymlinks) + flags |= FOS_NODEREFERENCELINKS; + switch (mode) { + case QFileDialogOptions::AnyFile: + if (acceptMode == QFileDialogOptions::AcceptSave) + flags |= FOS_NOREADONLYRETURN; + if (!(options & QFileDialogOptions::DontConfirmOverwrite)) + flags |= FOS_OVERWRITEPROMPT; + break; + case QFileDialogOptions::ExistingFile: + flags |= FOS_FILEMUSTEXIST; + break; + case QFileDialogOptions::Directory: + case QFileDialogOptions::DirectoryOnly: + flags |= FOS_PICKFOLDERS | FOS_FILEMUSTEXIST; + break; + case QFileDialogOptions::ExistingFiles: + flags |= FOS_FILEMUSTEXIST | FOS_ALLOWMULTISELECT; + break; + } + qCDebug(lcQpaDialogs) << __FUNCTION__ << "mode=" << mode + << "acceptMode=" << acceptMode << "options=" << options + << "results in" << showbase << hex << flags; + + if (FAILED(m_fileDialog->SetOptions(flags))) + qErrnoWarning("%s: SetOptions() failed", __FUNCTION__); +} + +#if !defined(Q_OS_WINCE) && defined(__IShellLibrary_INTERFACE_DEFINED__) // Windows SDK 7 + +// Helper for "Libraries": collections of folders appearing from Windows 7 +// on, visible in the file dialogs. + +// Load a library from a IShellItem (sanitized copy of the inline function +// SHLoadLibraryFromItem from ShObjIdl.h, which does not exist for MinGW). +static IShellLibrary *sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode) +{ + // ID symbols present from Windows 7 on: + static const CLSID classId_ShellLibrary = {0xd9b3211d, 0xe57f, 0x4426, {0xaa, 0xef, 0x30, 0xa8, 0x6, 0xad, 0xd3, 0x97}}; + static const IID iId_IShellLibrary = {0x11a66efa, 0x382e, 0x451a, {0x92, 0x34, 0x1e, 0xe, 0x12, 0xef, 0x30, 0x85}}; + + IShellLibrary *helper = 0; + IShellLibrary *result = 0; + if (SUCCEEDED(CoCreateInstance(classId_ShellLibrary, NULL, CLSCTX_INPROC_SERVER, iId_IShellLibrary, reinterpret_cast(&helper)))) + if (SUCCEEDED(helper->LoadLibraryFromItem(libraryItem, mode))) + helper->QueryInterface(iId_IShellLibrary, reinterpret_cast(&result)); + if (helper) + helper->Release(); + return result; +} + +// Return all folders of a library-type item. +QList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *item) +{ + QList result; + if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) { + IShellItemArray *itemArray = 0; + if (SUCCEEDED(library->GetFolders(LFF_FORCEFILESYSTEM, IID_IShellItemArray, reinterpret_cast(&itemArray)))) { + QWindowsNativeFileDialogBase::itemPaths(itemArray, &result); + itemArray->Release(); + } + library->Release(); + } + return result; +} + +// Return default save folders of a library-type item. +QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *item) +{ + QString result; + if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) { + IShellItem *item = 0; + if (SUCCEEDED(library->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem, reinterpret_cast(&item)))) { + result = QWindowsNativeFileDialogBase::itemPath(item); + item->Release(); + } + library->Release(); + } + return result; +} + +#else // !Q_OS_WINCE && __IShellLibrary_INTERFACE_DEFINED__ + +QList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *) +{ + return QList(); +} + +QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *) +{ + return QString(); +} + +#endif // Q_OS_WINCE || !__IShellLibrary_INTERFACE_DEFINED__ + +QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item) +{ + SFGAOF attributes = 0; + // Check whether it has a file system representation? + if (FAILED(item->GetAttributes(SFGAO_FILESYSTEM, &attributes))) + return QString(); + if (attributes & SFGAO_FILESYSTEM) { + LPWSTR name = 0; + QString result; + if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) { + result = QDir::cleanPath(QString::fromWCharArray(name)); + CoTaskMemFree(name); + } + return result; + } + // Check for a "Library" item + if ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) && QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) + return QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(item); + return QString(); +} + +int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items, + QList *result /* = 0 */) +{ + DWORD itemCount = 0; + if (result) + result->clear(); + if (FAILED(items->GetCount(&itemCount))) + return 0; + if (result && itemCount) { + result->reserve(itemCount); + for (DWORD i = 0; i < itemCount; ++i) { + IShellItem *item = 0; + if (SUCCEEDED(items->GetItemAt(i, &item))) + result->push_back(QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item))); + } + } + return itemCount; +} + +// Split a list of name filters into description and actual filters +struct FilterSpec +{ + QString description; + QString filter; +}; + +static QList filterSpecs(const QStringList &filters, + bool hideFilterDetails, + int *totalStringLength) +{ + QList result; + result.reserve(filters.size()); + *totalStringLength = 0; + + const QRegExp filterSeparatorRE(QStringLiteral("[;\\s]+")); + const QString separator = QStringLiteral(";"); + Q_ASSERT(filterSeparatorRE.isValid()); + // Split filter specification as 'Texts (*.txt[;] *.doc)', '*.txt[;] *.doc' + // into description and filters specification as '*.txt;*.doc' + foreach (const QString &filterString, filters) { + const int openingParenPos = filterString.lastIndexOf(QLatin1Char('(')); + const int closingParenPos = openingParenPos != -1 ? + filterString.indexOf(QLatin1Char(')'), openingParenPos + 1) : -1; + FilterSpec filterSpec; + filterSpec.filter = closingParenPos == -1 ? + filterString : + filterString.mid(openingParenPos + 1, closingParenPos - openingParenPos - 1).trimmed(); + if (filterSpec.filter.isEmpty()) + filterSpec.filter += QLatin1Char('*'); + filterSpec.filter.replace(filterSeparatorRE, separator); + filterSpec.description = filterString; + if (hideFilterDetails && openingParenPos != -1) { // Do not show pattern in description + filterSpec.description.truncate(openingParenPos); + while (filterSpec.description.endsWith(QLatin1Char(' '))) + filterSpec.description.truncate(filterSpec.description.size() - 1); + } + *totalStringLength += filterSpec.filter.size() + filterSpec.description.size(); + result.push_back(filterSpec); + } + return result; +} + +void QWindowsNativeFileDialogBase::setNameFilters(const QStringList &filters) +{ + /* Populates an array of COMDLG_FILTERSPEC from list of filters, + * store the strings in a flat, contiguous buffer. */ + m_nameFilters = filters; + int totalStringLength = 0; + const QList specs = filterSpecs(filters, m_hideFiltersDetails, &totalStringLength); + const int size = specs.size(); + + QScopedArrayPointer buffer(new WCHAR[totalStringLength + 2 * size]); + QScopedArrayPointer comFilterSpec(new COMDLG_FILTERSPEC[size]); + + const QString matchesAll = QStringLiteral(" (*)"); + WCHAR *ptr = buffer.data(); + // Split filter specification as 'Texts (*.txt[;] *.doc)' + // into description and filters specification as '*.txt;*.doc' + + for (int i = 0; i < size; ++i) { + // Display glitch (CLSID only): 'All files (*)' shows up as 'All files (*) (*)' + QString description = specs[i].description; + if (!m_hideFiltersDetails && description.endsWith(matchesAll)) + description.truncate(description.size() - matchesAll.size()); + // Add to buffer. + comFilterSpec[i].pszName = ptr; + ptr += description.toWCharArray(ptr); + *ptr++ = 0; + comFilterSpec[i].pszSpec = ptr; + ptr += specs[i].filter.toWCharArray(ptr); + *ptr++ = 0; + } + + m_fileDialog->SetFileTypes(size, comFilterSpec.data()); +} + +void QWindowsNativeFileDialogBase::setDefaultSuffix(const QString &s) +{ + setDefaultSuffixSys(s); + m_hasDefaultSuffix = !s.isEmpty(); +} + +void QWindowsNativeFileDialogBase::setDefaultSuffixSys(const QString &s) +{ + // If this parameter is non-empty, it will be appended by the dialog for the 'Any files' + // filter ('*'). If this parameter is non-empty and the current filter has a suffix, + // the dialog will append the filter's suffix. + wchar_t *wSuffix = const_cast(reinterpret_cast(s.utf16())); + m_fileDialog->SetDefaultExtension(wSuffix); +} + +void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel l, const QString &text) +{ + wchar_t *wText = const_cast(reinterpret_cast(text.utf16())); + switch (l) { + break; + case QFileDialogOptions::FileName: + m_fileDialog->SetFileNameLabel(wText); + break; + case QFileDialogOptions::Accept: + m_fileDialog->SetOkButtonLabel(wText); + break; + case QFileDialogOptions::LookIn: + case QFileDialogOptions::Reject: + case QFileDialogOptions::FileType: + case QFileDialogOptions::DialogLabelCount: + break; + } +} + +void QWindowsNativeFileDialogBase::selectFile(const QString &fileName) const +{ + QString file = QDir::toNativeSeparators(fileName); + int lastBackSlash = file.lastIndexOf(QChar::fromLatin1('\\')); + if (lastBackSlash >= 0) { + file = file.mid(lastBackSlash + 1); + } + m_fileDialog->SetFileName((wchar_t*)file.utf16()); +} + +// Return the index of the selected filter, accounting for QFileDialog +// sometimes stripping the filter specification depending on the +// hideFilterDetails setting. +static int indexOfNameFilter(const QStringList &filters, const QString &needle) +{ + const int index = filters.indexOf(needle); + if (index >= 0) + return index; + for (int i = 0; i < filters.size(); ++i) + if (filters.at(i).startsWith(needle)) + return i; + return -1; +} + +void QWindowsNativeFileDialogBase::selectNameFilter(const QString &filter) +{ + if (filter.isEmpty()) + return; + const int index = indexOfNameFilter(m_nameFilters, filter); + if (index < 0) { + qWarning("%s: Invalid parameter '%s' not found in '%s'.", + __FUNCTION__, qPrintable(filter), + qPrintable(m_nameFilters.join(QStringLiteral(", ")))); + return; + } + m_fileDialog->SetFileTypeIndex(index + 1); // one-based. +} + +QString QWindowsNativeFileDialogBase::selectedNameFilter() const +{ + UINT uIndex = 0; + if (SUCCEEDED(m_fileDialog->GetFileTypeIndex(&uIndex))) { + const int index = uIndex - 1; // one-based + if (index < m_nameFilters.size()) + return m_nameFilters.at(index); + } + return QString(); +} + +void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item) +{ + if (item) { + const QUrl directory = QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item)); + m_data.setDirectory(directory); + emit directoryEntered(directory); + } +} + +void QWindowsNativeFileDialogBase::onSelectionChange() +{ + const QList current = selectedFiles(); + m_data.setSelectedFiles(current); + if (current.size() == 1) + emit currentChanged(current.front()); +} + +void QWindowsNativeFileDialogBase::onTypeChange() +{ + const QString filter = selectedNameFilter(); + m_data.setSelectedNameFilter(filter); + emit filterSelected(filter); +} + +bool QWindowsNativeFileDialogBase::onFileOk() +{ + // Store selected files as GetResults() returns invalid data after the dialog closes. + m_data.setSelectedFiles(dialogResult()); + m_data.setSelectedRemoteContent(dialogRemoteContent()); + return true; +} + +void QWindowsNativeFileDialogBase::close() +{ + m_fileDialog->Close(S_OK); +#ifndef Q_OS_WINCE + // IFileDialog::Close() does not work unless invoked from a callback. + // Try to find the window and send it a WM_CLOSE in addition. + const HWND hwnd = findDialogWindow(m_title); + qCDebug(lcQpaDialogs) << __FUNCTION__ << "closing" << hwnd; + if (hwnd && IsWindowVisible(hwnd)) + PostMessageW(hwnd, WM_CLOSE, 0, 0); +#endif // !Q_OS_WINCE +} + +HRESULT QWindowsNativeFileDialogEventHandler::OnFolderChanging(IFileDialog *, IShellItem *item) +{ + m_nativeFileDialog->onFolderChange(item); + return S_OK; +} + +HRESULT QWindowsNativeFileDialogEventHandler::OnSelectionChange(IFileDialog *) +{ + m_nativeFileDialog->onSelectionChange(); + return S_OK; +} + +HRESULT QWindowsNativeFileDialogEventHandler::OnTypeChange(IFileDialog *) +{ + m_nativeFileDialog->onTypeChange(); + return S_OK; +} + +HRESULT QWindowsNativeFileDialogEventHandler::OnFileOk(IFileDialog *) +{ + return m_nativeFileDialog->onFileOk() ? S_OK : S_FALSE; +} + +/*! + \class QWindowsNativeSaveFileDialog + \brief Windows native file save dialog wrapper around IFileSaveDialog. + + Implements single-selection methods. + + \internal + \ingroup qt-lighthouse-win +*/ + +class QWindowsNativeSaveFileDialog : public QWindowsNativeFileDialogBase +{ + Q_OBJECT +public: + explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) + : QWindowsNativeFileDialogBase(data) {} + virtual void setNameFilters(const QStringList &f); + virtual QList selectedFiles() const; + virtual QList dialogResult() const; +}; + +// Return the first suffix from the name filter "Foo files (*.foo;*.bar)" -> "foo". +static inline QString suffixFromFilter(const QString &filter) +{ + int suffixPos = filter.indexOf(QLatin1String("(*.")); + if (suffixPos < 0) + return QString(); + suffixPos += 3; + int endPos = filter.indexOf(QLatin1Char(' '), suffixPos + 1); + if (endPos < 0) + endPos = filter.indexOf(QLatin1Char(';'), suffixPos + 1); + if (endPos < 0) + endPos = filter.indexOf(QLatin1Char(')'), suffixPos + 1); + return endPos >= 0 ? filter.mid(suffixPos, endPos - suffixPos) : QString(); +} + +void QWindowsNativeSaveFileDialog::setNameFilters(const QStringList &f) +{ + QWindowsNativeFileDialogBase::setNameFilters(f); + // QTBUG-31381, QTBUG-30748: IFileDialog will update the suffix of the selected name + // filter only if a default suffix is set (see docs). Set the first available + // suffix unless we have a defaultSuffix. + if (!hasDefaultSuffix()) { + foreach (const QString &filter, f) { + const QString suffix = suffixFromFilter(filter); + if (!suffix.isEmpty()) { + setDefaultSuffixSys(suffix); + break; + } + } + } // m_hasDefaultSuffix +} + +QList QWindowsNativeSaveFileDialog::dialogResult() const +{ + QList result; + IShellItem *item = 0; + if (SUCCEEDED(fileDialog()->GetResult(&item)) && item) + result.push_back(QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item))); + return result; +} + +QList QWindowsNativeSaveFileDialog::selectedFiles() const +{ + QList result; + IShellItem *item = 0; + const HRESULT hr = fileDialog()->GetCurrentSelection(&item); + if (SUCCEEDED(hr) && item) + result.push_back(QUrl::fromLocalFile(QWindowsNativeSaveFileDialog::itemPath(item))); + return result; +} + +/*! + \class QWindowsNativeOpenFileDialog + \brief Windows native file save dialog wrapper around IFileOpenDialog. + + Implements multi-selection methods. + + \internal + \ingroup qt-lighthouse-win +*/ + +class QWindowsNativeOpenFileDialog : public QWindowsNativeFileDialogBase +{ +public: + explicit QWindowsNativeOpenFileDialog(const QWindowsFileDialogSharedData &data) : + QWindowsNativeFileDialogBase(data) {} + virtual QList selectedFiles() const; + virtual QList dialogResult() const; + virtual QByteArray dialogRemoteContent() const; + +private: + inline IFileOpenDialog *openFileDialog() const + { return static_cast(fileDialog()); } +}; + +QList QWindowsNativeOpenFileDialog::dialogResult() const +{ + QList result; + IShellItemArray *items = 0; + if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) + QWindowsNativeFileDialogBase::itemPaths(items, &result); + return result; +} + +QByteArray QWindowsNativeOpenFileDialog::dialogRemoteContent() const { + QByteArray result; + IShellItemArray *items = 0; + if (FAILED(openFileDialog()->GetResults(&items)) || !items) + return result; + DWORD itemCount = 0; + if (FAILED(items->GetCount(&itemCount)) || !itemCount) + return result; + for (DWORD i = 0; i < itemCount; ++i) { + IShellItem *item = 0; + if (SUCCEEDED(items->GetItemAt(i, &item))) { + SFGAOF attributes = 0; + // Check whether it has a file system representation? + if (FAILED(item->GetAttributes(SFGAO_FILESYSTEM, &attributes)) || (attributes & SFGAO_FILESYSTEM)) { + LPWSTR name = 0; + if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) { + CoTaskMemFree(name); + continue; + } + } + if (FAILED(item->GetAttributes(SFGAO_STREAM, &attributes)) || !(attributes & SFGAO_STREAM)) + continue; + + IBindCtx *bind = 0; + if (FAILED(CreateBindCtx(0, &bind))) + continue; + + IStream *stream = 0; + if (FAILED(item->BindToHandler(bind, BHID_Stream, IID_IStream, reinterpret_cast(&stream)))) + continue; + + STATSTG stat = { 0 }; + if (FAILED(stream->Stat(&stat, STATFLAG_NONAME)) || !stat.cbSize.QuadPart) + continue; + + quint64 fullSize = stat.cbSize.QuadPart; + result.resize(fullSize); + ULONG read = 0; + HRESULT r = stream->Read(result.data(), fullSize, &read); + if (r == S_FALSE || r == S_OK) + return result; + + result.clear(); + } + } + return result; +} + +QList QWindowsNativeOpenFileDialog::selectedFiles() const +{ + QList result; + IShellItemArray *items = 0; + const HRESULT hr = openFileDialog()->GetSelectedItems(&items); + if (SUCCEEDED(hr) && items) + QWindowsNativeFileDialogBase::itemPaths(items, &result); + return result; +} + +/*! + \brief Factory method for QWindowsNativeFileDialogBase returning + QWindowsNativeOpenFileDialog or QWindowsNativeSaveFileDialog depending on + QFileDialog::AcceptMode. +*/ + +QWindowsNativeFileDialogBase *QWindowsNativeFileDialogBase::create(QFileDialogOptions::AcceptMode am, + const QWindowsFileDialogSharedData &data) +{ + QWindowsNativeFileDialogBase *result = 0; + if (am == QFileDialogOptions::AcceptOpen) { + result = new QWindowsNativeOpenFileDialog(data); + if (!result->init(CLSID_FileOpenDialog, IID_IFileOpenDialog)) { + delete result; + return 0; + } + } else { + result = new QWindowsNativeSaveFileDialog(data); + if (!result->init(CLSID_FileSaveDialog, IID_IFileSaveDialog)) { + delete result; + return 0; + } + } + return result; +} + +static inline bool isQQuickWindow(const QWindow *w = 0) +{ + return w && w->inherits("QQuickWindow"); +} + +/*! + \class QWindowsFileDialogHelper + \brief Helper for native Windows file dialogs + + For Qt 4 compatibility, do not create native non-modal dialogs on widgets, + but only on QQuickWindows, which do not have a fallback. + + \internal + \ingroup qt-lighthouse-win +*/ + +class QWindowsFileDialogHelper : public QWindowsDialogHelperBase +{ +public: + QWindowsFileDialogHelper() {} + virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return false; } + virtual bool defaultNameFilterDisables() const + { return false; } + virtual void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + virtual QUrl directory() const Q_DECL_OVERRIDE; + virtual void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; + virtual QList selectedFiles() const Q_DECL_OVERRIDE; + virtual QByteArray selectedRemoteContent() const Q_DECL_OVERRIDE; + virtual void setFilter() Q_DECL_OVERRIDE; + virtual void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE; + virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; + +private: + virtual QWindowsNativeDialogBase *createNativeDialog(); + inline QWindowsNativeFileDialogBase *nativeFileDialog() const + { return static_cast(nativeDialog()); } + + // Cache for the case no native dialog is created. + QWindowsFileDialogSharedData m_data; +}; + +QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() +{ + QWindowsNativeFileDialogBase *result = QWindowsNativeFileDialogBase::create(options()->acceptMode(), m_data); + if (!result) + return 0; + QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept())); + QObject::connect(result, SIGNAL(rejected()), this, SIGNAL(reject())); + QObject::connect(result, SIGNAL(directoryEntered(QUrl)), + this, SIGNAL(directoryEntered(QUrl))); + QObject::connect(result, SIGNAL(currentChanged(QUrl)), + this, SIGNAL(currentChanged(QUrl))); + QObject::connect(result, SIGNAL(filterSelected(QString)), + this, SIGNAL(filterSelected(QString))); + + // Apply settings. + const QSharedPointer &opts = options(); + m_data.fromOptions(opts); + const QFileDialogOptions::FileMode mode = opts->fileMode(); + result->setWindowTitle(opts->windowTitle()); + result->setMode(mode, opts->acceptMode(), opts->options()); + result->setHideFiltersDetails(opts->testOption(QFileDialogOptions::HideNameFilterDetails)); + const QStringList nameFilters = opts->nameFilters(); + if (!nameFilters.isEmpty()) + result->setNameFilters(nameFilters); + if (opts->isLabelExplicitlySet(QFileDialogOptions::FileName)) + result->setLabelText(QFileDialogOptions::FileName, opts->labelText(QFileDialogOptions::FileName)); + if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept)) + result->setLabelText(QFileDialogOptions::Accept, opts->labelText(QFileDialogOptions::Accept)); + result->updateDirectory(); + result->updateSelectedNameFilter(); + const QList initialSelection = opts->initiallySelectedFiles(); + if (initialSelection.size() > 0) { + const QUrl url = initialSelection.front(); + if (url.isLocalFile()) { + QFileInfo info(url.toLocalFile()); + if (!info.isDir()) + result->selectFile(info.fileName()); + } else { + result->selectFile(url.path()); // TODO url.fileName() once it exists + } + } + // No need to select initialNameFilter if mode is Dir + if (mode != QFileDialogOptions::Directory && mode != QFileDialogOptions::DirectoryOnly) { + const QString initialNameFilter = opts->initiallySelectedNameFilter(); + if (!initialNameFilter.isEmpty()) + result->selectNameFilter(initialNameFilter); + } + const QString defaultSuffix = opts->defaultSuffix(); + if (!defaultSuffix.isEmpty()) + result->setDefaultSuffix(defaultSuffix); + return result; +} + +void QWindowsFileDialogHelper::setDirectory(const QUrl &directory) +{ + qCDebug(lcQpaDialogs) << __FUNCTION__ << directory.toString(); + + m_data.setDirectory(directory); + if (hasNativeDialog()) + nativeFileDialog()->updateDirectory(); +} + +QUrl QWindowsFileDialogHelper::directory() const +{ + return m_data.directory(); +} + +void QWindowsFileDialogHelper::selectFile(const QUrl &fileName) +{ + qCDebug(lcQpaDialogs) << __FUNCTION__ << fileName.toString(); + + if (hasNativeDialog()) // Might be invoked from the QFileDialog constructor. + nativeFileDialog()->selectFile(fileName.toLocalFile()); // ## should use QUrl::fileName() once it exists +} + +QList QWindowsFileDialogHelper::selectedFiles() const +{ + return m_data.selectedFiles(); +} + +QByteArray QWindowsFileDialogHelper::selectedRemoteContent() const +{ + return m_data.selectedRemoteContent(); +} + +void QWindowsFileDialogHelper::setFilter() +{ + qCDebug(lcQpaDialogs) << __FUNCTION__; +} + +void QWindowsFileDialogHelper::selectNameFilter(const QString &filter) +{ + m_data.setSelectedNameFilter(filter); + if (hasNativeDialog()) + nativeFileDialog()->updateSelectedNameFilter(); +} + +QString QWindowsFileDialogHelper::selectedNameFilter() const +{ + return m_data.selectedNameFilter(); +} + +#ifndef Q_OS_WINCE + +/*! + \class QWindowsXpNativeFileDialog + \brief Native Windows directory dialog for Windows XP using SHlib-functions. + + Uses the synchronous GetOpenFileNameW(), GetSaveFileNameW() from ComDlg32 + or SHBrowseForFolder() for directories. + + \internal + \sa QWindowsXpFileDialogHelper + + \ingroup qt-lighthouse-win +*/ + +class QWindowsXpNativeFileDialog : public QWindowsNativeDialogBase +{ + Q_OBJECT +public: + typedef QSharedPointer OptionsPtr; + + static QWindowsXpNativeFileDialog *create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data); + + virtual void setWindowTitle(const QString &t) { m_title = t; } + virtual void doExec(HWND owner = 0); + virtual QPlatformDialogHelper::DialogCode result() const { return m_result; } + + int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam); + +public slots: + virtual void close() {} + +private: + typedef BOOL (APIENTRY *PtrGetOpenFileNameW)(LPOPENFILENAMEW); + typedef BOOL (APIENTRY *PtrGetSaveFileNameW)(LPOPENFILENAMEW); + + explicit QWindowsXpNativeFileDialog(const OptionsPtr &options, const QWindowsFileDialogSharedData &data); + void populateOpenFileName(OPENFILENAME *ofn, HWND owner) const; + QList execExistingDir(HWND owner); + QList execFileNames(HWND owner, int *selectedFilterIndex) const; + + const OptionsPtr m_options; + QString m_title; + QPlatformDialogHelper::DialogCode m_result; + QWindowsFileDialogSharedData m_data; + + static PtrGetOpenFileNameW m_getOpenFileNameW; + static PtrGetSaveFileNameW m_getSaveFileNameW; +}; + +QWindowsXpNativeFileDialog::PtrGetOpenFileNameW QWindowsXpNativeFileDialog::m_getOpenFileNameW = 0; +QWindowsXpNativeFileDialog::PtrGetSaveFileNameW QWindowsXpNativeFileDialog::m_getSaveFileNameW = 0; + +QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data) +{ + // GetOpenFileNameW() GetSaveFileName() are resolved + // dynamically as not to create a dependency on Comdlg32, which + // is used on XP only. + if (!m_getOpenFileNameW) { + QSystemLibrary library(QStringLiteral("Comdlg32")); + m_getOpenFileNameW = (PtrGetOpenFileNameW)(library.resolve("GetOpenFileNameW")); + m_getSaveFileNameW = (PtrGetSaveFileNameW)(library.resolve("GetSaveFileNameW")); + } + if (m_getOpenFileNameW && m_getSaveFileNameW) + return new QWindowsXpNativeFileDialog(options, data); + return 0; +} + +QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options, + const QWindowsFileDialogSharedData &data) : + m_options(options), m_result(QPlatformDialogHelper::Rejected), m_data(data) +{ + setWindowTitle(m_options->windowTitle()); +} + +void QWindowsXpNativeFileDialog::doExec(HWND owner) +{ + int selectedFilterIndex = -1; + const QList selectedFiles = + m_options->fileMode() == QFileDialogOptions::DirectoryOnly ? + execExistingDir(owner) : execFileNames(owner, &selectedFilterIndex); + m_data.setSelectedFiles(selectedFiles); + QWindowsDialogs::eatMouseMove(); + if (selectedFiles.isEmpty()) { + m_result = QPlatformDialogHelper::Rejected; + emit rejected(); + } else { + const QStringList nameFilters = m_options->nameFilters(); + if (selectedFilterIndex >= 0 && selectedFilterIndex < nameFilters.size()) + m_data.setSelectedNameFilter(nameFilters.at(selectedFilterIndex)); + QUrl firstFile = selectedFiles.front(); + m_data.setDirectory(firstFile.adjusted(QUrl::RemoveFilename)); + m_result = QPlatformDialogHelper::Accepted; + emit accepted(); + } +} + +// Callback for QWindowsNativeXpFileDialog directory dialog. +// MFC Directory Dialog. Contrib: Steve Williams (minor parts from Scott Powers) + +static int QT_WIN_CALLBACK xpFileDialogGetExistingDirCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + QWindowsXpNativeFileDialog *dialog = reinterpret_cast(lpData); + return dialog->existingDirCallback(hwnd, uMsg, lParam); +} + +/* The correct declaration of the SHGetPathFromIDList symbol is + * being used in mingw-w64 as of r6215, which is a v3 snapshot. */ +#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) +typedef ITEMIDLIST *qt_LpItemIdList; +#else +typedef PIDLIST_ABSOLUTE qt_LpItemIdList; +#endif + +int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam) +{ + switch (uMsg) { + case BFFM_INITIALIZED: { + if (!m_title.isEmpty()) + SetWindowText(hwnd, (wchar_t *)m_title.utf16()); + const QString initialFile = QDir::toNativeSeparators(m_data.directory().toLocalFile()); + if (!initialFile.isEmpty()) + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initialFile.utf16())); + } + break; + case BFFM_SELCHANGED: { + wchar_t path[MAX_PATH]; + const bool ok = SHGetPathFromIDList(reinterpret_cast(lParam), path) + && path[0]; + SendMessage(hwnd, BFFM_ENABLEOK, ok ? 1 : 0, 1); + } + break; + } + return 0; +} + +QList QWindowsXpNativeFileDialog::execExistingDir(HWND owner) +{ + BROWSEINFO bi; + wchar_t initPath[MAX_PATH]; + initPath[0] = 0; + bi.hwndOwner = owner; + bi.pidlRoot = NULL; + bi.lpszTitle = 0; + bi.pszDisplayName = initPath; + bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE; + bi.lpfn = xpFileDialogGetExistingDirCallbackProc; + bi.lParam = LPARAM(this); + QList selectedFiles; + if (qt_LpItemIdList pItemIDList = SHBrowseForFolder(&bi)) { + wchar_t path[MAX_PATH]; + path[0] = 0; + if (SHGetPathFromIDList(pItemIDList, path) && path[0]) + selectedFiles.push_back(QUrl::fromLocalFile(QDir::cleanPath(QString::fromWCharArray(path)))); + IMalloc *pMalloc; + if (SHGetMalloc(&pMalloc) == NOERROR) { + pMalloc->Free(pItemIDList); + pMalloc->Release(); + } + } + return selectedFiles; +} + +// Open/Save files +void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND owner) const +{ + ZeroMemory(ofn, sizeof(OPENFILENAME)); + ofn->lStructSize = sizeof(OPENFILENAME); + ofn->hwndOwner = owner; + + // Create a buffer with the filter strings. + int totalStringLength = 0; + QList specs = + filterSpecs(m_options->nameFilters(), m_options->options() & QFileDialogOptions::HideNameFilterDetails, &totalStringLength); + const int size = specs.size(); + wchar_t *ptr = new wchar_t[totalStringLength + 2 * size + 1]; + ofn->lpstrFilter = ptr; + foreach (const FilterSpec &spec, specs) { + ptr += spec.description.toWCharArray(ptr); + *ptr++ = 0; + ptr += spec.filter.toWCharArray(ptr); + *ptr++ = 0; + } + *ptr = 0; + const int nameFilterIndex = indexOfNameFilter(m_options->nameFilters(), m_data.selectedNameFilter()); + if (nameFilterIndex >= 0) + ofn->nFilterIndex = nameFilterIndex + 1; // 1..n based. + // lpstrFile receives the initial selection and is the buffer + // for the target. If it contains any invalid character, the dialog + // will not show. + ofn->nMaxFile = 65535; + const QString initiallySelectedFile = + QDir::toNativeSeparators(m_data.selectedFile()).remove(QLatin1Char('<')). + remove(QLatin1Char('>')).remove(QLatin1Char('"')).remove(QLatin1Char('|')); + ofn->lpstrFile = qStringToWCharArray(initiallySelectedFile, ofn->nMaxFile); + ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_data.directory().toLocalFile())); + ofn->lpstrTitle = (wchar_t*)m_title.utf16(); + // Determine lpstrDefExt. Note that the current MSDN docs document this + // member wrong. It should rather be documented as "the default extension + // if no extension was given and if the current filter does not have an + // extension (e.g (*)). If the current filter has an extension, use + // the extension of the current filter". + if (m_options->acceptMode() == QFileDialogOptions::AcceptSave) { + QString defaultSuffix = m_options->defaultSuffix(); + if (defaultSuffix.startsWith(QLatin1Char('.'))) + defaultSuffix.remove(0, 1); + // QTBUG-33156, also create empty strings to trigger the appending mechanism. + ofn->lpstrDefExt = qStringToWCharArray(defaultSuffix); + } + // Flags. + ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_PATHMUSTEXIST); + if (m_options->fileMode() == QFileDialogOptions::ExistingFile + || m_options->fileMode() == QFileDialogOptions::ExistingFiles) + ofn->Flags |= (OFN_FILEMUSTEXIST); + if (m_options->fileMode() == QFileDialogOptions::ExistingFiles) + ofn->Flags |= (OFN_ALLOWMULTISELECT); + if (!(m_options->options() & QFileDialogOptions::DontConfirmOverwrite)) + ofn->Flags |= OFN_OVERWRITEPROMPT; +} + +QList QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedFilterIndex) const +{ + *selectedFilterIndex = -1; + OPENFILENAME ofn; + populateOpenFileName(&ofn, owner); + QList result; + const bool isSave = m_options->acceptMode() == QFileDialogOptions::AcceptSave; + if (isSave ? m_getSaveFileNameW(&ofn) : m_getOpenFileNameW(&ofn)) { + *selectedFilterIndex = ofn.nFilterIndex - 1; + const QString dir = QDir::cleanPath(QString::fromWCharArray(ofn.lpstrFile)); + result.push_back(QUrl::fromLocalFile(dir)); + // For multiselection, the first item is the path followed + // by "\0\0\0\0". + if (ofn.Flags & (OFN_ALLOWMULTISELECT)) { + wchar_t *ptr = ofn.lpstrFile + dir.size() + 1; + if (*ptr) { + result.pop_front(); + const QString path = dir + QLatin1Char('/'); + while (*ptr) { + const QString fileName = QString::fromWCharArray(ptr); + result.push_back(QUrl::fromLocalFile(path + fileName)); + ptr += fileName.size() + 1; + } // extract multiple files + } // has multiple files + } // multiple flag set + } + delete [] ofn.lpstrFile; + delete [] ofn.lpstrInitialDir; + delete [] ofn.lpstrFilter; + delete [] ofn.lpstrDefExt; + return result; +} + +/*! + \class QWindowsXpFileDialogHelper + \brief Dialog helper using QWindowsXpNativeFileDialog + + \sa QWindowsXpNativeFileDialog + \internal + \ingroup qt-lighthouse-win +*/ + +class QWindowsXpFileDialogHelper : public QWindowsDialogHelperBase +{ +public: + QWindowsXpFileDialogHelper() {} + virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return false; } + virtual bool defaultNameFilterDisables() const + { return true; } + virtual void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + virtual QUrl directory() const Q_DECL_OVERRIDE; + virtual void selectFile(const QUrl &url) Q_DECL_OVERRIDE; + virtual QList selectedFiles() const Q_DECL_OVERRIDE; + virtual QByteArray selectedRemoteContent() const Q_DECL_OVERRIDE; + virtual void setFilter() Q_DECL_OVERRIDE {} + virtual void selectNameFilter(const QString &) Q_DECL_OVERRIDE; + virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; + +private: + virtual QWindowsNativeDialogBase *createNativeDialog(); + inline QWindowsXpNativeFileDialog *nativeFileDialog() const + { return static_cast(nativeDialog()); } + + QWindowsFileDialogSharedData m_data; +}; + +QWindowsNativeDialogBase *QWindowsXpFileDialogHelper::createNativeDialog() +{ + m_data.fromOptions(options()); + if (QWindowsXpNativeFileDialog *result = QWindowsXpNativeFileDialog::create(options(), m_data)) { + QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept())); + QObject::connect(result, SIGNAL(rejected()), this, SIGNAL(reject())); + return result; + } + return 0; +} + +void QWindowsXpFileDialogHelper::setDirectory(const QUrl &directory) +{ + m_data.setDirectory(directory); // Dialog cannot be updated at run-time. +} + +QUrl QWindowsXpFileDialogHelper::directory() const +{ + return m_data.directory(); +} + +void QWindowsXpFileDialogHelper::selectFile(const QUrl &url) +{ + m_data.setSelectedFiles(QList() << url); // Dialog cannot be updated at run-time. +} + +QList QWindowsXpFileDialogHelper::selectedFiles() const +{ + return m_data.selectedFiles(); +} + +QByteArray QWindowsXpFileDialogHelper::selectedRemoteContent() const +{ + return m_data.selectedRemoteContent(); +} + +void QWindowsXpFileDialogHelper::selectNameFilter(const QString &f) +{ + m_data.setSelectedNameFilter(f); // Dialog cannot be updated at run-time. +} + +QString QWindowsXpFileDialogHelper::selectedNameFilter() const +{ + return m_data.selectedNameFilter(); +} + +#endif // Q_OS_WINCE + +/*! + \class QWindowsNativeColorDialog + \brief Native Windows color dialog. + + Wrapper around Comdlg32's ChooseColor() function. + Not currently in use as QColorDialog is equivalent. + + \sa QWindowsColorDialogHelper + \sa #define USE_NATIVE_COLOR_DIALOG + \internal + \ingroup qt-lighthouse-win +*/ + +typedef QSharedPointer SharedPointerColor; + +#ifdef USE_NATIVE_COLOR_DIALOG +class QWindowsNativeColorDialog : public QWindowsNativeDialogBase +{ + Q_OBJECT +public: + enum { CustomColorCount = 16 }; + + explicit QWindowsNativeColorDialog(const SharedPointerColor &color); + + virtual void setWindowTitle(const QString &) {} + virtual QPlatformDialogHelper::DialogCode result() const { return m_code; } + +public slots: + virtual void close() {} + +private: + virtual void doExec(HWND owner = 0); + + COLORREF m_customColors[CustomColorCount]; + QPlatformDialogHelper::DialogCode m_code; + SharedPointerColor m_color; +}; + +QWindowsNativeColorDialog::QWindowsNativeColorDialog(const SharedPointerColor &color) : + m_code(QPlatformDialogHelper::Rejected), m_color(color) +{ + std::fill(m_customColors, m_customColors + 16, COLORREF(0)); +} + +void QWindowsNativeColorDialog::doExec(HWND owner) +{ + typedef BOOL (WINAPI *ChooseColorWType)(LPCHOOSECOLORW); + + CHOOSECOLOR chooseColor; + ZeroMemory(&chooseColor, sizeof(chooseColor)); + chooseColor.lStructSize = sizeof(chooseColor); + chooseColor.hwndOwner = owner; + chooseColor.lpCustColors = m_customColors; + QRgb *qCustomColors = QColorDialogOptions::customColors(); + const int customColorCount = qMin(QColorDialogOptions::customColorCount(), + int(CustomColorCount)); + for (int c= 0; c < customColorCount; ++c) + m_customColors[c] = qColorToCOLORREF(QColor(qCustomColors[c])); + chooseColor.rgbResult = qColorToCOLORREF(*m_color); + chooseColor.Flags = CC_FULLOPEN | CC_RGBINIT; + static ChooseColorWType chooseColorW = 0; + if (!chooseColorW) { + QSystemLibrary library(QStringLiteral("Comdlg32")); + chooseColorW = (ChooseColorWType)library.resolve("ChooseColorW"); + } + if (chooseColorW) { + m_code = chooseColorW(&chooseColor) ? + QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected; + QWindowsDialogs::eatMouseMove(); + } else { + m_code = QPlatformDialogHelper::Rejected; + } + if (m_code == QPlatformDialogHelper::Accepted) { + *m_color = COLORREFToQColor(chooseColor.rgbResult); + for (int c= 0; c < customColorCount; ++c) + qCustomColors[c] = COLORREFToQColor(m_customColors[c]).rgb(); + emit accepted(); + } else { + emit rejected(); + } +} + +/*! + \class QWindowsColorDialogHelper + \brief Helper for native Windows color dialogs + + Not currently in use as QColorDialog is equivalent. + + \sa #define USE_NATIVE_COLOR_DIALOG + \sa QWindowsNativeColorDialog + \internal + \ingroup qt-lighthouse-win +*/ + +class QWindowsColorDialogHelper : public QWindowsDialogHelperBase +{ +public: + QWindowsColorDialogHelper() : m_currentColor(new QColor) {} + + virtual bool supportsNonModalDialog() + { return false; } + + virtual QColor currentColor() const { return *m_currentColor; } + virtual void setCurrentColor(const QColor &c) { *m_currentColor = c; } + +private: + inline QWindowsNativeColorDialog *nativeFileDialog() const + { return static_cast(nativeDialog()); } + virtual QWindowsNativeDialogBase *createNativeDialog(); + + SharedPointerColor m_currentColor; +}; + +QWindowsNativeDialogBase *QWindowsColorDialogHelper::createNativeDialog() +{ + QWindowsNativeColorDialog *nativeDialog = new QWindowsNativeColorDialog(m_currentColor); + nativeDialog->setWindowTitle(options()->windowTitle()); + connect(nativeDialog, SIGNAL(accepted()), this, SIGNAL(accept())); + connect(nativeDialog, SIGNAL(rejected()), this, SIGNAL(reject())); + return nativeDialog; +} +#endif // USE_NATIVE_COLOR_DIALOG + +namespace QWindowsDialogs { + +// QWindowsDialogHelperBase creation functions +bool useHelper(QPlatformTheme::DialogType type) +{ + if (QWindowsIntegration::instance()->options() & QWindowsIntegration::NoNativeDialogs) + return false; + switch (type) { + case QPlatformTheme::FileDialog: + return QSysInfo::windowsVersion() >= QSysInfo::WV_XP; + case QPlatformTheme::ColorDialog: +#ifdef USE_NATIVE_COLOR_DIALOG + return true; +#else + break; +#endif + case QPlatformTheme::FontDialog: + case QPlatformTheme::MessageDialog: + break; + default: + break; + } + return false; +} + +QPlatformDialogHelper *createHelper(QPlatformTheme::DialogType type) +{ + if (QWindowsIntegration::instance()->options() & QWindowsIntegration::NoNativeDialogs) + return 0; + switch (type) { + case QPlatformTheme::FileDialog: +#ifndef Q_OS_WINCE // Note: "Windows XP Professional x64 Edition has version number WV_5_2 (WV_2003). + if (QWindowsIntegration::instance()->options() & QWindowsIntegration::XpNativeDialogs + || QSysInfo::windowsVersion() <= QSysInfo::WV_2003) { + return new QWindowsXpFileDialogHelper(); + } + if (QSysInfo::windowsVersion() > QSysInfo::WV_2003) + return new QWindowsFileDialogHelper(); +#else + return new QWindowsFileDialogHelper(); +#endif // Q_OS_WINCE + case QPlatformTheme::ColorDialog: +#ifdef USE_NATIVE_COLOR_DIALOG + return new QWindowsColorDialogHelper(); +#else + break; +#endif + case QPlatformTheme::FontDialog: + case QPlatformTheme::MessageDialog: + break; + default: + break; + } + return 0; +} + +} // namespace QWindowsDialogs +QT_END_NAMESPACE + +#include "qwindowsdialoghelpers.moc" diff --git a/Telegram/_qt_5_3_0_patch/qtbase/src/widgets/dialogs/qfiledialog.cpp b/Telegram/_qt_5_3_0_patch/qtbase/src/widgets/dialogs/qfiledialog.cpp new file mode 100644 index 000000000..44e63c692 --- /dev/null +++ b/Telegram/_qt_5_3_0_patch/qtbase/src/widgets/dialogs/qfiledialog.cpp @@ -0,0 +1,4002 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWidgets module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include "qfiledialog.h" + +#ifndef QT_NO_FILEDIALOG +#include "qfiledialog_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(Q_OS_WINCE) +#include "ui_qfiledialog.h" +#else +#define Q_EMBEDDED_SMALLSCREEN +#include "ui_qfiledialog_embedded.h" +#if defined(Q_OS_WINCE) +extern bool qt_priv_ptr_valid; +#endif +#endif +#if defined(Q_OS_UNIX) +#include +#elif defined(Q_OS_WIN) +# include +#endif + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QString, lastVisitedDir) + +/*! + \class QFileDialog + \brief The QFileDialog class provides a dialog that allow users to select files or directories. + \ingroup standard-dialogs + \inmodule QtWidgets + + The QFileDialog class enables a user to traverse the file system in + order to select one or many files or a directory. + + The easiest way to create a QFileDialog is to use the static + functions. On Windows, Mac OS X, KDE and GNOME, these static functions will + call the native file dialog when possible. + + \snippet code/src_gui_dialogs_qfiledialog.cpp 0 + + In the above example, a modal QFileDialog is created using a static + function. The dialog initially displays the contents of the "/home/jana" + directory, and displays files matching the patterns given in the + string "Image Files (*.png *.jpg *.bmp)". The parent of the file dialog + is set to \e this, and the window title is set to "Open Image". + + If you want to use multiple filters, separate each one with + \e two semicolons. For example: + + \snippet code/src_gui_dialogs_qfiledialog.cpp 1 + + You can create your own QFileDialog without using the static + functions. By calling setFileMode(), you can specify what the user must + select in the dialog: + + \snippet code/src_gui_dialogs_qfiledialog.cpp 2 + + In the above example, the mode of the file dialog is set to + AnyFile, meaning that the user can select any file, or even specify a + file that doesn't exist. This mode is useful for creating a + "Save As" file dialog. Use ExistingFile if the user must select an + existing file, or \l Directory if only a directory may be selected. + See the \l QFileDialog::FileMode enum for the complete list of modes. + + The fileMode property contains the mode of operation for the dialog; + this indicates what types of objects the user is expected to select. + Use setNameFilter() to set the dialog's file filter. For example: + + \snippet code/src_gui_dialogs_qfiledialog.cpp 3 + + In the above example, the filter is set to \c{"Images (*.png *.xpm *.jpg)"}, + this means that only files with the extension \c png, \c xpm, + or \c jpg will be shown in the QFileDialog. You can apply + several filters by using setNameFilters(). Use selectNameFilter() to select + one of the filters you've given as the file dialog's default filter. + + The file dialog has two view modes: \l{QFileDialog::}{List} and + \l{QFileDialog::}{Detail}. + \l{QFileDialog::}{List} presents the contents of the current directory + as a list of file and directory names. \l{QFileDialog::}{Detail} also + displays a list of file and directory names, but provides additional + information alongside each name, such as the file size and modification + date. Set the mode with setViewMode(): + + \snippet code/src_gui_dialogs_qfiledialog.cpp 4 + + The last important function you will need to use when creating your + own file dialog is selectedFiles(). + + \snippet code/src_gui_dialogs_qfiledialog.cpp 5 + + In the above example, a modal file dialog is created and shown. If + the user clicked OK, the file they selected is put in \c fileName. + + The dialog's working directory can be set with setDirectory(). + Each file in the current directory can be selected using + the selectFile() function. + + The \l{dialogs/standarddialogs}{Standard Dialogs} example shows + how to use QFileDialog as well as other built-in Qt dialogs. + + By default, a platform-native file dialog will be used if the platform has + one. In that case, the widgets which would otherwise be used to construct the + dialog will not be instantiated, so related accessors such as layout() and + itemDelegate() will return null. You can set the \l DontUseNativeDialog option to + ensure that the widget-based implementation will be used instead of the + native dialog. + + \sa QDir, QFileInfo, QFile, QColorDialog, QFontDialog, {Standard Dialogs Example}, + {Application Example} +*/ + +/*! + \enum QFileDialog::AcceptMode + + \value AcceptOpen + \value AcceptSave +*/ + +/*! + \enum QFileDialog::ViewMode + + This enum describes the view mode of the file dialog; i.e. what + information about each file will be displayed. + + \value Detail Displays an icon, a name, and details for each item in + the directory. + \value List Displays only an icon and a name for each item in the + directory. + + \sa setViewMode() +*/ + +/*! + \enum QFileDialog::FileMode + + This enum is used to indicate what the user may select in the file + dialog; i.e. what the dialog will return if the user clicks OK. + + \value AnyFile The name of a file, whether it exists or not. + \value ExistingFile The name of a single existing file. + \value Directory The name of a directory. Both files and + directories are displayed. + \value ExistingFiles The names of zero or more existing files. + + This value is obsolete since Qt 4.5: + + \value DirectoryOnly Use \c Directory and setOption(ShowDirsOnly, true) instead. + + \sa setFileMode() +*/ + +/*! + \enum QFileDialog::Option + + \value ShowDirsOnly Only show directories in the file dialog. By + default both files and directories are shown. (Valid only in the + \l Directory file mode.) + + \value DontResolveSymlinks Don't resolve symlinks in the file + dialog. By default symlinks are resolved. + + \value DontConfirmOverwrite Don't ask for confirmation if an + existing file is selected. By default confirmation is requested. + + \value DontUseNativeDialog Don't use the native file dialog. By + default, the native file dialog is used unless you use a subclass + of QFileDialog that contains the Q_OBJECT macro, or the platform + does not have a native dialog of the type that you require. + + \value ReadOnly Indicates that the model is readonly. + + \value HideNameFilterDetails Indicates if the file name filter details are + hidden or not. + + \value DontUseSheet In previous versions of Qt, the static + functions would create a sheet by default if the static function + was given a parent. This is no longer supported and does nothing in Qt 4.5, The + static functions will always be an application modal dialog. If + you want to use sheets, use QFileDialog::open() instead. + + \value DontUseCustomDirectoryIcons Always use the default directory icon. + Some platforms allow the user to set a different icon. Custom icon lookup + cause a big performance impact over network or removable drives. + Setting this will enable the QFileIconProvider::DontUseCustomDirectoryIcons + option in the icon provider. This enum value was added in Qt 5.2. +*/ + +/*! + \enum QFileDialog::DialogLabel + + \value LookIn + \value FileName + \value FileType + \value Accept + \value Reject +*/ + +/*! + \fn void QFileDialog::filesSelected(const QStringList &selected) + + When the selection changes for local operations and the dialog is + accepted, this signal is emitted with the (possibly empty) list + of \a selected files. + + \sa currentChanged(), QDialog::Accepted +*/ + +/*! + \fn void QFileDialog::urlsSelected(const QList &urls) + + When the selection changes and the dialog is accepted, this signal is + emitted with the (possibly empty) list of selected \a urls. + + \sa currentUrlChanged(), QDialog::Accepted + \since 5.2 +*/ + +/*! + \fn void QFileDialog::fileSelected(const QString &file) + + When the selection changes for local operations and the dialog is + accepted, this signal is emitted with the (possibly empty) + selected \a file. + + \sa currentChanged(), QDialog::Accepted +*/ + +/*! + \fn void QFileDialog::urlSelected(const QUrl &url) + + When the selection changes and the dialog is accepted, this signal is + emitted with the (possibly empty) selected \a url. + + \sa currentUrlChanged(), QDialog::Accepted + \since 5.2 +*/ + +/*! + \fn void QFileDialog::currentChanged(const QString &path) + + When the current file changes for local operations, this signal is + emitted with the new file name as the \a path parameter. + + \sa filesSelected() +*/ + +/*! + \fn void QFileDialog::currentUrlChanged(const QUrl &url) + + When the current file changes, this signal is emitted with the + new file URL as the \a url parameter. + + \sa urlsSelected() + \since 5.2 +*/ + +/*! + \fn void QFileDialog::directoryEntered(const QString &directory) + \since 4.3 + + This signal is emitted for local operations when the user enters + a \a directory. +*/ + +/*! + \fn void QFileDialog::directoryUrlEntered(const QUrl &directory) + + This signal is emitted when the user enters a \a directory. + + \since 5.2 +*/ + +/*! + \fn void QFileDialog::filterSelected(const QString &filter) + \since 4.3 + + This signal is emitted when the user selects a \a filter. +*/ + +//#if defined(Q_WS_WIN) || defined(Q_WS_MAC) +//bool Q_WIDGETS_EXPORT qt_use_native_dialogs = true; // for the benefit of testing tools, until we have a proper API +//#endif + +QT_BEGIN_INCLUDE_NAMESPACE +#ifdef Q_WS_WIN +#include +#endif +#include +#ifdef Q_WS_MAC +#include +#endif +QT_END_INCLUDE_NAMESPACE + +/*! + \fn QFileDialog::QFileDialog(QWidget *parent, Qt::WindowFlags flags) + + Constructs a file dialog with the given \a parent and widget \a flags. +*/ +QFileDialog::QFileDialog(QWidget *parent, Qt::WindowFlags f) + : QDialog(*new QFileDialogPrivate, parent, f) +{ + Q_D(QFileDialog); + d->init(); +} + +/*! + Constructs a file dialog with the given \a parent and \a caption that + initially displays the contents of the specified \a directory. + The contents of the directory are filtered before being shown in the + dialog, using a semicolon-separated list of filters specified by + \a filter. +*/ +QFileDialog::QFileDialog(QWidget *parent, + const QString &caption, + const QString &directory, + const QString &filter) + : QDialog(*new QFileDialogPrivate, parent, 0) +{ + Q_D(QFileDialog); + d->init(directory, filter, caption); +} + +/*! + \internal +*/ +QFileDialog::QFileDialog(const QFileDialogArgs &args) + : QDialog(*new QFileDialogPrivate, args.parent, 0) +{ + Q_D(QFileDialog); + d->init(args.directory, args.filter, args.caption); + setFileMode(args.mode); + setOptions(args.options); + selectFile(args.selection); +} + +/*! + Destroys the file dialog. +*/ +QFileDialog::~QFileDialog() +{ +#ifndef QT_NO_SETTINGS + QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); + settings.beginGroup(QLatin1String("Qt")); + settings.setValue(QLatin1String("filedialog"), saveState()); +#endif +} + +/*! + \since 4.3 + Sets the \a urls that are located in the sidebar. + + For instance: + + \snippet filedialogurls.cpp 0 + + The file dialog will then look like this: + + \image filedialogurls.png + + \sa sidebarUrls() +*/ +void QFileDialog::setSidebarUrls(const QList &urls) +{ + Q_D(QFileDialog); + if (!d->nativeDialogInUse) + d->qFileDialogUi->sidebar->setUrls(urls); +} + +/*! + \since 4.3 + Returns a list of urls that are currently in the sidebar +*/ +QList QFileDialog::sidebarUrls() const +{ + Q_D(const QFileDialog); + return (d->nativeDialogInUse ? QList() : d->qFileDialogUi->sidebar->urls()); +} + +static const qint32 QFileDialogMagic = 0xbe; + +/*! + \since 4.3 + Saves the state of the dialog's layout, history and current directory. + + Typically this is used in conjunction with QSettings to remember the size + for a future session. A version number is stored as part of the data. +*/ +QByteArray QFileDialog::saveState() const +{ + Q_D(const QFileDialog); + int version = 3; + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + + stream << qint32(QFileDialogMagic); + stream << qint32(version); + if (d->usingWidgets()) { + stream << d->qFileDialogUi->splitter->saveState(); + stream << d->qFileDialogUi->sidebar->urls(); + } else { + stream << QByteArray(); + stream << QList(); + } + stream << history(); + stream << *lastVisitedDir(); + if (d->usingWidgets()) + stream << d->qFileDialogUi->treeView->header()->saveState(); + else + stream << QByteArray(); + stream << qint32(viewMode()); + return data; +} + +/*! + \since 4.3 + Restores the dialogs's layout, history and current directory to the \a state specified. + + Typically this is used in conjunction with QSettings to restore the size + from a past session. + + Returns \c false if there are errors +*/ +bool QFileDialog::restoreState(const QByteArray &state) +{ + Q_D(QFileDialog); + int version = 3; + QByteArray sd = state; + QDataStream stream(&sd, QIODevice::ReadOnly); + if (stream.atEnd()) + return false; + QByteArray splitterState; + QByteArray headerData; + QList bookmarks; + QStringList history; + QString currentDirectory; + qint32 marker; + qint32 v; + qint32 viewMode; + stream >> marker; + stream >> v; + if (marker != QFileDialogMagic || v != version) + return false; + + stream >> splitterState + >> bookmarks + >> history + >> currentDirectory + >> headerData + >> viewMode; + + setDirectory(lastVisitedDir()->isEmpty() ? currentDirectory : *lastVisitedDir()); + setViewMode(static_cast(viewMode)); + + if (!d->usingWidgets()) + return true; + + if (!d->qFileDialogUi->splitter->restoreState(splitterState)) + return false; + QList list = d->qFileDialogUi->splitter->sizes(); + if (list.count() >= 2 && list.at(0) == 0 && list.at(1) == 0) { + for (int i = 0; i < list.count(); ++i) + list[i] = d->qFileDialogUi->splitter->widget(i)->sizeHint().width(); + d->qFileDialogUi->splitter->setSizes(list); + } + + d->qFileDialogUi->sidebar->setUrls(bookmarks); + while (history.count() > 5) + history.pop_front(); + setHistory(history); + QHeaderView *headerView = d->qFileDialogUi->treeView->header(); + if (!headerView->restoreState(headerData)) + return false; + + QList actions = headerView->actions(); + QAbstractItemModel *abstractModel = d->model; +#ifndef QT_NO_PROXYMODEL + if (d->proxyModel) + abstractModel = d->proxyModel; +#endif + int total = qMin(abstractModel->columnCount(QModelIndex()), actions.count() + 1); + for (int i = 1; i < total; ++i) + actions.at(i - 1)->setChecked(!headerView->isSectionHidden(i)); + + return true; +} + +/*! + \reimp +*/ +void QFileDialog::changeEvent(QEvent *e) +{ + Q_D(QFileDialog); + if (e->type() == QEvent::LanguageChange) { + d->retranslateWindowTitle(); + d->retranslateStrings(); + } + QDialog::changeEvent(e); +} + +QFileDialogPrivate::QFileDialogPrivate() + : +#ifndef QT_NO_PROXYMODEL + proxyModel(0), +#endif + model(0), + currentHistoryLocation(-1), + renameAction(0), + deleteAction(0), + showHiddenAction(0), + useDefaultCaption(true), + defaultFileTypes(true), + qFileDialogUi(0), + options(new QFileDialogOptions) +{ +} + +QFileDialogPrivate::~QFileDialogPrivate() +{ +} + +void QFileDialogPrivate::initHelper(QPlatformDialogHelper *h) +{ + QFileDialog *d = q_func(); + QObject::connect(h, SIGNAL(fileSelected(QUrl)), d, SLOT(_q_nativeFileSelected(QUrl))); + QObject::connect(h, SIGNAL(filesSelected(QList)), d, SLOT(_q_nativeFilesSelected(QList))); + QObject::connect(h, SIGNAL(currentChanged(QUrl)), d, SLOT(_q_nativeCurrentChanged(QUrl))); + QObject::connect(h, SIGNAL(directoryEntered(QUrl)), d, SLOT(_q_nativeEnterDirectory(QUrl))); + QObject::connect(h, SIGNAL(filterSelected(QString)), d, SIGNAL(filterSelected(QString))); + static_cast(h)->setOptions(options); + nativeDialogInUse = true; +} + +void QFileDialogPrivate::helperPrepareShow(QPlatformDialogHelper *) +{ + Q_Q(QFileDialog); + options->setWindowTitle(q->windowTitle()); + options->setHistory(q->history()); + if (usingWidgets()) + options->setSidebarUrls(qFileDialogUi->sidebar->urls()); + const QDir directory = q->directory(); + options->setInitialDirectory(directory.exists() ? + QUrl::fromLocalFile(directory.absolutePath()) : + QUrl()); + if (options->initiallySelectedNameFilter().isEmpty()) + options->setInitiallySelectedNameFilter(q->selectedNameFilter()); + if (options->initiallySelectedFiles().isEmpty()) + options->setInitiallySelectedFiles(userSelectedFiles()); +} + +void QFileDialogPrivate::helperDone(QDialog::DialogCode code, QPlatformDialogHelper *) +{ + if (code == QDialog::Accepted) { + Q_Q(QFileDialog); + q->setViewMode(static_cast(options->viewMode())); + q->setSidebarUrls(options->sidebarUrls()); + q->setHistory(options->history()); + } +} + +void QFileDialogPrivate::retranslateWindowTitle() +{ + Q_Q(QFileDialog); + if (!useDefaultCaption || setWindowTitle != q->windowTitle()) + return; + if (q->acceptMode() == QFileDialog::AcceptOpen) { + const QFileDialog::FileMode fileMode = q->fileMode(); + if (fileMode == QFileDialog::DirectoryOnly || fileMode == QFileDialog::Directory) + q->setWindowTitle(QFileDialog::tr("Find Directory")); + else + q->setWindowTitle(QFileDialog::tr("Open")); + } else + q->setWindowTitle(QFileDialog::tr("Save As")); + + setWindowTitle = q->windowTitle(); +} + +void QFileDialogPrivate::setLastVisitedDirectory(const QString &dir) +{ + *lastVisitedDir() = dir; +} + +void QFileDialogPrivate::updateLookInLabel() +{ + if (options->isLabelExplicitlySet(QFileDialogOptions::LookIn)) + setLabelTextControl(QFileDialog::LookIn, options->labelText(QFileDialogOptions::LookIn)); +} + +void QFileDialogPrivate::updateFileNameLabel() +{ + if (options->isLabelExplicitlySet(QFileDialogOptions::FileName)) { + setLabelTextControl(QFileDialog::FileName, options->labelText(QFileDialogOptions::FileName)); + } else { + switch (q_func()->fileMode()) { + case QFileDialog::DirectoryOnly: + case QFileDialog::Directory: + setLabelTextControl(QFileDialog::FileName, QFileDialog::tr("Directory:")); + break; + default: + setLabelTextControl(QFileDialog::FileName, QFileDialog::tr("File &name:")); + break; + } + } +} + +void QFileDialogPrivate::updateFileTypeLabel() +{ + if (options->isLabelExplicitlySet(QFileDialogOptions::FileType)) + setLabelTextControl(QFileDialog::FileType, options->labelText(QFileDialogOptions::FileType)); +} + +void QFileDialogPrivate::updateOkButtonText(bool saveAsOnFolder) +{ + Q_Q(QFileDialog); + // 'Save as' at a folder: Temporarily change to "Open". + if (saveAsOnFolder) { + setLabelTextControl(QFileDialog::Accept, QFileDialog::tr("&Open")); + } else if (options->isLabelExplicitlySet(QFileDialogOptions::Accept)) { + setLabelTextControl(QFileDialog::Accept, options->labelText(QFileDialogOptions::Accept)); + return; + } else { + switch (q->fileMode()) { + case QFileDialog::DirectoryOnly: + case QFileDialog::Directory: + setLabelTextControl(QFileDialog::Accept, QFileDialog::tr("&Choose")); + break; + default: + setLabelTextControl(QFileDialog::Accept, + q->acceptMode() == QFileDialog::AcceptOpen ? + QFileDialog::tr("&Open") : + QFileDialog::tr("&Save")); + break; + } + } +} + +void QFileDialogPrivate::updateCancelButtonText() +{ + if (options->isLabelExplicitlySet(QFileDialogOptions::Reject)) + setLabelTextControl(QFileDialog::Reject, options->labelText(QFileDialogOptions::Reject)); +} + +void QFileDialogPrivate::retranslateStrings() +{ + Q_Q(QFileDialog); + /* WIDGETS */ + if (defaultFileTypes) + q->setNameFilter(QFileDialog::tr("All Files (*)")); + if (nativeDialogInUse) + return; + + QList actions = qFileDialogUi->treeView->header()->actions(); + QAbstractItemModel *abstractModel = model; +#ifndef QT_NO_PROXYMODEL + if (proxyModel) + abstractModel = proxyModel; +#endif + int total = qMin(abstractModel->columnCount(QModelIndex()), actions.count() + 1); + for (int i = 1; i < total; ++i) { + actions.at(i - 1)->setText(QFileDialog::tr("Show ") + abstractModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString()); + } + + /* MENU ACTIONS */ + renameAction->setText(QFileDialog::tr("&Rename")); + deleteAction->setText(QFileDialog::tr("&Delete")); + showHiddenAction->setText(QFileDialog::tr("Show &hidden files")); + newFolderAction->setText(QFileDialog::tr("&New Folder")); + qFileDialogUi->retranslateUi(q); + updateLookInLabel(); + updateFileNameLabel(); + updateFileTypeLabel(); + updateCancelButtonText(); +} + +void QFileDialogPrivate::emitFilesSelected(const QStringList &files) +{ + Q_Q(QFileDialog); + emit q->filesSelected(files); + if (files.count() == 1) + emit q->fileSelected(files.first()); +} + +bool QFileDialogPrivate::canBeNativeDialog() const +{ + Q_Q(const QFileDialog); + if (nativeDialogInUse) + return true; + if (q->testAttribute(Qt::WA_DontShowOnScreen)) + return false; + if (q->options() & QFileDialog::DontUseNativeDialog) + return false; + + QLatin1String staticName(QFileDialog::staticMetaObject.className()); + QLatin1String dynamicName(q->metaObject()->className()); + return (staticName == dynamicName); +} + +bool QFileDialogPrivate::usingWidgets() const +{ + return !nativeDialogInUse && qFileDialogUi; +} + +/*! + \since 4.5 + Sets the given \a option to be enabled if \a on is true; otherwise, + clears the given \a option. + + \sa options, testOption() +*/ +void QFileDialog::setOption(Option option, bool on) +{ + const QFileDialog::Options previousOptions = options(); + if (!(previousOptions & option) != !on) + setOptions(previousOptions ^ option); +} + +/*! + \since 4.5 + + Returns \c true if the given \a option is enabled; otherwise, returns + false. + + \sa options, setOption() +*/ +bool QFileDialog::testOption(Option option) const +{ + Q_D(const QFileDialog); + return d->options->testOption(static_cast(option)); +} + +/*! + \property QFileDialog::options + \brief the various options that affect the look and feel of the dialog + \since 4.5 + + By default, all options are disabled. + + Options should be set before showing the dialog. Setting them while the + dialog is visible is not guaranteed to have an immediate effect on the + dialog (depending on the option and on the platform). + + \sa setOption(), testOption() +*/ +void QFileDialog::setOptions(Options options) +{ + Q_D(QFileDialog); + + Options changed = (options ^ QFileDialog::options()); + if (!changed) + return; + + d->options->setOptions(QFileDialogOptions::FileDialogOptions(int(options))); + + if ((options & DontUseNativeDialog) && !d->usingWidgets()) + d->createWidgets(); + + if (d->usingWidgets()) { + if (changed & DontResolveSymlinks) + d->model->setResolveSymlinks(!(options & DontResolveSymlinks)); + if (changed & ReadOnly) { + bool ro = (options & ReadOnly); + d->model->setReadOnly(ro); + d->qFileDialogUi->newFolderButton->setEnabled(!ro); + d->renameAction->setEnabled(!ro); + d->deleteAction->setEnabled(!ro); + } + + if (changed & DontUseCustomDirectoryIcons) { + QFileIconProvider::Options providerOptions = iconProvider()->options(); + if (options & DontUseCustomDirectoryIcons) + providerOptions |= QFileIconProvider::DontUseCustomDirectoryIcons; + else + providerOptions &= ~QFileIconProvider::DontUseCustomDirectoryIcons; + iconProvider()->setOptions(providerOptions); + } + } + + if (changed & HideNameFilterDetails) + setNameFilters(d->options->nameFilters()); + + if (changed & ShowDirsOnly) + setFilter((options & ShowDirsOnly) ? filter() & ~QDir::Files : filter() | QDir::Files); +} + +QFileDialog::Options QFileDialog::options() const +{ + Q_D(const QFileDialog); + return QFileDialog::Options(int(d->options->options())); +} + +/*! + \overload + + \since 4.5 + + This function connects one of its signals to the slot specified by \a receiver + and \a member. The specific signal depends is filesSelected() if fileMode is + ExistingFiles and fileSelected() if fileMode is anything else. + + The signal will be disconnected from the slot when the dialog is closed. +*/ +void QFileDialog::open(QObject *receiver, const char *member) +{ + Q_D(QFileDialog); + const char *signal = (fileMode() == ExistingFiles) ? SIGNAL(filesSelected(QStringList)) + : SIGNAL(fileSelected(QString)); + connect(this, signal, receiver, member); + d->signalToDisconnectOnClose = signal; + d->receiverToDisconnectOnClose = receiver; + d->memberToDisconnectOnClose = member; + + QDialog::open(); +} + + +/*! + \reimp +*/ +void QFileDialog::setVisible(bool visible) +{ + Q_D(QFileDialog); + if (visible){ + if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden)) + return; + } else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden)) + return; + + if (d->canBeNativeDialog()){ + if (d->setNativeDialogVisible(visible)){ + // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below + // updates the state correctly, but skips showing the non-native version: + setAttribute(Qt::WA_DontShowOnScreen); +#ifndef QT_NO_FSCOMPLETER + // So the completer doesn't try to complete and therefore show a popup + if (!d->nativeDialogInUse) + d->completer->setModel(0); +#endif + } else { + d->createWidgets(); + setAttribute(Qt::WA_DontShowOnScreen, false); +#ifndef QT_NO_FSCOMPLETER + if (!d->nativeDialogInUse) { + if (d->proxyModel != 0) + d->completer->setModel(d->proxyModel); + else + d->completer->setModel(d->model); + } +#endif + } + } + + if (d->usingWidgets()) + d->qFileDialogUi->fileNameEdit->setFocus(); + + QDialog::setVisible(visible); +} + +/*! + \internal + set the directory to url +*/ +void QFileDialogPrivate::_q_goToUrl(const QUrl &url) +{ + //The shortcut in the side bar may have a parent that is not fetched yet (e.g. an hidden file) + //so we force the fetching + QFileSystemModelPrivate::QFileSystemNode *node = model->d_func()->node(url.toLocalFile(), true); + QModelIndex idx = model->d_func()->index(node); + _q_enterDirectory(idx); +} + +/*! + \fn void QFileDialog::setDirectory(const QDir &directory) + + \overload +*/ + +/*! + Sets the file dialog's current \a directory. +*/ +void QFileDialog::setDirectory(const QString &directory) +{ + Q_D(QFileDialog); + QString newDirectory = directory; + QFileInfo info(directory); + //we remove .. and . from the given path if exist + if (!directory.isEmpty()) + newDirectory = QDir::cleanPath(directory); + + if (!directory.isEmpty() && newDirectory.isEmpty()) + return; + + d->setLastVisitedDirectory(newDirectory); + + d->options->setInitialDirectory(QUrl::fromLocalFile(directory)); + if (!d->usingWidgets()) { + d->setDirectory_sys(QUrl::fromLocalFile(newDirectory)); + return; + } + if (d->rootPath() == newDirectory) + return; + QModelIndex root = d->model->setRootPath(newDirectory); + if (!d->nativeDialogInUse) { + d->qFileDialogUi->newFolderButton->setEnabled(d->model->flags(root) & Qt::ItemIsDropEnabled); + if (root != d->rootIndex()) { +#ifndef QT_NO_FSCOMPLETER + if (directory.endsWith(QLatin1Char('/'))) + d->completer->setCompletionPrefix(newDirectory); + else + d->completer->setCompletionPrefix(newDirectory + QLatin1Char('/')); +#endif + d->setRootIndex(root); + } + d->qFileDialogUi->listView->selectionModel()->clear(); + } +} + +/*! + Returns the directory currently being displayed in the dialog. +*/ +QDir QFileDialog::directory() const +{ + Q_D(const QFileDialog); + if (d->nativeDialogInUse) { + QString dir = d->directory_sys().toLocalFile(); + return QDir(dir.isEmpty() ? d->options->initialDirectory().toLocalFile() : dir); + } + return d->rootPath(); +} + +/*! + Sets the file dialog's current \a directory url. + + \note The non-native QFileDialog supports only local files. + + \since 5.2 +*/ +void QFileDialog::setDirectoryUrl(const QUrl &directory) +{ + Q_D(QFileDialog); + if (!directory.isValid()) + return; + + if (d->nativeDialogInUse) + d->setDirectory_sys(directory); + else if (directory.isLocalFile()) + setDirectory(directory.toLocalFile()); + else + qWarning() << "Non-native QFileDialog supports only local files"; +} + +/*! + Returns the url of the directory currently being displayed in the dialog. + + \since 5.2 +*/ +QUrl QFileDialog::directoryUrl() const +{ + Q_D(const QFileDialog); + if (d->nativeDialogInUse) + return d->directory_sys(); + else + return QUrl::fromLocalFile(directory().absolutePath()); +} + +/*! + Selects the given \a filename in the file dialog. + + \sa selectedFiles() +*/ +void QFileDialog::selectFile(const QString &filename) +{ + Q_D(QFileDialog); + if (filename.isEmpty()) + return; + + if (!d->usingWidgets()) { + QUrl url = QUrl::fromLocalFile(filename); + if (QFileInfo(filename).isRelative()) { + QDir dir(d->options->initialDirectory().toLocalFile()); + url = QUrl::fromLocalFile(dir.absoluteFilePath(filename)); + } + d->selectFile_sys(url); + d->options->setInitiallySelectedFiles(QList() << url); + return; + } + + if (!QDir::isRelativePath(filename)) { + QFileInfo info(filename); + QString filenamePath = info.absoluteDir().path(); + + if (d->model->rootPath() != filenamePath) + setDirectory(filenamePath); + } + + QModelIndex index = d->model->index(filename); + QString file; + if (!index.isValid()) { + // save as dialog where we want to input a default value + QString text = filename; + if (QFileInfo(filename).isAbsolute()) { + QString current = d->rootPath(); + text.remove(current); + if (text.at(0) == QDir::separator() +#ifdef Q_OS_WIN + //On Windows both cases can happen + || text.at(0) == QLatin1Char('/') +#endif + ) + text = text.remove(0,1); + } + file = text; + } else { + file = index.data().toString(); + } + d->qFileDialogUi->listView->selectionModel()->clear(); + if (!isVisible() || !d->lineEdit()->hasFocus()) + d->lineEdit()->setText(file); +} + +/*! + Selects the given \a url in the file dialog. + + \note The non-native QFileDialog supports only local files. + + \sa selectedUrls() + \since 5.2 +*/ +void QFileDialog::selectUrl(const QUrl &url) +{ + Q_D(QFileDialog); + if (!url.isValid()) + return; + + if (d->nativeDialogInUse) + d->selectFile_sys(url); + else if (url.isLocalFile()) + selectFile(url.toLocalFile()); + else + qWarning() << "Non-native QFileDialog supports only local files"; +} + +#ifdef Q_OS_UNIX +Q_AUTOTEST_EXPORT QString qt_tildeExpansion(const QString &path, bool *expanded = 0) +{ + if (expanded != 0) + *expanded = false; + if (!path.startsWith(QLatin1Char('~'))) + return path; + QString ret = path; + QStringList tokens = ret.split(QDir::separator()); + if (tokens.first() == QLatin1String("~")) { + ret.replace(0, 1, QDir::homePath()); + } else { + QString userName = tokens.first(); + userName.remove(0, 1); +#if defined(Q_OS_VXWORKS) + const QString homePath = QDir::homePath(); +#elif defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) + passwd pw; + passwd *tmpPw; + char buf[200]; + const int bufSize = sizeof(buf); + int err = 0; +#if defined(Q_OS_SOLARIS) && (_POSIX_C_SOURCE - 0 < 199506L) + tmpPw = getpwnam_r(userName.toLocal8Bit().constData(), &pw, buf, bufSize); +#else + err = getpwnam_r(userName.toLocal8Bit().constData(), &pw, buf, bufSize, &tmpPw); +#endif + if (err || !tmpPw) + return ret; + const QString homePath = QString::fromLocal8Bit(pw.pw_dir); +#else + passwd *pw = getpwnam(userName.toLocal8Bit().constData()); + if (!pw) + return ret; + const QString homePath = QString::fromLocal8Bit(pw->pw_dir); +#endif + ret.replace(0, tokens.first().length(), homePath); + } + if (expanded != 0) + *expanded = true; + return ret; +} +#endif + +/** + Returns the text in the line edit which can be one or more file names + */ +QStringList QFileDialogPrivate::typedFiles() const +{ + Q_Q(const QFileDialog); + QStringList files; + QString editText = lineEdit()->text(); + if (!editText.contains(QLatin1Char('"'))) { +#ifdef Q_OS_UNIX + const QString prefix = q->directory().absolutePath() + QDir::separator(); + if (QFile::exists(prefix + editText)) + files << editText; + else + files << qt_tildeExpansion(editText); +#else + files << editText; + Q_UNUSED(q) +#endif + } else { + // " is used to separate files like so: "file1" "file2" "file3" ... + // ### need escape character for filenames with quotes (") + QStringList tokens = editText.split(QLatin1Char('\"')); + for (int i=0; idirectory().absolutePath() + QDir::separator(); + if (QFile::exists(prefix + token)) + files << token; + else + files << qt_tildeExpansion(token); +#else + files << toInternal(tokens.at(i)); +#endif + } + } + return addDefaultSuffixToFiles(files); +} + +// Return selected files without defaulting to the root of the file system model +// used for initializing QFileDialogOptions for native dialogs. The default is +// not suitable for native dialogs since it mostly equals directory(). +QList QFileDialogPrivate::userSelectedFiles() const +{ + QList files; + + if (!usingWidgets()) + return addDefaultSuffixToUrls(selectedFiles_sys()); + + foreach (const QModelIndex &index, qFileDialogUi->listView->selectionModel()->selectedRows()) + files.append(QUrl::fromLocalFile(index.data(QFileSystemModel::FilePathRole).toString())); + + if (files.isEmpty() && !lineEdit()->text().isEmpty()) + foreach (const QString &path, typedFiles()) + files.append(QUrl::fromLocalFile(path)); + + return files; +} + +QByteArray QFileDialogPrivate::userSelectedRemoteContent() const +{ + if (nativeDialogInUse) + return selectedRemoteContent_sys(); + + return QByteArray(); +} + +QStringList QFileDialogPrivate::addDefaultSuffixToFiles(const QStringList filesToFix) const +{ + QStringList files; + for (int i=0; idefaultSuffix(); + if (!defaultSuffix.isEmpty() && !info.isDir() && name.lastIndexOf(QLatin1Char('.')) == -1) + name += QLatin1Char('.') + defaultSuffix; + if (info.isAbsolute()) { + files.append(name); + } else { + // at this point the path should only have Qt path separators. + // This check is needed since we might be at the root directory + // and on Windows it already ends with slash. + QString path = rootPath(); + if (!path.endsWith(QLatin1Char('/'))) + path += QLatin1Char('/'); + path += name; + files.append(path); + } + } + return files; +} + +QList QFileDialogPrivate::addDefaultSuffixToUrls(const QList &urlsToFix) const +{ + QList urls; + for (int i=0; idefaultSuffix(); + if (!defaultSuffix.isEmpty() && !url.path().endsWith(QLatin1Char('/')) && url.path().lastIndexOf(QLatin1Char('.')) == -1) + url.setPath(url.path() + QLatin1Char('.') + defaultSuffix); + urls.append(url); + } + return urls; +} + + +/*! + Returns a list of strings containing the absolute paths of the + selected files in the dialog. If no files are selected, or + the mode is not ExistingFiles or ExistingFile, selectedFiles() contains the current path in the viewport. + + \sa selectedNameFilter(), selectFile() +*/ +QStringList QFileDialog::selectedFiles() const +{ + Q_D(const QFileDialog); + + QStringList files; + foreach (const QUrl &file, d->userSelectedFiles()) + files.append(file.toLocalFile()); + if (files.isEmpty()) { + const FileMode fm = fileMode(); + if (fm != ExistingFile && fm != ExistingFiles) + files.append(d->rootIndex().data(QFileSystemModel::FilePathRole).toString()); + } + return files; +} + +QByteArray QFileDialog::selectedRemoteContent() const +{ + Q_D(const QFileDialog); + + return d->userSelectedRemoteContent(); +} + +/*! + Returns a list of urls containing the selected files in the dialog. + If no files are selected, or the mode is not ExistingFiles or + ExistingFile, selectedUrls() contains the current path in the viewport. + + \sa selectedNameFilter(), selectUrl() + \since 5.2 +*/ +QList QFileDialog::selectedUrls() const +{ + Q_D(const QFileDialog); + if (d->nativeDialogInUse) { + return d->userSelectedFiles(); + } else { + QList urls; + foreach (const QString &file, selectedFiles()) + urls.append(QUrl::fromLocalFile(file)); + return urls; + } +} + +/* + Makes a list of filters from ;;-separated text. + Used by the mac and windows implementations +*/ +QStringList qt_make_filter_list(const QString &filter) +{ + QString f(filter); + + if (f.isEmpty()) + return QStringList(); + + QString sep(QLatin1String(";;")); + int i = f.indexOf(sep, 0); + if (i == -1) { + if (f.indexOf(QLatin1Char('\n'), 0) != -1) { + sep = QLatin1Char('\n'); + i = f.indexOf(sep, 0); + } + } + + return f.split(sep); +} + +/*! + \since 4.4 + + Sets the filter used in the file dialog to the given \a filter. + + If \a filter contains a pair of parentheses containing one or more + filename-wildcard patterns, separated by spaces, then only the + text contained in the parentheses is used as the filter. This means + that these calls are all equivalent: + + \snippet code/src_gui_dialogs_qfiledialog.cpp 6 + + \sa setMimeTypeFilters(), setNameFilters() +*/ +void QFileDialog::setNameFilter(const QString &filter) +{ + setNameFilters(qt_make_filter_list(filter)); +} + + +/*! + \property QFileDialog::nameFilterDetailsVisible + \obsolete + \brief This property holds whether the filter details is shown or not. + \since 4.4 + + When this property is \c true (the default), the filter details are shown + in the combo box. When the property is set to false, these are hidden. + + Use setOption(HideNameFilterDetails, !\e enabled) or + !testOption(HideNameFilterDetails). +*/ +void QFileDialog::setNameFilterDetailsVisible(bool enabled) +{ + setOption(HideNameFilterDetails, !enabled); +} + +bool QFileDialog::isNameFilterDetailsVisible() const +{ + return !testOption(HideNameFilterDetails); +} + + +/* + Strip the filters by removing the details, e.g. (*.*). +*/ +QStringList qt_strip_filters(const QStringList &filters) +{ + QStringList strippedFilters; + QRegExp r(QString::fromLatin1(QPlatformFileDialogHelper::filterRegExp)); + for (int i = 0; i < filters.count(); ++i) { + QString filterName; + int index = r.indexIn(filters[i]); + if (index >= 0) + filterName = r.cap(1); + strippedFilters.append(filterName.simplified()); + } + return strippedFilters; +} + + +/*! + \since 4.4 + + Sets the \a filters used in the file dialog. + + Note that the filter \b{*.*} is not portable, because the historical + assumption that the file extension determines the file type is not + consistent on every operating system. It is possible to have a file with no + dot in its name (for example, \c Makefile). In a native Windows file + dialog, \b{*.*} will match such files, while in other types of file dialogs + it may not. So it is better to use \b{*} if you mean to select any file. + + \snippet code/src_gui_dialogs_qfiledialog.cpp 7 + + \l setMimeTypeFilters() has the advantage of providing all possible name + filters for each file type. For example, JPEG images have three possible + extensions; if your application can open such files, selecting the + \c image/jpeg mime type as a filter will allow you to open all of them. +*/ +void QFileDialog::setNameFilters(const QStringList &filters) +{ + Q_D(QFileDialog); + d->defaultFileTypes = (filters == QStringList(QFileDialog::tr("All Files (*)"))); + QStringList cleanedFilters; + for (int i = 0; i < filters.count(); ++i) { + cleanedFilters << filters[i].simplified(); + } + d->options->setNameFilters(cleanedFilters); + + if (!d->usingWidgets()) + return; + + d->qFileDialogUi->fileTypeCombo->clear(); + if (cleanedFilters.isEmpty()) + return; + + if (testOption(HideNameFilterDetails)) + d->qFileDialogUi->fileTypeCombo->addItems(qt_strip_filters(cleanedFilters)); + else + d->qFileDialogUi->fileTypeCombo->addItems(cleanedFilters); + + d->_q_useNameFilter(0); +} + +/*! + \since 4.4 + + Returns the file type filters that are in operation on this file + dialog. +*/ +QStringList QFileDialog::nameFilters() const +{ + return d_func()->options->nameFilters(); +} + +/*! + \since 4.4 + + Sets the current file type \a filter. Multiple filters can be + passed in \a filter by separating them with semicolons or spaces. + + \sa setNameFilter(), setNameFilters(), selectedNameFilter() +*/ +void QFileDialog::selectNameFilter(const QString &filter) +{ + Q_D(QFileDialog); + d->options->setInitiallySelectedNameFilter(filter); + if (!d->usingWidgets()) { + d->selectNameFilter_sys(filter); + return; + } + int i = -1; + if (testOption(HideNameFilterDetails)) { + const QStringList filters = qt_strip_filters(qt_make_filter_list(filter)); + if (!filters.isEmpty()) + i = d->qFileDialogUi->fileTypeCombo->findText(filters.first()); + } else { + i = d->qFileDialogUi->fileTypeCombo->findText(filter); + } + if (i >= 0) { + d->qFileDialogUi->fileTypeCombo->setCurrentIndex(i); + d->_q_useNameFilter(d->qFileDialogUi->fileTypeCombo->currentIndex()); + } +} + +/*! + \since 4.4 + + Returns the filter that the user selected in the file dialog. + + \sa selectedFiles() +*/ +QString QFileDialog::selectedNameFilter() const +{ + Q_D(const QFileDialog); + if (!d->usingWidgets()) + return d->selectedNameFilter_sys(); + + return d->qFileDialogUi->fileTypeCombo->currentText(); +} + +/*! + \since 4.4 + + Returns the filter that is used when displaying files. + + \sa setFilter() +*/ +QDir::Filters QFileDialog::filter() const +{ + Q_D(const QFileDialog); + if (d->usingWidgets()) + return d->model->filter(); + return d->options->filter(); +} + +/*! + \since 4.4 + + Sets the filter used by the model to \a filters. The filter is used + to specify the kind of files that should be shown. + + \sa filter() +*/ + +void QFileDialog::setFilter(QDir::Filters filters) +{ + Q_D(QFileDialog); + d->options->setFilter(filters); + if (!d->usingWidgets()) { + d->setFilter_sys(); + return; + } + + d->model->setFilter(filters); + d->showHiddenAction->setChecked((filters & QDir::Hidden)); +} + +static QString nameFilterForMime(const QString &mimeType) +{ + QMimeDatabase db; + QMimeType mime(db.mimeTypeForName(mimeType)); + if (mime.isValid()) { + if (mime.isDefault()) { + return QFileDialog::tr("All files (*)"); + } else { + const QString patterns = mime.globPatterns().join(QLatin1Char(' ')); + return mime.comment() + QStringLiteral(" (") + patterns + QLatin1Char(')'); + } + } + return QString(); +} + +/*! + \since 5.2 + + Sets the \a filters used in the file dialog, from a list of MIME types. + + Convenience method for setNameFilters(). + Uses QMimeType to create a name filter from the glob patterns and description + defined in each MIME type. + + Use application/octet-stream for the "All files (*)" filter, since that + is the base MIME type for all files. + + Calling setMimeTypeFilters overrides any previously set name filters, + and changes the return value of nameFilters(). + + \snippet code/src_gui_dialogs_qfiledialog.cpp 13 +*/ +void QFileDialog::setMimeTypeFilters(const QStringList &filters) +{ + Q_D(QFileDialog); + QStringList nameFilters; + foreach (const QString &mimeType, filters) { + const QString text = nameFilterForMime(mimeType); + if (!text.isEmpty()) + nameFilters.append(text); + } + setNameFilters(nameFilters); + d->options->setMimeTypeFilters(filters); +} + +/*! + \since 5.2 + + Returns the MIME type filters that are in operation on this file + dialog. +*/ +QStringList QFileDialog::mimeTypeFilters() const +{ + return d_func()->options->mimeTypeFilters(); +} + +/*! + \since 5.2 + + Sets the current MIME type \a filter. + +*/ +void QFileDialog::selectMimeTypeFilter(const QString &filter) +{ + const QString text = nameFilterForMime(filter); + if (!text.isEmpty()) + selectNameFilter(text); +} + +/*! + \property QFileDialog::viewMode + \brief the way files and directories are displayed in the dialog + + By default, the \c Detail mode is used to display information about + files and directories. + + \sa ViewMode +*/ +void QFileDialog::setViewMode(QFileDialog::ViewMode mode) +{ + Q_D(QFileDialog); + d->options->setViewMode(static_cast(mode)); + if (!d->usingWidgets()) + return; + if (mode == Detail) + d->_q_showDetailsView(); + else + d->_q_showListView(); +} + +QFileDialog::ViewMode QFileDialog::viewMode() const +{ + Q_D(const QFileDialog); + if (!d->usingWidgets()) + return QFileDialog::List; + return (d->qFileDialogUi->stackedWidget->currentWidget() == d->qFileDialogUi->listView->parent() ? QFileDialog::List : QFileDialog::Detail); +} + +/*! + \property QFileDialog::fileMode + \brief the file mode of the dialog + + The file mode defines the number and type of items that the user is + expected to select in the dialog. + + By default, this property is set to AnyFile. + + This function will set the labels for the FileName and + \l{QFileDialog::}{Accept} \l{DialogLabel}s. It is possible to set + custom text after the call to setFileMode(). + + \sa FileMode +*/ +void QFileDialog::setFileMode(QFileDialog::FileMode mode) +{ + Q_D(QFileDialog); + d->options->setFileMode(static_cast(mode)); + + // keep ShowDirsOnly option in sync with fileMode (BTW, DirectoryOnly is obsolete) + setOption(ShowDirsOnly, mode == DirectoryOnly); + + if (!d->usingWidgets()) + return; + + d->retranslateWindowTitle(); + + // set selection mode and behavior + QAbstractItemView::SelectionMode selectionMode; + if (mode == QFileDialog::ExistingFiles) + selectionMode = QAbstractItemView::ExtendedSelection; + else + selectionMode = QAbstractItemView::SingleSelection; + d->qFileDialogUi->listView->setSelectionMode(selectionMode); + d->qFileDialogUi->treeView->setSelectionMode(selectionMode); + // set filter + d->model->setFilter(d->filterForMode(filter())); + // setup file type for directory + if (mode == DirectoryOnly || mode == Directory) { + d->qFileDialogUi->fileTypeCombo->clear(); + d->qFileDialogUi->fileTypeCombo->addItem(tr("Directories")); + d->qFileDialogUi->fileTypeCombo->setEnabled(false); + } + d->updateFileNameLabel(); + d->updateOkButtonText(); + d->qFileDialogUi->fileTypeCombo->setEnabled(!testOption(ShowDirsOnly)); + d->_q_updateOkButton(); +} + +QFileDialog::FileMode QFileDialog::fileMode() const +{ + Q_D(const QFileDialog); + return static_cast(d->options->fileMode()); +} + +/*! + \property QFileDialog::acceptMode + \brief the accept mode of the dialog + + The action mode defines whether the dialog is for opening or saving files. + + By default, this property is set to \l{AcceptOpen}. + + \sa AcceptMode +*/ +void QFileDialog::setAcceptMode(QFileDialog::AcceptMode mode) +{ + Q_D(QFileDialog); + d->options->setAcceptMode(static_cast(mode)); + // clear WA_DontShowOnScreen so that d->canBeNativeDialog() doesn't return false incorrectly + setAttribute(Qt::WA_DontShowOnScreen, false); + if (!d->usingWidgets()) + return; + QDialogButtonBox::StandardButton button = (mode == AcceptOpen ? QDialogButtonBox::Open : QDialogButtonBox::Save); + d->qFileDialogUi->buttonBox->setStandardButtons(button | QDialogButtonBox::Cancel); + d->qFileDialogUi->buttonBox->button(button)->setEnabled(false); + d->_q_updateOkButton(); + if (mode == AcceptSave) { + d->qFileDialogUi->lookInCombo->setEditable(false); + } + d->retranslateWindowTitle(); +} + +/* + Returns the file system model index that is the root index in the + views +*/ +QModelIndex QFileDialogPrivate::rootIndex() const { + return mapToSource(qFileDialogUi->listView->rootIndex()); +} + +QAbstractItemView *QFileDialogPrivate::currentView() const { + if (!qFileDialogUi->stackedWidget) + return 0; + if (qFileDialogUi->stackedWidget->currentWidget() == qFileDialogUi->listView->parent()) + return qFileDialogUi->listView; + return qFileDialogUi->treeView; +} + +QLineEdit *QFileDialogPrivate::lineEdit() const { + return (QLineEdit*)qFileDialogUi->fileNameEdit; +} + +int QFileDialogPrivate::maxNameLength(const QString &path) +{ +#if defined(Q_OS_UNIX) + return ::pathconf(QFile::encodeName(path).data(), _PC_NAME_MAX); +#elif defined(Q_OS_WINCE) || defined(Q_OS_WINRT) + Q_UNUSED(path); + return MAX_PATH; +#elif defined(Q_OS_WIN) + DWORD maxLength; + const QString drive = path.left(3); + if (::GetVolumeInformation(reinterpret_cast(drive.utf16()), NULL, 0, NULL, &maxLength, NULL, NULL, 0) == false) + return -1; + return maxLength; +#else + Q_UNUSED(path); +#endif + return -1; +} + +/* + Sets the view root index to be the file system model index +*/ +void QFileDialogPrivate::setRootIndex(const QModelIndex &index) const { + Q_ASSERT(index.isValid() ? index.model() == model : true); + QModelIndex idx = mapFromSource(index); + qFileDialogUi->treeView->setRootIndex(idx); + qFileDialogUi->listView->setRootIndex(idx); +} +/* + Select a file system model index + returns the index that was selected (or not depending upon sortfilterproxymodel) +*/ +QModelIndex QFileDialogPrivate::select(const QModelIndex &index) const { + Q_ASSERT(index.isValid() ? index.model() == model : true); + + QModelIndex idx = mapFromSource(index); + if (idx.isValid() && !qFileDialogUi->listView->selectionModel()->isSelected(idx)) + qFileDialogUi->listView->selectionModel()->select(idx, + QItemSelectionModel::Select | QItemSelectionModel::Rows); + return idx; +} + +QFileDialog::AcceptMode QFileDialog::acceptMode() const +{ + Q_D(const QFileDialog); + return static_cast(d->options->acceptMode()); +} + +/*! + \property QFileDialog::readOnly + \obsolete + \brief Whether the filedialog is read-only + + If this property is set to false, the file dialog will allow renaming, + and deleting of files and directories and creating directories. + + Use setOption(ReadOnly, \e enabled) or testOption(ReadOnly) instead. +*/ +void QFileDialog::setReadOnly(bool enabled) +{ + setOption(ReadOnly, enabled); +} + +bool QFileDialog::isReadOnly() const +{ + return testOption(ReadOnly); +} + +/*! + \property QFileDialog::resolveSymlinks + \obsolete + \brief whether the filedialog should resolve shortcuts + + If this property is set to true, the file dialog will resolve + shortcuts or symbolic links. + + Use setOption(DontResolveSymlinks, !\a enabled) or + !testOption(DontResolveSymlinks). +*/ +void QFileDialog::setResolveSymlinks(bool enabled) +{ + setOption(DontResolveSymlinks, !enabled); +} + +bool QFileDialog::resolveSymlinks() const +{ + return !testOption(DontResolveSymlinks); +} + +/*! + \property QFileDialog::confirmOverwrite + \obsolete + \brief whether the filedialog should ask before accepting a selected file, + when the accept mode is AcceptSave + + Use setOption(DontConfirmOverwrite, !\e enabled) or + !testOption(DontConfirmOverwrite) instead. +*/ +void QFileDialog::setConfirmOverwrite(bool enabled) +{ + setOption(DontConfirmOverwrite, !enabled); +} + +bool QFileDialog::confirmOverwrite() const +{ + return !testOption(DontConfirmOverwrite); +} + +/*! + \property QFileDialog::defaultSuffix + \brief suffix added to the filename if no other suffix was specified + + This property specifies a string that will be added to the + filename if it has no suffix already. The suffix is typically + used to indicate the file type (e.g. "txt" indicates a text + file). + + If the first character is a dot ('.'), it is removed. +*/ +void QFileDialog::setDefaultSuffix(const QString &suffix) +{ + Q_D(QFileDialog); + d->options->setDefaultSuffix(suffix); +} + +QString QFileDialog::defaultSuffix() const +{ + Q_D(const QFileDialog); + return d->options->defaultSuffix(); +} + +/*! + Sets the browsing history of the filedialog to contain the given + \a paths. +*/ +void QFileDialog::setHistory(const QStringList &paths) +{ + Q_D(QFileDialog); + if (d->usingWidgets()) + d->qFileDialogUi->lookInCombo->setHistory(paths); +} + +void QFileDialogComboBox::setHistory(const QStringList &paths) +{ + m_history = paths; + // Only populate the first item, showPopup will populate the rest if needed + QList list; + QModelIndex idx = d_ptr->model->index(d_ptr->rootPath()); + //On windows the popup display the "C:\", convert to nativeSeparators + QUrl url = QUrl::fromLocalFile(QDir::toNativeSeparators(idx.data(QFileSystemModel::FilePathRole).toString())); + if (url.isValid()) + list.append(url); + urlModel->setUrls(list); +} + +/*! + Returns the browsing history of the filedialog as a list of paths. +*/ +QStringList QFileDialog::history() const +{ + Q_D(const QFileDialog); + if (!d->usingWidgets()) + return QStringList(); + QStringList currentHistory = d->qFileDialogUi->lookInCombo->history(); + //On windows the popup display the "C:\", convert to nativeSeparators + QString newHistory = QDir::toNativeSeparators(d->rootIndex().data(QFileSystemModel::FilePathRole).toString()); + if (!currentHistory.contains(newHistory)) + currentHistory << newHistory; + return currentHistory; +} + +/*! + Sets the item delegate used to render items in the views in the + file dialog to the given \a delegate. + + \warning You should not share the same instance of a delegate between views. + Doing so can cause incorrect or unintuitive editing behavior since each + view connected to a given delegate may receive the \l{QAbstractItemDelegate::}{closeEditor()} + signal, and attempt to access, modify or close an editor that has already been closed. + + Note that the model used is QFileSystemModel. It has custom item data roles, which is + described by the \l{QFileSystemModel::}{Roles} enum. You can use a QFileIconProvider if + you only want custom icons. + + \sa itemDelegate(), setIconProvider(), QFileSystemModel +*/ +void QFileDialog::setItemDelegate(QAbstractItemDelegate *delegate) +{ + Q_D(QFileDialog); + if (!d->usingWidgets()) + return; + d->qFileDialogUi->listView->setItemDelegate(delegate); + d->qFileDialogUi->treeView->setItemDelegate(delegate); +} + +/*! + Returns the item delegate used to render the items in the views in the filedialog. +*/ +QAbstractItemDelegate *QFileDialog::itemDelegate() const +{ + Q_D(const QFileDialog); + if (!d->usingWidgets()) + return 0; + return d->qFileDialogUi->listView->itemDelegate(); +} + +/*! + Sets the icon provider used by the filedialog to the specified \a provider. +*/ +void QFileDialog::setIconProvider(QFileIconProvider *provider) +{ + Q_D(QFileDialog); + if (!d->usingWidgets()) + return; + d->model->setIconProvider(provider); + //It forces the refresh of all entries in the side bar, then we can get new icons + d->qFileDialogUi->sidebar->setUrls(d->qFileDialogUi->sidebar->urls()); +} + +/*! + Returns the icon provider used by the filedialog. +*/ +QFileIconProvider *QFileDialog::iconProvider() const +{ + Q_D(const QFileDialog); + return d->model->iconProvider(); +} + +void QFileDialogPrivate::setLabelTextControl(QFileDialog::DialogLabel label, const QString &text) +{ + if (!qFileDialogUi) + return; + switch (label) { + case QFileDialog::LookIn: + qFileDialogUi->lookInLabel->setText(text); + break; + case QFileDialog::FileName: + qFileDialogUi->fileNameLabel->setText(text); + break; + case QFileDialog::FileType: + qFileDialogUi->fileTypeLabel->setText(text); + break; + case QFileDialog::Accept: + if (q_func()->acceptMode() == QFileDialog::AcceptOpen) { + if (QPushButton *button = qFileDialogUi->buttonBox->button(QDialogButtonBox::Open)) + button->setText(text); + } else { + if (QPushButton *button = qFileDialogUi->buttonBox->button(QDialogButtonBox::Save)) + button->setText(text); + } + break; + case QFileDialog::Reject: + if (QPushButton *button = qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel)) + button->setText(text); + break; + } +} + +/*! + Sets the \a text shown in the filedialog in the specified \a label. +*/ + +void QFileDialog::setLabelText(DialogLabel label, const QString &text) +{ + Q_D(QFileDialog); + d->options->setLabelText(static_cast(label), text); + d->setLabelTextControl(label, text); +} + +/*! + Returns the text shown in the filedialog in the specified \a label. +*/ +QString QFileDialog::labelText(DialogLabel label) const +{ + Q_D(const QFileDialog); + if (!d->usingWidgets()) + return d->options->labelText(static_cast(label)); + QPushButton *button; + switch (label) { + case LookIn: + return d->qFileDialogUi->lookInLabel->text(); + case FileName: + return d->qFileDialogUi->fileNameLabel->text(); + case FileType: + return d->qFileDialogUi->fileTypeLabel->text(); + case Accept: + if (acceptMode() == AcceptOpen) + button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Open); + else + button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Save); + if (button) + return button->text(); + case Reject: + button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel); + if (button) + return button->text(); + } + return QString(); +} + +/* + For the native file dialogs +*/ + +#if defined(Q_WS_WIN) +extern QString qt_win_get_open_file_name(const QFileDialogArgs &args, + QString *initialDirectory, + QString *selectedFilter); + +extern QString qt_win_get_save_file_name(const QFileDialogArgs &args, + QString *initialDirectory, + QString *selectedFilter); + +extern QStringList qt_win_get_open_file_names(const QFileDialogArgs &args, + QString *initialDirectory, + QString *selectedFilter); + +extern QString qt_win_get_existing_directory(const QFileDialogArgs &args); +#endif + +/*! + This is a convenience static function that returns an existing file + selected by the user. If the user presses Cancel, it returns a null string. + + \snippet code/src_gui_dialogs_qfiledialog.cpp 8 + + The function creates a modal file dialog with the given \a parent widget. + If \a parent is not 0, the dialog will be shown centered over the parent + widget. + + The file dialog's working directory will be set to \a dir. If \a dir + includes a file name, the file will be selected. Only files that match the + given \a filter are shown. The filter selected is set to \a selectedFilter. + The parameters \a dir, \a selectedFilter, and \a filter may be empty + strings. If you want multiple filters, separate them with ';;', for + example: + + \code + "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" + \endcode + + The \a options argument holds various options about how to run the dialog, + see the QFileDialog::Option enum for more information on the flags you can + pass. + + The dialog's caption is set to \a caption. If \a caption is not specified + then a default caption will be used. + + On Windows, and Mac OS X, this static function will use the + native file dialog and not a QFileDialog. + + On Windows the dialog will spin a blocking modal event loop that will not + dispatch any QTimers, and if \a parent is not 0 then it will position the + dialog just below the parent's title bar. + + On Unix/X11, the normal behavior of the file dialog is to resolve and + follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp}, + the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. If + \a options includes DontResolveSymlinks, the file dialog will treat + symlinks as regular directories. + + \warning Do not delete \a parent during the execution of the dialog. If you + want to do this, you should create the dialog yourself using one of the + QFileDialog constructors. + + \sa getOpenFileNames(), getSaveFileName(), getExistingDirectory() +*/ +QString QFileDialog::getOpenFileName(QWidget *parent, + const QString &caption, + const QString &dir, + const QString &filter, + QString *selectedFilter, + Options options) +{ + QFileDialogArgs args; + args.parent = parent; + args.caption = caption; + args.directory = QFileDialogPrivate::workingDirectory(dir); + args.selection = QFileDialogPrivate::initialSelection(dir); + args.filter = filter; + args.mode = ExistingFile; + args.options = options; +#if defined(Q_WS_WIN) + if (QGuiApplicationPrivate::platformIntegration()->usePlatformNativeDialog() && !(args.options & DontUseNativeDialog)) { + return qt_win_get_open_file_name(args, &(args.directory), selectedFilter); + } +#endif + + // create a qt dialog + QFileDialog dialog(args); + if (selectedFilter && !selectedFilter->isEmpty()) + dialog.selectNameFilter(*selectedFilter); + if (dialog.exec() == QDialog::Accepted) { + if (selectedFilter) + *selectedFilter = dialog.selectedNameFilter(); + return dialog.selectedFiles().value(0); + } + return QString(); +} + +/*! + This is a convenience static function that returns an existing file + selected by the user. If the user presses Cancel, it returns an + empty url. + + The function is used similarly to QFileDialog::getOpenFileName(). In + particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter + and \a options are used in the exact same way. + + The main difference with QFileDialog::getOpenFileName() comes from + the ability offered to the user to select a remote file. That's why + the return type and the type of \a dir is QUrl. + + The \a supportedSchemes argument allows to restrict the type of URLs the + user will be able to select. It is a way for the application to declare + the protocols it will support to fetch the file content. An empty list + means that no restriction is applied (the default). + Supported for local files ("file" scheme) is implicit and always enabled. + it is not necessary to include in the restriction. + + When possible, this static function will use the native file dialog and + not a QFileDialog. On platforms which don't support selecting remote + files, Qt will allow to select only local files. + + \sa getOpenFileName(), getOpenFileUrls(), getSaveFileUrl(), getExistingDirectoryUrl() + \since 5.2 +*/ +QUrl QFileDialog::getOpenFileUrl(QWidget *parent, + const QString &caption, + const QUrl &dir, + const QString &filter, + QString *selectedFilter, + Options options, + const QStringList &supportedSchemes) +{ + Q_UNUSED(supportedSchemes); + + // Falls back to local file + return QUrl::fromLocalFile(getOpenFileName(parent, caption, dir.toLocalFile(), filter, selectedFilter, options)); +} + +/*! + This is a convenience static function that will return one or more existing + files selected by the user. + + \snippet code/src_gui_dialogs_qfiledialog.cpp 9 + + This function creates a modal file dialog with the given \a parent widget. + If \a parent is not 0, the dialog will be shown centered over the parent + widget. + + The file dialog's working directory will be set to \a dir. If \a dir + includes a file name, the file will be selected. The filter is set to + \a filter so that only those files which match the filter are shown. The + filter selected is set to \a selectedFilter. The parameters \a dir, + \a selectedFilter and \a filter may be empty strings. If you need multiple + filters, separate them with ';;', for instance: + + \code + "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" + \endcode + + The dialog's caption is set to \a caption. If \a caption is not specified + then a default caption will be used. + + On Windows, and Mac OS X, this static function will use the + native file dialog and not a QFileDialog. + + On Windows the dialog will spin a blocking modal event loop that will not + dispatch any QTimers, and if \a parent is not 0 then it will position the + dialog just below the parent's title bar. + + On Unix/X11, the normal behavior of the file dialog is to resolve and + follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp}, + the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. + The \a options argument holds various options about how to run the dialog, + see the QFileDialog::Option enum for more information on the flags you can + pass. + + \note If you want to iterate over the list of files, you should iterate + over a copy. For example: + + \snippet code/src_gui_dialogs_qfiledialog.cpp 10 + + \warning Do not delete \a parent during the execution of the dialog. If you + want to do this, you should create the dialog yourself using one of the + QFileDialog constructors. + + \sa getOpenFileName(), getSaveFileName(), getExistingDirectory() +*/ +QStringList QFileDialog::getOpenFileNames(QWidget *parent, + const QString &caption, + const QString &dir, + const QString &filter, + QString *selectedFilter, + Options options) +{ + QFileDialogArgs args; + args.parent = parent; + args.caption = caption; + args.directory = QFileDialogPrivate::workingDirectory(dir); + args.selection = QFileDialogPrivate::initialSelection(dir); + args.filter = filter; + args.mode = ExistingFiles; + args.options = options; + +#if defined(Q_WS_WIN) + if (QGuiApplicationPrivate::platformIntegration()->usePlatformNativeDialog() && !(args.options & DontUseNativeDialog)) { + return qt_win_get_open_file_names(args, &(args.directory), selectedFilter); + } +#endif + + // create a qt dialog + QFileDialog dialog(args); + if (selectedFilter && !selectedFilter->isEmpty()) + dialog.selectNameFilter(*selectedFilter); + if (dialog.exec() == QDialog::Accepted) { + if (selectedFilter) + *selectedFilter = dialog.selectedNameFilter(); + return dialog.selectedFiles(); + } + return QStringList(); +} + +/*! + This is a convenience static function that will return or or more existing + files selected by the user. If the user presses Cancel, it returns an + empty list. + + The function is used similarly to QFileDialog::getOpenFileNames(). In + particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter + and \a options are used in the exact same way. + + The main difference with QFileDialog::getOpenFileNames() comes from + the ability offered to the user to select remote files. That's why + the return type and the type of \a dir are respectively QList + and QUrl. + + The \a supportedSchemes argument allows to restrict the type of URLs the + user will be able to select. It is a way for the application to declare + the protocols it will support to fetch the file content. An empty list + means that no restriction is applied (the default). + Supported for local files ("file" scheme) is implicit and always enabled. + it is not necessary to include in the restriction. + + When possible, this static function will use the native file dialog and + not a QFileDialog. On platforms which don't support selecting remote + files, Qt will allow to select only local files. + + \sa getOpenFileNames(), getOpenFileUrl(), getSaveFileUrl(), getExistingDirectoryUrl() + \since 5.2 +*/ +QList QFileDialog::getOpenFileUrls(QWidget *parent, + const QString &caption, + const QUrl &dir, + const QString &filter, + QString *selectedFilter, + Options options, + const QStringList &supportedSchemes) +{ + Q_UNUSED(supportedSchemes); + + // Falls back to local files + QList urls; + + const QStringList fileNames = getOpenFileNames(parent, caption, dir.toLocalFile(), filter, selectedFilter, options); + foreach (const QString &fileName, fileNames) + urls << QUrl::fromLocalFile(fileName); + + return urls; +} + +/*! + This is a convenience static function that will return a file name selected + by the user. The file does not have to exist. + + It creates a modal file dialog with the given \a parent widget. If + \a parent is not 0, the dialog will be shown centered over the parent + widget. + + \snippet code/src_gui_dialogs_qfiledialog.cpp 11 + + The file dialog's working directory will be set to \a dir. If \a dir + includes a file name, the file will be selected. Only files that match the + \a filter are shown. The filter selected is set to \a selectedFilter. The + parameters \a dir, \a selectedFilter, and \a filter may be empty strings. + Multiple filters are separated with ';;'. For instance: + + \code + "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" + \endcode + + The \a options argument holds various options about how to run the dialog, + see the QFileDialog::Option enum for more information on the flags you can + pass. + + The default filter can be chosen by setting \a selectedFilter to the + desired value. + + The dialog's caption is set to \a caption. If \a caption is not specified, + a default caption will be used. + + On Windows, and Mac OS X, this static function will use the + native file dialog and not a QFileDialog. + + On Windows the dialog will spin a blocking modal event loop that will not + dispatch any QTimers, and if \a parent is not 0 then it will position the + dialog just below the parent's title bar. On Mac OS X, with its native file + dialog, the filter argument is ignored. + + On Unix/X11, the normal behavior of the file dialog is to resolve and + follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp}, + the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. If + \a options includes DontResolveSymlinks the file dialog will treat symlinks + as regular directories. + + \warning Do not delete \a parent during the execution of the dialog. If you + want to do this, you should create the dialog yourself using one of the + QFileDialog constructors. + + \sa getOpenFileName(), getOpenFileNames(), getExistingDirectory() +*/ +QString QFileDialog::getSaveFileName(QWidget *parent, + const QString &caption, + const QString &dir, + const QString &filter, + QString *selectedFilter, + Options options) +{ + QFileDialogArgs args; + args.parent = parent; + args.caption = caption; + args.directory = QFileDialogPrivate::workingDirectory(dir); + args.selection = QFileDialogPrivate::initialSelection(dir); + args.filter = filter; + args.mode = AnyFile; + args.options = options; + +#if defined(Q_WS_WIN) + if (QGuiApplicationPrivate::platformIntegration()->usePlatformNativeDialog() && !(args.options & DontUseNativeDialog)) { + return qt_win_get_save_file_name(args, &(args.directory), selectedFilter); + } +#endif + + // create a qt dialog + QFileDialog dialog(args); + dialog.setAcceptMode(AcceptSave); + if (selectedFilter && !selectedFilter->isEmpty()) + dialog.selectNameFilter(*selectedFilter); + if (dialog.exec() == QDialog::Accepted) { + if (selectedFilter) + *selectedFilter = dialog.selectedNameFilter(); + return dialog.selectedFiles().value(0); + } + + return QString(); +} + +/*! + This is a convenience static function that returns a file selected by + the user. The file does not have to exist. If the user presses Cancel, + it returns an empty url. + + The function is used similarly to QFileDialog::getSaveFileName(). In + particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter + and \a options are used in the exact same way. + + The main difference with QFileDialog::getSaveFileName() comes from + the ability offered to the user to select a remote file. That's why + the return type and the type of \a dir is QUrl. + + The \a supportedSchemes argument allows to restrict the type of URLs the + user will be able to select. It is a way for the application to declare + the protocols it will support to save the file content. An empty list + means that no restriction is applied (the default). + Supported for local files ("file" scheme) is implicit and always enabled. + it is not necessary to include in the restriction. + + When possible, this static function will use the native file dialog and + not a QFileDialog. On platforms which don't support selecting remote + files, Qt will allow to select only local files. + + \sa getSaveFileName(), getOpenFileUrl(), getOpenFileUrls(), getExistingDirectoryUrl() + \since 5.2 +*/ +QUrl QFileDialog::getSaveFileUrl(QWidget *parent, + const QString &caption, + const QUrl &dir, + const QString &filter, + QString *selectedFilter, + Options options, + const QStringList &supportedSchemes) +{ + Q_UNUSED(supportedSchemes); + + // Falls back to local file + return QUrl::fromLocalFile(getSaveFileName(parent, caption, dir.toLocalFile(), filter, selectedFilter, options)); +} + +/*! + This is a convenience static function that will return an existing + directory selected by the user. + + \snippet code/src_gui_dialogs_qfiledialog.cpp 12 + + This function creates a modal file dialog with the given \a parent widget. + If \a parent is not 0, the dialog will be shown centered over the parent + widget. + + The dialog's working directory is set to \a dir, and the caption is set to + \a caption. Either of these may be an empty string in which case the + current directory and a default caption will be used respectively. + + The \a options argument holds various options about how to run the dialog, + see the QFileDialog::Option enum for more information on the flags you can + pass. To ensure a native file dialog, \l{QFileDialog::}{ShowDirsOnly} must + be set. + + On Windows, and Mac OS X, this static function will use the + native file dialog and not a QFileDialog. On Windows CE, if the device has + no native file dialog, a QFileDialog will be used. + + On Unix/X11, the normal behavior of the file dialog is to resolve and + follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp}, + the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. If + \a options includes DontResolveSymlinks, the file dialog will treat + symlinks as regular directories. + + On Windows the dialog will spin a blocking modal event loop that will not + dispatch any QTimers, and if \a parent is not 0 then it will position the + dialog just below the parent's title bar. + + \warning Do not delete \a parent during the execution of the dialog. If you + want to do this, you should create the dialog yourself using one of the + QFileDialog constructors. + + \sa getOpenFileName(), getOpenFileNames(), getSaveFileName() +*/ +QString QFileDialog::getExistingDirectory(QWidget *parent, + const QString &caption, + const QString &dir, + Options options) +{ + QFileDialogArgs args; + args.parent = parent; + args.caption = caption; + args.directory = QFileDialogPrivate::workingDirectory(dir); + args.mode = (options & ShowDirsOnly ? DirectoryOnly : Directory); + args.options = options; + +#if defined(Q_WS_WIN) + if (QGuiApplicationPrivate::platformIntegration()->usePlatformNativeDialog() && !(args.options & DontUseNativeDialog) && (options & ShowDirsOnly) +#if defined(Q_OS_WINCE) + && qt_priv_ptr_valid +#endif + ) { + return qt_win_get_existing_directory(args); + } +#endif + + // create a qt dialog + QFileDialog dialog(args); + if (dialog.exec() == QDialog::Accepted) { + return dialog.selectedFiles().value(0); + } + return QString(); +} + +/*! + This is a convenience static function that will return an existing + directory selected by the user. If the user presses Cancel, it + returns an empty url. + + The function is used similarly to QFileDialog::getExistingDirectory(). + In particular \a parent, \a caption, \a dir and \a options are used + in the exact same way. + + The main difference with QFileDialog::getExistingDirectory() comes from + the ability offered to the user to select a remote directory. That's why + the return type and the type of \a dir is QUrl. + + The \a supportedSchemes argument allows to restrict the type of URLs the + user will be able to select. It is a way for the application to declare + the protocols it will support to fetch the file content. An empty list + means that no restriction is applied (the default). + Supported for local files ("file" scheme) is implicit and always enabled. + it is not necessary to include in the restriction. + + When possible, this static function will use the native file dialog and + not a QFileDialog. On platforms which don't support selecting remote + files, Qt will allow to select only local files. + + \sa getExistingDirectory(), getOpenFileUrl(), getOpenFileUrls(), getSaveFileUrl() + \since 5.2 +*/ +QUrl QFileDialog::getExistingDirectoryUrl(QWidget *parent, + const QString &caption, + const QUrl &dir, + Options options, + const QStringList &supportedSchemes) +{ + Q_UNUSED(supportedSchemes); + + // Falls back to local file + return QUrl::fromLocalFile(getExistingDirectory(parent, caption, dir.toLocalFile(), options)); +} + +inline static QString _qt_get_directory(const QString &path) +{ + QFileInfo info = QFileInfo(QDir::current(), path); + if (info.exists() && info.isDir()) + return QDir::cleanPath(info.absoluteFilePath()); + info.setFile(info.absolutePath()); + if (info.exists() && info.isDir()) + return info.absoluteFilePath(); + return QString(); +} +/* + Get the initial directory path + + \sa initialSelection() + */ +QString QFileDialogPrivate::workingDirectory(const QString &path) +{ + if (!path.isEmpty()) { + QString directory = _qt_get_directory(path); + if (!directory.isEmpty()) + return directory; + } + QString directory = _qt_get_directory(*lastVisitedDir()); + if (!directory.isEmpty()) + return directory; + return QDir::currentPath(); +} + +/* + Get the initial selection given a path. The initial directory + can contain both the initial directory and initial selection + /home/user/foo.txt + + \sa workingDirectory() + */ +QString QFileDialogPrivate::initialSelection(const QString &path) +{ + if (!path.isEmpty()) { + QFileInfo info(path); + if (!info.isDir()) + return info.fileName(); + } + return QString(); +} + +/*! + \reimp +*/ +void QFileDialog::done(int result) +{ + Q_D(QFileDialog); + + QDialog::done(result); + + if (d->receiverToDisconnectOnClose) { + disconnect(this, d->signalToDisconnectOnClose, + d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose); + d->receiverToDisconnectOnClose = 0; + } + d->memberToDisconnectOnClose.clear(); + d->signalToDisconnectOnClose.clear(); +} + +/*! + \reimp +*/ +void QFileDialog::accept() +{ + Q_D(QFileDialog); + QStringList files = selectedFiles(); + if (files.isEmpty()) + return; + if (!d->usingWidgets()) { + d->emitFilesSelected(files); + QDialog::accept(); + return; + } + + QString lineEditText = d->lineEdit()->text(); + // "hidden feature" type .. and then enter, and it will move up a dir + // special case for ".." + if (lineEditText == QLatin1String("..")) { + d->_q_navigateToParent(); + const QSignalBlocker blocker(d->qFileDialogUi->fileNameEdit); + d->lineEdit()->selectAll(); + return; + } + + switch (fileMode()) { + case DirectoryOnly: + case Directory: { + QString fn = files.first(); + QFileInfo info(fn); + if (!info.exists()) + info = QFileInfo(d->getEnvironmentVariable(fn)); + if (!info.exists()) { +#ifndef QT_NO_MESSAGEBOX + QString message = tr("%1\nDirectory not found.\nPlease verify the " + "correct directory name was given."); + QMessageBox::warning(this, windowTitle(), message.arg(info.fileName())); +#endif // QT_NO_MESSAGEBOX + return; + } + if (info.isDir()) { + d->emitFilesSelected(files); + QDialog::accept(); + } + return; + } + + case AnyFile: { + QString fn = files.first(); + QFileInfo info(fn); + if (info.isDir()) { + setDirectory(info.absoluteFilePath()); + return; + } + + if (!info.exists()) { + int maxNameLength = d->maxNameLength(info.path()); + if (maxNameLength >= 0 && info.fileName().length() > maxNameLength) + return; + } + + // check if we have to ask for permission to overwrite the file + if (!info.exists() || !confirmOverwrite() || acceptMode() == AcceptOpen) { + d->emitFilesSelected(QStringList(fn)); + QDialog::accept(); +#ifndef QT_NO_MESSAGEBOX + } else { + if (QMessageBox::warning(this, windowTitle(), + tr("%1 already exists.\nDo you want to replace it?") + .arg(info.fileName()), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No) + == QMessageBox::Yes) { + d->emitFilesSelected(QStringList(fn)); + QDialog::accept(); + } +#endif + } + return; + } + + case ExistingFile: + case ExistingFiles: + for (int i = 0; i < files.count(); ++i) { + QFileInfo info(files.at(i)); + if (!info.exists()) + info = QFileInfo(d->getEnvironmentVariable(files.at(i))); + if (!info.exists()) { +#ifndef QT_NO_MESSAGEBOX + QString message = tr("%1\nFile not found.\nPlease verify the " + "correct file name was given."); + QMessageBox::warning(this, windowTitle(), message.arg(info.fileName())); +#endif // QT_NO_MESSAGEBOX + return; + } + if (info.isDir()) { + setDirectory(info.absoluteFilePath()); + d->lineEdit()->clear(); + return; + } + } + d->emitFilesSelected(files); + QDialog::accept(); + return; + } +} + +/*! + \internal + + Create widgets, layout and set default values +*/ +void QFileDialogPrivate::init(const QString &directory, const QString &nameFilter, + const QString &caption) +{ + Q_Q(QFileDialog); + if (!caption.isEmpty()) { + useDefaultCaption = false; + setWindowTitle = caption; + q->setWindowTitle(caption); + } + + q->setAcceptMode(QFileDialog::AcceptOpen); + nativeDialogInUse = (canBeNativeDialog() && platformFileDialogHelper() != 0); + if (!nativeDialogInUse) + createWidgets(); + q->setFileMode(QFileDialog::AnyFile); + if (!nameFilter.isEmpty()) + q->setNameFilter(nameFilter); + q->setDirectory(workingDirectory(directory)); + q->selectFile(initialSelection(directory)); + +#ifndef QT_NO_SETTINGS + const QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); + q->restoreState(settings.value(QLatin1String("Qt/filedialog")).toByteArray()); +#endif + +#if defined(Q_EMBEDDED_SMALLSCREEN) + qFileDialogUi->lookInLabel->setVisible(false); + qFileDialogUi->fileNameLabel->setVisible(false); + qFileDialogUi->fileTypeLabel->setVisible(false); + qFileDialogUi->sidebar->hide(); +#endif + + q->resize(q->sizeHint()); +} + +/*! + \internal + + Create the widgets, set properties and connections +*/ +void QFileDialogPrivate::createWidgets() +{ + if (qFileDialogUi) + return; + Q_Q(QFileDialog); + model = new QFileSystemModel(q); + options->setFilter(model->filter()); + model->setObjectName(QLatin1String("qt_filesystem_model")); + if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) + model->setNameFilterDisables(helper->defaultNameFilterDisables()); + else + model->setNameFilterDisables(false); + if (nativeDialogInUse) + deletePlatformHelper(); + model->d_func()->disableRecursiveSort = true; + QFileDialog::connect(model, SIGNAL(fileRenamed(QString,QString,QString)), q, SLOT(_q_fileRenamed(QString,QString,QString))); + QFileDialog::connect(model, SIGNAL(rootPathChanged(QString)), + q, SLOT(_q_pathChanged(QString))); + QFileDialog::connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), + q, SLOT(_q_rowsInserted(QModelIndex))); + model->setReadOnly(false); + + qFileDialogUi.reset(new Ui_QFileDialog()); + qFileDialogUi->setupUi(q); + + QList initialBookmarks; + initialBookmarks << QUrl::fromLocalFile(QLatin1String("")) + << QUrl::fromLocalFile(QDir::homePath()); + qFileDialogUi->sidebar->setModelAndUrls(model, initialBookmarks); + QFileDialog::connect(qFileDialogUi->sidebar, SIGNAL(goToUrl(QUrl)), + q, SLOT(_q_goToUrl(QUrl))); + + QObject::connect(qFileDialogUi->buttonBox, SIGNAL(accepted()), q, SLOT(accept())); + QObject::connect(qFileDialogUi->buttonBox, SIGNAL(rejected()), q, SLOT(reject())); + + qFileDialogUi->lookInCombo->setFileDialogPrivate(this); + QObject::connect(qFileDialogUi->lookInCombo, SIGNAL(activated(QString)), q, SLOT(_q_goToDirectory(QString))); + + qFileDialogUi->lookInCombo->setInsertPolicy(QComboBox::NoInsert); + qFileDialogUi->lookInCombo->setDuplicatesEnabled(false); + + // filename + qFileDialogUi->fileNameEdit->setFileDialogPrivate(this); +#ifndef QT_NO_SHORTCUT + qFileDialogUi->fileNameLabel->setBuddy(qFileDialogUi->fileNameEdit); +#endif +#ifndef QT_NO_FSCOMPLETER + completer = new QFSCompleter(model, q); + qFileDialogUi->fileNameEdit->setCompleter(completer); +#endif // QT_NO_FSCOMPLETER + QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)), + q, SLOT(_q_autoCompleteFileName(QString))); + QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)), + q, SLOT(_q_updateOkButton())); + + QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(returnPressed()), q, SLOT(accept())); + + // filetype + qFileDialogUi->fileTypeCombo->setDuplicatesEnabled(false); + qFileDialogUi->fileTypeCombo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength); + qFileDialogUi->fileTypeCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + QObject::connect(qFileDialogUi->fileTypeCombo, SIGNAL(activated(int)), + q, SLOT(_q_useNameFilter(int))); + QObject::connect(qFileDialogUi->fileTypeCombo, SIGNAL(activated(QString)), + q, SIGNAL(filterSelected(QString))); + + qFileDialogUi->listView->setFileDialogPrivate(this); + qFileDialogUi->listView->setModel(model); + QObject::connect(qFileDialogUi->listView, SIGNAL(activated(QModelIndex)), + q, SLOT(_q_enterDirectory(QModelIndex))); + QObject::connect(qFileDialogUi->listView, SIGNAL(customContextMenuRequested(QPoint)), + q, SLOT(_q_showContextMenu(QPoint))); +#ifndef QT_NO_SHORTCUT + QShortcut *shortcut = new QShortcut(qFileDialogUi->listView); + shortcut->setKey(QKeySequence(QLatin1String("Delete"))); + QObject::connect(shortcut, SIGNAL(activated()), q, SLOT(_q_deleteCurrent())); +#endif + + qFileDialogUi->treeView->setFileDialogPrivate(this); + qFileDialogUi->treeView->setModel(model); + QHeaderView *treeHeader = qFileDialogUi->treeView->header(); + QFontMetrics fm(q->font()); + treeHeader->resizeSection(0, fm.width(QLatin1String("wwwwwwwwwwwwwwwwwwwwwwwwww"))); + treeHeader->resizeSection(1, fm.width(QLatin1String("128.88 GB"))); + treeHeader->resizeSection(2, fm.width(QLatin1String("mp3Folder"))); + treeHeader->resizeSection(3, fm.width(QLatin1String("10/29/81 02:02PM"))); + treeHeader->setContextMenuPolicy(Qt::ActionsContextMenu); + + QActionGroup *showActionGroup = new QActionGroup(q); + showActionGroup->setExclusive(false); + QObject::connect(showActionGroup, SIGNAL(triggered(QAction*)), + q, SLOT(_q_showHeader(QAction*)));; + + QAbstractItemModel *abstractModel = model; +#ifndef QT_NO_PROXYMODEL + if (proxyModel) + abstractModel = proxyModel; +#endif + for (int i = 1; i < abstractModel->columnCount(QModelIndex()); ++i) { + QAction *showHeader = new QAction(showActionGroup); + showHeader->setCheckable(true); + showHeader->setChecked(true); + treeHeader->addAction(showHeader); + } + + QScopedPointer selModel(qFileDialogUi->treeView->selectionModel()); + qFileDialogUi->treeView->setSelectionModel(qFileDialogUi->listView->selectionModel()); + + QObject::connect(qFileDialogUi->treeView, SIGNAL(activated(QModelIndex)), + q, SLOT(_q_enterDirectory(QModelIndex))); + QObject::connect(qFileDialogUi->treeView, SIGNAL(customContextMenuRequested(QPoint)), + q, SLOT(_q_showContextMenu(QPoint))); +#ifndef QT_NO_SHORTCUT + shortcut = new QShortcut(qFileDialogUi->treeView); + shortcut->setKey(QKeySequence(QLatin1String("Delete"))); + QObject::connect(shortcut, SIGNAL(activated()), q, SLOT(_q_deleteCurrent())); +#endif + + // Selections + QItemSelectionModel *selections = qFileDialogUi->listView->selectionModel(); + QObject::connect(selections, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + q, SLOT(_q_selectionChanged())); + QObject::connect(selections, SIGNAL(currentChanged(QModelIndex,QModelIndex)), + q, SLOT(_q_currentChanged(QModelIndex))); + qFileDialogUi->splitter->setStretchFactor(qFileDialogUi->splitter->indexOf(qFileDialogUi->splitter->widget(1)), QSizePolicy::Expanding); + + createToolButtons(); + createMenuActions(); + +#ifndef QT_NO_SETTINGS + const QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); + q->restoreState(settings.value(QLatin1String("Qt/filedialog")).toByteArray()); +#endif + + // Initial widget states from options + q->setFileMode(static_cast(options->fileMode())); + q->setAcceptMode(static_cast(options->acceptMode())); + q->setViewMode(static_cast(options->viewMode())); + q->setOptions(static_cast(static_cast(options->options()))); + if (!options->sidebarUrls().isEmpty()) + q->setSidebarUrls(options->sidebarUrls()); + q->setDirectoryUrl(options->initialDirectory()); + if (!options->mimeTypeFilters().isEmpty()) + q->setMimeTypeFilters(options->mimeTypeFilters()); + else if (!options->nameFilters().isEmpty()) + q->setNameFilters(options->nameFilters()); + q->selectNameFilter(options->initiallySelectedNameFilter()); + q->setDefaultSuffix(options->defaultSuffix()); + q->setHistory(options->history()); + if (options->initiallySelectedFiles().count() == 1) + q->selectFile(options->initiallySelectedFiles().first().fileName()); + foreach (QUrl url, options->initiallySelectedFiles()) + q->selectUrl(url); + lineEdit()->selectAll(); + _q_updateOkButton(); + retranslateStrings(); + q->resize(q->sizeHint()); +} + +void QFileDialogPrivate::_q_showHeader(QAction *action) +{ + Q_Q(QFileDialog); + QActionGroup *actionGroup = qobject_cast(q->sender()); + qFileDialogUi->treeView->header()->setSectionHidden(actionGroup->actions().indexOf(action) + 1, !action->isChecked()); +} + +#ifndef QT_NO_PROXYMODEL +/*! + \since 4.3 + + Sets the model for the views to the given \a proxyModel. This is useful if you + want to modify the underlying model; for example, to add columns, filter + data or add drives. + + Any existing proxy model will be removed, but not deleted. The file dialog + will take ownership of the \a proxyModel. + + \sa proxyModel() +*/ +void QFileDialog::setProxyModel(QAbstractProxyModel *proxyModel) +{ + Q_D(QFileDialog); + if (!d->usingWidgets()) + return; + if ((!proxyModel && !d->proxyModel) + || (proxyModel == d->proxyModel)) + return; + + QModelIndex idx = d->rootIndex(); + if (d->proxyModel) { + disconnect(d->proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(_q_rowsInserted(QModelIndex))); + } else { + disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(_q_rowsInserted(QModelIndex))); + } + + if (proxyModel != 0) { + proxyModel->setParent(this); + d->proxyModel = proxyModel; + proxyModel->setSourceModel(d->model); + d->qFileDialogUi->listView->setModel(d->proxyModel); + d->qFileDialogUi->treeView->setModel(d->proxyModel); +#ifndef QT_NO_FSCOMPLETER + d->completer->setModel(d->proxyModel); + d->completer->proxyModel = d->proxyModel; +#endif + connect(d->proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(_q_rowsInserted(QModelIndex))); + } else { + d->proxyModel = 0; + d->qFileDialogUi->listView->setModel(d->model); + d->qFileDialogUi->treeView->setModel(d->model); +#ifndef QT_NO_FSCOMPLETER + d->completer->setModel(d->model); + d->completer->sourceModel = d->model; + d->completer->proxyModel = 0; +#endif + connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(_q_rowsInserted(QModelIndex))); + } + QScopedPointer selModel(d->qFileDialogUi->treeView->selectionModel()); + d->qFileDialogUi->treeView->setSelectionModel(d->qFileDialogUi->listView->selectionModel()); + + d->setRootIndex(idx); + + // reconnect selection + QItemSelectionModel *selections = d->qFileDialogUi->listView->selectionModel(); + QObject::connect(selections, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(_q_selectionChanged())); + QObject::connect(selections, SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(_q_currentChanged(QModelIndex))); +} + +/*! + Returns the proxy model used by the file dialog. By default no proxy is set. + + \sa setProxyModel() +*/ +QAbstractProxyModel *QFileDialog::proxyModel() const +{ + Q_D(const QFileDialog); + return d->proxyModel; +} +#endif // QT_NO_PROXYMODEL + +/*! + \internal + + Create tool buttons, set properties and connections +*/ +void QFileDialogPrivate::createToolButtons() +{ + Q_Q(QFileDialog); + qFileDialogUi->backButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowBack, 0, q)); + qFileDialogUi->backButton->setAutoRaise(true); + qFileDialogUi->backButton->setEnabled(false); + QObject::connect(qFileDialogUi->backButton, SIGNAL(clicked()), q, SLOT(_q_navigateBackward())); + + qFileDialogUi->forwardButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowForward, 0, q)); + qFileDialogUi->forwardButton->setAutoRaise(true); + qFileDialogUi->forwardButton->setEnabled(false); + QObject::connect(qFileDialogUi->forwardButton, SIGNAL(clicked()), q, SLOT(_q_navigateForward())); + + qFileDialogUi->toParentButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogToParent, 0, q)); + qFileDialogUi->toParentButton->setAutoRaise(true); + qFileDialogUi->toParentButton->setEnabled(false); + QObject::connect(qFileDialogUi->toParentButton, SIGNAL(clicked()), q, SLOT(_q_navigateToParent())); + + qFileDialogUi->listModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogListView, 0, q)); + qFileDialogUi->listModeButton->setAutoRaise(true); + qFileDialogUi->listModeButton->setDown(true); + QObject::connect(qFileDialogUi->listModeButton, SIGNAL(clicked()), q, SLOT(_q_showListView())); + + qFileDialogUi->detailModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogDetailedView, 0, q)); + qFileDialogUi->detailModeButton->setAutoRaise(true); + QObject::connect(qFileDialogUi->detailModeButton, SIGNAL(clicked()), q, SLOT(_q_showDetailsView())); + + QSize toolSize(qFileDialogUi->fileNameEdit->sizeHint().height(), qFileDialogUi->fileNameEdit->sizeHint().height()); + qFileDialogUi->backButton->setFixedSize(toolSize); + qFileDialogUi->listModeButton->setFixedSize(toolSize); + qFileDialogUi->detailModeButton->setFixedSize(toolSize); + qFileDialogUi->forwardButton->setFixedSize(toolSize); + qFileDialogUi->toParentButton->setFixedSize(toolSize); + + qFileDialogUi->newFolderButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogNewFolder, 0, q)); + qFileDialogUi->newFolderButton->setFixedSize(toolSize); + qFileDialogUi->newFolderButton->setAutoRaise(true); + qFileDialogUi->newFolderButton->setEnabled(false); + QObject::connect(qFileDialogUi->newFolderButton, SIGNAL(clicked()), q, SLOT(_q_createDirectory())); +} + +/*! + \internal + + Create actions which will be used in the right click. +*/ +void QFileDialogPrivate::createMenuActions() +{ + Q_Q(QFileDialog); + + QAction *goHomeAction = new QAction(q); +#ifndef QT_NO_SHORTCUT + goHomeAction->setShortcut(Qt::CTRL + Qt::Key_H + Qt::SHIFT); +#endif + QObject::connect(goHomeAction, SIGNAL(triggered()), q, SLOT(_q_goHome())); + q->addAction(goHomeAction); + + // ### TODO add Desktop & Computer actions + + QAction *goToParent = new QAction(q); + goToParent->setObjectName(QLatin1String("qt_goto_parent_action")); +#ifndef QT_NO_SHORTCUT + goToParent->setShortcut(Qt::CTRL + Qt::UpArrow); +#endif + QObject::connect(goToParent, SIGNAL(triggered()), q, SLOT(_q_navigateToParent())); + q->addAction(goToParent); + + renameAction = new QAction(q); + renameAction->setEnabled(false); + renameAction->setObjectName(QLatin1String("qt_rename_action")); + QObject::connect(renameAction, SIGNAL(triggered()), q, SLOT(_q_renameCurrent())); + + deleteAction = new QAction(q); + deleteAction->setEnabled(false); + deleteAction->setObjectName(QLatin1String("qt_delete_action")); + QObject::connect(deleteAction, SIGNAL(triggered()), q, SLOT(_q_deleteCurrent())); + + showHiddenAction = new QAction(q); + showHiddenAction->setObjectName(QLatin1String("qt_show_hidden_action")); + showHiddenAction->setCheckable(true); + QObject::connect(showHiddenAction, SIGNAL(triggered()), q, SLOT(_q_showHidden())); + + newFolderAction = new QAction(q); + newFolderAction->setObjectName(QLatin1String("qt_new_folder_action")); + QObject::connect(newFolderAction, SIGNAL(triggered()), q, SLOT(_q_createDirectory())); +} + +void QFileDialogPrivate::_q_goHome() +{ + Q_Q(QFileDialog); + q->setDirectory(QDir::homePath()); +} + +/*! + \internal + + Update history with new path, buttons, and combo +*/ +void QFileDialogPrivate::_q_pathChanged(const QString &newPath) +{ + Q_Q(QFileDialog); + QDir dir(model->rootDirectory()); + qFileDialogUi->toParentButton->setEnabled(dir.exists()); + qFileDialogUi->sidebar->selectUrl(QUrl::fromLocalFile(newPath)); + q->setHistory(qFileDialogUi->lookInCombo->history()); + + if (currentHistoryLocation < 0 || currentHistory.value(currentHistoryLocation) != QDir::toNativeSeparators(newPath)) { + while (currentHistoryLocation >= 0 && currentHistoryLocation + 1 < currentHistory.count()) { + currentHistory.removeLast(); + } + currentHistory.append(QDir::toNativeSeparators(newPath)); + ++currentHistoryLocation; + } + qFileDialogUi->forwardButton->setEnabled(currentHistory.size() - currentHistoryLocation > 1); + qFileDialogUi->backButton->setEnabled(currentHistoryLocation > 0); +} + +/*! + \internal + + Navigates to the last directory viewed in the dialog. +*/ +void QFileDialogPrivate::_q_navigateBackward() +{ + Q_Q(QFileDialog); + if (!currentHistory.isEmpty() && currentHistoryLocation > 0) { + --currentHistoryLocation; + QString previousHistory = currentHistory.at(currentHistoryLocation); + q->setDirectory(previousHistory); + } +} + +/*! + \internal + + Navigates to the last directory viewed in the dialog. +*/ +void QFileDialogPrivate::_q_navigateForward() +{ + Q_Q(QFileDialog); + if (!currentHistory.isEmpty() && currentHistoryLocation < currentHistory.size() - 1) { + ++currentHistoryLocation; + QString nextHistory = currentHistory.at(currentHistoryLocation); + q->setDirectory(nextHistory); + } +} + +/*! + \internal + + Navigates to the parent directory of the currently displayed directory + in the dialog. +*/ +void QFileDialogPrivate::_q_navigateToParent() +{ + Q_Q(QFileDialog); + QDir dir(model->rootDirectory()); + QString newDirectory; + if (dir.isRoot()) { + newDirectory = model->myComputer().toString(); + } else { + dir.cdUp(); + newDirectory = dir.absolutePath(); + } + q->setDirectory(newDirectory); + emit q->directoryEntered(newDirectory); +} + +/*! + \internal + + Creates a new directory, first asking the user for a suitable name. +*/ +void QFileDialogPrivate::_q_createDirectory() +{ + Q_Q(QFileDialog); + qFileDialogUi->listView->clearSelection(); + + QString newFolderString = QFileDialog::tr("New Folder"); + QString folderName = newFolderString; + QString prefix = q->directory().absolutePath() + QDir::separator(); + if (QFile::exists(prefix + folderName)) { + qlonglong suffix = 2; + while (QFile::exists(prefix + folderName)) { + folderName = newFolderString + QString::number(suffix++); + } + } + + QModelIndex parent = rootIndex(); + QModelIndex index = model->mkdir(parent, folderName); + if (!index.isValid()) + return; + + index = select(index); + if (index.isValid()) { + qFileDialogUi->treeView->setCurrentIndex(index); + currentView()->edit(index); + } +} + +void QFileDialogPrivate::_q_showListView() +{ + qFileDialogUi->listModeButton->setDown(true); + qFileDialogUi->detailModeButton->setDown(false); + qFileDialogUi->treeView->hide(); + qFileDialogUi->listView->show(); + qFileDialogUi->stackedWidget->setCurrentWidget(qFileDialogUi->listView->parentWidget()); + qFileDialogUi->listView->doItemsLayout(); +} + +void QFileDialogPrivate::_q_showDetailsView() +{ + qFileDialogUi->listModeButton->setDown(false); + qFileDialogUi->detailModeButton->setDown(true); + qFileDialogUi->listView->hide(); + qFileDialogUi->treeView->show(); + qFileDialogUi->stackedWidget->setCurrentWidget(qFileDialogUi->treeView->parentWidget()); + qFileDialogUi->treeView->doItemsLayout(); +} + +/*! + \internal + + Show the context menu for the file/dir under position +*/ +void QFileDialogPrivate::_q_showContextMenu(const QPoint &position) +{ +#ifdef QT_NO_MENU + Q_UNUSED(position); +#else + Q_Q(QFileDialog); + QAbstractItemView *view = 0; + if (q->viewMode() == QFileDialog::Detail) + view = qFileDialogUi->treeView; + else + view = qFileDialogUi->listView; + QModelIndex index = view->indexAt(position); + index = mapToSource(index.sibling(index.row(), 0)); + + QMenu menu(view); + if (index.isValid()) { + // file context menu + const bool ro = model && model->isReadOnly(); + QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt()); + renameAction->setEnabled(!ro && p & QFile::WriteUser); + menu.addAction(renameAction); + deleteAction->setEnabled(!ro && p & QFile::WriteUser); + menu.addAction(deleteAction); + menu.addSeparator(); + } + menu.addAction(showHiddenAction); + if (qFileDialogUi->newFolderButton->isVisible()) { + newFolderAction->setEnabled(qFileDialogUi->newFolderButton->isEnabled()); + menu.addAction(newFolderAction); + } + menu.exec(view->viewport()->mapToGlobal(position)); +#endif // QT_NO_MENU +} + +/*! + \internal +*/ +void QFileDialogPrivate::_q_renameCurrent() +{ + Q_Q(QFileDialog); + QModelIndex index = qFileDialogUi->listView->currentIndex(); + index = index.sibling(index.row(), 0); + if (q->viewMode() == QFileDialog::List) + qFileDialogUi->listView->edit(index); + else + qFileDialogUi->treeView->edit(index); +} + +bool QFileDialogPrivate::removeDirectory(const QString &path) +{ + QModelIndex modelIndex = model->index(path); + return model->remove(modelIndex); +} + +/*! + \internal + + Deletes the currently selected item in the dialog. +*/ +void QFileDialogPrivate::_q_deleteCurrent() +{ + if (model->isReadOnly()) + return; + + QModelIndexList list = qFileDialogUi->listView->selectionModel()->selectedRows(); + for (int i = list.count() - 1; i >= 0; --i) { + QModelIndex index = list.at(i); + if (index == qFileDialogUi->listView->rootIndex()) + continue; + + index = mapToSource(index.sibling(index.row(), 0)); + if (!index.isValid()) + continue; + + QString fileName = index.data(QFileSystemModel::FileNameRole).toString(); + QString filePath = index.data(QFileSystemModel::FilePathRole).toString(); + bool isDir = model->isDir(index); + + QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt()); +#ifndef QT_NO_MESSAGEBOX + Q_Q(QFileDialog); + if (!(p & QFile::WriteUser) && (QMessageBox::warning(q_func(), QFileDialog::tr("Delete"), + QFileDialog::tr("'%1' is write protected.\nDo you want to delete it anyway?") + .arg(fileName), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No)) + return; + else if (QMessageBox::warning(q_func(), QFileDialog::tr("Delete"), + QFileDialog::tr("Are you sure you want to delete '%1'?") + .arg(fileName), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) + return; + +#else + if (!(p & QFile::WriteUser)) + return; +#endif // QT_NO_MESSAGEBOX + + // the event loop has run, we can NOT reuse index because the model might have removed it. + if (isDir) { + if (!removeDirectory(filePath)) { +#ifndef QT_NO_MESSAGEBOX + QMessageBox::warning(q, q->windowTitle(), + QFileDialog::tr("Could not delete directory.")); +#endif + } + } else { + model->remove(index); + } + } +} + +void QFileDialogPrivate::_q_autoCompleteFileName(const QString &text) +{ + if (text.startsWith(QLatin1String("//")) || text.startsWith(QLatin1Char('\\'))) { + qFileDialogUi->listView->selectionModel()->clearSelection(); + return; + } + + QStringList multipleFiles = typedFiles(); + if (multipleFiles.count() > 0) { + QModelIndexList oldFiles = qFileDialogUi->listView->selectionModel()->selectedRows(); + QModelIndexList newFiles; + for (int i = 0; i < multipleFiles.count(); ++i) { + QModelIndex idx = model->index(multipleFiles.at(i)); + if (oldFiles.contains(idx)) + oldFiles.removeAll(idx); + else + newFiles.append(idx); + } + for (int i = 0; i < newFiles.count(); ++i) + select(newFiles.at(i)); + if (lineEdit()->hasFocus()) + for (int i = 0; i < oldFiles.count(); ++i) + qFileDialogUi->listView->selectionModel()->select(oldFiles.at(i), + QItemSelectionModel::Toggle | QItemSelectionModel::Rows); + } +} + +/*! + \internal +*/ +void QFileDialogPrivate::_q_updateOkButton() +{ + Q_Q(QFileDialog); + QPushButton *button = qFileDialogUi->buttonBox->button((q->acceptMode() == QFileDialog::AcceptOpen) + ? QDialogButtonBox::Open : QDialogButtonBox::Save); + if (!button) + return; + const QFileDialog::FileMode fileMode = q->fileMode(); + + bool enableButton = true; + bool isOpenDirectory = false; + + QStringList files = q->selectedFiles(); + QString lineEditText = lineEdit()->text(); + + if (lineEditText.startsWith(QLatin1String("//")) || lineEditText.startsWith(QLatin1Char('\\'))) { + button->setEnabled(true); + updateOkButtonText(); + return; + } + + if (files.isEmpty()) { + enableButton = false; + } else if (lineEditText == QLatin1String("..")) { + isOpenDirectory = true; + } else { + switch (fileMode) { + case QFileDialog::DirectoryOnly: + case QFileDialog::Directory: { + QString fn = files.first(); + QModelIndex idx = model->index(fn); + if (!idx.isValid()) + idx = model->index(getEnvironmentVariable(fn)); + if (!idx.isValid() || !model->isDir(idx)) + enableButton = false; + break; + } + case QFileDialog::AnyFile: { + QString fn = files.first(); + QFileInfo info(fn); + QModelIndex idx = model->index(fn); + QString fileDir; + QString fileName; + if (info.isDir()) { + fileDir = info.canonicalFilePath(); + } else { + fileDir = fn.mid(0, fn.lastIndexOf(QLatin1Char('/'))); + fileName = fn.mid(fileDir.length() + 1); + } + if (lineEditText.contains(QLatin1String(".."))) { + fileDir = info.canonicalFilePath(); + fileName = info.fileName(); + } + + if (fileDir == q->directory().canonicalPath() && fileName.isEmpty()) { + enableButton = false; + break; + } + if (idx.isValid() && model->isDir(idx)) { + isOpenDirectory = true; + enableButton = true; + break; + } + if (!idx.isValid()) { + int maxLength = maxNameLength(fileDir); + enableButton = maxLength < 0 || fileName.length() <= maxLength; + } + break; + } + case QFileDialog::ExistingFile: + case QFileDialog::ExistingFiles: + for (int i = 0; i < files.count(); ++i) { + QModelIndex idx = model->index(files.at(i)); + if (!idx.isValid()) + idx = model->index(getEnvironmentVariable(files.at(i))); + if (!idx.isValid()) { + enableButton = false; + break; + } + if (idx.isValid() && model->isDir(idx)) { + isOpenDirectory = true; + break; + } + } + break; + default: + break; + } + } + + button->setEnabled(enableButton); + updateOkButtonText(isOpenDirectory); +} + +/*! + \internal +*/ +void QFileDialogPrivate::_q_currentChanged(const QModelIndex &index) +{ + _q_updateOkButton(); + emit q_func()->currentChanged(index.data(QFileSystemModel::FilePathRole).toString()); +} + +/*! + \internal + + This is called when the user double clicks on a file with the corresponding + model item \a index. +*/ +void QFileDialogPrivate::_q_enterDirectory(const QModelIndex &index) +{ + Q_Q(QFileDialog); + // My Computer or a directory + QModelIndex sourceIndex = index.model() == proxyModel ? mapToSource(index) : index; + QString path = sourceIndex.data(QFileSystemModel::FilePathRole).toString(); + if (path.isEmpty() || model->isDir(sourceIndex)) { + const QFileDialog::FileMode fileMode = q->fileMode(); + q->setDirectory(path); + emit q->directoryEntered(path); + if (fileMode == QFileDialog::Directory + || fileMode == QFileDialog::DirectoryOnly) { + // ### find out why you have to do both of these. + lineEdit()->setText(QString()); + lineEdit()->clear(); + } + } else { + // Do not accept when shift-clicking to multi-select a file in environments with single-click-activation (KDE) + if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) + || q->fileMode() != QFileDialog::ExistingFiles || !(QGuiApplication::keyboardModifiers() & Qt::CTRL)) { + q->accept(); + } + } +} + +/*! + \internal + + Changes the file dialog's current directory to the one specified + by \a path. +*/ +void QFileDialogPrivate::_q_goToDirectory(const QString &path) +{ + #ifndef QT_NO_MESSAGEBOX + Q_Q(QFileDialog); +#endif + QModelIndex index = qFileDialogUi->lookInCombo->model()->index(qFileDialogUi->lookInCombo->currentIndex(), + qFileDialogUi->lookInCombo->modelColumn(), + qFileDialogUi->lookInCombo->rootModelIndex()); + QString path2 = path; + if (!index.isValid()) + index = mapFromSource(model->index(getEnvironmentVariable(path))); + else { + path2 = index.data(UrlRole).toUrl().toLocalFile(); + index = mapFromSource(model->index(path2)); + } + QDir dir(path2); + if (!dir.exists()) + dir = getEnvironmentVariable(path2); + + if (dir.exists() || path2.isEmpty() || path2 == model->myComputer().toString()) { + _q_enterDirectory(index); +#ifndef QT_NO_MESSAGEBOX + } else { + QString message = QFileDialog::tr("%1\nDirectory not found.\nPlease verify the " + "correct directory name was given."); + QMessageBox::warning(q, q->windowTitle(), message.arg(path2)); +#endif // QT_NO_MESSAGEBOX + } +} + +/*! + \internal + + Sets the current name filter to be nameFilter and + update the qFileDialogUi->fileNameEdit when in AcceptSave mode with the new extension. +*/ +void QFileDialogPrivate::_q_useNameFilter(int index) +{ + QStringList nameFilters = options->nameFilters(); + if (index == nameFilters.size()) { + QAbstractItemModel *comboModel = qFileDialogUi->fileTypeCombo->model(); + nameFilters.append(comboModel->index(comboModel->rowCount() - 1, 0).data().toString()); + options->setNameFilters(nameFilters); + } + + QString nameFilter = nameFilters.at(index); + QStringList newNameFilters = QPlatformFileDialogHelper::cleanFilterList(nameFilter); + if (q_func()->acceptMode() == QFileDialog::AcceptSave) { + QString newNameFilterExtension; + if (newNameFilters.count() > 0) + newNameFilterExtension = QFileInfo(newNameFilters.at(0)).suffix(); + + QString fileName = lineEdit()->text(); + const QString fileNameExtension = QFileInfo(fileName).suffix(); + if (!fileNameExtension.isEmpty() && !newNameFilterExtension.isEmpty()) { + const int fileNameExtensionLength = fileNameExtension.count(); + fileName.replace(fileName.count() - fileNameExtensionLength, + fileNameExtensionLength, newNameFilterExtension); + qFileDialogUi->listView->clearSelection(); + lineEdit()->setText(fileName); + } + } + + model->setNameFilters(newNameFilters); +} + +/*! + \internal + + This is called when the model index corresponding to the current file is changed + from \a index to \a current. +*/ +void QFileDialogPrivate::_q_selectionChanged() +{ + const QFileDialog::FileMode fileMode = q_func()->fileMode(); + QModelIndexList indexes = qFileDialogUi->listView->selectionModel()->selectedRows(); + bool stripDirs = (fileMode != QFileDialog::DirectoryOnly && fileMode != QFileDialog::Directory); + + QStringList allFiles; + for (int i = 0; i < indexes.count(); ++i) { + if (stripDirs && model->isDir(mapToSource(indexes.at(i)))) + continue; + allFiles.append(indexes.at(i).data().toString()); + } + if (allFiles.count() > 1) + for (int i = 0; i < allFiles.count(); ++i) { + allFiles.replace(i, QString(QLatin1Char('"') + allFiles.at(i) + QLatin1Char('"'))); + } + + QString finalFiles = allFiles.join(QLatin1Char(' ')); + if (!finalFiles.isEmpty() && !lineEdit()->hasFocus() && lineEdit()->isVisible()) + lineEdit()->setText(finalFiles); + else + _q_updateOkButton(); +} + +/*! + \internal + + Includes hidden files and directories in the items displayed in the dialog. +*/ +void QFileDialogPrivate::_q_showHidden() +{ + Q_Q(QFileDialog); + QDir::Filters dirFilters = q->filter(); + if (showHiddenAction->isChecked()) + dirFilters |= QDir::Hidden; + else + dirFilters &= ~QDir::Hidden; + q->setFilter(dirFilters); +} + +/*! + \internal + + When parent is root and rows have been inserted when none was there before + then select the first one. +*/ +void QFileDialogPrivate::_q_rowsInserted(const QModelIndex &parent) +{ + if (!qFileDialogUi->treeView + || parent != qFileDialogUi->treeView->rootIndex() + || !qFileDialogUi->treeView->selectionModel() + || qFileDialogUi->treeView->selectionModel()->hasSelection() + || qFileDialogUi->treeView->model()->rowCount(parent) == 0) + return; +} + +void QFileDialogPrivate::_q_fileRenamed(const QString &path, const QString oldName, const QString newName) +{ + const QFileDialog::FileMode fileMode = q_func()->fileMode(); + if (fileMode == QFileDialog::Directory || fileMode == QFileDialog::DirectoryOnly) { + if (path == rootPath() && lineEdit()->text() == oldName) + lineEdit()->setText(newName); + } +} + +void QFileDialogPrivate::_q_nativeFileSelected(const QUrl &file) +{ + Q_Q(QFileDialog); + emit q->urlSelected(file); + if (file.isLocalFile()) + emit q->fileSelected(file.toLocalFile()); +} + +void QFileDialogPrivate::_q_nativeFilesSelected(const QList &files) +{ + Q_Q(QFileDialog); + emit q->urlsSelected(files); + QStringList localFiles; + foreach (const QUrl &file, files) + if (file.isLocalFile()) + localFiles.append(file.toLocalFile()); + if (!localFiles.isEmpty()) + emit q->filesSelected(localFiles); +} + +void QFileDialogPrivate::_q_nativeCurrentChanged(const QUrl &file) +{ + Q_Q(QFileDialog); + emit q->currentUrlChanged(file); + if (file.isLocalFile()) + emit q->currentChanged(file.toLocalFile()); +} + +void QFileDialogPrivate::_q_nativeEnterDirectory(const QUrl &directory) +{ + Q_Q(QFileDialog); + emit q->directoryUrlEntered(directory); + if (!directory.isEmpty() && directory.isLocalFile()) { // Windows native dialogs occasionally emit signals with empty strings. + *lastVisitedDir() = directory.toLocalFile(); + emit q->directoryEntered(directory.toLocalFile()); + } +} + +/*! + \internal + + For the list and tree view watch keys to goto parent and back in the history + + returns \c true if handled +*/ +bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) { + + Q_Q(QFileDialog); + switch (event->key()) { + case Qt::Key_Backspace: + _q_navigateToParent(); + return true; + case Qt::Key_Back: +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled()) + return false; +#endif + case Qt::Key_Left: + if (event->key() == Qt::Key_Back || event->modifiers() == Qt::AltModifier) { + _q_navigateBackward(); + return true; + } + break; + case Qt::Key_Escape: + q->hide(); + return true; + default: + break; + } + return false; +} + +QString QFileDialogPrivate::getEnvironmentVariable(const QString &string) +{ +#ifdef Q_OS_UNIX + if (string.size() > 1 && string.startsWith(QLatin1Char('$'))) { + return QString::fromLocal8Bit(getenv(string.mid(1).toLatin1().constData())); + } +#else + if (string.size() > 2 && string.startsWith(QLatin1Char('%')) && string.endsWith(QLatin1Char('%'))) { + return QString::fromLocal8Bit(qgetenv(string.mid(1, string.size() - 2).toLatin1().constData())); + } +#endif + return string; +} + +void QFileDialogComboBox::setFileDialogPrivate(QFileDialogPrivate *d_pointer) { + d_ptr = d_pointer; + urlModel = new QUrlModel(this); + urlModel->showFullPath = true; + urlModel->setFileSystemModel(d_ptr->model); + setModel(urlModel); +} + +void QFileDialogComboBox::showPopup() +{ + if (model()->rowCount() > 1) + QComboBox::showPopup(); + + urlModel->setUrls(QList()); + QList list; + QModelIndex idx = d_ptr->model->index(d_ptr->rootPath()); + while (idx.isValid()) { + QUrl url = QUrl::fromLocalFile(idx.data(QFileSystemModel::FilePathRole).toString()); + if (url.isValid()) + list.append(url); + idx = idx.parent(); + } + // add "my computer" + list.append(QUrl::fromLocalFile(QLatin1String(""))); + urlModel->addUrls(list, 0); + idx = model()->index(model()->rowCount() - 1, 0); + + // append history + QList urls; + for (int i = 0; i < m_history.count(); ++i) { + QUrl path = QUrl::fromLocalFile(m_history.at(i)); + if (!urls.contains(path)) + urls.prepend(path); + } + if (urls.count() > 0) { + model()->insertRow(model()->rowCount()); + idx = model()->index(model()->rowCount()-1, 0); + // ### TODO maybe add a horizontal line before this + model()->setData(idx, QFileDialog::tr("Recent Places")); + QStandardItemModel *m = qobject_cast(model()); + if (m) { + Qt::ItemFlags flags = m->flags(idx); + flags &= ~Qt::ItemIsEnabled; + m->item(idx.row(), idx.column())->setFlags(flags); + } + urlModel->addUrls(urls, -1, false); + } + setCurrentIndex(0); + + QComboBox::showPopup(); +} + +// Exact same as QComboBox::paintEvent(), except we elide the text. +void QFileDialogComboBox::paintEvent(QPaintEvent *) +{ + QStylePainter painter(this); + painter.setPen(palette().color(QPalette::Text)); + + // draw the combobox frame, focusrect and selected etc. + QStyleOptionComboBox opt; + initStyleOption(&opt); + + QRect editRect = style()->subControlRect(QStyle::CC_ComboBox, &opt, + QStyle::SC_ComboBoxEditField, this); + int size = editRect.width() - opt.iconSize.width() - 4; + opt.currentText = opt.fontMetrics.elidedText(opt.currentText, Qt::ElideMiddle, size); + painter.drawComplexControl(QStyle::CC_ComboBox, opt); + + // draw the icon and text + painter.drawControl(QStyle::CE_ComboBoxLabel, opt); +} + +QFileDialogListView::QFileDialogListView(QWidget *parent) : QListView(parent) +{ +} + +void QFileDialogListView::setFileDialogPrivate(QFileDialogPrivate *d_pointer) +{ + d_ptr = d_pointer; + setSelectionBehavior(QAbstractItemView::SelectRows); + setWrapping(true); + setResizeMode(QListView::Adjust); + setEditTriggers(QAbstractItemView::EditKeyPressed); + setContextMenuPolicy(Qt::CustomContextMenu); +#ifndef QT_NO_DRAGANDDROP + setDragDropMode(QAbstractItemView::InternalMove); +#endif +} + +QSize QFileDialogListView::sizeHint() const +{ + int height = qMax(10, sizeHintForRow(0)); + return QSize(QListView::sizeHint().width() * 2, height * 30); +} + +void QFileDialogListView::keyPressEvent(QKeyEvent *e) +{ +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) { + QListView::keyPressEvent(e); + return; + } +#endif // QT_KEYPAD_NAVIGATION + + if (!d_ptr->itemViewKeyboardEvent(e)) + QListView::keyPressEvent(e); + e->accept(); +} + +QFileDialogTreeView::QFileDialogTreeView(QWidget *parent) : QTreeView(parent) +{ +} + +void QFileDialogTreeView::setFileDialogPrivate(QFileDialogPrivate *d_pointer) +{ + d_ptr = d_pointer; + setSelectionBehavior(QAbstractItemView::SelectRows); + setRootIsDecorated(false); + setItemsExpandable(false); + setSortingEnabled(true); + header()->setSortIndicator(0, Qt::AscendingOrder); + header()->setStretchLastSection(false); + setTextElideMode(Qt::ElideMiddle); + setEditTriggers(QAbstractItemView::EditKeyPressed); + setContextMenuPolicy(Qt::CustomContextMenu); +#ifndef QT_NO_DRAGANDDROP + setDragDropMode(QAbstractItemView::InternalMove); +#endif +} + +void QFileDialogTreeView::keyPressEvent(QKeyEvent *e) +{ +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) { + QTreeView::keyPressEvent(e); + return; + } +#endif // QT_KEYPAD_NAVIGATION + + if (!d_ptr->itemViewKeyboardEvent(e)) + QTreeView::keyPressEvent(e); + e->accept(); +} + +QSize QFileDialogTreeView::sizeHint() const +{ + int height = qMax(10, sizeHintForRow(0)); + QSize sizeHint = header()->sizeHint(); + return QSize(sizeHint.width() * 4, height * 30); +} + +/*! + // FIXME: this is a hack to avoid propagating key press events + // to the dialog and from there to the "Ok" button +*/ +void QFileDialogLineEdit::keyPressEvent(QKeyEvent *e) +{ +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) { + QLineEdit::keyPressEvent(e); + return; + } +#endif // QT_KEYPAD_NAVIGATION + + int key = e->key(); + QLineEdit::keyPressEvent(e); + if (key != Qt::Key_Escape && key != Qt::Key_Back) + e->accept(); +} + +#ifndef QT_NO_FSCOMPLETER + +QString QFSCompleter::pathFromIndex(const QModelIndex &index) const +{ + const QFileSystemModel *dirModel; + if (proxyModel) + dirModel = qobject_cast(proxyModel->sourceModel()); + else + dirModel = sourceModel; + QString currentLocation = dirModel->rootPath(); + QString path = index.data(QFileSystemModel::FilePathRole).toString(); + if (!currentLocation.isEmpty() && path.startsWith(currentLocation)) { +#if defined(Q_OS_UNIX) || defined(Q_OS_WINCE) + if (currentLocation == QDir::separator()) + return path.mid(currentLocation.length()); +#endif + if (currentLocation.endsWith(QLatin1Char('/'))) + return path.mid(currentLocation.length()); + else + return path.mid(currentLocation.length()+1); + } + return index.data(QFileSystemModel::FilePathRole).toString(); +} + +QStringList QFSCompleter::splitPath(const QString &path) const +{ + if (path.isEmpty()) + return QStringList(completionPrefix()); + + QString pathCopy = QDir::toNativeSeparators(path); + QString sep = QDir::separator(); +#if defined(Q_OS_WIN) + if (pathCopy == QLatin1String("\\") || pathCopy == QLatin1String("\\\\")) + return QStringList(pathCopy); + QString doubleSlash(QLatin1String("\\\\")); + if (pathCopy.startsWith(doubleSlash)) + pathCopy = pathCopy.mid(2); + else + doubleSlash.clear(); +#elif defined(Q_OS_UNIX) + bool expanded; + pathCopy = qt_tildeExpansion(pathCopy, &expanded); + if (expanded) { + QFileSystemModel *dirModel; + if (proxyModel) + dirModel = qobject_cast(proxyModel->sourceModel()); + else + dirModel = sourceModel; + dirModel->fetchMore(dirModel->index(pathCopy)); + } +#endif + + QRegExp re(QLatin1Char('[') + QRegExp::escape(sep) + QLatin1Char(']')); + +#if defined(Q_OS_WIN) + QStringList parts = pathCopy.split(re, QString::SkipEmptyParts); + if (!doubleSlash.isEmpty() && !parts.isEmpty()) + parts[0].prepend(doubleSlash); + if (pathCopy.endsWith(sep)) + parts.append(QString()); +#else + QStringList parts = pathCopy.split(re); + if (pathCopy[0] == sep[0]) // read the "/" at the beginning as the split removed it + parts[0] = sep[0]; +#endif + +#if defined(Q_OS_WIN) + bool startsFromRoot = !parts.isEmpty() && parts[0].endsWith(QLatin1Char(':')); +#else + bool startsFromRoot = pathCopy[0] == sep[0]; +#endif + if (parts.count() == 1 || (parts.count() > 1 && !startsFromRoot)) { + const QFileSystemModel *dirModel; + if (proxyModel) + dirModel = qobject_cast(proxyModel->sourceModel()); + else + dirModel = sourceModel; + QString currentLocation = QDir::toNativeSeparators(dirModel->rootPath()); +#if defined(Q_OS_WIN) + if (currentLocation.endsWith(QLatin1Char(':'))) + currentLocation.append(sep); +#endif + if (currentLocation.contains(sep) && path != currentLocation) { + QStringList currentLocationList = splitPath(currentLocation); + while (!currentLocationList.isEmpty() + && parts.count() > 0 + && parts.at(0) == QLatin1String("..")) { + parts.removeFirst(); + currentLocationList.removeLast(); + } + if (!currentLocationList.isEmpty() && currentLocationList.last().isEmpty()) + currentLocationList.removeLast(); + return currentLocationList + parts; + } + } + return parts; +} + +#endif // QT_NO_COMPLETER + + +QT_END_NAMESPACE + +#include "moc_qfiledialog.cpp" + +#endif // QT_NO_FILEDIALOG diff --git a/Telegram/_qt_5_3_0_patch/qtbase/src/widgets/dialogs/qfiledialog.h b/Telegram/_qt_5_3_0_patch/qtbase/src/widgets/dialogs/qfiledialog.h new file mode 100644 index 000000000..eaa1e5d79 --- /dev/null +++ b/Telegram/_qt_5_3_0_patch/qtbase/src/widgets/dialogs/qfiledialog.h @@ -0,0 +1,317 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWidgets module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFILEDIALOG_H +#define QFILEDIALOG_H + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + + +#ifndef QT_NO_FILEDIALOG + +class QModelIndex; +class QItemSelection; +struct QFileDialogArgs; +class QFileIconProvider; +class QFileDialogPrivate; +class QAbstractItemDelegate; +class QAbstractProxyModel; + +class Q_WIDGETS_EXPORT QFileDialog : public QDialog +{ + Q_OBJECT + Q_ENUMS(ViewMode FileMode AcceptMode Option) + Q_FLAGS(Options) + Q_PROPERTY(ViewMode viewMode READ viewMode WRITE setViewMode) + Q_PROPERTY(FileMode fileMode READ fileMode WRITE setFileMode) + Q_PROPERTY(AcceptMode acceptMode READ acceptMode WRITE setAcceptMode) + Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly DESIGNABLE false) + Q_PROPERTY(bool resolveSymlinks READ resolveSymlinks WRITE setResolveSymlinks DESIGNABLE false) + Q_PROPERTY(bool confirmOverwrite READ confirmOverwrite WRITE setConfirmOverwrite DESIGNABLE false) + Q_PROPERTY(QString defaultSuffix READ defaultSuffix WRITE setDefaultSuffix) + Q_PROPERTY(bool nameFilterDetailsVisible READ isNameFilterDetailsVisible + WRITE setNameFilterDetailsVisible DESIGNABLE false) + Q_PROPERTY(Options options READ options WRITE setOptions) + +public: + enum ViewMode { Detail, List }; + enum FileMode { AnyFile, ExistingFile, Directory, ExistingFiles, DirectoryOnly }; + enum AcceptMode { AcceptOpen, AcceptSave }; + enum DialogLabel { LookIn, FileName, FileType, Accept, Reject }; + + enum Option + { + ShowDirsOnly = 0x00000001, + DontResolveSymlinks = 0x00000002, + DontConfirmOverwrite = 0x00000004, + DontUseSheet = 0x00000008, + DontUseNativeDialog = 0x00000010, + ReadOnly = 0x00000020, + HideNameFilterDetails = 0x00000040, + DontUseCustomDirectoryIcons = 0x00000080 + }; + Q_DECLARE_FLAGS(Options, Option) + + QFileDialog(QWidget *parent, Qt::WindowFlags f); + explicit QFileDialog(QWidget *parent = 0, + const QString &caption = QString(), + const QString &directory = QString(), + const QString &filter = QString()); + ~QFileDialog(); + + void setDirectory(const QString &directory); + inline void setDirectory(const QDir &directory); + QDir directory() const; + + void setDirectoryUrl(const QUrl &directory); + QUrl directoryUrl() const; + + void selectFile(const QString &filename); + QStringList selectedFiles() const; + QByteArray selectedRemoteContent() const; + + void selectUrl(const QUrl &url); + QList selectedUrls() const; + + void setNameFilterDetailsVisible(bool enabled); + bool isNameFilterDetailsVisible() const; + + void setNameFilter(const QString &filter); + void setNameFilters(const QStringList &filters); + QStringList nameFilters() const; + void selectNameFilter(const QString &filter); + QString selectedNameFilter() const; + + void setMimeTypeFilters(const QStringList &filters); + QStringList mimeTypeFilters() const; + void selectMimeTypeFilter(const QString &filter); + + QDir::Filters filter() const; + void setFilter(QDir::Filters filters); + + void setViewMode(ViewMode mode); + ViewMode viewMode() const; + + void setFileMode(FileMode mode); + FileMode fileMode() const; + + void setAcceptMode(AcceptMode mode); + AcceptMode acceptMode() const; + + void setReadOnly(bool enabled); + bool isReadOnly() const; + + void setResolveSymlinks(bool enabled); + bool resolveSymlinks() const; + + void setSidebarUrls(const QList &urls); + QList sidebarUrls() const; + + QByteArray saveState() const; + bool restoreState(const QByteArray &state); + + void setConfirmOverwrite(bool enabled); + bool confirmOverwrite() const; + + void setDefaultSuffix(const QString &suffix); + QString defaultSuffix() const; + + void setHistory(const QStringList &paths); + QStringList history() const; + + void setItemDelegate(QAbstractItemDelegate *delegate); + QAbstractItemDelegate *itemDelegate() const; + + void setIconProvider(QFileIconProvider *provider); + QFileIconProvider *iconProvider() const; + + void setLabelText(DialogLabel label, const QString &text); + QString labelText(DialogLabel label) const; + +#ifndef QT_NO_PROXYMODEL + void setProxyModel(QAbstractProxyModel *model); + QAbstractProxyModel *proxyModel() const; +#endif + + void setOption(Option option, bool on = true); + bool testOption(Option option) const; + void setOptions(Options options); + Options options() const; + +#ifdef Q_NO_USING_KEYWORD +#ifndef Q_QDOC + void open() { QDialog::open(); } +#endif +#else + using QDialog::open; +#endif + void open(QObject *receiver, const char *member); + void setVisible(bool visible); + +Q_SIGNALS: + void fileSelected(const QString &file); + void filesSelected(const QStringList &files); + void currentChanged(const QString &path); + void directoryEntered(const QString &directory); + + void urlSelected(const QUrl &url); + void urlsSelected(const QList &urls); + void currentUrlChanged(const QUrl &url); + void directoryUrlEntered(const QUrl &directory); + + void filterSelected(const QString &filter); + +public: + + static QString getOpenFileName(QWidget *parent = 0, + const QString &caption = QString(), + const QString &dir = QString(), + const QString &filter = QString(), + QString *selectedFilter = 0, + Options options = 0); + + static QUrl getOpenFileUrl(QWidget *parent = 0, + const QString &caption = QString(), + const QUrl &dir = QUrl(), + const QString &filter = QString(), + QString *selectedFilter = 0, + Options options = 0, + const QStringList &supportedSchemes = QStringList()); + + static QString getSaveFileName(QWidget *parent = 0, + const QString &caption = QString(), + const QString &dir = QString(), + const QString &filter = QString(), + QString *selectedFilter = 0, + Options options = 0); + + static QUrl getSaveFileUrl(QWidget *parent = 0, + const QString &caption = QString(), + const QUrl &dir = QUrl(), + const QString &filter = QString(), + QString *selectedFilter = 0, + Options options = 0, + const QStringList &supportedSchemes = QStringList()); + + static QString getExistingDirectory(QWidget *parent = 0, + const QString &caption = QString(), + const QString &dir = QString(), + Options options = ShowDirsOnly); + + static QUrl getExistingDirectoryUrl(QWidget *parent = 0, + const QString &caption = QString(), + const QUrl &dir = QUrl(), + Options options = ShowDirsOnly, + const QStringList &supportedSchemes = QStringList()); + + static QStringList getOpenFileNames(QWidget *parent = 0, + const QString &caption = QString(), + const QString &dir = QString(), + const QString &filter = QString(), + QString *selectedFilter = 0, + Options options = 0); + + static QList getOpenFileUrls(QWidget *parent = 0, + const QString &caption = QString(), + const QUrl &dir = QUrl(), + const QString &filter = QString(), + QString *selectedFilter = 0, + Options options = 0, + const QStringList &supportedSchemes = QStringList()); + + +protected: + QFileDialog(const QFileDialogArgs &args); + void done(int result); + void accept(); + void changeEvent(QEvent *e); + +private: + Q_DECLARE_PRIVATE(QFileDialog) + Q_DISABLE_COPY(QFileDialog) + + Q_PRIVATE_SLOT(d_func(), void _q_pathChanged(const QString &)) + + Q_PRIVATE_SLOT(d_func(), void _q_navigateBackward()) + Q_PRIVATE_SLOT(d_func(), void _q_navigateForward()) + Q_PRIVATE_SLOT(d_func(), void _q_navigateToParent()) + Q_PRIVATE_SLOT(d_func(), void _q_createDirectory()) + Q_PRIVATE_SLOT(d_func(), void _q_showListView()) + Q_PRIVATE_SLOT(d_func(), void _q_showDetailsView()) + Q_PRIVATE_SLOT(d_func(), void _q_showContextMenu(const QPoint &)) + Q_PRIVATE_SLOT(d_func(), void _q_renameCurrent()) + Q_PRIVATE_SLOT(d_func(), void _q_deleteCurrent()) + Q_PRIVATE_SLOT(d_func(), void _q_showHidden()) + Q_PRIVATE_SLOT(d_func(), void _q_updateOkButton()) + Q_PRIVATE_SLOT(d_func(), void _q_currentChanged(const QModelIndex &index)) + Q_PRIVATE_SLOT(d_func(), void _q_enterDirectory(const QModelIndex &index)) + Q_PRIVATE_SLOT(d_func(), void _q_nativeFileSelected(const QUrl &)) + Q_PRIVATE_SLOT(d_func(), void _q_nativeFilesSelected(const QList &)) + Q_PRIVATE_SLOT(d_func(), void _q_nativeCurrentChanged(const QUrl &)) + Q_PRIVATE_SLOT(d_func(), void _q_nativeEnterDirectory(const QUrl&)) + Q_PRIVATE_SLOT(d_func(), void _q_goToDirectory(const QString &path)) + Q_PRIVATE_SLOT(d_func(), void _q_useNameFilter(int index)) + Q_PRIVATE_SLOT(d_func(), void _q_selectionChanged()) + Q_PRIVATE_SLOT(d_func(), void _q_goToUrl(const QUrl &url)) + Q_PRIVATE_SLOT(d_func(), void _q_goHome()) + Q_PRIVATE_SLOT(d_func(), void _q_showHeader(QAction *)) + Q_PRIVATE_SLOT(d_func(), void _q_autoCompleteFileName(const QString &text)) + Q_PRIVATE_SLOT(d_func(), void _q_rowsInserted(const QModelIndex & parent)) + Q_PRIVATE_SLOT(d_func(), void _q_fileRenamed(const QString &path, + const QString oldName, const QString newName)) + friend class QPlatformDialogHelper; +}; + +inline void QFileDialog::setDirectory(const QDir &adirectory) +{ setDirectory(adirectory.absolutePath()); } + +Q_DECLARE_OPERATORS_FOR_FLAGS(QFileDialog::Options) + +#endif // QT_NO_FILEDIALOG + +QT_END_NAMESPACE + +#endif // QFILEDIALOG_H diff --git a/Telegram/_qt_5_3_0_patch/qtbase/src/widgets/dialogs/qfiledialog_p.h b/Telegram/_qt_5_3_0_patch/qtbase/src/widgets/dialogs/qfiledialog_p.h new file mode 100644 index 000000000..022b8636d --- /dev/null +++ b/Telegram/_qt_5_3_0_patch/qtbase/src/widgets/dialogs/qfiledialog_p.h @@ -0,0 +1,425 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWidgets module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFILEDIALOG_P_H +#define QFILEDIALOG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#ifndef QT_NO_FILEDIALOG + +#include "qfiledialog.h" +#include "private/qdialog_p.h" +#include "qplatformdefs.h" + +#include "qfilesystemmodel_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qsidebar_p.h" +#include "qfscompleter_p.h" + +#if defined (Q_OS_UNIX) +#include +#endif + +QT_BEGIN_NAMESPACE + +class QFileDialogListView; +class QFileDialogTreeView; +class QFileDialogLineEdit; +class QGridLayout; +class QCompleter; +class QHBoxLayout; +class Ui_QFileDialog; +class QPlatformDialogHelper; + +struct QFileDialogArgs +{ + QFileDialogArgs() : parent(0), mode(QFileDialog::AnyFile) {} + + QWidget *parent; + QString caption; + QString directory; + QString selection; + QString filter; + QFileDialog::FileMode mode; + QFileDialog::Options options; +}; + +#define UrlRole (Qt::UserRole + 1) + +class Q_WIDGETS_EXPORT QFileDialogPrivate : public QDialogPrivate +{ + Q_DECLARE_PUBLIC(QFileDialog) + +public: + QFileDialogPrivate(); + + QPlatformFileDialogHelper *platformFileDialogHelper() const + { return static_cast(platformHelper()); } + + void createToolButtons(); + void createMenuActions(); + void createWidgets(); + + void init(const QString &directory = QString(), const QString &nameFilter = QString(), + const QString &caption = QString()); + bool itemViewKeyboardEvent(QKeyEvent *event); + QString getEnvironmentVariable(const QString &string); + static QString workingDirectory(const QString &path); + static QString initialSelection(const QString &path); + QStringList typedFiles() const; + QList userSelectedFiles() const; + QByteArray userSelectedRemoteContent() const; + QStringList addDefaultSuffixToFiles(const QStringList filesToFix) const; + QList addDefaultSuffixToUrls(const QList &urlsToFix) const; + bool removeDirectory(const QString &path); + void setLabelTextControl(QFileDialog::DialogLabel label, const QString &text); + inline void updateLookInLabel(); + inline void updateFileNameLabel(); + inline void updateFileTypeLabel(); + void updateOkButtonText(bool saveAsOnFolder = false); + void updateCancelButtonText(); + + inline QModelIndex mapToSource(const QModelIndex &index) const; + inline QModelIndex mapFromSource(const QModelIndex &index) const; + inline QModelIndex rootIndex() const; + inline void setRootIndex(const QModelIndex &index) const; + inline QModelIndex select(const QModelIndex &index) const; + inline QString rootPath() const; + + QLineEdit *lineEdit() const; + + static int maxNameLength(const QString &path); + + QString basename(const QString &path) const + { + int separator = QDir::toNativeSeparators(path).lastIndexOf(QDir::separator()); + if (separator != -1) + return path.mid(separator + 1); + return path; + } + + QDir::Filters filterForMode(QDir::Filters filters) const + { + const QFileDialog::FileMode fileMode = q_func()->fileMode(); + if (fileMode == QFileDialog::DirectoryOnly) { + filters |= QDir::Drives | QDir::AllDirs | QDir::Dirs; + filters &= ~QDir::Files; + } else { + filters |= QDir::Drives | QDir::AllDirs | QDir::Files | QDir::Dirs; + } + return filters; + } + + QAbstractItemView *currentView() const; + + static inline QString toInternal(const QString &path) + { +#if defined(Q_OS_WIN) + QString n(path); + n.replace(QLatin1Char('\\'), QLatin1Char('/')); +#if defined(Q_OS_WINCE) + if ((n.size() > 1) && (n.startsWith(QLatin1String("//")))) + n = n.mid(1); +#endif + return n; +#else // the compile should optimize away this + return path; +#endif + } + + void setLastVisitedDirectory(const QString &dir); + void retranslateWindowTitle(); + void retranslateStrings(); + void emitFilesSelected(const QStringList &files); + + void _q_goHome(); + void _q_pathChanged(const QString &); + void _q_navigateBackward(); + void _q_navigateForward(); + void _q_navigateToParent(); + void _q_createDirectory(); + void _q_showListView(); + void _q_showDetailsView(); + void _q_showContextMenu(const QPoint &position); + void _q_renameCurrent(); + void _q_deleteCurrent(); + void _q_showHidden(); + void _q_showHeader(QAction *); + void _q_updateOkButton(); + void _q_currentChanged(const QModelIndex &index); + void _q_enterDirectory(const QModelIndex &index); + void _q_nativeFileSelected(const QUrl &file); + void _q_nativeFilesSelected(const QList &files); + void _q_nativeCurrentChanged(const QUrl &file); + void _q_nativeEnterDirectory(const QUrl &directory); + void _q_goToDirectory(const QString &); + void _q_useNameFilter(int index); + void _q_selectionChanged(); + void _q_goToUrl(const QUrl &url); + void _q_autoCompleteFileName(const QString &); + void _q_rowsInserted(const QModelIndex & parent); + void _q_fileRenamed(const QString &path, const QString oldName, const QString newName); + + // layout +#ifndef QT_NO_PROXYMODEL + QAbstractProxyModel *proxyModel; +#endif + + // data + QStringList watching; + QFileSystemModel *model; + +#ifndef QT_NO_FSCOMPLETER + QFSCompleter *completer; +#endif //QT_NO_FSCOMPLETER + + QString setWindowTitle; + + QStringList currentHistory; + int currentHistoryLocation; + + QAction *renameAction; + QAction *deleteAction; + QAction *showHiddenAction; + QAction *newFolderAction; + + bool useDefaultCaption; + bool defaultFileTypes; + + // setVisible_sys returns true if it ends up showing a native + // dialog. Returning false means that a non-native dialog must be + // used instead. + bool canBeNativeDialog() const; + inline bool usingWidgets() const; + + void setDirectory_sys(const QUrl &directory); + QUrl directory_sys() const; + void selectFile_sys(const QUrl &filename); + QList selectedFiles_sys() const; + QByteArray selectedRemoteContent_sys() const; + void setFilter_sys(); + void selectNameFilter_sys(const QString &filter); + QString selectedNameFilter_sys() const; + ////////////////////////////////////////////// + + QScopedPointer qFileDialogUi; + + QString acceptLabel; + + QPointer receiverToDisconnectOnClose; + QByteArray memberToDisconnectOnClose; + QByteArray signalToDisconnectOnClose; + + QSharedPointer options; + + ~QFileDialogPrivate(); + +private: + virtual void initHelper(QPlatformDialogHelper *); + virtual void helperPrepareShow(QPlatformDialogHelper *); + virtual void helperDone(QDialog::DialogCode, QPlatformDialogHelper *); + + Q_DISABLE_COPY(QFileDialogPrivate) +}; + +class QFileDialogLineEdit : public QLineEdit +{ +public: + QFileDialogLineEdit(QWidget *parent = 0) : QLineEdit(parent), d_ptr(0){} + void setFileDialogPrivate(QFileDialogPrivate *d_pointer) {d_ptr = d_pointer; } + void keyPressEvent(QKeyEvent *e); + bool hideOnEsc; +private: + QFileDialogPrivate *d_ptr; +}; + +class QFileDialogComboBox : public QComboBox +{ +public: + QFileDialogComboBox(QWidget *parent = 0) : QComboBox(parent), urlModel(0) {} + void setFileDialogPrivate(QFileDialogPrivate *d_pointer); + void showPopup(); + void setHistory(const QStringList &paths); + QStringList history() const { return m_history; } + void paintEvent(QPaintEvent *); + +private: + QUrlModel *urlModel; + QFileDialogPrivate *d_ptr; + QStringList m_history; +}; + +class QFileDialogListView : public QListView +{ +public: + QFileDialogListView(QWidget *parent = 0); + void setFileDialogPrivate(QFileDialogPrivate *d_pointer); + QSize sizeHint() const; +protected: + void keyPressEvent(QKeyEvent *e); +private: + QFileDialogPrivate *d_ptr; +}; + +class QFileDialogTreeView : public QTreeView +{ +public: + QFileDialogTreeView(QWidget *parent); + void setFileDialogPrivate(QFileDialogPrivate *d_pointer); + QSize sizeHint() const; + +protected: + void keyPressEvent(QKeyEvent *e); +private: + QFileDialogPrivate *d_ptr; +}; + +inline QModelIndex QFileDialogPrivate::mapToSource(const QModelIndex &index) const { +#ifdef QT_NO_PROXYMODEL + return index; +#else + return proxyModel ? proxyModel->mapToSource(index) : index; +#endif +} +inline QModelIndex QFileDialogPrivate::mapFromSource(const QModelIndex &index) const { +#ifdef QT_NO_PROXYMODEL + return index; +#else + return proxyModel ? proxyModel->mapFromSource(index) : index; +#endif +} + +inline QString QFileDialogPrivate::rootPath() const { + return (model ? model->rootPath() : QStringLiteral("/")); +} + +inline void QFileDialogPrivate::setDirectory_sys(const QUrl &directory) +{ + QPlatformFileDialogHelper *helper = platformFileDialogHelper(); + + if (!helper) + return; + + if (helper->isSupportedUrl(directory)) + helper->setDirectory(directory); +} + +inline QUrl QFileDialogPrivate::directory_sys() const +{ + if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) + return helper->directory(); + return QString(); +} + +inline void QFileDialogPrivate::selectFile_sys(const QUrl &filename) +{ + QPlatformFileDialogHelper *helper = platformFileDialogHelper(); + + if (!helper) + return; + + if (helper->isSupportedUrl(filename)) + helper->selectFile(filename); +} + +inline QList QFileDialogPrivate::selectedFiles_sys() const +{ + if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) + return helper->selectedFiles(); + return QList(); +} + +inline QByteArray QFileDialogPrivate::selectedRemoteContent_sys() const +{ + if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) + return helper->selectedRemoteContent(); + return QByteArray(); +} + +inline void QFileDialogPrivate::setFilter_sys() +{ + if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) + helper->setFilter(); +} + +inline void QFileDialogPrivate::selectNameFilter_sys(const QString &filter) +{ + if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) + helper->selectNameFilter(filter); +} + +inline QString QFileDialogPrivate::selectedNameFilter_sys() const +{ + if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) + return helper->selectedNameFilter(); + return QString(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_FILEDIALOG + +#endif // QFILEDIALOG_P_H diff --git a/Telegram/resource.h b/Telegram/resource.h new file mode 100644 index 000000000..351dc5e4c Binary files /dev/null and b/Telegram/resource.h differ diff --git a/Telegram/resource1.h b/Telegram/resource1.h new file mode 100644 index 000000000..fa4d7c2ea --- /dev/null +++ b/Telegram/resource1.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Updater.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/build-msvc2013.txt b/build-msvc2013.txt new file mode 100644 index 000000000..18e8ebd5e --- /dev/null +++ b/build-msvc2013.txt @@ -0,0 +1,141 @@ +Build with Visual Studio 2013, Windows 8.1 + +Prepare folder: + + Choose folder for future build, for example "D:\TBuild\". + There you will have two folders, "Libraries" for third-party libs and "tdesktop" for the app. + +Clone sources: + + - By git: in Git Bash go to "/d/tbuild" and run "git clone https://github.com/telegramdesktop/tdesktop.git" + - Or download in ZIP and extract to "D:\TBuild\", rename "tdesktop-master" to "tdesktop" to have "D:\TBuild\tdesktop\Telegram.sln" solution + +Prepare libraries: + +OpenSSL (1.0.1g) + + https://www.openssl.org/related/binaries.html > "OpenSSL for Windows" > "Win32 OpenSSL v1.0.1g" (16 Mb) + - Install to "D:\TBuild\Libraries\OpenSSL-Win32", while installing "Copy OpenSSL DLLs to" choose "The OpenSSL binaries (/bin) directory" + +LZMA (9.20) + + http://www.7-zip.org/sdk.html > Download 9.20 "LZMA SDK (C, C++, C#, Java)" + - Extract to "D:\TBuild\Libraries\lzma\" + + Building Lib: + + - Open "D:\TBuild\Libraries\lzma\C\Util\LzmaLib\LzmaLib.dsw" with Visual Studio 2013 > One-way upgrade OK + - For Debug and Release configurations: + - LzmaLib Properties > General > Configuration Type = "Static library (.lib)" > OK + - LzmaLib Properties > Librarian > General > Target Machine = "MachineX86 (/MACHINE:X86)" > OK + - Build Debug + - Build Release + +zlib (1.2.8) + + http://www.zlib.net/ > "zlib source code, version 1.2.8, zipfile format" > http://zlib.net/zlib128.zip + - Extract to "D:\TBuild\Libraries\" + + Building Lib: + - Open "D:\TBuild\Libraries\zlib-1.2.8\contrib\vstudio\vc11\zlibvc.sln" > Upgrade .. > OK + - We are interested in only "zlibstat" project, but it depends on some custom pre-build step + - For Debug configuration: + - zlibstat Properties > C/C++ > Code Generation > Runtime Library = "Multi-threaded Debug (/MTd)" > OK + - For Release configuration: + - zlibstat Properties > C/C++ > Code Generation > Runtime Library = "Multi-threaded (/MT)" > OK + - Build Solution for Debug - only "zlibstat" project build successfully, and we need only it + - Build Solution for Release - only "zlibstat" project build successfully, and we need only it + +libexif (0.6.20) - prepared + + https://github.com/telegramdesktop/libexif-0.6.20 + - By git: in Git Bash go to "/d/tbuild/libraries" and run "git clone https://github.com/telegramdesktop/libexif-0.6.20.git" + - Or download in ZIP and extract to "D:\TBuild\Libraries\", rename "libexif-0.6.20-master" to "libexif-0.6.20" to have "D:\TBuild\Libraries\libexif-0.6.20\win32\lib_exif.sln" solution + + Building Lib: + - Open "D:\TBuild\Libraries\libexif-0.6.20\win32\lib_exif.sln" + - Build Debug + - Build Release + +Qt (5.3.0) + + http://download.qt-project.org/official_releases/qt/5.3/5.3.0/single/qt-everywhere-opensource-src-5.3.0.zip + - Extract to "D:\TBuild\Libraries\Tmp\" + - Copy everything from "D:\TBuild\Libraries\Tmp\qt-everywhere-opensource-src-5.3.0" to "D:\TBuild\Libraries\QtStatic" + - Copy (with overwrite) everything from "D:\TBuild\tdesktop\_qt_5_3_0_patch" to "D:\TBuild\Libraries\QtStatic" + + Building Lib: + + - Install Python (3.3.2) from https://www.python.org/download/releases/3.3.2 > "Windows x86 MSI Installer (3.3.2)" (https://www.python.org/ftp/python/3.3.2/python-3.3.2.msi) + - Open "VS2013 x86 Native Tools Command Prompt.bat" (should be in "\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\Shortcuts") + + Go to Qt directory ("D:" > Enter > "cd TBuild\Libraries\QtStatic" > Enter) and run "configure -debug-and-release -opensource -static -opengl desktop -mp -nomake examples -platform win32-msvc2013", then "y" (accept), after configuration is complete run "nmake" and then "nmake install", nmake will take really long time. + +Qt Visual Studio Addin 1.2.3 + + http://download.qt-project.org/official_releases/vsaddin/qt-vs-addin-1.2.3-opensource.exe + - Install to default location + +Building Telegram Desktop: + + - Launch Microsoft Visual Studio 2013 + - QT5 > Qt Options > Add: + Version name: QtStatic.5.3.0 + Path: D:\TBuild\Libraries\QtStatic\qtbase + - Default Qt/Win version: QtStatic.5.3.0 > OK + - File > Open > Project/Solution > D:\TBuild\tdesktop\Telegram.sln + - Build > Build Solution + +Projects in Telegram solution: + + Telegram: + tdesktop messenger + + Updater: + little app, that is launched by Telegram when update is ready, replaces all files and launches it back + + Packer: + compiles given files to single update file, compresses it with lzma and signs with a private key, + it was not included to Telegram solution, because private key is inaccessible + + Prepare: + prepares a release for deployment: puts all files to deploy/{version} folder + current tsetup{version}exe installer + current Telegram.exe + current Telegram.pdb (debug info for crash minidumps view) + current tupdate{updversion} binary lzma update archive + + MetaEmoji: + from two folders + SourceFiles/art/Emoji + SourceFiles/art/Emoji_200x + and some inner config creates four sprites and text2emoji replace code: + SourceFiles/art/emoji.png + SourceFiles/art/emoji_125x.png + SourceFiles/art/emoji_150x.png + SourceFiles/art/emoji_200x.png + SourceFiles/gui/emoji_config.cpp + + MetaStyle: + from two files and two sprites + Resources/style_classes.txt + Resources/style.txt + SourceFiles/art/sprite.png + SourceFiles/art/sprite_200x.png + creates two other sprites, four sprite grids and style constants code: + SourceFiles/art/sprite_125x.png + SourceFiles/art/sprite_150x.png + SourceFiles/art/grid.png + SourceFiles/art/grid_125x.png + Sourcefiles/art/grid_150x.png + SourceFiles/art/grid_200x.png + GeneratedFiles/style_classes.h + GeneratedFiles/style_auto.h + GeneratedFiles/style_auto.cpp + + MetaLang: + from langpack file + Resources/lang.txt + creates lang constants code and lang file parse code: + GeneratedFiles/lang.h + GeneratedFiles/lang.cpp