diff --git a/CMakeLists.txt b/CMakeLists.txt index e974b388..6209cb33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # Project cmake_minimum_required(VERSION 3.16 FATAL_ERROR) # 3.1 is ok, but is 3.16 needed for proper version string -project(nchat VERSION 2.15 LANGUAGES CXX) +project(nchat VERSION 2.16 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 14) include(CheckCXXSourceCompiles) set(NCHAT_PROJECT_VERSION ${PROJECT_VERSION}) diff --git a/lib/tgchat/ext/td/.clang-format b/lib/tgchat/ext/td/.clang-format index 78d519b5..6ce3c0d6 100644 --- a/lib/tgchat/ext/td/.clang-format +++ b/lib/tgchat/ext/td/.clang-format @@ -92,7 +92,7 @@ PenaltyBreakString: 1000 PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 -PointerAlignment: Left +PointerAlignment: Right ReflowComments: false # true SortIncludes: false # disabled, because we need case insensitive sort SortUsingDeclarations: false # true diff --git a/lib/tgchat/ext/td/.gitattributes b/lib/tgchat/ext/td/.gitattributes index 2d04f9b7..06e5328a 100644 --- a/lib/tgchat/ext/td/.gitattributes +++ b/lib/tgchat/ext/td/.gitattributes @@ -5,6 +5,7 @@ *.h text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.c text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.tl text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent +*.mm text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.txt text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.sh text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent eol=lf *.php text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent @@ -18,6 +19,7 @@ *.java text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.py text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.js text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent +*.patch text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.swift text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.pbxproj text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.cs text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent @@ -32,7 +34,5 @@ sqlite/sqlite/* linguist-vendored -*.tlo binary - *.pfx binary *.png binary diff --git a/lib/tgchat/ext/td/CMake/TdSetUpCompiler.cmake b/lib/tgchat/ext/td/CMake/TdSetUpCompiler.cmake index 11a681c1..62013f52 100644 --- a/lib/tgchat/ext/td/CMake/TdSetUpCompiler.cmake +++ b/lib/tgchat/ext/td/CMake/TdSetUpCompiler.cmake @@ -5,6 +5,8 @@ function(td_set_up_compiler) set(CMAKE_POSITION_INDEPENDENT_CODE ON PARENT_SCOPE) + include(illumos) + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(GCC 1) set(GCC 1 PARENT_SCOPE) @@ -40,11 +42,6 @@ function(td_set_up_compiler) message(FATAL_ERROR "No C++14 support in the compiler. Please upgrade the compiler.") endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") - if (MSVC) if (CMAKE_CXX_FLAGS_DEBUG MATCHES "/RTC1") string(REPLACE "/RTC1" " " CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") @@ -54,12 +51,21 @@ function(td_set_up_compiler) elseif (CLANG OR GCC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${STD14_FLAG} -fno-omit-frame-pointer -fno-exceptions -fno-rtti") if (APPLE) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-dead_strip,-x,-S") + set(TD_LINKER_FLAGS "-Wl,-dead_strip") + if (NOT CMAKE_BUILD_TYPE MATCHES "Deb") + set(TD_LINKER_FLAGS "${TD_LINKER_FLAGS},-x,-S") + endif() else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections -Wl,--exclude-libs,ALL") + if (CMAKE_SYSTEM_NAME STREQUAL "SunOS") + set(TD_LINKER_FLAGS "-Wl,-z,ignore") + else() + set(TD_LINKER_FLAGS "-Wl,--gc-sections -Wl,--exclude-libs,ALL") + endif() endif() + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${TD_LINKER_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${TD_LINKER_FLAGS}") if (WIN32 OR CYGWIN) if (GCC) @@ -81,6 +87,13 @@ function(td_set_up_compiler) add_definitions(-D_FILE_OFFSET_BITS=64) endif() + if (CMAKE_SYSTEM_NAME STREQUAL "SunOS") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lsocket -lnsl") + if (ILLUMOS) + add_definitions(-DTD_ILLUMOS=1) + endif() + endif() + include(AddCXXCompilerFlag) if (NOT MSVC) add_cxx_compiler_flag("-Wall") @@ -121,6 +134,10 @@ function(td_set_up_compiler) if (GCC AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)) add_cxx_compiler_flag("-Wno-maybe-uninitialized") # too much false positives endif() + if (WIN32 AND GCC AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)) + # warns about casts of function pointers returned by GetProcAddress + add_cxx_compiler_flag("-Wno-cast-function-type") + endif() if (GCC AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)) # warns about a lot of "return std::move", which are not redundant for compilers without fix for DR 1579, i.e. GCC 4.9 or clang 3.8 # see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1579 @@ -141,5 +158,6 @@ function(td_set_up_compiler) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}" PARENT_SCOPE) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}" PARENT_SCOPE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}" PARENT_SCOPE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" PARENT_SCOPE) endfunction() diff --git a/lib/tgchat/ext/td/CMake/iOS.cmake b/lib/tgchat/ext/td/CMake/iOS.cmake index 70f611d5..2b488c02 100644 --- a/lib/tgchat/ext/td/CMake/iOS.cmake +++ b/lib/tgchat/ext/td/CMake/iOS.cmake @@ -48,9 +48,9 @@ endif (CMAKE_UNAME) # Force the compilers to gcc for iOS set (CMAKE_C_COMPILER /usr/bin/gcc) set (CMAKE_CXX_COMPILER /usr/bin/g++) -set(CMAKE_AR ar CACHE FILEPATH "" FORCE) -set(CMAKE_RANLIB ranlib CACHE FILEPATH "" FORCE) -set(PKG_CONFIG_EXECUTABLE pkg-config CACHE FILEPATH "" FORCE) +set (CMAKE_AR ar CACHE FILEPATH "" FORCE) +set (CMAKE_RANLIB ranlib CACHE FILEPATH "" FORCE) +set (PKG_CONFIG_EXECUTABLE pkg-config CACHE FILEPATH "" FORCE) # Setup iOS platform unless specified manually with IOS_PLATFORM if (NOT DEFINED IOS_PLATFORM) @@ -195,15 +195,15 @@ set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS su if (IOS_PLATFORM STREQUAL "OS") set (IOS_ARCH "armv7;armv7s;arm64") elseif (IOS_PLATFORM STREQUAL "SIMULATOR") - set (IOS_ARCH "i386;x86_64") + set (IOS_ARCH "i386;x86_64;arm64") elseif (IOS_PLATFORM STREQUAL "WATCHOS") - set (IOS_ARCH "armv7k") + set (IOS_ARCH "armv7k;arm64_32") elseif (IOS_PLATFORM STREQUAL "WATCHSIMULATOR") - set (IOS_ARCH "i386") + set (IOS_ARCH "i386;x86_64;arm64") elseif (IOS_PLATFORM STREQUAL "TVOS") set (IOS_ARCH "arm64") elseif (IOS_PLATFORM STREQUAL "TVSIMULATOR") - set (IOS_ARCH "x86_64") + set (IOS_ARCH "x86_64;arm64") else() message (WARNING "Unknown IOS_PLATFORM=<${IOS_PLATFORM}>") endif() diff --git a/lib/tgchat/ext/td/CMake/illumos.cmake b/lib/tgchat/ext/td/CMake/illumos.cmake new file mode 100644 index 00000000..70583d1a --- /dev/null +++ b/lib/tgchat/ext/td/CMake/illumos.cmake @@ -0,0 +1,10 @@ +if (CMAKE_SYSTEM_NAME STREQUAL "SunOS") + # + # Determine if the host is running an illumos distribution: + # + execute_process(COMMAND /usr/bin/uname -o OUTPUT_VARIABLE UNAME_O OUTPUT_STRIP_TRAILING_WHITESPACE) + + if (UNAME_O STREQUAL "illumos") + set(ILLUMOS 1) + endif() +endif() diff --git a/lib/tgchat/ext/td/CMakeLists.txt b/lib/tgchat/ext/td/CMakeLists.txt index 91943754..75af8ae3 100644 --- a/lib/tgchat/ext/td/CMakeLists.txt +++ b/lib/tgchat/ext/td/CMakeLists.txt @@ -1,6 +1,12 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) -project(TDLib VERSION 1.7.0 LANGUAGES CXX C) +if (POLICY CMP0065) + # do not export symbols from executables + # affects compiler checks in project(), so must be set before it + cmake_policy(SET CMP0065 NEW) +endif() + +project(TDLib VERSION 1.7.9 LANGUAGES CXX C) if (NOT DEFINED CMAKE_MODULE_PATH) set(CMAKE_MODULE_PATH "") @@ -25,6 +31,10 @@ if (POLICY CMP0060) # link libraries by full path cmake_policy(SET CMP0060 NEW) endif() +if (POLICY CMP0074) + # use environment variables to find libraries + cmake_policy(SET CMP0074 NEW) +endif() include(PreventInSourceBuild) prevent_in_source_build() @@ -49,15 +59,15 @@ if (POLICY CMP0069) # set_property(DIRECTORY PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) do not work? string(REPLACE ";" " " CXX_FLAGS_IPO "${CMAKE_CXX_COMPILE_OPTIONS_IPO}") message(STATUS "Use link time optimization CXX options: ${CXX_FLAGS_IPO}") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${CXX_FLAGS_IPO}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_IPO}") string(REPLACE ";" " " C_FLAGS_IPO "${CMAKE_C_COMPILE_OPTIONS_IPO}") message(STATUS "Use link time optimization C options: ${C_FLAGS_IPO}") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${C_FLAGS_IPO}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_FLAGS_IPO}") string(REPLACE ";" " " LINK_FLAGS_IPO "${CMAKE_CXX_LINK_OPTIONS_IPO}") message(STATUS "Use link time optimization linker options: ${LINK_FLAGS_IPO}") - set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_FLAGS_IPO}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINK_FLAGS_IPO}") endif() endif() endif() @@ -197,7 +207,6 @@ endif() get_directory_property(HAS_PARENT PARENT_DIRECTORY) if (HAS_PARENT) - set(TL_TD_API_TLO ${TL_TD_API_TLO} PARENT_SCOPE) # was used in standalone binding generators set(TL_TD_JSON_AUTO ${TL_TD_JSON_AUTO_SOURCE} PARENT_SCOPE) # used in tdbot set(TD_TEST_SOURCE ${TD_TEST_SOURCE} PARENT_SCOPE) # used to build tests endif() @@ -248,6 +257,7 @@ set(TL_DOTNET_SCHEME_SOURCE set(TDLIB_SOURCE td/mtproto/AuthData.cpp + td/mtproto/ConnectionManager.cpp td/mtproto/DhHandshake.cpp td/mtproto/Handshake.cpp td/mtproto/HandshakeActor.cpp @@ -266,12 +276,15 @@ set(TDLIB_SOURCE td/mtproto/Transport.cpp td/mtproto/utils.cpp + td/telegram/Account.cpp td/telegram/AnimationsManager.cpp td/telegram/AudiosManager.cpp td/telegram/AuthManager.cpp td/telegram/AutoDownloadSettings.cpp td/telegram/BackgroundManager.cpp td/telegram/BackgroundType.cpp + td/telegram/BotCommand.cpp + td/telegram/BotCommandScope.cpp td/telegram/CallActor.cpp td/telegram/CallDiscardReason.cpp td/telegram/CallManager.cpp @@ -279,6 +292,7 @@ set(TDLIB_SOURCE td/telegram/ClientActor.cpp td/telegram/ConfigManager.cpp td/telegram/ConfigShared.cpp + td/telegram/ConnectionState.cpp td/telegram/Contact.cpp td/telegram/ContactsManager.cpp td/telegram/CountryInfoManager.cpp @@ -287,10 +301,13 @@ set(TDLIB_SOURCE td/telegram/DeviceTokenManager.cpp td/telegram/DhCache.cpp td/telegram/DialogAction.cpp + td/telegram/DialogActionBar.cpp td/telegram/DialogAdministrator.cpp td/telegram/DialogDb.cpp + td/telegram/DialogEventLog.cpp td/telegram/DialogFilter.cpp td/telegram/DialogId.cpp + td/telegram/DialogInviteLink.cpp td/telegram/DialogLocation.cpp td/telegram/DialogParticipant.cpp td/telegram/DialogSource.cpp @@ -318,13 +335,20 @@ set(TDLIB_SOURCE td/telegram/files/PartsManager.cpp td/telegram/files/ResourceManager.cpp td/telegram/Game.cpp + td/telegram/GameManager.cpp td/telegram/Global.cpp + td/telegram/GroupCallManager.cpp + td/telegram/GroupCallParticipant.cpp + td/telegram/GroupCallParticipantOrder.cpp + td/telegram/GroupCallVideoPayload.cpp td/telegram/HashtagHints.cpp td/telegram/InlineQueriesManager.cpp td/telegram/InputDialogId.cpp + td/telegram/InputGroupCallId.cpp td/telegram/InputMessageText.cpp td/telegram/JsonValue.cpp td/telegram/LanguagePackManager.cpp + td/telegram/LinkManager.cpp td/telegram/Location.cpp td/telegram/logevent/LogEventHelper.cpp td/telegram/Logging.cpp @@ -335,7 +359,9 @@ set(TDLIB_SOURCE td/telegram/MessageReplyInfo.cpp td/telegram/MessagesDb.cpp td/telegram/MessageSearchFilter.cpp + td/telegram/MessageSender.cpp td/telegram/MessagesManager.cpp + td/telegram/MessageTtlSetting.cpp td/telegram/misc.cpp td/telegram/net/AuthDataShared.cpp td/telegram/net/ConnectionCreator.cpp @@ -355,6 +381,7 @@ set(TDLIB_SOURCE td/telegram/net/Session.cpp td/telegram/net/SessionProxy.cpp td/telegram/net/SessionMultiProxy.cpp + td/telegram/NewPasswordState.cpp td/telegram/NotificationManager.cpp td/telegram/NotificationSettings.cpp td/telegram/NotificationType.cpp @@ -366,7 +393,9 @@ set(TDLIB_SOURCE td/telegram/PhotoSizeSource.cpp td/telegram/PollManager.cpp td/telegram/QueryCombiner.cpp + td/telegram/RecentDialogList.cpp td/telegram/ReplyMarkup.cpp + td/telegram/ReportReason.cpp td/telegram/RestrictionReason.cpp td/telegram/SecretChatActor.cpp td/telegram/SecretChatDb.cpp @@ -377,6 +406,7 @@ set(TDLIB_SOURCE td/telegram/SendCodeHelper.cpp td/telegram/SequenceDispatcher.cpp td/telegram/SpecialStickerSetType.cpp + td/telegram/SponsoredMessageManager.cpp td/telegram/StateManager.cpp td/telegram/StickersManager.cpp td/telegram/StorageManager.cpp @@ -384,6 +414,8 @@ set(TDLIB_SOURCE td/telegram/Td.cpp td/telegram/TdDb.cpp td/telegram/TermsOfService.cpp + td/telegram/ThemeManager.cpp + td/telegram/TopDialogCategory.cpp td/telegram/TopDialogManager.cpp td/telegram/UpdatesManager.cpp td/telegram/Venue.cpp @@ -395,7 +427,9 @@ set(TDLIB_SOURCE td/mtproto/AuthData.h td/mtproto/AuthKey.h + td/mtproto/ConnectionManager.h td/mtproto/CryptoStorer.h + td/mtproto/DhCallback.h td/mtproto/DhHandshake.h td/mtproto/Handshake.h td/mtproto/HandshakeActor.h @@ -403,13 +437,13 @@ set(TDLIB_SOURCE td/mtproto/HttpTransport.h td/mtproto/IStreamTransport.h td/mtproto/KDF.h + td/mtproto/MtprotoQuery.h td/mtproto/NoCryptoStorer.h td/mtproto/PacketInfo.h td/mtproto/PacketStorer.h td/mtproto/Ping.h td/mtproto/PingConnection.h td/mtproto/ProxySecret.h - td/mtproto/Query.h td/mtproto/RawConnection.h td/mtproto/RSA.h td/mtproto/SessionConnection.h @@ -421,6 +455,8 @@ set(TDLIB_SOURCE td/mtproto/utils.h td/telegram/AccessRights.h + td/telegram/Account.h + td/telegram/AffectedHistory.h td/telegram/AnimationsManager.h td/telegram/AudiosManager.h td/telegram/AuthManager.h @@ -428,6 +464,8 @@ set(TDLIB_SOURCE td/telegram/BackgroundId.h td/telegram/BackgroundManager.h td/telegram/BackgroundType.h + td/telegram/BotCommand.h + td/telegram/BotCommandScope.h td/telegram/CallActor.h td/telegram/CallDiscardReason.h td/telegram/CallId.h @@ -438,6 +476,7 @@ set(TDLIB_SOURCE td/telegram/ClientActor.h td/telegram/ConfigManager.h td/telegram/ConfigShared.h + td/telegram/ConnectionState.h td/telegram/Contact.h td/telegram/ContactsManager.h td/telegram/CountryInfoManager.h @@ -447,12 +486,15 @@ set(TDLIB_SOURCE td/telegram/DhCache.h td/telegram/DhConfig.h td/telegram/DialogAction.h + td/telegram/DialogActionBar.h td/telegram/DialogAdministrator.h td/telegram/DialogDate.h td/telegram/DialogDb.h + td/telegram/DialogEventLog.h td/telegram/DialogFilter.h td/telegram/DialogFilterId.h td/telegram/DialogId.h + td/telegram/DialogInviteLink.h td/telegram/DialogListId.h td/telegram/DialogLocation.h td/telegram/DialogParticipant.h @@ -460,6 +502,7 @@ set(TDLIB_SOURCE td/telegram/Document.h td/telegram/DocumentsManager.h td/telegram/DraftMessage.h + td/telegram/EncryptedFile.h td/telegram/FileReferenceManager.h td/telegram/files/FileBitmask.h td/telegram/files/FileData.h @@ -490,13 +533,21 @@ set(TDLIB_SOURCE td/telegram/FolderId.h td/telegram/FullMessageId.h td/telegram/Game.h + td/telegram/GameManager.h td/telegram/Global.h + td/telegram/GroupCallId.h + td/telegram/GroupCallManager.h + td/telegram/GroupCallParticipant.h + td/telegram/GroupCallParticipantOrder.h + td/telegram/GroupCallVideoPayload.h td/telegram/HashtagHints.h td/telegram/InlineQueriesManager.h td/telegram/InputDialogId.h + td/telegram/InputGroupCallId.h td/telegram/InputMessageText.h td/telegram/JsonValue.h td/telegram/LanguagePackManager.h + td/telegram/LinkManager.h td/telegram/Location.h td/telegram/logevent/LogEvent.h td/telegram/logevent/LogEventHelper.h @@ -507,10 +558,14 @@ set(TDLIB_SOURCE td/telegram/MessageCopyOptions.h td/telegram/MessageEntity.h td/telegram/MessageId.h + td/telegram/MessageLinkInfo.h td/telegram/MessageReplyInfo.h + td/telegram/MessageThreadInfo.h td/telegram/MessagesDb.h td/telegram/MessageSearchFilter.h + td/telegram/MessageSender.h td/telegram/MessagesManager.h + td/telegram/MessageTtlSetting.h td/telegram/misc.h td/telegram/net/AuthDataShared.h td/telegram/net/ConnectionCreator.h @@ -535,6 +590,7 @@ set(TDLIB_SOURCE td/telegram/net/SessionProxy.h td/telegram/net/SessionMultiProxy.h td/telegram/net/TempAuthKeyWatchdog.h + td/telegram/NewPasswordState.h td/telegram/Notification.h td/telegram/NotificationGroupId.h td/telegram/NotificationGroupKey.h @@ -554,13 +610,16 @@ set(TDLIB_SOURCE td/telegram/PtsManager.h td/telegram/PublicDialogType.h td/telegram/QueryCombiner.h + td/telegram/RecentDialogList.h td/telegram/ReplyMarkup.h + td/telegram/ReportReason.h td/telegram/RequestActor.h td/telegram/RestrictionReason.h td/telegram/ScheduledServerMessageId.h td/telegram/SecretChatActor.h td/telegram/SecretChatId.h td/telegram/SecretChatDb.h + td/telegram/SecretChatLayer.h td/telegram/SecretChatsManager.h td/telegram/SecretInputMedia.h td/telegram/SecureManager.h @@ -571,6 +630,7 @@ set(TDLIB_SOURCE td/telegram/ServerMessageId.h td/telegram/SetWithPosition.h td/telegram/SpecialStickerSetType.h + td/telegram/SponsoredMessageManager.h td/telegram/StateManager.h td/telegram/StickerSetId.h td/telegram/StickersManager.h @@ -581,6 +641,7 @@ set(TDLIB_SOURCE td/telegram/TdDb.h td/telegram/TdParameters.h td/telegram/TermsOfService.h + td/telegram/ThemeManager.h td/telegram/TopDialogCategory.h td/telegram/TopDialogManager.h td/telegram/UniqueId.h @@ -668,7 +729,7 @@ if (MEMPROF) endif() -add_library(tdapi STATIC ${TL_TD_API_SOURCE}) +add_library(tdapi ${TL_TD_API_SOURCE}) target_include_directories(tdapi PUBLIC $ INTERFACE $) target_link_libraries(tdapi PRIVATE tdutils) @@ -903,4 +964,5 @@ install(FILES "TdConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/TdConfigVersion.cmak # Add SOVERSION to shared libraries set_property(TARGET tdclient PROPERTY SOVERSION "${TDLib_VERSION}") +set_property(TARGET tdapi PROPERTY SOVERSION "${TDLib_VERSION}") set_property(TARGET tdjson PROPERTY SOVERSION "${TDLib_VERSION}") diff --git a/lib/tgchat/ext/td/README.md b/lib/tgchat/ext/td/README.md index ca683dc2..46902f44 100644 --- a/lib/tgchat/ext/td/README.md +++ b/lib/tgchat/ext/td/README.md @@ -7,7 +7,6 @@ TDLib (Telegram Database library) is a cross-platform library for building [Tele - [Examples and documentation](#usage) - [Dependencies](#dependencies) - [Building](#building) -- [Installing dependencies](#installing-dependencies) - [Using in CMake C++ projects](#using-cxx) - [Using in Java projects](#using-java) - [Using in .NET projects](#using-dotnet) @@ -19,7 +18,7 @@ TDLib (Telegram Database library) is a cross-platform library for building [Tele `TDLib` has many advantages. Notably `TDLib` is: -* **Cross-platform**: `TDLib` can be used on Android, iOS, Windows, macOS, Linux, FreeBSD, OpenBSD, NetBSD, Windows Phone, WebAssembly, watchOS, tvOS, Tizen, Cygwin. It should also work on other *nix systems with or without minimal effort. +* **Cross-platform**: `TDLib` can be used on Android, iOS, Windows, macOS, Linux, FreeBSD, OpenBSD, NetBSD, illumos, Windows Phone, WebAssembly, watchOS, tvOS, Tizen, Cygwin. It should also work on other *nix systems with or without minimal effort. * **Multilanguage**: `TDLib` can be easily used with any programming language that is able to execute C functions. Additionally it already has native Java (using `JNI`) bindings and .NET (using `C++/CLI` and `C++/CX`) bindings. * **Easy to use**: `TDLib` takes care of all network implementation details, encryption and local data storage. * **High-performance**: in the [Telegram Bot API](https://core.telegram.org/bots/api), each `TDLib` instance handles more than 24000 active bots simultaneously. @@ -59,8 +58,7 @@ for a list of all available `TDLib` [methods](https://core.telegram.org/tdlib/do The simplest way to build `TDLib` is to use our [TDLib build instructions generator](https://tdlib.github.io/td/build.html). You need only to choose your programming language and target operating system to receive complete build instructions. -In general, you need to install all `TDLib` [dependencies](#dependencies) as described in [Installing dependencies](#installing-dependencies). -Then enter directory containing `TDLib` sources and compile them using CMake: +In general, you need to install all `TDLib` [dependencies](#dependencies), enter directory containing `TDLib` sources and compile them using CMake: ``` mkdir build @@ -86,44 +84,6 @@ php SplitSource.php --undo ``` In our tests clang 6.0 with libc++ required less than 500 MB of RAM per file and GCC 4.9/6.3 used less than 1 GB of RAM per file. - -### Installing dependencies - - -#### macOS -* Install the latest Xcode command line tools, for example, via `xcode-select --install`. -* Install other [dependencies](#dependencies), for example, using [Homebrew](https://brew.sh): -``` -brew install gperf cmake openssl -``` -* Build `TDLib` with CMake as explained in [building](#building). You will likely need to manually specify path to the installed OpenSSL to CMake, e.g., -``` -cmake -DCMAKE_BUILD_TYPE=Release -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl/ .. -``` - - -#### Windows -* Download and install Microsoft Visual Studio 2015 or later. -* Download and install [gperf](https://sourceforge.net/projects/gnuwin32/files/gperf/3.0.1/). Add the path to gperf.exe to the PATH environment variable. -* Install [vcpkg](https://github.com/Microsoft/vcpkg#quick-start). -* Run the following commands to install `TDLib` dependencies using vcpkg: -``` -cd -.\vcpkg.exe install openssl:x64-windows openssl:x86-windows zlib:x64-windows zlib:x86-windows -``` -* Download and install [CMake](https://cmake.org/download/); choose "Add CMake to the system PATH" option while installing. -* Build `TDLib` with CMake as explained in [building](#building), but instead of `cmake -DCMAKE_BUILD_TYPE=Release ..` use -``` -cmake -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake .. -``` - -To build 32-bit/64-bit `TDLib` using MSVC, you will need to additionally specify parameter `-A Win32`/`-A x64` to CMake. -To build `TDLib` in Release mode using MSVC, you will need to additionally specify parameter `--config Release` to the `cmake --build .` command. - - -#### Linux -* Install all [dependencies](#dependencies) using your package manager. - ## Using in CMake C++ projects For C++ projects that use CMake, the best approach is to build `TDLib` as part of your project or to install it system-wide. @@ -131,11 +91,9 @@ For C++ projects that use CMake, the best approach is to build `TDLib` as part o There are several libraries that you could use in your CMake project: * Td::TdJson, Td::TdJsonStatic — dynamic and static version of a JSON interface. This has a simple C interface, so it can be easily used with any programming language that is able to execute C functions. - See [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html) and [td_log](https://core.telegram.org/tdlib/docs/td__log_8h.html) documentation for more information. + See [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html) documentation for more information. * Td::TdStatic — static library with C++ interface for general usage. - See [Client](https://core.telegram.org/tdlib/docs/classtd_1_1_client.html) and [Log](https://core.telegram.org/tdlib/docs/classtd_1_1_log.html) documentation for more information. -* Td::TdCoreStatic — static library with low-level C++ interface intended mostly for internal usage. - See [ClientActor](https://core.telegram.org/tdlib/docs/classtd_1_1_client_actor.html) and [Log](https://core.telegram.org/tdlib/docs/classtd_1_1_log.html) documentation for more information. + See [ClientManager](https://core.telegram.org/tdlib/docs/classtd_1_1_client_manager.html) and [Client](https://core.telegram.org/tdlib/docs/classtd_1_1_client.html) documentation for more information. For example, part of your CMakeLists.txt may look like this: ``` @@ -145,7 +103,7 @@ target_link_libraries(YourTarget PRIVATE Td::TdStatic) Or you could install `TDLib` and then reference it in your CMakeLists.txt like this: ``` -find_package(Td 1.7.0 REQUIRED) +find_package(Td 1.7.9 REQUIRED) target_link_libraries(YourTarget PRIVATE Td::TdStatic) ``` See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/tree/master/example/cpp/CMakeLists.txt). @@ -173,7 +131,7 @@ git checkout td/telegram/Client.h td/telegram/Log.h td/tl/TlObject.h ## Using from other programming languages `TDLib` provides efficient native C++, Java, and .NET interfaces. But for most use cases we suggest to use the JSON interface, which can be easily used with any programming language that is able to execute C functions. -See [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html) and [td_log](https://core.telegram.org/tdlib/docs/td__log_8h.html) documentation for detailed JSON interface description, +See [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html) documentation for detailed JSON interface description, the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of all available `TDLib` [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html). diff --git a/lib/tgchat/ext/td/SplitSource.php b/lib/tgchat/ext/td/SplitSource.php index 605ee012..853a9bec 100644 --- a/lib/tgchat/ext/td/SplitSource.php +++ b/lib/tgchat/ext/td/SplitSource.php @@ -75,6 +75,7 @@ function split_file($file, $chunks, $undo) { $target_depth = 1 + $is_generated; $is_static = false; $in_define = false; + $in_comment = false; $current = ''; $common = ''; $functions = array(); @@ -113,6 +114,17 @@ function split_file($file, $chunks, $undo) { continue; } + if ($in_comment && strpos($line, '*/') === 0) { + $in_comment = false; + continue; + } + if (strpos($line, '/*') === 0) { + $in_comment = true; + } + if ($in_comment) { + continue; + } + if ($depth !== $target_depth) { $common .= $line; continue; @@ -139,7 +151,8 @@ function split_file($file, $chunks, $undo) { $in_define = false; } } - if (!empty(trim($current))) { + $current = trim($current); + if (!empty($current)) { fwrite(STDERR, "ERROR: $current".PHP_EOL); exit(); } @@ -153,7 +166,7 @@ function split_file($file, $chunks, $undo) { $parents = array(); foreach ($functions as $i => $f) { if (preg_match_all('/(?J)(create_handler|create_net_actor)<(?[A-Z][A-Za-z]*)>|'. - '(?[A-Z][A-Za-z]*) : public (Td::ResultHandler|NetActor|Request)|'. + '(?[A-Z][A-Za-z]*) (final )?: public (Td::ResultHandler|NetActor|Request)|'. '(CREATE_REQUEST|CREATE_NO_ARGS_REQUEST)[(](?[A-Z][A-Za-z]*)|'. '(?complete_pending_preauthentication_requests)|'. '(?get_message_history_slice)|'. @@ -265,27 +278,36 @@ function ($matches) use ($needed_std_headers) { 'animations_manager[_(-][^.]|AnimationsManager[^;>]' => "AnimationsManager", 'audios_manager[_(-][^.]|AudiosManager' => "AudiosManager", 'auth_manager[_(-][^.]|AuthManager' => 'AuthManager', + 'background_manager[_(-][^.]|BackgroundManager' => "BackgroundManager", 'ConfigShared|shared_config[(]' => 'ConfigShared', 'contacts_manager[_(-][^.]|ContactsManager([^ ;.]| [^*])' => 'ContactsManager', + 'country_info_manager[_(-][^.]|CountryInfoManager' => 'CountryInfoManager', 'documents_manager[_(-][^.]|DocumentsManager' => "DocumentsManager", 'file_reference_manager[_(-][^.]|FileReferenceManager|file_references[)]' => 'FileReferenceManager', 'file_manager[_(-][^.]|FileManager([^ ;.]| [^*])|update_file[)]' => 'files/FileManager', 'G[(][)]|Global[^A-Za-z]' => 'Global', + 'game_manager[_(-][^.]|GameManager' => 'GameManager', + 'group_call_manager[_(-][^.]|GroupCallManager' => 'GroupCallManager', 'HashtagHints' => 'HashtagHints', 'inline_queries_manager[_(-][^.]|InlineQueriesManager' => 'InlineQueriesManager', 'language_pack_manager[_(-][^.]|LanguagePackManager' => 'LanguagePackManager', + 'link_manager[_(-][^.]|LinkManager' => 'LinkManager', 'LogeventIdWithGeneration|add_log_event|delete_log_event|get_erase_log_event_promise|parse_time|store_time' => 'logevent/LogEventHelper', 'MessageCopyOptions' => 'MessageCopyOptions', 'messages_manager[_(-][^.]|MessagesManager' => 'MessagesManager', 'notification_manager[_(-][^.]|NotificationManager|notifications[)]' => 'NotificationManager', + 'phone_number_manager[_(-][^.]|PhoneNumberManager' => "PhoneNumberManager", + 'poll_manager[_(-][^.]|PollManager' => "PollManager", 'PublicDialogType|get_public_dialog_type' => 'PublicDialogType', 'SecretChatActor' => 'SecretChatActor', 'secret_chats_manager[_(-][^.]|SecretChatsManager' => 'SecretChatsManager', + 'sponsored_message_manager[_(-][^.]|SponsoredMessageManager' => 'SponsoredMessageManager', 'stickers_manager[_(-][^.]|StickersManager' => 'StickersManager', '[>](td_db[(][)]|get_td_db_impl[(])|TdDb[^A-Za-z]' => 'TdDb', + 'theme_manager[_(-][^.]|ThemeManager' => "ThemeManager", 'TopDialogCategory|get_top_dialog_category' => 'TopDialogCategory', 'top_dialog_manager[_(-][^.]|TopDialogManager' => 'TopDialogManager', - 'updates_manager[_(-][^.]|UpdatesManager|get_difference[)]' => 'UpdatesManager', + 'updates_manager[_(-][^.]|UpdatesManager|get_difference[)]|updateSentMessage|dummyUpdate' => 'UpdatesManager', 'WebPageId(Hash)?' => 'WebPageId', 'web_pages_manager[_(-][^.]|WebPagesManager' => 'WebPagesManager'); diff --git a/lib/tgchat/ext/td/benchmark/CMakeLists.txt b/lib/tgchat/ext/td/benchmark/CMakeLists.txt index 78bb649f..c4f17cae 100644 --- a/lib/tgchat/ext/td/benchmark/CMakeLists.txt +++ b/lib/tgchat/ext/td/benchmark/CMakeLists.txt @@ -1,4 +1,6 @@ -cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +if ((CMAKE_MAJOR_VERSION LESS 3) OR (CMAKE_VERSION VERSION_LESS "3.0.2")) + message(FATAL_ERROR "CMake >= 3.0.2 is required") +endif() if (NOT OPENSSL_FOUND) find_package(OpenSSL REQUIRED) diff --git a/lib/tgchat/ext/td/benchmark/bench_actor.cpp b/lib/tgchat/ext/td/benchmark/bench_actor.cpp index d6f25710..a8494958 100644 --- a/lib/tgchat/ext/td/benchmark/bench_actor.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_actor.cpp @@ -1,42 +1,95 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include "td/utils/benchmark.h" - #include "td/actor/actor.h" #include "td/actor/ConcurrentScheduler.h" #include "td/actor/PromiseFuture.h" +#include "td/utils/benchmark.h" #include "td/utils/common.h" #include "td/utils/crypto.h" #include "td/utils/logging.h" +#include "td/utils/SliceBuilder.h" #if TD_MSVC #pragma comment(linker, "/STACK:16777216") #endif +struct TestActor final : public td::Actor { + static td::int32 actor_count_; + + void start_up() final { + actor_count_++; + stop(); + } + + void tear_down() final { + if (--actor_count_ == 0) { + td::Scheduler::instance()->finish(); + } + } +}; + +td::int32 TestActor::actor_count_; + +namespace td { +template <> +class ActorTraits { + public: + static constexpr bool need_context = false; + static constexpr bool need_start_up = true; +}; +} // namespace td + +class CreateActorBench final : public td::Benchmark { + td::ConcurrentScheduler scheduler_; + + void start_up() final { + scheduler_.init(0); + scheduler_.start(); + } + + void tear_down() final { + scheduler_.finish(); + } + + public: + td::string get_description() const final { + return "CreateActor"; + } + + void run(int n) final { + for (int i = 0; i < n; i++) { + scheduler_.create_actor_unsafe(0, "TestActor").release(); + } + while (scheduler_.run_main(10)) { + // empty + } + } +}; + template -class RingBench : public td::Benchmark { +class RingBench final : public td::Benchmark { public: struct PassActor; private: int actor_n_ = -1; int thread_n_ = -1; - std::vector> actor_array_; + td::vector> actor_array_; td::ConcurrentScheduler *scheduler_ = nullptr; public: - std::string get_description() const override { + td::string get_description() const final { static const char *types[] = {"later", "immediate", "raw", "tail", "lambda"}; static_assert(0 <= type && type < 5, ""); return PSTRING() << "Ring (send_" << types[type] << ") (threads_n = " << thread_n_ << ")"; } - struct PassActor : public td::Actor { + struct PassActor final : public td::Actor { int id = -1; td::ActorId next_actor; int start_n = 0; @@ -58,8 +111,7 @@ class RingBench : public td::Benchmark { } else { // TODO: it is three times faster than send_event // maybe send event could be further optimized? - ::td::Scheduler::instance()->hack(static_cast>(next_actor), - td::Event::raw(static_cast(n - 1))); + next_actor.get_actor_unsafe()->raw_event(td::Event::raw(static_cast(n - 1)).data); } } else if (type == 4) { send_lambda(next_actor, [n, ptr = next_actor.get_actor_unsafe()] { ptr->pass(n - 1); }); @@ -67,14 +119,14 @@ class RingBench : public td::Benchmark { } } - void raw_event(const td::Event::Raw &raw) override { + void raw_event(const td::Event::Raw &raw) final { pass(static_cast(raw.u32)); } - void start_up() override { + void start_up() final { yield(); } - void wakeup() override { + void wakeup() final { if (start_n != 0) { int n = start_n; start_n = 0; @@ -86,11 +138,11 @@ class RingBench : public td::Benchmark { RingBench(int actor_n, int thread_n) : actor_n_(actor_n), thread_n_(thread_n) { } - void start_up() override { + void start_up() final { scheduler_ = new td::ConcurrentScheduler(); scheduler_->init(thread_n_); - actor_array_ = std::vector>(actor_n_); + actor_array_ = td::vector>(actor_n_); for (int i = 0; i < actor_n_; i++) { actor_array_[i] = scheduler_->create_actor_unsafe(thread_n_ ? i % thread_n_ : 0, "PassActor").release(); @@ -102,7 +154,7 @@ class RingBench : public td::Benchmark { scheduler_->start(); } - void run(int n) override { + void run(int n) final { // first actor is on main_thread actor_array_[0].get_actor_unsafe()->start_n = td::max(n, 100); while (scheduler_->run_main(10)) { @@ -110,22 +162,22 @@ class RingBench : public td::Benchmark { } } - void tear_down() override { + void tear_down() final { scheduler_->finish(); delete scheduler_; } }; template -class QueryBench : public td::Benchmark { +class QueryBench final : public td::Benchmark { public: - std::string get_description() const override { + td::string get_description() const final { static const char *types[] = {"callback", "immediate future", "delayed future", "dummy", "lambda", "lambda_future"}; static_assert(0 <= type && type < 6, ""); return PSTRING() << "QueryBench: " << types[type]; } - class ClientActor : public td::Actor { + class ClientActor final : public td::Actor { public: class Callback { public: @@ -156,20 +208,20 @@ class QueryBench : public td::Benchmark { td::unique_ptr callback_; }; - class ServerActor : public td::Actor { + class ServerActor final : public td::Actor { public: - class ClientCallback : public ClientActor::Callback { + class ClientCallback final : public ClientActor::Callback { public: explicit ClientCallback(td::ActorId server) : server_(server) { } - void on_result(int x) override { + void on_result(int x) final { send_closure(server_, &ServerActor::on_result, x); } private: td::ActorId server_; }; - void start_up() override { + void start_up() final { client_ = td::create_actor("Client", td::make_unique(actor_id(this))).release(); } @@ -178,7 +230,7 @@ class QueryBench : public td::Benchmark { wakeup(); } - void wakeup() override { + void wakeup() final { while (true) { if (n_ < 0) { td::Scheduler::instance()->finish(); @@ -221,7 +273,7 @@ class QueryBench : public td::Benchmark { wakeup(); } - void raw_event(const td::Event::Raw &event) override { + void raw_event(const td::Event::Raw &event) final { int val = future_.move_as_ok(); CHECK(val == n_ * n_); wakeup(); @@ -237,7 +289,7 @@ class QueryBench : public td::Benchmark { td::FutureActor future_; }; - void start_up() override { + void start_up() final { scheduler_ = new td::ConcurrentScheduler(); scheduler_->init(0); @@ -245,7 +297,7 @@ class QueryBench : public td::Benchmark { scheduler_->start(); } - void run(int n) override { + void run(int n) final { // first actor is on main_thread { auto guard = scheduler_->get_main_guard(); @@ -256,7 +308,7 @@ class QueryBench : public td::Benchmark { } } - void tear_down() override { + void tear_down() final { server_.release(); scheduler_->finish(); delete scheduler_; @@ -270,7 +322,7 @@ class QueryBench : public td::Benchmark { int main() { td::init_openssl_threads(); - SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG)); + bench(CreateActorBench()); bench(RingBench<4>(504, 0)); bench(RingBench<3>(504, 0)); bench(RingBench<0>(504, 0)); diff --git a/lib/tgchat/ext/td/benchmark/bench_crypto.cpp b/lib/tgchat/ext/td/benchmark/bench_crypto.cpp index ce880b8d..f915fbcf 100644 --- a/lib/tgchat/ext/td/benchmark/bench_crypto.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_crypto.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -8,19 +8,21 @@ #include "td/utils/common.h" #include "td/utils/crypto.h" -#include "td/utils/logging.h" #include "td/utils/port/thread.h" #include "td/utils/Random.h" #include "td/utils/Slice.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/UInt.h" #include #include +#include #include #include #include #include +#include #include #include #include @@ -28,48 +30,45 @@ static constexpr int DATA_SIZE = 8 << 10; static constexpr int SHORT_DATA_SIZE = 64; -class SHA1Bench : public td::Benchmark { +#if OPENSSL_VERSION_NUMBER <= 0x10100000L +class SHA1Bench final : public td::Benchmark { public: alignas(64) unsigned char data[DATA_SIZE]; - std::string get_description() const override { + std::string get_description() const final { return PSTRING() << "SHA1 OpenSSL [" << (DATA_SIZE >> 10) << "KB]"; } - void start_up() override { - for (int i = 0; i < DATA_SIZE; i++) { - data[i] = 123; - data[i] = 0; - } + void start_up() final { + std::fill(std::begin(data), std::end(data), static_cast(123)); } - void run(int n) override { + void run(int n) final { for (int i = 0; i < n; i++) { unsigned char md[20]; SHA1(data, DATA_SIZE, md); } } }; +#endif -class AesEcbBench : public td::Benchmark { +class AesEcbBench final : public td::Benchmark { public: alignas(64) unsigned char data[DATA_SIZE]; td::UInt256 key; td::UInt256 iv; - std::string get_description() const override { + std::string get_description() const final { return PSTRING() << "AES ECB OpenSSL [" << (DATA_SIZE >> 10) << "KB]"; } - void start_up() override { - for (int i = 0; i < DATA_SIZE; i++) { - data[i] = 123; - } + void start_up() final { + std::fill(std::begin(data), std::end(data), static_cast(123)); td::Random::secure_bytes(key.raw, sizeof(key)); td::Random::secure_bytes(iv.raw, sizeof(iv)); } - void run(int n) override { + void run(int n) final { td::AesState state; state.init(td::as_slice(key), true); td::MutableSlice data_slice(data, DATA_SIZE); @@ -82,25 +81,23 @@ class AesEcbBench : public td::Benchmark { } }; -class AesIgeEncryptBench : public td::Benchmark { +class AesIgeEncryptBench final : public td::Benchmark { public: alignas(64) unsigned char data[DATA_SIZE]; td::UInt256 key; td::UInt256 iv; - std::string get_description() const override { + std::string get_description() const final { return PSTRING() << "AES IGE OpenSSL encrypt [" << (DATA_SIZE >> 10) << "KB]"; } - void start_up() override { - for (int i = 0; i < DATA_SIZE; i++) { - data[i] = 123; - } + void start_up() final { + std::fill(std::begin(data), std::end(data), static_cast(123)); td::Random::secure_bytes(key.raw, sizeof(key)); td::Random::secure_bytes(iv.raw, sizeof(iv)); } - void run(int n) override { + void run(int n) final { td::MutableSlice data_slice(data, DATA_SIZE); td::AesIgeState state; state.init(as_slice(key), as_slice(iv), true); @@ -110,25 +107,23 @@ class AesIgeEncryptBench : public td::Benchmark { } }; -class AesIgeDecryptBench : public td::Benchmark { +class AesIgeDecryptBench final : public td::Benchmark { public: alignas(64) unsigned char data[DATA_SIZE]; td::UInt256 key; td::UInt256 iv; - std::string get_description() const override { + std::string get_description() const final { return PSTRING() << "AES IGE OpenSSL decrypt [" << (DATA_SIZE >> 10) << "KB]"; } - void start_up() override { - for (int i = 0; i < DATA_SIZE; i++) { - data[i] = 123; - } + void start_up() final { + std::fill(std::begin(data), std::end(data), static_cast(123)); td::Random::secure_bytes(key.raw, sizeof(key)); td::Random::secure_bytes(iv.raw, sizeof(iv)); } - void run(int n) override { + void run(int n) final { td::MutableSlice data_slice(data, DATA_SIZE); td::AesIgeState state; state.init(as_slice(key), as_slice(iv), false); @@ -138,25 +133,23 @@ class AesIgeDecryptBench : public td::Benchmark { } }; -class AesCtrBench : public td::Benchmark { +class AesCtrBench final : public td::Benchmark { public: alignas(64) unsigned char data[DATA_SIZE]; td::UInt256 key; td::UInt128 iv; - std::string get_description() const override { + std::string get_description() const final { return PSTRING() << "AES CTR OpenSSL [" << (DATA_SIZE >> 10) << "KB]"; } - void start_up() override { - for (int i = 0; i < DATA_SIZE; i++) { - data[i] = 123; - } + void start_up() final { + std::fill(std::begin(data), std::end(data), static_cast(123)); td::Random::secure_bytes(key.raw, sizeof(key)); td::Random::secure_bytes(iv.raw, sizeof(iv)); } - void run(int n) override { + void run(int n) final { td::MutableSlice data_slice(data, DATA_SIZE); td::AesCtrState state; state.init(as_slice(key), as_slice(iv)); @@ -167,25 +160,23 @@ class AesCtrBench : public td::Benchmark { }; #if OPENSSL_VERSION_NUMBER >= 0x10100000L -class AesCtrOpenSSLBench : public td::Benchmark { +class AesCtrOpenSSLBench final : public td::Benchmark { public: alignas(64) unsigned char data[DATA_SIZE]; td::UInt256 key; td::UInt128 iv; - std::string get_description() const override { + std::string get_description() const final { return PSTRING() << "AES CTR RAW OpenSSL [" << (DATA_SIZE >> 10) << "KB]"; } - void start_up() override { - for (int i = 0; i < DATA_SIZE; i++) { - data[i] = 123; - } + void start_up() final { + std::fill(std::begin(data), std::end(data), static_cast(123)); td::Random::secure_bytes(key.raw, sizeof(key)); td::Random::secure_bytes(iv.raw, sizeof(iv)); } - void run(int n) override { + void run(int n) final { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_EncryptInit_ex(ctx, EVP_aes_256_ctr(), nullptr, key.raw, iv.raw); @@ -203,25 +194,23 @@ class AesCtrOpenSSLBench : public td::Benchmark { }; #endif -class AesCbcDecryptBench : public td::Benchmark { +class AesCbcDecryptBench final : public td::Benchmark { public: alignas(64) unsigned char data[DATA_SIZE]; td::UInt256 key; td::UInt128 iv; - std::string get_description() const override { + std::string get_description() const final { return PSTRING() << "AES CBC Decrypt OpenSSL [" << (DATA_SIZE >> 10) << "KB]"; } - void start_up() override { - for (int i = 0; i < DATA_SIZE; i++) { - data[i] = 123; - } + void start_up() final { + std::fill(std::begin(data), std::end(data), static_cast(123)); td::Random::secure_bytes(as_slice(key)); td::Random::secure_bytes(as_slice(iv)); } - void run(int n) override { + void run(int n) final { td::MutableSlice data_slice(data, DATA_SIZE); for (int i = 0; i < n; i++) { td::aes_cbc_decrypt(as_slice(key), as_slice(iv), data_slice, data_slice); @@ -229,25 +218,23 @@ class AesCbcDecryptBench : public td::Benchmark { } }; -class AesCbcEncryptBench : public td::Benchmark { +class AesCbcEncryptBench final : public td::Benchmark { public: alignas(64) unsigned char data[DATA_SIZE]; td::UInt256 key; td::UInt128 iv; - std::string get_description() const override { + std::string get_description() const final { return PSTRING() << "AES CBC Encrypt OpenSSL [" << (DATA_SIZE >> 10) << "KB]"; } - void start_up() override { - for (int i = 0; i < DATA_SIZE; i++) { - data[i] = 123; - } + void start_up() final { + std::fill(std::begin(data), std::end(data), static_cast(123)); td::Random::secure_bytes(as_slice(key)); td::Random::secure_bytes(as_slice(iv)); } - void run(int n) override { + void run(int n) final { td::MutableSlice data_slice(data, DATA_SIZE); for (int i = 0; i < n; i++) { td::aes_cbc_encrypt(as_slice(key), as_slice(iv), data_slice, data_slice); @@ -256,25 +243,23 @@ class AesCbcEncryptBench : public td::Benchmark { }; template -class AesIgeShortBench : public td::Benchmark { +class AesIgeShortBench final : public td::Benchmark { public: alignas(64) unsigned char data[SHORT_DATA_SIZE]; td::UInt256 key; td::UInt256 iv; - std::string get_description() const override { + std::string get_description() const final { return PSTRING() << "AES IGE OpenSSL " << (use_state ? "EVP" : "C ") << "[" << SHORT_DATA_SIZE << "B]"; } - void start_up() override { - for (int i = 0; i < SHORT_DATA_SIZE; i++) { - data[i] = 123; - } + void start_up() final { + std::fill(std::begin(data), std::end(data), static_cast(123)); td::Random::secure_bytes(as_slice(key)); td::Random::secure_bytes(as_slice(iv)); } - void run(int n) override { + void run(int n) final { td::MutableSlice data_slice(data, SHORT_DATA_SIZE); for (int i = 0; i < n; i++) { if (use_state) { @@ -361,22 +346,19 @@ BENCH(Pbkdf2, "pbkdf2") { td::pbkdf2_sha256(password, salt, n, key); } -class Crc32Bench : public td::Benchmark { +class Crc32Bench final : public td::Benchmark { public: alignas(64) unsigned char data[DATA_SIZE]; - std::string get_description() const override { + std::string get_description() const final { return PSTRING() << "Crc32 zlib [" << (DATA_SIZE >> 10) << "KB]"; } - void start_up() override { - for (int i = 0; i < DATA_SIZE; i++) { - data[i] = 123; - data[i] = 0; - } + void start_up() final { + std::fill(std::begin(data), std::end(data), static_cast(123)); } - void run(int n) override { + void run(int n) final { td::uint64 res = 0; for (int i = 0; i < n; i++) { res += td::crc32(td::Slice(data, DATA_SIZE)); @@ -385,22 +367,19 @@ class Crc32Bench : public td::Benchmark { } }; -class Crc64Bench : public td::Benchmark { +class Crc64Bench final : public td::Benchmark { public: alignas(64) unsigned char data[DATA_SIZE]; - std::string get_description() const override { + std::string get_description() const final { return PSTRING() << "Crc64 Anton [" << (DATA_SIZE >> 10) << "KB]"; } - void start_up() override { - for (int i = 0; i < DATA_SIZE; i++) { - data[i] = 123; - data[i] = 0; - } + void start_up() final { + std::fill(std::begin(data), std::end(data), static_cast(123)); } - void run(int n) override { + void run(int n) final { td::uint64 res = 0; for (int i = 0; i < n; i++) { res += td::crc64(td::Slice(data, DATA_SIZE)); @@ -433,7 +412,9 @@ int main() { td::bench(SslRandBench()); #endif td::bench(SslRandBufBench()); +#if OPENSSL_VERSION_NUMBER <= 0x10100000L td::bench(SHA1Bench()); +#endif td::bench(Crc32Bench()); td::bench(Crc64Bench()); } diff --git a/lib/tgchat/ext/td/benchmark/bench_db.cpp b/lib/tgchat/ext/td/benchmark/bench_db.cpp index 9b5d548c..61ce57ab 100644 --- a/lib/tgchat/ext/td/benchmark/bench_db.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_db.cpp @@ -1,12 +1,9 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include "td/actor/actor.h" -#include "td/actor/ConcurrentScheduler.h" - #include "td/db/binlog/Binlog.h" #include "td/db/binlog/ConcurrentBinlog.h" #include "td/db/BinlogKeyValue.h" @@ -17,17 +14,21 @@ #include "td/db/SqliteKeyValueAsync.h" #include "td/db/SqliteKeyValueSafe.h" +#include "td/actor/actor.h" +#include "td/actor/ConcurrentScheduler.h" + #include "td/utils/benchmark.h" #include "td/utils/common.h" #include "td/utils/format.h" #include "td/utils/logging.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Status.h" #include "td/utils/StringBuilder.h" #include template -class TdKvBench : public td::Benchmark { +class TdKvBench final : public td::Benchmark { td::ConcurrentScheduler sched; td::string name_; @@ -36,27 +37,27 @@ class TdKvBench : public td::Benchmark { name_ = std::move(name); } - td::string get_description() const override { + td::string get_description() const final { return name_; } - class Main : public td::Actor { + class Main final : public td::Actor { public: explicit Main(int n) : n_(n) { } private: - void loop() override { + void loop() final { KeyValueT::destroy("test_tddb").ignore(); - class Worker : public Actor { + class Worker final : public Actor { public: Worker(int n, td::string db_name) : n_(n) { kv_.init(db_name).ensure(); } private: - void loop() override { + void loop() final { for (int i = 0; i < n_; i++) { kv_.set(td::to_string(i % 10), td::to_string(i)); } @@ -70,12 +71,12 @@ class TdKvBench : public td::Benchmark { int n_; }; - void start_up_n(int n) override { + void start_up_n(int n) final { sched.init(1); sched.create_actor_unsafe
(1, "Main", n).release(); } - void run(int n) override { + void run(int n) final { sched.start(); while (sched.run_main(10)) { // empty @@ -83,24 +84,23 @@ class TdKvBench : public td::Benchmark { sched.finish(); } - void tear_down() override { + void tear_down() final { } }; template -class SqliteKVBench : public td::Benchmark { +class SqliteKVBench final : public td::Benchmark { td::SqliteDb db; - td::string get_description() const override { + td::string get_description() const final { return PSTRING() << "SqliteKV " << td::tag("is_encrypted", is_encrypted); } - void start_up() override { + void start_up() final { td::string path = "testdb.sqlite"; td::SqliteDb::destroy(path).ignore(); if (is_encrypted) { - td::SqliteDb::change_key(path, td::DbKey::password("cucumber"), td::DbKey::empty()).ensure(); - db = td::SqliteDb::open_with_key(path, td::DbKey::password("cucumber")).move_as_ok(); + db = td::SqliteDb::change_key(path, true, td::DbKey::password("cucumber"), td::DbKey::empty()).move_as_ok(); } else { - db = td::SqliteDb::open_with_key(path, td::DbKey::empty()).move_as_ok(); + db = td::SqliteDb::open_with_key(path, true, td::DbKey::empty()).move_as_ok(); } db.exec("PRAGMA encoding=\"UTF-8\"").ensure(); db.exec("PRAGMA synchronous=NORMAL").ensure(); @@ -109,7 +109,7 @@ class SqliteKVBench : public td::Benchmark { db.exec("DROP TABLE IF EXISTS KV").ensure(); db.exec("CREATE TABLE IF NOT EXISTS KV (k BLOB PRIMARY KEY, v BLOB)").ensure(); } - void run(int n) override { + void run(int n) final { auto stmt = db.get_statement("REPLACE INTO KV (k, v) VALUES(?1, ?2)").move_as_ok(); db.exec("BEGIN TRANSACTION").ensure(); for (int i = 0; i < n; i++) { @@ -141,16 +141,16 @@ static td::Status init_db(td::SqliteDb &db) { return td::Status::OK(); } -class SqliteKeyValueAsyncBench : public td::Benchmark { +class SqliteKeyValueAsyncBench final : public td::Benchmark { public: - td::string get_description() const override { + td::string get_description() const final { return "SqliteKeyValueAsync"; } - void start_up() override { + void start_up() final { do_start_up().ensure(); scheduler_->start(); } - void run(int n) override { + void run(int n) final { auto guard = scheduler_->get_main_guard(); for (int i = 0; i < n; i++) { @@ -159,7 +159,7 @@ class SqliteKeyValueAsyncBench : public td::Benchmark { sqlite_kv_async_->set(key, value, td::Auto()); } } - void tear_down() override { + void tear_down() final { scheduler_->run_main(0.1); { auto guard = scheduler_->get_main_guard(); @@ -187,7 +187,7 @@ class SqliteKeyValueAsyncBench : public td::Benchmark { td::string sql_db_name = "testdb.sqlite"; td::SqliteDb::destroy(sql_db_name).ignore(); - sql_connection_ = std::make_shared(sql_db_name); + sql_connection_ = std::make_shared(sql_db_name, td::DbKey::empty()); auto &db = sql_connection_->get(); TRY_STATUS(init_db(db)); @@ -198,13 +198,13 @@ class SqliteKeyValueAsyncBench : public td::Benchmark { } }; -class SeqKvBench : public td::Benchmark { - td::string get_description() const override { +class SeqKvBench final : public td::Benchmark { + td::string get_description() const final { return "SeqKvBench"; } td::SeqKeyValue kv; - void run(int n) override { + void run(int n) final { for (int i = 0; i < n; i++) { kv.set(PSLICE() << i % 10, PSLICE() << i); } @@ -212,17 +212,17 @@ class SeqKvBench : public td::Benchmark { }; template -class BinlogKeyValueBench : public td::Benchmark { - td::string get_description() const override { +class BinlogKeyValueBench final : public td::Benchmark { + td::string get_description() const final { return PSTRING() << "BinlogKeyValue " << td::tag("is_encrypted", is_encrypted); } td::BinlogKeyValue kv; - void start_up() override { + void start_up() final { td::SqliteDb::destroy("test_binlog").ignore(); kv.init("test_binlog", is_encrypted ? td::DbKey::password("cucumber") : td::DbKey::empty()).ensure(); } - void run(int n) override { + void run(int n) final { for (int i = 0; i < n; i++) { kv.set(td::to_string(i % 10), td::to_string(i)); } diff --git a/lib/tgchat/ext/td/benchmark/bench_empty.cpp b/lib/tgchat/ext/td/benchmark/bench_empty.cpp index 24bce2a1..d2ba2579 100644 --- a/lib/tgchat/ext/td/benchmark/bench_empty.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_empty.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/benchmark/bench_handshake.cpp b/lib/tgchat/ext/td/benchmark/bench_handshake.cpp index 23ca5c64..509af7df 100644 --- a/lib/tgchat/ext/td/benchmark/bench_handshake.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_handshake.cpp @@ -1,16 +1,15 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include "td/utils/benchmark.h" - +#include "td/mtproto/DhCallback.h" #include "td/mtproto/DhHandshake.h" #include "td/utils/base64.h" +#include "td/utils/benchmark.h" #include "td/utils/common.h" -#include "td/utils/logging.h" #include "td/utils/Slice.h" #include @@ -19,43 +18,41 @@ #include #endif -namespace td { - -static int32 g = 3; -static string prime_base64 = +static td::int32 g = 3; +static td::string prime_base64 = "xxyuucaxyQSObFIvcPE_c5gNQCOOPiHBSTTQN1Y9kw9IGYoKp8FAWCKUk9IlMPTb-jNvbgrJJROVQ67UTM58NyD9UfaUWHBaxozU_mtrE6vcl0ZRKW" "kyhFTxj6-MWV9kJHf-lrsqlB1bzR1KyMxJiAcI-ps3jjxPOpBgvuZ8-aSkppWBEFGQfhYnU7VrD2tBDbp02KhLKhSzFE4O8ShHVP0X7ZUNWWW0ud1G" "WC2xF40WnGvEZbDW_5yjko_vW5rk5Bj8Feg-vqD4f6n_Xu1wBQ3tKEn0e_lZ2VaFDOkphR8NgRX2NbEF7i5OFdBLJFS_b0-t8DSxBAMRnNjjuS_MW" "w"; -class HandshakeBench : public Benchmark { - std::string get_description() const override { +class HandshakeBench final : public td::Benchmark { + td::string get_description() const final { return "Handshake"; } - class FakeDhCallback : public DhCallback { + class FakeDhCallback final : public td::mtproto::DhCallback { public: - int is_good_prime(Slice prime_str) const override { + int is_good_prime(td::Slice prime_str) const final { auto it = cache.find(prime_str.str()); if (it == cache.end()) { return -1; } return it->second; } - void add_good_prime(Slice prime_str) const override { + void add_good_prime(td::Slice prime_str) const final { cache[prime_str.str()] = 1; } - void add_bad_prime(Slice prime_str) const override { + void add_bad_prime(td::Slice prime_str) const final { cache[prime_str.str()] = 0; } - mutable std::map cache; + mutable std::map cache; } dh_callback; - void run(int n) override { - DhHandshake a; - DhHandshake b; - auto prime = base64url_decode(prime_base64).move_as_ok(); - DhHandshake::check_config(g, prime, &dh_callback).ensure(); + void run(int n) final { + td::mtproto::DhHandshake a; + td::mtproto::DhHandshake b; + auto prime = td::base64url_decode(prime_base64).move_as_ok(); + td::mtproto::DhHandshake::check_config(g, prime, &dh_callback).ensure(); for (int i = 0; i < n; i += 2) { a.set_config(g, prime); b.set_config(g, prime); @@ -69,9 +66,7 @@ class HandshakeBench : public Benchmark { } } }; -} // namespace td int main() { - SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG)); - td::bench(td::HandshakeBench()); + td::bench(HandshakeBench()); } diff --git a/lib/tgchat/ext/td/benchmark/bench_http.cpp b/lib/tgchat/ext/td/benchmark/bench_http.cpp index 479db4f4..f1147c01 100644 --- a/lib/tgchat/ext/td/benchmark/bench_http.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_http.cpp @@ -1,17 +1,18 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include "td/actor/actor.h" -#include "td/actor/ConcurrentScheduler.h" - #include "td/net/HttpOutboundConnection.h" #include "td/net/HttpQuery.h" #include "td/net/SslStream.h" +#include "td/actor/actor.h" +#include "td/actor/ConcurrentScheduler.h" + #include "td/utils/buffer.h" +#include "td/utils/BufferedFd.h" #include "td/utils/logging.h" #include "td/utils/port/IPAddress.h" #include "td/utils/port/SocketFd.h" @@ -20,50 +21,52 @@ #include #include -namespace td { - std::atomic counter; -class HttpClient : public HttpOutboundConnection::Callback { - void start_up() override { - IPAddress addr; +class HttpClient final : public td::HttpOutboundConnection::Callback { + void start_up() final { + td::IPAddress addr; addr.init_ipv4_port("127.0.0.1", 8082).ensure(); - auto fd = SocketFd::open(addr); + auto fd = td::SocketFd::open(addr); LOG_CHECK(fd.is_ok()) << fd.error(); - connection_ = create_actor("Connect", fd.move_as_ok(), SslStream{}, - std::numeric_limits::max(), 0, 0, - ActorOwn(actor_id(this))); + connection_ = td::create_actor( + "Connect", td::BufferedFd(fd.move_as_ok()), td::SslStream{}, std::numeric_limits::max(), + 0, 0, td::ActorOwn(actor_id(this))); yield(); cnt_ = 100000; counter++; } - void tear_down() override { + + void tear_down() final { if (--counter == 0) { - Scheduler::instance()->finish(); + td::Scheduler::instance()->finish(); } } - void loop() override { + + void loop() final { if (cnt_-- < 0) { return stop(); } - send_closure(connection_, &HttpOutboundConnection::write_next, BufferSlice("GET / HTTP/1.1\r\n\r\n")); - send_closure(connection_, &HttpOutboundConnection::write_ok); + send_closure(connection_, &td::HttpOutboundConnection::write_next, td::BufferSlice("GET / HTTP/1.1\r\n\r\n")); + send_closure(connection_, &td::HttpOutboundConnection::write_ok); LOG(INFO) << "SEND"; } - void handle(unique_ptr result) override { + + void handle(td::unique_ptr result) final { loop(); } - void on_connection_error(Status error) override { + + void on_connection_error(td::Status error) final { LOG(ERROR) << "ERROR: " << error; } - ActorOwn connection_; - int cnt_; + td::ActorOwn connection_; + int cnt_ = 0; }; int main() { SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR)); - auto scheduler = make_unique(); + auto scheduler = td::make_unique(); scheduler->init(0); scheduler->create_actor_unsafe(0, "Client1").release(); scheduler->create_actor_unsafe(0, "Client2").release(); @@ -72,10 +75,4 @@ int main() { // empty } scheduler->finish(); - return 0; -} -} // namespace td - -int main() { - return td::main(); } diff --git a/lib/tgchat/ext/td/benchmark/bench_http_reader.cpp b/lib/tgchat/ext/td/benchmark/bench_http_reader.cpp index 132c7059..3babb748 100644 --- a/lib/tgchat/ext/td/benchmark/bench_http_reader.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_http_reader.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,13 +16,13 @@ static std::string http_query = "GET / HTTP/1.1\r\nConnection:keep-alive\r\nhost:127.0.0.1:8080\r\n\r\n"; static const size_t block_size = 2500; -class HttpReaderBench : public td::Benchmark { - std::string get_description() const override { +class HttpReaderBench final : public td::Benchmark { + std::string get_description() const final { return "HttpReaderBench"; } - void run(int n) override { - int cnt = static_cast(block_size / http_query.size()); + void run(int n) final { + auto cnt = static_cast(block_size / http_query.size()); td::HttpQuery q; int parsed = 0; int sent = 0; @@ -46,19 +46,19 @@ class HttpReaderBench : public td::Benchmark { td::ChainBufferReader reader_; td::HttpReader http_reader_; - void start_up() override { + void start_up() final { reader_ = writer_.extract_reader(); http_reader_.init(&reader_, 10000, 0); } }; -class BufferBench : public td::Benchmark { - std::string get_description() const override { +class BufferBench final : public td::Benchmark { + std::string get_description() const final { return "BufferBench"; } - void run(int n) override { - int cnt = static_cast(block_size / http_query.size()); + void run(int n) final { + auto cnt = static_cast(block_size / http_query.size()); for (int i = 0; i < n; i += cnt) { for (int j = 0; j < cnt; j++) { writer_.append(http_query); @@ -73,18 +73,18 @@ class BufferBench : public td::Benchmark { td::ChainBufferReader reader_; td::HttpReader http_reader_; - void start_up() override { + void start_up() final { reader_ = writer_.extract_reader(); } }; -class FindBoundaryBench : public td::Benchmark { - std::string get_description() const override { +class FindBoundaryBench final : public td::Benchmark { + std::string get_description() const final { return "FindBoundaryBench"; } - void run(int n) override { - int cnt = static_cast(block_size / http_query.size()); + void run(int n) final { + auto cnt = static_cast(block_size / http_query.size()); for (int i = 0; i < n; i += cnt) { for (int j = 0; j < cnt; j++) { writer_.append(http_query); @@ -103,7 +103,7 @@ class FindBoundaryBench : public td::Benchmark { td::ChainBufferReader reader_; td::HttpReader http_reader_; - void start_up() override { + void start_up() final { reader_ = writer_.extract_reader(); } }; diff --git a/lib/tgchat/ext/td/benchmark/bench_http_server.cpp b/lib/tgchat/ext/td/benchmark/bench_http_server.cpp index 948b795f..87a25a80 100644 --- a/lib/tgchat/ext/td/benchmark/bench_http_server.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_http_server.cpp @@ -1,33 +1,32 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include "td/actor/actor.h" -#include "td/actor/ConcurrentScheduler.h" - #include "td/net/HttpHeaderCreator.h" #include "td/net/HttpInboundConnection.h" #include "td/net/HttpQuery.h" #include "td/net/TcpListener.h" +#include "td/actor/actor.h" +#include "td/actor/ConcurrentScheduler.h" + #include "td/utils/buffer.h" +#include "td/utils/BufferedFd.h" #include "td/utils/logging.h" #include "td/utils/port/SocketFd.h" #include "td/utils/Slice.h" -namespace td { - static int cnt = 0; -class HelloWorld : public HttpInboundConnection::Callback { +class HelloWorld final : public td::HttpInboundConnection::Callback { public: - void handle(unique_ptr query, ActorOwn connection) override { + void handle(td::unique_ptr query, td::ActorOwn connection) final { // LOG(ERROR) << *query; - HttpHeaderCreator hc; - Slice content = "hello world"; - //auto content = BufferSlice("hello world"); + td::HttpHeaderCreator hc; + td::Slice content = "hello world"; + //auto content = td::BufferSlice("hello world"); hc.init_ok(); hc.set_keep_alive(); hc.set_content_size(content.size()); @@ -37,44 +36,45 @@ class HelloWorld : public HttpInboundConnection::Callback { auto res = hc.finish(content); LOG_IF(FATAL, res.is_error()) << res.error(); - send_closure(connection, &HttpInboundConnection::write_next, BufferSlice(res.ok())); - send_closure(connection.release(), &HttpInboundConnection::write_ok); + send_closure(connection, &td::HttpInboundConnection::write_next, td::BufferSlice(res.ok())); + send_closure(connection.release(), &td::HttpInboundConnection::write_ok); } - void hangup() override { + void hangup() final { LOG(ERROR) << "CLOSE " << cnt--; stop(); } }; const int N = 0; -class Server : public TcpListener::Callback { +class Server final : public td::TcpListener::Callback { public: - void start_up() override { - listener_ = create_actor("Listener", 8082, ActorOwn(actor_id(this))); + void start_up() final { + listener_ = + td::create_actor("Listener", 8082, td::ActorOwn(actor_id(this))); } - void accept(SocketFd fd) override { + void accept(td::SocketFd fd) final { LOG(ERROR) << "ACCEPT " << cnt++; pos_++; auto scheduler_id = pos_ % (N != 0 ? N : 1) + (N != 0); - create_actor_on_scheduler("HttpInboundConnection", scheduler_id, std::move(fd), 1024 * 1024, - 0, 0, - create_actor_on_scheduler("HelloWorld", scheduler_id)) + td::create_actor_on_scheduler( + "HttpInboundConnection", scheduler_id, td::BufferedFd(std::move(fd)), 1024 * 1024, 0, 0, + td::create_actor_on_scheduler("HelloWorld", scheduler_id)) .release(); } - void hangup() override { + void hangup() final { // may be it should be default?.. LOG(ERROR) << "Hanging up.."; stop(); } private: - ActorOwn listener_; + td::ActorOwn listener_; int pos_{0}; }; int main() { SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR)); - auto scheduler = make_unique(); + auto scheduler = td::make_unique(); scheduler->init(N); scheduler->create_actor_unsafe(0, "Server").release(); scheduler->start(); @@ -82,10 +82,4 @@ int main() { // empty } scheduler->finish(); - return 0; -} -} // namespace td - -int main() { - return td::main(); } diff --git a/lib/tgchat/ext/td/benchmark/bench_http_server_cheat.cpp b/lib/tgchat/ext/td/benchmark/bench_http_server_cheat.cpp index 7d1d46b6..c7f4cc64 100644 --- a/lib/tgchat/ext/td/benchmark/bench_http_server_cheat.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_http_server_cheat.cpp @@ -1,16 +1,15 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include "td/actor/actor.h" -#include "td/actor/ConcurrentScheduler.h" - #include "td/net/HttpHeaderCreator.h" -#include "td/net/HttpInboundConnection.h" #include "td/net/TcpListener.h" +#include "td/actor/actor.h" +#include "td/actor/ConcurrentScheduler.h" + #include "td/utils/buffer.h" #include "td/utils/logging.h" #include "td/utils/port/detail/PollableFd.h" @@ -20,30 +19,28 @@ #include -namespace td { - -// HttpInboundConnection header static int cnt = 0; -class HelloWorld : public Actor { + +class HelloWorld final : public td::Actor { public: - explicit HelloWorld(SocketFd socket_fd) : socket_fd_(std::move(socket_fd)) { + explicit HelloWorld(td::SocketFd socket_fd) : socket_fd_(std::move(socket_fd)) { } private: - SocketFd socket_fd_; + td::SocketFd socket_fd_; std::array read_buf; size_t read_new_lines{0}; - std::string hello_; - std::string write_buf_; + td::string hello_; + td::string write_buf_; size_t write_pos_{0}; - void start_up() override { - Scheduler::subscribe(socket_fd_.get_poll_info().extract_pollable_fd(this)); - HttpHeaderCreator hc; - Slice content = "hello world"; - //auto content = BufferSlice("hello world"); + void start_up() final { + td::Scheduler::subscribe(socket_fd_.get_poll_info().extract_pollable_fd(this)); + td::HttpHeaderCreator hc; + td::Slice content = "hello world"; + //auto content = td::BufferSlice("hello world"); hc.init_ok(); hc.set_keep_alive(); hc.set_content_size(content.size()); @@ -53,37 +50,37 @@ class HelloWorld : public Actor { hello_ = hc.finish(content).ok().str(); } - void loop() override { + void loop() final { auto status = do_loop(); if (status.is_error()) { - Scheduler::unsubscribe(socket_fd_.get_poll_info().get_pollable_fd_ref()); + td::Scheduler::unsubscribe(socket_fd_.get_poll_info().get_pollable_fd_ref()); stop(); LOG(ERROR) << "CLOSE: " << status; } } - Status do_loop() { + td::Status do_loop() { sync_with_poll(socket_fd_); TRY_STATUS(read_loop()); TRY_STATUS(write_loop()); if (can_close_local(socket_fd_)) { - return Status::Error("CLOSE"); + return td::Status::Error("CLOSE"); } - return Status::OK(); + return td::Status::OK(); } - Status write_loop() { + td::Status write_loop() { while (can_write_local(socket_fd_) && write_pos_ < write_buf_.size()) { - TRY_RESULT(written, socket_fd_.write(Slice(write_buf_).substr(write_pos_))); + TRY_RESULT(written, socket_fd_.write(td::Slice(write_buf_).substr(write_pos_))); write_pos_ += written; if (write_pos_ == write_buf_.size()) { write_pos_ = 0; write_buf_.clear(); } } - return Status::OK(); + return td::Status::OK(); } - Status read_loop() { + td::Status read_loop() { while (can_read_local(socket_fd_)) { - TRY_RESULT(read_size, socket_fd_.read(MutableSlice(read_buf.data(), read_buf.size()))); + TRY_RESULT(read_size, socket_fd_.read(td::MutableSlice(read_buf.data(), read_buf.size()))); for (size_t i = 0; i < read_size; i++) { if (read_buf[i] == '\n') { read_new_lines++; @@ -94,35 +91,37 @@ class HelloWorld : public Actor { } } } - return Status::OK(); + return td::Status::OK(); } }; + const int N = 0; -class Server : public TcpListener::Callback { +class Server final : public td::TcpListener::Callback { public: - void start_up() override { - listener_ = create_actor("Listener", 8082, ActorOwn(actor_id(this))); + void start_up() final { + listener_ = + td::create_actor("Listener", 8082, td::ActorOwn(actor_id(this))); } - void accept(SocketFd fd) override { + void accept(td::SocketFd fd) final { LOG(ERROR) << "ACCEPT " << cnt++; pos_++; auto scheduler_id = pos_ % (N != 0 ? N : 1) + (N != 0); - create_actor_on_scheduler("HttpInboundConnection", scheduler_id, std::move(fd)).release(); + td::create_actor_on_scheduler("HelloWorld", scheduler_id, std::move(fd)).release(); } - void hangup() override { + void hangup() final { // may be it should be default?.. LOG(ERROR) << "Hanging up.."; stop(); } private: - ActorOwn listener_; + td::ActorOwn listener_; int pos_{0}; }; int main() { SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR)); - auto scheduler = make_unique(); + auto scheduler = td::make_unique(); scheduler->init(N); scheduler->create_actor_unsafe(0, "Server").release(); scheduler->start(); @@ -130,10 +129,4 @@ int main() { // empty } scheduler->finish(); - return 0; -} -} // namespace td - -int main() { - return td::main(); } diff --git a/lib/tgchat/ext/td/benchmark/bench_http_server_fast.cpp b/lib/tgchat/ext/td/benchmark/bench_http_server_fast.cpp index 2592a4d4..50cc753a 100644 --- a/lib/tgchat/ext/td/benchmark/bench_http_server_fast.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_http_server_fast.cpp @@ -1,17 +1,17 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include "td/actor/actor.h" -#include "td/actor/ConcurrentScheduler.h" - #include "td/net/HttpHeaderCreator.h" #include "td/net/HttpQuery.h" #include "td/net/HttpReader.h" #include "td/net/TcpListener.h" +#include "td/actor/actor.h" +#include "td/actor/ConcurrentScheduler.h" + #include "td/utils/buffer.h" #include "td/utils/BufferedFd.h" #include "td/utils/logging.h" @@ -20,31 +20,29 @@ #include "td/utils/Slice.h" #include "td/utils/Status.h" -namespace td { - -class HttpEchoConnection : public Actor { +class HttpEchoConnection final : public td::Actor { public: - explicit HttpEchoConnection(SocketFd fd) : fd_(std::move(fd)) { + explicit HttpEchoConnection(td::SocketFd fd) : fd_(std::move(fd)) { } private: - BufferedFd fd_; - HttpReader reader_; - HttpQuery query_; - void start_up() override { - Scheduler::subscribe(fd_.get_poll_info().extract_pollable_fd(this)); + td::BufferedFd fd_; + td::HttpReader reader_; + td::HttpQuery query_; + void start_up() final { + td::Scheduler::subscribe(fd_.get_poll_info().extract_pollable_fd(this)); reader_.init(&fd_.input_buffer(), 1024 * 1024, 0); } - void tear_down() override { - Scheduler::unsubscribe_before_close(fd_.get_poll_info().get_pollable_fd_ref()); + void tear_down() final { + td::Scheduler::unsubscribe_before_close(fd_.get_poll_info().get_pollable_fd_ref()); fd_.close(); } void handle_query() { - query_ = HttpQuery(); - HttpHeaderCreator hc; - Slice content = "hello world"; - //auto content = BufferSlice("hello world"); + query_ = td::HttpQuery(); + td::HttpHeaderCreator hc; + td::Slice content = "hello world"; + //auto content = td::BufferSlice("hello world"); hc.init_ok(); hc.set_keep_alive(); hc.set_content_size(content.size()); @@ -55,18 +53,18 @@ class HttpEchoConnection : public Actor { fd_.output_buffer().append(res.ok()); } - void loop() override { + void loop() final { sync_with_poll(fd_); auto status = [&] { TRY_STATUS(loop_read()); TRY_STATUS(loop_write()); - return Status::OK(); + return td::Status::OK(); }(); if (status.is_error() || can_close_local(fd_)) { stop(); } } - Status loop_read() { + td::Status loop_read() { TRY_STATUS(fd_.flush_read()); while (true) { TRY_RESULT(need, reader_.read_next(&query_)); @@ -76,38 +74,39 @@ class HttpEchoConnection : public Actor { break; } } - return Status::OK(); + return td::Status::OK(); } - Status loop_write() { + td::Status loop_write() { TRY_STATUS(fd_.flush_write()); - return Status::OK(); + return td::Status::OK(); } }; const int N = 8; -class Server : public TcpListener::Callback { +class Server final : public td::TcpListener::Callback { public: - void start_up() override { - listener_ = create_actor("Listener", 8082, ActorOwn(actor_id(this))); + void start_up() final { + listener_ = + td::create_actor("Listener", 8082, td::ActorOwn(actor_id(this))); } - void accept(SocketFd fd) override { + void accept(td::SocketFd fd) final { pos_++; auto scheduler_id = pos_ % (N != 0 ? N : 1) + (N != 0); - create_actor_on_scheduler("HttpInboundConnection", scheduler_id, std::move(fd)).release(); + td::create_actor_on_scheduler("HttpEchoConnection", scheduler_id, std::move(fd)).release(); } - void hangup() override { + void hangup() final { LOG(ERROR) << "Hanging up.."; stop(); } private: - ActorOwn listener_; + td::ActorOwn listener_; int pos_{0}; }; int main() { SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR)); - auto scheduler = make_unique(); + auto scheduler = td::make_unique(); scheduler->init(N); scheduler->create_actor_unsafe(0, "Server").release(); scheduler->start(); @@ -117,8 +116,3 @@ int main() { scheduler->finish(); return 0; } -} // namespace td - -int main() { - return td::main(); -} diff --git a/lib/tgchat/ext/td/benchmark/bench_log.cpp b/lib/tgchat/ext/td/benchmark/bench_log.cpp index 0f778e75..fa42828d 100644 --- a/lib/tgchat/ext/td/benchmark/bench_log.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_log.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -36,7 +36,7 @@ std::string create_tmp_file() { #endif } -class IostreamWriteBench : public td::Benchmark { +class IostreamWriteBench final : public td::Benchmark { protected: std::string file_name_; std::ofstream stream; @@ -44,30 +44,30 @@ class IostreamWriteBench : public td::Benchmark { char buffer[BUFFER_SIZE]; public: - std::string get_description() const override { + std::string get_description() const final { return "ostream (to file, no buf, no flush)"; } - void start_up() override { + void start_up() final { file_name_ = create_tmp_file(); stream.open(file_name_.c_str()); CHECK(stream.is_open()); // stream.rdbuf()->pubsetbuf(buffer, BUFFER_SIZE); } - void run(int n) override { + void run(int n) final { for (int i = 0; i < n; i++) { stream << "This is just for test" << 987654321 << '\n'; } } - void tear_down() override { + void tear_down() final { stream.close(); unlink(file_name_.c_str()); } }; -class FILEWriteBench : public td::Benchmark { +class FILEWriteBench final : public td::Benchmark { protected: std::string file_name_; FILE *file; @@ -75,24 +75,24 @@ class FILEWriteBench : public td::Benchmark { char buffer[BUFFER_SIZE]; public: - std::string get_description() const override { + std::string get_description() const final { return "std::fprintf (to file, no buf, no flush)"; } - void start_up() override { + void start_up() final { file_name_ = create_tmp_file(); file = fopen(file_name_.c_str(), "w"); // setvbuf(file, buffer, _IOFBF, BUFFER_SIZE); } - void run(int n) override { + void run(int n) final { for (int i = 0; i < n; i++) { std::fprintf(file, "This is just for test%d\n", 987654321); // std::fflush(file); } } - void tear_down() override { + void tear_down() final { std::fclose(file); unlink(file_name_.c_str()); } @@ -101,24 +101,24 @@ class FILEWriteBench : public td::Benchmark { #if TD_ANDROID #include #define ALOG(...) __android_log_print(ANDROID_LOG_VERBOSE, "XXX", __VA_ARGS__) -class ALogWriteBench : public td::Benchmark { +class ALogWriteBench final : public td::Benchmark { public: - std::string get_description() const override { + std::string get_description() const final { return "android_log"; } - void start_up() override { + void start_up() final { } - void run(int n) override { + void run(int n) final { for (int i = 0; i < n; i++) { ALOG("This is just for test%d\n", 987654321); } } - void tear_down() override { + void tear_down() final { } }; #endif -class LogWriteBench : public td::Benchmark { +class LogWriteBench final : public td::Benchmark { protected: std::string file_name_; std::ofstream stream; @@ -127,24 +127,24 @@ class LogWriteBench : public td::Benchmark { char buffer[BUFFER_SIZE]; public: - std::string get_description() const override { + std::string get_description() const final { return "td_log (slow in debug mode)"; } - void start_up() override { + void start_up() final { file_name_ = create_tmp_file(); stream.open(file_name_.c_str()); CHECK(stream.is_open()); old_buf = std::cerr.rdbuf(stream.rdbuf()); } - void run(int n) override { + void run(int n) final { for (int i = 0; i < n; i++) { LOG(DEBUG) << "This is just for test" << 987654321; } } - void tear_down() override { + void tear_down() final { stream.close(); unlink(file_name_.c_str()); std::cerr.rdbuf(old_buf); diff --git a/lib/tgchat/ext/td/benchmark/bench_misc.cpp b/lib/tgchat/ext/td/benchmark/bench_misc.cpp index f87d2af3..148f24de 100644 --- a/lib/tgchat/ext/td/benchmark/bench_misc.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_misc.cpp @@ -1,11 +1,15 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // +#include "td/telegram/telegram_api.h" +#include "td/telegram/telegram_api.hpp" + #include "td/utils/benchmark.h" #include "td/utils/common.h" +#include "td/utils/format.h" #include "td/utils/logging.h" #include "td/utils/port/Clocks.h" #include "td/utils/port/EventFd.h" @@ -15,9 +19,9 @@ #include "td/utils/port/Stat.h" #include "td/utils/port/thread.h" #include "td/utils/Slice.h" - -#include "td/telegram/telegram_api.h" -#include "td/telegram/telegram_api.hpp" +#include "td/utils/SliceBuilder.h" +#include "td/utils/Status.h" +#include "td/utils/ThreadSafeCounter.h" #if !TD_WINDOWS #include @@ -28,37 +32,38 @@ #include #endif +#include +#include #include #include - -namespace td { +#include class F { - uint32 ∑ + td::uint32 ∑ public: - explicit F(uint32 &sum) : sum(sum) { + explicit F(td::uint32 &sum) : sum(sum) { } template void operator()(const T &x) const { - sum += static_cast(x.get_id()); + sum += static_cast(x.get_id()); } }; BENCH(Call, "TL Call") { - tl_object_ptr x = make_tl_object(0); - uint32 res = 0; + td::tl_object_ptr x = td::make_tl_object(0); + td::uint32 res = 0; F f(res); for (int i = 0; i < n; i++) { downcast_call(*x, f); } - do_not_optimize_away(res); + td::do_not_optimize_away(res); } #if !TD_EVENTFD_UNSUPPORTED BENCH(EventFd, "EventFd") { - EventFd fd; + td::EventFd fd; fd.init(); for (int i = 0; i < n; i++) { fd.release(); @@ -75,15 +80,15 @@ BENCH(NewInt, "new int + delete") { res += reinterpret_cast(x); delete x; } - do_not_optimize_away(res); + td::do_not_optimize_away(res); } BENCH(NewObj, "new struct, then delete") { struct A { - int32 a = 0; - int32 b = 0; - int32 c = 0; - int32 d = 0; + td::int32 a = 0; + td::int32 b = 0; + td::int32 c = 0; + td::int32 d = 0; }; std::uintptr_t res = 0; A **ptr = new A *[n]; @@ -95,14 +100,15 @@ BENCH(NewObj, "new struct, then delete") { delete ptr[i]; } delete[] ptr; - do_not_optimize_away(res); + td::do_not_optimize_away(res); } #if !TD_THREAD_UNSUPPORTED -BENCH(ThreadNew, "new struct, then delete in several threads") { - td::NewObjBench a, b; - thread ta([&] { a.run(n / 2); }); - thread tb([&] { b.run(n - n / 2); }); +BENCH(ThreadNew, "new struct, then delete in 2 threads") { + NewObjBench a; + NewObjBench b; + td::thread ta([&] { a.run(n / 2); }); + td::thread tb([&] { b.run(n - n / 2); }); ta.join(); tb.join(); } @@ -112,26 +118,26 @@ BENCH(ThreadNew, "new struct, then delete in several threads") { BENCH(Time, "Clocks::monotonic") { double res = 0; for (int i = 0; i < n; i++) { - res += Clocks::monotonic(); + res += td::Clocks::monotonic(); } - do_not_optimize_away(res); + td::do_not_optimize_away(res); } */ #if !TD_WINDOWS -class PipeBench : public Benchmark { +class PipeBench final : public td::Benchmark { public: int p[2]; - string get_description() const override { + td::string get_description() const final { return "pipe write + read int32"; } - void start_up() override { + void start_up() final { int res = pipe(p); CHECK(res == 0); } - void run(int n) override { + void run(int n) final { int res = 0; for (int i = 0; i < n; i++) { int val = 1; @@ -141,10 +147,10 @@ class PipeBench : public Benchmark { CHECK(read_len == sizeof(val)); res += val; } - do_not_optimize_away(res); + td::do_not_optimize_away(res); } - void tear_down() override { + void tear_down() final { close(p[0]); close(p[1]); } @@ -152,42 +158,42 @@ class PipeBench : public Benchmark { #endif #if TD_LINUX || TD_ANDROID || TD_TIZEN -class SemBench : public Benchmark { +class SemBench final : public td::Benchmark { sem_t sem; public: - string get_description() const override { + td::string get_description() const final { return "sem post + wait"; } - void start_up() override { + void start_up() final { int err = sem_init(&sem, 0, 0); CHECK(err != -1); } - void run(int n) override { + void run(int n) final { for (int i = 0; i < n; i++) { sem_post(&sem); sem_wait(&sem); } } - void tear_down() override { + void tear_down() final { sem_destroy(&sem); } }; #endif #if !TD_WINDOWS -class UtimeBench : public Benchmark { +class UtimeBench final : public td::Benchmark { public: - void start_up() override { - FileFd::open("test", FileFd::Flags::Create | FileFd::Flags::Write).move_as_ok().close(); + void start_up() final { + td::FileFd::open("test", td::FileFd::Create | td::FileFd::Write).move_as_ok().close(); } - string get_description() const override { + td::string get_description() const final { return "utime"; } - void run(int n) override { + void run(int n) final { for (int i = 0; i < n; i++) { int err = utime("test", nullptr); CHECK(err >= 0); @@ -202,62 +208,62 @@ class UtimeBench : public Benchmark { #endif BENCH(Pwrite, "pwrite") { - auto fd = FileFd::open("test", FileFd::Flags::Create | FileFd::Flags::Write).move_as_ok(); + auto fd = td::FileFd::open("test", td::FileFd::Create | td::FileFd::Write).move_as_ok(); for (int i = 0; i < n; i++) { fd.pwrite("a", 0).ok(); } fd.close(); } -class CreateFileBench : public Benchmark { - string get_description() const override { +class CreateFileBench final : public td::Benchmark { + td::string get_description() const final { return "create_file"; } - void start_up() override { - mkdir("A").ensure(); + void start_up() final { + td::mkdir("A").ensure(); } - void run(int n) override { + void run(int n) final { for (int i = 0; i < n; i++) { - FileFd::open(PSLICE() << "A/" << i, FileFd::Flags::Write | FileFd::Flags::Create).move_as_ok().close(); + td::FileFd::open(PSLICE() << "A/" << i, td::FileFd::Write | td::FileFd::Create).move_as_ok().close(); } } - void tear_down() override { - td::walk_path("A/", [&](CSlice path, auto type) { + void tear_down() final { + td::walk_path("A/", [&](td::CSlice path, auto type) { if (type == td::WalkPath::Type::ExitDir) { - rmdir(path).ignore(); + td::rmdir(path).ignore(); } else if (type == td::WalkPath::Type::NotDir) { - unlink(path).ignore(); + td::unlink(path).ignore(); } }).ignore(); } }; -class WalkPathBench : public Benchmark { - string get_description() const override { +class WalkPathBench final : public td::Benchmark { + td::string get_description() const final { return "walk_path"; } - void start_up_n(int n) override { - mkdir("A").ensure(); + void start_up_n(int n) final { + td::mkdir("A").ensure(); for (int i = 0; i < n; i++) { - FileFd::open(PSLICE() << "A/" << i, FileFd::Flags::Write | FileFd::Flags::Create).move_as_ok().close(); + td::FileFd::open(PSLICE() << "A/" << i, td::FileFd::Write | td::FileFd::Create).move_as_ok().close(); } } - void run(int n) override { + void run(int n) final { int cnt = 0; - td::walk_path("A/", [&](CSlice path, auto type) { + td::walk_path("A/", [&](td::CSlice path, auto type) { if (type == td::WalkPath::Type::EnterDir) { return; } - stat(path).ok(); + td::stat(path).ok(); cnt++; }).ignore(); } - void tear_down() override { - td::walk_path("A/", [&](CSlice path, auto type) { + void tear_down() final { + td::walk_path("A/", [&](td::CSlice path, auto type) { if (type == td::WalkPath::Type::ExitDir) { - rmdir(path).ignore(); + td::rmdir(path).ignore(); } else if (type == td::WalkPath::Type::NotDir) { - unlink(path).ignore(); + td::unlink(path).ignore(); } }).ignore(); } @@ -265,14 +271,14 @@ class WalkPathBench : public Benchmark { #if !TD_THREAD_UNSUPPORTED template -class AtomicReleaseIncBench : public Benchmark { - string get_description() const override { +class AtomicReleaseIncBench final : public td::Benchmark { + td::string get_description() const final { return PSTRING() << "AtomicReleaseInc" << ThreadN; } - static std::atomic a_; - void run(int n) override { - std::vector threads; + static std::atomic a_; + void run(int n) final { + td::vector threads; for (int i = 0; i < ThreadN; i++) { threads.emplace_back([&] { for (int i = 0; i < n / ThreadN; i++) { @@ -286,17 +292,17 @@ class AtomicReleaseIncBench : public Benchmark { } }; template -std::atomic AtomicReleaseIncBench::a_; +std::atomic AtomicReleaseIncBench::a_; template -class AtomicReleaseCasIncBench : public Benchmark { - string get_description() const override { +class AtomicReleaseCasIncBench final : public td::Benchmark { + td::string get_description() const final { return PSTRING() << "AtomicReleaseCasInc" << ThreadN; } - static std::atomic a_; - void run(int n) override { - std::vector threads; + static std::atomic a_; + void run(int n) final { + td::vector threads; for (int i = 0; i < ThreadN; i++) { threads.emplace_back([&] { for (int i = 0; i < n / ThreadN; i++) { @@ -312,16 +318,16 @@ class AtomicReleaseCasIncBench : public Benchmark { } }; template -std::atomic AtomicReleaseCasIncBench::a_; +std::atomic AtomicReleaseCasIncBench::a_; -template -class RwMutexReadBench : public Benchmark { - string get_description() const override { +template +class RwMutexReadBench final : public td::Benchmark { + td::string get_description() const final { return PSTRING() << "RwMutexRead" << ThreadN; } - RwMutex mutex_; - void run(int n) override { - std::vector threads; + td::RwMutex mutex_; + void run(int n) final { + td::vector threads; for (int i = 0; i < ThreadN; i++) { threads.emplace_back([&] { for (int i = 0; i < n / ThreadN; i++) { @@ -334,14 +340,15 @@ class RwMutexReadBench : public Benchmark { } } }; -template -class RwMutexWriteBench : public Benchmark { - string get_description() const override { + +template +class RwMutexWriteBench final : public td::Benchmark { + td::string get_description() const final { return PSTRING() << "RwMutexWrite" << ThreadN; } - RwMutex mutex_; - void run(int n) override { - std::vector threads; + td::RwMutex mutex_; + void run(int n) final { + td::vector threads; for (int i = 0; i < ThreadN; i++) { threads.emplace_back([&] { for (int i = 0; i < n / ThreadN; i++) { @@ -354,41 +361,366 @@ class RwMutexWriteBench : public Benchmark { } } }; + +class ThreadSafeCounterBench final : public td::Benchmark { + static td::ThreadSafeCounter counter_; + int thread_count_; + + td::string get_description() const final { + return PSTRING() << "ThreadSafeCounter" << thread_count_; + } + void run(int n) final { + counter_.clear(); + td::vector threads; + for (int i = 0; i < thread_count_; i++) { + threads.emplace_back([n] { + for (int i = 0; i < n; i++) { + counter_.add(1); + } + }); + } + for (auto &thread : threads) { + thread.join(); + } + CHECK(counter_.sum() == n * thread_count_); + } + + public: + explicit ThreadSafeCounterBench(int thread_count) : thread_count_(thread_count) { + } +}; +td::ThreadSafeCounter ThreadSafeCounterBench::counter_; + +template +class AtomicCounterBench final : public td::Benchmark { + static std::atomic counter_; + int thread_count_; + + td::string get_description() const final { + return PSTRING() << "AtomicCounter" << thread_count_; + } + void run(int n) final { + counter_.store(0); + td::vector threads; + for (int i = 0; i < thread_count_; i++) { + threads.emplace_back([n] { + for (int i = 0; i < n; i++) { + counter_.fetch_add(1, StrictOrder ? std::memory_order_seq_cst : std::memory_order_relaxed); + } + }); + } + for (auto &thread : threads) { + thread.join(); + } + CHECK(counter_.load() == n * thread_count_); + } + + public: + explicit AtomicCounterBench(int thread_count) : thread_count_(thread_count) { + } +}; +template +std::atomic AtomicCounterBench::counter_; + #endif -} // namespace td + +class IdDuplicateCheckerOld { + public: + static td::string get_description() { + return "Old"; + } + td::Status check(td::int64 message_id) { + if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS) { + auto oldest_message_id = *saved_message_ids_.begin(); + if (message_id < oldest_message_id) { + return td::Status::Error(2, PSLICE() << "Ignore very old message_id " + << td::tag("oldest message_id", oldest_message_id) + << td::tag("got message_id", message_id)); + } + } + if (saved_message_ids_.count(message_id) != 0) { + return td::Status::Error(1, PSLICE() << "Ignore duplicated message_id " << td::tag("message_id", message_id)); + } + + saved_message_ids_.insert(message_id); + if (saved_message_ids_.size() > MAX_SAVED_MESSAGE_IDS) { + saved_message_ids_.erase(saved_message_ids_.begin()); + } + return td::Status::OK(); + } + + private: + static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000; + std::set saved_message_ids_; +}; + +template +class IdDuplicateCheckerNew { + public: + static td::string get_description() { + return PSTRING() << "New" << MAX_SAVED_MESSAGE_IDS; + } + td::Status check(td::int64 message_id) { + auto insert_result = saved_message_ids_.insert(message_id); + if (!insert_result.second) { + return td::Status::Error(1, PSLICE() << "Ignore duplicated message_id " << td::tag("message_id", message_id)); + } + if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS + 1) { + auto begin_it = saved_message_ids_.begin(); + bool is_very_old = begin_it == insert_result.first; + saved_message_ids_.erase(begin_it); + if (is_very_old) { + return td::Status::Error(2, PSLICE() << "Ignore very old message_id " + << td::tag("oldest message_id", *saved_message_ids_.begin()) + << td::tag("got message_id", message_id)); + } + } + return td::Status::OK(); + } + + private: + std::set saved_message_ids_; +}; + +class IdDuplicateCheckerNewOther { + public: + static td::string get_description() { + return "NewOther"; + } + td::Status check(td::int64 message_id) { + if (!saved_message_ids_.insert(message_id).second) { + return td::Status::Error(1, PSLICE() << "Ignore duplicated message_id " << td::tag("message_id", message_id)); + } + if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS + 1) { + auto begin_it = saved_message_ids_.begin(); + bool is_very_old = *begin_it == message_id; + saved_message_ids_.erase(begin_it); + if (is_very_old) { + return td::Status::Error(2, PSLICE() << "Ignore very old message_id " + << td::tag("oldest message_id", *saved_message_ids_.begin()) + << td::tag("got message_id", message_id)); + } + } + return td::Status::OK(); + } + + private: + static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000; + std::set saved_message_ids_; +}; + +class IdDuplicateCheckerNewSimple { + public: + static td::string get_description() { + return "NewSimple"; + } + td::Status check(td::int64 message_id) { + auto insert_result = saved_message_ids_.insert(message_id); + if (!insert_result.second) { + return td::Status::Error(1, "Ignore duplicated message_id"); + } + if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS + 1) { + auto begin_it = saved_message_ids_.begin(); + bool is_very_old = begin_it == insert_result.first; + saved_message_ids_.erase(begin_it); + if (is_very_old) { + return td::Status::Error(2, "Ignore very old message_id"); + } + } + return td::Status::OK(); + } + + private: + static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000; + std::set saved_message_ids_; +}; + +template +class IdDuplicateCheckerArray { + public: + static td::string get_description() { + return PSTRING() << "Array" << max_size; + } + td::Status check(td::int64 message_id) { + if (end_pos_ == 2 * max_size) { + std::copy_n(&saved_message_ids_[max_size], max_size, &saved_message_ids_[0]); + end_pos_ = max_size; + } + if (end_pos_ == 0 || message_id > saved_message_ids_[end_pos_ - 1]) { + // fast path + saved_message_ids_[end_pos_++] = message_id; + return td::Status::OK(); + } + if (end_pos_ >= max_size && message_id < saved_message_ids_[0]) { + return td::Status::Error(2, PSLICE() << "Ignore very old message_id " + << td::tag("oldest message_id", saved_message_ids_[0]) + << td::tag("got message_id", message_id)); + } + auto it = std::lower_bound(&saved_message_ids_[0], &saved_message_ids_[end_pos_], message_id); + if (*it == message_id) { + return td::Status::Error(1, PSLICE() << "Ignore duplicated message_id " << td::tag("message_id", message_id)); + } + std::copy_backward(it, &saved_message_ids_[end_pos_], &saved_message_ids_[end_pos_ + 1]); + *it = message_id; + ++end_pos_; + return td::Status::OK(); + } + + private: + std::array saved_message_ids_; + std::size_t end_pos_ = 0; +}; + +template +class DuplicateCheckerBench final : public td::Benchmark { + td::string get_description() const final { + return PSTRING() << "DuplicateCheckerBench" << T::get_description(); + } + void run(int n) final { + T checker_; + for (int i = 0; i < n; i++) { + checker_.check(i).ensure(); + } + } +}; + +template +class DuplicateCheckerBenchRepeat final : public td::Benchmark { + td::string get_description() const final { + return PSTRING() << "DuplicateCheckerBenchRepeat" << T::get_description(); + } + void run(int n) final { + T checker_; + for (int i = 0; i < n; i++) { + auto iter = i >> 10; + auto pos = i - (iter << 10); + if (pos < 768) { + if (iter >= 3 && pos == 0) { + auto error = checker_.check((iter - 3) * 768 + pos); + CHECK(error.error().code() == 2); + } + checker_.check(iter * 768 + pos).ensure(); + } else { + checker_.check(iter * 768 + pos - 256).ensure_error(); + } + } + } +}; + +template +class DuplicateCheckerBenchRepeatOnly final : public td::Benchmark { + td::string get_description() const final { + return PSTRING() << "DuplicateCheckerBenchRepeatOnly" << T::get_description(); + } + void run(int n) final { + T checker_; + for (int i = 0; i < n; i++) { + auto result = checker_.check(i & 255); + CHECK(result.is_error() == (i >= 256)); + } + } +}; + +template +class DuplicateCheckerBenchReverse final : public td::Benchmark { + td::string get_description() const final { + return PSTRING() << "DuplicateCheckerBenchReverseAdd" << T::get_description(); + } + void run(int n) final { + T checker_; + for (int i = 0; i < n; i++) { + auto pos = i & 255; + checker_.check(i - pos + (255 - pos)).ensure(); + } + } +}; + +template +class DuplicateCheckerBenchEvenOdd final : public td::Benchmark { + td::string get_description() const final { + return PSTRING() << "DuplicateCheckerBenchEvenOdd" << T::get_description(); + } + void run(int n) final { + T checker_; + for (int i = 0; i < n; i++) { + auto pos = i & 255; + checker_.check(i - pos + (pos * 2) % 256 + (pos * 2) / 256).ensure(); + } + } +}; int main() { SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG)); + + td::bench(DuplicateCheckerBenchEvenOdd>()); + td::bench(DuplicateCheckerBenchEvenOdd>()); + td::bench(DuplicateCheckerBenchEvenOdd>()); + td::bench(DuplicateCheckerBenchEvenOdd>()); + + td::bench(DuplicateCheckerBenchReverse>()); + td::bench(DuplicateCheckerBenchReverse>()); + td::bench(DuplicateCheckerBenchReverse>()); + td::bench(DuplicateCheckerBenchReverse>()); + + td::bench(DuplicateCheckerBenchRepeatOnly>()); + td::bench(DuplicateCheckerBenchRepeatOnly>()); + td::bench(DuplicateCheckerBenchRepeatOnly>()); + td::bench(DuplicateCheckerBenchRepeatOnly>()); + + td::bench(DuplicateCheckerBenchRepeat()); + td::bench(DuplicateCheckerBenchRepeat>()); + td::bench(DuplicateCheckerBenchRepeat()); + td::bench(DuplicateCheckerBenchRepeat()); + td::bench(DuplicateCheckerBenchRepeat>()); + td::bench(DuplicateCheckerBenchRepeat>()); + td::bench(DuplicateCheckerBenchRepeat>()); + + td::bench(DuplicateCheckerBench()); + td::bench(DuplicateCheckerBench>()); + td::bench(DuplicateCheckerBench()); + td::bench(DuplicateCheckerBench()); + td::bench(DuplicateCheckerBench>()); + td::bench(DuplicateCheckerBench>()); + td::bench(DuplicateCheckerBench>()); + td::bench(DuplicateCheckerBench>()); + td::bench(DuplicateCheckerBench>()); + #if !TD_THREAD_UNSUPPORTED - td::bench(td::AtomicReleaseIncBench<1>()); - td::bench(td::AtomicReleaseIncBench<2>()); - td::bench(td::AtomicReleaseCasIncBench<1>()); - td::bench(td::AtomicReleaseCasIncBench<2>()); - td::bench(td::RwMutexWriteBench<1>()); - td::bench(td::RwMutexReadBench<1>()); - td::bench(td::RwMutexWriteBench<>()); - td::bench(td::RwMutexReadBench<>()); + for (int i = 1; i <= 16; i *= 2) { + td::bench(ThreadSafeCounterBench(i)); + td::bench(AtomicCounterBench(i)); + td::bench(AtomicCounterBench(i)); + } + + td::bench(AtomicReleaseIncBench<1>()); + td::bench(AtomicReleaseIncBench<2>()); + td::bench(AtomicReleaseCasIncBench<1>()); + td::bench(AtomicReleaseCasIncBench<2>()); + td::bench(RwMutexWriteBench<1>()); + td::bench(RwMutexReadBench<1>()); + td::bench(RwMutexWriteBench<2>()); + td::bench(RwMutexReadBench<2>()); #endif #if !TD_WINDOWS - td::bench(td::UtimeBench()); + td::bench(UtimeBench()); #endif - td::bench(td::WalkPathBench()); - td::bench(td::CreateFileBench()); - td::bench(td::PwriteBench()); + td::bench(WalkPathBench()); + td::bench(CreateFileBench()); + td::bench(PwriteBench()); - td::bench(td::CallBench()); + td::bench(CallBench()); #if !TD_THREAD_UNSUPPORTED - td::bench(td::ThreadNewBench()); + td::bench(ThreadNewBench()); #endif #if !TD_EVENTFD_UNSUPPORTED - td::bench(td::EventFdBench()); + td::bench(EventFdBench()); #endif - td::bench(td::NewObjBench()); - td::bench(td::NewIntBench()); + td::bench(NewObjBench()); + td::bench(NewIntBench()); #if !TD_WINDOWS - td::bench(td::PipeBench()); + td::bench(PipeBench()); #endif #if TD_LINUX || TD_ANDROID || TD_TIZEN - td::bench(td::SemBench()); + td::bench(SemBench()); #endif } diff --git a/lib/tgchat/ext/td/benchmark/bench_queue.cpp b/lib/tgchat/ext/td/benchmark/bench_queue.cpp index f8dedbe7..6205f37b 100644 --- a/lib/tgchat/ext/td/benchmark/bench_queue.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_queue.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -17,15 +17,14 @@ // TODO: all return values must be checked #include -#include -#include -#include +#if TD_PORT_POSIX #include #include #include #include #include +#endif #if TD_LINUX #include @@ -34,17 +33,31 @@ #define MODE std::memory_order_relaxed // void set_affinity(int mask) { -// int err, syscallres; -// pid_t pid = gettid(); -// syscallres = syscall(__NR_sched_setaffinity, pid, sizeof(mask), &mask); -// if (syscallres) { -// err = errno; -// perror("oppa"); -//} -//} +// pid_t pid = gettid(); +// int syscallres = syscall(__NR_sched_setaffinity, pid, sizeof(mask), &mask); +// if (syscallres) { +// perror("Failed to set affinity"); +// } +// } using qvalue_t = int; +class Backoff { + int cnt = 0; + + public: + bool next() { + cnt++; + if (cnt < 50) { + return true; + } else { + td::this_thread::yield(); + return cnt < 500; + } + } +}; + +#if TD_PORT_POSIX // Just for testing, not production class PipeQueue { int input; @@ -77,24 +90,6 @@ class PipeQueue { } }; -class Backoff { - int cnt; - - public: - Backoff() : cnt(0) { - } - - bool next() { - cnt++; - if (cnt < 50) { - return true; - } else { - sched_yield(); - return cnt < 500; - } - } -}; - class VarQueue { std::atomic data{0}; @@ -178,6 +173,7 @@ class SemQueue { return get(); } }; +#endif #if TD_LINUX class EventfdQueue { @@ -320,8 +316,7 @@ class BufferQueue { return; } if (!update_writer()) { - std::fprintf(stderr, "put strong failed\n"); - std::exit(0); + LOG(FATAL) << "Put strong failed"; } put_unsafe(val); } @@ -474,10 +469,9 @@ class FdQueue { td::int64 x; wait_flag.store(1, MODE); __sync_synchronize(); - // std::fprintf(stderr, "!\n"); // while (res == -1 && read(fd, &x, sizeof(x)) == sizeof(x)) { - // res = q.try_get(); - //} + // res = q.try_get(); + // } do { __sync_synchronize(); res = q.try_get(); @@ -493,6 +487,7 @@ class FdQueue { }; #endif +#if TD_PORT_POSIX class SemBackoffQueue { sem_t sem; VarQueue q; @@ -562,46 +557,40 @@ class SemCheatQueue { }; template -class QueueBenchmark2 : public td::Benchmark { +class QueueBenchmark2 final : public td::Benchmark { QueueT client, server; int connections_n, queries_n; int server_active_connections; int client_active_connections; - std::vector server_conn; - std::vector client_conn; + td::vector server_conn; + td::vector client_conn; + + td::string name; public: - explicit QueueBenchmark2(int connections_n = 1) : connections_n(connections_n) { + QueueBenchmark2(int connections_n, td::string name) : connections_n(connections_n), name(std::move(name)) { } - std::string get_description() const override { - return "QueueBenchmark2"; + td::string get_description() const final { + return name; } - void start_up() override { + void start_up() final { client.init(); server.init(); } - void tear_down() override { + void tear_down() final { client.destroy(); server.destroy(); } void server_process(qvalue_t value) { int no = value & 0x00FFFFFF; - int co = static_cast(static_cast(value) >> 24); - // std::fprintf(stderr, "-->%d %d\n", co, no); - if (co < 0 || co >= connections_n || no != server_conn[co]++) { - std::fprintf(stderr, "%d %d\n", co, no); - std::fprintf(stderr, "expected %d %lld\n", co, static_cast(server_conn[co] - 1)); - std::fprintf(stderr, "Server BUG\n"); - while (true) { - } - } - // std::fprintf(stderr, "no = %d/%d\n", no, queries_n); - // std::fprintf(stderr, "answer: %d %d\n", no, co); + auto co = static_cast(static_cast(value) >> 24); + CHECK(co >= 0 && co < connections_n); + CHECK(no == server_conn[co]++); client.writer_put(value); client.writer_flush(); @@ -611,15 +600,12 @@ class QueueBenchmark2 : public td::Benchmark { } void *server_run(void *) { - server_conn = std::vector(connections_n); + server_conn = td::vector(connections_n); server_active_connections = connections_n; while (server_active_connections > 0) { int cnt = server.reader_wait(); - if (cnt == 0) { - std::fprintf(stderr, "ERROR!\n"); - std::exit(0); - } + CHECK(cnt != 0); while (cnt-- > 0) { server_process(server.reader_get_unsafe()); server.reader_flush(); @@ -632,18 +618,10 @@ class QueueBenchmark2 : public td::Benchmark { void client_process(qvalue_t value) { int no = value & 0x00FFFFFF; - int co = static_cast(static_cast(value) >> 24); - // std::fprintf(stderr, "<--%d %d\n", co, no); - if (co < 0 || co >= connections_n || no != client_conn[co]++) { - std::fprintf(stderr, "%d %d\n", co, no); - std::fprintf(stderr, "expected %d %lld\n", co, static_cast(client_conn[co] - 1)); - std::fprintf(stderr, "BUG\n"); - while (true) { - } - std::exit(0); - } + auto co = static_cast(static_cast(value) >> 24); + CHECK(co >= 0 && co < connections_n); + CHECK(no == client_conn[co]++); if (no + 1 < queries_n) { - // std::fprintf(stderr, "query: %d %d\n", no + 1, co); server.writer_put(value + 1); server.writer_flush(); } else { @@ -652,12 +630,9 @@ class QueueBenchmark2 : public td::Benchmark { } void *client_run(void *) { - client_conn = std::vector(connections_n); + client_conn = td::vector(connections_n); client_active_connections = connections_n; - if (queries_n >= (1 << 24)) { - std::fprintf(stderr, "Too big queries_n\n"); - std::exit(0); - } + CHECK(queries_n < (1 << 24)); for (int i = 0; i < connections_n; i++) { server.writer_put(static_cast(i) << 24); @@ -666,10 +641,7 @@ class QueueBenchmark2 : public td::Benchmark { while (client_active_connections > 0) { int cnt = client.reader_wait(); - if (cnt == 0) { - std::fprintf(stderr, "ERROR!\n"); - std::exit(0); - } + CHECK(cnt != 0); while (cnt-- > 0) { client_process(client.reader_get_unsafe()); client.reader_flush(); @@ -689,7 +661,7 @@ class QueueBenchmark2 : public td::Benchmark { return static_cast(arg)->server_run(nullptr); } - void run(int n) override { + void run(int n) final { pthread_t client_thread_id; pthread_t server_thread_id; @@ -704,45 +676,40 @@ class QueueBenchmark2 : public td::Benchmark { }; template -class QueueBenchmark : public td::Benchmark { +class QueueBenchmark final : public td::Benchmark { QueueT client, server; const int connections_n; int queries_n; + td::string name; + public: - explicit QueueBenchmark(int connections_n = 1) : connections_n(connections_n) { + QueueBenchmark(int connections_n, td::string name) : connections_n(connections_n), name(std::move(name)) { } - std::string get_description() const override { - return "QueueBenchmark"; + td::string get_description() const final { + return name; } - void start_up() override { + void start_up() final { client.init(); server.init(); } - void tear_down() override { + void tear_down() final { client.destroy(); server.destroy(); } void *server_run(void *) { - std::vector conn(connections_n); + td::vector conn(connections_n); int active_connections = connections_n; while (active_connections > 0) { qvalue_t value = server.get(); int no = value & 0x00FFFFFF; - int co = static_cast(value >> 24); - // std::fprintf(stderr, "-->%d %d\n", co, no); - if (co < 0 || co >= connections_n || no != conn[co]++) { - std::fprintf(stderr, "%d %d\n", co, no); - std::fprintf(stderr, "expected %d %lld\n", co, static_cast(conn[co] - 1)); - std::fprintf(stderr, "Server BUG\n"); - while (true) { - } - } - // std::fprintf(stderr, "no = %d/%d\n", no, queries_n); + auto co = static_cast(value >> 24); + CHECK(co >= 0 && co < connections_n); + CHECK(no == conn[co]++); client.put(value); if (no + 1 >= queries_n) { active_connections--; @@ -752,11 +719,8 @@ class QueueBenchmark : public td::Benchmark { } void *client_run(void *) { - std::vector conn(connections_n); - if (queries_n >= (1 << 24)) { - std::fprintf(stderr, "Too big queries_n\n"); - std::exit(0); - } + td::vector conn(connections_n); + CHECK(queries_n < (1 << 24)); for (int i = 0; i < connections_n; i++) { server.put(static_cast(i) << 24); } @@ -764,16 +728,9 @@ class QueueBenchmark : public td::Benchmark { while (active_connections > 0) { qvalue_t value = client.get(); int no = value & 0x00FFFFFF; - int co = static_cast(value >> 24); - // std::fprintf(stderr, "<--%d %d\n", co, no); - if (co < 0 || co >= connections_n || no != conn[co]++) { - std::fprintf(stderr, "%d %d\n", co, no); - std::fprintf(stderr, "expected %d %lld\n", co, static_cast(conn[co] - 1)); - std::fprintf(stderr, "BUG\n"); - while (true) { - } - std::exit(0); - } + auto co = static_cast(value >> 24); + CHECK(co >= 0 && co < connections_n); + CHECK(no == conn[co]++); if (no + 1 < queries_n) { server.put(value + 1); } else { @@ -785,11 +742,8 @@ class QueueBenchmark : public td::Benchmark { } void *client_run2(void *) { - std::vector conn(connections_n); - if (queries_n >= (1 << 24)) { - std::fprintf(stderr, "Too big queries_n\n"); - std::exit(0); - } + td::vector conn(connections_n); + CHECK(queries_n < (1 << 24)); for (int query = 0; query < queries_n; query++) { for (int i = 0; i < connections_n; i++) { server.put((static_cast(i) << 24) + query); @@ -797,16 +751,9 @@ class QueueBenchmark : public td::Benchmark { for (int i = 0; i < connections_n; i++) { qvalue_t value = client.get(); int no = value & 0x00FFFFFF; - int co = static_cast(value >> 24); - // std::fprintf(stderr, "<--%d %d\n", co, no); - if (co < 0 || co >= connections_n || no != conn[co]++) { - std::fprintf(stderr, "%d %d\n", co, no); - std::fprintf(stderr, "expected %d %lld\n", co, static_cast(conn[co] - 1)); - std::fprintf(stderr, "BUG\n"); - while (true) { - } - std::exit(0); - } + auto co = static_cast(value >> 24); + CHECK(co >= 0 && co < connections_n); + CHECK(no == conn[co]++); } } // system("cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"); @@ -821,7 +768,7 @@ class QueueBenchmark : public td::Benchmark { return static_cast(arg)->server_run(nullptr); } - void run(int n) override { + void run(int n) final { pthread_t client_thread_id; pthread_t server_thread_id; @@ -836,7 +783,7 @@ class QueueBenchmark : public td::Benchmark { }; template -class RingBenchmark : public td::Benchmark { +class RingBenchmark final : public td::Benchmark { static constexpr int QN = 504; struct Thread { @@ -848,7 +795,6 @@ class RingBenchmark : public td::Benchmark { void *run() { qvalue_t value; - // std::fprintf(stderr, "start %d\n", int_id); do { int cnt = queue.reader_wait(); CHECK(cnt == 1); @@ -869,7 +815,7 @@ class RingBenchmark : public td::Benchmark { return static_cast(arg)->run(); } - void start_up() override { + void start_up() final { for (int i = 0; i < QN; i++) { q[i].int_id = i; q[i].queue.init(); @@ -877,18 +823,17 @@ class RingBenchmark : public td::Benchmark { } } - void tear_down() override { + void tear_down() final { for (int i = 0; i < QN; i++) { q[i].queue.destroy(); } } - void run(int n) override { + void run(int n) final { for (int i = 0; i < QN; i++) { pthread_create(&q[i].id, nullptr, run_gateway, &q[i]); } - std::fprintf(stderr, "run %d\n", n); if (n < 1000) { n = 1000; } @@ -900,11 +845,14 @@ class RingBenchmark : public td::Benchmark { } } }; +#endif -void test_queue() { - std::vector threads; +/* +#if !TD_THREAD_UNSUPPORTED && !TD_EVENTFD_UNSUPPORTED +static void test_queue() { + td::vector threads; static constexpr size_t THREAD_COUNT = 100; - std::vector> queues(THREAD_COUNT); + td::vector> queues(THREAD_COUNT); for (auto &q : queues) { q.init(); } @@ -920,58 +868,66 @@ void test_queue() { }); } - while (true) { + for (size_t iter = 0; iter < THREAD_COUNT; iter++) { td::usleep_for(100); for (int i = 0; i < 5; i++) { queues[td::Random::fast(0, THREAD_COUNT - 1)].writer_put(1); } } + + for (size_t i = 0; i < THREAD_COUNT; i++) { + threads[i].join(); + } } +#endif +*/ int main() { - SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG)); - //test_queue(); -#define BENCH_Q2(Q, N) \ - std::fprintf(stderr, "!%s %d:\t", #Q, N); \ - td::bench(QueueBenchmark2(N)); -#define BENCH_Q(Q, N) \ - std::fprintf(stderr, "%s %d:\t", #Q, N); \ - td::bench(QueueBenchmark(N)); - -#define BENCH_R(Q) \ - std::fprintf(stderr, "%s:\t", #Q); \ - td::bench(RingBenchmark()); +#if !TD_THREAD_UNSUPPORTED && !TD_EVENTFD_UNSUPPORTED + // test_queue(); +#endif + +#if TD_PORT_POSIX // TODO: yield makes it extremely slow. Yet some backoff may be necessary. - // BENCH_R(SemQueue); - // BENCH_R(td::PollQueue); + // td::bench(RingBenchmark()); + // td::bench(RingBenchmark>()); - BENCH_Q2(td::PollQueue, 1); - BENCH_Q2(td::MpscPollableQueue, 1); - BENCH_Q2(td::PollQueue, 100); - BENCH_Q2(td::MpscPollableQueue, 100); - BENCH_Q2(td::PollQueue, 10); - BENCH_Q2(td::MpscPollableQueue, 10); +#define BENCH_Q2(Q, N) td::bench(QueueBenchmark2>(N, #Q "(" #N ")")) - BENCH_Q(VarQueue, 1); - // BENCH_Q(FdQueue, 1); - // BENCH_Q(BufferedFdQueue, 1); - BENCH_Q(PipeQueue, 1); - BENCH_Q(SemCheatQueue, 1); - BENCH_Q(SemQueue, 1); +#if !TD_THREAD_UNSUPPORTED && !TD_EVENTFD_UNSUPPORTED + BENCH_Q2(td::InfBackoffQueue, 1); + BENCH_Q2(td::MpscPollableQueue, 1); + BENCH_Q2(td::PollQueue, 1); - // BENCH_Q2(td::PollQueue, 100); - // BENCH_Q2(td::PollQueue, 10); - // BENCH_Q2(td::PollQueue, 4); - // BENCH_Q2(td::InfBackoffQueue, 100); + BENCH_Q2(td::InfBackoffQueue, 10); + BENCH_Q2(td::MpscPollableQueue, 10); + BENCH_Q2(td::PollQueue, 10); - // BENCH_Q2(td::InfBackoffQueue, 1); - // BENCH_Q(SemCheatQueue, 1); + BENCH_Q2(td::InfBackoffQueue, 100); + BENCH_Q2(td::MpscPollableQueue, 100); + BENCH_Q2(td::PollQueue, 100); - // BENCH_Q(BufferedFdQueue, 100); - // BENCH_Q(BufferedFdQueue, 10); + BENCH_Q2(td::PollQueue, 4); + BENCH_Q2(td::PollQueue, 10); + BENCH_Q2(td::PollQueue, 100); +#endif + +#define BENCH_Q(Q, N) td::bench(QueueBenchmark(N, #Q "(" #N ")")) - // BENCH_Q(BufferQueue, 4); - // BENCH_Q(BufferQueue, 100); - // BENCH_Q(BufferQueue, 10); - // BENCH_Q(BufferQueue, 1); +#if TD_LINUX + BENCH_Q(BufferQueue, 1); + BENCH_Q(BufferedFdQueue, 1); + BENCH_Q(FdQueue, 1); +#endif + BENCH_Q(PipeQueue, 1); + BENCH_Q(SemCheatQueue, 1); + BENCH_Q(SemQueue, 1); + BENCH_Q(VarQueue, 1); + +#if TD_LINUX + BENCH_Q(BufferQueue, 4); + BENCH_Q(BufferQueue, 10); + BENCH_Q(BufferQueue, 100); +#endif +#endif } diff --git a/lib/tgchat/ext/td/benchmark/bench_tddb.cpp b/lib/tgchat/ext/td/benchmark/bench_tddb.cpp index 33427055..f079ff28 100644 --- a/lib/tgchat/ext/td/benchmark/bench_tddb.cpp +++ b/lib/tgchat/ext/td/benchmark/bench_tddb.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -11,12 +11,13 @@ #include "td/telegram/ServerMessageId.h" #include "td/telegram/UserId.h" -#include "td/actor/ConcurrentScheduler.h" -#include "td/actor/PromiseFuture.h" - +#include "td/db/DbKey.h" #include "td/db/SqliteConnectionSafe.h" #include "td/db/SqliteDb.h" +#include "td/actor/ConcurrentScheduler.h" +#include "td/actor/PromiseFuture.h" + #include "td/utils/benchmark.h" #include "td/utils/buffer.h" #include "td/utils/common.h" @@ -26,48 +27,46 @@ #include -namespace td { - -static Status init_db(SqliteDb &db) { +static td::Status init_db(td::SqliteDb &db) { TRY_STATUS(db.exec("PRAGMA encoding=\"UTF-8\"")); TRY_STATUS(db.exec("PRAGMA synchronous=NORMAL")); TRY_STATUS(db.exec("PRAGMA journal_mode=WAL")); TRY_STATUS(db.exec("PRAGMA temp_store=MEMORY")); TRY_STATUS(db.exec("PRAGMA secure_delete=1")); - return Status::OK(); + return td::Status::OK(); } -class MessagesDbBench : public Benchmark { +class MessagesDbBench final : public td::Benchmark { public: - string get_description() const override { + td::string get_description() const final { return "MessagesDb"; } - void start_up() override { + void start_up() final { LOG(ERROR) << "START UP"; do_start_up().ensure(); scheduler_->start(); } - void run(int n) override { + void run(int n) final { auto guard = scheduler_->get_main_guard(); for (int i = 0; i < n; i += 20) { - auto dialog_id = DialogId{UserId{Random::fast(1, 100)}}; - auto message_id_raw = Random::fast(1, 100000); + auto dialog_id = td::DialogId(td::UserId(static_cast(td::Random::fast(1, 100)))); + auto message_id_raw = td::Random::fast(1, 100000); for (int j = 0; j < 20; j++) { - auto message_id = MessageId{ServerMessageId{message_id_raw + j}}; - auto unique_message_id = ServerMessageId{i + 1}; - auto sender_user_id = UserId{Random::fast(1, 1000)}; + auto message_id = td::MessageId{td::ServerMessageId{message_id_raw + j}}; + auto unique_message_id = td::ServerMessageId{i + 1}; + auto sender_user_id = td::UserId(static_cast(td::Random::fast(1, 1000))); auto random_id = i + 1; auto ttl_expires_at = 0; - auto data = BufferSlice(Random::fast(100, 299)); + auto data = td::BufferSlice(td::Random::fast(100, 299)); // use async on same thread. messages_db_async_->add_message({dialog_id, message_id}, unique_message_id, sender_user_id, random_id, - ttl_expires_at, 0, 0, "", NotificationId(), MessageId(), std::move(data), - Promise<>()); + ttl_expires_at, 0, 0, "", td::NotificationId(), td::MessageId(), + std::move(data), td::Promise<>()); } } } - void tear_down() override { + void tear_down() final { scheduler_->run_main(0.1); { auto guard = scheduler_->get_main_guard(); @@ -82,19 +81,19 @@ class MessagesDbBench : public Benchmark { } private: - td::unique_ptr scheduler_; - std::shared_ptr sql_connection_; - std::shared_ptr messages_db_sync_safe_; - std::shared_ptr messages_db_async_; + td::unique_ptr scheduler_; + std::shared_ptr sql_connection_; + std::shared_ptr messages_db_sync_safe_; + std::shared_ptr messages_db_async_; - Status do_start_up() { - scheduler_ = make_unique(); + td::Status do_start_up() { + scheduler_ = td::make_unique(); scheduler_->init(1); auto guard = scheduler_->get_main_guard(); - string sql_db_name = "testdb.sqlite"; - sql_connection_ = std::make_shared(sql_db_name); + td::string sql_db_name = "testdb.sqlite"; + sql_connection_ = std::make_shared(sql_db_name, td::DbKey::empty()); auto &db = sql_connection_->get(); TRY_STATUS(init_db(db)); @@ -103,14 +102,13 @@ class MessagesDbBench : public Benchmark { TRY_STATUS(init_messages_db(db, 0)); db.exec("COMMIT TRANSACTION").ensure(); - messages_db_sync_safe_ = create_messages_db_sync(sql_connection_); - messages_db_async_ = create_messages_db_async(messages_db_sync_safe_, 0); - return Status::OK(); + messages_db_sync_safe_ = td::create_messages_db_sync(sql_connection_); + messages_db_async_ = td::create_messages_db_async(messages_db_sync_safe_, 0); + return td::Status::OK(); } }; -} // namespace td int main() { SET_VERBOSITY_LEVEL(VERBOSITY_NAME(WARNING)); - bench(td::MessagesDbBench()); + td::bench(MessagesDbBench()); } diff --git a/lib/tgchat/ext/td/benchmark/check_proxy.cpp b/lib/tgchat/ext/td/benchmark/check_proxy.cpp index 7b9a1480..965418ce 100644 --- a/lib/tgchat/ext/td/benchmark/check_proxy.cpp +++ b/lib/tgchat/ext/td/benchmark/check_proxy.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -12,6 +12,7 @@ #include "td/utils/filesystem.h" #include "td/utils/logging.h" #include "td/utils/misc.h" +#include "td/utils/TsCerr.h" #include #include diff --git a/lib/tgchat/ext/td/benchmark/check_tls.cpp b/lib/tgchat/ext/td/benchmark/check_tls.cpp index a60d64f1..b2fa2ecd 100644 --- a/lib/tgchat/ext/td/benchmark/check_tls.cpp +++ b/lib/tgchat/ext/td/benchmark/check_tls.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,6 +16,7 @@ #include "td/utils/port/thread.h" #include "td/utils/Random.h" #include "td/utils/Slice.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Status.h" #include "td/utils/Time.h" @@ -95,8 +96,8 @@ td::Result test_tls(const td::string &url) { const size_t MAX_GREASE = 7; char greases[MAX_GREASE]; td::Random::secure_bytes(td::MutableSlice{greases, MAX_GREASE}); - for (size_t i = 0; i < MAX_GREASE; i++) { - greases[i] = static_cast((greases[i] & 0xF0) + 0x0A); + for (auto &grease : greases) { + grease = static_cast((grease & 0xF0) + 0x0A); } for (size_t i = 1; i < MAX_GREASE; i += 2) { if (greases[i] == greases[i - 1]) { diff --git a/lib/tgchat/ext/td/benchmark/rmdir.cpp b/lib/tgchat/ext/td/benchmark/rmdir.cpp index 0c573e32..77b45d75 100644 --- a/lib/tgchat/ext/td/benchmark/rmdir.cpp +++ b/lib/tgchat/ext/td/benchmark/rmdir.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/benchmark/wget.cpp b/lib/tgchat/ext/td/benchmark/wget.cpp index d1f32612..357ebd03 100644 --- a/lib/tgchat/ext/td/benchmark/wget.cpp +++ b/lib/tgchat/ext/td/benchmark/wget.cpp @@ -1,16 +1,16 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // +#include "td/net/HttpQuery.h" +#include "td/net/Wget.h" + #include "td/actor/actor.h" #include "td/actor/ConcurrentScheduler.h" #include "td/actor/PromiseFuture.h" -#include "td/net/HttpQuery.h" -#include "td/net/Wget.h" - #include "td/utils/common.h" #include "td/utils/logging.h" #include "td/utils/Status.h" diff --git a/lib/tgchat/ext/td/build.html b/lib/tgchat/ext/td/build.html index cfd2b192..3cf8802d 100644 --- a/lib/tgchat/ext/td/build.html +++ b/lib/tgchat/ext/td/build.html @@ -2,18 +2,185 @@ -TDLib build instructions - + TDLib build instructions +
-
+

Choose a programming language, from which you want to use TDLib:

-
+

Choose an operating system, on which you want to use TDLib:

@@ -61,7 +228,7 @@ - + @@ -71,7 +238,7 @@

-
+
@@ -133,14 +300,17 @@

-
+

Hidden text

-
-

Here is complete instruction for TDLib binaries building:

+
+

Here is complete instruction for TDLib binaries building:

Hidden text

Empty commands +
@@ -229,7 +399,7 @@ if (supported_os.length) { document.getElementById('osSelectDiv').style.display = 'block'; } else { - if (history.state != '') { + if (history.state !== '' && history.state !== null) { history.pushState('', '', 'build.html'); } document.getElementById('osSelectDiv').style.display = 'none'; @@ -501,7 +671,6 @@ pre_text.push('Download and install Microsoft Visual Studio. Enable C++' + win10_sdk + ' support while installing.'); pre_text.push('Download and install CMake; choose "Add CMake to the system PATH" option while installing.'); pre_text.push('Download and install Git.'); - pre_text.push('Download and install gperf. Add the path to gperf.exe to the PATH environment variable.'); pre_text.push('Download and unpack PHP. Add the path to php.exe to the PATH environment variable.'); if (target === 'C++/CX') { switch (archiver) { @@ -526,7 +695,7 @@ } if (os_linux && linux_distro === 'Other') { var jdk = target === 'JNI' ? ', JDK ' : ''; - var compiler = use_clang ? 'clang >= 3.4' : 'g++ >= 4.9.2'; + var compiler = use_clang ? 'clang >= 3.4, libc++' : 'g++ >= 4.9.2'; pre_text.push('Install Git, ' + compiler + ', make, CMake >= 3.0.2, OpenSSL-dev, zlib-dev, gperf, PHP' + jdk + ' using your package manager.'); } if (os_linux && os.includes('Node.js')) { @@ -543,6 +712,10 @@ if (os_netbsd) { pre_text.push('Note that the following instruction is for NetBSD 8.0 and default SH shell.'); } + if (os_mac) { + pre_text.push('Note that the following instruction will build TDLib only for the current architecture (x64 or Apple silicon).'); + pre_text.push('If you want to create a universal XCFramework, take a look at our example instead.'); + } var terminal_name = (function () { if (os_windows) { @@ -626,7 +799,7 @@ cmake = 'cmake3'; packages += ' gperf'; } else { - commands.push(sudo + 'dnf --enablerepo=PowerTools install gperf'); + commands.push(sudo + 'dnf --enablerepo=powertools install gperf'); } packages += ' ' + cmake; if (target === 'JNI') { @@ -636,7 +809,7 @@ break; case 'Debian 8': case 'Debian 9': - case 'Debian 10': + case 'Debian 10+': case 'Ubuntu 14': case 'Ubuntu 16': case 'Ubuntu 18': @@ -665,7 +838,7 @@ } if (use_clang) { packages += ' clang' + getClangVersionSuffix() + ' libc++-dev'; - if (linux_distro === 'Debian 10' || linux_distro === 'Ubuntu 18' || linux_distro === 'Ubuntu 20') { + if (linux_distro === 'Debian 10+' || linux_distro === 'Ubuntu 18' || linux_distro === 'Ubuntu 20') { packages += ' libc++abi-dev'; } } else { @@ -715,19 +888,19 @@ commands.push('git clone https://github.com/tdlib/td.git'); commands.push('cd td'); - commands.push('git checkout v1.7.0'); + // commands.push('git checkout v1.7.0'); if (use_vcpkg) { commands.push('git clone https://github.com/Microsoft/vcpkg.git'); commands.push('cd vcpkg'); commands.push(local + 'bootstrap-vcpkg.bat'); if (target === 'C++/CX') { - commands.push(local + 'vcpkg.exe install openssl-uwp:arm-uwp openssl-uwp:x64-uwp openssl-uwp:x86-uwp zlib:arm-uwp zlib:x64-uwp zlib:x86-uwp'); + commands.push(local + 'vcpkg.exe install gperf:x86-windows openssl:arm-uwp openssl:arm64-uwp openssl:x64-uwp openssl:x86-uwp zlib:arm-uwp zlib:arm64-uwp zlib:x64-uwp zlib:x86-uwp'); } else { if (build_64bit) { - commands.push(local + 'vcpkg.exe install openssl:x64-windows zlib:x64-windows'); + commands.push(local + 'vcpkg.exe install gperf:x64-windows openssl:x64-windows zlib:x64-windows'); } else { - commands.push(local + 'vcpkg.exe install openssl:x86-windows zlib:x86-windows'); + commands.push(local + 'vcpkg.exe install gperf:x86-windows openssl:x86-windows zlib:x86-windows'); } } commands.push('cd ..'); @@ -771,7 +944,7 @@ break; } - commands.push('powershell -ExecutionPolicy ByPass ' + local + 'build.ps1 -mode clean'); + commands.push('powershell -ExecutionPolicy ByPass ' + local + 'build.ps1 -vcpkg_root ../../vcpkg -mode clean'); commands.push('powershell -ExecutionPolicy ByPass ' + local + 'build.ps1 -vcpkg_root ../../vcpkg' + archiver_option); if (install_dir) { commands.push('cp build-uwp/vsix/tdlib.vsix ' + install_dir); @@ -900,6 +1073,26 @@ commands.push((use_powershell ? 'dir ' : 'ls -l ') + install_dir); } document.getElementById('buildCommands').innerHTML = '
  • ' + commands.join('
  • ') + '
'; + document.getElementById('copyBuildCommandsButton').style.display = commands.includes('exit') ? 'none' : 'block'; +} + +function copyBuildInstructions() { + var text = document.getElementById('buildCommands').innerText; + + function resetButtonState (state) { + document.getElementById('copyBuildCommandsButton').classList.remove(state); + document.getElementById('copyBuildCommandsText').innerText = "Copy"; + } + + navigator.clipboard.writeText(text).then(result => { + document.getElementById('copyBuildCommandsButton').classList.add('success'); + document.getElementById('copyBuildCommandsText').innerText = "Copied!"; + setTimeout(() => resetButtonState('success'), 5000); + }, error => { + document.getElementById('copyBuildCommandsButton').classList.add('fail'); + document.getElementById('copyBuildCommandsText').innerText = "Couldn't copy :("; + setTimeout(() => resetButtonState('fail'), 5000); + }) } diff --git a/lib/tgchat/ext/td/example/README.md b/lib/tgchat/ext/td/example/README.md index b00d12b5..86233e2a 100644 --- a/lib/tgchat/ext/td/example/README.md +++ b/lib/tgchat/ext/td/example/README.md @@ -43,10 +43,13 @@ TDLib can be used from Python through the [JSON](https://github.com/tdlib/td#usi Convenient Python wrappers already exist for our JSON interface. -If you use modern Python >= 3.6, take a look at [python-telegram](https://github.com/alexander-akhmetov/python-telegram). +If you use Python >= 3.6, take a look at [python-telegram](https://github.com/alexander-akhmetov/python-telegram). The wrapper uses the full power of asyncio, has a good documentation and has several examples. It can be installed through pip or used in a Docker container. You can also try a fork [python-telegram](https://github.com/iTeam-co/python-telegram) of this library. +If you want to use TDLib with asyncio and Python >= 3.9, take a look at [aiotdlib](https://github.com/pylakey/aiotdlib). +This wrapper contains automatically generated fully-documented classes for all TDLib API types and functions and provides set of helper methods which makes work with TDLib much simpler. + For older Python versions you can use [pytdlib](https://github.com/pytdlib/pytdlib). This wrapper contains generator for TDLib API classes and basic interface for interaction with TDLib. @@ -125,18 +128,19 @@ TDLib has a simple and convenient C++11-interface for sending and receiving requ See [example/cpp](https://github.com/tdlib/td/tree/master/example/cpp) for an example of TDLib usage from C++. [td_example.cpp](https://github.com/tdlib/td/tree/master/example/cpp/td_example.cpp) contains an example of authorization, processing new incoming messages, getting a list of chats and sending a text message. -See also the source code of [Depecher](https://github.com/blacksailer/depecher) – a Telegram app for Sailfish OS, [TELEports](https://gitlab.com/ubports/apps/teleports) – a Qt-client for Ubuntu Touch, or -[tdlib-purple](https://github.com/ars3niy/tdlib-purple) - Telegram plugin for Pidgin, all of which are based on TDLib. +See also the source code of [Fernschreiber](https://github.com/Wunderfitz/harbour-fernschreiber) and [Depecher](https://github.com/blacksailer/depecher) – Telegram apps for Sailfish OS, +[TELEports](https://gitlab.com/ubports/apps/teleports) – a Qt-client for Ubuntu Touch, or [tdlib-purple](https://github.com/ars3niy/tdlib-purple) - Telegram plugin for Pidgin, all of which are based on TDLib. ## Using TDLib in Swift projects TDLib can be used from the Swift programming language through the [JSON](https://github.com/tdlib/td#using-json) interface and can be linked statically or dynamically. -See [TDLib-iOS](https://github.com/leoMehlig/TDLib-iOS) or [tdlib-swift](https://github.com/modestman/tdlib-swift), which provide convenient TDLib clients with automatically generated and fully-documented classes for all TDLib API methods and objects. +See [example/ios](https://github.com/tdlib/td/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS. + +See [TDLibKit](https://github.com/Swiftgram/TDLibKit), [tdlib-swift](https://github.com/modestman/tdlib-swift), or [TDLib-iOS](https://github.com/leoMehlig/TDLib-iOS), which provide convenient TDLib clients with automatically generated and fully-documented classes for all TDLib API methods and objects. See [example/swift](https://github.com/tdlib/td/tree/master/example/swift) for an example of a macOS Swift application. -See [example/ios](https://github.com/tdlib/td/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS. ## Using TDLib in Objective-C projects @@ -169,12 +173,14 @@ See [project.scarlet](https://github.com/aaugmentum/project.scarlet), [tdlib](ht TDLib can be used from the Rust programming language through the [JSON](https://github.com/tdlib/td#using-json) interface. -See [tdlib-rs](https://github.com/agnipau/tdlib-rs), which contains automatically generated classes for all TDLib API methods and objects. +See [rust-tdlib](https://github.com/aCLr/rust-tdlib), [tdgrand](https://github.com/melix99/tdgrand), or [tdlib-rs](https://github.com/agnipau/tdlib-rs), which provide convenient TDLib clients with automatically generated and fully-documented classes for all TDLib API methods and objects. See [rtdlib](https://github.com/fewensa/rtdlib), [tdlib-rs](https://github.com/d653/tdlib-rs), [tdlib-futures](https://github.com/yuri91/tdlib-futures), -[tdlib-sys](https://github.com/nuxeh/tdlib-sys), [rust-tdlib](https://github.com/lattenwald/rust-tdlib), or +[tdlib-sys](https://github.com/nuxeh/tdlib-sys), or [tdjson-rs](https://github.com/mersinvald/tdjson-rs) for examples of TDLib Rust bindings. +Also see [Telegrand](https://github.com/melix99/telegrand) – a Telegram client optimized for the GNOME desktop. + ## Using TDLib in Erlang projects @@ -201,7 +207,7 @@ See [tdlib-bundle](https://github.com/yaroslavche/tdlib-bundle) – a Symfony bu TDLib can be used from the Lua programming language through the [JSON](https://github.com/tdlib/td#using-json) interface. -See [luajit-tdlib](https://github.com/Rami-Sabbagh/luajit-tdlib), [tdlua](https://github.com/giuseppeM99/tdlua), [Luagram](https://github.com/Luagram/LuagramProject), or +See [luajit-tdlib](https://github.com/Rami-Sabbagh/luajit-tdlib), [tdlua](https://github.com/giuseppeM99/tdlua), or [luajit-tdlib](https://github.com/Playermet/luajit-tdlib) for examples of TDLib Lua bindings and basic usage examples. See also [tdbot](https://github.com/vysheng/tdbot), which makes all TDLib features available from Lua scripts. diff --git a/lib/tgchat/ext/td/example/cpp/CMakeLists.txt b/lib/tgchat/ext/td/example/cpp/CMakeLists.txt index 2d1e0cde..585ba56b 100644 --- a/lib/tgchat/ext/td/example/cpp/CMakeLists.txt +++ b/lib/tgchat/ext/td/example/cpp/CMakeLists.txt @@ -1,8 +1,8 @@ -cmake_minimum_required(VERSION 3.1 FATAL_ERROR) +cmake_minimum_required(VERSION 3.4 FATAL_ERROR) project(TdExample VERSION 1.0 LANGUAGES CXX) -find_package(Td 1.7.0 REQUIRED) +find_package(Td 1.7.9 REQUIRED) add_executable(tdjson_example tdjson_example.cpp) target_link_libraries(tdjson_example PRIVATE Td::TdJson) diff --git a/lib/tgchat/ext/td/example/cpp/td_example.cpp b/lib/tgchat/ext/td/example/cpp/td_example.cpp index 5715501f..e185702d 100644 --- a/lib/tgchat/ext/td/example/cpp/td_example.cpp +++ b/lib/tgchat/ext/td/example/cpp/td_example.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -35,7 +34,7 @@ struct overload : public F { template struct overload : public overload - , overload { + , public overload { overload(F f, Fs... fs) : overload(f), overload(fs...) { } using overload::operator(); @@ -66,8 +65,8 @@ class TdExample { } else if (!are_authorized_) { process_response(client_manager_->receive(10)); } else { - std::cout << "Enter action [q] quit [u] check for updates and request results [c] show chats [m ] " - "send message [me] show self [l] logout: " + std::cout << "Enter action [q] quit [u] check for updates and request results [c] show chats [m " + "] send message [me] show self [l] logout: " << std::endl; std::string line; std::getline(std::cin, line); @@ -116,16 +115,15 @@ class TdExample { send_query(std::move(send_message), {}); } else if (action == "c") { std::cout << "Loading chat list..." << std::endl; - send_query(td_api::make_object(nullptr, std::numeric_limits::max(), 0, 20), - [this](Object object) { - if (object->get_id() == td_api::error::ID) { - return; - } - auto chats = td::move_tl_object_as(object); - for (auto chat_id : chats->chat_ids_) { - std::cout << "[id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl; - } - }); + send_query(td_api::make_object(nullptr, 20), [this](Object object) { + if (object->get_id() == td_api::error::ID) { + return; + } + auto chats = td::move_tl_object_as(object); + for (auto chat_id : chats->chat_ids_) { + std::cout << "[chat_id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl; + } + }); } } } @@ -144,7 +142,7 @@ class TdExample { std::map> handlers_; - std::map> users_; + std::map> users_; std::map chat_title_; @@ -172,10 +170,11 @@ class TdExample { auto it = handlers_.find(response.request_id); if (it != handlers_.end()) { it->second(std::move(response.object)); + handlers_.erase(it); } } - std::string get_user_name(std::int32_t user_id) const { + std::string get_user_name(std::int64_t user_id) const { auto it = users_.find(user_id); if (it == users_.end()) { return "unknown user"; diff --git a/lib/tgchat/ext/td/example/cpp/tdjson_example.cpp b/lib/tgchat/ext/td/example/cpp/tdjson_example.cpp index 080de969..a3e2698b 100644 --- a/lib/tgchat/ext/td/example/cpp/tdjson_example.cpp +++ b/lib/tgchat/ext/td/example/cpp/tdjson_example.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/example/csharp/README.md b/lib/tgchat/ext/td/example/csharp/README.md index ad1103e3..b20d6594 100644 --- a/lib/tgchat/ext/td/example/csharp/README.md +++ b/lib/tgchat/ext/td/example/csharp/README.md @@ -7,13 +7,12 @@ This is an example of building TDLib with `C++/CLI` support and an example of TD * Download and install Microsoft Visual Studio 2015 or later. * Download and install [CMake](https://cmake.org/download/); choose "Add CMake to the system PATH" option while installing. * Install [vcpkg](https://github.com/Microsoft/vcpkg#quick-start) or update it to the latest version using `vcpkg update` and following received instructions. -* Install `zlib` and `openssl` using `vcpkg`: +* Install `gperf`, `zlib`, and `openssl` using `vcpkg`: ``` cd -.\vcpkg.exe install openssl:x64-windows openssl:x86-windows zlib:x64-windows zlib:x86-windows +.\vcpkg.exe install gperf:x64-windows gperf:x86-windows openssl:x64-windows openssl:x86-windows zlib:x64-windows zlib:x86-windows ``` * (Optional. For XML documentation generation.) Download [PHP](https://windows.php.net/download#php-7.2). Add the path to php.exe to the PATH environment variable. -* Download and install [gperf](https://sourceforge.net/projects/gnuwin32/files/gperf/3.0.1/). Add the path to gperf.exe to the PATH environment variable. * Build `TDLib` with CMake enabling `.NET` support and specifying correct path to `vcpkg` toolchain file: ``` cd /example/csharp @@ -34,6 +33,6 @@ cmake --build . --config Debug After `TDLib` is built you can open and run TdExample project. It contains a simple console C# application with implementation of authorization and message sending. -Just open it with Visual Studio 2015 or 2017 and run. +Just open it with Visual Studio 2015 or later and run. Also see TdExample.csproj for example of including TDLib in C# project with all native shared library dependencies. diff --git a/lib/tgchat/ext/td/example/csharp/TdExample.cs b/lib/tgchat/ext/td/example/csharp/TdExample.cs index 7c5b4d25..39afc0ab 100644 --- a/lib/tgchat/ext/td/example/csharp/TdExample.cs +++ b/lib/tgchat/ext/td/example/csharp/TdExample.cs @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -34,13 +34,7 @@ class Example private static Td.Client CreateTdClient() { - Td.Client result = Td.Client.Create(new UpdateHandler()); - new Thread(() => - { - Thread.CurrentThread.IsBackground = true; - result.Run(); - }).Start(); - return result; + return Td.Client.Create(new UpdateHandler()); } private static void Print(string str) @@ -133,7 +127,6 @@ private static void OnAuthorizationStateUpdated(TdApi.AuthorizationState authori else if (_authorizationState is TdApi.AuthorizationStateClosed) { Print("Closed"); - _client.Dispose(); // _client is closed and native resources can be disposed now if (!_needQuit) { _client = CreateTdClient(); // recreate _client after previous has closed @@ -223,6 +216,11 @@ static void Main() { throw new System.IO.IOException("Write access to the current directory is required"); } + new Thread(() => + { + Thread.CurrentThread.IsBackground = true; + Td.Client.Run(); + }).Start(); // create Td.Client _client = CreateTdClient(); @@ -237,7 +235,7 @@ static void Main() _gotAuthorization.Reset(); _gotAuthorization.WaitOne(); - _client.Send(new TdApi.GetChats(null, Int64.MaxValue, 0, 100), _defaultHandler); // preload main chat list + _client.Send(new TdApi.LoadChats(null, 100), _defaultHandler); // preload main chat list while (_haveAuthorization) { GetCommand(); diff --git a/lib/tgchat/ext/td/example/ios/Python-Apple-support.patch b/lib/tgchat/ext/td/example/ios/Python-Apple-support.patch new file mode 100644 index 00000000..65845102 --- /dev/null +++ b/lib/tgchat/ext/td/example/ios/Python-Apple-support.patch @@ -0,0 +1,82 @@ +diff --git a/Makefile b/Makefile +index 695be54..4efe5e5 100644 +--- a/Makefile ++++ b/Makefile +@@ -5,10 +5,13 @@ + # - iOS - build everything for iOS + # - tvOS - build everything for tvOS + # - watchOS - build everything for watchOS + # - OpenSSL-macOS - build OpenSSL for macOS + # - OpenSSL-iOS - build OpenSSL for iOS ++# - OpenSSL-iOS-simulator - build OpenSSL for iOS-simulator + # - OpenSSL-tvOS - build OpenSSL for tvOS ++# - OpenSSL-tvOS-simulator - build OpenSSL for tvOS-simulator + # - OpenSSL-watchOS - build OpenSSL for watchOS ++# - OpenSSL-watchOS-simulator - build OpenSSL for watchOS-simulator + # - BZip2-macOS - build BZip2 for macOS + # - BZip2-iOS - build BZip2 for iOS + # - BZip2-tvOS - build BZip2 for tvOS +@@ -36,31 +39,45 @@ OPENSSL_VERSION=$(OPENSSL_VERSION_NUMBER)$(OPENSSL_REVISION) + BZIP2_VERSION=1.0.6 + + # Supported OS +-OS=macOS iOS tvOS watchOS ++OS=macOS iOS iOS-simulator tvOS tvOS-simulator watchOS watchOS-simulator + + # macOS targets +-TARGETS-macOS=macosx.x86_64 ++TARGETS-macOS=macosx.arm64 macosx.x86_64 ++PYTHON_TARGETS-macOS=macOS + CFLAGS-macOS=-mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) + + # iOS targets +-TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.i386 iphoneos.armv7 iphoneos.armv7s iphoneos.arm64 ++TARGETS-iOS=iphoneos.armv7 iphoneos.armv7s iphoneos.arm64 + CFLAGS-iOS=-mios-version-min=7.0 + CFLAGS-iphoneos.armv7=-fembed-bitcode + CFLAGS-iphoneos.armv7s=-fembed-bitcode + CFLAGS-iphoneos.arm64=-fembed-bitcode + ++# iOS-simulator targets ++TARGETS-iOS-simulator=iphonesimulator.x86_64 iphonesimulator.i386 iphonesimulator.arm64 ++CFLAGS-iOS-simulator=-mios-simulator-version-min=7.0 ++ + # tvOS targets +-TARGETS-tvOS=appletvsimulator.x86_64 appletvos.arm64 ++TARGETS-tvOS=appletvos.arm64 + CFLAGS-tvOS=-mtvos-version-min=9.0 + CFLAGS-appletvos.arm64=-fembed-bitcode + PYTHON_CONFIGURE-tvOS=ac_cv_func_sigaltstack=no + ++# tvOS-simulator targets ++TARGETS-tvOS-simulator=appletvsimulator.x86_64 appletvsimulator.arm64 ++CFLAGS-tvOS-simulator=-mtvos-simulator-version-min=9.0 ++ + # watchOS targets +-TARGETS-watchOS=watchsimulator.i386 watchos.armv7k ++TARGETS-watchOS=watchos.armv7k watchos.arm64_32 + CFLAGS-watchOS=-mwatchos-version-min=4.0 + CFLAGS-watchos.armv7k=-fembed-bitcode ++CFLAGS-watchos.arm64_32=-fembed-bitcode + PYTHON_CONFIGURE-watchOS=ac_cv_func_sigaltstack=no + ++# watchOS-simulator targets ++TARGETS-watchOS-simulator=watchsimulator.i386 watchsimulator.x86_64 watchsimulator.arm64 ++CFLAGS-watchOS-simulator=-mwatchos-simulator-version-min=4.0 ++ + # override machine types for arm64 + MACHINE_DETAILED-arm64=aarch64 + MACHINE_SIMPLE-arm64=arm +@@ -194,9 +211,11 @@ endif + + # Configure the build + ifeq ($2,macOS) ++ # Patch openssl-darwin-arm64 ++ cd $$(OPENSSL_DIR-$1) && git apply ../../../../openssl-1.0.2n-darwin-arm64.patch + cd $$(OPENSSL_DIR-$1) && \ + CC="$$(CC-$1)" MACOSX_DEPLOYMENT_TARGET=$$(MACOSX_DEPLOYMENT_TARGET) \ +- ./Configure darwin64-x86_64-cc --openssldir=$(PROJECT_DIR)/build/$2/openssl ++ ./Configure darwin64-$$(ARCH-$1)-cc --openssldir=$(PROJECT_DIR)/build/$2/openssl + else + cd $$(OPENSSL_DIR-$1) && \ + CC="$$(CC-$1)" \ diff --git a/lib/tgchat/ext/td/example/ios/README.md b/lib/tgchat/ext/td/example/ios/README.md index 168f0328..32266528 100644 --- a/lib/tgchat/ext/td/example/ios/README.md +++ b/lib/tgchat/ext/td/example/ios/README.md @@ -1,8 +1,8 @@ -# Build for iOS +# Universal XCFramework build example Below are instructions for building TDLib for iOS, watchOS, tvOS, and also macOS. -If you need only a macOS build, take a look at our build instructions for [macOS](https://github.com/tdlib/td#macos). +If you need only a macOS build for the current architecture, take a look at [TDLib build instructions generator](https://tdlib.github.io/td/build.html). For example of usage take a look at our [Swift example](https://github.com/tdlib/td/tree/master/example/swift). @@ -13,7 +13,7 @@ To compile `TDLib` you will need to: ``` brew install gperf cmake coreutils ``` -* If you don't want to build `TDLib` for macOS, you can pregenerate required source code files using `CMake` prepare_cross_compiling target: +* If you don't want to build `TDLib` for macOS first, you **must** pregenerate required source code files using `CMake` prepare_cross_compiling target: ``` cd mkdir native-build @@ -21,24 +21,26 @@ cd native-build cmake .. cmake --build . --target prepare_cross_compiling ``` -* Build OpenSSL for iOS, watchOS, tvOS and macOS: +* Build OpenSSL for iOS, watchOS, tvOS, and macOS: ``` cd /example/ios ./build-openssl.sh ``` -Here we use scripts from [Python Apple support](https://github.com/pybee/Python-Apple-support), but any other OpenSSL builds should work too. -[Python Apple support](https://github.com/pybee/Python-Apple-support) has known problems with spaces in the path to the current directory, so -you need to ensure that there is no spaces in the path. -Built libraries should be stored in `third_party/openssl/`, because the next script will rely on this location. -* Build TDLib for iOS, watchOS, tvOS and macOS: +Here we use scripts from [Python Apple support](https://github.com/beeware/Python-Apple-support), but any other OpenSSL build should work too. +[Python Apple support](https://github.com/beeware/Python-Apple-support) has known problems with spaces in the path to the current directory, so +you need to ensure that there are no spaces in the path. +Built OpenSSL libraries should be stored in the directory `third_party/openssl/`, because the next script will rely on this location. +* Build TDLib for iOS, watchOS, tvOS, and macOS: ``` cd /example/ios ./build.sh ``` -This may take a while, because TDLib will be built about 10 times. -Resulting library for iOS will work on any architecture (armv7, armv7s, arm64) and even on a simulator. +This may take a while, because TDLib will be built about 16 times. +Resulting XCFramework will work on any architecture and even on a simulator (x64, Apple silicon). We use [CMake/iOS.cmake](https://github.com/tdlib/td/blob/master/CMake/iOS.cmake) toolchain, other toolchains may work too. -Built libraries will be store in `tdjson` directory. +Built libraries and XCFramework will be stored in `tdjson` directory. Documentation for all available classes and methods can be found at https://core.telegram.org/tdlib/docs. + +If you receive an "error: SDK "appletvsimulator" cannot be located", you need to run the command "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" before running ./build.sh. diff --git a/lib/tgchat/ext/td/example/ios/build-openssl.sh b/lib/tgchat/ext/td/example/ios/build-openssl.sh index 8a6df6f8..ce489e71 100755 --- a/lib/tgchat/ext/td/example/ios/build-openssl.sh +++ b/lib/tgchat/ext/td/example/ios/build-openssl.sh @@ -1,22 +1,36 @@ #!/bin/sh -git clone https://github.com/pybee/Python-Apple-support +git clone https://github.com/beeware/Python-Apple-support cd Python-Apple-support git checkout 60b990128d5f1f04c336ff66594574515ab56604 +git apply ../Python-Apple-support.patch cd .. #TODO: change openssl version platforms="macOS iOS watchOS tvOS" + for platform in $platforms; do - echo $platform - cd Python-Apple-support - #NB: -j will fail - make OpenSSL-$platform - cd .. - rm -rf third_party/openssl/$platform - mkdir -p third_party/openssl/$platform/lib - cp ./Python-Apple-support/build/$platform/libcrypto.a third_party/openssl/$platform/lib/ - cp ./Python-Apple-support/build/$platform/libssl.a third_party/openssl/$platform/lib/ - cp -r ./Python-Apple-support/build/$platform/Support/OpenSSL/Headers/ third_party/openssl/$platform/include + if [[ $platform = "macOS" ]]; then + simulators="0" + else + simulators="0 1" + fi + + for simulator in $simulators; + do + if [[ $simulator = "1" ]]; then + platform="${platform}-simulator" + fi + echo $platform + cd Python-Apple-support + #NB: -j will fail + make OpenSSL-$platform + cd .. + rm -rf third_party/openssl/$platform + mkdir -p third_party/openssl/$platform/lib + cp ./Python-Apple-support/build/$platform/libcrypto.a third_party/openssl/$platform/lib/ + cp ./Python-Apple-support/build/$platform/libssl.a third_party/openssl/$platform/lib/ + cp -r ./Python-Apple-support/build/$platform/Support/OpenSSL/Headers/ third_party/openssl/$platform/include + done done diff --git a/lib/tgchat/ext/td/example/ios/build.sh b/lib/tgchat/ext/td/example/ios/build.sh index 7ee8ff2e..4c5aaa5b 100755 --- a/lib/tgchat/ext/td/example/ios/build.sh +++ b/lib/tgchat/ext/td/example/ios/build.sh @@ -5,70 +5,85 @@ rm -rf build mkdir -p build cd build -platforms="macOS iOS watchOS tvOS" -for platform in $platforms; -do - echo "Platform = ${platform} Simulator = ${simulator}" - openssl_path=$(grealpath ../third_party/openssl/${platform}) +set_cmake_options () { + # Set CMAKE options depending on platform passed $1 + openssl_path=$(grealpath ../third_party/openssl/$1) echo "OpenSSL path = ${openssl_path}" openssl_crypto_library="${openssl_path}/lib/libcrypto.a" openssl_ssl_library="${openssl_path}/lib/libssl.a" + options="" options="$options -DOPENSSL_FOUND=1" options="$options -DOPENSSL_CRYPTO_LIBRARY=${openssl_crypto_library}" options="$options -DOPENSSL_SSL_LIBRARY=${openssl_ssl_library}" options="$options -DOPENSSL_INCLUDE_DIR=${openssl_path}/include" options="$options -DOPENSSL_LIBRARIES=${openssl_crypto_library};${openssl_ssl_library}" options="$options -DCMAKE_BUILD_TYPE=Release" +} + +platforms="macOS iOS watchOS tvOS" +#platforms="watchOS" +for platform in $platforms; +do + echo "Platform = ${platform}" if [[ $platform = "macOS" ]]; then + simulators="0" + else + simulators="0 1" + fi + + for simulator in $simulators; + do + if [[ $platform = "macOS" ]]; then + other_options="-DCMAKE_OSX_ARCHITECTURES='x86_64;arm64'" + else + if [[ $platform = "watchOS" ]]; then + ios_platform="WATCH" + elif [[ $platform = "tvOS" ]]; then + ios_platform="TV" + else + ios_platform="" + fi + + if [[ $simulator = "1" ]]; then + platform="${platform}-simulator" + ios_platform="${ios_platform}SIMULATOR" + else + ios_platform="${ios_platform}OS" + fi + + echo "iOS platform = ${ios_platform}" + other_options="-DIOS_PLATFORM=${ios_platform} -DCMAKE_TOOLCHAIN_FILE=${td_path}/CMake/iOS.cmake" + fi + + set_cmake_options $platform build="build-${platform}" install="install-${platform}" rm -rf $build mkdir -p $build mkdir -p $install cd $build - cmake $td_path $options -DCMAKE_INSTALL_PREFIX=../${install} + cmake $td_path $options $other_options -DCMAKE_INSTALL_PREFIX=../${install} make -j3 install || exit cd .. - mkdir -p $platform - cp $build/libtdjson.dylib $platform/libtdjson.dylib - install_name_tool -id @rpath/libtdjson.dylib $platform/libtdjson.dylib - else - simulators="0 1" - for simulator in $simulators; - do - build="build-${platform}" - install="install-${platform}" - if [[ $simulator = "1" ]]; then - build="${build}-simulator" - install="${install}-simulator" - ios_platform="SIMULATOR" - else - ios_platform="OS" - fi - if [[ $platform = "watchOS" ]]; then - ios_platform="WATCH${ios_platform}" - fi - if [[ $platform = "tvOS" ]]; then - ios_platform="TV${ios_platform}" - fi - echo $ios_platform - rm -rf $build - mkdir -p $build - mkdir -p $install - cd $build - cmake $td_path $options -DIOS_PLATFORM=${ios_platform} -DCMAKE_TOOLCHAIN_FILE=${td_path}/CMake/iOS.cmake -DCMAKE_INSTALL_PREFIX=../${install} - make -j3 install || exit - cd .. - done - lib="install-${platform}/lib/libtdjson.dylib" - lib_simulator="install-${platform}-simulator/lib/libtdjson.dylib" - mkdir -p $platform - lipo -create $lib $lib_simulator -o $platform/libtdjson.dylib - install_name_tool -id @rpath/libtdjson.dylib $platform/libtdjson.dylib - fi + install_name_tool -id @rpath/libtdjson.dylib ${install}/lib/libtdjson.dylib + mkdir -p ../tdjson/${platform}/include + rsync --recursive ${install}/include/ ../tdjson/${platform}/include/ + mkdir -p ../tdjson/${platform}/lib + cp ${install}/lib/libtdjson.dylib ../tdjson/${platform}/lib/ + done +done - mkdir -p ../tdjson/$platform/include - rsync --recursive ${install}/include/ ../tdjson/${platform}/include/ - mkdir -p ../tdjson/$platform/lib - cp $platform/libtdjson.dylib ../tdjson/$platform/lib/ +produced_dylibs=(install-*/lib/libtdjson.dylib) +xcodebuild_frameworks=() + +for dylib in "${produced_dylibs[@]}"; +do + xcodebuild_frameworks+=(-library $(grealpath "${dylib}")) done + +# Make xcframework +xcodebuild -create-xcframework \ + "${xcodebuild_frameworks[@]}" \ + -output "libtdjson.xcframework" + +rsync --recursive libtdjson.xcframework ../tdjson/ diff --git a/lib/tgchat/ext/td/example/ios/openssl-1.0.2n-darwin-arm64.patch b/lib/tgchat/ext/td/example/ios/openssl-1.0.2n-darwin-arm64.patch new file mode 100644 index 00000000..5239d94c --- /dev/null +++ b/lib/tgchat/ext/td/example/ios/openssl-1.0.2n-darwin-arm64.patch @@ -0,0 +1,12 @@ +--- Configure 2019-12-20 14:02:41.000000000 +0100 ++++ Configure 2020-11-22 16:23:13.000000000 +0100 +@@ -650,7 +650,9 @@ + "darwin-i386-cc","cc:-arch i386 -O3 -fomit-frame-pointer -DL_ENDIAN::-D_REENTRANT:MACOSX:-Wl,-search_paths_first%:BN_LLONG RC4_INT RC4_CHUNK DES_UNROLL BF_PTR:".eval{my $asm=$x86_asm;$asm=~s/cast\-586\.o//;$asm}.":macosx:dlfcn:darwin-shared:-fPIC -fno-common:-arch i386 -dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", + "debug-darwin-i386-cc","cc:-arch i386 -g3 -DL_ENDIAN::-D_REENTRANT:MACOSX:-Wl,-search_paths_first%:BN_LLONG RC4_INT RC4_CHUNK DES_UNROLL BF_PTR:${x86_asm}:macosx:dlfcn:darwin-shared:-fPIC -fno-common:-arch i386 -dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", + "darwin64-x86_64-cc","cc:-arch x86_64 -O3 -DL_ENDIAN -Wall::-D_REENTRANT:MACOSX:-Wl,-search_paths_first%:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:".eval{my $asm=$x86_64_asm;$asm=~s/rc4\-[^:]+//;$asm}.":macosx:dlfcn:darwin-shared:-fPIC -fno-common:-arch x86_64 -dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", ++"darwin64-arm64-cc","cc:-arch arm64 -O3 -DL_ENDIAN -Wall::-D_REENTRANT:MACOSX:-Wl,-search_paths_first%:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${no_asm}:dlfcn:darwin-shared:-fPIC -fno-common:-arch arm64 -dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", + "debug-darwin64-x86_64-cc","cc:-arch x86_64 -ggdb -g2 -O0 -DL_ENDIAN -Wall::-D_REENTRANT:MACOSX:-Wl,-search_paths_first%:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:".eval{my $asm=$x86_64_asm;$asm=~s/rc4\-[^:]+//;$asm}.":macosx:dlfcn:darwin-shared:-fPIC -fno-common:-arch x86_64 -dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", ++"debug-darwin64-arm64-cc","cc:-arch arm64 -ggdb -g2 -O0 -DL_ENDIAN -Wall::-D_REENTRANT:MACOSX:-Wl,-search_paths_first%:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${no_asm}:dlfcn:darwin-shared:-fPIC -fno-common:-arch arm64 -dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", + "debug-darwin-ppc-cc","cc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DCRYPTO_MDEBUG -DB_ENDIAN -g -Wall -O::-D_REENTRANT:MACOSX::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${ppc32_asm}:osx32:dlfcn:darwin-shared:-fPIC:-dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", + # iPhoneOS/iOS + "iphoneos-cross","llvm-gcc:-O3 -isysroot \$(CROSS_TOP)/SDKs/\$(CROSS_SDK) -fomit-frame-pointer -fno-common::-D_REENTRANT:macOS:-Wl,-search_paths_first%:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}:dlfcn:darwin-shared:-fPIC -fno-common:-dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", diff --git a/lib/tgchat/ext/td/example/java/CMakeLists.txt b/lib/tgchat/ext/td/example/java/CMakeLists.txt index 057c8eca..6a03776b 100644 --- a/lib/tgchat/ext/td/example/java/CMakeLists.txt +++ b/lib/tgchat/ext/td/example/java/CMakeLists.txt @@ -1,11 +1,25 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +if (POLICY CMP0065) + # do not export symbols from executables + # affects compiler checks in project(), so must be set before it + cmake_policy(SET CMP0065 NEW) +endif() + project(TdJavaExample VERSION 1.0 LANGUAGES CXX) if (POLICY CMP0054) # do not expand quoted arguments cmake_policy(SET CMP0054 NEW) endif() +if (POLICY CMP0060) + # link libraries by full path + cmake_policy(SET CMP0060 NEW) +endif() +if (POLICY CMP0074) + # use environment variables to find libraries + cmake_policy(SET CMP0074 NEW) +endif() find_package(Td REQUIRED) diff --git a/lib/tgchat/ext/td/example/java/README.md b/lib/tgchat/ext/td/example/java/README.md index 28be665a..49455299 100644 --- a/lib/tgchat/ext/td/example/java/README.md +++ b/lib/tgchat/ext/td/example/java/README.md @@ -32,8 +32,8 @@ cd /example/java/bin java '-Djava.library.path=.' org/drinkless/tdlib/example/Example ``` -If you get "Could NOT find JNI ..." error from CMake, you need to specify to CMake path to the installed JDK, for example, "-DJAVA_HOME=/usr/lib/jvm/java-8-oracle/". +If you receive "Could NOT find JNI ..." error from CMake, you need to specify to CMake path to the installed JDK, for example, "-DJAVA_HOME=/usr/lib/jvm/java-8-oracle/". -If you get java.lang.UnsatisfiedLinkError with "Can't find dependent libraries", you may also need to copy some dependent shared OpenSSL and zlib libraries to `bin/`. +If you receive java.lang.UnsatisfiedLinkError with "Can't find dependent libraries", you may also need to copy some dependent shared OpenSSL and zlib libraries to `bin/`. In case you compiled the example as 32-bit version, you may need to give -d32 parameter to Java. diff --git a/lib/tgchat/ext/td/example/java/org/drinkless/tdlib/Client.java b/lib/tgchat/ext/td/example/java/org/drinkless/tdlib/Client.java index e6a30f33..0d0959e7 100644 --- a/lib/tgchat/ext/td/example/java/org/drinkless/tdlib/Client.java +++ b/lib/tgchat/ext/td/example/java/org/drinkless/tdlib/Client.java @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/example/java/org/drinkless/tdlib/Log.java b/lib/tgchat/ext/td/example/java/org/drinkless/tdlib/Log.java index 98189d87..cb8733f1 100644 --- a/lib/tgchat/ext/td/example/java/org/drinkless/tdlib/Log.java +++ b/lib/tgchat/ext/td/example/java/org/drinkless/tdlib/Log.java @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/example/java/org/drinkless/tdlib/example/Example.java b/lib/tgchat/ext/td/example/java/org/drinkless/tdlib/example/Example.java index 7c2e5649..ee5e2f1c 100644 --- a/lib/tgchat/ext/td/example/java/org/drinkless/tdlib/example/Example.java +++ b/lib/tgchat/ext/td/example/java/org/drinkless/tdlib/example/Example.java @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -37,18 +37,18 @@ public final class Example { private static final Lock authorizationLock = new ReentrantLock(); private static final Condition gotAuthorization = authorizationLock.newCondition(); - private static final ConcurrentMap users = new ConcurrentHashMap(); - private static final ConcurrentMap basicGroups = new ConcurrentHashMap(); - private static final ConcurrentMap supergroups = new ConcurrentHashMap(); + private static final ConcurrentMap users = new ConcurrentHashMap(); + private static final ConcurrentMap basicGroups = new ConcurrentHashMap(); + private static final ConcurrentMap supergroups = new ConcurrentHashMap(); private static final ConcurrentMap secretChats = new ConcurrentHashMap(); private static final ConcurrentMap chats = new ConcurrentHashMap(); private static final NavigableSet mainChatList = new TreeSet(); private static boolean haveFullMainChatList = false; - private static final ConcurrentMap usersFullInfo = new ConcurrentHashMap(); - private static final ConcurrentMap basicGroupsFullInfo = new ConcurrentHashMap(); - private static final ConcurrentMap supergroupsFullInfo = new ConcurrentHashMap(); + private static final ConcurrentMap usersFullInfo = new ConcurrentHashMap(); + private static final ConcurrentMap basicGroupsFullInfo = new ConcurrentHashMap(); + private static final ConcurrentMap supergroupsFullInfo = new ConcurrentHashMap(); private static final String newLine = System.getProperty("line.separator"); private static final String commandsLine = "Enter command (gcs - GetChats, gc - GetChat, me - GetMe, sm - SendMessage, lo - LogOut, q - Quit): "; @@ -248,28 +248,21 @@ private static void getCommand() { private static void getMainChatList(final int limit) { synchronized (mainChatList) { if (!haveFullMainChatList && limit > mainChatList.size()) { - // have enough chats in the chat list or chat list is too small - long offsetOrder = Long.MAX_VALUE; - long offsetChatId = 0; - if (!mainChatList.isEmpty()) { - OrderedChat last = mainChatList.last(); - offsetOrder = last.position.order; - offsetChatId = last.chatId; - } - client.send(new TdApi.GetChats(new TdApi.ChatListMain(), offsetOrder, offsetChatId, limit - mainChatList.size()), new Client.ResultHandler() { + // send GetChats request if there are some unknown chats and have not enough known chats + client.send(new TdApi.LoadChats(new TdApi.ChatListMain(), limit - mainChatList.size()), new Client.ResultHandler() { @Override public void onResult(TdApi.Object object) { switch (object.getConstructor()) { case TdApi.Error.CONSTRUCTOR: - System.err.println("Receive an error for GetChats:" + newLine + object); - break; - case TdApi.Chats.CONSTRUCTOR: - long[] chatIds = ((TdApi.Chats) object).chatIds; - if (chatIds.length == 0) { + if (((TdApi.Error) object).code == 404) { synchronized (mainChatList) { haveFullMainChatList = true; } + } else { + System.err.println("Receive an error for GetChats:" + newLine + object); } + break; + case TdApi.Ok.CONSTRUCTOR: // chats had already been received through updates, let's retry request getMainChatList(limit); break; @@ -281,11 +274,10 @@ public void onResult(TdApi.Object object) { return; } - // have enough chats in the chat list to answer request java.util.Iterator iter = mainChatList.iterator(); System.out.println(); System.out.println("First " + limit + " chat(s) out of " + mainChatList.size() + " known chat(s):"); - for (int i = 0; i < limit; i++) { + for (int i = 0; i < limit && i < mainChatList.size(); i++) { long chatId = iter.next().chatId; TdApi.Chat chat = chats.get(chatId); synchronized (chat) { diff --git a/lib/tgchat/ext/td/example/java/td_jni.cpp b/lib/tgchat/ext/td/example/java/td_jni.cpp index 61df8b09..02d14289 100644 --- a/lib/tgchat/ext/td/example/java/td_jni.cpp +++ b/lib/tgchat/ext/td/example/java/td_jni.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -50,10 +50,10 @@ static jint Client_nativeClientReceive(JNIEnv *env, jclass clazz, jintArray clie auto *manager = get_manager(); auto response = manager->receive(timeout); while (response.object) { - jint client_id = static_cast(response.client_id); + auto client_id = static_cast(response.client_id); env->SetIntArrayRegion(client_ids, result_size, 1, &client_id); - jlong request_id = static_cast(response.request_id); + auto request_id = static_cast(response.request_id); env->SetLongArrayRegion(ids, result_size, 1, &request_id); jobject object; @@ -101,7 +101,10 @@ static constexpr jint JAVA_VERSION = JNI_VERSION_1_6; static JavaVM *java_vm; static jclass log_class; -static void on_fatal_error(const char *error_message) { +static void on_log_message(int verbosity_level, const char *error_message) { + if (verbosity_level != 0) { + return; + } auto env = td::jni::get_jni_env(java_vm, JAVA_VERSION); if (env == nullptr) { return; @@ -154,7 +157,7 @@ static jint register_native(JavaVM *vm) { td::jni::init_vars(env, PACKAGE_NAME); td::td_api::Object::init_jni_vars(env, PACKAGE_NAME); td::td_api::Function::init_jni_vars(env, PACKAGE_NAME); - td::Log::set_fatal_error_callback(on_fatal_error); + td::ClientManager::set_log_message_callback(0, on_log_message); return JAVA_VERSION; } diff --git a/lib/tgchat/ext/td/example/python/README.md b/lib/tgchat/ext/td/example/python/README.md index c4a4ad37..c3c171d9 100644 --- a/lib/tgchat/ext/td/example/python/README.md +++ b/lib/tgchat/ext/td/example/python/README.md @@ -7,5 +7,5 @@ Then you can run the example: python tdjson_example.py ``` -Description of all available classes and methods can be found at [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html), -[td_log](https://core.telegram.org/tdlib/docs/td__log_8h.html) and [td_api](https://core.telegram.org/tdlib/docs/td__api_8h.html) documentation. +Description of all available classes and methods can be found at [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html) +and [td_api](https://core.telegram.org/tdlib/docs/td__api_8h.html) documentation. diff --git a/lib/tgchat/ext/td/example/python/tdjson_example.py b/lib/tgchat/ext/td/example/python/tdjson_example.py index e0f46f82..7c8f350e 100644 --- a/lib/tgchat/ext/td/example/python/tdjson_example.py +++ b/lib/tgchat/ext/td/example/python/tdjson_example.py @@ -1,6 +1,6 @@ # # Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com), -# Pellegrino Prevete (pellegrinoprevete@gmail.com) 2014-2020 +# Pellegrino Prevete (pellegrinoprevete@gmail.com) 2014-2021 # # Distributed under the Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,8 +13,7 @@ # load shared library tdjson_path = find_library('tdjson') or 'tdjson.dll' if tdjson_path is None: - print('can\'t find tdjson library') - quit() + sys.exit("Can't find 'tdjson' library") tdjson = CDLL(tdjson_path) # load TDLib functions from shared library @@ -34,16 +33,16 @@ _td_execute.restype = c_char_p _td_execute.argtypes = [c_char_p] -fatal_error_callback_type = CFUNCTYPE(None, c_char_p) +log_message_callback_type = CFUNCTYPE(None, c_int, c_char_p) -_td_set_log_fatal_error_callback = tdjson.td_set_log_fatal_error_callback -_td_set_log_fatal_error_callback.restype = None -_td_set_log_fatal_error_callback.argtypes = [fatal_error_callback_type] +_td_set_log_message_callback = tdjson.td_set_log_message_callback +_td_set_log_message_callback.restype = None +_td_set_log_message_callback.argtypes = [c_int, log_message_callback_type] # initialize TDLib log with desired parameters -def on_fatal_error_callback(error_message): - print('TDLib fatal error: ', error_message) - sys.stdout.flush() +def on_log_message_callback(verbosity_level, message): + if verbosity_level == 0: + sys.exit('TDLib fatal error: %r' % message) def td_execute(query): query = json.dumps(query).encode('utf-8') @@ -52,8 +51,8 @@ def td_execute(query): result = json.loads(result.decode('utf-8')) return result -c_on_fatal_error_callback = fatal_error_callback_type(on_fatal_error_callback) -_td_set_log_fatal_error_callback(c_on_fatal_error_callback) +c_on_log_message_callback = log_message_callback_type(on_log_message_callback) +_td_set_log_message_callback(2, c_on_log_message_callback) # setting TDLib log verbosity level to 1 (errors) print(str(td_execute({'@type': 'setLogVerbosityLevel', 'new_verbosity_level': 1, '@extra': 1.01234})).encode('utf-8')) diff --git a/lib/tgchat/ext/td/example/swift/README.md b/lib/tgchat/ext/td/example/swift/README.md index 113a606b..7c57dcf6 100644 --- a/lib/tgchat/ext/td/example/swift/README.md +++ b/lib/tgchat/ext/td/example/swift/README.md @@ -11,5 +11,5 @@ cmake --build . --target install Then you can open and build the example with the latest Xcode. -Description of all available classes and methods can be found at [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html), -[td_log](https://core.telegram.org/tdlib/docs/td__log_8h.html) and [td_api](https://core.telegram.org/tdlib/docs/td__api_8h.html) documentation. +Description of all available classes and methods can be found at [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html) +and [td_api](https://core.telegram.org/tdlib/docs/td__api_8h.html) documentation. diff --git a/lib/tgchat/ext/td/example/swift/src/main.swift b/lib/tgchat/ext/td/example/swift/src/main.swift index 82851a80..a6a23a13 100644 --- a/lib/tgchat/ext/td/example/swift/src/main.swift +++ b/lib/tgchat/ext/td/example/swift/src/main.swift @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/example/swift/src/td-Bridging-Header.h b/lib/tgchat/ext/td/example/swift/src/td-Bridging-Header.h index e3514d0b..1f02be33 100644 --- a/lib/tgchat/ext/td/example/swift/src/td-Bridging-Header.h +++ b/lib/tgchat/ext/td/example/swift/src/td-Bridging-Header.h @@ -1,11 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/example/uwp/README.md b/lib/tgchat/ext/td/example/uwp/README.md index 65952d63..f6cf3aa5 100644 --- a/lib/tgchat/ext/td/example/uwp/README.md +++ b/lib/tgchat/ext/td/example/uwp/README.md @@ -7,23 +7,22 @@ This is an example of building TDLib SDK for Universal Windows Platform and an e * Download and install Microsoft Visual Studio 2015+ with Windows 10 SDK. We recommend to use the latest available versions of Microsoft Visual Studio and Windows 10 SDK. * Download and install [CMake](https://cmake.org/download/). * Install [vcpkg](https://github.com/Microsoft/vcpkg#quick-start) or update it to the latest version using `vcpkg update` and following received instructions. -* Install `zlib` and `openssl` for all UWP architectures using `vcpkg`: +* Install `zlib` and `openssl` for all UWP architectures and `gperf` for x86 using `vcpkg`: ``` cd -.\vcpkg.exe install openssl-uwp:arm-uwp openssl-uwp:x64-uwp openssl-uwp:x86-uwp zlib:arm-uwp zlib:x64-uwp zlib:x86-uwp +.\vcpkg.exe install gperf:x86-windows openssl:arm-uwp openssl:arm64-uwp openssl:x64-uwp openssl:x86-uwp zlib:arm-uwp zlib:arm64-uwp zlib:x64-uwp zlib:x86-uwp ``` * (Optional. For XML documentation generation.) Download [PHP](https://windows.php.net/download#php-7.2). Add the path to php.exe to the PATH environment variable. -* Download and install [gperf](https://sourceforge.net/projects/gnuwin32/files/gperf/3.0.1/). Add the path to gperf.exe to the PATH environment variable. * Download and install [7-Zip](http://www.7-zip.org/download.html) archiver, which is used by the `build.ps1` script to create a Telegram.Td.UWP Visual Studio Extension. Add the path to 7z.exe to the PATH environment variable. Alternatively `build.ps1` supports compressing using [WinRAR](https://en.wikipedia.org/wiki/WinRAR) with option `-compress winrar` and compressing using [zip](http://gnuwin32.sourceforge.net/packages/zip.htm) with `-compress zip`. * Build `TDLib` using provided `build.ps1` script (TDLib should be built 6 times for multiple platforms in Debug and Release configurations, so it make take few hours). Pass path to vcpkg.exe as `-vcpkg-root` argument, for example: ``` powershell -ExecutionPolicy ByPass .\build.ps1 -vcpkg_root C:\vcpkg ``` -If you need to restart the build from scratch, call `.\build.ps1 -mode clean` first. +If you need to restart the build from scratch, call `.\build.ps1 -vcpkg_root ../../vcpkg -mode clean` first. * Install Visual Studio Extension "TDLib for Universal Windows Platform" located at `build-uwp\vsix\tdlib.vsix`, which was created on the previous step by `build.ps1` script. -Now `TDLib` can be freely used from any UWP project, built in Visual Studio. +Now `TDLib` can be used from any UWP project, built in Visual Studio. ## Example of usage -The `app/` directory contains a simple example of a C# application for Universal Windows Platform. Just open it with Visual Studio 2015 or 2017 and run. +The `app/` directory contains a simple example of a C# application for Universal Windows Platform. Just open it with Visual Studio 2015 or later and run. diff --git a/lib/tgchat/ext/td/example/uwp/app/App.xaml.cs b/lib/tgchat/ext/td/example/uwp/app/App.xaml.cs index 52746ca8..42b2b07b 100644 --- a/lib/tgchat/ext/td/example/uwp/app/App.xaml.cs +++ b/lib/tgchat/ext/td/example/uwp/app/App.xaml.cs @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/example/uwp/app/MainPage.xaml.cs b/lib/tgchat/ext/td/example/uwp/app/MainPage.xaml.cs index 21d38262..7b843ec9 100644 --- a/lib/tgchat/ext/td/example/uwp/app/MainPage.xaml.cs +++ b/lib/tgchat/ext/td/example/uwp/app/MainPage.xaml.cs @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -29,30 +29,24 @@ public MainPage() Td.Client.Execute(new TdApi.SetLogVerbosityLevel(0)); Td.Client.Execute(new TdApi.SetLogStream(new TdApi.LogStreamFile(Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "log"), 1 << 27, false))); - + Td.Client.SetLogMessageCallback(100, LogMessageCallback); System.Threading.Tasks.Task.Run(() => { - try - { - _client = Td.Client.Create(_handler); - var parameters = new TdApi.TdlibParameters(); - parameters.DatabaseDirectory = Windows.Storage.ApplicationData.Current.LocalFolder.Path; - parameters.UseSecretChats = true; - parameters.UseMessageDatabase = true; - parameters.ApiId = 94575; - parameters.ApiHash = "a3406de8d171bb422bb6ddf3bbd800e2"; - parameters.SystemLanguageCode = "en"; - parameters.DeviceModel = "Desktop"; - parameters.ApplicationVersion = "1.0.0"; - _client.Send(new TdApi.SetTdlibParameters(parameters), null); - _client.Send(new TdApi.CheckDatabaseEncryptionKey(), null); - _client.Run(); - } - catch (Exception ex) - { - Print(ex.ToString()); - } + Td.Client.Run(); }); + + _client = Td.Client.Create(_handler); + var parameters = new TdApi.TdlibParameters(); + parameters.DatabaseDirectory = Windows.Storage.ApplicationData.Current.LocalFolder.Path; + parameters.UseSecretChats = true; + parameters.UseMessageDatabase = true; + parameters.ApiId = 94575; + parameters.ApiHash = "a3406de8d171bb422bb6ddf3bbd800e2"; + parameters.SystemLanguageCode = "en"; + parameters.DeviceModel = "Desktop"; + parameters.ApplicationVersion = "1.0.0"; + _client.Send(new TdApi.SetTdlibParameters(parameters), null); + _client.Send(new TdApi.CheckDatabaseEncryptionKey(), null); } public void Print(String str) @@ -63,6 +57,14 @@ public void Print(String str) }); } + private void LogMessageCallback(int verbosity_level, String str) + { + if (verbosity_level < 0) { + return; + } + Print(verbosity_level + ": " + str); + } + private Td.Client _client; private void AcceptCommand(String command) @@ -107,6 +109,12 @@ private void Button_Click(object sender, RoutedEventArgs e) AcceptCommand(command); _client.Send(new TdApi.CheckAuthenticationPassword(args[1]), _handler); } + else if (command.StartsWith("alm")) + { + var args = command.Split(" ".ToCharArray(), 3); + AcceptCommand(command); + _client.Send(new TdApi.AddLogMessage(Int32.Parse(args[1]), args[2]), _handler); + } else if (command.StartsWith("gco")) { var args = command.Split(" ".ToCharArray(), 2); diff --git a/lib/tgchat/ext/td/example/uwp/app/Properties/AssemblyInfo.cs b/lib/tgchat/ext/td/example/uwp/app/Properties/AssemblyInfo.cs index c8708286..88081c3f 100644 --- a/lib/tgchat/ext/td/example/uwp/app/Properties/AssemblyInfo.cs +++ b/lib/tgchat/ext/td/example/uwp/app/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("App2")] -[assembly: AssemblyCopyright("Copyright © 2015-2020")] +[assembly: AssemblyCopyright("Copyright © 2015-2021")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/lib/tgchat/ext/td/example/uwp/build.ps1 b/lib/tgchat/ext/td/example/uwp/build.ps1 index 0d84bfc8..a61998d1 100644 --- a/lib/tgchat/ext/td/example/uwp/build.ps1 +++ b/lib/tgchat/ext/td/example/uwp/build.ps1 @@ -2,7 +2,8 @@ param ( [string]$vcpkg_root = $(throw "-vcpkg_root= is required"), [string]$arch = "", [string]$mode = "all", - [string]$compress = "7z" + [string]$compress = "7z", + [switch]$release_only = $false ) $ErrorActionPreference = "Stop" @@ -13,6 +14,11 @@ $arch_list = @( "x86", "x64", "ARM" ) if ($arch) { $arch_list = @(, $arch) } +$config_list = @( "Debug", "Release" ) +if ($release_only) { + $config_list = @(, "RelWithDebInfo") +} +$targets = @{ Debug = "Debug"; Release = "Retail"; RelWithDebInfo = "CommonConfiguration"} $td_root = Resolve-Path "../.." @@ -47,7 +53,7 @@ function config { New-Item -ItemType Directory -Force -Path build-uwp cd build-uwp - ForEach($arch in $arch_list) { + ForEach ($arch in $arch_list) { echo "Config Arch = [$arch]" New-Item -ItemType Directory -Force -Path $arch cd $arch @@ -66,11 +72,12 @@ function config { function build { cd build-uwp - ForEach($arch in $arch_list) { + ForEach ($arch in $arch_list) { echo "Build Arch = [$arch]" cd $arch - cmake --build . --config Release --target tddotnet - cmake --build . --config Debug --target tddotnet + ForEach ($config in $config_list) { + cmake --build . --config $config --target tddotnet + } cd .. } cd .. @@ -85,23 +92,19 @@ function export { cp '../`[Content_Types`].xml' vsix cp ../LICENSE_1_0.txt vsix - ForEach($arch in $arch_list) { - New-Item -ItemType Directory -Force -Path vsix/DesignTime/Debug/${arch} - New-Item -ItemType Directory -Force -Path vsix/DesignTime/Retail/${arch} - New-Item -ItemType Directory -Force -Path vsix/Redist/Debug/${arch} - New-Item -ItemType Directory -Force -Path vsix/Redist/Retail/${arch} + ForEach ($arch in $arch_list) { New-Item -ItemType Directory -Force -Path vsix/References/CommonConfiguration/${arch} + ForEach ($config in $config_list) { + $target = $targets[$config] - cp ${arch}/Debug/* -include "SSLEAY*","LIBEAY*","libcrypto*","libssl*","zlib*" vsix/Redist/Debug/${arch}/ - cp ${arch}/Release/* -include "SSLEAY*","LIBEAY*","libcrypto*","libssl*","zlib*" vsix/Redist/Retail/${arch}/ + New-Item -ItemType Directory -Force -Path vsix/DesignTime/${target}/${arch} + cp ${arch}/${config}/Telegram.Td.lib vsix/DesignTime/${target}/${arch}/ - cp ${arch}/Debug/* -filter "Telegram.Td.*" -include "*.lib" vsix/DesignTime/Debug/${arch}/ - cp ${arch}/Release/* -filter "Telegram.Td.*" -include "*.lib" vsix/DesignTime/Retail/${arch}/ + New-Item -ItemType Directory -Force -Path vsix/Redist/${target}/${arch} + cp ${arch}/${config}/* -include "SSLEAY*","LIBEAY*","libcrypto*","libssl*","zlib*","Telegram.Td.pdb","Telegram.Td.dll" vsix/Redist/${target}/${arch}/ - cp ${arch}/Debug/* -filter "Telegram.Td.*" -include "*.pdb","*.dll" vsix/Redist/Debug/${arch}/ - cp ${arch}/Release/* -filter "Telegram.Td.*" -include "*.pdb","*.dll" vsix/Redist/Retail/${arch}/ - - cp ${arch}/Release/* -filter "Telegram.Td.*" -include "*.pri","*.winmd","*.xml" vsix/References/CommonConfiguration/${arch}/ + cp ${arch}/${config}/* -include "Telegram.Td.pri","Telegram.Td.winmd","Telegram.Td.xml" vsix/References/CommonConfiguration/${arch}/ + } } cd vsix diff --git a/lib/tgchat/ext/td/example/uwp/extension.vsixmanifest b/lib/tgchat/ext/td/example/uwp/extension.vsixmanifest index 62a2374f..d058a800 100644 --- a/lib/tgchat/ext/td/example/uwp/extension.vsixmanifest +++ b/lib/tgchat/ext/td/example/uwp/extension.vsixmanifest @@ -1,6 +1,6 @@ - + TDLib for Universal Windows Platform TDLib is a library for building Telegram clients https://core.telegram.org/tdlib diff --git a/lib/tgchat/ext/td/format.ps1 b/lib/tgchat/ext/td/format.ps1 index f64296cc..a1079a34 100644 --- a/lib/tgchat/ext/td/format.ps1 +++ b/lib/tgchat/ext/td/format.ps1 @@ -1,3 +1,3 @@ -./src.ps1 | Select-String -NotMatch "CxCli.h" | Select-String -NotMatch "dotnet" | ForEach-Object { +./src.ps1 | Select-String -NotMatch "CxCli.h" | Select-String -NotMatch "DotNet" | Select-String -NotMatch "/tl-parser/" | ForEach-Object { clang-format -verbose -style=file -i $_ } diff --git a/lib/tgchat/ext/td/format.sh b/lib/tgchat/ext/td/format.sh index 64280e33..c33dabb5 100755 --- a/lib/tgchat/ext/td/format.sh +++ b/lib/tgchat/ext/td/format.sh @@ -1,2 +1,2 @@ #!/bin/sh -./src.sh | grep -v CxCli.h | grep -iv dotnet | xargs -n 1 clang-format -verbose -style=file -i +./src.sh | grep -v CxCli.h | grep -iv dotnet | grep -v /tl-parser/ | xargs -n 1 clang-format -verbose -style=file -i diff --git a/lib/tgchat/ext/td/memprof/memprof.cpp b/lib/tgchat/ext/td/memprof/memprof.cpp index b64f82b5..b33d1194 100644 --- a/lib/tgchat/ext/td/memprof/memprof.cpp +++ b/lib/tgchat/ext/td/memprof/memprof.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -58,7 +58,7 @@ static int fast_backtrace(void **buffer, int size) { void *ip; }; - stack_frame *bp = reinterpret_cast(get_bp()); + auto *bp = reinterpret_cast(get_bp()); int i = 0; while (i < size && #if TD_LINUX @@ -153,7 +153,7 @@ std::size_t get_ht_size() { std::int32_t get_ht_pos(const Backtrace &bt, bool force = false) { auto hash = get_hash(bt); - std::int32_t pos = static_cast(hash % ht.size()); + auto pos = static_cast(hash % ht.size()); bool was_overflow = false; while (true) { auto pos_hash = ht[pos].hash.load(); @@ -237,7 +237,7 @@ static void *malloc_with_frame(std::size_t size, const Backtrace &frame) { } static malloc_info *get_info(void *data_void) { - char *data = static_cast(data_void); + auto *data = static_cast(data_void); auto *buf = data - RESERVED_SIZE; auto *info = reinterpret_cast(buf); diff --git a/lib/tgchat/ext/td/memprof/memprof.h b/lib/tgchat/ext/td/memprof/memprof.h index dba2b760..1a618c40 100644 --- a/lib/tgchat/ext/td/memprof/memprof.h +++ b/lib/tgchat/ext/td/memprof/memprof.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/sqlite/CMakeLists.txt b/lib/tgchat/ext/td/sqlite/CMakeLists.txt index b439b0cd..df2f5c18 100644 --- a/lib/tgchat/ext/td/sqlite/CMakeLists.txt +++ b/lib/tgchat/ext/td/sqlite/CMakeLists.txt @@ -1,4 +1,6 @@ -cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +if ((CMAKE_MAJOR_VERSION LESS 3) OR (CMAKE_VERSION VERSION_LESS "3.0.2")) + message(FATAL_ERROR "CMake >= 3.0.2 is required") +endif() if (NOT DEFINED CMAKE_INSTALL_LIBDIR) set(CMAKE_INSTALL_LIBDIR "lib") @@ -30,14 +32,21 @@ if (WIN32) endif() target_compile_definitions(tdsqlite PRIVATE + -DOMIT_MEMLOCK -DSQLITE_DEFAULT_MEMSTATUS=0 - -DSQLITE_OMIT_LOAD_EXTENSION + -DSQLITE_DEFAULT_RECURSIVE_TRIGGERS=1 + -DSQLITE_DEFAULT_SYNCHRONOUS=1 + -DSQLITE_DISABLE_LFS + -DSQLITE_ENABLE_FTS5 + -DSQLITE_HAS_CODEC -DSQLITE_OMIT_DECLTYPE + -DSQLITE_OMIT_DEPRECATED + -DSQLITE_OMIT_DESERIALIZE + -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_OMIT_PROGRESS_CALLBACK - #-DSQLITE_OMIT_DEPRECATED # SQLCipher uses deprecated sqlite3_profile #-DSQLITE_OMIT_SHARED_CACHE + -DSQLITE_TEMP_STORE=2 ) -target_compile_definitions(tdsqlite PRIVATE -DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_ENABLE_FTS5 -DSQLITE_DISABLE_LFS) if (NOT WIN32) target_compile_definitions(tdsqlite PRIVATE -DHAVE_USLEEP -DNDEBUG=1) diff --git a/lib/tgchat/ext/td/sqlite/sqlite/sqlite3.c b/lib/tgchat/ext/td/sqlite/sqlite/sqlite3.c index 9f589068..cb15a29a 100644 --- a/lib/tgchat/ext/td/sqlite/sqlite/sqlite3.c +++ b/lib/tgchat/ext/td/sqlite/sqlite/sqlite3.c @@ -22555,7 +22555,7 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar /* #include "sqlcipher.h" */ /* #include "crypto.h" */ -#ifndef OMIT_MEMLOCK +// #ifndef OMIT_MEMLOCK #if defined(__unix__) || defined(__APPLE__) || defined(_AIX) #include #include @@ -22564,7 +22564,7 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar #elif defined(_WIN32) #include #endif -#endif +// #endif static volatile unsigned int default_flags = DEFAULT_CIPHER_FLAGS; static volatile unsigned char hmac_salt_mask = HMAC_SALT_MASK; diff --git a/lib/tgchat/ext/td/td/generate/CMakeLists.txt b/lib/tgchat/ext/td/td/generate/CMakeLists.txt index adbaa266..e7f6aea0 100644 --- a/lib/tgchat/ext/td/td/generate/CMakeLists.txt +++ b/lib/tgchat/ext/td/td/generate/CMakeLists.txt @@ -1,4 +1,6 @@ -cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +if ((CMAKE_MAJOR_VERSION LESS 3) OR (CMAKE_VERSION VERSION_LESS "3.0.2")) + message(FATAL_ERROR "CMake >= 3.0.2 is required") +endif() if (NOT DEFINED CMAKE_INSTALL_BINDIR) set(CMAKE_INSTALL_BINDIR "bin") @@ -6,6 +8,7 @@ endif() file(MAKE_DIRECTORY auto/td/telegram) file(MAKE_DIRECTORY auto/td/mtproto) +file(MAKE_DIRECTORY auto/tlo) set(TL_TD_AUTO_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/auto PARENT_SCOPE) @@ -37,9 +40,6 @@ set(TL_TD_JSON_AUTO_SOURCE PARENT_SCOPE ) -set(TL_TD_API_TLO ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tlo) -set(TL_TD_API_TLO ${TL_TD_API_TLO} PARENT_SCOPE) - set(TL_C_AUTO_SOURCE ${TD_AUTO_INCLUDE_DIR}/telegram/td_tdc_api.cpp ${TD_AUTO_INCLUDE_DIR}/telegram/td_tdc_api.h @@ -106,13 +106,36 @@ if (NOT CMAKE_CROSSCOMPILING) set(GENERATE_COMMON_CMD generate_common) endif() + add_subdirectory(tl-parser) + + set(TLO_AUTO_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/auto/tlo) + set(TLO_FILES ${TLO_AUTO_INCLUDE_DIR}/mtproto_api.tlo ${TLO_AUTO_INCLUDE_DIR}/secret_api.tlo ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo ${TLO_AUTO_INCLUDE_DIR}/telegram_api.tlo) + set(TD_API_TLO_FILE ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo) + + # Ninja generator uses relative paths and can't correctly handle these dependencies + # See https://gitlab.kitware.com/cmake/cmake/-/issues/13894 + if (CMAKE_GENERATOR STREQUAL "Ninja") + set(TLO_FILES) + set(TD_API_TLO_FILE) + endif() + + add_custom_target(tl_generate_tlo + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND tl-parser -e auto/tlo/mtproto_api.tlo scheme/mtproto_api.tl + COMMAND tl-parser -e auto/tlo/secret_api.tlo scheme/secret_api.tl + COMMAND tl-parser -e auto/tlo/td_api.tlo scheme/td_api.tl + COMMAND tl-parser -e auto/tlo/telegram_api.tlo scheme/telegram_api.tl + COMMENT "Generate TLO files" + DEPENDS tl-parser ${CMAKE_CURRENT_SOURCE_DIR}/scheme/mtproto_api.tl ${CMAKE_CURRENT_SOURCE_DIR}/scheme/secret_api.tl ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl ${CMAKE_CURRENT_SOURCE_DIR}/scheme/telegram_api.tl + ) + add_executable(generate_common ${TL_GENERATE_COMMON_SOURCE}) target_link_libraries(generate_common PRIVATE tdtl) add_custom_target(tl_generate_common WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${GENERATE_COMMON_CMD} - COMMENT "Generate common tl source files" - DEPENDS generate_common scheme/mtproto_api.tlo scheme/telegram_api.tlo scheme/secret_api.tlo ${TL_TD_API_TLO} DoxygenTlDocumentationGenerator.php + COMMENT "Generate common TL source files" + DEPENDS generate_common tl_generate_tlo ${TLO_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl ${CMAKE_CURRENT_SOURCE_DIR}/DoxygenTlDocumentationGenerator.php ) if (TD_ENABLE_JNI) target_compile_definitions(generate_common PRIVATE TD_ENABLE_JNI=1) @@ -126,8 +149,8 @@ if (NOT CMAKE_CROSSCOMPILING) add_custom_target(tl_generate_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND generate_c - COMMENT "Generate C tl source files" - DEPENDS generate_c ${TL_TD_API_TLO} + COMMENT "Generate C TL source files" + DEPENDS generate_c tl_generate_tlo ${TD_API_TLO_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl ) add_executable(td_generate_java_api ${TL_GENERATE_JAVA_SOURCE}) @@ -138,30 +161,30 @@ if (NOT CMAKE_CROSSCOMPILING) add_custom_target(tl_generate_json WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND generate_json - COMMENT "Generate JSON tl source files" - DEPENDS generate_json ${TL_TD_API_TLO} + COMMENT "Generate JSON TL source files" + DEPENDS generate_json tl_generate_tlo ${TD_API_TLO_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl ) if (TD_ENABLE_JNI) install(TARGETS td_generate_java_api RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") install(FILES JavadocTlDocumentationGenerator.php TlDocumentationGenerator.php DESTINATION "${CMAKE_INSTALL_BINDIR}/td/generate") - install(FILES scheme/td_api.tlo scheme/td_api.tl DESTINATION "${CMAKE_INSTALL_BINDIR}/td/generate/scheme") + install(FILES ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo scheme/td_api.tl DESTINATION "${CMAKE_INSTALL_BINDIR}/td/generate/scheme") endif() if (TD_ENABLE_DOTNET) if (PHP_EXECUTABLE) - set(GENERATE_DOTNET_API_CMD td_generate_dotnet_api ${TL_TD_API_TLO} && ${PHP_EXECUTABLE} DotnetTlDocumentationGenerator.php scheme/td_api.tl auto/td/telegram/TdDotNetApi.h) + set(GENERATE_DOTNET_API_CMD td_generate_dotnet_api ${TD_API_TLO_FILE} && ${PHP_EXECUTABLE} DotnetTlDocumentationGenerator.php scheme/td_api.tl auto/td/telegram/TdDotNetApi.h) else() - set(GENERATE_DOTNET_API_CMD td_generate_dotnet_api ${TL_TD_API_TLO}) + set(GENERATE_DOTNET_API_CMD td_generate_dotnet_api ${TD_API_TLO_FILE}) endif() add_executable(td_generate_dotnet_api generate_dotnet.cpp tl_writer_dotnet.h) target_link_libraries(td_generate_dotnet_api PRIVATE tdtl) add_custom_target(generate_dotnet_api WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND ${GENERATE_DOTNET_API_CMD} ${TL_TD_API_TLO} + COMMAND ${GENERATE_DOTNET_API_CMD} COMMENT "Generate .NET API files" - DEPENDS td_generate_dotnet_api ${TL_TD_API_TLO} DotnetTlDocumentationGenerator.php + DEPENDS td_generate_dotnet_api tl_generate_tlo ${TD_API_TLO_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl ${CMAKE_CURRENT_SOURCE_DIR}/DotnetTlDocumentationGenerator.php ) endif() diff --git a/lib/tgchat/ext/td/td/generate/DoxygenTlDocumentationGenerator.php b/lib/tgchat/ext/td/td/generate/DoxygenTlDocumentationGenerator.php index 8f727a04..5acffadf 100644 --- a/lib/tgchat/ext/td/td/generate/DoxygenTlDocumentationGenerator.php +++ b/lib/tgchat/ext/td/td/generate/DoxygenTlDocumentationGenerator.php @@ -127,6 +127,7 @@ protected function needSkipLine($line) return empty($tline) || $tline[0] === '}' || $tline === 'public:' || strpos($line, '#pragma ') === 0 || strpos($line, '#include <') === 0 || strpos($tline, 'return ') === 0 || strpos($tline, 'namespace') === 0 || preg_match('/class [A-Za-z0-9_]*;/', $line) || $tline === 'if (value == nullptr) {' || + strpos($tline, 'result += ') === 0 || strpos($tline, 'result = ') || strpos($tline, ' : values') || strpos($line, 'JNIEnv') || strpos($line, 'jfieldID') || $tline === 'virtual ~Object() {' || $tline === 'virtual void store(TlStorerToString &s, const char *field_name) const = 0;'; } @@ -294,7 +295,7 @@ protected function addGlobalDocumentation() $this->addDocumentation('std::string to_string(const BaseObject &value);', <<addDocumentation('std::string to_string(const object_ptr &value) {', <<addDocumentation('std::string to_string(const std::vector> &values) {', <<addDocumentation(' void store(TlStorerToString &s, const char *field_name) const final;', << $field_info) { - if ($field_name !== 'description') { - $this->printError("Have info about unexisted field `$field_name`"); - } + foreach ($info as &$v) { + $v = $this->escapeDocumentation($this->addDot($v)); } - if (!$info['description']) { + $description = $info['description']; + unset($info['description']); + + if (!$description) { $this->printError("Have no description for class `$class_name`"); } - foreach ($info as &$v) { - $v = $this->escapeDocumentation($this->addDot($v)); + foreach (array_diff_key($info, $known_fields) as $field_name => $field_info) { + $this->printError("Have info about unexisted field `$field_name`"); + } + + if (array_keys($info) !== array_keys($known_fields)) { + $this->printError("Have wrong documentation for class `$class_name`"); } $base_class_name = $current_class ?: $this->getBaseClassName($is_function); - $class_description = $info['description']; + $class_description = $description; if ($is_function) { $class_description .= $this->getFunctionReturnTypeDescription($this->getTypeName($type), false); } @@ -254,7 +259,7 @@ public function generate($tl_scheme_file, $source_file) if ($is_function) { $default_constructor_prefix = 'Default constructor for a function, which '; $full_constructor_prefix = 'Creates a function, which '; - $class_description = lcfirst($info['description']); + $class_description = lcfirst($description); $class_description .= $this->getFunctionReturnTypeDescription($this->getTypeName($type), true); } else { $default_constructor_prefix = ''; diff --git a/lib/tgchat/ext/td/td/generate/generate_c.cpp b/lib/tgchat/ext/td/td/generate/generate_c.cpp index 3dbee73b..01831e72 100644 --- a/lib/tgchat/ext/td/td/generate/generate_c.cpp +++ b/lib/tgchat/ext/td/td/generate/generate_c.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -10,7 +10,7 @@ #include "td/tl/tl_generate.h" int main() { - td::tl::tl_config config_td = td::tl::read_tl_config_from_file("scheme/td_api.tlo"); + td::tl::tl_config config_td = td::tl::read_tl_config_from_file("auto/tlo/td_api.tlo"); td::tl::write_tl_to_file(config_td, "auto/td/telegram/td_tdc_api.h", td::TlWriterCCommon("TdApi", 1, "#include \"td/telegram/td_api.h\"\n")); td::tl::write_tl_to_file(config_td, "auto/td/telegram/td_tdc_api_inner.h", diff --git a/lib/tgchat/ext/td/td/generate/generate_common.cpp b/lib/tgchat/ext/td/td/generate/generate_common.cpp index 5d1b6f8d..8fcdc8e2 100644 --- a/lib/tgchat/ext/td/td/generate/generate_common.cpp +++ b/lib/tgchat/ext/td/td/generate/generate_common.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -22,7 +22,7 @@ static void generate_cpp(const std::string &directory, const std::string &tl_nam const std::string &bytes_type, const std::vector &ext_cpp_includes, const std::vector &ext_h_includes) { std::string path = directory + "/" + tl_name; - td::tl::tl_config config = td::tl::read_tl_config_from_file("scheme/" + tl_name + ".tlo"); + td::tl::tl_config config = td::tl::read_tl_config_from_file("auto/tlo/" + tl_name + ".tlo"); td::tl::write_tl_to_file(config, path + ".cpp", WriterCpp(tl_name, string_type, bytes_type, ext_cpp_includes)); td::tl::write_tl_to_file(config, path + ".h", WriterH(tl_name, string_type, bytes_type, ext_h_includes)); td::tl::write_tl_to_file(config, path + ".hpp", WriterHpp(tl_name, string_type, bytes_type)); diff --git a/lib/tgchat/ext/td/td/generate/generate_dotnet.cpp b/lib/tgchat/ext/td/td/generate/generate_dotnet.cpp index 916affd4..f9f7beba 100644 --- a/lib/tgchat/ext/td/td/generate/generate_dotnet.cpp +++ b/lib/tgchat/ext/td/td/generate/generate_dotnet.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/generate/generate_java.cpp b/lib/tgchat/ext/td/td/generate/generate_java.cpp index ecfa5a0f..d5b8aaf1 100644 --- a/lib/tgchat/ext/td/td/generate/generate_java.cpp +++ b/lib/tgchat/ext/td/td/generate/generate_java.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/generate/generate_json.cpp b/lib/tgchat/ext/td/td/generate/generate_json.cpp index 5c7783ca..b1e47add 100644 --- a/lib/tgchat/ext/td/td/generate/generate_json.cpp +++ b/lib/tgchat/ext/td/td/generate/generate_json.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -10,6 +10,6 @@ #include "td/tl/tl_generate.h" int main() { - td::gen_json_converter(td::tl::read_tl_config_from_file("scheme/td_api.tlo"), "td/telegram/td_api_json", + td::gen_json_converter(td::tl::read_tl_config_from_file("auto/tlo/td_api.tlo"), "td/telegram/td_api_json", td::tl::TL_writer::Server); } diff --git a/lib/tgchat/ext/td/td/generate/remove_documentation.cpp b/lib/tgchat/ext/td/td/generate/remove_documentation.cpp index 47a57328..598a4139 100644 --- a/lib/tgchat/ext/td/td/generate/remove_documentation.cpp +++ b/lib/tgchat/ext/td/td/generate/remove_documentation.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/generate/scheme/mtproto_api.tl b/lib/tgchat/ext/td/td/generate/scheme/mtproto_api.tl index fdfe78d8..de2e94bd 100644 --- a/lib/tgchat/ext/td/td/generate/scheme/mtproto_api.tl +++ b/lib/tgchat/ext/td/td/generate/scheme/mtproto_api.tl @@ -15,7 +15,6 @@ resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fing p_q_inner_data_dc#a9f55f95 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int = P_Q_inner_data; p_q_inner_data_temp_dc#56fddf88 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int expires_in:int = 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; @@ -41,8 +40,8 @@ future_salts#ae500895 req_msg_id:long now:int salts:vector = Future 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; +//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; @@ -80,18 +79,10 @@ set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:st rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer; get_future_salts#b921bd04 num:int = FutureSalts; -ping#7abe77ec ping_id:long = Pong; +//ping#7abe77ec ping_id:long = Pong; ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong; -destroy_session#e7512126 session_id:long = DestroySessionRes; +//destroy_session#e7512126 session_id:long = DestroySessionRes; http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; destroy_auth_key#d1435160 = DestroyAuthKeyRes; - -//test.useGzipPacked = GzipPacked; -//test.useServerDhInnerData = Server_DH_inner_data; -//test.useNewSessionCreated = NewSession; -//test.useMsgsAck = MsgsAck; -//test.useBadMsgNotification = BadMsgNotification; - -//test.useOther key:rsa_public_key p_q_data:P_Q_inner_data dh_data:client_DH_inner_data = RpcError; diff --git a/lib/tgchat/ext/td/td/generate/scheme/td_api.tl b/lib/tgchat/ext/td/td/generate/scheme/td_api.tl index 0b029223..6157eee8 100644 --- a/lib/tgchat/ext/td/td/generate/scheme/td_api.tl +++ b/lib/tgchat/ext/td/td/generate/scheme/td_api.tl @@ -52,11 +52,11 @@ authenticationCodeTypeSms length:int32 = AuthenticationCodeType; //@description An authentication code is delivered via a phone call to the specified phone number @length Length of the code authenticationCodeTypeCall length:int32 = AuthenticationCodeType; -//@description An authentication code is delivered by an immediately cancelled call to the specified phone number. The number from which the call was made is the code @pattern Pattern of the phone number from which the call will be made +//@description An authentication code is delivered by an immediately canceled call to the specified phone number. The number from which the call was made is the code @pattern Pattern of the phone number from which the call will be made authenticationCodeTypeFlashCall pattern:string = AuthenticationCodeType; -//@description Information about the authentication code that was sent @phone_number A phone number that is being authenticated @type Describes the way the code was sent to the user @next_type Describes the way the next code will be sent to the user; may be null @timeout Timeout before the code should be re-sent, in seconds +//@description Information about the authentication code that was sent @phone_number A phone number that is being authenticated @type The way the code was sent to the user @next_type The way the next code will be sent to the user; may be null @timeout Timeout before the code can be re-sent, in seconds authenticationCodeInfo phone_number:string type:AuthenticationCodeType next_type:AuthenticationCodeType timeout:int32 = AuthenticationCodeInfo; //@description Information about the email address authentication code that was sent @email_address_pattern Pattern of the email address to which an authentication code was sent @length Length of the code; 0 if unknown @@ -112,14 +112,15 @@ authorizationStateLoggingOut = AuthorizationState; authorizationStateClosing = AuthorizationState; //@description TDLib client is in its final state. All databases are closed and all resources are released. No other updates will be received after this. All queries will be responded to -//-with error code 500. To continue working, one should create a new instance of the TDLib client +//-with error code 500. To continue working, one must create a new instance of the TDLib client authorizationStateClosed = AuthorizationState; //@description Represents the current state of 2-step verification @has_password True, if a 2-step verification password is set @password_hint Hint for the password; may be empty //@has_recovery_email_address True, if a recovery email is set @has_passport_data True, if some Telegram Passport elements were saved //@recovery_email_address_code_info Information about the recovery email address to which the confirmation email was sent; may be null -passwordState has_password:Bool password_hint:string has_recovery_email_address:Bool has_passport_data:Bool recovery_email_address_code_info:emailAddressAuthenticationCodeInfo = PasswordState; +//@pending_reset_date If not 0, point in time (Unix timestamp) after which the password can be reset immediately using resetPassword +passwordState has_password:Bool password_hint:string has_recovery_email_address:Bool has_passport_data:Bool recovery_email_address_code_info:emailAddressAuthenticationCodeInfo pending_reset_date:int32 = PasswordState; //@description Contains information about the current recovery email address @recovery_email_address Recovery email address recoveryEmailAddress recovery_email_address:string = RecoveryEmailAddress; @@ -136,24 +137,24 @@ temporaryPasswordState has_password:Bool valid_for:int32 = TemporaryPasswordStat //@is_downloading_active True, if the file is currently being downloaded (or a local copy is being generated by some other means) //@is_downloading_completed True, if the local copy is fully available //@download_offset Download will be started from this offset. downloaded_prefix_size is calculated from this offset -//@downloaded_prefix_size If is_downloading_completed is false, then only some prefix of the file starting from download_offset is ready to be read. downloaded_prefix_size is the size of that prefix -//@downloaded_size Total downloaded file bytes. Should be used only for calculating download progress. The actual file size may be bigger, and some parts of it may contain garbage +//@downloaded_prefix_size If is_downloading_completed is false, then only some prefix of the file starting from download_offset is ready to be read. downloaded_prefix_size is the size of that prefix in bytes +//@downloaded_size Total downloaded file size, in bytes. Can be used only for calculating download progress. The actual file size may be bigger, and some parts of it may contain garbage localFile path:string can_be_downloaded:Bool can_be_deleted:Bool is_downloading_active:Bool is_downloading_completed:Bool download_offset:int32 downloaded_prefix_size:int32 downloaded_size:int32 = LocalFile; //@description Represents a remote file //@id Remote file identifier; may be empty. Can be used by the current user across application restarts or even from other devices. Uniquely identifies a file, but a file can have a lot of different valid identifiers. //-If the ID starts with "http://" or "https://", it represents the HTTP URL of the file. TDLib is currently unable to download files if only their URL is known. -//-If downloadFile is called on such a file or if it is sent to a secret chat, TDLib starts a file generation process by sending updateFileGenerationStart to the application with the HTTP URL in the original_path and "#url#" as the conversion string. Application should generate the file by downloading it to the specified location +//-If downloadFile is called on such a file or if it is sent to a secret chat, TDLib starts a file generation process by sending updateFileGenerationStart to the application with the HTTP URL in the original_path and "#url#" as the conversion string. Application must generate the file by downloading it to the specified location //@unique_id Unique file identifier; may be empty if unknown. The unique file identifier which is the same for the same file even for different users and is persistent over time //@is_uploading_active True, if the file is currently being uploaded (or a remote copy is being generated by some other means) //@is_uploading_completed True, if a remote copy is fully available -//@uploaded_size Size of the remote available part of the file; 0 if unknown +//@uploaded_size Size of the remote available part of the file, in bytes; 0 if unknown remoteFile id:string unique_id:string is_uploading_active:Bool is_uploading_completed:Bool uploaded_size:int32 = RemoteFile; //@description Represents a file //@id Unique file identifier -//@size File size; 0 if unknown -//@expected_size Expected file size in case the exact file size is unknown, but an approximate size is known. Can be used to show download/upload progress +//@size File size, in bytes; 0 if unknown +//@expected_size Approximate file size in bytes in case the exact file size is unknown. Can be used to show download/upload progress //@local Information about the local copy of the file //@remote Information about the remote copy of the file file id:int32 size:int32 expected_size:int32 local:localFile remote:remoteFile = File; @@ -173,14 +174,14 @@ inputFileRemote id:string = InputFile; inputFileLocal path:string = InputFile; //@description A file generated by the application @original_path Local path to a file from which the file is generated; may be empty if there is no such file -//@conversion String specifying the conversion applied to the original file; should be persistent across application restarts. Conversions beginning with '#' are reserved for internal TDLib usage -//@expected_size Expected size of the generated file; 0 if unknown +//@conversion String specifying the conversion applied to the original file; must be persistent across application restarts. Conversions beginning with '#' are reserved for internal TDLib usage +//@expected_size Expected size of the generated file, in bytes; 0 if unknown inputFileGenerated original_path:string conversion:string expected_size:int32 = InputFile; //@description Describes an image in JPEG format @type Image type (see https://core.telegram.org/constructor/photoSize) //@photo Information about the image file @width Image width @height Image height -//@progressive_sizes Sizes of progressive JPEG file prefixes, which can be used to preliminarily show the image +//@progressive_sizes Sizes of progressive JPEG file prefixes, which can be used to preliminarily show the image; in bytes photoSize type:string photo:file width:int32 height:int32 progressive_sizes:vector = PhotoSize; //@description Thumbnail image of a very poor quality and low resolution @width Thumbnail width, usually doesn't exceed 40 @height Thumbnail height, usually doesn't exceed 40 @data The thumbnail in JPEG format @@ -212,28 +213,36 @@ thumbnailFormatMpeg4 = ThumbnailFormat; thumbnail format:ThumbnailFormat width:int32 height:int32 file:file = Thumbnail; -//@class MaskPoint @description Part of the face, relative to which a mask should be placed +//@class MaskPoint @description Part of the face, relative to which a mask is placed -//@description A mask should be placed relatively to the forehead +//@description The mask is placed relatively to the forehead maskPointForehead = MaskPoint; -//@description A mask should be placed relatively to the eyes +//@description The mask is placed relatively to the eyes maskPointEyes = MaskPoint; -//@description A mask should be placed relatively to the mouth +//@description The mask is placed relatively to the mouth maskPointMouth = MaskPoint; -//@description A mask should be placed relatively to the chin +//@description The mask is placed relatively to the chin maskPointChin = MaskPoint; -//@description Position on a photo where a mask should be placed @point Part of the face, relative to which the mask should be placed +//@description Position on a photo where a mask is placed @point Part of the face, relative to which the mask is placed //@x_shift Shift by X-axis measured in widths of the mask scaled to the face size, from left to right. (For example, -1.0 will place the mask just to the left of the default mask position) //@y_shift Shift by Y-axis measured in heights of the mask scaled to the face size, from top to bottom. (For example, 1.0 will place the mask just below the default mask position) //@scale Mask scaling coefficient. (For example, 2.0 means a doubled size) maskPosition point:MaskPoint x_shift:double y_shift:double scale:double = MaskPosition; -//@description Describes one answer option of a poll @text Option text, 1-100 characters @voter_count Number of voters for this option, available only for closed or voted polls @vote_percentage The percentage of votes for this option, 0-100 +//@description Describes a color replacement for animated emoji @old_color Original animated emoji color in the RGB24 format @new_color Replacement animated emoji color in the RGB24 format +colorReplacement old_color:int32 new_color:int32 = ColorReplacement; + + +//@description Represents a closed vector path. The path begins at the end point of the last command @commands List of vector path commands +closedVectorPath commands:vector = ClosedVectorPath; + + +//@description Describes one answer option of a poll @text Option text; 1-100 characters @voter_count Number of voters for this option, available only for closed or voted polls @vote_percentage The percentage of votes for this option; 0-100 //@is_chosen True, if the option was chosen by the user @is_being_chosen True, if the option is being chosen by a pending setPollAnswer request pollOption text:string voter_count:int32 vote_percentage:int32 is_chosen:Bool is_being_chosen:Bool = PollOption; @@ -245,7 +254,7 @@ pollTypeRegular allow_multiple_answers:Bool = PollType; //@description A poll in quiz mode, which has exactly one correct answer option and can be answered only once //@correct_option_id 0-based identifier of the correct answer option; -1 for a yet unanswered poll -//@explanation Text that is shown when the user chooses an incorrect answer or taps on the lamp icon, 0-200 characters with at most 2 line feeds; empty for a yet unanswered poll +//@explanation Text that is shown when the user chooses an incorrect answer or taps on the lamp icon; 0-200 characters with at most 2 line feeds; empty for a yet unanswered poll pollTypeQuiz correct_option_id:int32 explanation:formattedText = PollType; @@ -257,7 +266,7 @@ animation duration:int32 width:int32 height:int32 file_name:string mime_type:str //@description Describes an audio file. Audio is usually in MP3 or M4A format @duration Duration of the audio, in seconds; as defined by the sender @title Title of the audio; as defined by the sender @performer Performer of the audio; as defined by the sender //@file_name Original name of the file; as defined by the sender @mime_type The MIME type of the file; as defined by the sender @album_cover_minithumbnail The minithumbnail of the album cover; may be null -//@album_cover_thumbnail The thumbnail of the album cover in JPEG format; as defined by the sender. The full size thumbnail should be extracted from the downloaded file; may be null @audio File containing the audio +//@album_cover_thumbnail The thumbnail of the album cover in JPEG format; as defined by the sender. The full size thumbnail is supposed to be extracted from the downloaded file; may be null @audio File containing the audio audio duration:int32 title:string performer:string file_name:string mime_type:string album_cover_minithumbnail:minithumbnail album_cover_thumbnail:thumbnail audio:file = Audio; //@description Describes a document of any type @file_name Original name of the file; as defined by the sender @mime_type MIME type of the file; as defined by the sender @@ -269,14 +278,14 @@ document file_name:string mime_type:string minithumbnail:minithumbnail thumbnail photo has_stickers:Bool minithumbnail:minithumbnail sizes:vector = Photo; //@description Describes a sticker @set_id The identifier of the sticker set to which the sticker belongs; 0 if none @width Sticker width; as defined by the sender @height Sticker height; as defined by the sender -//@emoji Emoji corresponding to the sticker @is_animated True, if the sticker is an animated sticker in TGS format @is_mask True, if the sticker is a mask @mask_position Position where the mask should be placed; may be null -//@thumbnail Sticker thumbnail in WEBP or JPEG format; may be null @sticker File containing the sticker -sticker set_id:int64 width:int32 height:int32 emoji:string is_animated:Bool is_mask:Bool mask_position:maskPosition thumbnail:thumbnail sticker:file = Sticker; +//@emoji Emoji corresponding to the sticker @is_animated True, if the sticker is an animated sticker in TGS format @is_mask True, if the sticker is a mask @mask_position Position where the mask is placed; may be null +//@outline Sticker's outline represented as a list of closed vector paths; may be empty. The coordinate system origin is in the upper-left corner @thumbnail Sticker thumbnail in WEBP or JPEG format; may be null @sticker File containing the sticker +sticker set_id:int64 width:int32 height:int32 emoji:string is_animated:Bool is_mask:Bool mask_position:maskPosition outline:vector thumbnail:thumbnail sticker:file = Sticker; //@description Describes a video file @duration Duration of the video, in seconds; as defined by the sender @width Video width; as defined by the sender @height Video height; as defined by the sender //@file_name Original name of the file; as defined by the sender @mime_type MIME type of the file; as defined by the sender //@has_stickers True, if stickers were added to the video. The list of corresponding sticker sets can be received using getAttachedStickerSets -//@supports_streaming True, if the video should be tried to be streamed @minithumbnail Video minithumbnail; may be null +//@supports_streaming True, if the video is supposed to be streamed @minithumbnail Video minithumbnail; may be null //@thumbnail Video thumbnail in JPEG or MPEG4 format; as defined by the sender; may be null @video File containing the video video duration:int32 width:int32 height:int32 file_name:string mime_type:string has_stickers:Bool supports_streaming:Bool minithumbnail:minithumbnail thumbnail:thumbnail video:file = Video; @@ -289,8 +298,14 @@ videoNote duration:int32 length:int32 minithumbnail:minithumbnail thumbnail:thum //@waveform A waveform representation of the voice note in 5-bit format @mime_type MIME type of the file; as defined by the sender @voice File containing the voice note voiceNote duration:int32 waveform:bytes mime_type:string voice:file = VoiceNote; +//@description Describes an animated representation of an emoji +//@sticker Animated sticker for the emoji +//@color_replacements List of colors to be replaced while the sticker is rendered +//@sound File containing the sound to be played when the animated emoji is clicked if any; may be null. The sound is encoded with the Opus codec, and stored inside an OGG container +animatedEmoji sticker:sticker color_replacements:vector sound:file = AnimatedEmoji; + //@description Describes a user contact @phone_number Phone number of the user @first_name First name of the user; 1-255 characters in length @last_name Last name of the user @vcard Additional data about the user in a form of vCard; 0-2048 bytes in length @user_id Identifier of the user, if known; otherwise 0 -contact phone_number:string first_name:string last_name:string vcard:string user_id:int32 = Contact; +contact phone_number:string first_name:string last_name:string vcard:string user_id:int53 = Contact; //@description Describes a location on planet Earth @latitude Latitude of the location in degrees; as defined by the sender @longitude Longitude of the location, in degrees; as defined by the sender //@horizontal_accuracy The estimated horizontal accuracy of the location, in meters; as defined by the sender. 0 if unknown @@ -304,24 +319,26 @@ venue location:location title:string address:string provider:string id:string ty //@param_description Game description @photo Game photo @animation Game animation; may be null game id:int64 short_name:string title:string text:formattedText description:string photo:photo animation:animation = Game; -//@description Describes a poll @id Unique poll identifier @question Poll question, 1-300 characters @options List of poll answer options +//@description Describes a poll @id Unique poll identifier @question Poll question; 1-300 characters @options List of poll answer options //@total_voter_count Total number of voters, participating in the poll @recent_voter_user_ids User identifiers of recent voters, if the poll is non-anonymous //@is_anonymous True, if the poll is anonymous @type Type of the poll //@open_period Amount of time the poll will be active after creation, in seconds @close_date Point in time (Unix timestamp) when the poll will be automatically closed @is_closed True, if the poll is closed -poll id:int64 question:string options:vector total_voter_count:int32 recent_voter_user_ids:vector is_anonymous:Bool type:PollType open_period:int32 close_date:int32 is_closed:Bool = Poll; +poll id:int64 question:string options:vector total_voter_count:int32 recent_voter_user_ids:vector is_anonymous:Bool type:PollType open_period:int32 close_date:int32 is_closed:Bool = Poll; //@description Describes a user profile photo @id Photo identifier; 0 for an empty photo. Can be used to find a photo in a list of user profile photos //@small A small (160x160) user profile photo. The file can be downloaded only before the photo is changed //@big A big (640x640) user profile photo. The file can be downloaded only before the photo is changed +//@minithumbnail User profile photo minithumbnail; may be null //@has_animation True, if the photo has animated variant -profilePhoto id:int64 small:file big:file has_animation:Bool = ProfilePhoto; +profilePhoto id:int64 small:file big:file minithumbnail:minithumbnail has_animation:Bool = ProfilePhoto; //@description Contains basic information about the photo of a chat //@small A small (160x160) chat photo variant in JPEG format. The file can be downloaded only before the photo is changed //@big A big (640x640) chat photo variant in JPEG format. The file can be downloaded only before the photo is changed +//@minithumbnail Chat photo minithumbnail; may be null //@has_animation True, if the photo has animated variant -chatPhotoInfo small:file big:file has_animation:Bool = ChatPhotoInfo; +chatPhotoInfo small:file big:file minithumbnail:minithumbnail has_animation:Bool = ChatPhotoInfo; //@class UserType @description Represents the type of a user. The following types are possible: regular users, deleted users and bots @@ -334,7 +351,7 @@ userTypeDeleted = UserType; //@description A bot (see https://core.telegram.org/bots) @can_join_groups True, if the bot can be invited to basic group and supergroup chats //@can_read_all_group_messages True, if the bot can read all messages in basic group or supergroup chats and not just those addressed to the bot. In private and channel chats a bot can always read all messages -//@is_inline True, if the bot supports inline queries @inline_query_placeholder Placeholder for inline queries (displayed on the application input field) @need_location True, if the location of the user should be sent with every inline query to this bot +//@is_inline True, if the bot supports inline queries @inline_query_placeholder Placeholder for inline queries (displayed on the application input field) @need_location True, if the location of the user is expected to be sent with every inline query to this bot userTypeBot can_join_groups:Bool can_read_all_group_messages:Bool is_inline:Bool inline_query_placeholder:string need_location:Bool = UserType; //@description No information on the user besides the user identifier is available, yet this user has not been deleted. This object is extremely rare and must be handled like a deleted user. It is not possible to perform any actions on users of this type @@ -344,8 +361,8 @@ userTypeUnknown = UserType; //@description Represents a command supported by a bot @command Text of the bot command @param_description Description of the bot command botCommand command:string description:string = BotCommand; -//@description Provides information about a bot and its supported commands @param_description Long description shown on the user info page @commands A list of commands supported by the bot -botInfo description:string commands:vector = BotInfo; +//@description Contains a list of bot commands @bot_user_id Bot's user identifier @commands List of bot commands +botCommands bot_user_id:int53 commands:vector = BotCommands; //@description Represents a location to which a chat is connected @location The location @address Location address; 1-64 characters, as defined by the chat owner @@ -373,7 +390,7 @@ chatPhotos total_count:int32 photos:vector = ChatPhotos; //@class InputChatPhoto @description Describes a photo to be set as a user profile or chat photo -//@description A previously used profile photo of the current user @chat_photo_id Identifier of the profile photo to reuse +//@description A previously used profile photo of the current user @chat_photo_id Identifier of the current user's profile photo to reuse inputChatPhotoPrevious chat_photo_id:int64 = InputChatPhoto; //@description A static photo in JPEG format @photo Photo to be set as profile photo. Only inputFileLocal and inputFileGenerated are allowed @@ -399,10 +416,11 @@ inputChatPhotoAnimation animation:InputFile main_frame_timestamp:double = InputC //@is_support True, if the user is Telegram support account //@restriction_reason If non-empty, it contains a human-readable description of the reason why access to this user must be restricted //@is_scam True, if many users reported this user as a scam +//@is_fake True, if many users reported this user as a fake account //@have_access If false, the user is inaccessible, and the only information known about the user is inside this class. It can't be passed to any method except GetUser //@type Type of the user //@language_code IETF language tag of the user's language; only available to bots -user id:int32 first_name:string last_name:string username:string phone_number:string status:UserStatus profile_photo:profilePhoto is_contact:Bool is_mutual_contact:Bool is_verified:Bool is_support:Bool restriction_reason:string is_scam:Bool have_access:Bool type:UserType language_code:string = User; +user id:int53 first_name:string last_name:string username:string phone_number:string status:UserStatus profile_photo:profilePhoto is_contact:Bool is_mutual_contact:Bool is_verified:Bool is_support:Bool restriction_reason:string is_scam:Bool is_fake:Bool have_access:Bool type:UserType language_code:string = User; //@description Contains full information about a user //@photo User profile photo; may be null @@ -411,17 +429,19 @@ user id:int32 first_name:string last_name:string username:string phone_number:st //@supports_video_calls True, if a video call can be created with the user //@has_private_calls True, if the user can't be called due to their privacy settings //@need_phone_number_privacy_exception True, if the current user needs to explicitly allow to share their phone number with the user when the method addContact is used -//@bio A short user bio @share_text For bots, the text that is included with the link when users share the bot +//@bio A short user bio +//@share_text For bots, the text that is shown on the bot's profile page and is sent together with the link when users share the bot +//@param_description For bots, the text shown in the chat with the bot if the chat is empty //@group_in_common_count Number of group chats where both the other user and the current user are a member; 0 for the current user -//@bot_info If the user is a bot, information about the bot; may be null -userFullInfo photo:chatPhoto is_blocked:Bool can_be_called:Bool supports_video_calls:Bool has_private_calls:Bool need_phone_number_privacy_exception:Bool bio:string share_text:string group_in_common_count:int32 bot_info:botInfo = UserFullInfo; +//@commands For bots, list of the bot commands +userFullInfo photo:chatPhoto is_blocked:Bool can_be_called:Bool supports_video_calls:Bool has_private_calls:Bool need_phone_number_privacy_exception:Bool bio:string share_text:string description:string group_in_common_count:int32 commands:vector = UserFullInfo; //@description Represents a list of users @total_count Approximate total count of users found @user_ids A list of user identifiers -users total_count:int32 user_ids:vector = Users; +users total_count:int32 user_ids:vector = Users; //@description Contains information about a chat administrator @user_id User identifier of the administrator @custom_title Custom title of the administrator @is_owner True, if the user is the owner of the chat -chatAdministrator user_id:int32 custom_title:string is_owner:Bool = ChatAdministrator; +chatAdministrator user_id:int53 custom_title:string is_owner:Bool = ChatAdministrator; //@description Represents a list of chat administrators @administrators A list of chat administrators chatAdministrators administrators:vector = ChatAdministrators; @@ -441,27 +461,29 @@ chatPermissions can_send_messages:Bool can_send_media_messages:Bool can_send_pol //@class ChatMemberStatus @description Provides information about the status of a member in a chat -//@description The user is the owner of a chat and has all the administrator privileges +//@description The user is the owner of the chat and has all the administrator privileges //@custom_title A custom title of the owner; 0-16 characters without emojis; applicable to supergroups only //@is_anonymous True, if the creator isn't shown in the chat member list and sends messages anonymously; applicable to supergroups only //@is_member True, if the user is a member of the chat chatMemberStatusCreator custom_title:string is_anonymous:Bool is_member:Bool = ChatMemberStatus; -//@description The user is a member of a chat and has some additional privileges. In basic groups, administrators can edit and delete messages sent by others, add new members, and ban unprivileged members. In supergroups and channels, there are more detailed options for administrator privileges +//@description The user is a member of the chat and has some additional privileges. In basic groups, administrators can edit and delete messages sent by others, add new members, ban unprivileged members, and manage video chats. In supergroups and channels, there are more detailed options for administrator privileges //@custom_title A custom title of the administrator; 0-16 characters without emojis; applicable to supergroups only //@can_be_edited True, if the current user can edit the administrator privileges for the called user +//@can_manage_chat True, if the administrator can get chat event log, get chat statistics, get message statistics in channels, get channel members, see anonymous administrators in supergroups and ignore slow mode. Implied by any other privilege; applicable to supergroups and channels only //@can_change_info True, if the administrator can change the chat title, photo, and other settings //@can_post_messages True, if the administrator can create channel posts; applicable to channels only //@can_edit_messages True, if the administrator can edit messages of other users and pin messages; applicable to channels only //@can_delete_messages True, if the administrator can delete messages of other users //@can_invite_users True, if the administrator can invite new users to the chat -//@can_restrict_members True, if the administrator can restrict, ban, or unban chat members -//@can_pin_messages True, if the administrator can pin messages; applicable to groups only +//@can_restrict_members True, if the administrator can restrict, ban, or unban chat members; always true for channels +//@can_pin_messages True, if the administrator can pin messages; applicable to basic groups and supergroups only //@can_promote_members True, if the administrator can add new administrators with a subset of their own privileges or demote administrators that were directly or indirectly promoted by them +//@can_manage_video_chats True, if the administrator can manage video chats //@is_anonymous True, if the administrator isn't shown in the chat member list and sends messages anonymously; applicable to supergroups only -chatMemberStatusAdministrator custom_title:string can_be_edited:Bool can_change_info:Bool can_post_messages:Bool can_edit_messages:Bool can_delete_messages:Bool can_invite_users:Bool can_restrict_members:Bool can_pin_messages:Bool can_promote_members:Bool is_anonymous:Bool = ChatMemberStatus; +chatMemberStatusAdministrator custom_title:string can_be_edited:Bool can_manage_chat:Bool can_change_info:Bool can_post_messages:Bool can_edit_messages:Bool can_delete_messages:Bool can_invite_users:Bool can_restrict_members:Bool can_pin_messages:Bool can_promote_members:Bool can_manage_video_chats:Bool is_anonymous:Bool = ChatMemberStatus; -//@description The user is a member of a chat, without any additional privileges or restrictions +//@description The user is a member of the chat, without any additional privileges or restrictions chatMemberStatusMember = ChatMemberStatus; //@description The user is under certain restrictions in the chat. Not supported in basic groups and channels @@ -470,20 +492,20 @@ chatMemberStatusMember = ChatMemberStatus; //@permissions User permissions in the chat chatMemberStatusRestricted is_member:Bool restricted_until_date:int32 permissions:chatPermissions = ChatMemberStatus; -//@description The user is not a chat member +//@description The user or the chat is not a chat member chatMemberStatusLeft = ChatMemberStatus; -//@description The user was banned (and hence is not a member of the chat). Implies the user can't return to the chat or view messages -//@banned_until_date Point in time (Unix timestamp) when the user will be unbanned; 0 if never. If the user is banned for more than 366 days or for less than 30 seconds from the current time, the user is considered to be banned forever +//@description The user or the chat was banned (and hence is not a member of the chat). Implies the user can't return to the chat, view messages, or be used as a participant identifier to join a video chat of the chat +//@banned_until_date Point in time (Unix timestamp) when the user will be unbanned; 0 if never. If the user is banned for more than 366 days or for less than 30 seconds from the current time, the user is considered to be banned forever. Always 0 in basic groups chatMemberStatusBanned banned_until_date:int32 = ChatMemberStatus; -//@description A user with information about joining/leaving a chat @user_id User identifier of the chat member +//@description Describes a user or a chat as a member of another chat +//@member_id Identifier of the chat member. Currently, other chats can be only Left or Banned. Only supergroups and channels can have other chats as Left or Banned members and these chats must be supergroups or channels //@inviter_user_id Identifier of a user that invited/promoted/banned this member in the chat; 0 if unknown //@joined_chat_date Point in time (Unix timestamp) when the user joined the chat //@status Status of the member in the chat -//@bot_info If the user is a bot, information about the bot; may be null. Can be null even for a bot if the bot is not the chat member -chatMember user_id:int32 inviter_user_id:int32 joined_chat_date:int32 status:ChatMemberStatus bot_info:botInfo = ChatMember; +chatMember member_id:MessageSender inviter_user_id:int53 joined_chat_date:int32 status:ChatMemberStatus = ChatMember; //@description Contains a list of chat members @total_count Approximate total count of chat members found @members A list of chat members chatMembers total_count:int32 members:vector = ChatMembers; @@ -540,21 +562,78 @@ supergroupMembersFilterMention query:string message_thread_id:int53 = Supergroup supergroupMembersFilterBots = SupergroupMembersFilter; +//@description Contains a chat invite link +//@invite_link Chat invite link +//@name Name of the link +//@creator_user_id User identifier of an administrator created the link +//@date Point in time (Unix timestamp) when the link was created +//@edit_date Point in time (Unix timestamp) when the link was last edited; 0 if never or unknown +//@expire_date Point in time (Unix timestamp) when the link will expire; 0 if never +//@member_limit The maximum number of members, which can join the chat using the link simultaneously; 0 if not limited. Always 0 if the link requires approval +//@member_count Number of chat members, which joined the chat using the link +//@pending_join_request_count Number of pending join requests created using this link +//@creates_join_request True, if the link only creates join request. If true, total number of joining members will be unlimited +//@is_primary True, if the link is primary. Primary invite link can't have name, expire date or usage limit. There is exactly one primary invite link for each administrator with can_invite_users right at a given time +//@is_revoked True, if the link was revoked +chatInviteLink invite_link:string name:string creator_user_id:int53 date:int32 edit_date:int32 expire_date:int32 member_limit:int32 member_count:int32 pending_join_request_count:int32 creates_join_request:Bool is_primary:Bool is_revoked:Bool = ChatInviteLink; + +//@description Contains a list of chat invite links @total_count Approximate total count of chat invite links found @invite_links List of invite links +chatInviteLinks total_count:int32 invite_links:vector = ChatInviteLinks; + +//@description Describes a chat administrator with a number of active and revoked chat invite links +//@user_id Administrator's user identifier +//@invite_link_count Number of active invite links +//@revoked_invite_link_count Number of revoked invite links +chatInviteLinkCount user_id:int53 invite_link_count:int32 revoked_invite_link_count:int32 = ChatInviteLinkCount; + +//@description Contains a list of chat invite link counts @invite_link_counts List of invite link counts +chatInviteLinkCounts invite_link_counts:vector = ChatInviteLinkCounts; + +//@description Describes a chat member joined a chat by an invite link @user_id User identifier @joined_chat_date Point in time (Unix timestamp) when the user joined the chat @approver_user_id User identifier of the chat administrator, approved user join request +chatInviteLinkMember user_id:int53 joined_chat_date:int32 approver_user_id:int53 = ChatInviteLinkMember; + +//@description Contains a list of chat members joined a chat by an invite link @total_count Approximate total count of chat members found @members List of chat members, joined a chat by an invite link +chatInviteLinkMembers total_count:int32 members:vector = ChatInviteLinkMembers; + +//@description Contains information about a chat invite link +//@chat_id Chat identifier of the invite link; 0 if the user has no access to the chat before joining +//@accessible_for If non-zero, the amount of time for which read access to the chat will remain available, in seconds +//@type Type of the chat +//@title Title of the chat +//@photo Chat photo; may be null +//@param_description Chat description +//@member_count Number of members in the chat +//@member_user_ids User identifiers of some chat members that may be known to the current user +//@creates_join_request True, if the link only creates join request +//@is_public True, if the chat is a public supergroup or channel, i.e. it has a username or it is a location-based supergroup +chatInviteLinkInfo chat_id:int53 accessible_for:int32 type:ChatType title:string photo:chatPhotoInfo description:string member_count:int32 member_user_ids:vector creates_join_request:Bool is_public:Bool = ChatInviteLinkInfo; + +//@description Describes a user that sent a join request and waits for administrator approval @user_id User identifier @date Point in time (Unix timestamp) when the user sent the join request @bio A short bio of the user +chatJoinRequest user_id:int53 date:int32 bio:string = ChatJoinRequest; + +//@description Contains a list of chat join requests @total_count Approximate total count of requests found @requests List of the requests +chatJoinRequests total_count:int32 requests:vector = ChatJoinRequests; + +//@description Contains information about pending chat join requests @total_count Total number of pending join requests @user_ids Identifiers of users sent the newest pending join requests +chatJoinRequestsInfo total_count:int32 user_ids:vector = ChatJoinRequestsInfo; + + //@description Represents a basic group of 0-200 users (must be upgraded to a supergroup to accommodate more than 200 users) //@id Group identifier //@member_count Number of members in the group //@status Status of the current user in the group //@is_active True, if the group is active //@upgraded_to_supergroup_id Identifier of the supergroup to which this group was upgraded; 0 if none -basicGroup id:int32 member_count:int32 status:ChatMemberStatus is_active:Bool upgraded_to_supergroup_id:int32 = BasicGroup; +basicGroup id:int53 member_count:int32 status:ChatMemberStatus is_active:Bool upgraded_to_supergroup_id:int53 = BasicGroup; //@description Contains full information about a basic group //@photo Chat photo; may be null -//@param_description Group description +//@param_description Group description. Updated only after the basic group is opened //@creator_user_id User identifier of the creator of the group; 0 if unknown //@members Group members -//@invite_link Invite link for this group; available only after it has been generated at least once and only for the group creator -basicGroupFullInfo photo:chatPhoto description:string creator_user_id:int32 members:vector invite_link:string = BasicGroupFullInfo; +//@invite_link Primary invite link for this group; may be null. For chat administrators with can_invite_users right only. Updated only after the basic group is opened +//@bot_commands List of commands of bots in the group +basicGroupFullInfo photo:chatPhoto description:string creator_user_id:int53 members:vector invite_link:chatInviteLink bot_commands:vector = BasicGroupFullInfo; //@description Represents a supergroup or channel with zero or more members (subscribers in the case of channels). From the point of view of the system, a channel is a special kind of a supergroup: only administrators can post and see the list of members, and posts from all administrators use the name and photo of the channel instead of individual names and profile photos. Unlike supergroups, channels can have an unlimited number of subscribers @@ -565,13 +644,15 @@ basicGroupFullInfo photo:chatPhoto description:string creator_user_id:int32 memb //@member_count Number of members in the supergroup or channel; 0 if unknown. Currently it is guaranteed to be known only if the supergroup or channel was received through searchPublicChats, searchChatsNearby, getInactiveSupergroupChats, getSuitableDiscussionChats, getGroupsInCommon, or getUserPrivacySettingRules //@has_linked_chat True, if the channel has a discussion group, or the supergroup is the designated discussion group for a channel //@has_location True, if the supergroup is connected to a location, i.e. the supergroup is a location-based supergroup -//@sign_messages True, if messages sent to the channel should contain information about the sender. This field is only applicable to channels +//@sign_messages True, if messages sent to the channel need to contain information about the sender. This field is only applicable to channels //@is_slow_mode_enabled True, if the slow mode is enabled in the supergroup //@is_channel True, if the supergroup is a channel +//@is_broadcast_group True, if the supergroup is a broadcast group, i.e. only administrators can send messages and there is no limit on number of members //@is_verified True, if the supergroup or channel is verified //@restriction_reason If non-empty, contains a human-readable description of the reason why access to this supergroup or channel must be restricted -//@is_scam True, if many users reported this supergroup as a scam -supergroup id:int32 username:string date:int32 status:ChatMemberStatus member_count:int32 has_linked_chat:Bool has_location:Bool sign_messages:Bool is_slow_mode_enabled:Bool is_channel:Bool is_verified:Bool restriction_reason:string is_scam:Bool = Supergroup; +//@is_scam True, if many users reported this supergroup or channel as a scam +//@is_fake True, if many users reported this supergroup or channel as a fake account +supergroup id:int53 username:string date:int32 status:ChatMemberStatus member_count:int32 has_linked_chat:Bool has_location:Bool sign_messages:Bool is_slow_mode_enabled:Bool is_channel:Bool is_broadcast_group:Bool is_verified:Bool restriction_reason:string is_scam:Bool is_fake:Bool = Supergroup; //@description Contains full information about a supergroup or channel //@photo Chat photo; may be null @@ -591,10 +672,11 @@ supergroup id:int32 username:string date:int32 status:ChatMemberStatus member_co //@is_all_history_available True, if new chat members will have access to old messages. In public or discussion groups and both public and private channels, old messages are always available, so this option affects only private supergroups without a linked chat. The value of this field is only available for chat administrators //@sticker_set_id Identifier of the supergroup sticker set; 0 if none //@location Location to which the supergroup is connected; may be null -//@invite_link Invite link for this chat +//@invite_link Primary invite link for this chat; may be null. For chat administrators with can_invite_users right only +//@bot_commands List of commands of bots in the group //@upgraded_from_basic_group_id Identifier of the basic group from which supergroup was upgraded; 0 if none //@upgraded_from_max_message_id Identifier of the last message in the basic group from which supergroup was upgraded; 0 if none -supergroupFullInfo photo:chatPhoto description:string member_count:int32 administrator_count:int32 restricted_count:int32 banned_count:int32 linked_chat_id:int53 slow_mode_delay:int32 slow_mode_delay_expires_in:double can_get_members:Bool can_set_username:Bool can_set_sticker_set:Bool can_set_location:Bool can_get_statistics:Bool is_all_history_available:Bool sticker_set_id:int64 location:chatLocation invite_link:string upgraded_from_basic_group_id:int32 upgraded_from_max_message_id:int53 = SupergroupFullInfo; +supergroupFullInfo photo:chatPhoto description:string member_count:int32 administrator_count:int32 restricted_count:int32 banned_count:int32 linked_chat_id:int53 slow_mode_delay:int32 slow_mode_delay_expires_in:double can_get_members:Bool can_set_username:Bool can_set_sticker_set:Bool can_set_location:Bool can_get_statistics:Bool is_all_history_available:Bool sticker_set_id:int64 location:chatLocation invite_link:chatInviteLink bot_commands:vector upgraded_from_basic_group_id:int53 upgraded_from_max_message_id:int53 = SupergroupFullInfo; //@class SecretChatState @description Describes the current secret chat state @@ -614,17 +696,16 @@ secretChatStateClosed = SecretChatState; //@user_id Identifier of the chat partner //@state State of the secret chat //@is_outbound True, if the chat was created by the current user; otherwise false -//@ttl Current message Time To Live setting (self-destruct timer) for the chat, in seconds //@key_hash Hash of the currently used key for comparison with the hash of the chat partner's key. This is a string of 36 little-endian bytes, which must be split into groups of 2 bits, each denoting a pixel of one of 4 colors FFFFFF, D5E6F3, 2D5775, and 2F99C9. //-The pixels must be used to make a 12x12 square image filled from left to right, top to bottom. Alternatively, the first 32 bytes of the hash can be converted to the hexadecimal format and printed as 32 2-digit hex numbers -//@layer Secret chat layer; determines features supported by the chat partner's application. Video notes are supported if the layer >= 66; nested text entities and underline and strikethrough entities are supported if the layer >= 101 -secretChat id:int32 user_id:int32 state:SecretChatState is_outbound:Bool ttl:int32 key_hash:bytes layer:int32 = SecretChat; +//@layer Secret chat layer; determines features supported by the chat partner's application. Nested text entities and underline and strikethrough entities are supported if the layer >= 101 +secretChat id:int32 user_id:int53 state:SecretChatState is_outbound:Bool key_hash:bytes layer:int32 = SecretChat; //@class MessageSender @description Contains information about the sender of a message //@description The message was sent by a known user @user_id Identifier of the user that sent the message -messageSenderUser user_id:int32 = MessageSender; +messageSenderUser user_id:int53 = MessageSender; //@description The message was sent on behalf of a chat @chat_id Identifier of the chat that sent the message messageSenderChat chat_id:int53 = MessageSender; @@ -637,7 +718,7 @@ messageSenders total_count:int32 senders:vector = MessageSenders; //@class MessageForwardOrigin @description Contains information about the origin of a forwarded message //@description The message was originally sent by a known user @sender_user_id Identifier of the user that originally sent the message -messageForwardOriginUser sender_user_id:int32 = MessageForwardOrigin; +messageForwardOriginUser sender_user_id:int53 = MessageForwardOrigin; //@description The message was originally sent by an anonymous chat administrator on behalf of the chat //@sender_chat_id Identifier of the chat that originally sent the message @@ -653,6 +734,9 @@ messageForwardOriginHiddenUser sender_name:string = MessageForwardOrigin; //@author_signature Original post author signature messageForwardOriginChannel chat_id:int53 message_id:int53 author_signature:string = MessageForwardOrigin; +//@description The message was imported from an exported message history @sender_name Name of the sender +messageForwardOriginMessageImport sender_name:string = MessageForwardOrigin; + //@description Contains information about a forwarded message //@origin Origin of a forwarded message @@ -673,7 +757,7 @@ messageReplyInfo reply_count:int32 recent_repliers:vector last_re //@description Contains information about interactions with a message //@view_count Number of times the message was viewed //@forward_count Number of times the message was forwarded -//@reply_info Contains information about direct or indirect replies to the message; may be null. Currently, available only in channels with a discussion supergroup and discussion supergroups for messages, which are not replies itself +//@reply_info Information about direct or indirect replies to the message; may be null. Currently, available only in channels with a discussion supergroup and discussion supergroups for messages, which are not replies itself messageInteractionInfo view_count:int32 forward_count:int32 reply_info:messageReplyInfo = MessageInteractionInfo; @@ -691,8 +775,8 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool r //@id Message identifier; unique for the chat to which the message belongs //@sender The sender of the message //@chat_id Chat identifier -//@sending_state Information about the sending state of the message; may be null -//@scheduling_state Information about the scheduling state of the message; may be null +//@sending_state The sending state of the message; may be null +//@scheduling_state The scheduling state of the message; may be null //@is_outgoing True, if the message is outgoing //@is_pinned True, if the message is pinned //@can_be_edited True, if the message can be edited. For live location and poll messages this fields shows whether editMessageLiveLocation or stopPoll can be used with this message by the application @@ -701,6 +785,9 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool r //@can_be_deleted_for_all_users True, if the message can be deleted for all users //@can_get_statistics True, if the message statistics are available //@can_get_message_thread True, if the message thread info is available +//@can_get_viewers True, if chat members already viewed the message can be received through getMessageViewers +//@can_get_media_timestamp_links True, if media timestamp links can be generated for media timestamp entities in the message text, caption or web page description +//@has_timestamped_media True, if media timestamp entities refers to a media in this message as opposed to a media in the replied message //@is_channel_post True, if the message is a channel post. All messages to channels are channel posts, all other messages are not channel posts //@contains_unread_mention True, if the message contains an unread mention for the current user //@date Point in time (Unix timestamp) when the message was sent @@ -711,14 +798,14 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool r //@reply_to_message_id If non-zero, the identifier of the message this message is replying to; can be the identifier of a deleted message //@message_thread_id If non-zero, the identifier of the message thread the message belongs to; unique within the chat to which the message belongs //@ttl For self-destructing messages, the message's TTL (Time To Live), in seconds; 0 if none. TDLib will send updateDeleteMessages or updateMessageContent once the TTL expires -//@ttl_expires_in Time left before the message expires, in seconds +//@ttl_expires_in Time left before the message expires, in seconds. If the TTL timer isn't started yet, equals to the value of the ttl field //@via_bot_user_id If non-zero, the user identifier of the bot through which this message was sent //@author_signature For channel posts and anonymous group messages, optional author signature -//@media_album_id Unique identifier of an album this message belongs to. Only photos and videos can be grouped together in albums +//@media_album_id Unique identifier of an album this message belongs to. Only audios, documents, photos and videos can be grouped together in albums //@restriction_reason If non-empty, contains a human-readable description of the reason why access to this message must be restricted //@content Content of the message //@reply_markup Reply markup for the message; may be null -message id:int53 sender:MessageSender chat_id:int53 sending_state:MessageSendingState scheduling_state:MessageSchedulingState is_outgoing:Bool is_pinned:Bool can_be_edited:Bool can_be_forwarded:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_get_statistics:Bool can_get_message_thread:Bool is_channel_post:Bool contains_unread_mention:Bool date:int32 edit_date:int32 forward_info:messageForwardInfo interaction_info:messageInteractionInfo reply_in_chat_id:int53 reply_to_message_id:int53 message_thread_id:int53 ttl:int32 ttl_expires_in:double via_bot_user_id:int32 author_signature:string media_album_id:int64 restriction_reason:string content:MessageContent reply_markup:ReplyMarkup = Message; +message id:int53 sender:MessageSender chat_id:int53 sending_state:MessageSendingState scheduling_state:MessageSchedulingState is_outgoing:Bool is_pinned:Bool can_be_edited:Bool can_be_forwarded:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_get_statistics:Bool can_get_message_thread:Bool can_get_viewers:Bool can_get_media_timestamp_links:Bool has_timestamped_media:Bool is_channel_post:Bool contains_unread_mention:Bool date:int32 edit_date:int32 forward_info:messageForwardInfo interaction_info:messageInteractionInfo reply_in_chat_id:int53 reply_to_message_id:int53 message_thread_id:int53 ttl:int32 ttl_expires_in:double via_bot_user_id:int53 author_signature:string media_album_id:int64 restriction_reason:string content:MessageContent reply_markup:ReplyMarkup = Message; //@description Contains a list of messages @total_count Approximate total count of messages found @messages List of messages; messages may be null messages total_count:int32 messages:vector = Messages; @@ -726,8 +813,28 @@ messages total_count:int32 messages:vector = Messages; //@description Contains a list of messages found by a search @total_count Approximate total count of messages found; -1 if unknown @messages List of messages @next_offset The offset for the next request. If empty, there are no more results foundMessages total_count:int32 messages:vector next_offset:string = FoundMessages; +//@description Contains information about a message in a specific position @position 0-based message position in the full list of suitable messages @message_id Message identifier @date Point in time (Unix timestamp) when the message was sent +messagePosition position:int32 message_id:int53 date:int32 = MessagePosition; + +//@description Contains a list of message positions @total_count Total count of messages found @positions List of message positions +messagePositions total_count:int32 positions:vector = MessagePositions; + +//@description Contains information about found messages sent in a specific day @total_count Total number of found messages sent in the day @message First message sent in the day +messageCalendarDay total_count:int32 message:message = MessageCalendarDay; + +//@description Contains information about found messages, splitted by days according to the option "utc_time_offset" @total_count Total number of found messages @days Information about messages sent +messageCalendar total_count:int32 days:vector = MessageCalendar; + + +//@description Describes a sponsored message @id Unique sponsored message identifier @sponsor_chat_id Chat identifier +//@link An internal link to be opened when the sponsored message is clicked; may be null. If null, the sponsor chat needs to be opened instead @content Content of the message +sponsoredMessage id:int32 sponsor_chat_id:int53 link:InternalLinkType content:MessageContent = SponsoredMessage; + +//@description Contains a list of sponsored messages @messages List of sponsored messages +sponsoredMessages messages:vector = SponsoredMessages; -//@class NotificationSettingsScope @description Describes the types of chats to which notification settings are applied + +//@class NotificationSettingsScope @description Describes the types of chats to which notification settings are relevant //@description Notification settings applied to all private and secret chats when the corresponding chat setting has a default value notificationSettingsScopePrivateChats = NotificationSettingsScope; @@ -742,7 +849,7 @@ notificationSettingsScopeChannelChats = NotificationSettingsScope; //@description Contains information about notification settings for a chat //@use_default_mute_for If true, mute_for is ignored and the value for the relevant type of chat is used instead @mute_for Time left before notifications will be unmuted, in seconds //@use_default_sound If true, sound is ignored and the value for the relevant type of chat is used instead @sound The name of an audio file to be used for notification sounds; only applies to iOS applications -//@use_default_show_preview If true, show_preview is ignored and the value for the relevant type of chat is used instead @show_preview True, if message content should be displayed in notifications +//@use_default_show_preview If true, show_preview is ignored and the value for the relevant type of chat is used instead @show_preview True, if message content must be displayed in notifications //@use_default_disable_pinned_message_notifications If true, disable_pinned_message_notifications is ignored and the value for the relevant type of chat is used instead @disable_pinned_message_notifications If true, notifications for incoming pinned messages will be created as for an ordinary unread message //@use_default_disable_mention_notifications If true, disable_mention_notifications is ignored and the value for the relevant type of chat is used instead @disable_mention_notifications If true, notifications for messages with mentions will be created as for an ordinary unread message chatNotificationSettings use_default_mute_for:Bool mute_for:int32 use_default_sound:Bool sound:string use_default_show_preview:Bool show_preview:Bool use_default_disable_pinned_message_notifications:Bool disable_pinned_message_notifications:Bool use_default_disable_mention_notifications:Bool disable_mention_notifications:Bool = ChatNotificationSettings; @@ -750,7 +857,7 @@ chatNotificationSettings use_default_mute_for:Bool mute_for:int32 use_default_so //@description Contains information about notification settings for several chats //@mute_for Time left before notifications will be unmuted, in seconds //@sound The name of an audio file to be used for notification sounds; only applies to iOS applications -//@show_preview True, if message content should be displayed in notifications +//@show_preview True, if message content must be displayed in notifications //@disable_pinned_message_notifications True, if notifications for incoming pinned messages will be created as for an ordinary unread message //@disable_mention_notifications True, if notifications for messages with mentions will be created as for an ordinary unread message scopeNotificationSettings mute_for:int32 sound:string show_preview:Bool disable_pinned_message_notifications:Bool disable_mention_notifications:Bool = ScopeNotificationSettings; @@ -759,23 +866,23 @@ scopeNotificationSettings mute_for:int32 sound:string show_preview:Bool disable_ //@description Contains information about a message draft //@reply_to_message_id Identifier of the message to reply to; 0 if none //@date Point in time (Unix timestamp) when the draft was created -//@input_message_text Content of the message draft; this should always be of type inputMessageText +//@input_message_text Content of the message draft; must be of the type inputMessageText draftMessage reply_to_message_id:int53 date:int32 input_message_text:InputMessageContent = DraftMessage; //@class ChatType @description Describes the type of a chat //@description An ordinary chat with a user @user_id User identifier -chatTypePrivate user_id:int32 = ChatType; +chatTypePrivate user_id:int53 = ChatType; -//@description A basic group (i.e., a chat with 0-200 other users) @basic_group_id Basic group identifier -chatTypeBasicGroup basic_group_id:int32 = ChatType; +//@description A basic group (a chat with 0-200 other users) @basic_group_id Basic group identifier +chatTypeBasicGroup basic_group_id:int53 = ChatType; -//@description A supergroup (i.e. a chat with up to GetOption("supergroup_max_size") other users), or channel (with unlimited members) @supergroup_id Supergroup or channel identifier @is_channel True, if the supergroup is a channel -chatTypeSupergroup supergroup_id:int32 is_channel:Bool = ChatType; +//@description A supergroup or channel (with unlimited members) @supergroup_id Supergroup or channel identifier @is_channel True, if the supergroup is a channel +chatTypeSupergroup supergroup_id:int53 is_channel:Bool = ChatType; //@description A secret chat with a user @secret_chat_id Secret chat identifier @user_id User identifier of the secret chat peer -chatTypeSecret secret_chat_id:int32 user_id:int32 = ChatType; +chatTypeSecret secret_chat_id:int32 user_id:int53 = ChatType; //@description Represents a filter of user chats @@ -840,6 +947,13 @@ chatSourcePublicServiceAnnouncement type:string text:string = ChatSource; chatPosition list:ChatList order:int64 is_pinned:Bool source:ChatSource = ChatPosition; +//@description Describes a video chat +//@group_call_id Group call identifier of an active video chat; 0 if none. Full information about the video chat can be received through the method getGroupCall +//@has_participants True, if the video chat has participants +//@default_participant_id Default group call participant identifier to join the video chat; may be null +videoChat group_call_id:int32 has_participants:Bool default_participant_id:MessageSender = VideoChat; + + //@description A chat. (Can be a private chat, basic group, supergroup, or secret chat) //@id Chat unique identifier //@type Type of the chat @@ -853,18 +967,22 @@ chatPosition list:ChatList order:int64 is_pinned:Bool source:ChatSource = ChatPo //@has_scheduled_messages True, if the chat has scheduled messages //@can_be_deleted_only_for_self True, if the chat messages can be deleted only for the current user while other users will continue to see the messages //@can_be_deleted_for_all_users True, if the chat messages can be deleted for all users -//@can_be_reported True, if the chat can be reported to Telegram moderators through reportChat +//@can_be_reported True, if the chat can be reported to Telegram moderators through reportChat or reportChatPhoto //@default_disable_notification Default value of the disable_notification parameter, used when a message is sent to the chat //@unread_count Number of unread messages in the chat //@last_read_inbox_message_id Identifier of the last read incoming message //@last_read_outbox_message_id Identifier of the last read outgoing message //@unread_mention_count Number of unread messages with a mention/reply in the chat //@notification_settings Notification settings for this chat -//@action_bar Describes actions which should be possible to do through a chat action bar; may be null +//@message_ttl_setting Current message Time To Live setting (self-destruct timer) for the chat; 0 if not defined. TTL is counted from the time message or its content is viewed in secret chats and from the send date in other chats +//@theme_name If non-empty, name of a theme, set for the chat +//@action_bar Information about actions which must be possible to do through the chat action bar; may be null +//@video_chat Information about video chat of the chat +//@pending_join_requests Information about pending join requests; may be null //@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat //@draft_message A draft of a message in the chat; may be null -//@client_data Contains application-specific data associated with the chat. (For example, the chat scroll position or local chat notification settings can be stored here.) Persistent if the message database is used -chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings action_bar:ChatActionBar reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; +//@client_data Application-specific data associated with the chat. (For example, the chat scroll position or local chat notification settings can be stored here.) Persistent if the message database is used +chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl_setting:int32 theme_name:string action_bar:ChatActionBar video_chat:videoChat pending_join_requests:chatJoinRequestsInfo reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; //@description Represents a list of chats @total_count Approximate total count of chats found @chat_ids List of chat identifiers chats total_count:int32 chat_ids:vector = Chats; @@ -877,21 +995,6 @@ chatNearby chat_id:int53 distance:int32 = ChatNearby; chatsNearby users_nearby:vector supergroups_nearby:vector = ChatsNearby; -//@description Contains a chat invite link @invite_link Chat invite link -chatInviteLink invite_link:string = ChatInviteLink; - -//@description Contains information about a chat invite link -//@chat_id Chat identifier of the invite link; 0 if the user has no access to the chat before joining -//@accessible_for If non-zero, the amount of time for which read access to the chat will remain available, in seconds -//@type Contains information about the type of the chat -//@title Title of the chat -//@photo Chat photo; may be null -//@member_count Number of members in the chat -//@member_user_ids User identifiers of some chat members that may be known to the current user -//@is_public True, if the chat is a public supergroup or channel, i.e. it has a username or it is a location-based supergroup -chatInviteLinkInfo chat_id:int53 accessible_for:int32 type:ChatType title:string photo:chatPhotoInfo member_count:int32 member_user_ids:vector is_public:Bool = ChatInviteLinkInfo; - - //@class PublicChatType @description Describes a type of public chats //@description The chat is public, because it has username @@ -901,7 +1004,7 @@ publicChatTypeHasUsername = PublicChatType; publicChatTypeIsLocationBased = PublicChatType; -//@class ChatActionBar @description Describes actions which should be possible to do through a chat action bar +//@class ChatActionBar @description Describes actions which must be possible to do through a chat action bar //@description The chat can be reported as spam using the method reportChat with the reason chatReportReasonSpam //@can_unarchive If true, the chat was automatically archived and can be moved back to the main chat list using addChatToList simultaneously with setting chat notification settings to default using setChatNotificationSettings @@ -910,7 +1013,10 @@ chatActionBarReportSpam can_unarchive:Bool = ChatActionBar; //@description The chat is a location-based supergroup, which can be reported as having unrelated location using the method reportChat with the reason chatReportReasonUnrelatedLocation chatActionBarReportUnrelatedLocation = ChatActionBar; -//@description The chat is a private or secret chat, which can be reported using the method reportChat, or the other user can be blocked using the method blockUser, or the other user can be added to the contact list using the method addContact +//@description The chat is a recently created group chat, to which new members can be invited +chatActionBarInviteMembers = ChatActionBar; + +//@description The chat is a private or secret chat, which can be reported using the method reportChat, or the other user can be blocked using the method toggleMessageSenderIsBlocked, or the other user can be added to the contact list using the method addContact //@can_unarchive If true, the chat was automatically archived and can be moved back to the main chat list using addChatToList simultaneously with setting chat notification settings to default using setChatNotificationSettings //@distance If non-negative, the current user was found by the peer through searchChatsNearby and this is the distance between the users chatActionBarReportAddBlock can_unarchive:Bool distance:int32 = ChatActionBar; @@ -924,7 +1030,7 @@ chatActionBarSharePhoneNumber = ChatActionBar; //@class KeyboardButtonType @description Describes a keyboard button type -//@description A simple button, with text that should be sent when the button is pressed +//@description A simple button, with text that must be sent when the button is pressed keyboardButtonTypeText = KeyboardButtonType; //@description A button that sends the user's phone number when pressed; available only in private chats @@ -946,8 +1052,8 @@ keyboardButton text:string type:KeyboardButtonType = KeyboardButton; //@description A button that opens a specified URL @url HTTP or tg:// URL to open inlineKeyboardButtonTypeUrl url:string = InlineKeyboardButtonType; -//@description A button that opens a specified URL and automatically logs in in current user if they allowed to do that @url An HTTP URL to open @id Unique button identifier @forward_text If non-empty, new text of the button in forwarded messages -inlineKeyboardButtonTypeLoginUrl url:string id:int32 forward_text:string = InlineKeyboardButtonType; +//@description A button that opens a specified URL and automatically authorize the current user if allowed to do so @url An HTTP URL to open @id Unique button identifier @forward_text If non-empty, new text of the button in forwarded messages +inlineKeyboardButtonTypeLoginUrl url:string id:int53 forward_text:string = InlineKeyboardButtonType; //@description A button that sends a callback query to a bot @data Data to be sent to the bot via a callback query inlineKeyboardButtonTypeCallback data:bytes = InlineKeyboardButtonType; @@ -958,7 +1064,7 @@ inlineKeyboardButtonTypeCallbackWithPassword data:bytes = InlineKeyboardButtonTy //@description A button with a game that sends a callback query to a bot. This button must be in the first column and row of the keyboard and can be attached only to a message with content of the type messageGame inlineKeyboardButtonTypeCallbackGame = InlineKeyboardButtonType; -//@description A button that forces an inline query to the bot to be inserted in the input field @query Inline query to be sent to the bot @in_current_chat True, if the inline query should be sent from the current chat +//@description A button that forces an inline query to the bot to be inserted in the input field @query Inline query to be sent to the bot @in_current_chat True, if the inline query must be sent from the current chat inlineKeyboardButtonTypeSwitchInline query:string in_current_chat:Bool = InlineKeyboardButtonType; //@description A button to buy something. This button must be in the first column and row of the keyboard and can be attached only to a message with content of the type messageInvoice @@ -977,14 +1083,16 @@ replyMarkupRemoveKeyboard is_personal:Bool = ReplyMarkup; //@description Instructs application to force a reply to this message //@is_personal True, if a forced reply must automatically be shown to the current user. For outgoing messages, specify true to show the forced reply only for the mentioned users and for the target user of a reply -replyMarkupForceReply is_personal:Bool = ReplyMarkup; +//@input_field_placeholder If non-empty, the placeholder to be shown in the input field when the reply is active; 0-64 characters +replyMarkupForceReply is_personal:Bool input_field_placeholder:string = ReplyMarkup; //@description Contains a custom keyboard layout to quickly reply to bots //@rows A list of rows of bot keyboard buttons //@resize_keyboard True, if the application needs to resize the keyboard vertically //@one_time True, if the application needs to hide the keyboard after use //@is_personal True, if the keyboard must automatically be shown to the current user. For outgoing messages, specify true to show the keyboard only for the mentioned users and for the target user of a reply -replyMarkupShowKeyboard rows:vector> resize_keyboard:Bool one_time:Bool is_personal:Bool = ReplyMarkup; +//@input_field_placeholder If non-empty, the placeholder to be shown in the input field when the keyboard is active; 0-64 characters +replyMarkupShowKeyboard rows:vector> resize_keyboard:Bool one_time:Bool is_personal:Bool input_field_placeholder:string = ReplyMarkup; //@description Contains an inline keyboard layout //@rows A list of rows of inline keyboard buttons @@ -998,16 +1106,17 @@ loginUrlInfoOpen url:string skip_confirm:Bool = LoginUrlInfo; //@description An authorization confirmation dialog needs to be shown to the user @url An HTTP URL to be opened @domain A domain of the URL //@bot_user_id User identifier of a bot linked with the website @request_write_access True, if the user needs to be requested to give the permission to the bot to send them messages -loginUrlInfoRequestConfirmation url:string domain:string bot_user_id:int32 request_write_access:Bool = LoginUrlInfo; +loginUrlInfoRequestConfirmation url:string domain:string bot_user_id:int53 request_write_access:Bool = LoginUrlInfo; //@description Contains information about a message thread //@chat_id Identifier of the chat to which the message thread belongs //@message_thread_id Message thread identifier, unique within the chat -//@reply_info Contains information about the message thread +//@reply_info Information about the message thread +//@unread_message_count Approximate number of unread messages in the message thread //@messages The messages from which the thread starts. The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id) //@draft_message A draft of a message in the message thread; may be null -messageThreadInfo chat_id:int53 message_thread_id:int53 reply_info:messageReplyInfo messages:vector draft_message:draftMessage = MessageThreadInfo; +messageThreadInfo chat_id:int53 message_thread_id:int53 reply_info:messageReplyInfo unread_message_count:int32 messages:vector draft_message:draftMessage = MessageThreadInfo; //@class RichText @description Describes a text object inside an instant-view web page @@ -1049,8 +1158,8 @@ richTextMarked text:RichText = RichText; richTextPhoneNumber text:RichText phone_number:string = RichText; //@description A small image inside the text @document The image represented as a document. The image can be in GIF, JPEG or PNG format -//@width Width of a bounding box in which the image should be shown; 0 if unknown -//@height Height of a bounding box in which the image should be shown; 0 if unknown +//@width Width of a bounding box in which the image must be shown; 0 if unknown +//@height Height of a bounding box in which the image must be shown; 0 if unknown richTextIcon document:document width:int32 height:int32 = RichText; //@description A reference to a richTexts object on the same web page @text The text @anchor_name The name of a richTextAnchor object, which is the first element of the target richTexts object @url An HTTP URL, opening the reference @@ -1059,7 +1168,7 @@ richTextReference text:RichText anchor_name:string url:string = RichText; //@description An anchor @name Anchor name richTextAnchor name:string = RichText; -//@description A link to an anchor on the same web page @text The link text @anchor_name The anchor name. If the name is empty, the link should bring back to top @url An HTTP URL, opening the anchor +//@description A link to an anchor on the same web page @text The link text @anchor_name The anchor name. If the name is empty, the link must bring back to top @url An HTTP URL, opening the anchor richTextAnchorLink text:RichText anchor_name:string url:string = RichText; //@description A concatenation of rich texts @texts Texts @@ -1074,28 +1183,28 @@ pageBlockListItem label:string page_blocks:vector = PageBlockListItem //@class PageBlockHorizontalAlignment @description Describes a horizontal alignment of a table cell content -//@description The content should be left-aligned +//@description The content must be left-aligned pageBlockHorizontalAlignmentLeft = PageBlockHorizontalAlignment; -//@description The content should be center-aligned +//@description The content must be center-aligned pageBlockHorizontalAlignmentCenter = PageBlockHorizontalAlignment; -//@description The content should be right-aligned +//@description The content must be right-aligned pageBlockHorizontalAlignmentRight = PageBlockHorizontalAlignment; //@class PageBlockVerticalAlignment @description Describes a Vertical alignment of a table cell content -//@description The content should be top-aligned +//@description The content must be top-aligned pageBlockVerticalAlignmentTop = PageBlockVerticalAlignment; -//@description The content should be middle-aligned +//@description The content must be middle-aligned pageBlockVerticalAlignmentMiddle = PageBlockVerticalAlignment; -//@description The content should be bottom-aligned +//@description The content must be bottom-aligned pageBlockVerticalAlignmentBottom = PageBlockVerticalAlignment; -//@description Represents a cell of a table @text Cell text; may be null. If the text is null, then the cell should be invisible @is_header True, if it is a header cell -//@colspan The number of columns the cell should span @rowspan The number of rows the cell should span +//@description Represents a cell of a table @text Cell text; may be null. If the text is null, then the cell must be invisible @is_header True, if it is a header cell +//@colspan The number of columns the cell spans @rowspan The number of rows the cell spans //@align Horizontal cell content alignment @valign Vertical cell content alignment pageBlockTableCell text:RichText is_header:Bool colspan:int32 rowspan:int32 align:PageBlockHorizontalAlignment valign:PageBlockVerticalAlignment = PageBlockTableCell; @@ -1127,7 +1236,7 @@ pageBlockKicker kicker:RichText = PageBlock; //@description A text paragraph @text Paragraph text pageBlockParagraph text:RichText = PageBlock; -//@description A preformatted text paragraph @text Paragraph text @language Programming language for which the text should be formatted +//@description A preformatted text paragraph @text Paragraph text @language Programming language for which the text needs to be formatted pageBlockPreformatted text:RichText language:string = PageBlock; //@description The footer of a page @footer Footer @@ -1148,7 +1257,7 @@ pageBlockBlockQuote text:RichText credit:RichText = PageBlock; //@description A pull quote @text Quote text @credit Quote credit pageBlockPullQuote text:RichText credit:RichText = PageBlock; -//@description An animation @animation Animation file; may be null @caption Animation caption @need_autoplay True, if the animation should be played automatically +//@description An animation @animation Animation file; may be null @caption Animation caption @need_autoplay True, if the animation must be played automatically pageBlockAnimation animation:animation caption:pageBlockCaption need_autoplay:Bool = PageBlock; //@description An audio file @audio Audio file; may be null @caption Audio file caption @@ -1157,7 +1266,7 @@ pageBlockAudio audio:audio caption:pageBlockCaption = PageBlock; //@description A photo @photo Photo file; may be null @caption Photo caption @url URL that needs to be opened when the photo is clicked pageBlockPhoto photo:photo caption:pageBlockCaption url:string = PageBlock; -//@description A video @video Video file; may be null @caption Video caption @need_autoplay True, if the video should be played automatically @is_looped True, if the video should be looped +//@description A video @video Video file; may be null @caption Video caption @need_autoplay True, if the video must be played automatically @is_looped True, if the video must be looped pageBlockVideo video:video caption:pageBlockCaption need_autoplay:Bool is_looped:Bool = PageBlock; //@description A voice note @voice_note Voice note; may be null @caption Voice note caption @@ -1166,7 +1275,7 @@ pageBlockVoiceNote voice_note:voiceNote caption:pageBlockCaption = PageBlock; //@description A page cover @cover Cover pageBlockCover cover:PageBlock = PageBlock; -//@description An embedded web page @url Web page URL, if available @html HTML-markup of the embedded page @poster_photo Poster photo, if available; may be null @width Block width; 0 if unknown @height Block height; 0 if unknown @caption Block caption @is_full_width True, if the block should be full width @allow_scrolling True, if scrolling should be allowed +//@description An embedded web page @url Web page URL, if available @html HTML-markup of the embedded page @poster_photo Poster photo, if available; may be null @width Block width; 0 if unknown @height Block height; 0 if unknown @caption Block caption @is_full_width True, if the block must be full width @allow_scrolling True, if scrolling needs to be allowed pageBlockEmbedded url:string html:string poster_photo:photo width:int32 height:int32 caption:pageBlockCaption is_full_width:Bool allow_scrolling:Bool = PageBlock; //@description An embedded post @url Web page URL @author Post author @author_photo Post author photo; may be null @date Point in time (Unix timestamp) when the post was created; 0 if unknown @page_blocks Post content @caption Post caption @@ -1178,7 +1287,7 @@ pageBlockCollage page_blocks:vector caption:pageBlockCaption = PageBl //@description A slideshow @page_blocks Slideshow item contents @caption Block caption pageBlockSlideshow page_blocks:vector caption:pageBlockCaption = PageBlock; -//@description A link to a chat @title Chat title @photo Chat photo; may be null @username Chat username, by which all other information about the chat should be resolved +//@description A link to a chat @title Chat title @photo Chat photo; may be null @username Chat username, by which all other information about the chat can be resolved pageBlockChatLink title:string photo:chatPhotoInfo username:string = PageBlock; //@description A table @caption Table caption @cells Table cells @is_bordered True, if the table is bordered @is_striped True, if the table is striped @@ -1200,7 +1309,8 @@ pageBlockMap location:location zoom:int32 width:int32 height:int32 caption:pageB //@version Version of the instant view, currently can be 1 or 2 //@is_rtl True, if the instant view must be shown from right to left //@is_full True, if the instant view contains the full page. A network request might be needed to get the full web page instant view -webPageInstantView page_blocks:vector view_count:int32 version:int32 is_rtl:Bool is_full:Bool = WebPageInstantView; +//@feedback_link An internal link to be opened to leave feedback about the instant view +webPageInstantView page_blocks:vector view_count:int32 version:int32 is_rtl:Bool is_full:Bool feedback_link:InternalLinkType = WebPageInstantView; //@description Describes a web page preview @@ -1232,7 +1342,7 @@ webPage url:string display_url:string type:string site_name:string title:string //@country_code A two-letter ISO 3166-1 alpha-2 country code //@name Native name of the country //@english_name English name of the country -//@is_hidden True, if the country should be hidden from the list of all countries +//@is_hidden True, if the country must be hidden from the list of all countries //@calling_codes List of country calling codes countryInfo country_code:string name:string english_name:string is_hidden:Bool calling_codes:vector = CountryInfo; @@ -1242,7 +1352,7 @@ countries countries:vector = Countries; //@description Contains information about a phone number //@country Information about the country to which the phone number belongs; may be null //@country_calling_code The part of the phone number denoting country calling code or its part -//@formatted_phone_number The phone number without country calling code formatted accordingly to local rules +//@formatted_phone_number The phone number without country calling code formatted accordingly to local rules. Expected digits are returned as '-', but even more digits might be entered by the user phoneNumberInfo country:countryInfo country_calling_code:string formatted_phone_number:string = PhoneNumberInfo; @@ -1257,14 +1367,22 @@ bankCardInfo title:string actions:vector = BankCardInfo; address country_code:string state:string city:string street_line1:string street_line2:string postal_code:string = Address; -//@description Portion of the price of a product (e.g., "delivery cost", "tax amount") @label Label for this portion of the product price @amount Currency amount in minimal quantity of the currency +//@description Portion of the price of a product (e.g., "delivery cost", "tax amount") @label Label for this portion of the product price @amount Currency amount in the smallest units of the currency labeledPricePart label:string amount:int53 = LabeledPricePart; -//@description Product invoice @currency ISO 4217 currency code @price_parts A list of objects used to calculate the total price of the product @is_test True, if the payment is a test payment -//@need_name True, if the user's name is needed for payment @need_phone_number True, if the user's phone number is needed for payment @need_email_address True, if the user's email address is needed for payment -//@need_shipping_address True, if the user's shipping address is needed for payment @send_phone_number_to_provider True, if the user's phone number will be sent to the provider -//@send_email_address_to_provider True, if the user's email address will be sent to the provider @is_flexible True, if the total price depends on the shipping method -invoice currency:string price_parts:vector is_test:Bool need_name:Bool need_phone_number:Bool need_email_address:Bool need_shipping_address:Bool send_phone_number_to_provider:Bool send_email_address_to_provider:Bool is_flexible:Bool = Invoice; +//@description Product invoice @currency ISO 4217 currency code +//@price_parts A list of objects used to calculate the total price of the product +//@max_tip_amount The maximum allowed amount of tip in the smallest units of the currency +//@suggested_tip_amounts Suggested amounts of tip in the smallest units of the currency +//@is_test True, if the payment is a test payment +//@need_name True, if the user's name is needed for payment +//@need_phone_number True, if the user's phone number is needed for payment +//@need_email_address True, if the user's email address is needed for payment +//@need_shipping_address True, if the user's shipping address is needed for payment +//@send_phone_number_to_provider True, if the user's phone number will be sent to the provider +//@send_email_address_to_provider True, if the user's email address will be sent to the provider +//@is_flexible True, if the total price depends on the shipping method +invoice currency:string price_parts:vector max_tip_amount:int53 suggested_tip_amounts:vector is_test:Bool need_name:Bool need_phone_number:Bool need_email_address:Bool need_shipping_address:Bool send_phone_number_to_provider:Bool send_email_address_to_provider:Bool is_flexible:Bool = Invoice; //@description Order information @name Name of the user @phone_number Phone number of the user @email_address Email address of the user @shipping_address Shipping address for this order; may be null orderInfo name:string phone_number:string email_address:string shipping_address:address = OrderInfo; @@ -1280,31 +1398,55 @@ savedCredentials id:string title:string = SavedCredentials; //@description Applies if a user chooses some previously saved payment credentials. To use their previously saved credentials, the user must have a valid temporary password @saved_credentials_id Identifier of the saved credentials inputCredentialsSaved saved_credentials_id:string = InputCredentials; -//@description Applies if a user enters new credentials on a payment provider website @data Contains JSON-encoded data with a credential identifier from the payment provider @allow_save True, if the credential identifier can be saved on the server side +//@description Applies if a user enters new credentials on a payment provider website @data JSON-encoded data with the credential identifier from the payment provider @allow_save True, if the credential identifier can be saved on the server side inputCredentialsNew data:string allow_save:Bool = InputCredentials; -//@description Applies if a user enters new credentials using Android Pay @data JSON-encoded data with the credential identifier -inputCredentialsAndroidPay data:string = InputCredentials; - //@description Applies if a user enters new credentials using Apple Pay @data JSON-encoded data with the credential identifier inputCredentialsApplePay data:string = InputCredentials; +//@description Applies if a user enters new credentials using Google Pay @data JSON-encoded data with the credential identifier +inputCredentialsGooglePay data:string = InputCredentials; + //@description Stripe payment provider @publishable_key Stripe API publishable key @need_country True, if the user country must be provided @need_postal_code True, if the user ZIP/postal code must be provided @need_cardholder_name True, if the cardholder name must be provided paymentsProviderStripe publishable_key:string need_country:Bool need_postal_code:Bool need_cardholder_name:Bool = PaymentsProviderStripe; -//@description Contains information about an invoice payment form @invoice Full information of the invoice @url Payment form URL @payments_provider Contains information about the payment provider, if available, to support it natively without the need for opening the URL; may be null -//@saved_order_info Saved server-side order information; may be null @saved_credentials Contains information about saved card credentials; may be null @can_save_credentials True, if the user can choose to save credentials @need_password True, if the user will be able to save credentials protected by a password they set up -paymentForm invoice:invoice url:string payments_provider:paymentsProviderStripe saved_order_info:orderInfo saved_credentials:savedCredentials can_save_credentials:Bool need_password:Bool = PaymentForm; +//@description Theme colors for a payment form @background_color A color of the payment form background in the RGB24 format @text_color A color of text in the RGB24 format +//@hint_color A color of hints in the RGB24 format @link_color A color of links in the RGB24 format @button_color A color of the buttons in the RGB24 format +//@button_text_color A color of text on the buttons in the RGB24 format +paymentFormTheme background_color:int32 text_color:int32 hint_color:int32 link_color:int32 button_color:int32 button_text_color:int32 = PaymentFormTheme; + +//@description Contains information about an invoice payment form +//@id The payment form identifier +//@invoice Full information of the invoice +//@url Payment form URL +//@seller_bot_user_id User identifier of the seller bot +//@payments_provider_user_id User identifier of the payment provider bot +//@payments_provider Information about the payment provider, if available, to support it natively without the need for opening the URL; may be null +//@saved_order_info Saved server-side order information; may be null +//@saved_credentials Information about saved card credentials; may be null +//@can_save_credentials True, if the user can choose to save credentials +//@need_password True, if the user will be able to save credentials protected by a password they set up +paymentForm id:int64 invoice:invoice url:string seller_bot_user_id:int53 payments_provider_user_id:int53 payments_provider:paymentsProviderStripe saved_order_info:orderInfo saved_credentials:savedCredentials can_save_credentials:Bool need_password:Bool = PaymentForm; //@description Contains a temporary identifier of validated order information, which is stored for one hour. Also contains the available shipping options @order_info_id Temporary identifier of the order information @shipping_options Available shipping options validatedOrderInfo order_info_id:string shipping_options:vector = ValidatedOrderInfo; -//@description Contains the result of a payment request @success True, if the payment request was successful; otherwise the verification_url will be not empty @verification_url URL for additional payment credentials verification +//@description Contains the result of a payment request @success True, if the payment request was successful; otherwise the verification_url will be non-empty @verification_url URL for additional payment credentials verification paymentResult success:Bool verification_url:string = PaymentResult; -//@description Contains information about a successful payment @date Point in time (Unix timestamp) when the payment was made @payments_provider_user_id User identifier of the payment provider bot @invoice Contains information about the invoice -//@order_info Contains order information; may be null @shipping_option Chosen shipping option; may be null @credentials_title Title of the saved credentials -paymentReceipt date:int32 payments_provider_user_id:int32 invoice:invoice order_info:orderInfo shipping_option:shippingOption credentials_title:string = PaymentReceipt; +//@description Contains information about a successful payment +//@title Product title +//@param_description Product description +//@photo Product photo; may be null +//@date Point in time (Unix timestamp) when the payment was made +//@seller_bot_user_id User identifier of the seller bot +//@payments_provider_user_id User identifier of the payment provider bot +//@invoice Information about the invoice +//@order_info Order information; may be null +//@shipping_option Chosen shipping option; may be null +//@credentials_title Title of the saved credentials chosen by the buyer +//@tip_amount The amount of tip chosen by the buyer in the smallest units of the currency +paymentReceipt title:string description:string photo:photo date:int32 seller_bot_user_id:int53 payments_provider_user_id:int53 invoice:invoice order_info:orderInfo shipping_option:shippingOption credentials_title:string tip_amount:int53 = PaymentReceipt; //@description File with the date it was uploaded @file The file @date Point in time (Unix timestamp) when the file was uploaded @@ -1353,7 +1495,7 @@ passportElementTypePhoneNumber = PassportElementType; passportElementTypeEmailAddress = PassportElementType; -//@description Represents a date according to the Gregorian calendar @day Day of the month, 1-31 @month Month, 1-12 @year Year, 1-9999 +//@description Represents a date according to the Gregorian calendar @day Day of the month; 1-31 @month Month; 1-12 @year Year; 1-9999 date day:int32 month:int32 year:int32 = Date; //@description Contains the user's personal details @@ -1362,12 +1504,12 @@ date day:int32 month:int32 year:int32 = Date; //@birthdate Birthdate of the user @gender Gender of the user, "male" or "female" @country_code A two-letter ISO 3166-1 alpha-2 country code of the user's country @residence_country_code A two-letter ISO 3166-1 alpha-2 country code of the user's residence country personalDetails first_name:string middle_name:string last_name:string native_first_name:string native_middle_name:string native_last_name:string birthdate:date gender:string country_code:string residence_country_code:string = PersonalDetails; -//@description An identity document @number Document number; 1-24 characters @expiry_date Document expiry date; may be null @front_side Front side of the document -//@reverse_side Reverse side of the document; only for driver license and identity card @selfie Selfie with the document; may be null @translation List of files containing a certified English translation of the document +//@description An identity document @number Document number; 1-24 characters @expiry_date Document expiry date; may be null if not applicable @front_side Front side of the document +//@reverse_side Reverse side of the document; only for driver license and identity card; may be null @selfie Selfie with the document; may be null @translation List of files containing a certified English translation of the document identityDocument number:string expiry_date:date front_side:datedFile reverse_side:datedFile selfie:datedFile translation:vector = IdentityDocument; -//@description An identity document to be saved to Telegram Passport @number Document number; 1-24 characters @expiry_date Document expiry date, if available @front_side Front side of the document -//@reverse_side Reverse side of the document; only for driver license and identity card @selfie Selfie with the document, if available @translation List of files containing a certified English translation of the document +//@description An identity document to be saved to Telegram Passport @number Document number; 1-24 characters @expiry_date Document expiry date; pass null if not applicable @front_side Front side of the document +//@reverse_side Reverse side of the document; only for driver license and identity card; pass null otherwise @selfie Selfie with the document; pass null if unavailable @translation List of files containing a certified English translation of the document inputIdentityDocument number:string expiry_date:date front_side:InputFile reverse_side:InputFile selfie:InputFile translation:vector = InputIdentityDocument; //@description A personal document, containing some information about a user @files List of files containing the pages of the document @translation List of files containing a certified English translation of the document @@ -1507,7 +1649,7 @@ passportSuitableElement type:PassportElementType is_selfie_required:Bool is_tran passportRequiredElement suitable_elements:vector = PassportRequiredElement; //@description Contains information about a Telegram Passport authorization form that was requested @id Unique identifier of the authorization form -//@required_elements Information about the Telegram Passport elements that must be provided to complete the form +//@required_elements Telegram Passport elements that must be provided to complete the form //@privacy_policy_url URL for the privacy policy of the service; may be empty passportAuthorizationForm id:int32 required_elements:vector privacy_policy_url:string = PassportAuthorizationForm; @@ -1604,6 +1746,9 @@ messageVenue venue:venue = MessageContent; //@description A message with a user contact @contact The contact description messageContact contact:contact = MessageContent; +//@description A message with an animated emoji @animated_emoji The animated emoji @emoji The corresponding emoji +messageAnimatedEmoji animated_emoji:animatedEmoji emoji:string = MessageContent; + //@description A dice message. The dice value is randomly generated by the server //@initial_state The animated stickers with the initial dice animation; may be null if unknown. updateMessageContent will be sent when the sticker became known //@final_state The animated stickers with the final dice animation; may be null if unknown. updateMessageContent will be sent when the sticker became known @@ -1618,16 +1763,28 @@ messageGame game:game = MessageContent; //@description A message with a poll @poll The poll description messagePoll poll:poll = MessageContent; -//@description A message with an invoice from a bot @title Product title @param_description Product description @photo Product photo; may be null @currency Currency for the product price @total_amount Product total price in the minimal quantity of the currency +//@description A message with an invoice from a bot @title Product title @param_description Product description @photo Product photo; may be null @currency Currency for the product price @total_amount Product total price in the smallest units of the currency //@start_parameter Unique invoice bot start_parameter. To share an invoice use the URL https://t.me/{bot_username}?start={start_parameter} @is_test True, if the invoice is a test invoice -//@need_shipping_address True, if the shipping address should be specified @receipt_message_id The identifier of the message with the receipt, after the product has been purchased +//@need_shipping_address True, if the shipping address must be specified @receipt_message_id The identifier of the message with the receipt, after the product has been purchased messageInvoice title:string description:string photo:photo currency:string total_amount:int53 start_parameter:string is_test:Bool need_shipping_address:Bool receipt_message_id:int53 = MessageContent; //@description A message with information about an ended call @is_video True, if the call was a video call @discard_reason Reason why the call was discarded @duration Call duration, in seconds messageCall is_video:Bool discard_reason:CallDiscardReason duration:int32 = MessageContent; +//@description A new video chat was scheduled @group_call_id Identifier of the video chat. The video chat can be received through the method getGroupCall @start_date Point in time (Unix timestamp) when the group call is supposed to be started by an administrator +messageVideoChatScheduled group_call_id:int32 start_date:int32 = MessageContent; + +//@description A newly created video chat @group_call_id Identifier of the video chat. The video chat can be received through the method getGroupCall +messageVideoChatStarted group_call_id:int32 = MessageContent; + +//@description A message with information about an ended video chat @duration Call duration, in seconds +messageVideoChatEnded duration:int32 = MessageContent; + +//@description A message with information about an invite to a video chat @group_call_id Identifier of the video chat. The video chat can be received through the method getGroupCall @user_ids Invited user identifiers +messageInviteVideoChatParticipants group_call_id:int32 user_ids:vector = MessageContent; + //@description A newly created basic group @title Title of the basic group @member_user_ids User identifiers of members in the basic group -messageBasicGroupChatCreate title:string member_user_ids:vector = MessageContent; +messageBasicGroupChatCreate title:string member_user_ids:vector = MessageContent; //@description A newly created supergroup or channel @title Title of the supergroup or channel messageSupergroupChatCreate title:string = MessageContent; @@ -1642,19 +1799,22 @@ messageChatChangePhoto photo:chatPhoto = MessageContent; messageChatDeletePhoto = MessageContent; //@description New chat members were added @member_user_ids User identifiers of the new members -messageChatAddMembers member_user_ids:vector = MessageContent; +messageChatAddMembers member_user_ids:vector = MessageContent; //@description A new member joined the chat by invite link messageChatJoinByLink = MessageContent; +//@description A new member was accepted to the chat by an administrator +messageChatJoinByRequest = MessageContent; + //@description A chat member was deleted @user_id User identifier of the deleted chat member -messageChatDeleteMember user_id:int32 = MessageContent; +messageChatDeleteMember user_id:int53 = MessageContent; //@description A basic group was upgraded to a supergroup and was deactivated as the result @supergroup_id Identifier of the supergroup to which the basic group was upgraded -messageChatUpgradeTo supergroup_id:int32 = MessageContent; +messageChatUpgradeTo supergroup_id:int53 = MessageContent; //@description A supergroup has been created from a basic group @title Title of the newly created supergroup @basic_group_id The identifier of the original basic group -messageChatUpgradeFrom title:string basic_group_id:int32 = MessageContent; +messageChatUpgradeFrom title:string basic_group_id:int53 = MessageContent; //@description A message has been pinned @message_id Identifier of the pinned message, can be an identifier of a deleted message or 0 messagePinMessage message_id:int53 = MessageContent; @@ -1662,7 +1822,10 @@ messagePinMessage message_id:int53 = MessageContent; //@description A screenshot of a message in the chat has been taken messageScreenshotTaken = MessageContent; -//@description The TTL (Time To Live) setting messages in a secret chat has been changed @ttl New TTL +//@description A theme in the chat has been changed @theme_name If non-empty, name of a new theme, set for the chat. Otherwise chat theme was reset to the default one +messageChatSetTheme theme_name:string = MessageContent; + +//@description The TTL (Time To Live) setting for messages in the chat has been changed @ttl New message TTL setting messageChatSetTtl ttl:int32 = MessageContent; //@description A non-standard action has happened in the chat @text Message text to be shown in the chat @@ -1671,13 +1834,13 @@ messageCustomServiceAction text:string = MessageContent; //@description A new high score was achieved in a game @game_message_id Identifier of the message with the game, can be an identifier of a deleted message @game_id Identifier of the game; may be different from the games presented in the message with the game @score New score messageGameScore game_message_id:int53 game_id:int64 score:int32 = MessageContent; -//@description A payment has been completed @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for the price of the product @total_amount Total price for the product, in the minimal quantity of the currency -messagePaymentSuccessful invoice_message_id:int53 currency:string total_amount:int53 = MessageContent; +//@description A payment has been completed @invoice_chat_id Identifier of the chat, containing the corresponding invoice message; 0 if unknown @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for the price of the product @total_amount Total price for the product, in the smallest units of the currency +messagePaymentSuccessful invoice_chat_id:int53 invoice_message_id:int53 currency:string total_amount:int53 = MessageContent; -//@description A payment has been completed; for bots only @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for price of the product -//@total_amount Total price for the product, in the minimal quantity of the currency @invoice_payload Invoice payload @shipping_option_id Identifier of the shipping option chosen by the user; may be empty if not applicable @order_info Information about the order; may be null +//@description A payment has been completed; for bots only @currency Currency for price of the product +//@total_amount Total price for the product, in the smallest units of the currency @invoice_payload Invoice payload @shipping_option_id Identifier of the shipping option chosen by the user; may be empty if not applicable @order_info Information about the order; may be null //@telegram_payment_charge_id Telegram payment identifier @provider_payment_charge_id Provider payment identifier -messagePaymentSuccessfulBot invoice_message_id:int53 currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo telegram_payment_charge_id:string provider_payment_charge_id:string = MessageContent; +messagePaymentSuccessfulBot currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo telegram_payment_charge_id:string provider_payment_charge_id:string = MessageContent; //@description A contact has registered with Telegram messageContactRegistered = MessageContent; @@ -1706,10 +1869,10 @@ textEntityTypeMention = TextEntityType; //@description A hashtag text, beginning with "#" textEntityTypeHashtag = TextEntityType; -//@description A cashtag text, beginning with "$" and consisting of capital english letters (i.e. "$USD") +//@description A cashtag text, beginning with "$" and consisting of capital English letters (e.g., "$USD") textEntityTypeCashtag = TextEntityType; -//@description A bot command, beginning with "/". This shouldn't be highlighted if there are no bots in the chat +//@description A bot command, beginning with "/" textEntityTypeBotCommand = TextEntityType; //@description An HTTP URL @@ -1749,11 +1912,16 @@ textEntityTypePreCode language:string = TextEntityType; textEntityTypeTextUrl url:string = TextEntityType; //@description A text shows instead of a raw mention of the user (e.g., when the user has no username) @user_id Identifier of the mentioned user -textEntityTypeMentionName user_id:int32 = TextEntityType; +textEntityTypeMentionName user_id:int53 = TextEntityType; + +//@description A media timestamp @media_timestamp Timestamp from which a video/audio/video note/voice note playing must start, in seconds. The media can be in the content or the web page preview of the current message, or in the same places in the replied message +textEntityTypeMediaTimestamp media_timestamp:int32 = TextEntityType; -//@description A thumbnail to be sent along with a file; must be in JPEG or WEBP format for stickers, and less than 200 KB in size @thumbnail Thumbnail file to send. Sending thumbnails by file_id is currently not supported -//@width Thumbnail width, usually shouldn't exceed 320. Use 0 if unknown @height Thumbnail height, usually shouldn't exceed 320. Use 0 if unknown +//@description A thumbnail to be sent along with a file; must be in JPEG or WEBP format for stickers, and less than 200 KB in size +//@thumbnail Thumbnail file to send. Sending thumbnails by file_id is currently not supported +//@width Thumbnail width, usually shouldn't exceed 320. Use 0 if unknown +//@height Thumbnail height, usually shouldn't exceed 320. Use 0 if unknown inputThumbnail thumbnail:InputFile width:int32 height:int32 = InputThumbnail; @@ -1769,52 +1937,52 @@ messageSchedulingStateSendWhenOnline = MessageSchedulingState; //@description Options to be used when a message is sent //@disable_notification Pass true to disable notification for the message //@from_background Pass true if the message is sent from the background -//@scheduling_state Message scheduling state. Messages sent to a secret chat, live location messages and self-destructing messages can't be scheduled +//@scheduling_state Message scheduling state; pass null to send message immediately. Messages sent to a secret chat, live location messages and self-destructing messages can't be scheduled messageSendOptions disable_notification:Bool from_background:Bool scheduling_state:MessageSchedulingState = MessageSendOptions; -//@description Options to be used when a message content is copied without a link to the original message -//@send_copy True, if content of the message needs to be copied without a link to the original message. Always true if the message is forwarded to a secret chat +//@description Options to be used when a message content is copied without reference to the original sender. Service messages and messageInvoice can't be copied +//@send_copy True, if content of the message needs to be copied without reference to the original sender. Always true if the message is forwarded to a secret chat or is local //@replace_caption True, if media caption of the message copy needs to be replaced. Ignored if send_copy is false -//@new_caption New message caption. Ignored if replace_caption is false +//@new_caption New message caption; pass null to copy message without caption. Ignored if replace_caption is false messageCopyOptions send_copy:Bool replace_caption:Bool new_caption:formattedText = MessageCopyOptions; //@class InputMessageContent @description The content of a message to send //@description A text message @text Formatted text to be sent; 1-GetOption("message_text_length_max") characters. Only Bold, Italic, Underline, Strikethrough, Code, Pre, PreCode, TextUrl and MentionName entities are allowed to be specified manually -//@disable_web_page_preview True, if rich web page previews for URLs in the message text should be disabled @clear_draft True, if a chat message draft should be deleted +//@disable_web_page_preview True, if rich web page previews for URLs in the message text must be disabled @clear_draft True, if a chat message draft must be deleted inputMessageText text:formattedText disable_web_page_preview:Bool clear_draft:Bool = InputMessageContent; -//@description An animation message (GIF-style). @animation Animation file to be sent @thumbnail Animation thumbnail, if available @added_sticker_file_ids File identifiers of the stickers added to the animation, if applicable -//@duration Duration of the animation, in seconds @width Width of the animation; may be replaced by the server @height Height of the animation; may be replaced by the server @caption Animation caption; 0-GetOption("message_caption_length_max") characters +//@description An animation message (GIF-style). @animation Animation file to be sent @thumbnail Animation thumbnail; pass null to skip thumbnail uploading @added_sticker_file_ids File identifiers of the stickers added to the animation, if applicable +//@duration Duration of the animation, in seconds @width Width of the animation; may be replaced by the server @height Height of the animation; may be replaced by the server @caption Animation caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters inputMessageAnimation animation:InputFile thumbnail:inputThumbnail added_sticker_file_ids:vector duration:int32 width:int32 height:int32 caption:formattedText = InputMessageContent; -//@description An audio message @audio Audio file to be sent @album_cover_thumbnail Thumbnail of the cover for the album, if available @duration Duration of the audio, in seconds; may be replaced by the server @title Title of the audio; 0-64 characters; may be replaced by the server -//@performer Performer of the audio; 0-64 characters, may be replaced by the server @caption Audio caption; 0-GetOption("message_caption_length_max") characters +//@description An audio message @audio Audio file to be sent @album_cover_thumbnail Thumbnail of the cover for the album; pass null to skip thumbnail uploading @duration Duration of the audio, in seconds; may be replaced by the server @title Title of the audio; 0-64 characters; may be replaced by the server +//@performer Performer of the audio; 0-64 characters, may be replaced by the server @caption Audio caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters inputMessageAudio audio:InputFile album_cover_thumbnail:inputThumbnail duration:int32 title:string performer:string caption:formattedText = InputMessageContent; -//@description A document message (general file) @document Document to be sent @thumbnail Document thumbnail, if available @disable_content_type_detection If true, automatic file type detection will be disabled and the document will be always sent as file. Always true for files sent to secret chats @caption Document caption; 0-GetOption("message_caption_length_max") characters +//@description A document message (general file) @document Document to be sent @thumbnail Document thumbnail; pass null to skip thumbnail uploading @disable_content_type_detection If true, automatic file type detection will be disabled and the document will be always sent as file. Always true for files sent to secret chats @caption Document caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters inputMessageDocument document:InputFile thumbnail:inputThumbnail disable_content_type_detection:Bool caption:formattedText = InputMessageContent; -//@description A photo message @photo Photo to send @thumbnail Photo thumbnail to be sent, this is sent to the other party in secret chats only @added_sticker_file_ids File identifiers of the stickers added to the photo, if applicable @width Photo width @height Photo height @caption Photo caption; 0-GetOption("message_caption_length_max") characters +//@description A photo message @photo Photo to send @thumbnail Photo thumbnail to be sent; pass null to skip thumbnail uploading. The thumbnail is sent to the other party only in secret chats @added_sticker_file_ids File identifiers of the stickers added to the photo, if applicable @width Photo width @height Photo height @caption Photo caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters //@ttl Photo TTL (Time To Live), in seconds (0-60). A non-zero TTL can be specified only in private chats inputMessagePhoto photo:InputFile thumbnail:inputThumbnail added_sticker_file_ids:vector width:int32 height:int32 caption:formattedText ttl:int32 = InputMessageContent; -//@description A sticker message @sticker Sticker to be sent @thumbnail Sticker thumbnail, if available @width Sticker width @height Sticker height -inputMessageSticker sticker:InputFile thumbnail:inputThumbnail width:int32 height:int32 = InputMessageContent; +//@description A sticker message @sticker Sticker to be sent @thumbnail Sticker thumbnail; pass null to skip thumbnail uploading @width Sticker width @height Sticker height @emoji Emoji used to choose the sticker +inputMessageSticker sticker:InputFile thumbnail:inputThumbnail width:int32 height:int32 emoji:string = InputMessageContent; -//@description A video message @video Video to be sent @thumbnail Video thumbnail, if available @added_sticker_file_ids File identifiers of the stickers added to the video, if applicable -//@duration Duration of the video, in seconds @width Video width @height Video height @supports_streaming True, if the video should be tried to be streamed -//@caption Video caption; 0-GetOption("message_caption_length_max") characters @ttl Video TTL (Time To Live), in seconds (0-60). A non-zero TTL can be specified only in private chats +//@description A video message @video Video to be sent @thumbnail Video thumbnail; pass null to skip thumbnail uploading @added_sticker_file_ids File identifiers of the stickers added to the video, if applicable +//@duration Duration of the video, in seconds @width Video width @height Video height @supports_streaming True, if the video is supposed to be streamed +//@caption Video caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters @ttl Video TTL (Time To Live), in seconds (0-60). A non-zero TTL can be specified only in private chats inputMessageVideo video:InputFile thumbnail:inputThumbnail added_sticker_file_ids:vector duration:int32 width:int32 height:int32 supports_streaming:Bool caption:formattedText ttl:int32 = InputMessageContent; -//@description A video note message @video_note Video note to be sent @thumbnail Video thumbnail, if available @duration Duration of the video, in seconds @length Video width and height; must be positive and not greater than 640 +//@description A video note message @video_note Video note to be sent @thumbnail Video thumbnail; pass null to skip thumbnail uploading @duration Duration of the video, in seconds @length Video width and height; must be positive and not greater than 640 inputMessageVideoNote video_note:InputFile thumbnail:inputThumbnail duration:int32 length:int32 = InputMessageContent; -//@description A voice note message @voice_note Voice note to be sent @duration Duration of the voice note, in seconds @waveform Waveform representation of the voice note, in 5-bit format @caption Voice note caption; 0-GetOption("message_caption_length_max") characters +//@description A voice note message @voice_note Voice note to be sent @duration Duration of the voice note, in seconds @waveform Waveform representation of the voice note, in 5-bit format @caption Voice note caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters inputMessageVoiceNote voice_note:InputFile duration:int32 waveform:bytes caption:formattedText = InputMessageContent; -//@description A message with a location @location Location to be sent @live_period Period for which the location can be updated, in seconds; should be between 60 and 86400 for a live location and 0 otherwise +//@description A message with a location @location Location to be sent @live_period Period for which the location can be updated, in seconds; must be between 60 and 86400 for a live location and 0 otherwise //@heading For live locations, a direction in which the location moves, in degrees; 1-360. Pass 0 if unknown //@proximity_alert_radius For live locations, a maximum distance to another chat member for proximity alerts, in meters (0-100000). Pass 0 if the notification is disabled. Can't be enabled in channels and Saved Messages inputMessageLocation location:location live_period:int32 heading:int32 proximity_alert_radius:int32 = InputMessageContent; @@ -1825,17 +1993,19 @@ inputMessageVenue venue:venue = InputMessageContent; //@description A message containing a user contact @contact Contact to send inputMessageContact contact:contact = InputMessageContent; -//@description A dice message @emoji Emoji on which the dice throw animation is based @clear_draft True, if a chat message draft should be deleted +//@description A dice message @emoji Emoji on which the dice throw animation is based @clear_draft True, if the chat message draft must be deleted inputMessageDice emoji:string clear_draft:Bool = InputMessageContent; //@description A message with a game; not supported for channels or secret chats @bot_user_id User identifier of the bot that owns the game @game_short_name Short name of the game -inputMessageGame bot_user_id:int32 game_short_name:string = InputMessageContent; +inputMessageGame bot_user_id:int53 game_short_name:string = InputMessageContent; -//@description A message with an invoice; can be used only by bots and only in private chats @invoice Invoice @title Product title; 1-32 characters @param_description Product description; 0-255 characters @photo_url Product photo URL; optional @photo_size Product photo size @photo_width Product photo width @photo_height Product photo height -//@payload The invoice payload @provider_token Payment provider token @provider_data JSON-encoded data about the invoice, which will be shared with the payment provider @start_parameter Unique invoice bot start_parameter for the generation of this invoice +//@description A message with an invoice; can be used only by bots @invoice Invoice @title Product title; 1-32 characters @param_description Product description; 0-255 characters +//@photo_url Product photo URL; optional @photo_size Product photo size @photo_width Product photo width @photo_height Product photo height +//@payload The invoice payload @provider_token Payment provider token @provider_data JSON-encoded data about the invoice, which will be shared with the payment provider +//@start_parameter Unique invoice bot deep link parameter for the generation of this invoice. If empty, it would be possible to pay directly from forwards of the invoice message inputMessageInvoice invoice:invoice title:string description:string photo_url:string photo_size:int32 photo_width:int32 photo_height:int32 payload:bytes provider_token:string provider_data:string start_parameter:string = InputMessageContent; -//@description A message with a poll. Polls can't be sent to secret chats. Polls can be sent only to a private chat with a bot @question Poll question, 1-255 characters (up to 300 characters for bots) @options List of poll answer options, 2-10 strings 1-100 characters each +//@description A message with a poll. Polls can't be sent to secret chats. Polls can be sent only to a private chat with a bot @question Poll question; 1-255 characters (up to 300 characters for bots) @options List of poll answer options, 2-10 strings 1-100 characters each //@is_anonymous True, if the poll voters are anonymous. Non-anonymous polls can't be sent or forwarded to channels @type Type of the poll //@open_period Amount of time the poll will be active after creation, in seconds; for bots only //@close_date Point in time (Unix timestamp) when the poll will be automatically closed; for bots only @@ -1843,8 +2013,8 @@ inputMessageInvoice invoice:invoice title:string description:string photo_url:st inputMessagePoll question:string options:vector is_anonymous:Bool type:PollType open_period:int32 close_date:int32 is_closed:Bool = InputMessageContent; //@description A forwarded message @from_chat_id Identifier for the chat this forwarded message came from @message_id Identifier of the message to forward -//@in_game_share True, if a game message should be shared within a launched game; applies only to game messages -//@copy_options Options to be used to copy content of the message without a link to the original message +//@in_game_share True, if a game message is being shared from a launched game; applies only to game messages +//@copy_options Options to be used to copy content of the message without reference to the original sender; pass null to try to forward the message as usual inputMessageForwarded from_chat_id:int53 message_id:int53 in_game_share:Bool copy_options:messageCopyOptions = InputMessageContent; @@ -1909,29 +2079,47 @@ searchMessagesFilterPinned = SearchMessagesFilter; //@description The user is typing a message chatActionTyping = ChatAction; + //@description The user is recording a video chatActionRecordingVideo = ChatAction; + //@description The user is uploading a video @progress Upload progress, as a percentage chatActionUploadingVideo progress:int32 = ChatAction; + //@description The user is recording a voice note chatActionRecordingVoiceNote = ChatAction; + //@description The user is uploading a voice note @progress Upload progress, as a percentage chatActionUploadingVoiceNote progress:int32 = ChatAction; + //@description The user is uploading a photo @progress Upload progress, as a percentage chatActionUploadingPhoto progress:int32 = ChatAction; + //@description The user is uploading a document @progress Upload progress, as a percentage chatActionUploadingDocument progress:int32 = ChatAction; + +//@description The user is picking a sticker to send +chatActionChoosingSticker = ChatAction; + //@description The user is picking a location or venue to send chatActionChoosingLocation = ChatAction; + //@description The user is picking a contact to send chatActionChoosingContact = ChatAction; + //@description The user has started to play a game chatActionStartPlayingGame = ChatAction; + //@description The user is recording a video note chatActionRecordingVideoNote = ChatAction; + //@description The user is uploading a video note @progress Upload progress, as a percentage chatActionUploadingVideoNote progress:int32 = ChatAction; -//@description The user has cancelled the previous action + +//@description The user is watching animations sent by the other party by clicking on an animated emoji @emoji The animated emoji +chatActionWatchingAnimations emoji:string = ChatAction; + +//@description The user has canceled the previous action chatActionCancel = ChatAction; @@ -1964,17 +2152,19 @@ emojis emojis:vector = Emojis; //@description Represents a sticker set //@id Identifier of the sticker set @title Title of the sticker set @name Name of the sticker set @thumbnail Sticker set thumbnail in WEBP or TGS format with width and height 100; may be null. The file can be downloaded only before the thumbnail is changed +//@thumbnail_outline Sticker set thumbnail's outline represented as a list of closed vector paths; may be empty. The coordinate system origin is in the upper-left corner //@is_installed True, if the sticker set has been installed by the current user @is_archived True, if the sticker set has been archived. A sticker set can't be installed and archived simultaneously //@is_official True, if the sticker set is official @is_animated True, is the stickers in the set are animated @is_masks True, if the stickers in the set are masks @is_viewed True for already viewed trending sticker sets //@stickers List of stickers in this set @emojis A list of emoji corresponding to the stickers in the same order. The list is only for informational purposes, because a sticker is always sent with a fixed emoji from the corresponding Sticker object -stickerSet id:int64 title:string name:string thumbnail:thumbnail is_installed:Bool is_archived:Bool is_official:Bool is_animated:Bool is_masks:Bool is_viewed:Bool stickers:vector emojis:vector = StickerSet; +stickerSet id:int64 title:string name:string thumbnail:thumbnail thumbnail_outline:vector is_installed:Bool is_archived:Bool is_official:Bool is_animated:Bool is_masks:Bool is_viewed:Bool stickers:vector emojis:vector = StickerSet; //@description Represents short information about a sticker set //@id Identifier of the sticker set @title Title of the sticker set @name Name of the sticker set @thumbnail Sticker set thumbnail in WEBP or TGS format with width and height 100; may be null -//@is_installed True, if the sticker set has been installed by current user @is_archived True, if the sticker set has been archived. A sticker set can't be installed and archived simultaneously +//@thumbnail_outline Sticker set thumbnail's outline represented as a list of closed vector paths; may be empty. The coordinate system origin is in the upper-left corner +//@is_installed True, if the sticker set has been installed by the current user @is_archived True, if the sticker set has been archived. A sticker set can't be installed and archived simultaneously //@is_official True, if the sticker set is official @is_animated True, is the stickers in the set are animated @is_masks True, if the stickers in the set are masks @is_viewed True for already viewed trending sticker sets -//@size Total number of stickers in the set @covers Contains up to the first 5 stickers from the set, depending on the context. If the application needs more stickers the full set should be requested -stickerSetInfo id:int64 title:string name:string thumbnail:thumbnail is_installed:Bool is_archived:Bool is_official:Bool is_animated:Bool is_masks:Bool is_viewed:Bool size:int32 covers:vector = StickerSetInfo; +//@size Total number of stickers in the set @covers Up to the first 5 stickers from the set, depending on the context. If the application needs more stickers the full sticker set needs to be requested +stickerSetInfo id:int64 title:string name:string thumbnail:thumbnail thumbnail_outline:vector is_installed:Bool is_archived:Bool is_official:Bool is_animated:Bool is_masks:Bool is_viewed:Bool size:int32 covers:vector = StickerSetInfo; //@description Represents a list of sticker sets @total_count Approximate total number of sticker sets found @sets List of sticker sets stickerSets total_count:int32 sets:vector = StickerSets; @@ -1985,7 +2175,7 @@ stickerSets total_count:int32 sets:vector = StickerSets; //@description The call wasn't discarded, or the reason is unknown callDiscardReasonEmpty = CallDiscardReason; -//@description The call was ended before the conversation started. It was cancelled by the caller or missed by the other party +//@description The call was ended before the conversation started. It was canceled by the caller or missed by the other party callDiscardReasonMissed = CallDiscardReason; //@description The call was ended before the conversation started. It was declined by the other party @@ -2003,7 +2193,7 @@ callDiscardReasonHungUp = CallDiscardReason; //@udp_reflector True, if connection through UDP reflectors is supported //@min_layer The minimum supported API layer; use 65 //@max_layer The maximum supported API layer; use 65 -//@library_versions List of supported libtgvoip versions +//@library_versions List of supported tgcalls versions callProtocol udp_p2p:Bool udp_reflector:Bool min_layer:int32 max_layer:int32 library_versions:vector = CallProtocol; @@ -2023,6 +2213,9 @@ callServer id:int64 ip_address:string ipv6_address:string port:int32 type:CallSe //@description Contains the call identifier @id Call identifier callId id:int32 = CallId; +//@description Contains the group call identifier @id Group call identifier +groupCallId id:int32 = GroupCallId; + //@class CallState @description Describes the current call state @@ -2038,13 +2231,79 @@ callStateReady protocol:callProtocol servers:vector config:string en //@description The call is hanging up after discardCall has been called callStateHangingUp = CallState; -//@description The call has ended successfully @reason The reason, why the call has ended @need_rating True, if the call rating should be sent to the server @need_debug_information True, if the call debug information should be sent to the server +//@description The call has ended successfully @reason The reason, why the call has ended @need_rating True, if the call rating must be sent to the server @need_debug_information True, if the call debug information must be sent to the server callStateDiscarded reason:CallDiscardReason need_rating:Bool need_debug_information:Bool = CallState; //@description The call has ended with an error @error Error. An error with the code 4005000 will be returned if an outgoing call is missed because of an expired timeout callStateError error:error = CallState; +//@class GroupCallVideoQuality @description Describes the quality of a group call video + +//@description The worst available video quality +groupCallVideoQualityThumbnail = GroupCallVideoQuality; + +//@description The medium video quality +groupCallVideoQualityMedium = GroupCallVideoQuality; + +//@description The best available video quality +groupCallVideoQualityFull = GroupCallVideoQuality; + + +//@description Describes a recently speaking participant in a group call @participant_id Group call participant identifier @is_speaking True, is the user has spoken recently +groupCallRecentSpeaker participant_id:MessageSender is_speaking:Bool = GroupCallRecentSpeaker; + +//@description Describes a group call +//@id Group call identifier +//@title Group call title +//@scheduled_start_date Point in time (Unix timestamp) when the group call is supposed to be started by an administrator; 0 if it is already active or was ended +//@enabled_start_notification True, if the group call is scheduled and the current user will receive a notification when the group call will start +//@is_active True, if the call is active +//@is_joined True, if the call is joined +//@need_rejoin True, if user was kicked from the call because of network loss and the call needs to be rejoined +//@can_be_managed True, if the current user can manage the group call +//@participant_count Number of participants in the group call +//@loaded_all_participants True, if all group call participants are loaded +//@recent_speakers Recently speaking users in the group call +//@is_my_video_enabled True, if the current user's video is enabled +//@is_my_video_paused True, if the current user's video is paused +//@can_enable_video True, if the current user can broadcast video or share screen +//@mute_new_participants True, if only group call administrators can unmute new participants +//@can_toggle_mute_new_participants True, if the current user can enable or disable mute_new_participants setting +//@record_duration Duration of the ongoing group call recording, in seconds; 0 if none. An updateGroupCall update is not triggered when value of this field changes, but the same recording goes on +//@is_video_recorded True, if a video file is being recorded for the call +//@duration Call duration, in seconds; for ended calls only +groupCall id:int32 title:string scheduled_start_date:int32 enabled_start_notification:Bool is_active:Bool is_joined:Bool need_rejoin:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector is_my_video_enabled:Bool is_my_video_paused:Bool can_enable_video:Bool mute_new_participants:Bool can_toggle_mute_new_participants:Bool record_duration:int32 is_video_recorded:Bool duration:int32 = GroupCall; + +//@description Describes a group of video synchronization source identifiers @semantics The semantics of sources, one of "SIM" or "FID" @source_ids The list of synchronization source identifiers +groupCallVideoSourceGroup semantics:string source_ids:vector = GroupCallVideoSourceGroup; + +//@description Contains information about a group call participant's video channel @source_groups List of synchronization source groups of the video @endpoint_id Video channel endpoint identifier +//@is_paused True if the video is paused. This flag needs to be ignored, if new video frames are received +groupCallParticipantVideoInfo source_groups:vector endpoint_id:string is_paused:Bool = GroupCallParticipantVideoInfo; + +//@description Represents a group call participant +//@participant_id Identifier of the group call participant +//@audio_source_id User's audio channel synchronization source identifier +//@screen_sharing_audio_source_id User's screen sharing audio channel synchronization source identifier +//@video_info Information about user's video channel; may be null if there is no active video +//@screen_sharing_video_info Information about user's screen sharing video channel; may be null if there is no active screen sharing video +//@bio The participant user's bio or the participant chat's description +//@is_current_user True, if the participant is the current user +//@is_speaking True, if the participant is speaking as set by setGroupCallParticipantIsSpeaking +//@is_hand_raised True, if the participant hand is raised +//@can_be_muted_for_all_users True, if the current user can mute the participant for all other group call participants +//@can_be_unmuted_for_all_users True, if the current user can allow the participant to unmute themselves or unmute the participant (if the participant is the current user) +//@can_be_muted_for_current_user True, if the current user can mute the participant only for self +//@can_be_unmuted_for_current_user True, if the current user can unmute the participant for self +//@is_muted_for_all_users True, if the participant is muted for all users +//@is_muted_for_current_user True, if the participant is muted for the current user +//@can_unmute_self True, if the participant is muted for all users, but can unmute themselves +//@volume_level Participant's volume level; 1-20000 in hundreds of percents +//@order User's order in the group call participant list. Orders must be compared lexicographically. The bigger is order, the higher is user in the list. If order is empty, the user must be removed from the participant list +groupCallParticipant participant_id:MessageSender audio_source_id:int32 screen_sharing_audio_source_id:int32 video_info:groupCallParticipantVideoInfo screen_sharing_video_info:groupCallParticipantVideoInfo bio:string is_current_user:Bool is_speaking:Bool is_hand_raised:Bool can_be_muted_for_all_users:Bool can_be_unmuted_for_all_users:Bool can_be_muted_for_current_user:Bool can_be_unmuted_for_current_user:Bool is_muted_for_all_users:Bool is_muted_for_current_user:Bool can_unmute_self:Bool volume_level:int32 order:string = GroupCallParticipant; + + //@class CallProblem @description Describes the exact type of a problem with a call //@description The user heard their own voice @@ -2076,7 +2335,7 @@ callProblemPixelatedVideo = CallProblem; //@description Describes a call @id Call identifier, not persistent @user_id Peer user identifier @is_outgoing True, if the call is outgoing @is_video True, if the call is a video call @state Call state -call id:int32 user_id:int32 is_outgoing:Bool is_video:Bool state:CallState = Call; +call id:int32 user_id:int53 is_outgoing:Bool is_video:Bool state:CallState = Call; //@description Contains settings for the authentication of the user's phone number @@ -2090,7 +2349,7 @@ phoneNumberAuthenticationSettings allow_flash_call:Bool is_current_phone_number: animations animations:vector = Animations; -//@class DiceStickers @description Contains animated stickers which should be used for dice animation rendering +//@class DiceStickers @description Contains animated stickers which must be used for dice animation rendering //@description A regular animated sticker @sticker The animated sticker with the dice animation diceStickersRegular sticker:sticker = DiceStickers; @@ -2106,7 +2365,7 @@ diceStickersSlotMachine background:sticker lever:sticker left_reel:sticker cente //@description Represents the result of an ImportContacts request @user_ids User identifiers of the imported contacts in the same order as they were specified in the request; 0 if the contact is not yet a registered user //@importer_count The number of users that imported the corresponding contact; 0 for already registered users or if unavailable -importedContacts user_ids:vector importer_count:vector = ImportedContacts; +importedContacts user_ids:vector importer_count:vector = ImportedContacts; //@description Contains an HTTP URL @url The URL @@ -2115,76 +2374,76 @@ httpUrl url:string = HttpUrl; //@class InputInlineQueryResult @description Represents a single result of an inline query; for bots only -//@description Represents a link to an animated GIF or an animated (i.e. without sound) H.264/MPEG-4 AVC video +//@description Represents a link to an animated GIF or an animated (i.e., without sound) H.264/MPEG-4 AVC video //@id Unique identifier of the query result @title Title of the query result //@thumbnail_url URL of the result thumbnail (JPEG, GIF, or MPEG4), if it exists @thumbnail_mime_type MIME type of the video thumbnail. If non-empty, must be one of "image/jpeg", "image/gif" and "video/mp4" //@video_url The URL of the video file (file size must not exceed 1MB) @video_mime_type MIME type of the video file. Must be one of "image/gif" and "video/mp4" //@video_duration Duration of the video, in seconds @video_width Width of the video @video_height Height of the video -//@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageAnimation, InputMessageLocation, InputMessageVenue or InputMessageContact +//@reply_markup The message reply markup; pass null if none. Must be of type replyMarkupInlineKeyboard or null +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageAnimation, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultAnimation id:string title:string thumbnail_url:string thumbnail_mime_type:string video_url:string video_mime_type:string video_duration:int32 video_width:int32 video_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to an article or web page @id Unique identifier of the query result @url URL of the result, if it exists @hide_url True, if the URL must be not shown @title Title of the result //@param_description A short description of the result @thumbnail_url URL of the result thumbnail, if it exists @thumbnail_width Thumbnail width, if known @thumbnail_height Thumbnail height, if known -//@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageLocation, InputMessageVenue or InputMessageContact +//@reply_markup The message reply markup; pass null if none. Must be of type replyMarkupInlineKeyboard or null +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultArticle id:string url:string hide_url:Bool title:string description:string thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to an MP3 audio file @id Unique identifier of the query result @title Title of the audio file @performer Performer of the audio file //@audio_url The URL of the audio file @audio_duration Audio file duration, in seconds -//@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageAudio, InputMessageLocation, InputMessageVenue or InputMessageContact +//@reply_markup The message reply markup; pass null if none. Must be of type replyMarkupInlineKeyboard or null +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageAudio, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultAudio id:string title:string performer:string audio_url:string audio_duration:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a user contact @id Unique identifier of the query result @contact User contact @thumbnail_url URL of the result thumbnail, if it exists @thumbnail_width Thumbnail width, if known @thumbnail_height Thumbnail height, if known -//@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageLocation, InputMessageVenue or InputMessageContact +//@reply_markup The message reply markup; pass null if none. Must be of type replyMarkupInlineKeyboard or null +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultContact id:string contact:contact thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to a file @id Unique identifier of the query result @title Title of the resulting file @param_description Short description of the result, if known @document_url URL of the file @mime_type MIME type of the file content; only "application/pdf" and "application/zip" are currently allowed //@thumbnail_url The URL of the file thumbnail, if it exists @thumbnail_width Width of the thumbnail @thumbnail_height Height of the thumbnail -//@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageDocument, InputMessageLocation, InputMessageVenue or InputMessageContact +//@reply_markup The message reply markup; pass null if none. Must be of type replyMarkupInlineKeyboard or null +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageDocument, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultDocument id:string title:string description:string document_url:string mime_type:string thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; -//@description Represents a game @id Unique identifier of the query result @game_short_name Short name of the game @reply_markup Message reply markup. Must be of type replyMarkupInlineKeyboard or null +//@description Represents a game @id Unique identifier of the query result @game_short_name Short name of the game @reply_markup The message reply markup; pass null if none. Must be of type replyMarkupInlineKeyboard or null inputInlineQueryResultGame id:string game_short_name:string reply_markup:ReplyMarkup = InputInlineQueryResult; //@description Represents a point on the map @id Unique identifier of the query result @location Location result //@live_period Amount of time relative to the message sent time until the location can be updated, in seconds //@title Title of the result @thumbnail_url URL of the result thumbnail, if it exists @thumbnail_width Thumbnail width, if known @thumbnail_height Thumbnail height, if known -//@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageLocation, InputMessageVenue or InputMessageContact +//@reply_markup The message reply markup; pass null if none. Must be of type replyMarkupInlineKeyboard or null +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultLocation id:string location:location live_period:int32 title:string thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents link to a JPEG image @id Unique identifier of the query result @title Title of the result, if known @param_description A short description of the result, if known @thumbnail_url URL of the photo thumbnail, if it exists //@photo_url The URL of the JPEG photo (photo size must not exceed 5MB) @photo_width Width of the photo @photo_height Height of the photo -//@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessagePhoto, InputMessageLocation, InputMessageVenue or InputMessageContact +//@reply_markup The message reply markup; pass null if none. Must be of type replyMarkupInlineKeyboard or null +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessagePhoto, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultPhoto id:string title:string description:string thumbnail_url:string photo_url:string photo_width:int32 photo_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to a WEBP or TGS sticker @id Unique identifier of the query result @thumbnail_url URL of the sticker thumbnail, if it exists //@sticker_url The URL of the WEBP or TGS sticker (sticker file size must not exceed 5MB) @sticker_width Width of the sticker @sticker_height Height of the sticker -//@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, inputMessageSticker, InputMessageLocation, InputMessageVenue or InputMessageContact +//@reply_markup The message reply markup; pass null if none. Must be of type replyMarkupInlineKeyboard or null +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageSticker, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultSticker id:string thumbnail_url:string sticker_url:string sticker_width:int32 sticker_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents information about a venue @id Unique identifier of the query result @venue Venue result @thumbnail_url URL of the result thumbnail, if it exists @thumbnail_width Thumbnail width, if known @thumbnail_height Thumbnail height, if known -//@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageLocation, InputMessageVenue or InputMessageContact +//@reply_markup The message reply markup; pass null if none. Must be of type replyMarkupInlineKeyboard or null +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultVenue id:string venue:venue thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to a page containing an embedded video player or a video file @id Unique identifier of the query result @title Title of the result @param_description A short description of the result, if known //@thumbnail_url The URL of the video thumbnail (JPEG), if it exists @video_url URL of the embedded video player or video file @mime_type MIME type of the content of the video URL, only "text/html" or "video/mp4" are currently supported //@video_width Width of the video @video_height Height of the video @video_duration Video duration, in seconds -//@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageVideo, InputMessageLocation, InputMessageVenue or InputMessageContact +//@reply_markup The message reply markup; pass null if none. Must be of type replyMarkupInlineKeyboard or null +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageVideo, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultVideo id:string title:string description:string thumbnail_url:string video_url:string mime_type:string video_width:int32 video_height:int32 video_duration:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to an opus-encoded audio file within an OGG container, single channel audio @id Unique identifier of the query result @title Title of the voice note //@voice_note_url The URL of the voice note file @voice_note_duration Duration of the voice note, in seconds -//@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageVoiceNote, InputMessageLocation, InputMessageVenue or InputMessageContact +//@reply_markup The message reply markup; pass null if none. Must be of type replyMarkupInlineKeyboard or null +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageVoiceNote, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultVoiceNote id:string title:string voice_note_url:string voice_note_duration:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; @@ -2229,7 +2488,7 @@ inlineQueryResultVoiceNote id:string voice_note:voiceNote title:string = InlineQ //@description Represents the results of the inline query. Use sendInlineQueryResultMessage to send the result of the query @inline_query_id Unique identifier of the inline query @next_offset The offset for the next request. If empty, there are no more results @results Results of the query -//@switch_pm_text If non-empty, this text should be shown on the button, which opens a private chat with the bot and sends the bot a start message with the switch_pm_parameter @switch_pm_parameter Parameter for the bot start message +//@switch_pm_text If non-empty, this text must be shown on the button, which opens a private chat with the bot and sends the bot a start message with the switch_pm_parameter @switch_pm_parameter Parameter for the bot start message inlineQueryResults inline_query_id:int64 next_offset:string results:vector switch_pm_text:string switch_pm_parameter:string = InlineQueryResults; @@ -2245,7 +2504,7 @@ callbackQueryPayloadDataWithPassword password:string data:bytes = CallbackQueryP callbackQueryPayloadGame game_short_name:string = CallbackQueryPayload; -//@description Contains a bot's answer to a callback query @text Text of the answer @show_alert True, if an alert should be shown to the user instead of a toast notification @url URL to be opened +//@description Contains a bot's answer to a callback query @text Text of the answer @show_alert True, if an alert must be shown to the user instead of a toast notification @url URL to be opened callbackQueryAnswer text:string show_alert:Bool url:string = CallbackQueryAnswer; @@ -2254,7 +2513,7 @@ customRequestResult result:string = CustomRequestResult; //@description Contains one row of the game high score table @position Position in the high score table @user_id User identifier @score User score -gameHighScore position:int32 user_id:int32 score:int32 = GameHighScore; +gameHighScore position:int32 user_id:int53 score:int32 = GameHighScore; //@description Contains a list of game high scores @scores A list of game high scores gameHighScores scores:vector = GameHighScores; @@ -2280,17 +2539,23 @@ chatEventMessageUnpinned message:message = ChatEventAction; //@description A new member joined the chat chatEventMemberJoined = ChatEventAction; +//@description A new member joined the chat by an invite link @invite_link Invite link used to join the chat +chatEventMemberJoinedByInviteLink invite_link:chatInviteLink = ChatEventAction; + +//@description A new member was accepted to the chat by an administrator @approver_user_id User identifier of the chat administrator, approved user join request @invite_link Invite link used to join the chat; may be null +chatEventMemberJoinedByRequest approver_user_id:int53 invite_link:chatInviteLink = ChatEventAction; + //@description A member left the chat chatEventMemberLeft = ChatEventAction; //@description A new chat member was invited @user_id New member user identifier @status New member status -chatEventMemberInvited user_id:int32 status:ChatMemberStatus = ChatEventAction; +chatEventMemberInvited user_id:int53 status:ChatMemberStatus = ChatEventAction; -//@description A chat member has gained/lost administrator status, or the list of their administrator privileges has changed @user_id Chat member user identifier @old_status Previous status of the chat member @new_status New status of the chat member -chatEventMemberPromoted user_id:int32 old_status:ChatMemberStatus new_status:ChatMemberStatus = ChatEventAction; +//@description A chat member has gained/lost administrator status, or the list of their administrator privileges has changed @user_id Affected chat member user identifier @old_status Previous status of the chat member @new_status New status of the chat member +chatEventMemberPromoted user_id:int53 old_status:ChatMemberStatus new_status:ChatMemberStatus = ChatEventAction; -//@description A chat member was restricted/unrestricted or banned/unbanned, or the list of their restrictions has changed @user_id Chat member user identifier @old_status Previous status of the chat member @new_status New status of the chat member -chatEventMemberRestricted user_id:int32 old_status:ChatMemberStatus new_status:ChatMemberStatus = ChatEventAction; +//@description A chat member was restricted/unrestricted or banned/unbanned, or the list of their restrictions has changed @member_id Affected chat member identifier @old_status Previous status of the chat member @new_status New status of the chat member +chatEventMemberRestricted member_id:MessageSender old_status:ChatMemberStatus new_status:ChatMemberStatus = ChatEventAction; //@description The chat title was changed @old_title Previous chat title @new_title New chat title chatEventTitleChanged old_title:string new_title:string = ChatEventAction; @@ -2313,9 +2578,12 @@ chatEventInvitesToggled can_invite_users:Bool = ChatEventAction; //@description The linked chat of a supergroup was changed @old_linked_chat_id Previous supergroup linked chat identifier @new_linked_chat_id New supergroup linked chat identifier chatEventLinkedChatChanged old_linked_chat_id:int53 new_linked_chat_id:int53 = ChatEventAction; -//@description The slow_mode_delay setting of a supergroup was changed @old_slow_mode_delay Previous value of slow_mode_delay @new_slow_mode_delay New value of slow_mode_delay +//@description The slow_mode_delay setting of a supergroup was changed @old_slow_mode_delay Previous value of slow_mode_delay, in seconds @new_slow_mode_delay New value of slow_mode_delay, in seconds chatEventSlowModeDelayChanged old_slow_mode_delay:int32 new_slow_mode_delay:int32 = ChatEventAction; +//@description The message TTL setting was changed @old_message_ttl_setting Previous value of message_ttl_setting @new_message_ttl_setting New value of message_ttl_setting +chatEventMessageTtlSettingChanged old_message_ttl_setting:int32 new_message_ttl_setting:int32 = ChatEventAction; + //@description The sign_messages setting of a channel was toggled @sign_messages New value of sign_messages chatEventSignMessagesToggled sign_messages:Bool = ChatEventAction; @@ -2328,24 +2596,50 @@ chatEventLocationChanged old_location:chatLocation new_location:chatLocation = C //@description The is_all_history_available setting of a supergroup was toggled @is_all_history_available New value of is_all_history_available chatEventIsAllHistoryAvailableToggled is_all_history_available:Bool = ChatEventAction; +//@description A chat invite link was edited @old_invite_link Previous information about the invite link @new_invite_link New information about the invite link +chatEventInviteLinkEdited old_invite_link:chatInviteLink new_invite_link:chatInviteLink = ChatEventAction; + +//@description A chat invite link was revoked @invite_link The invite link +chatEventInviteLinkRevoked invite_link:chatInviteLink = ChatEventAction; + +//@description A revoked chat invite link was deleted @invite_link The invite link +chatEventInviteLinkDeleted invite_link:chatInviteLink = ChatEventAction; + +//@description A video chat was created @group_call_id Identifier of the video chat. The video chat can be received through the method getGroupCall +chatEventVideoChatCreated group_call_id:int32 = ChatEventAction; + +//@description A video chat was discarded @group_call_id Identifier of the video chat. The video chat can be received through the method getGroupCall +chatEventVideoChatDiscarded group_call_id:int32 = ChatEventAction; + +//@description A video chat participant was muted or unmuted @participant_id Identifier of the affected group call participant @is_muted New value of is_muted +chatEventVideoChatParticipantIsMutedToggled participant_id:MessageSender is_muted:Bool = ChatEventAction; + +//@description A video chat participant volume level was changed @participant_id Identifier of the affected group call participant @volume_level New value of volume_level; 1-20000 in hundreds of percents +chatEventVideoChatParticipantVolumeLevelChanged participant_id:MessageSender volume_level:int32 = ChatEventAction; + +//@description The mute_new_participants setting of a video chat was toggled @mute_new_participants New value of the mute_new_participants setting +chatEventVideoChatMuteNewParticipantsToggled mute_new_participants:Bool = ChatEventAction; + //@description Represents a chat event @id Chat event identifier @date Point in time (Unix timestamp) when the event happened @user_id Identifier of the user who performed the action that triggered the event @action Action performed by the user -chatEvent id:int64 date:int32 user_id:int32 action:ChatEventAction = ChatEvent; +chatEvent id:int64 date:int32 user_id:int53 action:ChatEventAction = ChatEvent; //@description Contains a list of chat events @events List of events chatEvents events:vector = ChatEvents; //@description Represents a set of filters used to obtain a chat event log -//@message_edits True, if message edits should be returned -//@message_deletions True, if message deletions should be returned -//@message_pins True, if pin/unpin events should be returned -//@member_joins True, if members joining events should be returned -//@member_leaves True, if members leaving events should be returned -//@member_invites True, if invited member events should be returned -//@member_promotions True, if member promotion/demotion events should be returned -//@member_restrictions True, if member restricted/unrestricted/banned/unbanned events should be returned -//@info_changes True, if changes in chat information should be returned -//@setting_changes True, if changes in chat settings should be returned -chatEventLogFilters message_edits:Bool message_deletions:Bool message_pins:Bool member_joins:Bool member_leaves:Bool member_invites:Bool member_promotions:Bool member_restrictions:Bool info_changes:Bool setting_changes:Bool = ChatEventLogFilters; +//@message_edits True, if message edits need to be returned +//@message_deletions True, if message deletions need to be returned +//@message_pins True, if pin/unpin events need to be returned +//@member_joins True, if members joining events need to be returned +//@member_leaves True, if members leaving events need to be returned +//@member_invites True, if invited member events need to be returned +//@member_promotions True, if member promotion/demotion events need to be returned +//@member_restrictions True, if member restricted/unrestricted/banned/unbanned events need to be returned +//@info_changes True, if changes in chat information need to be returned +//@setting_changes True, if changes in chat settings need to be returned +//@invite_link_changes True, if changes to invite links need to be returned +//@video_chat_changes True, if video chat actions need to be returned +chatEventLogFilters message_edits:Bool message_deletions:Bool message_pins:Bool member_joins:Bool member_leaves:Bool member_invites:Bool member_promotions:Bool member_restrictions:Bool info_changes:Bool setting_changes:Bool invite_link_changes:Bool video_chat_changes:Bool = ChatEventLogFilters; //@class LanguagePackStringValue @description Represents the value of a string in a language pack @@ -2358,18 +2652,18 @@ languagePackStringValueOrdinary value:string = LanguagePackStringValue; //@few_value Value for few objects @many_value Value for many objects @other_value Default value languagePackStringValuePluralized zero_value:string one_value:string two_value:string few_value:string many_value:string other_value:string = LanguagePackStringValue; -//@description A deleted language pack string, the value should be taken from the built-in english language pack +//@description A deleted language pack string, the value must be taken from the built-in English language pack languagePackStringValueDeleted = LanguagePackStringValue; -//@description Represents one language pack string @key String key @value String value +//@description Represents one language pack string @key String key @value String value; pass null if the string needs to be taken from the built-in English language pack languagePackString key:string value:LanguagePackStringValue = LanguagePackString; //@description Contains a list of language pack strings @strings A list of language pack strings languagePackStrings strings:vector = LanguagePackStrings; //@description Contains information about a language pack @id Unique language pack identifier -//@base_language_pack_id Identifier of a base language pack; may be empty. If a string is missed in the language pack, then it should be fetched from base language pack. Unsupported in custom language packs +//@base_language_pack_id Identifier of a base language pack; may be empty. If a string is missed in the language pack, then it must be fetched from base language pack. Unsupported in custom language packs //@name Language name @native_name Name of the language in that language //@plural_code A language code to be used to apply plural forms. See https://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html for more info //@is_official True, if the language pack is official @is_rtl True, if the language pack strings are RTL @is_beta True, if the language pack is a beta language pack @@ -2384,13 +2678,13 @@ localizationTargetInfo language_packs:vector = LocalizationTar //@class DeviceToken @description Represents a data needed to subscribe for push notifications through registerDevice method. To use specific push notification service, the correct application platform must be specified and a valid server authentication data must be uploaded at https://my.telegram.org -//@description A token for Firebase Cloud Messaging @token Device registration token; may be empty to de-register a device @encrypt True, if push notifications should be additionally encrypted +//@description A token for Firebase Cloud Messaging @token Device registration token; may be empty to de-register a device @encrypt True, if push notifications must be additionally encrypted deviceTokenFirebaseCloudMessaging token:string encrypt:Bool = DeviceToken; //@description A token for Apple Push Notification service @device_token Device token; may be empty to de-register a device @is_app_sandbox True, if App Sandbox is enabled deviceTokenApplePush device_token:string is_app_sandbox:Bool = DeviceToken; -//@description A token for Apple Push Notification service VoIP notifications @device_token Device token; may be empty to de-register a device @is_app_sandbox True, if App Sandbox is enabled @encrypt True, if push notifications should be additionally encrypted +//@description A token for Apple Push Notification service VoIP notifications @device_token Device token; may be empty to de-register a device @is_app_sandbox True, if App Sandbox is enabled @encrypt True, if push notifications must be additionally encrypted deviceTokenApplePushVoIP device_token:string is_app_sandbox:Bool encrypt:Bool = DeviceToken; //@description A token for Windows Push Notification Services @access_token The access token that will be used to send notifications; may be empty to de-register a device @@ -2429,9 +2723,12 @@ pushReceiverId id:int64 = PushReceiverId; backgroundFillSolid color:int32 = BackgroundFill; //@description Describes a gradient fill of a background @top_color A top color of the background in the RGB24 format @bottom_color A bottom color of the background in the RGB24 format -//@rotation_angle Clockwise rotation angle of the gradient, in degrees; 0-359. Should be always divisible by 45 +//@rotation_angle Clockwise rotation angle of the gradient, in degrees; 0-359. Must be always divisible by 45 backgroundFillGradient top_color:int32 bottom_color:int32 rotation_angle:int32 = BackgroundFill; +//@description Describes a freeform gradient fill of a background @colors A list of 3 or 4 colors of the freeform gradients in the RGB24 format +backgroundFillFreeformGradient colors:vector = BackgroundFill; + //@class BackgroundType @description Describes the type of a background @@ -2441,12 +2738,13 @@ backgroundFillGradient top_color:int32 bottom_color:int32 rotation_angle:int32 = backgroundTypeWallpaper is_blurred:Bool is_moving:Bool = BackgroundType; //@description A PNG or TGV (gzipped subset of SVG with MIME type "application/x-tgwallpattern") pattern to be combined with the background fill chosen by the user -//@fill Description of the background fill -//@intensity Intensity of the pattern when it is shown above the filled background, 0-100 +//@fill Fill of the background +//@intensity Intensity of the pattern when it is shown above the filled background; 0-100. +//@is_inverted True, if the background fill must be applied only to the pattern itself. All other pixels are black in this case. For dark themes only //@is_moving True, if the background needs to be slightly moved when device is tilted -backgroundTypePattern fill:BackgroundFill intensity:int32 is_moving:Bool = BackgroundType; +backgroundTypePattern fill:BackgroundFill intensity:int32 is_inverted:Bool is_moving:Bool = BackgroundType; -//@description A filled background @fill Description of the background fill +//@description A filled background @fill The background fill backgroundTypeFill fill:BackgroundFill = BackgroundType; @@ -2473,6 +2771,22 @@ inputBackgroundLocal background:InputFile = InputBackground; inputBackgroundRemote background_id:int64 = InputBackground; +//@description Describes theme settings +//@accent_color Theme accent color in ARGB format +//@background The background to be used in chats; may be null +//@outgoing_message_fill The fill to be used as a background for outgoing messages +//@animate_outgoing_message_fill If true, the freeform gradient fill needs to be animated on every sent message +//@outgoing_message_accent_color Accent color of outgoing messages in ARGB format +themeSettings accent_color:int32 background:background outgoing_message_fill:BackgroundFill animate_outgoing_message_fill:Bool outgoing_message_accent_color:int32 = ThemeSettings; + + +//@description Describes a chat theme +//@name Theme name +//@light_settings Theme settings for a light chat theme +//@dark_settings Theme settings for a dark chat theme +chatTheme name:string light_settings:themeSettings dark_settings:themeSettings = ChatTheme; + + //@description Contains a list of hashtags @hashtags A list of hashtags hashtags hashtags:vector = Hashtags; @@ -2503,13 +2817,49 @@ checkChatUsernameResultUsernameInvalid = CheckChatUsernameResult; //@description The username is occupied checkChatUsernameResultUsernameOccupied = CheckChatUsernameResult; -//@description The user has too much chats with username, one of them should be made private first +//@description The user has too much chats with username, one of them must be made private first checkChatUsernameResultPublicChatsTooMuch = CheckChatUsernameResult; //@description The user can't be a member of a public supergroup checkChatUsernameResultPublicGroupsUnavailable = CheckChatUsernameResult; +//@class CheckStickerSetNameResult @description Represents result of checking whether a name can be used for a new sticker set + +//@description The name can be set +checkStickerSetNameResultOk = CheckStickerSetNameResult; + +//@description The name is invalid +checkStickerSetNameResultNameInvalid = CheckStickerSetNameResult; + +//@description The name is occupied +checkStickerSetNameResultNameOccupied = CheckStickerSetNameResult; + + +//@class ResetPasswordResult @description Represents result of 2-step verification password reset + +//@description The password was reset +resetPasswordResultOk = ResetPasswordResult; + +//@description The password reset request is pending @pending_reset_date Point in time (Unix timestamp) after which the password can be reset immediately using resetPassword +resetPasswordResultPending pending_reset_date:int32 = ResetPasswordResult; + +//@description The password reset request was declined @retry_date Point in time (Unix timestamp) when the password reset can be retried +resetPasswordResultDeclined retry_date:int32 = ResetPasswordResult; + + +//@class MessageFileType @description Contains information about a file with messages exported from another app + +//@description The messages was exported from a private chat @name Name of the other party; may be empty if unrecognized +messageFileTypePrivate name:string = MessageFileType; + +//@description The messages was exported from a group chat @title Title of the group chat; may be empty if unrecognized +messageFileTypeGroup title:string = MessageFileType; + +//@description The messages was exported from a chat of unknown type +messageFileTypeUnknown = MessageFileType; + + //@class PushMessageContent @description Contains content of a push message notification //@description A general message with hidden content @is_pinned True, if the message is a pinned message with the specified content @@ -2570,7 +2920,7 @@ pushMessageContentVoiceNote voice_note:voiceNote is_pinned:Bool = PushMessageCon pushMessageContentBasicGroupChatCreate = PushMessageContent; //@description New chat members were invited to a group @member_name Name of the added member @is_current_user True, if the current user was added to the group -//@is_returned True, if the user has returned to the group themself +//@is_returned True, if the user has returned to the group themselves pushMessageContentChatAddMembers member_name:string is_current_user:Bool is_returned:Bool = PushMessageContent; //@description A chat photo was edited @@ -2579,13 +2929,19 @@ pushMessageContentChatChangePhoto = PushMessageContent; //@description A chat title was edited @title New chat title pushMessageContentChatChangeTitle title:string = PushMessageContent; +//@description A chat theme was edited @theme_name If non-empty, name of a new theme, set for the chat. Otherwise chat theme was reset to the default one +pushMessageContentChatSetTheme theme_name:string = PushMessageContent; + //@description A chat member was deleted @member_name Name of the deleted member @is_current_user True, if the current user was deleted from the group -//@is_left True, if the user has left the group themself +//@is_left True, if the user has left the group themselves pushMessageContentChatDeleteMember member_name:string is_current_user:Bool is_left:Bool = PushMessageContent; //@description A new member joined the chat by invite link pushMessageContentChatJoinByLink = PushMessageContent; +//@description A new member was accepted to the chat by an administrator +pushMessageContentChatJoinByRequest = PushMessageContent; + //@description A forwarded messages @total_count Number of forwarded messages pushMessageContentMessageForwards total_count:int32 = PushMessageContent; @@ -2687,7 +3043,7 @@ userPrivacySettingRuleAllowAll = UserPrivacySettingRule; userPrivacySettingRuleAllowContacts = UserPrivacySettingRule; //@description A rule to allow certain specified users to do something @user_ids The user identifiers, total number of users in all rules must not exceed 1000 -userPrivacySettingRuleAllowUsers user_ids:vector = UserPrivacySettingRule; +userPrivacySettingRuleAllowUsers user_ids:vector = UserPrivacySettingRule; //@description A rule to allow all members of certain specified basic groups and supergroups to doing something @chat_ids The chat identifiers, total number of chats in all rules must not exceed 20 userPrivacySettingRuleAllowChatMembers chat_ids:vector = UserPrivacySettingRule; @@ -2699,7 +3055,7 @@ userPrivacySettingRuleRestrictAll = UserPrivacySettingRule; userPrivacySettingRuleRestrictContacts = UserPrivacySettingRule; //@description A rule to restrict all specified users from doing something @user_ids The user identifiers, total number of users in all rules must not exceed 1000 -userPrivacySettingRuleRestrictUsers user_ids:vector = UserPrivacySettingRule; +userPrivacySettingRuleRestrictUsers user_ids:vector = UserPrivacySettingRule; //@description A rule to restrict all members of specified basic groups and supergroups from doing something @chat_ids The chat identifiers, total number of chats in all rules must not exceed 20 userPrivacySettingRuleRestrictChatMembers chat_ids:vector = UserPrivacySettingRule; @@ -2734,11 +3090,11 @@ userPrivacySettingAllowPeerToPeerCalls = UserPrivacySetting; userPrivacySettingAllowFindingByPhoneNumber = UserPrivacySetting; -//@description Contains information about the period of inactivity after which the current user's account will automatically be deleted @days Number of days of inactivity before the account will be flagged for deletion; should range from 30-366 days +//@description Contains information about the period of inactivity after which the current user's account will automatically be deleted @days Number of days of inactivity before the account will be flagged for deletion; 30-366 days accountTtl days:int32 = AccountTtl; -//@description Contains information about one session in a Telegram application used by the current user. Sessions should be shown to the user in the returned order +//@description Contains information about one session in a Telegram application used by the current user. Sessions must be shown to the user in the returned order //@id Session identifier @is_current True, if this session is the current session //@is_password_pending True, if a password is needed to complete authorization of the session //@api_id Telegram API identifier, as provided by the application @application_name Name of the application, as provided by the application @@ -2763,7 +3119,7 @@ sessions sessions:vector = Sessions; //@last_active_date Point in time (Unix timestamp) when obtained authorization was last used //@ip IP address from which the user was logged in, in human-readable format //@location Human-readable description of a country and a region, from which the user was logged in, based on the IP address -connectedWebsite id:int64 domain_name:string bot_user_id:int32 browser:string platform:string log_in_date:int32 last_active_date:int32 ip:string location:string = ConnectedWebsite; +connectedWebsite id:int64 domain_name:string bot_user_id:int53 browser:string platform:string log_in_date:int32 last_active_date:int32 ip:string location:string = ConnectedWebsite; //@description Contains a list of websites the current user is logged in with Telegram @websites List of connected websites connectedWebsites websites:vector = ConnectedWebsites; @@ -2789,8 +3145,99 @@ chatReportReasonCopyright = ChatReportReason; //@description The location-based chat is unrelated to its stated location chatReportReasonUnrelatedLocation = ChatReportReason; -//@description A custom reason provided by the user @text Report text -chatReportReasonCustom text:string = ChatReportReason; +//@description The chat represents a fake account +chatReportReasonFake = ChatReportReason; + +//@description A custom reason provided by the user +chatReportReasonCustom = ChatReportReason; + + +//@class InternalLinkType @description Describes an internal https://t.me or tg: link, which must be processed by the app in a special way + +//@description The link is a link to the active sessions section of the app. Use getActiveSessions to handle the link +internalLinkTypeActiveSessions = InternalLinkType; + +//@description The link contains an authentication code. Call checkAuthenticationCode with the code if the current authorization state is authorizationStateWaitCode @code The authentication code +internalLinkTypeAuthenticationCode code:string = InternalLinkType; + +//@description The link is a link to a background. Call searchBackground with the given background name to process the link @background_name Name of the background +internalLinkTypeBackground background_name:string = InternalLinkType; + +//@description The link is a link to a chat with a Telegram bot. Call searchPublicChat with the given bot username, check that the user is a bot, show START button in the chat with the bot, +//-and then call sendBotStartMessage with the given start parameter after the button is pressed +//@bot_username Username of the bot @start_parameter The parameter to be passed to sendBotStartMessage +internalLinkTypeBotStart bot_username:string start_parameter:string = InternalLinkType; + +//@description The link is a link to a Telegram bot, which is supposed to be added to a group chat. Call searchPublicChat with the given bot username, check that the user is a bot and can be added to groups, +//-ask the current user to select a group to add the bot to, and then call sendBotStartMessage with the given start parameter and the chosen group chat. Bots can be added to a public group only by administrators of the group +//@bot_username Username of the bot @start_parameter The parameter to be passed to sendBotStartMessage +internalLinkTypeBotStartInGroup bot_username:string start_parameter:string = InternalLinkType; + +//@description The link is a link to the change phone number section of the app +internalLinkTypeChangePhoneNumber = InternalLinkType; + +//@description The link is a chat invite link. Call checkChatInviteLink with the given invite link to process the link @invite_link Internal representation of the invite link +internalLinkTypeChatInvite invite_link:string = InternalLinkType; + +//@description The link is a link to the filter settings section of the app +internalLinkTypeFilterSettings = InternalLinkType; + +//@description The link is a link to a game. Call searchPublicChat with the given bot username, check that the user is a bot, ask the current user to select a chat to send the game, and then call sendMessage with inputMessageGame +//@bot_username Username of the bot that owns the game @game_short_name Short name of the game +internalLinkTypeGame bot_username:string game_short_name:string = InternalLinkType; + +//@description The link is a link to a language pack. Call getLanguagePackInfo with the given language pack identifier to process the link @language_pack_id Language pack identifier +internalLinkTypeLanguagePack language_pack_id:string = InternalLinkType; + +//@description The link is a link to a Telegram message. Call getMessageLinkInfo with the given URL to process the link @url URL to be passed to getMessageLinkInfo +internalLinkTypeMessage url:string = InternalLinkType; + +//@description The link contains a message draft text. A share screen needs to be shown to the user, then the chosen chat must be opened and the text is added to the input field +//@text Message draft text @contains_link True, if the first line of the text contains a link. If true, the input field needs to be focused and the text after the link must be selected +internalLinkTypeMessageDraft text:formattedText contains_link:Bool = InternalLinkType; + +//@description The link contains a request of Telegram passport data. Call getPassportAuthorizationForm with the given parameters to process the link if the link was received from outside of the app, otherwise ignore it +//@bot_user_id User identifier of the service's bot @scope Telegram Passport element types requested by the service @public_key Service's public key @nonce Unique request identifier provided by the service +//@callback_url An HTTP URL to open once the request is finished or canceled with the parameter tg_passport=success or tg_passport=cancel respectively. If empty, then the link tgbot{bot_user_id}://passport/success or tgbot{bot_user_id}://passport/cancel needs to be opened instead +internalLinkTypePassportDataRequest bot_user_id:int53 scope:string public_key:string nonce:string callback_url:string = InternalLinkType; + +//@description The link can be used to confirm ownership of a phone number to prevent account deletion. Call sendPhoneNumberConfirmationCode with the given hash and phone number to process the link +//@hash Hash value from the link @phone_number Phone number value from the link +internalLinkTypePhoneNumberConfirmation hash:string phone_number:string = InternalLinkType; + +//@description The link is a link to a proxy. Call addProxy with the given parameters to process the link and add the proxy +//@server Proxy server IP address @port Proxy server port @type Type of the proxy +internalLinkTypeProxy server:string port:int32 type:ProxyType = InternalLinkType; + +//@description The link is a link to a chat by its username. Call searchPublicChat with the given chat username to process the link @chat_username Username of the chat +internalLinkTypePublicChat chat_username:string = InternalLinkType; + +//@description The link can be used to login the current user on another device, but it must be scanned from QR-code using in-app camera. An alert similar to +//-"This code can be used to allow someone to log in to your Telegram account. To confirm Telegram login, please go to Settings > Devices > Scan QR and scan the code" needs to be shown +internalLinkTypeQrCodeAuthentication = InternalLinkType; + +//@description The link is a link to app settings +internalLinkTypeSettings = InternalLinkType; + +//@description The link is a link to a sticker set. Call searchStickerSet with the given sticker set name to process the link and show the sticker set @sticker_set_name Name of the sticker set +internalLinkTypeStickerSet sticker_set_name:string = InternalLinkType; + +//@description The link is a link to a theme. TDLib has no theme support yet @theme_name Name of the theme +internalLinkTypeTheme theme_name:string = InternalLinkType; + +//@description The link is a link to the theme settings section of the app +internalLinkTypeThemeSettings = InternalLinkType; + +//@description The link is an unknown tg: link. Call getDeepLinkInfo to process the link @link Link to be passed to getDeepLinkInfo +internalLinkTypeUnknownDeepLink link:string = InternalLinkType; + +//@description The link is a link to an unsupported proxy. An alert can be shown to the user +internalLinkTypeUnsupportedProxy = InternalLinkType; + +//@description The link is a link to a video chat. Call searchPublicChat with the given chat username, and then joinGoupCall with the given invite hash to process the link +//@chat_username Username of the chat with the video chat @invite_hash If non-empty, invite hash to be used to join the video chat without being muted by administrators +//@is_live_stream True, if the video chat is expected to be a live stream in a channel or a broadcast group +internalLinkTypeVideoChat chat_username:string invite_hash:string is_live_stream:Bool = InternalLinkType; //@description Contains an HTTPS link to a message in a supergroup or channel @link Message link @is_public True, if the link will work for non-members of the chat @@ -2800,9 +3247,10 @@ messageLink link:string is_public:Bool = MessageLink; //@is_public True, if the link is a public link for a message in a chat //@chat_id If found, identifier of the chat to which the message belongs, 0 otherwise //@message If found, the linked message; may be null +//@media_timestamp Timestamp from which the video/audio/video note/voice note playing must start, in seconds; 0 if not specified. The media can be in the message content or in its web page preview //@for_album True, if the whole media album to which the message belongs is linked //@for_comment True, if the message is linked as a channel post comment or from a message thread -messageLinkInfo is_public:Bool chat_id:int53 message:message for_album:Bool for_comment:Bool = MessageLinkInfo; +messageLinkInfo is_public:Bool chat_id:int53 message:message media_timestamp:int32 for_album:Bool for_comment:Bool = MessageLinkInfo; //@description Contains a part of a file @data File bytes @@ -2860,16 +3308,16 @@ fileTypeVoiceNote = FileType; fileTypeWallpaper = FileType; -//@description Contains the storage usage statistics for a specific file type @file_type File type @size Total size of the files @count Total number of files +//@description Contains the storage usage statistics for a specific file type @file_type File type @size Total size of the files, in bytes @count Total number of files storageStatisticsByFileType file_type:FileType size:int53 count:int32 = StorageStatisticsByFileType; -//@description Contains the storage usage statistics for a specific chat @chat_id Chat identifier; 0 if none @size Total size of the files in the chat @count Total number of files in the chat @by_file_type Statistics split by file types +//@description Contains the storage usage statistics for a specific chat @chat_id Chat identifier; 0 if none @size Total size of the files in the chat, in bytes @count Total number of files in the chat @by_file_type Statistics split by file types storageStatisticsByChat chat_id:int53 size:int53 count:int32 by_file_type:vector = StorageStatisticsByChat; -//@description Contains the exact storage usage statistics split by chats and file type @size Total size of files @count Total number of files @by_chat Statistics split by chats +//@description Contains the exact storage usage statistics split by chats and file type @size Total size of files, in bytes @count Total number of files @by_chat Statistics split by chats storageStatistics size:int53 count:int32 by_chat:vector = StorageStatistics; -//@description Contains approximate storage usage statistics, excluding files of unknown file type @files_size Approximate total size of files @file_count Approximate number of files +//@description Contains approximate storage usage statistics, excluding files of unknown file type @files_size Approximate total size of files, in bytes @file_count Approximate number of files //@database_size Size of the database @language_pack_database_size Size of the language pack database @log_size Size of the TDLib internal log storageStatisticsFast files_size:int53 file_count:int32 database_size:int53 language_pack_database_size:int53 log_size:int53 = StorageStatisticsFast; @@ -2898,12 +3346,17 @@ networkTypeOther = NetworkType; //@class NetworkStatisticsEntry @description Contains statistics about network usage -//@description Contains information about the total amount of data that was used to send and receive files @file_type Type of the file the data is part of @network_type Type of the network the data was sent through. Call setNetworkType to maintain the actual network type +//@description Contains information about the total amount of data that was used to send and receive files +//@file_type Type of the file the data is part of; pass null if the data isn't related to files +//@network_type Type of the network the data was sent through. Call setNetworkType to maintain the actual network type //@sent_bytes Total number of bytes sent @received_bytes Total number of bytes received networkStatisticsEntryFile file_type:FileType network_type:NetworkType sent_bytes:int53 received_bytes:int53 = NetworkStatisticsEntry; -//@description Contains information about the total amount of data that was used for calls @network_type Type of the network the data was sent through. Call setNetworkType to maintain the actual network type -//@sent_bytes Total number of bytes sent @received_bytes Total number of bytes received @duration Total call duration, in seconds +//@description Contains information about the total amount of data that was used for calls +//@network_type Type of the network the data was sent through. Call setNetworkType to maintain the actual network type +//@sent_bytes Total number of bytes sent +//@received_bytes Total number of bytes received +//@duration Total call duration, in seconds networkStatisticsEntryCall network_type:NetworkType sent_bytes:int53 received_bytes:int53 duration:double = NetworkStatisticsEntry; //@description A full list of available network statistic entries @since_date Point in time (Unix timestamp) from which the statistics are collected @entries Network statistics entries @@ -2912,16 +3365,16 @@ networkStatistics since_date:int32 entries:vector = Netw //@description Contains auto-download settings //@is_auto_download_enabled True, if the auto-download is enabled -//@max_photo_file_size The maximum size of a photo file to be auto-downloaded -//@max_video_file_size The maximum size of a video file to be auto-downloaded -//@max_other_file_size The maximum size of other file types to be auto-downloaded -//@video_upload_bitrate The maximum suggested bitrate for uploaded videos +//@max_photo_file_size The maximum size of a photo file to be auto-downloaded, in bytes +//@max_video_file_size The maximum size of a video file to be auto-downloaded, in bytes +//@max_other_file_size The maximum size of other file types to be auto-downloaded, in bytes +//@video_upload_bitrate The maximum suggested bitrate for uploaded videos, in kbit/s //@preload_large_videos True, if the beginning of video files needs to be preloaded for instant playback //@preload_next_audio True, if the next audio track needs to be preloaded while the user is listening to an audio file //@use_less_data_for_calls True, if "use less data for calls" option needs to be enabled autoDownloadSettings is_auto_download_enabled:Bool max_photo_file_size:int32 max_video_file_size:int32 max_other_file_size:int32 video_upload_bitrate:int32 preload_large_videos:Bool preload_next_audio:Bool use_less_data_for_calls:Bool = AutoDownloadSettings; -//@description Contains auto-download settings presets for the user +//@description Contains auto-download settings presets for the current user //@low Preset with lowest settings; supposed to be used by default when roaming //@medium Preset with medium settings; supposed to be used by default when using mobile data //@high Preset with highest settings; supposed to be used by default when connected on Wi-Fi @@ -2973,7 +3426,7 @@ topChatCategoryForwardChats = TopChatCategory; //@class TMeUrlType @description Describes the type of a URL linking to an internal Telegram entity //@description A URL linking to a user @user_id Identifier of the user -tMeUrlTypeUser user_id:int32 = TMeUrlType; +tMeUrlTypeUser user_id:int53 = TMeUrlType; //@description A URL linking to a public supergroup or channel @supergroup_id Identifier of the supergroup or channel tMeUrlTypeSupergroup supergroup_id:int53 = TMeUrlType; @@ -2996,9 +3449,18 @@ tMeUrls urls:vector = TMeUrls; //@description Suggests the user to enable "archive_and_mute_new_chats_from_unknown_users" option suggestedActionEnableArchiveAndMuteNewChats = SuggestedAction; -//@description Suggests the user to check authorization phone number and change the phone number if it is inaccessible +//@description Suggests the user to check whether 2-step verification password is still remembered +suggestedActionCheckPassword = SuggestedAction; + +//@description Suggests the user to check whether authorization phone number is correct and change the phone number if it is inaccessible suggestedActionCheckPhoneNumber = SuggestedAction; +//@description Suggests the user to see a hint about meaning of one and two ticks on sent message +suggestedActionSeeTicksHint = SuggestedAction; + +//@description Suggests the user to convert specified supergroup to a broadcast group @supergroup_id Supergroup identifier +suggestedActionConvertToBroadcastGroup supergroup_id:int53 = SuggestedAction; + //@description Contains a counter @count Count count count:int32 = Count; @@ -3010,11 +3472,11 @@ text text:string = Text; seconds seconds:double = Seconds; -//@description Contains information about a tg:// deep link @text Text to be shown to the user @need_update_application True, if user should be asked to update the application +//@description Contains information about a tg: deep link @text Text to be shown to the user @need_update_application True, if the user must be asked to update the application deepLinkInfo text:formattedText need_update_application:Bool = DeepLinkInfo; -//@class TextParseMode @description Describes the way the text should be parsed for TextEntities +//@class TextParseMode @description Describes the way the text needs to be parsed for TextEntities //@description The text uses Markdown-style formatting //@version Version of the parser: 0 or 1 - Telegram Bot API "Markdown" parse mode, 2 - Telegram Bot API "MarkdownV2" parse mode @@ -3048,7 +3510,7 @@ proxies proxies:vector = Proxies; //@description A static sticker in PNG format, which will be converted to WEBP server-side //@sticker PNG image with the sticker; must be up to 512 KB in size and fit in a 512x512 square //@emojis Emojis corresponding to the sticker -//@mask_position For masks, position where the mask should be placed; may be null +//@mask_position For masks, position where the mask is placed; pass null if unspecified inputStickerStatic sticker:InputFile emojis:string mask_position:maskPosition = InputSticker; //@description An animated sticker in TGS format @@ -3086,20 +3548,20 @@ chatStatisticsMessageInteractionInfo message_id:int53 view_count:int32 forward_c //@description Contains statistics about messages sent by a user //@user_id User identifier //@sent_message_count Number of sent messages -//@average_character_count Average number of characters in sent messages -chatStatisticsMessageSenderInfo user_id:int32 sent_message_count:int32 average_character_count:int32 = ChatStatisticsMessageSenderInfo; +//@average_character_count Average number of characters in sent messages; 0 if unknown +chatStatisticsMessageSenderInfo user_id:int53 sent_message_count:int32 average_character_count:int32 = ChatStatisticsMessageSenderInfo; //@description Contains statistics about administrator actions done by a user //@user_id Administrator user identifier //@deleted_message_count Number of messages deleted by the administrator //@banned_user_count Number of users banned by the administrator //@restricted_user_count Number of users restricted by the administrator -chatStatisticsAdministratorActionsInfo user_id:int32 deleted_message_count:int32 banned_user_count:int32 restricted_user_count:int32 = ChatStatisticsAdministratorActionsInfo; +chatStatisticsAdministratorActionsInfo user_id:int53 deleted_message_count:int32 banned_user_count:int32 restricted_user_count:int32 = ChatStatisticsAdministratorActionsInfo; //@description Contains statistics about number of new members invited by a user //@user_id User identifier //@added_member_count Number of new members invited by the user -chatStatisticsInviterInfo user_id:int32 added_member_count:int32 = ChatStatisticsInviterInfo; +chatStatisticsInviterInfo user_id:int53 added_member_count:int32 = ChatStatisticsInviterInfo; //@class ChatStatistics @description Contains a detailed statistics about a chat @@ -3146,6 +3608,43 @@ chatStatisticsChannel period:dateRange member_count:statisticalValue mean_view_c messageStatistics message_interaction_graph:StatisticalGraph = MessageStatistics; +//@description A point on a Cartesian plane @x The point's first coordinate @y The point's second coordinate +point x:double y:double = Point; + + +//@class VectorPathCommand @description Represents a vector path command + +//@description A straight line to a given point @end_point The end point of the straight line +vectorPathCommandLine end_point:point = VectorPathCommand; + +//@description A cubic Bézier curve to a given point @start_control_point The start control point of the curve @end_control_point The end control point of the curve @end_point The end point of the curve +vectorPathCommandCubicBezierCurve start_control_point:point end_control_point:point end_point:point = VectorPathCommand; + + +//@class BotCommandScope @description Represents the scope to which bot commands are relevant + +//@description A scope covering all users +botCommandScopeDefault = BotCommandScope; + +//@description A scope covering all private chats +botCommandScopeAllPrivateChats = BotCommandScope; + +//@description A scope covering all group and supergroup chats +botCommandScopeAllGroupChats = BotCommandScope; + +//@description A scope covering all group and supergroup chat administrators +botCommandScopeAllChatAdministrators = BotCommandScope; + +//@description A scope covering all members of a chat @chat_id Chat identifier +botCommandScopeChat chat_id:int53 = BotCommandScope; + +//@description A scope covering all administrators of a chat @chat_id Chat identifier +botCommandScopeChatAdministrators chat_id:int53 = BotCommandScope; + +//@description A scope covering a member of a chat @chat_id Chat identifier @user_id User identifier +botCommandScopeChatMember chat_id:int53 user_id:int53 = BotCommandScope; + + //@class Update @description Contains notifications about data changes //@description The user authorization state has changed @authorization_state New authorization state @@ -3158,11 +3657,11 @@ updateNewMessage message:message = Update; //@chat_id The chat identifier of the sent message @message_id A temporary message identifier updateMessageSendAcknowledged chat_id:int53 message_id:int53 = Update; -//@description A message has been successfully sent @message Information about the sent message. Usually only the message identifier, date, and content are changed, but almost all other fields can also change @old_message_id The previous temporary message identifier +//@description A message has been successfully sent @message The sent message. Usually only the message identifier, date, and content are changed, but almost all other fields can also change @old_message_id The previous temporary message identifier updateMessageSendSucceeded message:message old_message_id:int53 = Update; //@description A message failed to send. Be aware that some messages being sent can be irrecoverably deleted, in which case updateDeleteMessages will be received instead of this update -//@message Contains information about the message which failed to send @old_message_id The previous temporary message identifier @error_code An error code @error_message Error message +//@message The failed to send message @old_message_id The previous temporary message identifier @error_code An error code @error_message Error message updateMessageSendFailed message:message old_message_id:int53 error_code:int32 error_message:string = Update; //@description The message content has changed @chat_id Chat identifier @message_id Message identifier @new_content New message content @@ -3214,10 +3713,13 @@ updateChatIsBlocked chat_id:int53 is_blocked:Bool = Update; //@description A chat's has_scheduled_messages field has changed @chat_id Chat identifier @has_scheduled_messages New value of has_scheduled_messages updateChatHasScheduledMessages chat_id:int53 has_scheduled_messages:Bool = Update; +//@description A chat video chat state has changed @chat_id Chat identifier @video_chat New value of video_chat +updateChatVideoChat chat_id:int53 video_chat:videoChat = Update; + //@description The value of the default disable_notification parameter, used when a message is sent to the chat, was changed @chat_id Chat identifier @default_disable_notification The new default_disable_notification value updateChatDefaultDisableNotification chat_id:int53 default_disable_notification:Bool = Update; -//@description Incoming messages were read or number of unread messages has been changed @chat_id Chat identifier @last_read_inbox_message_id Identifier of the last read incoming message @unread_count The number of unread messages left in the chat +//@description Incoming messages were read or the number of unread messages has been changed @chat_id Chat identifier @last_read_inbox_message_id Identifier of the last read incoming message @unread_count The number of unread messages left in the chat updateChatReadInbox chat_id:int53 last_read_inbox_message_id:int53 unread_count:int32 = Update; //@description Outgoing messages were read @chat_id Chat identifier @last_read_outbox_message_id Identifier of last read outgoing message @@ -3232,14 +3734,23 @@ updateChatNotificationSettings chat_id:int53 notification_settings:chatNotificat //@description Notification settings for some type of chats were updated @scope Types of chats for which notification settings were updated @notification_settings The new notification settings updateScopeNotificationSettings scope:NotificationSettingsScope notification_settings:scopeNotificationSettings = Update; +//@description The message Time To Live setting for a chat was changed @chat_id Chat identifier @message_ttl_setting New value of message_ttl_setting +updateChatMessageTtlSetting chat_id:int53 message_ttl_setting:int32 = Update; + //@description The chat action bar was changed @chat_id Chat identifier @action_bar The new value of the action bar; may be null updateChatActionBar chat_id:int53 action_bar:ChatActionBar = Update; +//@description The chat theme was changed @chat_id Chat identifier @theme_name The new name of the chat theme; may be empty if theme was reset to default +updateChatTheme chat_id:int53 theme_name:string = Update; + +//@description The chat pending join requests were changed @chat_id Chat identifier @pending_join_requests The new data about pending join requests; may be null +updateChatPendingJoinRequests chat_id:int53 pending_join_requests:chatJoinRequestsInfo = Update; + //@description The default chat reply markup was changed. Can occur because new messages with reply markup were received or because an old reply markup was hidden by the user //@chat_id Chat identifier @reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat updateChatReplyMarkup chat_id:int53 reply_markup_message_id:int53 = Update; -//@description A chat draft has changed. Be aware that the update may come in the currently opened chat but with old content of the draft. If the user has changed the content of the draft, this update shouldn't be applied @chat_id Chat identifier @draft_message The new draft message; may be null @positions The new chat positions in the chat lists +//@description A chat draft has changed. Be aware that the update may come in the currently opened chat but with old content of the draft. If the user has changed the content of the draft, this update mustn't be applied @chat_id Chat identifier @draft_message The new draft message; may be null @positions The new chat positions in the chat lists updateChatDraftMessage chat_id:int53 draft_message:draftMessage positions:vector = Update; //@description The list of chat filters or a chat filter has changed @chat_filters The new list of chat filters @@ -3256,7 +3767,7 @@ updateNotification notification_group_id:int32 notification:notification = Updat //@type New type of the notification group //@chat_id Identifier of a chat to which all notifications in the group belong //@notification_settings_chat_id Chat identifier, which notification settings must be applied to the added notifications -//@is_silent True, if the notifications should be shown without sound +//@is_silent True, if the notifications must be shown without sound //@total_count Total number of unread notifications in the group, can be bigger than number of active notifications //@added_notifications List of added group notifications, sorted by notification ID @removed_notification_ids Identifiers of removed group notifications, sorted by notification ID updateNotificationGroup notification_group_id:int32 type:NotificationGroupType chat_id:int53 notification_settings_chat_id:int53 is_silent:Bool total_count:int32 added_notifications:vector removed_notification_ids:vector = Update; @@ -3275,10 +3786,10 @@ updateHavePendingNotifications have_delayed_notifications:Bool have_unreceived_n updateDeleteMessages chat_id:int53 message_ids:vector is_permanent:Bool from_cache:Bool = Update; //@description User activity in the chat has changed @chat_id Chat identifier @message_thread_id If not 0, a message thread identifier in which the action was performed @user_id Identifier of a user performing an action @action The action description -updateUserChatAction chat_id:int53 message_thread_id:int53 user_id:int32 action:ChatAction = Update; +updateUserChatAction chat_id:int53 message_thread_id:int53 user_id:int53 action:ChatAction = Update; //@description The user went online or offline @user_id User identifier @status New status of the user -updateUserStatus user_id:int32 status:UserStatus = Update; +updateUserStatus user_id:int53 status:UserStatus = Update; //@description Some data of a user has changed. This update is guaranteed to come before the user identifier is returned to the application @user New data about the user updateUser user:user = Update; @@ -3293,16 +3804,16 @@ updateSupergroup supergroup:supergroup = Update; updateSecretChat secret_chat:secretChat = Update; //@description Some data from userFullInfo has been changed @user_id User identifier @user_full_info New full information about the user -updateUserFullInfo user_id:int32 user_full_info:userFullInfo = Update; +updateUserFullInfo user_id:int53 user_full_info:userFullInfo = Update; //@description Some data from basicGroupFullInfo has been changed @basic_group_id Identifier of a basic group @basic_group_full_info New full information about the group -updateBasicGroupFullInfo basic_group_id:int32 basic_group_full_info:basicGroupFullInfo = Update; +updateBasicGroupFullInfo basic_group_id:int53 basic_group_full_info:basicGroupFullInfo = Update; //@description Some data from supergroupFullInfo has been changed @supergroup_id Identifier of the supergroup or channel @supergroup_full_info New full information about the supergroup -updateSupergroupFullInfo supergroup_id:int32 supergroup_full_info:supergroupFullInfo = Update; +updateSupergroupFullInfo supergroup_id:int53 supergroup_full_info:supergroupFullInfo = Update; //@description Service notification from the server. Upon receiving this the application must show a popup with the content of the notification -//@type Notification type. If type begins with "AUTH_KEY_DROP_", then two buttons "Cancel" and "Log out" should be shown under notification; if user presses the second, all local data should be destroyed using Destroy method +//@type Notification type. If type begins with "AUTH_KEY_DROP_", then two buttons "Cancel" and "Log out" must be shown under notification; if user presses the second, all local data must be destroyed using Destroy method //@content Notification content updateServiceNotification type:string content:MessageContent = Update; @@ -3312,8 +3823,8 @@ updateFile file:file = Update; //@description The file generation process needs to be started by the application //@generation_id Unique identifier for the generation process //@original_path The path to a file from which a new file is generated; may be empty -//@destination_path The path to a file that should be created and where the new file should be generated -//@conversion String specifying the conversion applied to the original file. If conversion is "#url#" than original_path contains an HTTP/HTTPS URL of a file, which should be downloaded by the application +//@destination_path The path to a file that must be created and where the new file is generated +//@conversion String specifying the conversion applied to the original file. If conversion is "#url#" than original_path contains an HTTP/HTTPS URL of a file, which must be downloaded by the application updateFileGenerationStart generation_id:int64 original_path:string destination_path:string conversion:string = Update; //@description File generation is no longer needed @generation_id Unique identifier for the generation process @@ -3322,6 +3833,13 @@ updateFileGenerationStop generation_id:int64 = Update; //@description New call was created or information about a call was updated @call New data about a call updateCall call:call = Update; +//@description Information about a group call was updated @group_call New data about a group call +updateGroupCall group_call:groupCall = Update; + +//@description Information about a group call participant was changed. The updates are sent only after the group call is received through getGroupCall and only if the call is joined or being joined +//@group_call_id Identifier of group call @participant New data about a participant +updateGroupCallParticipant group_call_id:int32 participant:groupCallParticipant = Update; + //@description New call signaling data arrived @call_id The call identifier @data The data updateNewCallSignalingData call_id:int32 data:bytes = Update; @@ -3363,13 +3881,16 @@ updateSavedAnimations animation_ids:vector = Update; //@description The selected background has changed @for_dark_theme True, if background for dark theme has changed @background The new selected background; may be null updateSelectedBackground for_dark_theme:Bool background:background = Update; +//@description The list of available chat themes has changed @chat_themes The new list of chat themes +updateChatThemes chat_themes:vector = Update; + //@description Some language pack strings have been updated @localization_target Localization target to which the language pack belongs @language_pack_id Identifier of the updated language pack @strings List of changed language pack strings updateLanguagePackStrings localization_target:string language_pack_id:string strings:vector = Update; //@description The connection state has changed. This update must be used only to show a human-readable description of the connection state @state The new connection state updateConnectionState state:ConnectionState = Update; -//@description New terms of service must be accepted by the user. If the terms of service are declined, then the deleteAccount method should be called with the reason "Decline ToS update" @terms_of_service_id Identifier of the terms of service @terms_of_service The new terms of service +//@description New terms of service must be accepted by the user. If the terms of service are declined, then the deleteAccount method must be called with the reason "Decline ToS update" @terms_of_service_id Identifier of the terms of service @terms_of_service The new terms of service updateTermsOfService terms_of_service_id:string terms_of_service:termsOfService = Update; //@description The list of users nearby has changed. The update is guaranteed to be sent only 60 seconds after a successful searchChatsNearby request @users_nearby The new list of users nearby @@ -3378,6 +3899,10 @@ updateUsersNearby users_nearby:vector = Update; //@description The list of supported dice emojis has changed @emojis The new list of supported dice emojis updateDiceEmojis emojis:vector = Update; +//@description Some animated emoji message was clicked and a big animated sticker must be played if the message is visible on the screen. chatActionWatchingAnimations with the text of the message needs to be sent if the sticker is played +//@chat_id Chat identifier @message_id Message identifier @sticker The animated sticker to be played +updateAnimatedEmojiMessageClicked chat_id:int53 message_id:int53 sticker:sticker = Update; + //@description The parameters of animation search through GetOption("animation_search_bot_username") bot has changed @provider Name of the animation search provider @emojis The new list of emojis suggested for searching updateAnimationSearchParameters provider:string emojis:vector = Update; @@ -3385,28 +3910,28 @@ updateAnimationSearchParameters provider:string emojis:vector = Update; updateSuggestedActions added_actions:vector removed_actions:vector = Update; //@description A new incoming inline query; for bots only @id Unique query identifier @sender_user_id Identifier of the user who sent the query @user_location User location; may be null -//@query Text of the query @offset Offset of the first entry to return -updateNewInlineQuery id:int64 sender_user_id:int32 user_location:location query:string offset:string = Update; +//@chat_type The type of the chat, from which the query originated; may be null if unknown @query Text of the query @offset Offset of the first entry to return +updateNewInlineQuery id:int64 sender_user_id:int53 user_location:location chat_type:ChatType query:string offset:string = Update; //@description The user has chosen a result of an inline query; for bots only @sender_user_id Identifier of the user who sent the query @user_location User location; may be null //@query Text of the query @result_id Identifier of the chosen result @inline_message_id Identifier of the sent inline message, if known -updateNewChosenInlineResult sender_user_id:int32 user_location:location query:string result_id:string inline_message_id:string = Update; +updateNewChosenInlineResult sender_user_id:int53 user_location:location query:string result_id:string inline_message_id:string = Update; //@description A new incoming callback query; for bots only @id Unique query identifier @sender_user_id Identifier of the user who sent the query //@chat_id Identifier of the chat where the query was sent @message_id Identifier of the message, from which the query originated //@chat_instance Identifier that uniquely corresponds to the chat to which the message was sent @payload Query payload -updateNewCallbackQuery id:int64 sender_user_id:int32 chat_id:int53 message_id:int53 chat_instance:int64 payload:CallbackQueryPayload = Update; +updateNewCallbackQuery id:int64 sender_user_id:int53 chat_id:int53 message_id:int53 chat_instance:int64 payload:CallbackQueryPayload = Update; //@description A new incoming callback query from a message sent via a bot; for bots only @id Unique query identifier @sender_user_id Identifier of the user who sent the query @inline_message_id Identifier of the inline message, from which the query originated //@chat_instance An identifier uniquely corresponding to the chat a message was sent to @payload Query payload -updateNewInlineCallbackQuery id:int64 sender_user_id:int32 inline_message_id:string chat_instance:int64 payload:CallbackQueryPayload = Update; +updateNewInlineCallbackQuery id:int64 sender_user_id:int53 inline_message_id:string chat_instance:int64 payload:CallbackQueryPayload = Update; //@description A new incoming shipping query; for bots only. Only for invoices with flexible price @id Unique query identifier @sender_user_id Identifier of the user who sent the query @invoice_payload Invoice payload @shipping_address User shipping address -updateNewShippingQuery id:int64 sender_user_id:int32 invoice_payload:string shipping_address:address = Update; +updateNewShippingQuery id:int64 sender_user_id:int53 invoice_payload:string shipping_address:address = Update; -//@description A new incoming pre-checkout query; for bots only. Contains full information about a checkout @id Unique query identifier @sender_user_id Identifier of the user who sent the query @currency Currency for the product price @total_amount Total price for the product, in the minimal quantity of the currency +//@description A new incoming pre-checkout query; for bots only. Contains full information about a checkout @id Unique query identifier @sender_user_id Identifier of the user who sent the query @currency Currency for the product price @total_amount Total price for the product, in the smallest units of the currency //@invoice_payload Invoice payload @shipping_option_id Identifier of a shipping option chosen by the user; may be empty if not applicable @order_info Information about the order; may be null -updateNewPreCheckoutQuery id:int64 sender_user_id:int32 currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo = Update; +updateNewPreCheckoutQuery id:int64 sender_user_id:int53 currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo = Update; //@description A new incoming event; for bots only @event A JSON-serialized event updateNewCustomEvent event:string = Update; @@ -3418,7 +3943,15 @@ updateNewCustomQuery id:int64 data:string timeout:int32 = Update; updatePoll poll:poll = Update; //@description A user changed the answer to a poll; for bots only @poll_id Unique poll identifier @user_id The user, who changed the answer to the poll @option_ids 0-based identifiers of answer options, chosen by the user -updatePollAnswer poll_id:int64 user_id:int32 option_ids:vector = Update; +updatePollAnswer poll_id:int64 user_id:int53 option_ids:vector = Update; + +//@description User rights changed in a chat; for bots only @chat_id Chat identifier @actor_user_id Identifier of the user, changing the rights +//@date Point in time (Unix timestamp) when the user rights was changed @invite_link If user has joined the chat using an invite link, the invite link; may be null +//@old_chat_member Previous chat member @new_chat_member New chat member +updateChatMember chat_id:int53 actor_user_id:int53 date:int32 invite_link:chatInviteLink old_chat_member:chatMember new_chat_member:chatMember = Update; + +//@description A user sent a join request to a chat; for bots only @chat_id Chat identifier @request Join request @invite_link The invite link, which was used to send join request; may be null +updateNewChatJoinRequest chat_id:int53 request:chatJoinRequest invite_link:chatInviteLink = Update; //@description Contains a list of updates @updates List of updates @@ -3432,7 +3965,7 @@ logStreamDefault = LogStream; //@description The log is written to a file //@path Path to the file to where the internal TDLib log will be written -//@max_file_size The maximum size of the file to where the internal TDLib log is written before the file will be auto-rotated +//@max_file_size The maximum size of the file to where the internal TDLib log is written before the file will be auto-rotated, in bytes //@redirect_stderr Pass true to additionally redirect stderr to the log file. Ignored on Windows logStreamFile path:string max_file_size:int53 redirect_stderr:Bool = LogStream; @@ -3468,7 +4001,7 @@ testVectorStringObject value:vector = TestVectorStringObject; getAuthorizationState = AuthorizationState; -//@description Sets the parameters for TDLib initialization. Works only when the current authorization state is authorizationStateWaitTdlibParameters @parameters Parameters +//@description Sets the parameters for TDLib initialization. Works only when the current authorization state is authorizationStateWaitTdlibParameters @parameters Parameters for TDLib initialization setTdlibParameters parameters:tdlibParameters = Ok; //@description Checks the database encryption key for correctness. Works only when the current authorization state is authorizationStateWaitEncryptionKey @encryption_key Encryption key to check or set up @@ -3476,10 +4009,10 @@ checkDatabaseEncryptionKey encryption_key:bytes = Ok; //@description Sets the phone number of the user and sends an authentication code to the user. Works only when the current authorization state is authorizationStateWaitPhoneNumber, //-or if there is no pending authentication query and the current authorization state is authorizationStateWaitCode, authorizationStateWaitRegistration, or authorizationStateWaitPassword -//@phone_number The phone number of the user, in international format @settings Settings for the authentication of the user's phone number +//@phone_number The phone number of the user, in international format @settings Settings for the authentication of the user's phone number; pass null to use default settings setAuthenticationPhoneNumber phone_number:string settings:phoneNumberAuthenticationSettings = Ok; -//@description Re-sends an authentication code to the user. Works only when the current authorization state is authorizationStateWaitCode and the next_code_type of the result is not null +//@description Re-sends an authentication code to the user. Works only when the current authorization state is authorizationStateWaitCode, the next_code_type of the result is not null and the server-specified timeout has passed resendAuthenticationCode = Ok; //@description Checks the authentication code. Works only when the current authorization state is authorizationStateWaitCode @code The verification code received via SMS, Telegram message, phone call, or flash call @@ -3488,7 +4021,7 @@ checkAuthenticationCode code:string = Ok; //@description Requests QR code authentication by scanning a QR code on another logged in device. Works only when the current authorization state is authorizationStateWaitPhoneNumber, //-or if there is no pending authentication query and the current authorization state is authorizationStateWaitCode, authorizationStateWaitRegistration, or authorizationStateWaitPassword //@other_user_ids List of user identifiers of other users currently using the application -requestQrCodeAuthentication other_user_ids:vector = Ok; +requestQrCodeAuthentication other_user_ids:vector = Ok; //@description Finishes user registration. Works only when the current authorization state is authorizationStateWaitRegistration //@first_name The first name of the user; 1-64 characters @last_name The last name of the user; 0-64 characters @@ -3500,8 +4033,12 @@ checkAuthenticationPassword password:string = Ok; //@description Requests to send a password recovery code to an email address that was previously set up. Works only when the current authorization state is authorizationStateWaitPassword requestAuthenticationPasswordRecovery = Ok; -//@description Recovers the password with a password recovery code sent to an email address that was previously set up. Works only when the current authorization state is authorizationStateWaitPassword @recovery_code Recovery code to check -recoverAuthenticationPassword recovery_code:string = Ok; +//@description Checks whether a password recovery code sent to an email address is valid. Works only when the current authorization state is authorizationStateWaitPassword @recovery_code Recovery code to check +checkAuthenticationPasswordRecoveryCode recovery_code:string = Ok; + +//@description Recovers the password with a password recovery code sent to an email address that was previously set up. Works only when the current authorization state is authorizationStateWaitPassword +//@recovery_code Recovery code to check @new_password New password of the user; may be empty to remove the password @new_hint New password hint; may be empty +recoverAuthenticationPassword recovery_code:string new_password:string new_hint:string = Ok; //@description Checks the authentication token of a bot; to log in as a bot. Works only when the current authorization state is authorizationStateWaitPhoneNumber. Can be used instead of setAuthenticationPhoneNumber and checkAuthenticationCode to log in @token The bot token checkAuthenticationBotToken token:string = Ok; @@ -3531,8 +4068,8 @@ setDatabaseEncryptionKey new_encryption_key:bytes = Ok; //@description Returns the current state of 2-step verification getPasswordState = PasswordState; -//@description Changes the password for the user. If a new recovery email address is specified, then the change will not be applied until the new recovery email address is confirmed -//@old_password Previous password of the user @new_password New password of the user; may be empty to remove the password @new_hint New password hint; may be empty @set_recovery_email_address Pass true if the recovery email address should be changed @new_recovery_email_address New recovery email address; may be empty +//@description Changes the password for the current user. If a new recovery email address is specified, then the change will not be applied until the new recovery email address is confirmed +//@old_password Previous password of the user @new_password New password of the user; may be empty to remove the password @new_hint New password hint; may be empty @set_recovery_email_address Pass true if the recovery email address must be changed @new_recovery_email_address New recovery email address; may be empty setPassword old_password:string new_password:string new_hint:string set_recovery_email_address:Bool new_recovery_email_address:string = PasswordState; //@description Returns a 2-step verification recovery email address that was previously set up. This method can be used to verify a password provided by the user @password The password for the current user @@ -3548,13 +4085,23 @@ checkRecoveryEmailAddressCode code:string = PasswordState; //@description Resends the 2-step verification recovery email address verification code resendRecoveryEmailAddressCode = PasswordState; -//@description Requests to send a password recovery code to an email address that was previously set up +//@description Requests to send a 2-step verification password recovery code to an email address that was previously set up requestPasswordRecovery = EmailAddressAuthenticationCodeInfo; -//@description Recovers the password using a recovery code sent to an email address that was previously set up @recovery_code Recovery code to check -recoverPassword recovery_code:string = PasswordState; +//@description Checks whether a 2-step verification password recovery code sent to an email address is valid @recovery_code Recovery code to check +checkPasswordRecoveryCode recovery_code:string = Ok; + +//@description Recovers the 2-step verification password using a recovery code sent to an email address that was previously set up +//@recovery_code Recovery code to check @new_password New password of the user; may be empty to remove the password @new_hint New password hint; may be empty +recoverPassword recovery_code:string new_password:string new_hint:string = PasswordState; + +//@description Removes 2-step verification password without previous password and access to recovery email address. The password can't be reset immediately and the request needs to be repeated after the specified time +resetPassword = ResetPasswordResult; + +//@description Cancels reset of 2-step verification password. The method can be called if passwordState.pending_reset_date > 0 +cancelPasswordReset = Ok; -//@description Creates a new temporary password for processing payments @password Persistent user password @valid_for Time during which the temporary password will be valid, in seconds; should be between 60 and 86400 +//@description Creates a new temporary password for processing payments @password Persistent user password @valid_for Time during which the temporary password will be valid, in seconds; must be between 60 and 86400 createTemporaryPassword password:string valid_for:int32 = TemporaryPasswordState; //@description Returns information about the current temporary password @@ -3565,22 +4112,22 @@ getTemporaryPasswordState = TemporaryPasswordState; getMe = User; //@description Returns information about a user by their identifier. This is an offline request if the current user is not a bot @user_id User identifier -getUser user_id:int32 = User; +getUser user_id:int53 = User; //@description Returns full information about a user by their identifier @user_id User identifier -getUserFullInfo user_id:int32 = UserFullInfo; +getUserFullInfo user_id:int53 = UserFullInfo; //@description Returns information about a basic group by its identifier. This is an offline request if the current user is not a bot @basic_group_id Basic group identifier -getBasicGroup basic_group_id:int32 = BasicGroup; +getBasicGroup basic_group_id:int53 = BasicGroup; //@description Returns full information about a basic group by its identifier @basic_group_id Basic group identifier -getBasicGroupFullInfo basic_group_id:int32 = BasicGroupFullInfo; +getBasicGroupFullInfo basic_group_id:int53 = BasicGroupFullInfo; //@description Returns information about a supergroup or a channel by its identifier. This is an offline request if the current user is not a bot @supergroup_id Supergroup or channel identifier -getSupergroup supergroup_id:int32 = Supergroup; +getSupergroup supergroup_id:int53 = Supergroup; //@description Returns full information about a supergroup or a channel by its identifier, cached for up to 1 minute @supergroup_id Supergroup or channel identifier -getSupergroupFullInfo supergroup_id:int32 = SupergroupFullInfo; +getSupergroupFullInfo supergroup_id:int53 = SupergroupFullInfo; //@description Returns information about a secret chat by its identifier. This is an offline request @secret_chat_id Secret chat identifier getSecretChat secret_chat_id:int32 = SecretChat; @@ -3595,7 +4142,7 @@ getMessage chat_id:int53 message_id:int53 = Message; getMessageLocally chat_id:int53 message_id:int53 = Message; //@description Returns information about a message that is replied by a given message. Also returns the pinned message, the game message, and the invoice message for messages of the types messagePinMessage, messageGameScore, and messagePaymentSuccessful respectively -//@chat_id Identifier of the chat the message belongs to @message_id Identifier of the message reply to which to get +//@chat_id Identifier of the chat the message belongs to @message_id Identifier of the reply message getRepliedMessage chat_id:int53 message_id:int53 = Message; //@description Returns information about a newest pinned message in the chat @chat_id Identifier of the chat the message belongs to @@ -3610,34 +4157,40 @@ getMessages chat_id:int53 message_ids:vector = Messages; //@description Returns information about a message thread. Can be used only if message.can_get_message_thread == true @chat_id Chat identifier @message_id Identifier of the message getMessageThread chat_id:int53 message_id:int53 = MessageThreadInfo; +//@description Returns viewers of a recent outgoing message in a basic group or a supergroup chat. For video notes and voice notes only users, opened content of the message, are returned. The method can be called if message.can_get_viewers == true @chat_id Chat identifier @message_id Identifier of the message +getMessageViewers chat_id:int53 message_id:int53 = Users; + //@description Returns information about a file; this is an offline request @file_id Identifier of the file to get getFile file_id:int32 = File; //@description Returns information about a file by its remote ID; this is an offline request. Can be used to register a URL as a file for further uploading, or sending as a message. Even the request succeeds, the file can be used only if it is still accessible to the user. //-For example, if the file is from a message, then the message must be not deleted and accessible to the user. If the file database is disabled, then the corresponding object with the file must be preloaded by the application -//@remote_file_id Remote identifier of the file to get @file_type File type, if known +//@remote_file_id Remote identifier of the file to get @file_type File type; pass null if unknown getRemoteFile remote_file_id:string file_type:FileType = File; -//@description Returns an ordered list of chats in a chat list. Chats are sorted by the pair (chat.position.order, chat.id) in descending order. (For example, to get a list of chats from the beginning, the offset_order should be equal to a biggest signed 64-bit number 9223372036854775807 == 2^63 - 1). -//-For optimal performance the number of returned chats is chosen by the library -//@chat_list The chat list in which to return chats -//@offset_order Chat order to return chats from @offset_chat_id Chat identifier to return chats from -//@limit The maximum number of chats to be returned. It is possible that fewer chats than the limit are returned even if the end of the list is not reached -getChats chat_list:ChatList offset_order:int64 offset_chat_id:int53 limit:int32 = Chats; +//@description Loads more chats from a chat list. The loaded chats and their positions in the chat list will be sent through updates. Chats are sorted by the pair (chat.position.order, chat.id) in descending order. Returns a 404 error if all chats have been loaded +//@chat_list The chat list in which to load chats; pass null to load chats from the main chat list +//@limit The maximum number of chats to be loaded. For optimal performance, the number of loaded chats is chosen by TDLib and can be smaller than the specified limit, even if the end of the list is not reached +loadChats chat_list:ChatList limit:int32 = Ok; + +//@description Returns an ordered list of chats from the beginning of a chat list. For informational purposes only. Use loadChats and updates processing instead to maintain chat lists in a consistent state +//@chat_list The chat list in which to return chats; pass null to get chats from the main chat list @limit The maximum number of chats to be returned +getChats chat_list:ChatList limit:int32 = Chats; //@description Searches a public chat by its username. Currently only private chats, supergroups and channels can be public. Returns the chat if found; otherwise an error is returned @username Username to be resolved searchPublicChat username:string = Chat; -//@description Searches public chats by looking for specified query in their username and title. Currently only private chats, supergroups and channels can be public. Returns a meaningful number of results. Returns nothing if the length of the searched username prefix is less than 5. Excludes private chats with contacts and chats from the chat list from the results @query Query to search for +//@description Searches public chats by looking for specified query in their username and title. Currently only private chats, supergroups and channels can be public. Returns a meaningful number of results. +//-Excludes private chats with contacts and chats from the chat list from the results @query Query to search for searchPublicChats query:string = Chats; -//@description Searches for the specified query in the title and username of already known chats, this is an offline request. Returns chats in the order seen in the main chat list @query Query to search for. If the query is empty, returns up to 20 recently found chats @limit The maximum number of chats to be returned +//@description Searches for the specified query in the title and username of already known chats, this is an offline request. Returns chats in the order seen in the main chat list @query Query to search for. If the query is empty, returns up to 50 recently found chats @limit The maximum number of chats to be returned searchChats query:string limit:int32 = Chats; //@description Searches for the specified query in the title and username of already known chats via request to the server. Returns chats in the order seen in the main chat list @query Query to search for @limit The maximum number of chats to be returned searchChatsOnServer query:string limit:int32 = Chats; -//@description Returns a list of users and location-based supergroups nearby. The list of users nearby will be updated for 60 seconds after the request by the updates updateUsersNearby. The request should be sent again every 25 seconds with adjusted location to not miss new chats @location Current user location +//@description Returns a list of users and location-based supergroups nearby. The list of users nearby will be updated for 60 seconds after the request by the updates updateUsersNearby. The request must be sent again every 25 seconds with adjusted location to not miss new chats @location Current user location searchChatsNearby location:location = ChatsNearby; //@description Returns a list of frequently used chats. Supported only if the chat info database is enabled @category Category of chats to be returned @limit The maximum number of chats to be returned; up to 30 @@ -3655,7 +4208,10 @@ removeRecentlyFoundChat chat_id:int53 = Ok; //@description Clears the list of recently found chats clearRecentlyFoundChats = Ok; -//@description Checks whether a username can be set for a chat @chat_id Chat identifier; should be identifier of a supergroup chat, or a channel chat, or a private chat with self, or zero if chat is being created @username Username to be checked +//@description Returns recently opened chats, this is an offline request. Returns chats in the order of last opening @limit The maximum number of chats to be returned +getRecentlyOpenedChats limit:int32 = Chats; + +//@description Checks whether a username can be set for a chat @chat_id Chat identifier; must be identifier of a supergroup chat, or a channel chat, or a private chat with self, or zero if the chat is being created @username Username to be checked checkChatUsername chat_id:int53 username:string = CheckChatUsernameResult; //@description Returns a list of public chats of the specified type, owned by the user @type Type of the public chats to return @@ -3672,91 +4228,117 @@ getInactiveSupergroupChats = Chats; //@description Returns a list of common group chats with a given user. Chats are sorted by their type and creation date @user_id User identifier @offset_chat_id Chat identifier starting from which to return chats; use 0 for the first request @limit The maximum number of chats to be returned; up to 100 -getGroupsInCommon user_id:int32 offset_chat_id:int53 limit:int32 = Chats; +getGroupsInCommon user_id:int53 offset_chat_id:int53 limit:int32 = Chats; //@description Returns messages in a chat. The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id). -//-For optimal performance the number of returned messages is chosen by the library. This is an offline request if only_local is true +//-For optimal performance, the number of returned messages is chosen by TDLib. This is an offline request if only_local is true //@chat_id Chat identifier //@from_message_id Identifier of the message starting from which history must be fetched; use 0 to get results from the last message //@offset Specify 0 to get results from exactly the from_message_id or a negative offset up to 99 to get additionally some newer messages -//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. If the offset is negative, the limit must be greater than or equal to -offset. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached +//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. If the offset is negative, the limit must be greater than or equal to -offset. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit //@only_local If true, returns only messages that are available locally without sending network requests getChatHistory chat_id:int53 from_message_id:int53 offset:int32 limit:int32 only_local:Bool = Messages; //@description Returns messages in a message thread of a message. Can be used only if message.can_get_message_thread == true. Message thread of a channel message is in the channel's linked supergroup. -//-The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id). For optimal performance the number of returned messages is chosen by the library +//-The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id). For optimal performance, the number of returned messages is chosen by TDLib //@chat_id Chat identifier //@message_id Message identifier, which thread history needs to be returned //@from_message_id Identifier of the message starting from which history must be fetched; use 0 to get results from the last message //@offset Specify 0 to get results from exactly the from_message_id or a negative offset up to 99 to get additionally some newer messages -//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. If the offset is negative, the limit must be greater than or equal to -offset. Fewer messages may be returned than specified by the limit, even if the end of the message thread history has not been reached +//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. If the offset is negative, the limit must be greater than or equal to -offset. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit getMessageThreadHistory chat_id:int53 message_id:int53 from_message_id:int53 offset:int32 limit:int32 = Messages; -//@description Deletes all messages in the chat. Use Chat.can_be_deleted_only_for_self and Chat.can_be_deleted_for_all_users fields to find whether and how the method can be applied to the chat -//@chat_id Chat identifier @remove_from_chat_list Pass true if the chat should be removed from the chat list @revoke Pass true to try to delete chat history for all users +//@description Deletes all messages in the chat. Use chat.can_be_deleted_only_for_self and chat.can_be_deleted_for_all_users fields to find whether and how the method can be applied to the chat +//@chat_id Chat identifier @remove_from_chat_list Pass true if the chat needs to be removed from the chat list @revoke Pass true to try to delete chat history for all users deleteChatHistory chat_id:int53 remove_from_chat_list:Bool revoke:Bool = Ok; +//@description Deletes a chat along with all messages in the corresponding chat for all chat members; requires owner privileges. For group chats this will release the username and remove all members. Chats with more than 1000 members can't be deleted using this method @chat_id Chat identifier +deleteChat chat_id:int53 = Ok; + //@description Searches for messages with given words in the chat. Returns the results in reverse chronological order, i.e. in order of decreasing message_id. Cannot be used in secret chats with a non-empty query -//-(searchSecretMessages should be used instead), or without an enabled message database. For optimal performance the number of returned messages is chosen by the library +//-(searchSecretMessages must be used instead), or without an enabled message database. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit //@chat_id Identifier of the chat in which to search messages //@query Query to search for -//@sender If not null, only messages sent by the specified sender will be returned. Not supported in secret chats +//@sender Sender of messages to search for; pass null to search for messages from any sender. Not supported in secret chats //@from_message_id Identifier of the message starting from which history must be fetched; use 0 to get results from the last message //@offset Specify 0 to get results from exactly the from_message_id or a negative offset to get the specified message and some newer messages -//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. If the offset is negative, the limit must be greater than -offset. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached -//@filter Filter for message content in the search results +//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. If the offset is negative, the limit must be greater than -offset. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit +//@filter Additional filter for messages to search; pass null to search for all messages //@message_thread_id If not 0, only messages in the specified thread will be returned; supergroups only searchChatMessages chat_id:int53 query:string sender:MessageSender from_message_id:int53 offset:int32 limit:int32 filter:SearchMessagesFilter message_thread_id:int53 = Messages; //@description Searches for messages in all chats except secret chats. Returns the results in reverse chronological order (i.e., in order of decreasing (date, chat_id, message_id)). -//-For optimal performance the number of returned messages is chosen by the library -//@chat_list Chat list in which to search messages; pass null to search in all chats regardless of their chat list +//-For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit +//@chat_list Chat list in which to search messages; pass null to search in all chats regardless of their chat list. Only Main and Archive chat lists are supported //@query Query to search for -//@offset_date The date of the message starting from which the results should be fetched. Use 0 or any date in the future to get results from the last message +//@offset_date The date of the message starting from which the results need to be fetched. Use 0 or any date in the future to get results from the last message //@offset_chat_id The chat identifier of the last found message, or 0 for the first request //@offset_message_id The message identifier of the last found message, or 0 for the first request -//@limit The maximum number of messages to be returned; up to 100. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached -//@filter Filter for message content in the search results; searchMessagesFilterCall, searchMessagesFilterMissedCall, searchMessagesFilterMention, searchMessagesFilterUnreadMention, searchMessagesFilterFailedToSend and searchMessagesFilterPinned are unsupported in this function +//@limit The maximum number of messages to be returned; up to 100. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit +//@filter Additional filter for messages to search; pass null to search for all messages. Filters searchMessagesFilterCall, searchMessagesFilterMissedCall, searchMessagesFilterMention, searchMessagesFilterUnreadMention, searchMessagesFilterFailedToSend and searchMessagesFilterPinned are unsupported in this function //@min_date If not 0, the minimum date of the messages to return //@max_date If not 0, the maximum date of the messages to return searchMessages chat_list:ChatList query:string offset_date:int32 offset_chat_id:int53 offset_message_id:int53 limit:int32 filter:SearchMessagesFilter min_date:int32 max_date:int32 = Messages; -//@description Searches for messages in secret chats. Returns the results in reverse chronological order. For optimal performance the number of returned messages is chosen by the library +//@description Searches for messages in secret chats. Returns the results in reverse chronological order. For optimal performance, the number of returned messages is chosen by TDLib //@chat_id Identifier of the chat in which to search. Specify 0 to search in all secret chats -//@query Query to search for. If empty, searchChatMessages should be used instead +//@query Query to search for. If empty, searchChatMessages must be used instead //@offset Offset of the first entry to return as received from the previous request; use empty string to get first chunk of results -//@limit The maximum number of messages to be returned; up to 100. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached -//@filter A filter for message content in the search results +//@limit The maximum number of messages to be returned; up to 100. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit +//@filter Additional filter for messages to search; pass null to search for all messages searchSecretMessages chat_id:int53 query:string offset:string limit:int32 filter:SearchMessagesFilter = FoundMessages; -//@description Searches for call messages. Returns the results in reverse chronological order (i. e., in order of decreasing message_id). For optimal performance the number of returned messages is chosen by the library +//@description Searches for call messages. Returns the results in reverse chronological order (i. e., in order of decreasing message_id). For optimal performance, the number of returned messages is chosen by TDLib //@from_message_id Identifier of the message from which to search; use 0 to get results from the last message -//@limit The maximum number of messages to be returned; up to 100. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached @only_missed If true, returns only messages with missed calls +//@limit The maximum number of messages to be returned; up to 100. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit @only_missed If true, returns only messages with missed calls searchCallMessages from_message_id:int53 limit:int32 only_missed:Bool = Messages; +//@description Deletes all call messages @revoke Pass true to delete the messages for all users +deleteAllCallMessages revoke:Bool = Ok; + //@description Returns information about the recent locations of chat members that were sent to the chat. Returns up to 1 location message per user @chat_id Chat identifier @limit The maximum number of messages to be returned searchChatRecentLocationMessages chat_id:int53 limit:int32 = Messages; -//@description Returns all active live locations that should be updated by the application. The list is persistent across application restarts only if the message database is used +//@description Returns all active live locations that need to be updated by the application. The list is persistent across application restarts only if the message database is used getActiveLiveLocationMessages = Messages; //@description Returns the last message sent in a chat no later than the specified date @chat_id Chat identifier @date Point in time (Unix timestamp) relative to which to search for messages getChatMessageByDate chat_id:int53 date:int32 = Message; +//@description Returns sparse positions of messages of the specified type in the chat to be used for shared media scroll implementation. Returns the results in reverse chronological order (i.e., in order of decreasing message_id). +//-Cannot be used in secret chats or with searchMessagesFilterFailedToSend filter without an enabled message database +//@chat_id Identifier of the chat in which to return information about message positions +//@filter Filter for message content. Filters searchMessagesFilterEmpty, searchMessagesFilterCall, searchMessagesFilterMissedCall, searchMessagesFilterMention and searchMessagesFilterUnreadMention are unsupported in this function +//@from_message_id The message identifier from which to return information about message positions +//@limit The expected number of message positions to be returned; 50-2000. A smaller number of positions can be returned, if there are not enough appropriate messages +getChatSparseMessagePositions chat_id:int53 filter:SearchMessagesFilter from_message_id:int53 limit:int32 = MessagePositions; + +//@description Returns information about the next messages of the specified type in the chat splitted by days. Returns the results in reverse chronological order. Can return partial result for the last returned day. Behavior of this method depends on the value of the option "utc_time_offset" +//@chat_id Identifier of the chat in which to return information about messages +//@filter Filter for message content. Filters searchMessagesFilterEmpty, searchMessagesFilterCall, searchMessagesFilterMissedCall, searchMessagesFilterMention and searchMessagesFilterUnreadMention are unsupported in this function +//@from_message_id The message identifier from which to return information about messages; use 0 to get results from the last message +getChatMessageCalendar chat_id:int53 filter:SearchMessagesFilter from_message_id:int53 = MessageCalendar; + //@description Returns approximate number of messages of the specified type in the chat @chat_id Identifier of the chat in which to count messages @filter Filter for message content; searchMessagesFilterEmpty is unsupported in this function @return_local If true, returns count that is available locally without sending network requests, returning -1 if the number of messages is unknown getChatMessageCount chat_id:int53 filter:SearchMessagesFilter return_local:Bool = Count; //@description Returns all scheduled messages in a chat. The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id) @chat_id Chat identifier getChatScheduledMessages chat_id:int53 = Messages; -//@description Returns forwarded copies of a channel message to different public channels. For optimal performance the number of returned messages is chosen by the library +//@description Returns forwarded copies of a channel message to different public channels. For optimal performance, the number of returned messages is chosen by TDLib //@chat_id Chat identifier of the message //@message_id Message identifier //@offset Offset of the first entry to return as received from the previous request; use empty string to get first chunk of results -//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. Fewer messages may be returned than specified by the limit, even if the end of the list has not been reached +//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit getMessagePublicForwards chat_id:int53 message_id:int53 offset:string limit:int32 = FoundMessages; +//@description Returns sponsored messages to be shown in a chat; for channel chats only @chat_id Identifier of the chat +getChatSponsoredMessages chat_id:int53 = SponsoredMessages; + +//@description Informs TDLib that a sponsored message was viewed by the user @chat_id Identifier of the chat with the sponsored message @sponsored_message_id The identifier of the sponsored message being viewed +viewSponsoredMessage chat_id:int53 sponsored_message_id:int32 = Ok; + //@description Removes an active notification from notification list. Needs to be called only if the notification is removed by the current user @notification_group_id Identifier of notification group to which the notification belongs @notification_id Identifier of removed notification removeNotification notification_group_id:int32 notification_id:int32 = Ok; @@ -3765,12 +4347,13 @@ removeNotification notification_group_id:int32 notification_id:int32 = Ok; removeNotificationGroup notification_group_id:int32 max_notification_id:int32 = Ok; -//@description Returns an HTTPS link to a message in a chat. Available only for already sent messages in supergroups and channels. This is an offline request +//@description Returns an HTTPS link to a message in a chat. Available only for already sent messages in supergroups and channels, or if message.can_get_media_timestamp_links and a media timestamp link is generated. This is an offline request //@chat_id Identifier of the chat to which the message belongs //@message_id Identifier of the message +//@media_timestamp If not 0, timestamp from which the video/audio/video note/voice note playing must start, in seconds. The media can be in the message content or in its web page preview //@for_album Pass true to create a link for the whole media album //@for_comment Pass true to create a link to the message as a channel post comment, or from a message thread -getMessageLink chat_id:int53 message_id:int53 for_album:Bool for_comment:Bool = MessageLink; +getMessageLink chat_id:int53 message_id:int53 media_timestamp:int32 for_album:Bool for_comment:Bool = MessageLink; //@description Returns an HTML code for embedding the message. Available only for messages in supergroups and channels with a username //@chat_id Identifier of the chat to which the message belongs @@ -3778,7 +4361,7 @@ getMessageLink chat_id:int53 message_id:int53 for_album:Bool for_comment:Bool = //@for_album Pass true to return an HTML code for embedding of the whole media album getMessageEmbeddingCode chat_id:int53 message_id:int53 for_album:Bool = Text; -//@description Returns information about a public or private message link @url The message link in the format "https://t.me/c/...", or "tg://privatepost?...", or "https://t.me/username/...", or "tg://resolve?..." +//@description Returns information about a public or private message link. Can be called for any internal link of the type internalLinkTypeMessage @url The message link getMessageLinkInfo url:string = MessageLinkInfo; @@ -3786,52 +4369,54 @@ getMessageLinkInfo url:string = MessageLinkInfo; //@chat_id Target chat //@message_thread_id If not 0, a message thread identifier in which the message will be sent //@reply_to_message_id Identifier of the message to reply to or 0 -//@options Options to be used to send the message -//@reply_markup Markup for replying to the message; for bots only @input_message_content The content of the message to be sent +//@options Options to be used to send the message; pass null to use default options +//@reply_markup Markup for replying to the message; pass null if none; for bots only +//@input_message_content The content of the message to be sent sendMessage chat_id:int53 message_thread_id:int53 reply_to_message_id:int53 options:messageSendOptions reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message; -//@description Sends messages grouped together into an album. Currently only audio, document, photo and video messages can be grouped into an album. Documents and audio files can be only grouped in an album with messages of the same type. Returns sent messages +//@description Sends 2-10 messages grouped together into an album. Currently only audio, document, photo and video messages can be grouped into an album. Documents and audio files can be only grouped in an album with messages of the same type. Returns sent messages //@chat_id Target chat //@message_thread_id If not 0, a message thread identifier in which the messages will be sent //@reply_to_message_id Identifier of a message to reply to or 0 -//@options Options to be used to send the messages -//@input_message_contents Contents of messages to be sent +//@options Options to be used to send the messages; pass null to use default options +//@input_message_contents Contents of messages to be sent. At most 10 messages can be added to an album sendMessageAlbum chat_id:int53 message_thread_id:int53 reply_to_message_id:int53 options:messageSendOptions input_message_contents:vector = Messages; //@description Invites a bot to a chat (if it is not yet a member) and sends it the /start command. Bots can't be invited to a private chat other than the chat with the bot. Bots can't be invited to channels (although they can be added as admins) and secret chats. Returns the sent message //@bot_user_id Identifier of the bot @chat_id Identifier of the target chat @parameter A hidden parameter sent to the bot for deep linking purposes (https://core.telegram.org/bots#deep-linking) -sendBotStartMessage bot_user_id:int32 chat_id:int53 parameter:string = Message; +sendBotStartMessage bot_user_id:int53 chat_id:int53 parameter:string = Message; //@description Sends the result of an inline query as a message. Returns the sent message. Always clears a chat draft message //@chat_id Target chat //@message_thread_id If not 0, a message thread identifier in which the message will be sent //@reply_to_message_id Identifier of a message to reply to or 0 -//@options Options to be used to send the message -//@query_id Identifier of the inline query @result_id Identifier of the inline result +//@options Options to be used to send the message; pass null to use default options +//@query_id Identifier of the inline query +//@result_id Identifier of the inline result //@hide_via_bot If true, there will be no mention of a bot, via which the message is sent. Can be used only for bots GetOption("animation_search_bot_username"), GetOption("photo_search_bot_username") and GetOption("venue_search_bot_username") sendInlineQueryResultMessage chat_id:int53 message_thread_id:int53 reply_to_message_id:int53 options:messageSendOptions query_id:int64 result_id:string hide_via_bot:Bool = Message; //@description Forwards previously sent messages. Returns the forwarded messages in the same order as the message identifiers passed in message_ids. If a message can't be forwarded, null will be returned instead of the message -//@chat_id Identifier of the chat to which to forward messages @from_chat_id Identifier of the chat from which to forward messages @message_ids Identifiers of the messages to forward. Message identifiers must be in a strictly increasing order -//@options Options to be used to send the messages -//@send_copy True, if content of the messages needs to be copied without links to the original messages. Always true if the messages are forwarded to a secret chat -//@remove_caption True, if media caption of message copies needs to be removed. Ignored if send_copy is false -forwardMessages chat_id:int53 from_chat_id:int53 message_ids:vector options:messageSendOptions send_copy:Bool remove_caption:Bool = Messages; +//@chat_id Identifier of the chat to which to forward messages +//@from_chat_id Identifier of the chat from which to forward messages +//@message_ids Identifiers of the messages to forward. Message identifiers must be in a strictly increasing order. At most 100 messages can be forwarded simultaneously +//@options Options to be used to send the messages; pass null to use default options +//@send_copy If true, content of the messages will be copied without reference to the original sender. Always true if the messages are forwarded to a secret chat or are local +//@remove_caption If true, media caption of message copies will be removed. Ignored if send_copy is false +//@only_preview If true, messages will not be forwarded and instead fake messages will be returned +forwardMessages chat_id:int53 from_chat_id:int53 message_ids:vector options:messageSendOptions send_copy:Bool remove_caption:Bool only_preview:Bool = Messages; //@description Resends messages which failed to send. Can be called only for messages for which messageSendingStateFailed.can_retry is true and after specified in messageSendingStateFailed.retry_after time passed. //-If a message is re-sent, the corresponding failed to send message is deleted. Returns the sent messages in the same order as the message identifiers passed in message_ids. If a message can't be re-sent, null will be returned instead of the message //@chat_id Identifier of the chat to send messages @message_ids Identifiers of the messages to resend. Message identifiers must be in a strictly increasing order resendMessages chat_id:int53 message_ids:vector = Messages; -//@description Changes the current TTL setting (sets a new self-destruct timer) in a secret chat and sends the corresponding message @chat_id Chat identifier @ttl New TTL value, in seconds -sendChatSetTtlMessage chat_id:int53 ttl:int32 = Message; - //@description Sends a notification about a screenshot taken in a chat. Supported only in private and secret chats @chat_id Chat identifier sendChatScreenshotTakenNotification chat_id:int53 = Ok; //@description Adds a local message to a chat. The message is persistent across application restarts only if the message database is used. Returns the added message //@chat_id Target chat -//@sender The sender sender of the message +//@sender The sender of the message //@reply_to_message_id Identifier of the message to reply to or 0 //@disable_notification Pass true to disable notification for the message //@input_message_content The content of the message to be added @@ -3841,51 +4426,85 @@ addLocalMessage chat_id:int53 sender:MessageSender reply_to_message_id:int53 dis deleteMessages chat_id:int53 message_ids:vector revoke:Bool = Ok; //@description Deletes all messages sent by the specified user to a chat. Supported only for supergroups; requires can_delete_messages administrator privileges @chat_id Chat identifier @user_id User identifier -deleteChatMessagesFromUser chat_id:int53 user_id:int32 = Ok; +deleteChatMessagesFromUser chat_id:int53 user_id:int53 = Ok; + +//@description Deletes all messages between the specified dates in a chat. Supported only for private chats and basic groups. Messages sent in the last 30 seconds will not be deleted +//@chat_id Chat identifier @min_date The minimum date of the messages to delete @max_date The maximum date of the messages to delete @revoke Pass true to try to delete chat messages for all users; private chats only +deleteChatMessagesByDate chat_id:int53 min_date:int32 max_date:int32 revoke:Bool = Ok; //@description Edits the text of a message (or a text of a game message). Returns the edited message after the edit is completed on the server side -//@chat_id The chat the message belongs to @message_id Identifier of the message @reply_markup The new message reply markup; for bots only @input_message_content New text content of the message. Should be of type InputMessageText +//@chat_id The chat the message belongs to +//@message_id Identifier of the message +//@reply_markup The new message reply markup; pass null if none; for bots only +//@input_message_content New text content of the message. Must be of type inputMessageText editMessageText chat_id:int53 message_id:int53 reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message; //@description Edits the message content of a live location. Messages can be edited for a limited period of time specified in the live location. Returns the edited message after the edit is completed on the server side -//@chat_id The chat the message belongs to @message_id Identifier of the message @reply_markup The new message reply markup; for bots only @location New location content of the message; may be null. Pass null to stop sharing the live location +//@chat_id The chat the message belongs to +//@message_id Identifier of the message +//@reply_markup The new message reply markup; pass null if none; for bots only +//@location New location content of the message; pass null to stop sharing the live location //@heading The new direction in which the location moves, in degrees; 1-360. Pass 0 if unknown //@proximity_alert_radius The new maximum distance for proximity alerts, in meters (0-100000). Pass 0 if the notification is disabled editMessageLiveLocation chat_id:int53 message_id:int53 reply_markup:ReplyMarkup location:location heading:int32 proximity_alert_radius:int32 = Message; -//@description Edits the content of a message with an animation, an audio, a document, a photo or a video. The media in the message can't be replaced if the message was set to self-destruct. Media can't be replaced by self-destructing media. Media in an album can be edited only to contain a photo or a video. Returns the edited message after the edit is completed on the server side -//@chat_id The chat the message belongs to @message_id Identifier of the message @reply_markup The new message reply markup; for bots only @input_message_content New content of the message. Must be one of the following types: InputMessageAnimation, InputMessageAudio, InputMessageDocument, InputMessagePhoto or InputMessageVideo +//@description Edits the content of a message with an animation, an audio, a document, a photo or a video, including message caption. If only the caption needs to be edited, use editMessageCaption instead. +//-The media can't be edited if the message was set to self-destruct or to a self-destructing media. The type of message content in an album can't be changed with exception of replacing a photo with a video or vice versa. Returns the edited message after the edit is completed on the server side +//@chat_id The chat the message belongs to +//@message_id Identifier of the message +//@reply_markup The new message reply markup; pass null if none; for bots only +//@input_message_content New content of the message. Must be one of the following types: inputMessageAnimation, inputMessageAudio, inputMessageDocument, inputMessagePhoto or inputMessageVideo editMessageMedia chat_id:int53 message_id:int53 reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message; //@description Edits the message content caption. Returns the edited message after the edit is completed on the server side -//@chat_id The chat the message belongs to @message_id Identifier of the message @reply_markup The new message reply markup; for bots only @caption New message content caption; 0-GetOption("message_caption_length_max") characters +//@chat_id The chat the message belongs to +//@message_id Identifier of the message +//@reply_markup The new message reply markup; pass null if none; for bots only +//@caption New message content caption; 0-GetOption("message_caption_length_max") characters; pass null to remove caption editMessageCaption chat_id:int53 message_id:int53 reply_markup:ReplyMarkup caption:formattedText = Message; //@description Edits the message reply markup; for bots only. Returns the edited message after the edit is completed on the server side -//@chat_id The chat the message belongs to @message_id Identifier of the message @reply_markup The new message reply markup +//@chat_id The chat the message belongs to +//@message_id Identifier of the message +//@reply_markup The new message reply markup; pass null if none editMessageReplyMarkup chat_id:int53 message_id:int53 reply_markup:ReplyMarkup = Message; -//@description Edits the text of an inline text or game message sent via a bot; for bots only @inline_message_id Inline message identifier @reply_markup The new message reply markup @input_message_content New text content of the message. Should be of type InputMessageText +//@description Edits the text of an inline text or game message sent via a bot; for bots only +//@inline_message_id Inline message identifier +//@reply_markup The new message reply markup; pass null if none +//@input_message_content New text content of the message. Must be of type inputMessageText editInlineMessageText inline_message_id:string reply_markup:ReplyMarkup input_message_content:InputMessageContent = Ok; -//@description Edits the content of a live location in an inline message sent via a bot; for bots only @inline_message_id Inline message identifier @reply_markup The new message reply markup -//@location New location content of the message; may be null. Pass null to stop sharing the live location +//@description Edits the content of a live location in an inline message sent via a bot; for bots only +//@inline_message_id Inline message identifier +//@reply_markup The new message reply markup; pass null if none +//@location New location content of the message; pass null to stop sharing the live location //@heading The new direction in which the location moves, in degrees; 1-360. Pass 0 if unknown //@proximity_alert_radius The new maximum distance for proximity alerts, in meters (0-100000). Pass 0 if the notification is disabled editInlineMessageLiveLocation inline_message_id:string reply_markup:ReplyMarkup location:location heading:int32 proximity_alert_radius:int32 = Ok; -//@description Edits the content of a message with an animation, an audio, a document, a photo or a video in an inline message sent via a bot; for bots only @inline_message_id Inline message identifier -//@reply_markup The new message reply markup; for bots only @input_message_content New content of the message. Must be one of the following types: InputMessageAnimation, InputMessageAudio, InputMessageDocument, InputMessagePhoto or InputMessageVideo +//@description Edits the content of a message with an animation, an audio, a document, a photo or a video in an inline message sent via a bot; for bots only +//@inline_message_id Inline message identifier +//@reply_markup The new message reply markup; pass null if none; for bots only +//@input_message_content New content of the message. Must be one of the following types: inputMessageAnimation, inputMessageAudio, inputMessageDocument, inputMessagePhoto or inputMessageVideo editInlineMessageMedia inline_message_id:string reply_markup:ReplyMarkup input_message_content:InputMessageContent = Ok; -//@description Edits the caption of an inline message sent via a bot; for bots only @inline_message_id Inline message identifier @reply_markup The new message reply markup @caption New message content caption; 0-GetOption("message_caption_length_max") characters +//@description Edits the caption of an inline message sent via a bot; for bots only +//@inline_message_id Inline message identifier +//@reply_markup The new message reply markup; pass null if none +//@caption New message content caption; pass null to remove caption; 0-GetOption("message_caption_length_max") characters editInlineMessageCaption inline_message_id:string reply_markup:ReplyMarkup caption:formattedText = Ok; -//@description Edits the reply markup of an inline message sent via a bot; for bots only @inline_message_id Inline message identifier @reply_markup The new message reply markup +//@description Edits the reply markup of an inline message sent via a bot; for bots only +//@inline_message_id Inline message identifier +//@reply_markup The new message reply markup; pass null if none editInlineMessageReplyMarkup inline_message_id:string reply_markup:ReplyMarkup = Ok; -//@description Edits the time when a scheduled message will be sent. Scheduling state of all messages in the same album or forwarded together with the message will be also changed @chat_id The chat the message belongs to @message_id Identifier of the message @scheduling_state The new message scheduling state. Pass null to send the message immediately +//@description Edits the time when a scheduled message will be sent. Scheduling state of all messages in the same album or forwarded together with the message will be also changed +//@chat_id The chat the message belongs to +//@message_id Identifier of the message +//@scheduling_state The new message scheduling state; pass null to send the message immediately editMessageSchedulingState chat_id:int53 message_id:int53 scheduling_state:MessageSchedulingState = Ok; @@ -3927,15 +4546,17 @@ getJsonString json_value:JsonValue = Text; //@option_ids 0-based identifiers of answer options, chosen by the user. User can choose more than 1 answer option only is the poll allows multiple answers setPollAnswer chat_id:int53 message_id:int53 option_ids:vector = Ok; -//@description Returns users voted for the specified option in a non-anonymous polls. For the optimal performance the number of returned users is chosen by the library +//@description Returns users voted for the specified option in a non-anonymous polls. For optimal performance, the number of returned users is chosen by TDLib //@chat_id Identifier of the chat to which the poll belongs @message_id Identifier of the message containing the poll //@option_id 0-based identifier of the answer option //@offset Number of users to skip in the result; must be non-negative -//@limit The maximum number of users to be returned; must be positive and can't be greater than 50. Fewer users may be returned than specified by the limit, even if the end of the voter list has not been reached +//@limit The maximum number of users to be returned; must be positive and can't be greater than 50. For optimal performance, the number of returned users is chosen by TDLib and can be smaller than the specified limit, even if the end of the voter list has not been reached getPollVoters chat_id:int53 message_id:int53 option_id:int32 offset:int32 limit:int32 = Users; //@description Stops a poll. A poll in a message can be stopped when the message has can_be_edited flag set -//@chat_id Identifier of the chat to which the poll belongs @message_id Identifier of the message containing the poll @reply_markup The new message reply markup; for bots only +//@chat_id Identifier of the chat to which the poll belongs +//@message_id Identifier of the message containing the poll +//@reply_markup The new message reply markup; pass null if none; for bots only stopPoll chat_id:int53 message_id:int53 reply_markup:ReplyMarkup = Ok; @@ -3945,29 +4566,38 @@ hideSuggestedAction action:SuggestedAction = Ok; //@description Returns information about a button of type inlineKeyboardButtonTypeLoginUrl. The method needs to be called when the user presses the button //@chat_id Chat identifier of the message with the button @message_id Message identifier of the message with the button @button_id Button identifier -getLoginUrlInfo chat_id:int53 message_id:int53 button_id:int32 = LoginUrlInfo; +getLoginUrlInfo chat_id:int53 message_id:int53 button_id:int53 = LoginUrlInfo; //@description Returns an HTTP URL which can be used to automatically authorize the user on a website after clicking an inline button of type inlineKeyboardButtonTypeLoginUrl. //-Use the method getLoginUrlInfo to find whether a prior user confirmation is needed. If an error is returned, then the button must be handled as an ordinary URL button //@chat_id Chat identifier of the message with the button @message_id Message identifier of the message with the button @button_id Button identifier //@allow_write_access True, if the user allowed the bot to send them messages -getLoginUrl chat_id:int53 message_id:int53 button_id:int32 allow_write_access:Bool = HttpUrl; - - -//@description Sends an inline query to a bot and returns its results. Returns an error with code 502 if the bot fails to answer the query before the query timeout expires @bot_user_id The identifier of the target bot -//@chat_id Identifier of the chat where the query was sent @user_location Location of the user, only if needed @query Text of the query @offset Offset of the first entry to return -getInlineQueryResults bot_user_id:int32 chat_id:int53 user_location:location query:string offset:string = InlineQueryResults; - -//@description Sets the result of an inline query; for bots only @inline_query_id Identifier of the inline query @is_personal True, if the result of the query can be cached for the specified user -//@results The results of the query @cache_time Allowed time to cache the results of the query, in seconds @next_offset Offset for the next inline query; pass an empty string if there are no more results -//@switch_pm_text If non-empty, this text should be shown on the button that opens a private chat with the bot and sends a start message to the bot with the parameter switch_pm_parameter @switch_pm_parameter The parameter for the bot start message +getLoginUrl chat_id:int53 message_id:int53 button_id:int53 allow_write_access:Bool = HttpUrl; + + +//@description Sends an inline query to a bot and returns its results. Returns an error with code 502 if the bot fails to answer the query before the query timeout expires +//@bot_user_id The identifier of the target bot +//@chat_id Identifier of the chat where the query was sent +//@user_location Location of the user; pass null if unknown or the bot doesn't need user's location +//@query Text of the query +//@offset Offset of the first entry to return +getInlineQueryResults bot_user_id:int53 chat_id:int53 user_location:location query:string offset:string = InlineQueryResults; + +//@description Sets the result of an inline query; for bots only +//@inline_query_id Identifier of the inline query +//@is_personal True, if the result of the query can be cached for the specified user +//@results The results of the query +//@cache_time Allowed time to cache the results of the query, in seconds +//@next_offset Offset for the next inline query; pass an empty string if there are no more results +//@switch_pm_text If non-empty, this text must be shown on the button that opens a private chat with the bot and sends a start message to the bot with the parameter switch_pm_parameter +//@switch_pm_parameter The parameter for the bot start message answerInlineQuery inline_query_id:int64 is_personal:Bool results:vector cache_time:int32 next_offset:string switch_pm_text:string switch_pm_parameter:string = Ok; //@description Sends a callback query to a bot and returns an answer. Returns an error with code 502 if the bot fails to answer the query before the query timeout expires @chat_id Identifier of the chat with the message @message_id Identifier of the message from which the query originated @payload Query payload getCallbackQueryAnswer chat_id:int53 message_id:int53 payload:CallbackQueryPayload = CallbackQueryAnswer; -//@description Sets the result of a callback query; for bots only @callback_query_id Identifier of the callback query @text Text of the answer @show_alert If true, an alert should be shown to the user instead of a toast notification @url URL to be opened @cache_time Time during which the result of the query can be cached, in seconds +//@description Sets the result of a callback query; for bots only @callback_query_id Identifier of the callback query @text Text of the answer @show_alert If true, an alert must be shown to the user instead of a toast notification @url URL to be opened @cache_time Time during which the result of the query can be cached, in seconds answerCallbackQuery callback_query_id:int64 text:string show_alert:Bool url:string cache_time:int32 = Ok; @@ -3978,27 +4608,28 @@ answerShippingQuery shipping_query_id:int64 shipping_options:vector force_read:Bool = Ok; //@description Informs TDLib that the message content has been opened (e.g., the user has opened a photo, video, document, location or venue, or has listened to an audio file or voice note message). An updateMessageContentOpened update will be generated if something has changed @chat_id Chat identifier of the message @message_id Identifier of the message with the opened content openMessageContent chat_id:int53 message_id:int53 = Ok; +//@description Informs TDLib that a message with an animated emoji was clicked by the user. Returns a big animated sticker to be played or a 404 error if usual animation needs to be played @chat_id Chat identifier of the message @message_id Identifier of the clicked message +clickAnimatedEmojiMessage chat_id:int53 message_id:int53 = Sticker; + +//@description Returns information about the type of an internal link. Returns a 404 error if the link is not internal. Can be called before authorization @link The link +getInternalLinkType link:string = InternalLinkType; + +//@description Returns information about an action to be done when the current user clicks an external link. Don't use this method for links from secret chats if web page preview is disabled in secret chats @link The link +getExternalLinkInfo link:string = LoginUrlInfo; + +//@description Returns an HTTP URL which can be used to automatically authorize the current user on a website after clicking an HTTP link. Use the method getExternalLinkInfo to find whether a prior user confirmation is needed +//@link The HTTP link @allow_write_access True, if the current user allowed the bot, returned in getExternalLinkInfo, to send them messages +getExternalLink link:string allow_write_access:Bool = HttpUrl; + //@description Marks all mentions in a chat as read @chat_id Chat identifier readAllChatMentions chat_id:int53 = Ok; //@description Returns an existing chat corresponding to a given user @user_id User identifier @force If true, the chat will be created without network request. In this case all information about the chat except its type, title and photo can be incorrect -createPrivateChat user_id:int32 force:Bool = Chat; +createPrivateChat user_id:int53 force:Bool = Chat; //@description Returns an existing chat corresponding to a known basic group @basic_group_id Basic group identifier @force If true, the chat will be created without network request. In this case all information about the chat except its type, title and photo can be incorrect -createBasicGroupChat basic_group_id:int32 force:Bool = Chat; +createBasicGroupChat basic_group_id:int53 force:Bool = Chat; //@description Returns an existing chat corresponding to a known supergroup or channel @supergroup_id Supergroup or channel identifier @force If true, the chat will be created without network request. In this case all information about the chat except its type, title and photo can be incorrect -createSupergroupChat supergroup_id:int32 force:Bool = Chat; +createSupergroupChat supergroup_id:int53 force:Bool = Chat; //@description Returns an existing chat corresponding to a known secret chat @secret_chat_id Secret chat identifier createSecretChat secret_chat_id:int32 = Chat; //@description Creates a new basic group and sends a corresponding messageBasicGroupChatCreate. Returns the newly created chat @user_ids Identifiers of users to be added to the basic group @title Title of the new basic group; 1-128 characters -createNewBasicGroupChat user_ids:vector title:string = Chat; +createNewBasicGroupChat user_ids:vector title:string = Chat; -//@description Creates a new supergroup or channel and sends a corresponding messageSupergroupChatCreate. Returns the newly created chat @title Title of the new chat; 1-128 characters @is_channel True, if a channel chat should be created @param_description Chat description; 0-255 characters @location Chat location if a location-based supergroup is being created -createNewSupergroupChat title:string is_channel:Bool description:string location:chatLocation = Chat; +//@description Creates a new supergroup or channel and sends a corresponding messageSupergroupChatCreate. Returns the newly created chat +//@title Title of the new chat; 1-128 characters +//@is_channel True, if a channel chat needs to be created +//@param_description Chat description; 0-255 characters +//@location Chat location if a location-based supergroup is being created; pass null to create an ordinary supergroup chat +//@for_import True, if the supergroup is created for importing messages using importMessage +createNewSupergroupChat title:string is_channel:Bool description:string location:chatLocation for_import:Bool = Chat; //@description Creates a new secret chat. Returns the newly created chat @user_id Identifier of the target user -createNewSecretChat user_id:int32 = Chat; +createNewSecretChat user_id:int53 = Chat; //@description Creates a new supergroup from an existing basic group and sends a corresponding messageChatUpgradeTo and messageChatUpgradeFrom; requires creator privileges. Deactivates the original basic group @chat_id Identifier of the chat to upgrade upgradeBasicGroupChatToSupergroupChat chat_id:int53 = Chat; @@ -4077,19 +4726,27 @@ getRecommendedChatFilters = RecommendedChatFilters; getChatFilterDefaultIconName filter:chatFilter = Text; -//@description Changes the chat title. Supported only for basic groups, supergroups and channels. Requires can_change_info rights +//@description Changes the chat title. Supported only for basic groups, supergroups and channels. Requires can_change_info administrator right //@chat_id Chat identifier @title New title of the chat; 1-128 characters setChatTitle chat_id:int53 title:string = Ok; -//@description Changes the photo of a chat. Supported only for basic groups, supergroups and channels. Requires can_change_info rights -//@chat_id Chat identifier @photo New chat photo. Pass null to delete the chat photo +//@description Changes the photo of a chat. Supported only for basic groups, supergroups and channels. Requires can_change_info administrator right +//@chat_id Chat identifier @photo New chat photo; pass null to delete the chat photo setChatPhoto chat_id:int53 photo:InputChatPhoto = Ok; +//@description Changes the message TTL setting (sets a new self-destruct timer) in a chat. Requires can_delete_messages administrator right in basic groups, supergroups and channels +//-Message TTL setting of a chat with the current user (Saved Messages) and the chat 777000 (Telegram) can't be changed +//@chat_id Chat identifier @ttl New TTL value, in seconds; must be one of 0, 86400, 7 * 86400, or 31 * 86400 unless the chat is secret +setChatMessageTtlSetting chat_id:int53 ttl:int32 = Ok; + //@description Changes the chat members permissions. Supported only for basic groups and supergroups. Requires can_restrict_members administrator right //@chat_id Chat identifier @permissions New non-administrator members permissions in the chat setChatPermissions chat_id:int53 permissions:chatPermissions = Ok; -//@description Changes the draft message in a chat @chat_id Chat identifier @message_thread_id If not 0, a message thread identifier in which the draft was changed @draft_message New draft message; may be null +//@description Changes the chat theme. Supported only in private and secret chats @chat_id Chat identifier @theme_name Name of the new chat theme; pass an empty string to return the default theme +setChatTheme chat_id:int53 theme_name:string = Ok; + +//@description Changes the draft message in a chat @chat_id Chat identifier @message_thread_id If not 0, a message thread identifier in which the draft was changed @draft_message New draft message; pass null to remove the draft setChatDraftMessage chat_id:int53 message_thread_id:int53 draft_message:draftMessage = Ok; //@description Changes the notification settings of a chat. Notification settings of a chat with the current user (Saved Messages) can't be changed @@ -4105,23 +4762,23 @@ toggleChatDefaultDisableNotification chat_id:int53 default_disable_notification: //@description Changes application-specific data associated with a chat @chat_id Chat identifier @client_data New value of client_data setChatClientData chat_id:int53 client_data:string = Ok; -//@description Changes information about a chat. Available for basic groups, supergroups, and channels. Requires can_change_info rights @chat_id Identifier of the chat @param_description New chat description; 0-255 characters +//@description Changes information about a chat. Available for basic groups, supergroups, and channels. Requires can_change_info administrator right @chat_id Identifier of the chat @param_description New chat description; 0-255 characters setChatDescription chat_id:int53 description:string = Ok; -//@description Changes the discussion group of a channel chat; requires can_change_info rights in the channel if it is specified @chat_id Identifier of the channel chat. Pass 0 to remove a link from the supergroup passed in the second argument to a linked channel chat (requires can_pin_messages rights in the supergroup) @discussion_chat_id Identifier of a new channel's discussion group. Use 0 to remove the discussion group. +//@description Changes the discussion group of a channel chat; requires can_change_info administrator right in the channel if it is specified @chat_id Identifier of the channel chat. Pass 0 to remove a link from the supergroup passed in the second argument to a linked channel chat (requires can_pin_messages rights in the supergroup) @discussion_chat_id Identifier of a new channel's discussion group. Use 0 to remove the discussion group. //-Use the method getSuitableDiscussionChats to find all suitable groups. Basic group chats must be first upgraded to supergroup chats. If new chat members don't have access to old messages in the supergroup, then toggleSupergroupIsAllHistoryAvailable must be used first to change that setChatDiscussionGroup chat_id:int53 discussion_chat_id:int53 = Ok; //@description Changes the location of a chat. Available only for some location-based supergroups, use supergroupFullInfo.can_set_location to check whether the method is allowed to use @chat_id Chat identifier @location New location for the chat; must be valid and not null setChatLocation chat_id:int53 location:chatLocation = Ok; -//@description Changes the slow mode delay of a chat. Available only for supergroups; requires can_restrict_members rights @chat_id Chat identifier @slow_mode_delay New slow mode delay for the chat; must be one of 0, 10, 30, 60, 300, 900, 3600 +//@description Changes the slow mode delay of a chat. Available only for supergroups; requires can_restrict_members rights @chat_id Chat identifier @slow_mode_delay New slow mode delay for the chat, in seconds; must be one of 0, 10, 30, 60, 300, 900, 3600 setChatSlowModeDelay chat_id:int53 slow_mode_delay:int32 = Ok; //@description Pins a message in a chat; requires can_pin_messages rights or can_edit_messages rights in the channel //@chat_id Identifier of the chat //@message_id Identifier of the new pinned message -//@disable_notification True, if there should be no notification about the pinned message. Notifications are always disabled in channels and private chats +//@disable_notification True, if there must be no notification about the pinned message. Notifications are always disabled in channels and private chats //@only_for_self True, if the message needs to be pinned for one side only; private chats only pinChatMessage chat_id:int53 message_id:int53 disable_notification:Bool only_for_self:Bool = Ok; @@ -4132,35 +4789,46 @@ unpinChatMessage chat_id:int53 message_id:int53 = Ok; unpinAllChatMessages chat_id:int53 = Ok; -//@description Adds current user as a new member to a chat. Private and secret chats can't be joined using this method @chat_id Chat identifier +//@description Adds the current user as a new member to a chat. Private and secret chats can't be joined using this method @chat_id Chat identifier joinChat chat_id:int53 = Ok; -//@description Removes current user from chat members. Private and secret chats can't be left using this method @chat_id Chat identifier +//@description Removes the current user from chat members. Private and secret chats can't be left using this method @chat_id Chat identifier leaveChat chat_id:int53 = Ok; -//@description Adds a new member to a chat. Members can't be added to private or secret chats. Members will not be added until the chat state has been synchronized with the server -//@chat_id Chat identifier @user_id Identifier of the user @forward_limit The number of earlier messages from the chat to be forwarded to the new member; up to 100. Ignored for supergroups and channels -addChatMember chat_id:int53 user_id:int32 forward_limit:int32 = Ok; +//@description Adds a new member to a chat. Members can't be added to private or secret chats +//@chat_id Chat identifier @user_id Identifier of the user @forward_limit The number of earlier messages from the chat to be forwarded to the new member; up to 100. Ignored for supergroups and channels, or if the added user is a bot +addChatMember chat_id:int53 user_id:int53 forward_limit:int32 = Ok; -//@description Adds multiple new members to a chat. Currently this option is only available for supergroups and channels. This option can't be used to join a chat. Members can't be added to a channel if it has more than 200 members. Members will not be added until the chat state has been synchronized with the server -//@chat_id Chat identifier @user_ids Identifiers of the users to be added to the chat -addChatMembers chat_id:int53 user_ids:vector = Ok; +//@description Adds multiple new members to a chat. Currently this method is only available for supergroups and channels. This method can't be used to join a chat. Members can't be added to a channel if it has more than 200 members +//@chat_id Chat identifier @user_ids Identifiers of the users to be added to the chat. The maximum number of added users is 20 for supergroups and 100 for channels +addChatMembers chat_id:int53 user_ids:vector = Ok; -//@description Changes the status of a chat member, needs appropriate privileges. This function is currently not suitable for adding new members to the chat and transferring chat ownership; instead, use addChatMember or transferChatOwnership. The chat member status will not be changed until it has been synchronized with the server -//@chat_id Chat identifier @user_id User identifier @status The new status of the member in the chat -setChatMemberStatus chat_id:int53 user_id:int32 status:ChatMemberStatus = Ok; +//@description Changes the status of a chat member, needs appropriate privileges. This function is currently not suitable for transferring chat ownership; use transferChatOwnership instead. Use addChatMember or banChatMember if some additional parameters needs to be passed +//@chat_id Chat identifier @member_id Member identifier. Chats can be only banned and unbanned in supergroups and channels @status The new status of the member in the chat +setChatMemberStatus chat_id:int53 member_id:MessageSender status:ChatMemberStatus = Ok; + +//@description Bans a member in a chat. Members can't be banned in private or secret chats. In supergroups and channels, the user will not be able to return to the group on their own using invite links, etc., unless unbanned first +//@chat_id Chat identifier +//@member_id Member identifier +//@banned_until_date Point in time (Unix timestamp) when the user will be unbanned; 0 if never. If the user is banned for more than 366 days or for less than 30 seconds from the current time, the user is considered to be banned forever. Ignored in basic groups +//@revoke_messages Pass true to delete all messages in the chat for the user that is being removed. Always true for supergroups and channels +banChatMember chat_id:int53 member_id:MessageSender banned_until_date:int32 revoke_messages:Bool = Ok; //@description Checks whether the current session can be used to transfer a chat ownership to another user canTransferOwnership = CanTransferOwnershipResult; //@description Changes the owner of a chat. The current user must be a current owner of the chat. Use the method canTransferOwnership to check whether the ownership can be transferred from the current session. Available only for supergroups and channel chats //@chat_id Chat identifier @user_id Identifier of the user to which transfer the ownership. The ownership can't be transferred to a bot or to a deleted user @password The password of the current user -transferChatOwnership chat_id:int53 user_id:int32 password:string = Ok; +transferChatOwnership chat_id:int53 user_id:int53 password:string = Ok; -//@description Returns information about a single member of a chat @chat_id Chat identifier @user_id User identifier -getChatMember chat_id:int53 user_id:int32 = ChatMember; +//@description Returns information about a single member of a chat @chat_id Chat identifier @member_id Member identifier +getChatMember chat_id:int53 member_id:MessageSender = ChatMember; -//@description Searches for a specified query in the first name, last name and username of the members of a specified chat. Requires administrator rights in channels @chat_id Chat identifier @query Query to search for @limit The maximum number of users to be returned @filter The type of users to return. By default, chatMembersFilterMembers +//@description Searches for a specified query in the first name, last name and username of the members of a specified chat. Requires administrator rights in channels +//@chat_id Chat identifier +//@query Query to search for +//@limit The maximum number of users to be returned; up to 200 +//@filter The type of users to search for; pass null to search among all chat members searchChatMembers chat_id:int53 query:string limit:int32 filter:ChatMembersFilter = ChatMembers; //@description Returns a list of administrators of the chat with their custom titles @chat_id Chat identifier @@ -4171,7 +4839,9 @@ getChatAdministrators chat_id:int53 = ChatAdministrators; clearAllDraftMessages exclude_secret_chats:Bool = Ok; -//@description Returns list of chats with non-default notification settings @scope If specified, only chats from the specified scope will be returned @compare_sound If true, also chats with non-default sound will be returned +//@description Returns list of chats with non-default notification settings +//@scope If specified, only chats from the scope will be returned; pass null to return chats from all scopes +//@compare_sound If true, also chats with non-default sound will be returned getChatNotificationSettingsExceptions scope:NotificationSettingsScope compare_sound:Bool = Chats; //@description Returns the notification settings for chats of a given type @scope Types of chats for which to return the notification settings information @@ -4195,19 +4865,24 @@ setPinnedChats chat_list:ChatList chat_ids:vector = Ok; //@description Downloads a file from the cloud. Download progress and completion of the download will be notified through updateFile updates //@file_id Identifier of the file to download //@priority Priority of the download (1-32). The higher the priority, the earlier the file will be downloaded. If the priorities of two files are equal, then the last one for which downloadFile was called will be downloaded first -//@offset The starting position from which the file should be downloaded -//@limit Number of bytes which should be downloaded starting from the "offset" position before the download will be automatically cancelled; use 0 to download without a limit +//@offset The starting position from which the file needs to be downloaded +//@limit Number of bytes which need to be downloaded starting from the "offset" position before the download will be automatically canceled; use 0 to download without a limit //@synchronous If false, this request returns file state just after the download has been started. If true, this request returns file state only after -//-the download has succeeded, has failed, has been cancelled or a new downloadFile request with different offset/limit parameters was sent +//-the download has succeeded, has failed, has been canceled or a new downloadFile request with different offset/limit parameters was sent downloadFile file_id:int32 priority:int32 offset:int32 limit:int32 synchronous:Bool = File; -//@description Returns file downloaded prefix size from a given offset @file_id Identifier of the file @offset Offset from which downloaded prefix size should be calculated +//@description Returns file downloaded prefix size from a given offset, in bytes @file_id Identifier of the file @offset Offset from which downloaded prefix size needs to be calculated getFileDownloadedPrefixSize file_id:int32 offset:int32 = Count; //@description Stops the downloading of a file. If a file has already been downloaded, does nothing @file_id Identifier of a file to stop downloading @only_if_pending Pass true to stop downloading only if it hasn't been started, i.e. request hasn't been sent to server cancelDownloadFile file_id:int32 only_if_pending:Bool = Ok; -//@description Asynchronously uploads a file to the cloud without sending it in a message. updateFile will be used to notify about upload progress and successful completion of the upload. The file will not have a persistent remote identifier until it will be sent in a message @file File to upload @file_type File type +//@description Returns suggested name for saving a file in a given directory @file_id Identifier of the file @directory Directory in which the file is supposed to be saved +getSuggestedFileName file_id:int32 directory:string = Text; + +//@description Asynchronously uploads a file to the cloud without sending it in a message. updateFile will be used to notify about upload progress and successful completion of the upload. The file will not have a persistent remote identifier until it will be sent in a message +//@file File to upload +//@file_type File type; pass null if unknown //@priority Priority of the upload (1-32). The higher the priority, the earlier the file will be uploaded. If the priorities of two files are equal, then the first one for which uploadFile was called will be uploaded first uploadFile file:InputFile file_type:FileType priority:int32 = File; @@ -4226,7 +4901,7 @@ setFileGenerationProgress generation_id:int64 expected_size:int32 local_prefix_s //@description Finishes the file generation //@generation_id The identifier of the generation process -//@error If set, means that file generation has failed and should be terminated +//@error If passed, the file generation has failed and must be terminated; pass null if the file generation succeeded finishFileGeneration generation_id:int64 error:error = Ok; //@description Reads a part of a file from the TDLib file cache and returns read bytes. This method is intended to be used only if the application has no direct access to TDLib's file system, because it is usually slower than a direct read from the file @@ -4239,21 +4914,100 @@ readFilePart file_id:int32 offset:int32 count:int32 = FilePart; deleteFile file_id:int32 = Ok; -//@description Generates a new invite link for a chat; the previously generated link is revoked. Available for basic groups, supergroups, and channels. Requires administrator privileges and can_invite_users right @chat_id Chat identifier -generateChatInviteLink chat_id:int53 = ChatInviteLink; +//@description Returns information about a file with messages exported from another app @message_file_head Beginning of the message file; up to 100 first lines +getMessageFileType message_file_head:string = MessageFileType; + +//@description Returns a confirmation text to be shown to the user before starting message import +//@chat_id Identifier of a chat to which the messages will be imported. It must be an identifier of a private chat with a mutual contact or an identifier of a supergroup chat with can_change_info administrator right +getMessageImportConfirmationText chat_id:int53 = Text; + +//@description Imports messages exported from another app +//@chat_id Identifier of a chat to which the messages will be imported. It must be an identifier of a private chat with a mutual contact or an identifier of a supergroup chat with can_change_info administrator right +//@message_file File with messages to import. Only inputFileLocal and inputFileGenerated are supported. The file must not be previously uploaded +//@attached_files Files used in the imported messages. Only inputFileLocal and inputFileGenerated are supported. The files must not be previously uploaded +importMessages chat_id:int53 message_file:InputFile attached_files:vector = Ok; + + +//@description Replaces current primary invite link for a chat with a new primary invite link. Available for basic groups, supergroups, and channels. Requires administrator privileges and can_invite_users right @chat_id Chat identifier +replacePrimaryChatInviteLink chat_id:int53 = ChatInviteLink; -//@description Checks the validity of an invite link for a chat and returns information about the corresponding chat @invite_link Invite link to be checked; should begin with "https://t.me/joinchat/", "https://telegram.me/joinchat/", or "https://telegram.dog/joinchat/" +//@description Creates a new invite link for a chat. Available for basic groups, supergroups, and channels. Requires administrator privileges and can_invite_users right in the chat +//@chat_id Chat identifier +//@name Invite link name; 0-32 characters +//@expire_date Point in time (Unix timestamp) when the link will expire; pass 0 if never +//@member_limit The maximum number of chat members that can join the chat by the link simultaneously; 0-99999; pass 0 if not limited +//@creates_join_request True, if the link only creates join request. If true, member_limit must not be specified +createChatInviteLink chat_id:int53 name:string expire_date:int32 member_limit:int32 creates_join_request:Bool = ChatInviteLink; + +//@description Edits a non-primary invite link for a chat. Available for basic groups, supergroups, and channels. Requires administrator privileges and can_invite_users right in the chat for own links and owner privileges for other links +//@chat_id Chat identifier +//@invite_link Invite link to be edited +//@name Invite link name; 0-32 characters +//@expire_date Point in time (Unix timestamp) when the link will expire; pass 0 if never +//@member_limit The maximum number of chat members that can join the chat by the link simultaneously; 0-99999; pass 0 if not limited +//@creates_join_request True, if the link only creates join request. If true, member_limit must not be specified +editChatInviteLink chat_id:int53 invite_link:string name:string expire_date:int32 member_limit:int32 creates_join_request:Bool = ChatInviteLink; + +//@description Returns information about an invite link. Requires administrator privileges and can_invite_users right in the chat to get own links and owner privileges to get other links +//@chat_id Chat identifier +//@invite_link Invite link to get +getChatInviteLink chat_id:int53 invite_link:string = ChatInviteLink; + +//@description Returns list of chat administrators with number of their invite links. Requires owner privileges in the chat @chat_id Chat identifier +getChatInviteLinkCounts chat_id:int53 = ChatInviteLinkCounts; + +//@description Returns invite links for a chat created by specified administrator. Requires administrator privileges and can_invite_users right in the chat to get own links and owner privileges to get other links +//@chat_id Chat identifier +//@creator_user_id User identifier of a chat administrator. Must be an identifier of the current user for non-owner +//@is_revoked Pass true if revoked links needs to be returned instead of active or expired +//@offset_date Creation date of an invite link starting after which to return invite links; use 0 to get results from the beginning +//@offset_invite_link Invite link starting after which to return invite links; use empty string to get results from the beginning +//@limit The maximum number of invite links to return; up to 100 +getChatInviteLinks chat_id:int53 creator_user_id:int53 is_revoked:Bool offset_date:int32 offset_invite_link:string limit:int32 = ChatInviteLinks; + +//@description Returns chat members joined a chat by an invite link. Requires administrator privileges and can_invite_users right in the chat for own links and owner privileges for other links @chat_id Chat identifier @invite_link Invite link for which to return chat members +//@offset_member A chat member from which to return next chat members; pass null to get results from the beginning @limit The maximum number of chat members to return; up to 100 +getChatInviteLinkMembers chat_id:int53 invite_link:string offset_member:chatInviteLinkMember limit:int32 = ChatInviteLinkMembers; + +//@description Revokes invite link for a chat. Available for basic groups, supergroups, and channels. Requires administrator privileges and can_invite_users right in the chat for own links and owner privileges for other links. +//-If a primary link is revoked, then additionally to the revoked link returns new primary link +//@chat_id Chat identifier +//@invite_link Invite link to be revoked +revokeChatInviteLink chat_id:int53 invite_link:string = ChatInviteLinks; + +//@description Deletes revoked chat invite links. Requires administrator privileges and can_invite_users right in the chat for own links and owner privileges for other links @chat_id Chat identifier @invite_link Invite link to revoke +deleteRevokedChatInviteLink chat_id:int53 invite_link:string = Ok; + +//@description Deletes all revoked chat invite links created by a given chat administrator. Requires administrator privileges and can_invite_users right in the chat for own links and owner privileges for other links +//@chat_id Chat identifier +//@creator_user_id User identifier of a chat administrator, which links will be deleted. Must be an identifier of the current user for non-owner +deleteAllRevokedChatInviteLinks chat_id:int53 creator_user_id:int53 = Ok; + +//@description Checks the validity of an invite link for a chat and returns information about the corresponding chat @invite_link Invite link to be checked checkChatInviteLink invite_link:string = ChatInviteLinkInfo; -//@description Uses an invite link to add the current user to the chat if possible. The new member will not be added until the chat state has been synchronized with the server -//@invite_link Invite link to import; should begin with "https://t.me/joinchat/", "https://telegram.me/joinchat/", or "https://telegram.dog/joinchat/" +//@description Uses an invite link to add the current user to the chat if possible @invite_link Invite link to use joinChatByInviteLink invite_link:string = Chat; +//@description Returns pending join requests in a chat +//@chat_id Chat identifier +//@invite_link Invite link for which to return join requests. If empty, all join requests will be returned. Requires administrator privileges and can_invite_users right in the chat for own links and owner privileges for other links +//@query A query to search for in the first names, last names and usernames of the users to return +//@offset_request A chat join request from which to return next requests; pass null to get results from the beginning +//@limit The maximum number of chat join requests to return +getChatJoinRequests chat_id:int53 invite_link:string query:string offset_request:chatJoinRequest limit:int32 = ChatJoinRequests; + +//@description Approves pending join request in a chat @chat_id Chat identifier @user_id Identifier of the user, which request will be approved +approveChatJoinRequest chat_id:int53 user_id:int53 = Ok; + +//@description Declines pending join request in a chat @chat_id Chat identifier @user_id Identifier of the user, which request will be declined +declineChatJoinRequest chat_id:int53 user_id:int53 = Ok; + -//@description Creates a new call @user_id Identifier of the user to be called @protocol Description of the call protocols supported by the application @is_video True, if a video call needs to be created -createCall user_id:int32 protocol:callProtocol is_video:Bool = CallId; +//@description Creates a new call @user_id Identifier of the user to be called @protocol The call protocols supported by the application @is_video True, if a video call needs to be created +createCall user_id:int53 protocol:callProtocol is_video:Bool = CallId; -//@description Accepts an incoming call @call_id Call identifier @protocol Description of the call protocols supported by the application +//@description Accepts an incoming call @call_id Call identifier @protocol The call protocols supported by the application acceptCall call_id:int32 protocol:callProtocol = Ok; //@description Sends call signaling data @call_id Call identifier @data The data @@ -4269,6 +5023,119 @@ sendCallRating call_id:int32 rating:int32 comment:string problems:vector = Ok; + +//@description Returns invite link to a video chat in a public chat +//@group_call_id Group call identifier +//@can_self_unmute Pass true if the invite link needs to contain an invite hash, passing which to joinGroupCall would allow the invited user to unmute themselves. Requires groupCall.can_be_managed group call flag +getGroupCallInviteLink group_call_id:int32 can_self_unmute:Bool = HttpUrl; + +//@description Starts recording of an active group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title Group call recording title; 0-64 characters +//@record_video Pass true to record a video file instead of an audio file @use_portrait_orientation Pass true to use portrait orientation for video instead of landscape one +startGroupCallRecording group_call_id:int32 title:string record_video:Bool use_portrait_orientation:Bool = Ok; + +//@description Ends recording of an active group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier +endGroupCallRecording group_call_id:int32 = Ok; + +//@description Toggles whether current user's video is paused @group_call_id Group call identifier @is_my_video_paused Pass true if the current user's video is paused +toggleGroupCallIsMyVideoPaused group_call_id:int32 is_my_video_paused:Bool = Ok; + +//@description Toggles whether current user's video is enabled @group_call_id Group call identifier @is_my_video_enabled Pass true if the current user's video is enabled +toggleGroupCallIsMyVideoEnabled group_call_id:int32 is_my_video_enabled:Bool = Ok; + +//@description Informs TDLib that speaking state of a participant of an active group has changed @group_call_id Group call identifier +//@audio_source Group call participant's synchronization audio source identifier, or 0 for the current user @is_speaking True, if the user is speaking +setGroupCallParticipantIsSpeaking group_call_id:int32 audio_source:int32 is_speaking:Bool = Ok; + +//@description Toggles whether a participant of an active group call is muted, unmuted, or allowed to unmute themselves +//@group_call_id Group call identifier @participant_id Participant identifier @is_muted Pass true if the user must be muted and false otherwise +toggleGroupCallParticipantIsMuted group_call_id:int32 participant_id:MessageSender is_muted:Bool = Ok; + +//@description Changes volume level of a participant of an active group call. If the current user can manage the group call, then the participant's volume level will be changed for all users with the default volume level +//@group_call_id Group call identifier @participant_id Participant identifier @volume_level New participant's volume level; 1-20000 in hundreds of percents +setGroupCallParticipantVolumeLevel group_call_id:int32 participant_id:MessageSender volume_level:int32 = Ok; + +//@description Toggles whether a group call participant hand is rased +//@group_call_id Group call identifier @participant_id Participant identifier +//@is_hand_raised Pass true if the user's hand needs to be raised. Only self hand can be raised. Requires groupCall.can_be_managed group call flag to lower other's hand +toggleGroupCallParticipantIsHandRaised group_call_id:int32 participant_id:MessageSender is_hand_raised:Bool = Ok; + +//@description Loads more participants of a group call. The loaded participants will be received through updates. Use the field groupCall.loaded_all_participants to check whether all participants have already been loaded +//@group_call_id Group call identifier. The group call must be previously received through getGroupCall and must be joined or being joined +//@limit The maximum number of participants to load; up to 100 +loadGroupCallParticipants group_call_id:int32 limit:int32 = Ok; + +//@description Leaves a group call @group_call_id Group call identifier +leaveGroupCall group_call_id:int32 = Ok; + +//@description Discards a group call. Requires groupCall.can_be_managed @group_call_id Group call identifier +discardGroupCall group_call_id:int32 = Ok; + +//@description Returns a file with a segment of a group call stream in a modified OGG format for audio or MPEG-4 format for video +//@group_call_id Group call identifier +//@time_offset Point in time when the stream segment begins; Unix timestamp in milliseconds +//@scale Segment duration scale; 0-1. Segment's duration is 1000/(2**scale) milliseconds +//@channel_id Identifier of an audio/video channel to get as received from tgcalls +//@video_quality Video quality as received from tgcalls; pass null to get the worst available quality +getGroupCallStreamSegment group_call_id:int32 time_offset:int53 scale:int32 channel_id:int32 video_quality:GroupCallVideoQuality = FilePart; + + //@description Changes the block state of a message sender. Currently, only users and supergroup chats can be blocked @sender Message Sender @is_blocked New value of is_blocked toggleMessageSenderIsBlocked sender:MessageSender is_blocked:Bool = Ok; @@ -4284,7 +5151,7 @@ getBlockedMessageSenders offset:int32 limit:int32 = MessageSenders; //@description Adds a user to the contact list or edits an existing contact by their user identifier @contact The contact to add or edit; phone number can be empty and needs to be specified only if known, vCard is ignored -//@share_phone_number True, if the new contact needs to be allowed to see current user's phone number. A corresponding rule to userPrivacySettingShowPhoneNumber will be added if needed. Use the field UserFullInfo.need_phone_number_privacy_exception to check whether the current user needs to be asked to share their phone number +//@share_phone_number True, if the new contact needs to be allowed to see current user's phone number. A corresponding rule to userPrivacySettingShowPhoneNumber will be added if needed. Use the field userFullInfo.need_phone_number_privacy_exception to check whether the current user needs to be asked to share their phone number addContact contact:contact share_phone_number:Bool = Ok; //@description Adds new contacts or edits existing contacts by their phone numbers; contacts' user identifiers are ignored @contacts The list of contacts to import or edit; contacts' vCard are ignored and are not imported @@ -4297,12 +5164,12 @@ getContacts = Users; searchContacts query:string limit:int32 = Users; //@description Removes users from the contact list @user_ids Identifiers of users to be deleted -removeContacts user_ids:vector = Ok; +removeContacts user_ids:vector = Ok; //@description Returns the total number of imported contacts getImportedContactCount = Count; -//@description Changes imported contacts using the list of current user contacts saved on the device. Imports newly added contacts and, if at least the file database is enabled, deletes recently deleted contacts. +//@description Changes imported contacts using the list of contacts saved on the device. Imports newly added contacts and, if at least the file database is enabled, deletes recently deleted contacts. //-Query result depends on the result of the previous query, so only one query is possible at the same time @contacts The new list of contacts, contact's vCard are ignored and are not imported changeImportedContacts contacts:vector = ImportedContacts; @@ -4311,14 +5178,14 @@ clearImportedContacts = Ok; //@description Shares the phone number of the current user with a mutual contact. Supposed to be called when the user clicks on chatActionBarSharePhoneNumber @user_id Identifier of the user with whom to share the phone number. The user must be a mutual contact -sharePhoneNumber user_id:int32 = Ok; +sharePhoneNumber user_id:int53 = Ok; //@description Returns the profile photos of a user. The result of this query may be outdated: some photos might have been deleted already @user_id User identifier @offset The number of photos to skip; must be non-negative @limit The maximum number of photos to be returned; up to 100 -getUserProfilePhotos user_id:int32 offset:int32 limit:int32 = ChatPhotos; +getUserProfilePhotos user_id:int53 offset:int32 limit:int32 = ChatPhotos; -//@description Returns stickers from the installed sticker sets that correspond to a given emoji. If the emoji is not empty, favorite and recently used stickers may also be returned @emoji String representation of emoji. If empty, returns all known installed stickers @limit The maximum number of stickers to be returned +//@description Returns stickers from the installed sticker sets that correspond to a given emoji. If the emoji is non-empty, favorite and recently used stickers may also be returned @emoji String representation of emoji. If empty, returns all known installed stickers @limit The maximum number of stickers to be returned getStickers emoji:string limit:int32 = Stickers; //@description Searches for stickers from public sticker sets that correspond to a given emoji @emoji String representation of emoji; must be non-empty @limit The maximum number of stickers to be returned @@ -4327,12 +5194,12 @@ searchStickers emoji:string limit:int32 = Stickers; //@description Returns a list of installed sticker sets @is_masks Pass true to return mask sticker sets; pass false to return ordinary sticker sets getInstalledStickerSets is_masks:Bool = StickerSets; -//@description Returns a list of archived sticker sets @is_masks Pass true to return mask stickers sets; pass false to return ordinary sticker sets @offset_sticker_set_id Identifier of the sticker set from which to return the result @limit The maximum number of sticker sets to return +//@description Returns a list of archived sticker sets @is_masks Pass true to return mask stickers sets; pass false to return ordinary sticker sets @offset_sticker_set_id Identifier of the sticker set from which to return the result @limit The maximum number of sticker sets to return; up to 100 getArchivedStickerSets is_masks:Bool offset_sticker_set_id:int64 limit:int32 = StickerSets; -//@description Returns a list of trending sticker sets. For the optimal performance the number of returned sticker sets is chosen by the library +//@description Returns a list of trending sticker sets. For optimal performance, the number of returned sticker sets is chosen by TDLib //@offset The offset from which to return the sticker sets; must be non-negative -//@limit The maximum number of sticker sets to be returned; must be non-negative. Fewer sticker sets may be returned than specified by the limit, even if the end of the list has not been reached +//@limit The maximum number of sticker sets to be returned; up to 100. For optimal performance, the number of returned sticker sets is chosen by TDLib and can be smaller than the specified limit, even if the end of the list has not been reached getTrendingStickerSets offset:int32 limit:int32 = StickerSets; //@description Returns a list of sticker sets attached to a file. Currently only photos and videos can have attached sticker sets @file_id File identifier @@ -4388,6 +5255,9 @@ getStickerEmojis sticker:InputFile = Emojis; //@description Searches for emojis by keywords. Supported only if the file database is enabled @text Text to search for @exact_match True, if only emojis, which exactly match text needs to be returned @input_language_codes List of possible IETF language tags of the user's input language; may be empty if unknown searchEmojis text:string exact_match:Bool input_language_codes:vector = Emojis; +//@description Returns an animated emoji corresponding to a given emoji. Returns a 404 error if the emoji has no animated emoji @emoji The emoji +getAnimatedEmoji emoji:string = AnimatedEmoji; + //@description Returns an HTTP URL which can be used to automatically log in to the translation platform and suggest new emoji replacements. The URL will be valid for 30 seconds after generation @language_code Language code for which the emoji replacements will be suggested getEmojiSuggestionsUrl language_code:string = HttpUrl; @@ -4396,7 +5266,7 @@ getEmojiSuggestionsUrl language_code:string = HttpUrl; getSavedAnimations = Animations; //@description Manually adds a new animation to the list of saved animations. The new animation is added to the beginning of the list. If the animation was already in the list, it is removed first. Only non-secret video animations with MIME type "video/mp4" can be added to the list -//@animation The animation file to be added. Only animations known to the server (i.e. successfully sent via a message) can be added to the list +//@animation The animation file to be added. Only animations known to the server (i.e., successfully sent via a message) can be added to the list addSavedAnimation animation:InputFile = Ok; //@description Removes an animation from the list of saved animations @animation Animation file to be removed @@ -4427,7 +5297,7 @@ setProfilePhoto photo:InputChatPhoto = Ok; //@description Deletes a profile photo @profile_photo_id Identifier of the profile photo to delete deleteProfilePhoto profile_photo_id:int64 = Ok; -//@description Changes the first and last name of the current user @first_name The new value of the first name for the user; 1-64 characters @last_name The new value of the optional last name for the user; 0-64 characters +//@description Changes the first and last name of the current user @first_name The new value of the first name for the current user; 1-64 characters @last_name The new value of the optional last name for the current user; 0-64 characters setName first_name:string last_name:string = Ok; //@description Changes the bio of the current user @bio The new value of the user bio; 0-70 characters without line feeds @@ -4440,17 +5310,31 @@ setUsername username:string = Ok; setLocation location:location = Ok; //@description Changes the phone number of the user and sends an authentication code to the user's new phone number. On success, returns information about the sent code -//@phone_number The new phone number of the user in international format @settings Settings for the authentication of the user's phone number +//@phone_number The new phone number of the user in international format @settings Settings for the authentication of the user's phone number; pass null to use default settings changePhoneNumber phone_number:string settings:phoneNumberAuthenticationSettings = AuthenticationCodeInfo; -//@description Re-sends the authentication code sent to confirm a new phone number for the user. Works only if the previously received authenticationCodeInfo next_code_type was not null +//@description Re-sends the authentication code sent to confirm a new phone number for the current user. Works only if the previously received authenticationCodeInfo next_code_type was not null and the server-specified timeout has passed resendChangePhoneNumberCode = AuthenticationCodeInfo; //@description Checks the authentication code sent to confirm a new phone number of the user @code Verification code received by SMS, phone call or flash call checkChangePhoneNumberCode code:string = Ok; -//@description Sets the list of commands supported by the bot; for bots only @commands List of the bot's commands -setCommands commands:vector = Ok; + +//@description Sets the list of commands supported by the bot for the given user scope and language; for bots only +//@scope The scope to which the commands are relevant; pass null to change commands in the default bot command scope +//@language_code A two-letter ISO 639-1 country code. If empty, the commands will be applied to all users from the given scope, for which language there are no dedicated commands +//@commands List of the bot's commands +setCommands scope:BotCommandScope language_code:string commands:vector = Ok; + +//@description Deletes commands supported by the bot for the given user scope and language; for bots only +//@scope The scope to which the commands are relevant; pass null to delete commands in the default bot command scope +//@language_code A two-letter ISO 639-1 country code or an empty string +deleteCommands scope:BotCommandScope language_code:string = Ok; + +//@description Returns the list of commands supported by the bot for the given user scope and language; for bots only +//@scope The scope to which the commands are relevant; pass null to get commands in the default bot command scope +//@language_code A two-letter ISO 639-1 country code or an empty string +getCommands scope:BotCommandScope language_code:string = BotCommands; //@description Returns all active sessions of the current user @@ -4474,26 +5358,26 @@ disconnectAllWebsites = Ok; //@description Changes the username of a supergroup or channel, requires owner privileges in the supergroup or channel @supergroup_id Identifier of the supergroup or channel @username New value of the username. Use an empty string to remove the username -setSupergroupUsername supergroup_id:int32 username:string = Ok; +setSupergroupUsername supergroup_id:int53 username:string = Ok; -//@description Changes the sticker set of a supergroup; requires can_change_info rights @supergroup_id Identifier of the supergroup @sticker_set_id New value of the supergroup sticker set identifier. Use 0 to remove the supergroup sticker set -setSupergroupStickerSet supergroup_id:int32 sticker_set_id:int64 = Ok; +//@description Changes the sticker set of a supergroup; requires can_change_info administrator right @supergroup_id Identifier of the supergroup @sticker_set_id New value of the supergroup sticker set identifier. Use 0 to remove the supergroup sticker set +setSupergroupStickerSet supergroup_id:int53 sticker_set_id:int64 = Ok; -//@description Toggles sender signatures messages sent in a channel; requires can_change_info rights @supergroup_id Identifier of the channel @sign_messages New value of sign_messages -toggleSupergroupSignMessages supergroup_id:int32 sign_messages:Bool = Ok; +//@description Toggles sender signatures messages sent in a channel; requires can_change_info administrator right @supergroup_id Identifier of the channel @sign_messages New value of sign_messages +toggleSupergroupSignMessages supergroup_id:int53 sign_messages:Bool = Ok; -//@description Toggles whether the message history of a supergroup is available to new members; requires can_change_info rights @supergroup_id The identifier of the supergroup @is_all_history_available The new value of is_all_history_available -toggleSupergroupIsAllHistoryAvailable supergroup_id:int32 is_all_history_available:Bool = Ok; +//@description Toggles whether the message history of a supergroup is available to new members; requires can_change_info administrator right @supergroup_id The identifier of the supergroup @is_all_history_available The new value of is_all_history_available +toggleSupergroupIsAllHistoryAvailable supergroup_id:int53 is_all_history_available:Bool = Ok; -//@description Reports some messages from a user in a supergroup as spam; requires administrator rights in the supergroup @supergroup_id Supergroup identifier @user_id User identifier @message_ids Identifiers of messages sent in the supergroup by the user. This list must be non-empty -reportSupergroupSpam supergroup_id:int32 user_id:int32 message_ids:vector = Ok; +//@description Upgrades supergroup to a broadcast group; requires owner privileges in the supergroup @supergroup_id Identifier of the supergroup +toggleSupergroupIsBroadcastGroup supergroup_id:int53 = Ok; -//@description Returns information about members or banned users in a supergroup or channel. Can be used only if SupergroupFullInfo.can_get_members == true; additionally, administrator privileges may be required for some filters @supergroup_id Identifier of the supergroup or channel -//@filter The type of users to return. By default, supergroupMembersFilterRecent @offset Number of users to skip @limit The maximum number of users be returned; up to 200 -getSupergroupMembers supergroup_id:int32 filter:SupergroupMembersFilter offset:int32 limit:int32 = ChatMembers; +//@description Reports some messages from a user in a supergroup as spam; requires administrator rights in the supergroup @supergroup_id Supergroup identifier @user_id User identifier @message_ids Identifiers of messages sent in the supergroup by the user. This list must be non-empty +reportSupergroupSpam supergroup_id:int53 user_id:int53 message_ids:vector = Ok; -//@description Deletes a supergroup or channel along with all messages in the corresponding chat. This will release the supergroup or channel username and remove all members; requires owner privileges in the supergroup or channel. Chats with more than 1000 members can't be deleted using this method @supergroup_id Identifier of the supergroup or channel -deleteSupergroup supergroup_id:int32 = Ok; +//@description Returns information about members or banned users in a supergroup or channel. Can be used only if supergroupFullInfo.can_get_members == true; additionally, administrator privileges may be required for some filters @supergroup_id Identifier of the supergroup or channel +//@filter The type of users to return; pass null to use supergroupMembersFilterRecent @offset Number of users to skip @limit The maximum number of users be returned; up to 200 +getSupergroupMembers supergroup_id:int53 filter:SupergroupMembersFilter offset:int32 limit:int32 = ChatMembers; //@description Closes a secret chat, effectively transferring its state to secretChatStateClosed @secret_chat_id Secret chat identifier @@ -4502,19 +5386,27 @@ closeSecretChat secret_chat_id:int32 = Ok; //@description Returns a list of service actions taken by chat members and administrators in the last 48 hours. Available only for supergroups and channels. Requires administrator rights. Returns results in reverse chronological order (i. e., in order of decreasing event_id) //@chat_id Chat identifier @query Search query by which to filter events @from_event_id Identifier of an event from which to return results. Use 0 to get results from the latest events @limit The maximum number of events to return; up to 100 -//@filters The types of events to return. By default, all types will be returned @user_ids User identifiers by which to filter events. By default, events relating to all users will be returned -getChatEventLog chat_id:int53 query:string from_event_id:int64 limit:int32 filters:chatEventLogFilters user_ids:vector = ChatEvents; +//@filters The types of events to return; pass null to get chat events of all types @user_ids User identifiers by which to filter events. By default, events relating to all users will be returned +getChatEventLog chat_id:int53 query:string from_event_id:int64 limit:int32 filters:chatEventLogFilters user_ids:vector = ChatEvents; -//@description Returns an invoice payment form. This method should be called when the user presses inlineKeyboardButtonBuy @chat_id Chat identifier of the Invoice message @message_id Message identifier -getPaymentForm chat_id:int53 message_id:int53 = PaymentForm; +//@description Returns an invoice payment form. This method must be called when the user presses inlineKeyboardButtonBuy +//@chat_id Chat identifier of the Invoice message +//@message_id Message identifier +//@theme Preferred payment form theme; pass null to use the default theme +getPaymentForm chat_id:int53 message_id:int53 theme:paymentFormTheme = PaymentForm; -//@description Validates the order information provided by a user and returns the available shipping options for a flexible invoice @chat_id Chat identifier of the Invoice message @message_id Message identifier @order_info The order information, provided by the user @allow_save True, if the order information can be saved +//@description Validates the order information provided by a user and returns the available shipping options for a flexible invoice +//@chat_id Chat identifier of the Invoice message +//@message_id Message identifier +//@order_info The order information, provided by the user; pass null if empty +//@allow_save True, if the order information can be saved validateOrderInfo chat_id:int53 message_id:int53 order_info:orderInfo allow_save:Bool = ValidatedOrderInfo; -//@description Sends a filled-out payment form to the bot for final verification @chat_id Chat identifier of the Invoice message @message_id Message identifier @order_info_id Identifier returned by ValidateOrderInfo, or an empty string @shipping_option_id Identifier of a chosen shipping option, if applicable -//@credentials The credentials chosen by user for payment -sendPaymentForm chat_id:int53 message_id:int53 order_info_id:string shipping_option_id:string credentials:InputCredentials = PaymentResult; +//@description Sends a filled-out payment form to the bot for final verification @chat_id Chat identifier of the Invoice message @message_id Message identifier +//@payment_form_id Payment form identifier returned by getPaymentForm @order_info_id Identifier returned by validateOrderInfo, or an empty string @shipping_option_id Identifier of a chosen shipping option, if applicable +//@credentials The credentials chosen by user for payment @tip_amount Chosen by the user amount of tip in the smallest units of the currency +sendPaymentForm chat_id:int53 message_id:int53 payment_form_id:int64 order_info_id:string shipping_option_id:string credentials:InputCredentials tip_amount:int53 = PaymentResult; //@description Returns information about a successful payment @chat_id Chat identifier of the PaymentSuccessful message @message_id Message identifier getPaymentReceipt chat_id:int53 message_id:int53 = PaymentReceipt; @@ -4543,8 +5435,8 @@ getBackgroundUrl name:string type:BackgroundType = HttpUrl; searchBackground name:string = Background; //@description Changes the background selected by the user; adds background to the list of installed backgrounds -//@background The input background to use, null for filled backgrounds -//@type Background type; null for default background. The method will return error 404 if type is null +//@background The input background to use; pass null to create a new filled backgrounds or to remove the current background +//@type Background type; pass null to use the default type of the remote background or to remove the current background //@for_dark_theme True, if the background is chosen for dark theme setBackground background:InputBackground type:BackgroundType for_dark_theme:Bool = Background; @@ -4564,7 +5456,7 @@ getLanguagePackInfo language_pack_id:string = LanguagePackInfo; //@description Returns strings from a language pack in the current localization target by their keys. Can be called before authorization @language_pack_id Language pack identifier of the strings to be returned @keys Language pack keys of the strings to be returned; leave empty to request all available strings getLanguagePackStrings language_pack_id:string keys:vector = LanguagePackStrings; -//@description Fetches the latest versions of all strings from a language pack in the current localization target from the server. This method shouldn't be called explicitly for the current used/base language packs. Can be called before authorization @language_pack_id Language pack identifier +//@description Fetches the latest versions of all strings from a language pack in the current localization target from the server. This method doesn't need to be called explicitly for the current used/base language packs. Can be called before authorization @language_pack_id Language pack identifier synchronizeLanguagePack language_pack_id:string = Ok; //@description Adds a custom server language pack to the list of installed language packs in current localization target. Can be called before authorization @language_pack_id Identifier of a language pack to be added; may be different from a name that is used in an "https://t.me/setlanguage/" link @@ -4584,7 +5476,7 @@ deleteLanguagePack language_pack_id:string = Ok; //@description Registers the currently used device for receiving push notifications. Returns a globally unique identifier of the push notification subscription @device_token Device token @other_user_ids List of user identifiers of other users currently using the application -registerDevice device_token:DeviceToken other_user_ids:vector = PushReceiverId; +registerDevice device_token:DeviceToken other_user_ids:vector = PushReceiverId; //@description Handles a push notification. Returns error with code 406 if the push notification is not supported and connection to the server is required to fetch new data. Can be called before authorization //@payload JSON-encoded push notification payload with all fields sent by the server, and "google.sent_time" and "google.notification.sound" fields added @@ -4610,7 +5502,7 @@ getUserPrivacySettingRules setting:UserPrivacySetting = UserPrivacySettingRules; getOption name:string = OptionValue; //@description Sets the value of an option. (Check the list of available options on https://core.telegram.org/tdlib/options.) Only writable options can be set. Can be called before authorization -//@name The name of the option @value The new value of the option +//@name The name of the option @value The new value of the option; pass null to reset option value to a default value setOption name:string value:OptionValue = Ok; @@ -4627,24 +5519,25 @@ deleteAccount reason:string = Ok; //@description Removes a chat action bar without any other action @chat_id Chat identifier removeChatActionBar chat_id:int53 = Ok; -//@description Reports a chat to the Telegram moderators. A chat can be reported only from the chat action bar, or if this is a private chats with a bot, a private chat with a user sharing their location, a supergroup, or a channel, since other chats can't be checked by moderators @chat_id Chat identifier @reason The reason for reporting the chat @message_ids Identifiers of reported messages, if any -reportChat chat_id:int53 reason:ChatReportReason message_ids:vector = Ok; +//@description Reports a chat to the Telegram moderators. A chat can be reported only from the chat action bar, or if this is a private chat with a bot, a private chat with a user sharing their location, a supergroup, or a channel, since other chats can't be checked by moderators +//@chat_id Chat identifier @message_ids Identifiers of reported messages, if any @reason The reason for reporting the chat @text Additional report details; 0-1024 characters +reportChat chat_id:int53 message_ids:vector reason:ChatReportReason text:string = Ok; +//@description Reports a chat photo to the Telegram moderators. A chat photo can be reported only if this is a private chat with a bot, a private chat with a user sharing their location, a supergroup, or a channel, since other chats can't be checked by moderators +//@chat_id Chat identifier @file_id Identifier of the photo to report. Only full photos from chatPhoto can be reported @reason The reason for reporting the chat photo @text Additional report details; 0-1024 characters +reportChatPhoto chat_id:int53 file_id:int32 reason:ChatReportReason text:string = Ok; -//@description Returns an HTTP URL with the chat statistics. Currently this method of getting the statistics are disabled and can be deleted in the future @chat_id Chat identifier @parameters Parameters from "tg://statsrefresh?params=******" link @is_dark Pass true if a URL with the dark theme must be returned -getChatStatisticsUrl chat_id:int53 parameters:string is_dark:Bool = HttpUrl; - -//@description Returns detailed statistics about a chat. Currently this method can be used only for supergroups and channels. Can be used only if SupergroupFullInfo.can_get_statistics == true @chat_id Chat identifier @is_dark Pass true if a dark theme is used by the application +//@description Returns detailed statistics about a chat. Currently this method can be used only for supergroups and channels. Can be used only if supergroupFullInfo.can_get_statistics == true @chat_id Chat identifier @is_dark Pass true if a dark theme is used by the application getChatStatistics chat_id:int53 is_dark:Bool = ChatStatistics; -//@description Returns detailed statistics about a message. Can be used only if Message.can_get_statistics == true @chat_id Chat identifier @message_id Message identifier @is_dark Pass true if a dark theme is used by the application +//@description Returns detailed statistics about a message. Can be used only if message.can_get_statistics == true @chat_id Chat identifier @message_id Message identifier @is_dark Pass true if a dark theme is used by the application getMessageStatistics chat_id:int53 message_id:int53 is_dark:Bool = MessageStatistics; //@description Loads an asynchronous or a zoomed in statistical graph @chat_id Chat identifier @token The token for graph loading @x X-value for zoomed in graph or 0 otherwise getStatisticalGraph chat_id:int53 token:string x:int53 = StatisticalGraph; -//@description Returns storage usage statistics. Can be called before authorization @chat_limit The maximum number of chats with the largest storage usage for which separate statistics should be returned. All other chats will be grouped in entries with chat_id == 0. If the chat info database is not used, the chat_limit is ignored and is always set to 0 +//@description Returns storage usage statistics. Can be called before authorization @chat_limit The maximum number of chats with the largest storage usage for which separate statistics need to be returned. All other chats will be grouped in entries with chat_id == 0. If the chat info database is not used, the chat_limit is ignored and is always set to 0 getStorageStatistics chat_limit:int32 = StorageStatistics; //@description Quickly returns approximate storage usage statistics. Can be called before authorization @@ -4654,20 +5547,20 @@ getStorageStatisticsFast = StorageStatisticsFast; getDatabaseStatistics = DatabaseStatistics; //@description Optimizes storage usage, i.e. deletes some files and returns new storage usage statistics. Secret thumbnails can't be deleted -//@size Limit on the total size of files after deletion. Pass -1 to use the default limit +//@size Limit on the total size of files after deletion, in bytes. Pass -1 to use the default limit //@ttl Limit on the time that has passed since the last time a file was accessed (or creation time for some filesystems). Pass -1 to use the default limit //@count Limit on the total count of files after deletion. Pass -1 to use the default limit //@immunity_delay The amount of time after the creation of a file during which it can't be deleted, in seconds. Pass -1 to use the default value -//@file_types If not empty, only files with the given type(s) are considered. By default, all types except thumbnails, profile photos, stickers and wallpapers are deleted -//@chat_ids If not empty, only files from the given chats are considered. Use 0 as chat identifier to delete files not belonging to any chat (e.g., profile photos) -//@exclude_chat_ids If not empty, files from the given chats are excluded. Use 0 as chat identifier to exclude all files not belonging to any chat (e.g., profile photos) +//@file_types If non-empty, only files with the given types are considered. By default, all types except thumbnails, profile photos, stickers and wallpapers are deleted +//@chat_ids If non-empty, only files from the given chats are considered. Use 0 as chat identifier to delete files not belonging to any chat (e.g., profile photos) +//@exclude_chat_ids If non-empty, files from the given chats are excluded. Use 0 as chat identifier to exclude all files not belonging to any chat (e.g., profile photos) //@return_deleted_file_statistics Pass true if statistics about the files that were deleted must be returned instead of the whole storage usage statistics. Affects only returned statistics //@chat_limit Same as in getStorageStatistics. Affects only returned statistics optimizeStorage size:int53 ttl:int32 count:int32 immunity_delay:int32 file_types:vector chat_ids:vector exclude_chat_ids:vector return_deleted_file_statistics:Bool chat_limit:int32 = StorageStatistics; -//@description Sets the current network type. Can be called before authorization. Calling this method forces all network connections to reopen, mitigating the delay in switching between different networks, so it should be called whenever the network is changed, even if the network type remains the same. -//-Network type is used to check whether the library can use the network at all and also for collecting detailed network data usage statistics @type The new network type. By default, networkTypeOther +//@description Sets the current network type. Can be called before authorization. Calling this method forces all network connections to reopen, mitigating the delay in switching between different networks, so it must be called whenever the network is changed, even if the network type remains the same. +//-Network type is used to check whether the library can use the network at all and also for collecting detailed network data usage statistics @type The new network type; pass null to set network type to networkTypeOther setNetworkType type:NetworkType = Ok; //@description Returns network data usage statistics. Can be called before authorization @only_current If true, returns only data for the current library launch @@ -4682,7 +5575,7 @@ resetNetworkStatistics = Ok; //@description Returns auto-download settings presets for the current user getAutoDownloadSettingsPresets = AutoDownloadSettingsPresets; -//@description Sets auto-download settings @settings New user auto-download settings @type Type of the network for which the new settings are applied +//@description Sets auto-download settings @settings New user auto-download settings @type Type of the network for which the new settings are relevant setAutoDownloadSettings settings:autoDownloadSettings type:NetworkType = Ok; @@ -4703,15 +5596,15 @@ setPassportElement element:InputPassportElement password:string = PassportElemen deletePassportElement type:PassportElementType = Ok; //@description Informs the user that some of the elements in their Telegram Passport contain errors; for bots only. The user will not be able to resend the elements, until the errors are fixed @user_id User identifier @errors The errors -setPassportElementErrors user_id:int32 errors:vector = Ok; +setPassportElementErrors user_id:int53 errors:vector = Ok; -//@description Returns an IETF language tag of the language preferred in the country, which should be used to fill native fields in Telegram Passport personal details. Returns a 404 error if unknown @country_code A two-letter ISO 3166-1 alpha-2 country code +//@description Returns an IETF language tag of the language preferred in the country, which must be used to fill native fields in Telegram Passport personal details. Returns a 404 error if unknown @country_code A two-letter ISO 3166-1 alpha-2 country code getPreferredCountryLanguage country_code:string = Text; //@description Sends a code to verify a phone number to be added to a user's Telegram Passport -//@phone_number The phone number of the user, in international format @settings Settings for the authentication of the user's phone number +//@phone_number The phone number of the user, in international format @settings Settings for the authentication of the user's phone number; pass null to use default settings sendPhoneNumberVerificationCode phone_number:string settings:phoneNumberAuthenticationSettings = AuthenticationCodeInfo; //@description Re-sends the code to verify a phone number to be added to a user's Telegram Passport @@ -4731,8 +5624,8 @@ resendEmailAddressVerificationCode = EmailAddressAuthenticationCodeInfo; checkEmailAddressVerificationCode code:string = Ok; -//@description Returns a Telegram Passport authorization form for sharing data with a service @bot_user_id User identifier of the service's bot @scope Telegram Passport element types requested by the service @public_key Service's public_key @nonce Authorization form nonce provided by the service -getPassportAuthorizationForm bot_user_id:int32 scope:string public_key:string nonce:string = PassportAuthorizationForm; +//@description Returns a Telegram Passport authorization form for sharing data with a service @bot_user_id User identifier of the service's bot @scope Telegram Passport element types requested by the service @public_key Service's public key @nonce Unique request identifier provided by the service +getPassportAuthorizationForm bot_user_id:int53 scope:string public_key:string nonce:string = PassportAuthorizationForm; //@description Returns already available Telegram Passport elements suitable for completing a Telegram Passport authorization form. Result can be received only once for each authorization form @autorization_form_id Authorization form identifier @password Password of the current user getPassportAuthorizationFormAvailableElements autorization_form_id:int32 password:string = PassportElementsWithErrors; @@ -4742,8 +5635,7 @@ getPassportAuthorizationFormAvailableElements autorization_form_id:int32 passwor sendPassportAuthorizationForm autorization_form_id:int32 types:vector = Ok; -//@description Sends phone number confirmation code. Should be called when user presses "https://t.me/confirmphone?phone=*******&hash=**********" or "tg://confirmphone?phone=*******&hash=**********" link @hash Value of the "hash" parameter from the link -//@phone_number Value of the "phone" parameter from the link @settings Settings for the authentication of the user's phone number +//@description Sends phone number confirmation code to handle links of the type internalLinkTypePhoneNumberConfirmation @hash Hash value from the link @phone_number Phone number value from the link @settings Settings for the authentication of the user's phone number; pass null to use default settings sendPhoneNumberConfirmationCode hash:string phone_number:string settings:phoneNumberAuthenticationSettings = AuthenticationCodeInfo; //@description Resends phone number confirmation code @@ -4757,26 +5649,32 @@ checkPhoneNumberConfirmationCode code:string = Ok; setBotUpdatesStatus pending_update_count:int32 error_message:string = Ok; -//@description Uploads a PNG image with a sticker; for bots only; returns the uploaded file -//@user_id Sticker file owner @png_sticker PNG image with the sticker; must be up to 512 KB in size and fit in 512x512 square -uploadStickerFile user_id:int32 png_sticker:InputFile = File; +//@description Uploads a PNG image with a sticker; returns the uploaded file @user_id Sticker file owner; ignored for regular users @sticker Sticker file to upload +uploadStickerFile user_id:int53 sticker:InputSticker = File; + +//@description Returns a suggested name for a new sticker set with a given title @title Sticker set title; 1-64 characters +getSuggestedStickerSetName title:string = Text; -//@description Creates a new sticker set; for bots only. Returns the newly created sticker set -//@user_id Sticker set owner +//@description Checks whether a name can be used for a new sticker set @name Name to be checked +checkStickerSetName name:string = CheckStickerSetNameResult; + +//@description Creates a new sticker set. Returns the newly created sticker set +//@user_id Sticker set owner; ignored for regular users //@title Sticker set title; 1-64 characters -//@name Sticker set name. Can contain only English letters, digits and underscores. Must end with *"_by_"* (** is case insensitive); 1-64 characters +//@name Sticker set name. Can contain only English letters, digits and underscores. Must end with *"_by_"* (** is case insensitive) for bots; 1-64 characters //@is_masks True, if stickers are masks. Animated stickers can't be masks -//@stickers List of stickers to be added to the set; must be non-empty. All stickers must be of the same type -createNewStickerSet user_id:int32 title:string name:string is_masks:Bool stickers:vector = StickerSet; +//@stickers List of stickers to be added to the set; must be non-empty. All stickers must be of the same type. For animated stickers, uploadStickerFile must be used before the sticker is shown +//@source Source of the sticker set; may be empty if unknown +createNewStickerSet user_id:int53 title:string name:string is_masks:Bool stickers:vector source:string = StickerSet; //@description Adds a new sticker to a set; for bots only. Returns the sticker set //@user_id Sticker set owner @name Sticker set name @sticker Sticker to add to the set -addStickerToSet user_id:int32 name:string sticker:InputSticker = StickerSet; +addStickerToSet user_id:int53 name:string sticker:InputSticker = StickerSet; //@description Sets a sticker set thumbnail; for bots only. Returns the sticker set //@user_id Sticker set owner @name Sticker set name -//@thumbnail Thumbnail to set in PNG or TGS format. Animated thumbnail must be set for animated sticker sets and only for them. Pass a zero InputFileId to delete the thumbnail -setStickerSetThumbnail user_id:int32 name:string thumbnail:InputFile = StickerSet; +//@thumbnail Thumbnail to set in PNG or TGS format; pass null to remove the sticker set thumbnail. Animated thumbnail must be set for animated sticker sets and only for them +setStickerSetThumbnail user_id:int53 name:string thumbnail:InputFile = StickerSet; //@description Changes the position of a sticker in the set to which it belongs; for bots only. The sticker set must have been created by the bot //@sticker Sticker @position New position of the sticker in the set, zero-based @@ -4808,14 +5706,18 @@ setAlarm seconds:double = Ok; //@description Returns information about existing countries. Can be called before authorization getCountries = Countries; -//@description Uses current user IP address to find their country. Returns two-letter ISO 3166-1 alpha-2 country code. Can be called before authorization +//@description Uses the current IP address to find the current country. Returns two-letter ISO 3166-1 alpha-2 country code. Can be called before authorization getCountryCode = Text; //@description Returns information about a phone number by its prefix. Can be called before authorization @phone_number_prefix The phone number prefix getPhoneNumberInfo phone_number_prefix:string = PhoneNumberInfo; -//@description Returns the default text for invitation messages to be used as a placeholder when the current user invites friends to Telegram -getInviteText = Text; +//@description Returns information about a phone number by its prefix synchronously. getCountries must be called at least once after changing localization to the specified language if properly localized country information is expected. Can be called synchronously +//@language_code A two-letter ISO 639-1 country code for country information localization @phone_number_prefix The phone number prefix +getPhoneNumberInfoSync language_code:string phone_number_prefix:string = PhoneNumberInfo; + +//@description Returns the link for downloading official Telegram application to be used when the current user invites friends to Telegram +getApplicationDownloadLink = HttpUrl; //@description Returns information about a tg:// deep link. Use "tg://need_update_for_some_feature" or "tg:some_unsupported_feature" for testing. Returns a 404 error for unknown links. Can be called before authorization @link The link getDeepLinkInfo link:string = DeepLinkInfo; @@ -4828,10 +5730,10 @@ getApplicationConfig = JsonValue; saveApplicationLogEvent type:string chat_id:int53 data:JsonValue = Ok; -//@description Adds a proxy server for network requests. Can be called before authorization @server Proxy server IP address @port Proxy server port @enable True, if the proxy should be enabled @type Proxy type +//@description Adds a proxy server for network requests. Can be called before authorization @server Proxy server IP address @port Proxy server port @enable True, if the proxy needs to be enabled @type Proxy type addProxy server:string port:int32 enable:Bool type:ProxyType = Proxy; -//@description Edits an existing proxy server for network requests. Can be called before authorization @proxy_id Proxy identifier @server Proxy server IP address @port Proxy server port @enable True, if the proxy should be enabled @type Proxy type +//@description Edits an existing proxy server for network requests. Can be called before authorization @proxy_id Proxy identifier @server Proxy server IP address @port Proxy server port @enable True, if the proxy needs to be enabled @type Proxy type editProxy proxy_id:int32 server:string port:int32 enable:Bool type:ProxyType = Proxy; //@description Enables a proxy. Only one proxy can be enabled at a time. Can be called before authorization @proxy_id Proxy identifier @@ -4847,7 +5749,7 @@ removeProxy proxy_id:int32 = Ok; getProxies = Proxies; //@description Returns an HTTPS link, which can be used to add a proxy. Available only for SOCKS5 and MTProto proxies. Can be called before authorization @proxy_id Proxy identifier -getProxyLink proxy_id:int32 = Text; +getProxyLink proxy_id:int32 = HttpUrl; //@description Computes time needed to receive a response from a Telegram server through a proxy. Can be called before authorization @proxy_id Proxy identifier. Use 0 to ping a Telegram server without a proxy pingProxy proxy_id:int32 = Seconds; @@ -4877,7 +5779,7 @@ setLogTagVerbosityLevel tag:string new_verbosity_level:int32 = Ok; getLogTagVerbosityLevel tag:string = LogVerbosityLevel; //@description Adds a message to TDLib internal log. Can be called synchronously -//@verbosity_level The minimum verbosity level needed for the message to be logged, 0-1023 @text Text of a message to log +//@verbosity_level The minimum verbosity level needed for the message to be logged; 0-1023 @text Text of a message to log addLogMessage verbosity_level:int32 text:string = Ok; diff --git a/lib/tgchat/ext/td/td/generate/scheme/telegram_api.tl b/lib/tgchat/ext/td/td/generate/scheme/telegram_api.tl index 5bdda4ca..d6648559 100644 --- a/lib/tgchat/ext/td/td/generate/scheme/telegram_api.tl +++ b/lib/tgchat/ext/td/td/generate/scheme/telegram_api.tl @@ -19,6 +19,9 @@ ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort; accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector = AccessPointRule; help.configSimple#5a592a6c date:int expires:int rules:vector = help.ConfigSimple; +inputPeerPhotoFileLocationLegacy#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation; +inputStickerSetThumbLegacy#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation; + ---functions--- test.useError = Error; @@ -28,16 +31,16 @@ test.useConfigSimple = help.ConfigSimple; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; -inputPeerChat#179be863 chat_id:int = InputPeer; -inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; -inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; -inputPeerUserFromMessage#17bae2e6 peer:InputPeer msg_id:int user_id:int = InputPeer; -inputPeerChannelFromMessage#9c95f7bb peer:InputPeer msg_id:int channel_id:int = InputPeer; +inputPeerChat#35a95cb9 chat_id:long = InputPeer; +inputPeerUser#dde8a54c user_id:long access_hash:long = InputPeer; +inputPeerChannel#27bcbbfc channel_id:long access_hash:long = InputPeer; +inputPeerUserFromMessage#a87b0a1c peer:InputPeer msg_id:int user_id:long = InputPeer; +inputPeerChannelFromMessage#bd2a0840 peer:InputPeer msg_id:int channel_id:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; -inputUser#d8292816 user_id:int access_hash:long = InputUser; -inputUserFromMessage#2d117597 peer:InputPeer msg_id:int user_id:int = InputUser; +inputUser#f21158c6 user_id:long access_hash:long = InputUser; +inputUserFromMessage#1da448e2 peer:InputPeer msg_id:int user_id:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; @@ -50,12 +53,12 @@ inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMe inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true force_file:flags.4?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; -inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia; +inputMediaDocument#33473058 flags:# id:InputDocument ttl_seconds:flags.0?int query:flags.1?string = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; -inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; +inputMediaInvoice#d9799874 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:flags.1?string = InputMedia; inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector solution:flags.1?string solution_entities:flags.1?Vector = InputMedia; inputMediaDice#e66fbf7b emoticon:string = InputMedia; @@ -77,12 +80,13 @@ inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputTakeoutFileLocation#29be5899 = InputFileLocation; inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; -inputPeerPhotoFileLocation#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation; -inputStickerSetThumb#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation; +inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; +inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; +inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation; -peerUser#9db1bc6d user_id:int = Peer; -peerChat#bad0e5bb chat_id:int = Peer; -peerChannel#bddde532 channel_id:int = Peer; +peerUser#59511722 user_id:long = Peer; +peerChat#36c6019a chat_id:long = Peer; +peerChannel#a2a5371e channel_id:long = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; @@ -95,11 +99,11 @@ storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; -userEmpty#200250ba id:int = User; -user#938458c1 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; +userEmpty#d3bc4b7a id:long = User; +user#3ff6ecb0 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; -userProfilePhoto#69d3ab26 flags:# has_video:flags.0?true photo_id:long photo_small:FileLocation photo_big:FileLocation dc_id:int = UserProfilePhoto; +userProfilePhoto#82d1f706 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; @@ -108,33 +112,33 @@ userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; -chatEmpty#9ba2d800 id:int = Chat; -chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; -chatForbidden#7328bdb id:int title:string = Chat; -channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; -channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; +chatEmpty#29562865 id:long = Chat; +chat#41cbf256 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; +chatForbidden#6592a1a7 id:long title:string = Chat; +channel#8261ac61 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; +channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat; -chatFull#1b7c9db3 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull; -channelFull#f0e6672a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int = ChatFull; +chatFull#46a6ffb4 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector = ChatFull; +channelFull#59cff963 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector = ChatFull; -chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; -chatParticipantCreator#da13538a user_id:int = ChatParticipant; -chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; +chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant; +chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant; +chatParticipantAdmin#a0933f5b user_id:long inviter_id:long date:int = ChatParticipant; -chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; -chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; +chatParticipantsForbidden#8763d3e1 flags:# chat_id:long self_participant:flags.0?ChatParticipant = ChatParticipants; +chatParticipants#3cbc93f8 chat_id:long participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; -chatPhoto#d20b9f3c flags:# has_video:flags.0?true photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto; +chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; -messageEmpty#83e5de54 id:int = Message; -message#58ae39c9 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true id:int from_id:flags.8?Peer peer_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector = Message; -messageService#286fa604 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction = Message; +messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; +message#85d6cbe2 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true id:int from_id:flags.8?Peer peer_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector ttl_period:flags.25?int = Message; +messageService#2b085862 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction ttl_period:flags.25?int = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; -messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia; +messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; @@ -146,16 +150,16 @@ messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia; messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; -messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; +messageActionChatCreate#bd47cbad title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; -messageActionChatAddUser#488a7337 users:Vector = MessageAction; -messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; -messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; +messageActionChatAddUser#15cefd00 users:Vector = MessageAction; +messageActionChatDeleteUser#a43f30cc user_id:long = MessageAction; +messageActionChatJoinedByLink#31224c3 inviter_id:long = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; -messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; -messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; +messageActionChatMigrateTo#e1037f92 channel_id:long = MessageAction; +messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; @@ -169,6 +173,12 @@ messageActionSecureValuesSentMe#1b287353 values:Vector credentials: messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; messageActionContactSignUp#f3f25f76 = MessageAction; messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = MessageAction; +messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction; +messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector = MessageAction; +messageActionSetMessagesTTL#aa1afbfd period:int = MessageAction; +messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; +messageActionSetChatTheme#aa786345 emoticon:string = MessageAction; +messageActionChatJoinedByRequest#ebbca3cb = MessageAction; dialog#2c171f72 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; @@ -177,10 +187,11 @@ photoEmpty#2331b22d id:long = Photo; photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector video_sizes:flags.1?Vector dc_id:int = 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; +photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; +photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize; photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; -photoSizeProgressive#5aa86a51 type:string location:FileLocation w:int h:int sizes:Vector = PhotoSize; +photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector = PhotoSize; +photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint; @@ -190,7 +201,7 @@ auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string nex auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; -auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; +auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; @@ -201,26 +212,27 @@ inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings; -peerSettings#733f2961 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true geo_distance:flags.6?int = PeerSettings; +peerSettings#733f2961 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true geo_distance:flags.6?int = PeerSettings; wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; -wallPaperNoFile#8af40b25 flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper; +wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonChildAbuse#adf44ee3 = ReportReason; -inputReportReasonOther#e1746d0a text:string = ReportReason; +inputReportReasonOther#c1e4a2b1 = ReportReason; inputReportReasonCopyright#9b89f93a = ReportReason; inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; +inputReportReasonFake#f5ddd6e7 = ReportReason; -userFull#edf17c12 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true user:User about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int = UserFull; +userFull#d697ff05 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true user:User about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string = UserFull; -contact#f911c994 user_id:int mutual:Bool = Contact; +contact#145ade0b user_id:long mutual:Bool = Contact; -importedContact#d0028438 user_id:int client_id:long = ImportedContact; +importedContact#c13e3c50 user_id:long client_id:long = ImportedContact; -contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; +contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; @@ -267,64 +279,64 @@ inputMessagesFilterPinned#1bb00451 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; -updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; -updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; +updateUserTyping#c01e857f user_id:long action:SendMessageAction = Update; +updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; -updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; -updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; -updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; +updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update; +updateUserName#c3f202e0 user_id:long first_name:string last_name:string username:string = Update; +updateUserPhoto#f227868c user_id:long date:int photo:UserProfilePhoto previous:Bool = Update; 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; -updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; -updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; +updateChatParticipantAdd#3dda5451 chat_id:long user_id:long inviter_id:long date:int version:int = Update; +updateChatParticipantDelete#e32f3d77 chat_id:long user_id:long version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; -updateUserPhone#12b9417b user_id:int phone:string = Update; +updateUserPhone#5492a13 user_id:long phone:string = Update; updateReadHistoryInbox#9c974fdf flags:# folder_id:flags.0?int peer:Peer max_id:int still_unread_count:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; -updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; -updateChannel#b6d45656 channel_id:int = Update; +updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update; +updateChannel#635b4c09 channel_id:long = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; -updateReadChannelInbox#330b5424 flags:# folder_id:flags.0?int channel_id:int max_id:int still_unread_count:int pts:int = Update; -updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; -updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; -updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; +updateReadChannelInbox#922e6e10 flags:# folder_id:flags.0?int channel_id:long max_id:int still_unread_count:int pts:int = Update; +updateDeleteChannelMessages#c32d5b12 channel_id:long messages:Vector pts:int pts_count:int = Update; +updateChannelMessageViews#f226ac08 channel_id:long id:int views:int = Update; +updateChatParticipantAdmin#d7ca61a2 chat_id:long user_id:long is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; -updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; -updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; +updateBotInlineQuery#496f379c flags:# query_id:long user_id:long query:string geo:flags.0?GeoPoint peer_type:flags.1?InlineQueryPeerType offset:string = Update; +updateBotInlineSend#12f12a07 flags:# user_id:long query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; -updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; +updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; -updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; +updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; +updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; -updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; +updateChannelWebPage#2f2ba99f channel_id:long webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update; updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; -updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; -updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; +updateBotShippingQuery#b5aefd7d query_id:long user_id:long payload:bytes shipping_address:PostAddress = Update; +updateBotPrecheckoutQuery#8caa9a96 flags:# query_id:long user_id:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#46560264 lang_code:string = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; -updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector = Update; +updateChannelReadMessagesContents#44bdd535 channel_id:long messages:Vector = Update; updateContactsReset#7084a7be = Update; -updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; +updateChannelAvailableMessages#b23fc698 channel_id:long available_min_id:int = Update; updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update; updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update; updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; @@ -336,19 +348,29 @@ updateDeleteScheduledMessages#90866cee peer:Peer messages:Vector = Update; updateTheme#8216fba3 theme:Theme = Update; updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update; updateLoginToken#564fe691 = Update; -updateMessagePollVote#42f88f2c poll_id:long user_id:int options:Vector = Update; +updateMessagePollVote#106395c9 poll_id:long user_id:long options:Vector qts:int = Update; updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update; updateDialogFilterOrder#a5d72105 order:Vector = Update; updateDialogFilters#3504914f = Update; updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update; -updateChannelParticipant#65d2b464 flags:# channel_id:int date:int user_id:int prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant qts:int = Update; -updateChannelMessageForwards#6e8a84df channel_id:int id:int forwards:int = Update; -updateReadChannelDiscussionInbox#1cc7de54 flags:# channel_id:int top_msg_id:int read_max_id:int broadcast_id:flags.0?int broadcast_post:flags.0?int = Update; -updateReadChannelDiscussionOutbox#4638a26c channel_id:int top_msg_id:int read_max_id:int = Update; +updateChannelMessageForwards#d29a27f4 channel_id:long id:int forwards:int = Update; +updateReadChannelDiscussionInbox#d6b19546 flags:# channel_id:long top_msg_id:int read_max_id:int broadcast_id:flags.0?long broadcast_post:flags.0?int = Update; +updateReadChannelDiscussionOutbox#695c9e7c channel_id:long top_msg_id:int read_max_id:int = Update; updatePeerBlocked#246a4b22 peer_id:Peer blocked:Bool = Update; -updateChannelUserTyping#ff2abe9f flags:# channel_id:int top_msg_id:flags.0?int user_id:int action:SendMessageAction = Update; +updateChannelUserTyping#8c88c923 flags:# channel_id:long top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update; updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector pts:int pts_count:int = Update; -updatePinnedChannelMessages#8588878b flags:# pinned:flags.0?true channel_id:int messages:Vector pts:int pts_count:int = Update; +updatePinnedChannelMessages#5bb98608 flags:# pinned:flags.0?true channel_id:long messages:Vector pts:int pts_count:int = Update; +updateChat#f89a6a4e chat_id:long = Update; +updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector version:int = Update; +updateGroupCall#14b24500 chat_id:long call:GroupCall = Update; +updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update; +updateChatParticipant#d087663a flags:# chat_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update; +updateChannelParticipant#985d3abb flags:# channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update; +updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update; +updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update; +updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector = Update; +updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector = Update; +updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -358,12 +380,12 @@ updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_mess updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; -updateShortMessage#2296d2c8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector = Updates; -updateShortChatMessage#402d5dbb flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector = Updates; +updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; +updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?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; -updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; +updateShortSentMessage#9015e101 flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector ttl_period:flags.25?int = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; @@ -379,16 +401,16 @@ config#330b4067 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:fla nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; -help.appUpdate#1da7158f flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string = help.AppUpdate; +help.appUpdate#ccbbce30 flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string sticker:flags.3?Document = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; -encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; -encryptedChatRequested#62718a82 flags:# folder_id:flags.0?int 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; +encryptedChatWaiting#66b25953 id:int access_hash:long date:int admin_id:long participant_id:long = EncryptedChat; +encryptedChatRequested#48f1d94c flags:# folder_id:flags.0?int id:int access_hash:long date:int admin_id:long participant_id:long g_a:bytes = EncryptedChat; +encryptedChat#61f0d4c7 id:int access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long = EncryptedChat; +encryptedChatDiscarded#1e1c7c45 flags:# history_deleted:flags.0?true id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; @@ -435,6 +457,11 @@ sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; +speakingInGroupCallAction#d92c2285 = SendMessageAction; +sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction; +sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction; +sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction; +sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction; contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; @@ -462,17 +489,17 @@ inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; -inputPrivacyValueAllowChatParticipants#4c81c1ba chats:Vector = InputPrivacyRule; -inputPrivacyValueDisallowChatParticipants#d82363af chats:Vector = InputPrivacyRule; +inputPrivacyValueAllowChatParticipants#840649cf chats:Vector = InputPrivacyRule; +inputPrivacyValueDisallowChatParticipants#e94f0f86 chats:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; -privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; +privacyValueAllowUsers#b8905fb2 users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; -privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; -privacyValueAllowChatParticipants#18be796b chats:Vector = PrivacyRule; -privacyValueDisallowChatParticipants#acae0690 chats:Vector = PrivacyRule; +privacyValueDisallowUsers#e4621141 users:Vector = PrivacyRule; +privacyValueAllowChatParticipants#6b134e8e chats:Vector = PrivacyRule; +privacyValueDisallowChatParticipants#41c87565 chats:Vector = PrivacyRule; account.privacyRules#50a04e45 rules:Vector chats:Vector users:Vector = account.PrivacyRules; @@ -487,12 +514,12 @@ documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; -messages.stickers#e4599bbd hash:int stickers:Vector = messages.Stickers; +messages.stickers#30a6ec7e hash:long stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; -messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; +messages.allStickers#cdbbcebb hash:long sets:Vector = messages.AllStickers; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; @@ -505,7 +532,7 @@ authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true pa account.authorizations#1250abde authorizations:Vector = account.Authorizations; -account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password; +account.password#185b184f flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int = account.Password; account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; @@ -515,11 +542,10 @@ auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; -chatInviteEmpty#69df3769 = ExportedChatInvite; -chatInviteExported#fc2e05bc link:string = ExportedChatInvite; +chatInviteExported#ab4a819 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int title:flags.8?string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; -chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:Photo participants_count:int participants:flags.4?Vector = ChatInvite; +chatInvite#300c44c1 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector = ChatInvite; chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; @@ -527,14 +553,15 @@ inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; +inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; -stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet; +stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; -botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; +botInfo#1b74b335 user_id:long description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; @@ -551,8 +578,8 @@ keyboardButtonRequestPoll#bbc7515d flags:# quiz:flags.0?Bool text:string = Keybo keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; -replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; -replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; +replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup; +replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector placeholder:flags.3?string = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; @@ -566,7 +593,7 @@ messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; -messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; +messageEntityMentionName#dc7b1140 offset:int length:int user_id:long = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; @@ -576,8 +603,8 @@ messageEntityBlockquote#20df5d0 offset:int length:int = MessageEntity; messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; -inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; -inputChannelFromMessage#2a286531 peer:InputPeer msg_id:int channel_id:int = InputChannel; +inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; +inputChannelFromMessage#5b934f9d peer:InputPeer msg_id:int channel_id:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; @@ -590,12 +617,12 @@ updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:fl channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; -channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; -channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; -channelParticipantCreator#447dca4b flags:# user_id:int admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; -channelParticipantAdmin#ccbebbaf flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; -channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant; -channelParticipantLeft#c3c6796b user_id:int = ChannelParticipant; +channelParticipant#c00c07c0 user_id:long date:int = ChannelParticipant; +channelParticipantSelf#35a8bfa7 flags:# via_invite:flags.0?true user_id:long inviter_id:long date:int = ChannelParticipant; +channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; +channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; +channelParticipantBanned#6df8014e flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights = ChannelParticipant; +channelParticipantLeft#1b03f006 peer:Peer = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; @@ -606,15 +633,15 @@ channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter; -channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; +channels.channelParticipants#9ab0feaf count:int participants:Vector chats:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; -channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; +channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector users:Vector = channels.ChannelParticipant; help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; -messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; +messages.savedGifs#84a02a0d hash:long gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; @@ -622,6 +649,7 @@ inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:f inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; +inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; @@ -633,6 +661,7 @@ botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string ent botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; +botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; @@ -641,7 +670,7 @@ messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_off exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; -messageFwdHeader#5f777dce flags:# from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int psa_type:flags.6?string = MessageFwdHeader; +messageFwdHeader#5f777dce flags:# imported:flags.7?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int psa_type:flags.6?string = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; @@ -657,6 +686,7 @@ messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?t messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; +inputBotInlineMessageID64#b6d915d7 dc_id:int owner_id:long id:int access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; @@ -683,10 +713,10 @@ draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; -messages.featuredStickers#b6abc341 hash:int count:int sets:Vector unread:Vector = messages.FeaturedStickers; +messages.featuredStickers#84c02310 hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; -messages.recentStickers#22f3afb3 hash:int packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; +messages.recentStickers#88d37c56 hash:long packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; @@ -706,7 +736,7 @@ game#bdf9653b flags:# id:long access_hash:long short_name:string title:string de inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; -highScore#58fffcd0 pos:int user_id:int score:int = HighScore; +highScore#73a379eb pos:int user_id:long score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; @@ -766,7 +796,7 @@ dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; -invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector = Invoice; +invoice#cd886e0 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; @@ -786,21 +816,21 @@ inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; -payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; +payments.paymentForm#1694761b flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult; -payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; +payments.paymentReceipt#70c4fe03 flags:# date:int bot_id:long provider_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials; +inputPaymentCredentialsGooglePay#8ac32801 payment_token:DataJSON = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; @@ -811,10 +841,10 @@ inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_co inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; -phoneCallWaiting#1b8f4ad1 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; -phoneCallRequested#87eabb53 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCallAccepted#997c454a flags:# video:flags.6?true id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true video:flags.6?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int = PhoneCall; +phoneCallWaiting#c5226f17 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; +phoneCallRequested#14b0ed0c flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; +phoneCallAccepted#3660c311 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_b:bytes protocol:PhoneCallProtocol = PhoneCall; +phoneCall#967f7c67 flags:# p2p_allowed:flags.5?true video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; @@ -857,24 +887,36 @@ channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputSticker channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLinkedChat#a26f881b prev_value:int new_value:int = ChannelAdminLogEventAction; +channelAdminLogEventActionChangeLinkedChat#50c7ac8 prev_value:long new_value:long = ChannelAdminLogEventAction; channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction; - -channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; +channelAdminLogEventActionStartGroupCall#23209745 call:InputGroupCall = ChannelAdminLogEventAction; +channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = ChannelAdminLogEventAction; +channelAdminLogEventActionParticipantMute#f92424d2 participant:GroupCallParticipant = ChannelAdminLogEventAction; +channelAdminLogEventActionParticipantUnmute#e64429c0 participant:GroupCallParticipant = ChannelAdminLogEventAction; +channelAdminLogEventActionToggleGroupCallSetting#56d6a247 join_muted:Bool = ChannelAdminLogEventAction; +channelAdminLogEventActionParticipantJoinByInvite#5cdada77 invite:ExportedChatInvite = ChannelAdminLogEventAction; +channelAdminLogEventActionExportedInviteDelete#5a50fca4 invite:ExportedChatInvite = ChannelAdminLogEventAction; +channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvite = ChannelAdminLogEventAction; +channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction; +channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction; +channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction; +channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction; + +channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; -channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; +channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; -messages.favedStickers#f37f2f16 hash:int packs:Vector stickers:Vector = messages.FavedStickers; +messages.favedStickers#2cb51097 hash:long packs:Vector stickers:Vector = messages.FavedStickers; recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; -recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; -recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; +recentMeUrlUser#b92c09e2 url:string user_id:long = RecentMeUrl; +recentMeUrlChat#b2da71d2 url:string chat_id:long = RecentMeUrl; recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; @@ -882,7 +924,7 @@ help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vect inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; -webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; +webAuthorization#a6f8f452 hash:long bot_id:long domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; @@ -898,7 +940,7 @@ dialogPeer#e56dbf05 peer:Peer = DialogPeer; dialogPeerFolder#514519e2 folder_id:int = DialogPeer; messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; -messages.foundStickerSets#5108d648 hash:int sets:Vector = messages.FoundStickerSets; +messages.foundStickerSets#8af09dd2 hash:long sets:Vector = messages.FoundStickerSets; fileHash#6242c773 offset:int limit:int hash:bytes = FileHash; @@ -1017,26 +1059,26 @@ poll#86e18161 id:long flags:# closed:flags.0?true public_voters:flags.1?true mul pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int = PollAnswerVoters; -pollResults#badcc1a3 flags:# min:flags.0?true results:flags.1?Vector total_voters:flags.2?int recent_voters:flags.3?Vector solution:flags.4?string solution_entities:flags.4?Vector = PollResults; +pollResults#dcb82ea3 flags:# min:flags.0?true results:flags.1?Vector total_voters:flags.2?int recent_voters:flags.3?Vector solution:flags.4?string solution_entities:flags.4?Vector = PollResults; chatOnlines#f041e250 onlines:int = ChatOnlines; statsURL#47a971e0 url:string = StatsURL; -chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true = ChatAdminRights; +chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true = ChatAdminRights; chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights; inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; inputWallPaperSlug#72091c80 slug:string = InputWallPaper; -inputWallPaperNoFile#8427bbac = InputWallPaper; +inputWallPaperNoFile#967a462e id:long = InputWallPaper; account.wallPapersNotModified#1c199183 = account.WallPapers; -account.wallPapers#702b65a9 hash:int wallpapers:Vector = account.WallPapers; +account.wallPapers#cdc3858c hash:long wallpapers:Vector = account.WallPapers; codeSettings#debebe83 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true = CodeSettings; -wallPaperSettings#5086cf8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int intensity:flags.3?int rotation:flags.4?int = WallPaperSettings; +wallPaperSettings#1dc1bca4 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int = WallPaperSettings; autoDownloadSettings#e04232f3 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true photo_size_max:int video_size_max:int file_size_max:int video_upload_maxbitrate:int = AutoDownloadSettings; @@ -1051,8 +1093,6 @@ emojiURL#a575739d url:string = EmojiURL; emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; -fileLocationToBeDeprecated#bc7fc6cd volume_id:long local_id:int = FileLocation; - folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; @@ -1076,10 +1116,10 @@ restrictionReason#d072acb4 platform:string reason:string text:string = Restricti inputTheme#3c5693e9 id:long access_hash:long = InputTheme; inputThemeSlug#f5890df1 slug:string = InputTheme; -theme#28f1114 flags:# creator:flags.0?true default:flags.1?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?ThemeSettings installs_count:int = Theme; +theme#a00e67d6 flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?Vector emoticon:flags.6?string installs_count:flags.4?int = Theme; account.themesNotModified#f41eb622 = account.Themes; -account.themes#7f676421 hash:int themes:Vector = account.Themes; +account.themes#9a3d8c6d hash:long themes:Vector = account.Themes; auth.loginToken#629f1980 expires:int token:bytes = auth.LoginToken; auth.loginTokenMigrateTo#68e9916 dc_id:int token:bytes = auth.LoginToken; @@ -1095,15 +1135,15 @@ baseThemeNight#b7b31ea8 = BaseTheme; baseThemeTinted#6d5f77ee = BaseTheme; baseThemeArctic#5b11125a = BaseTheme; -inputThemeSettings#bd507cd1 flags:# base_theme:BaseTheme accent_color:int message_top_color:flags.0?int message_bottom_color:flags.0?int wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; +inputThemeSettings#8fde504f flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; -themeSettings#9c14984a flags:# base_theme:BaseTheme accent_color:int message_top_color:flags.0?int message_bottom_color:flags.0?int wallpaper:flags.1?WallPaper = ThemeSettings; +themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?WallPaper = ThemeSettings; webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settings:flags.1?ThemeSettings = WebPageAttribute; -messageUserVote#a28e5559 user_id:int option:bytes date:int = MessageUserVote; -messageUserVoteInputOption#36377430 user_id:int date:int = MessageUserVote; -messageUserVoteMultiple#e8fe0de user_id:int options:Vector date:int = MessageUserVote; +messageUserVote#34d247b4 user_id:long option:bytes date:int = MessageUserVote; +messageUserVoteInputOption#3ca5b0ec user_id:long date:int = MessageUserVote; +messageUserVoteMultiple#8a65e557 user_id:long options:Vector date:int = MessageUserVote; messages.votesList#823f649 flags:# count:int votes:Vector users:Vector next_offset:flags.0?string = messages.VotesList; @@ -1132,13 +1172,13 @@ stats.broadcastStats#bdf78394 period:StatsDateRangeDays followers:StatsAbsValueA help.promoDataEmpty#98f6ac75 expires:int = help.PromoData; help.promoData#8c39793f flags:# proxy:flags.0?true expires:int peer:Peer chats:Vector users:Vector psa_type:flags.1?string psa_message:flags.2?string = help.PromoData; -videoSize#e831c556 flags:# type:string location:FileLocation w:int h:int size:int video_start_ts:flags.0?double = VideoSize; +videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize; -statsGroupTopPoster#18f3d0f7 user_id:int messages:int avg_chars:int = StatsGroupTopPoster; +statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGroupTopPoster; -statsGroupTopAdmin#6014f412 user_id:int deleted:int kicked:int banned:int = StatsGroupTopAdmin; +statsGroupTopAdmin#d7584c87 user_id:long deleted:int kicked:int banned:int = StatsGroupTopAdmin; -statsGroupTopInviter#31962a4c user_id:int invitations:int = StatsGroupTopInviter; +statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInviter; stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; @@ -1155,16 +1195,88 @@ messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:fla messages.messageViews#b6c4f543 views:Vector chats:Vector users:Vector = messages.MessageViews; -messages.discussionMessage#f5dd8f9d flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int chats:Vector users:Vector = messages.DiscussionMessage; +messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; messageReplyHeader#a6d57763 flags:# reply_to_msg_id:int reply_to_peer_id:flags.0?Peer reply_to_top_id:flags.1?int = MessageReplyHeader; -messageReplies#4128faac flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?int max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; +messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats; +groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; +groupCall#d597650c flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int = GroupCall; + +inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; + +groupCallParticipant#eba636fe flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo = GroupCallParticipant; + +phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; + +phone.groupParticipants#f47751b6 count:int participants:Vector next_offset:string chats:Vector users:Vector version:int = phone.GroupParticipants; + +inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; +inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; +inlineQueryPeerTypeChat#d766c50a = InlineQueryPeerType; +inlineQueryPeerTypeMegagroup#5ec4be43 = InlineQueryPeerType; +inlineQueryPeerTypeBroadcast#6334ee9a = InlineQueryPeerType; + +messages.historyImport#1662af0b id:long = messages.HistoryImport; + +messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true title:flags.2?string = messages.HistoryImportParsed; + +messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector = messages.AffectedFoundMessages; + +chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter; + +messages.exportedChatInvites#bdc62dcc count:int invites:Vector users:Vector = messages.ExportedChatInvites; + +messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; +messages.exportedChatInviteReplaced#222600ef invite:ExportedChatInvite new_invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; + +messages.chatInviteImporters#81b6b00a count:int importers:Vector users:Vector = messages.ChatInviteImporters; + +chatAdminWithInvites#f2ecef23 admin_id:long invites_count:int revoked_invites_count:int = ChatAdminWithInvites; + +messages.chatAdminsWithInvites#b69b72d7 admins:Vector users:Vector = messages.ChatAdminsWithInvites; + +messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer; + +phone.joinAsPeers#afe5623f peers:Vector chats:Vector users:Vector = phone.JoinAsPeers; + +phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite; + +groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector = GroupCallParticipantVideoSourceGroup; + +groupCallParticipantVideo#67753ac8 flags:# paused:flags.0?true endpoint:string source_groups:Vector audio_source:flags.1?int = GroupCallParticipantVideo; + +stickers.suggestedShortName#85fea03f short_name:string = stickers.SuggestedShortName; + +botCommandScopeDefault#2f6cb2ab = BotCommandScope; +botCommandScopeUsers#3c4f04d8 = BotCommandScope; +botCommandScopeChats#6fe1a881 = BotCommandScope; +botCommandScopeChatAdmins#b9aa606a = BotCommandScope; +botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope; +botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope; +botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope; + +account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult; +account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; +account.resetPasswordOk#e926d63e = account.ResetPasswordResult; + +sponsoredMessage#d151e19a flags:# random_id:bytes from_id:Peer channel_post:flags.2?int start_param:flags.0?string message:string entities:flags.1?Vector = SponsoredMessage; + +messages.sponsoredMessages#65a4c7d5 messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; + +searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod; + +messages.searchResultsCalendar#147ee23c flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector messages:Vector chats:Vector users:Vector = messages.SearchResultsCalendar; + +searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosition; + +messages.searchResultsPositions#53b22baf count:int positions:Vector = messages.SearchResultsPositions; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1181,28 +1293,29 @@ auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:strin auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; -auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; +auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; -auth.recoverPassword#4ea56e92 code:string = auth.Authorization; +auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; -auth.exportLoginToken#b1b41517 api_id:int api_hash:string except_ids:Vector = auth.LoginToken; +auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector = auth.LoginToken; auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken; auth.acceptLoginToken#e894ad4d token:bytes = Authorization; +auth.checkRecoveryPassword#d36bf79 code:string = Bool; -account.registerDevice#68976c6f flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; -account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector = Bool; +account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; +account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; -account.getWallPapers#aabb1763 hash:int = account.WallPapers; -account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; +account.getWallPapers#7967d36 hash:long = account.WallPapers; +account.reportPeer#c5ba3d86 peer:InputPeer reason:ReportReason message:string = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; @@ -1228,8 +1341,8 @@ account.getAllSecureValues#b288bc7d = Vector; account.getSecureValue#73665bc2 types:Vector = Vector; account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; account.deleteSecureValue#b880bc4b types:Vector = Bool; -account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm; -account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; +account.getAuthorizationForm#a929597a bot_id:long scope:string public_key:string = account.AuthorizationForm; +account.acceptAuthorization#f3ed4c73 bot_id:long scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode; @@ -1250,25 +1363,29 @@ account.resetWallPapers#bb3b9804 = Bool; account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings; account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool; account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document; -account.createTheme#8432c21f flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?InputThemeSettings = Theme; -account.updateTheme#5cb367d5 flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?InputThemeSettings = Theme; +account.createTheme#652e4400 flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?Vector = Theme; +account.updateTheme#2bf40ccc flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?Vector = Theme; account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool; -account.installTheme#7ae43737 flags:# dark:flags.0?true format:flags.1?string theme:flags.1?InputTheme = Bool; +account.installTheme#c727bb3b flags:# dark:flags.0?true theme:flags.1?InputTheme format:flags.2?string base_theme:flags.3?BaseTheme = Bool; account.getTheme#8d9d742b format:string theme:InputTheme document_id:long = Theme; -account.getThemes#285946f8 format:string hash:int = account.Themes; +account.getThemes#7206e458 format:string hash:long = account.Themes; account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool; account.getContentSettings#8b9b4dae = account.ContentSettings; account.getMultiWallPapers#65ad71dc wallpapers:Vector = Vector; account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings; account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings; +account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool; +account.resetPassword#9308ce1b = account.ResetPasswordResult; +account.declinePasswordReset#4c9409f6 = Bool; +account.getChatThemes#d638de89 hash:long = account.Themes; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; -contacts.getContactIDs#2caa4a42 hash:int = Vector; +contacts.getContactIDs#7adc669d hash:long = Vector; contacts.getStatuses#c4a353ee = Vector; -contacts.getContacts#c023849f hash:int = contacts.Contacts; +contacts.getContacts#5dd69e12 hash:long = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; contacts.deleteContacts#96a0e00 id:Vector = Updates; contacts.deleteByPhones#1013fd9e phones:Vector = Bool; @@ -1277,7 +1394,7 @@ contacts.unblock#bea65d50 id:InputPeer = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; -contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; +contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:long = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; contacts.getSaved#82f1e39f = Vector; @@ -1288,31 +1405,31 @@ contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoP contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates; messages.getMessages#63c66506 id:Vector = messages.Messages; -messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; -messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; -messages.search#c352eec flags:# peer:InputPeer q:string from_id:flags.0?InputPeer top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; +messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; +messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; +messages.search#a0fda762 flags:# peer:InputPeer q:string from_id:flags.0?InputPeer top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; -messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory; +messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; messages.sendMessage#520c3870 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int = Updates; messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int = Updates; -messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer schedule_date:flags.10?int = Updates; +messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer schedule_date:flags.10?int = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; -messages.report#bd82b658 peer:InputPeer id:Vector reason:ReportReason = Bool; -messages.getChats#3c6aa187 id:Vector = messages.Chats; -messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; -messages.editChatTitle#dc452855 chat_id:int title:string = Updates; -messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; -messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; -messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; +messages.report#8953ab4e peer:InputPeer id:Vector reason:ReportReason message:string = Bool; +messages.getChats#49e9528f id:Vector = messages.Chats; +messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull; +messages.editChatTitle#73783ffd chat_id:long title:string = Updates; +messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates; +messages.addChatUser#f24753e3 chat_id:long user_id:InputUser fwd_limit:int = Updates; +messages.deleteChatUser#a2185cab flags:# revoke_history:flags.0?true chat_id:long user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; 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.discardEncryption#f393aea0 flags:# delete_history:flags.0?true chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; @@ -1321,10 +1438,10 @@ messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long da messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; -messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers; -messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; +messages.getStickers#d5a5d3a1 emoticon:string hash:long = messages.Stickers; +messages.getAllStickers#b8a0a1a8 hash:long = messages.AllStickers; messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector = MessageMedia; -messages.exportChatInvite#df7534c peer:InputPeer = ExportedChatInvite; +messages.exportChatInvite#a02ce5d5 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; @@ -1332,12 +1449,12 @@ messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = m messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector increment:Bool = messages.MessageViews; -messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; -messages.migrateChat#15a3b8e3 chat_id:int = Updates; +messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool; +messages.migrateChat#a2875319 chat_id:long = Updates; messages.searchGlobal#4bc6589a flags:# folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; -messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; +messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; @@ -1350,20 +1467,20 @@ messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; -messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; +messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; -messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; +messages.getRecentStickers#9da9403b flags:# attached:flags.0?true hash:long = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; -messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; +messages.getMaskStickers#640f82b8 hash:long = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; -messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; -messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; +messages.getCommonChats#e40ca104 user_id:InputUser max_id:long limit:int = messages.Chats; +messages.getAllChats#875f74be except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool; @@ -1372,14 +1489,14 @@ messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?stri messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; -messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; +messages.getFavedStickers#4f1aaa9 hash:long = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; -messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages; +messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages; messages.sendMultiMedia#cc0110cb flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector schedule_date:flags.10?int = Updates; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; -messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets; +messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; messages.getSplitRanges#1cff7e08 = Vector; messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool; messages.getDialogUnreadMarks#22e24e22 = Vector; @@ -1388,7 +1505,6 @@ messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true unpin:flags.1? messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates; messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; -messages.getStatsURL#812c2ae6 flags:# dark:flags.0?true peer:InputPeer params:string = StatsURL; messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; @@ -1396,10 +1512,10 @@ messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector = Vector; -messages.requestUrlAuth#e33f5613 peer:InputPeer msg_id:int button_id:int = UrlAuthResult; -messages.acceptUrlAuth#f729ea98 flags:# write_allowed:flags.0?true peer:InputPeer msg_id:int button_id:int = UrlAuthResult; +messages.requestUrlAuth#198fb446 flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult; +messages.acceptUrlAuth#b12c7125 flags:# write_allowed:flags.0?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult; messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool; -messages.getScheduledHistory#e2c2685b peer:InputPeer hash:int = messages.Messages; +messages.getScheduledHistory#f516760b peer:InputPeer hash:long = messages.Messages; messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector = messages.Messages; messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector = Updates; messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector = Updates; @@ -1409,11 +1525,31 @@ messages.getDialogFilters#f19ed96d = Vector; messages.getSuggestedDialogFilters#a29cd42c = Vector; messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool; messages.updateDialogFiltersOrder#c563c1e4 order:Vector = Bool; -messages.getOldFeaturedStickers#5fe7025b offset:int limit:int hash:int = messages.FeaturedStickers; -messages.getReplies#24b581ba peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; +messages.getOldFeaturedStickers#7ed094a1 offset:int limit:int hash:long = messages.FeaturedStickers; +messages.getReplies#22ddd30c peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage; messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool; messages.unpinAllMessages#f025bc8b peer:InputPeer = messages.AffectedHistory; +messages.deleteChat#5bd0ee50 chat_id:long = Bool; +messages.deletePhoneCallHistory#f9cbe409 flags:# revoke:flags.0?true = messages.AffectedFoundMessages; +messages.checkHistoryImport#43fe19f3 import_head:string = messages.HistoryImportParsed; +messages.initHistoryImport#34090c3b peer:InputPeer file:InputFile media_count:int = messages.HistoryImport; +messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia; +messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool; +messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites; +messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite; +messages.editExportedChatInvite#bdca2f75 flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int request_needed:flags.3?Bool title:flags.4?string = messages.ExportedChatInvite; +messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool; +messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool; +messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites; +messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true peer:InputPeer link:flags.1?string q:flags.2?string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; +messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates; +messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer; +messages.setChatTheme#e63be13f peer:InputPeer emoticon:string = Updates; +messages.getMessageReadParticipants#2c6f97b7 peer:InputPeer msg_id:int = Vector; +messages.getSearchResultsCalendar#49f0bde9 peer:InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar; +messages.getSearchResultsPositions#6e9583a3 peer:InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions; +messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; @@ -1453,7 +1589,7 @@ help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; help.getPromoData#c0977421 = help.PromoData; help.hidePromoData#1e251c95 peer:InputPeer = Bool; -help.dismissSuggestion#77fa99f suggestion:string = Bool; +help.dismissSuggestion#f50dbaa1 peer:InputPeer suggestion:string = Bool; help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; @@ -1461,11 +1597,11 @@ channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages. channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; -channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; -channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; +channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants; +channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; -channels.createChannel#3d5fb10f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string = Updates; +channels.createChannel#3d5fb10f flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string = Updates; channels.editAdmin#d33c8902 channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:string = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; @@ -1478,7 +1614,7 @@ channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true = messages.Chats; -channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates; +channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; @@ -1491,24 +1627,31 @@ channels.editCreator#8f38cd1f channel:InputChannel user_id:InputUser password:In channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool; channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates; channels.getInactiveChannels#11e831ee = messages.InactiveChats; +channels.convertToGigagroup#b290c69 channel:InputChannel = Updates; +channels.viewSponsoredMessage#beaedb94 channel:InputChannel random_id:bytes = Bool; +channels.getSponsoredMessages#ec210fbf channel:InputChannel = messages.SponsoredMessages; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; -bots.setBotCommands#805d46f6 commands:Vector = Bool; - -payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; -payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; -payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; -payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; +bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector = Bool; +bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool; +bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector; + +payments.getPaymentForm#8a333c8d flags:# peer:InputPeer msg_id:int theme_params:flags.0?DataJSON = payments.PaymentForm; +payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; +payments.validateRequestedInfo#db103170 flags:# save:flags.0?true peer:InputPeer msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; +payments.sendPaymentForm#30c3bc9d flags:# form_id:long peer:InputPeer msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials tip_amount:flags.2?long = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; payments.getBankCardData#2e79d779 number:string = payments.BankCardData; -stickers.createStickerSet#f1036780 flags:# masks:flags.0?true animated:flags.1?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector = messages.StickerSet; +stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true animated:flags.1?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; stickers.setStickerSetThumb#9a364e30 stickerset:InputStickerSet thumb:InputDocument = messages.StickerSet; +stickers.checkShortName#284b3639 short_name:string = Bool; +stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; @@ -1519,6 +1662,25 @@ phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall durati phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; +phone.createGroupCall#48cdc6d8 flags:# peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates; +phone.joinGroupCall#b132ff7b flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string params:DataJSON = Updates; +phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; +phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; +phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; +phone.toggleGroupCallSettings#74bbb43d flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool = Updates; +phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall; +phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; +phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector = Vector; +phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates; +phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates; +phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; +phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; +phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite; +phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates; +phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates; +phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool; +phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates; +phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates; langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; diff --git a/lib/tgchat/ext/td/td/generate/tl-parser/CMakeLists.txt b/lib/tgchat/ext/td/td/generate/tl-parser/CMakeLists.txt new file mode 100644 index 00000000..6cf5331f --- /dev/null +++ b/lib/tgchat/ext/td/td/generate/tl-parser/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.0 FATAL_ERROR) + +if (POLICY CMP0065) + # do not export symbols from executables + # affects compiler checks in project(), so must be set before it + cmake_policy(SET CMP0065 NEW) +endif() + +project(tl-parser LANGUAGES C) + +set(SOURCES crc32.h crc32.c tlc.c tl-parser.c tl-parser.h tl-parser-tree.h tl-tl.h portable_endian.h) + +if (WIN32) + add_definitions("-D_CRT_SECURE_NO_WARNINGS") + list(APPEND SOURCES wgetopt.c wgetopt.h) + if (MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8 /wd4101 /wd4244 /wd4267") + endif() +endif() + +add_executable(${PROJECT_NAME} ${SOURCES}) + +if (NOT WIN32) + target_link_libraries(${PROJECT_NAME} PRIVATE m) +endif() diff --git a/lib/tgchat/ext/td/td/generate/tl-parser/LICENSE b/lib/tgchat/ext/td/td/generate/tl-parser/LICENSE new file mode 100644 index 00000000..d159169d --- /dev/null +++ b/lib/tgchat/ext/td/td/generate/tl-parser/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/lib/tgchat/ext/td/td/generate/tl-parser/crc32.c b/lib/tgchat/ext/td/td/generate/tl-parser/crc32.c new file mode 100644 index 00000000..b7e02181 --- /dev/null +++ b/lib/tgchat/ext/td/td/generate/tl-parser/crc32.c @@ -0,0 +1,345 @@ +/* + This file is part of VK/KittenPHP-DB-Engine Library. + + VK/KittenPHP-DB-Engine Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + VK/KittenPHP-DB-Engine Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with VK/KittenPHP-DB-Engine Library. If not, see . + + Copyright 2009-2012 Vkontakte Ltd + 2009-2012 Nikolai Durov + 2009-2012 Andrei Lopatin + 2012 Anton Maydell +*/ + +#include +#include +#include + +#include "crc32.h" + +unsigned int crc32_table[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +unsigned int crc32_table2[256] = +{ + 0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, + 0x646cc504, 0x7d77f445, 0x565aa786, 0x4f4196c7, + 0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, + 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf, + 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, + 0x821b9859, 0x9b00a918, 0xb02dfadb, 0xa936cb9a, + 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, 0xcd5a0e9e, + 0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, + 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, + 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d, + 0xdf4636f3, 0xc65d07b2, 0xed705471, 0xf46b6530, + 0xbb2af3f7, 0xa231c2b6, 0x891c9175, 0x9007a034, + 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, + 0xf0794f05, 0xe9627e44, 0xc24f2d87, 0xdb541cc6, + 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2, + 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, 0x138d96ce, + 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, + 0xded79850, 0xc7cca911, 0xece1fad2, 0xf5facb93, + 0x7262d75c, 0x6b79e61d, 0x4054b5de, 0x594f849f, + 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b, + 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, + 0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, + 0xc94824ab, 0xd05315ea, 0xfb7e4629, 0xe2657768, + 0x2f3f79f6, 0x362448b7, 0x1d091b74, 0x04122a35, + 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, + 0x838a36fa, 0x9a9107bb, 0xb1bc5478, 0xa8a76539, + 0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, + 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c, + 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, + 0x71418a1a, 0x685abb5b, 0x4377e898, 0x5a6cd9d9, + 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, 0x3e001cdd, + 0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, + 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, + 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, + 0x66de36e1, 0x7fc507a0, 0x54e85463, 0x4df36522, + 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, 0x299fa026, + 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, + 0x2c1c24b0, 0x350715f1, 0x1e2a4632, 0x07317773, + 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277, + 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, + 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, + 0x674f9842, 0x7e54a903, 0x5579fac0, 0x4c62cb81, + 0x8138c51f, 0x9823f45e, 0xb30ea79d, 0xaa1596dc, + 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8, + 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, + 0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, + 0x3a1236e8, 0x230907a9, 0x0824546a, 0x113f652b, + 0x96a779e4, 0x8fbc48a5, 0xa4911b66, 0xbd8a2a27, + 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, + 0x70d024b9, 0x69cb15f8, 0x42e6463b, 0x5bfd777a, + 0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, + 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, 0x9324fd72, +}; + +unsigned int crc32_table1[256] = +{ + 0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, + 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, 0x054f1685, + 0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, + 0x091af964, 0x08d89353, 0x0a9e2d0a, 0x0b5c473d, + 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, + 0x1235f2c8, 0x13f798ff, 0x11b126a6, 0x10734c91, + 0x153c5a14, 0x14fe3023, 0x16b88e7a, 0x177ae44d, + 0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, + 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, + 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd, + 0x246be590, 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, + 0x23624d4c, 0x22a0277b, 0x20e69922, 0x2124f315, + 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, + 0x709a8dc0, 0x7158e7f7, 0x731e59ae, 0x72dc3399, + 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45, + 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, + 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, + 0x6bb5866c, 0x6a77ec5b, 0x68315202, 0x69f33835, + 0x62af7f08, 0x636d153f, 0x612bab66, 0x60e9c151, + 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d, + 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, + 0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, + 0x41cd3244, 0x400f5873, 0x4249e62a, 0x438b8c1d, + 0x54f16850, 0x55330267, 0x5775bc3e, 0x56b7d609, + 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, + 0x5deb9134, 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, + 0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, + 0xe63cb35c, 0xe7fed96b, 0xe5b86732, 0xe47a0d05, + 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, + 0xfd13b8f0, 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, + 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, 0xf85cae75, + 0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, + 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, + 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5, + 0xd76b0cd8, 0xd6a966ef, 0xd4efd8b6, 0xd52db281, + 0xd062a404, 0xd1a0ce33, 0xd3e6706a, 0xd2241a5d, + 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, + 0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, + 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d, + 0x91af9640, 0x906dfc77, 0x922b422e, 0x93e92819, + 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, + 0x98b56f24, 0x99770513, 0x9b31bb4a, 0x9af3d17d, + 0x8d893530, 0x8c4b5f07, 0x8e0de15e, 0x8fcf8b69, + 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5, + 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, + 0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, + 0xaeeb787c, 0xaf29124b, 0xad6fac12, 0xacadc625, + 0xa7f18118, 0xa633eb2f, 0xa4755576, 0xa5b73f41, + 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, + 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, 0xb08b6555, + 0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, + 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed, +}; + +unsigned int crc32_table0[256] = { + 0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, + 0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9, + 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, + 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, 0x58631056, + 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, + 0x95ad7f70, 0x2d111815, 0x3fa4b7fb, 0x8718d09e, + 0x1acfe827, 0xa2738f42, 0xb0c620ac, 0x087a47c9, + 0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, + 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, + 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68, + 0xf02bf8a1, 0x48979fc4, 0x5a22302a, 0xe29e574f, + 0x7f496ff6, 0xc7f50893, 0xd540a77d, 0x6dfcc018, + 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, + 0x9b14583d, 0x23a83f58, 0x311d90b6, 0x89a1f7d3, + 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084, + 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, + 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, + 0x446f98f5, 0xfcd3ff90, 0xee66507e, 0x56da371b, + 0x0eb9274d, 0xb6054028, 0xa4b0efc6, 0x1c0c88a3, + 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4, + 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, + 0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, + 0x71f048bb, 0xc94c2fde, 0xdbf98030, 0x6345e755, + 0x6b3fa09c, 0xd383c7f9, 0xc1366817, 0x798a0f72, + 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, + 0x21e91f24, 0x99557841, 0x8be0d7af, 0x335cb0ca, + 0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, + 0x623b216c, 0xda874609, 0xc832e9e7, 0x708e8e82, + 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, + 0xbd40e1a4, 0x05fc86c1, 0x1749292f, 0xaff54e4a, + 0x322276f3, 0x8a9e1196, 0x982bbe78, 0x2097d91d, + 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, + 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, + 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc, + 0x88df31ea, 0x3063568f, 0x22d6f961, 0x9a6a9e04, + 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, 0x15080953, + 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, + 0xd8c66675, 0x607a0110, 0x72cfaefe, 0xca73c99b, + 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc, + 0x764dee06, 0xcef18963, 0xdc44268d, 0x64f841e8, + 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, + 0x3c9b51be, 0x842736db, 0x96929935, 0x2e2efe50, + 0x2654b999, 0x9ee8defc, 0x8c5d7112, 0x34e11677, + 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120, + 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, + 0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, + 0x591dd66f, 0xe1a1b10a, 0xf3141ee4, 0x4ba87981, + 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, 0x017ec639, + 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, + 0x090481f0, 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, + 0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, + 0xccb0a91f, 0x740cce7a, 0x66b96194, 0xde0506f1, +}; + +static unsigned int crc32_partial (const void *data, int len, unsigned crc) { + const int *p = (const int *) data; + int x; +#define DO_ONE(v) crc ^= v; crc = crc32_table0[crc & 0xff] ^ crc32_table1[(crc & 0xff00) >> 8] ^ crc32_table2[(crc & 0xff0000) >> 16] ^ crc32_table[crc >> 24]; +#define DO_FOUR(p) DO_ONE((p)[0]); DO_ONE((p)[1]); DO_ONE((p)[2]); DO_ONE((p)[3]); + + for (x = (len >> 5); x > 0; x--) { + DO_FOUR (p); + DO_FOUR (p + 4); + p += 8; + } + if (len & 16) { + DO_FOUR (p); + p += 4; + } + if (len & 8) { + DO_ONE (p[0]); + DO_ONE (p[1]); + p += 2; + } + if (len & 4) { + DO_ONE (*p++); + } + /* + for (x = (len >> 2) & 7; x > 0; x--) { + DO_ONE (*p++); + } + */ +#undef DO_ONE +#undef DO_FOUR + const char *q = (const char *) p; + if (len & 2) { + crc = crc32_table[(crc ^ q[0]) & 0xff] ^ (crc >> 8); + crc = crc32_table[(crc ^ q[1]) & 0xff] ^ (crc >> 8); + q += 2; + } + if (len & 1) { + crc = crc32_table[(crc ^ *q++) & 0xff] ^ (crc >> 8); + } + return crc; +} + +unsigned int compute_crc32 (const void *data, int len) { + return crc32_partial (data, len, -1) ^ -1; +} + diff --git a/lib/tgchat/ext/td/td/generate/tl-parser/crc32.h b/lib/tgchat/ext/td/td/generate/tl-parser/crc32.h new file mode 100644 index 00000000..b461784b --- /dev/null +++ b/lib/tgchat/ext/td/td/generate/tl-parser/crc32.h @@ -0,0 +1,37 @@ +/* + This file is part of VK/KittenPHP-DB-Engine Library. + + VK/KittenPHP-DB-Engine Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + VK/KittenPHP-DB-Engine Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with VK/KittenPHP-DB-Engine Library. If not, see . + + Copyright 2009-2012 Vkontakte Ltd + 2009-2012 Nikolai Durov + 2009-2012 Andrei Lopatin + 2012 Anton Maydell +*/ + +#ifndef __CRC32_H__ +#define __CRC32_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned int compute_crc32 (const void *data, int len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/tgchat/ext/td/td/generate/tl-parser/portable_endian.h b/lib/tgchat/ext/td/td/generate/tl-parser/portable_endian.h new file mode 100644 index 00000000..7338c3ae --- /dev/null +++ b/lib/tgchat/ext/td/td/generate/tl-parser/portable_endian.h @@ -0,0 +1,124 @@ +// "License": Public Domain +// I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like. +// In case there are jurisdictions that don't support putting things in the public domain you can also consider it to +// be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it +// an example on how to get the endian conversion functions on different platforms. + +/* Originally cloned from https://gist.github.com/PkmX/63dd23f28ba885be53a5 + * Commit was: 1eca2ab34f2301b9641aa73d1016b951fff3fc39 + * Re-published at https://github.com/BenWiederhake/portable-endian.h to provide a means to submit patches and report issues. */ + +#ifndef PORTABLE_ENDIAN_H__ +#define PORTABLE_ENDIAN_H__ + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) + +# define __WINDOWS__ + +#endif + +#if defined(__linux__) || defined(__CYGWIN__) || defined(__sun) + +# include + +#elif defined(__APPLE__) + +# include + +# define htobe16(x) OSSwapHostToBigInt16(x) +# define htole16(x) OSSwapHostToLittleInt16(x) +# define be16toh(x) OSSwapBigToHostInt16(x) +# define le16toh(x) OSSwapLittleToHostInt16(x) + +# define htobe32(x) OSSwapHostToBigInt32(x) +# define htole32(x) OSSwapHostToLittleInt32(x) +# define be32toh(x) OSSwapBigToHostInt32(x) +# define le32toh(x) OSSwapLittleToHostInt32(x) + +# define htobe64(x) OSSwapHostToBigInt64(x) +# define htole64(x) OSSwapHostToLittleInt64(x) +# define be64toh(x) OSSwapBigToHostInt64(x) +# define le64toh(x) OSSwapLittleToHostInt64(x) + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#elif defined(__OpenBSD__) + +# include + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) + +# include + +# define be16toh(x) betoh16(x) +# define le16toh(x) letoh16(x) + +# define be32toh(x) betoh32(x) +# define le32toh(x) letoh32(x) + +# define be64toh(x) betoh64(x) +# define le64toh(x) letoh64(x) + +#elif defined(__WINDOWS__) + +# include +#ifdef __MINGW32__ +# include +#endif + +# if BYTE_ORDER == LITTLE_ENDIAN + +# define htobe16(x) htons(x) +# define htole16(x) (x) +# define be16toh(x) ntohs(x) +# define le16toh(x) (x) + +# define htobe32(x) htonl(x) +# define htole32(x) (x) +# define be32toh(x) ntohl(x) +# define le32toh(x) (x) + +# define htobe64(x) htonll(x) +# define htole64(x) (x) +# define be64toh(x) ntohll(x) +# define le64toh(x) (x) + +# elif BYTE_ORDER == BIG_ENDIAN + + /* that would be xbox 360 */ +# define htobe16(x) (x) +# define htole16(x) __builtin_bswap16(x) +# define be16toh(x) (x) +# define le16toh(x) __builtin_bswap16(x) + +# define htobe32(x) (x) +# define htole32(x) __builtin_bswap32(x) +# define be32toh(x) (x) +# define le32toh(x) __builtin_bswap32(x) + +# define htobe64(x) (x) +# define htole64(x) __builtin_bswap64(x) +# define be64toh(x) (x) +# define le64toh(x) __builtin_bswap64(x) + +# else + +# error byte order not supported + +# endif + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#else + +# error platform not supported + +#endif + +#endif diff --git a/lib/tgchat/ext/td/td/generate/tl-parser/tl-parser-tree.h b/lib/tgchat/ext/td/td/generate/tl-parser/tl-parser-tree.h new file mode 100644 index 00000000..fba7c675 --- /dev/null +++ b/lib/tgchat/ext/td/td/generate/tl-parser/tl-parser-tree.h @@ -0,0 +1,178 @@ +/* + This file is part of tgl-library + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Copyright Vitaly Valtman 2013-2014 +*/ +#ifndef __TREE_H__ +#define __TREE_H__ +#include + +#include +#include + +#pragma pack(push,4) +#define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \ +struct tree_ ## X_NAME { \ + struct tree_ ## X_NAME *left, *right;\ + X_TYPE x;\ + int y;\ +};\ +\ +static struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\ + struct tree_ ## X_NAME *T = malloc (sizeof (*T));\ + T->x = x;\ + T->y = y;\ + T->left = T->right = 0;\ + return T;\ +}\ +\ +static void delete_tree_node_ ## X_NAME (struct tree_ ## X_NAME *T) {\ + free (T);\ +}\ +\ +static void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## X_NAME **L, struct tree_ ## X_NAME **R) {\ + if (!T) {\ + *L = *R = 0;\ + } else {\ + int c = X_CMP (x, T->x);\ + if (c < 0) {\ + tree_split_ ## X_NAME (T->left, x, L, &T->left);\ + *R = T;\ + } else {\ + tree_split_ ## X_NAME (T->right, x, &T->right, R);\ + *L = T;\ + }\ + }\ +}\ +\ +static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) __attribute__ ((warn_unused_result,unused));\ +static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) {\ + if (!T) {\ + return new_tree_node_ ## X_NAME (x, y);\ + } else {\ + if (y > T->y) {\ + struct tree_ ## X_NAME *N = new_tree_node_ ## X_NAME (x, y);\ + tree_split_ ## X_NAME (T, x, &N->left, &N->right);\ + return N;\ + } else {\ + int c = X_CMP (x, T->x);\ + assert (c);\ + if (c < 0) { \ + T->left = tree_insert_ ## X_NAME (T->left, x, y);\ + } else { \ + T->right = tree_insert_ ## X_NAME (T->right, x, y);\ + } \ + return T; \ + }\ + }\ +}\ +\ +static struct tree_ ## X_NAME *tree_merge_ ## X_NAME (struct tree_ ## X_NAME *L, struct tree_ ## X_NAME *R) {\ + if (!L || !R) {\ + return L ? L : R;\ + } else {\ + if (L->y > R->y) {\ + L->right = tree_merge_ ## X_NAME (L->right, R);\ + return L;\ + } else {\ + R->left = tree_merge_ ## X_NAME (L, R->left);\ + return R;\ + }\ + }\ +}\ +\ +static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((warn_unused_result,unused));\ +static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ + assert (T);\ + int c = X_CMP (x, T->x);\ + if (!c) {\ + struct tree_ ## X_NAME *N = tree_merge_ ## X_NAME (T->left, T->right);\ + delete_tree_node_ ## X_NAME (T);\ + return N;\ + } else {\ + if (c < 0) { \ + T->left = tree_delete_ ## X_NAME (T->left, x); \ + } else { \ + T->right = tree_delete_ ## X_NAME (T->right, x); \ + } \ + return T; \ + }\ +}\ +\ +static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *t) __attribute__ ((unused));\ +static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *T) {\ + if (!T) { return X_UNSET; } \ + while (T->left) { T = T->left; }\ + return T->x; \ +} \ +\ +static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((unused));\ +static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ + int c;\ + while (T && (c = X_CMP (x, T->x))) {\ + T = (c < 0 ? T->left : T->right);\ + }\ + return T ? T->x : X_UNSET;\ +}\ +\ +static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) __attribute__ ((unused));\ +static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) {\ + if (!T) { return; } \ + tree_act_ ## X_NAME (T->left, act); \ + act (T->x); \ + tree_act_ ## X_NAME (T->right, act); \ +}\ +\ +static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) __attribute__ ((unused));\ +static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) {\ + if (!T) { return; } \ + tree_act_ex_ ## X_NAME (T->left, act, extra); \ + act (T->x, extra); \ + tree_act_ex_ ## X_NAME (T->right, act, extra); \ +}\ +\ +static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ +static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \ + if (!T) { return 0; }\ + return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \ +}\ +static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ +static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \ + if (!T) { return; }\ + if (T->left) { \ + assert (T->left->y <= T->y);\ + assert (X_CMP (T->left->x, T->x) < 0); \ + }\ + if (T->right) { \ + assert (T->right->y <= T->y);\ + assert (X_CMP (T->right->x, T->x) > 0); \ + }\ + tree_check_ ## X_NAME (T->left); \ + tree_check_ ## X_NAME (T->right); \ +}\ +static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ +static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) { \ + if (!T) { return 0; }\ + tree_clear_ ## X_NAME (T->left); \ + tree_clear_ ## X_NAME (T->right); \ + delete_tree_node_ ## X_NAME (T); \ + return 0; \ +} \ + +#define int_cmp(a,b) ((a) - (b)) +#pragma pack(pop) +#endif diff --git a/lib/tgchat/ext/td/td/generate/tl-parser/tl-parser.c b/lib/tgchat/ext/td/td/generate/tl-parser/tl-parser.c new file mode 100644 index 00000000..66276ba0 --- /dev/null +++ b/lib/tgchat/ext/td/td/generate/tl-parser/tl-parser.c @@ -0,0 +1,3078 @@ +/* + This file is part of tl-parser + + tl-parser is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + tl-parser is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this tl-parser. If not, see . + + Copyright Vitaly Valtman 2014 + + It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) + Copyright 2012-2013 Vkontakte Ltd + 2012-2013 Vitaliy Valtman + +*/ + +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "portable_endian.h" +#include "tl-parser-tree.h" +#include "tl-parser.h" +#include "crc32.h" +#include "tl-tl.h" + +extern int verbosity; +extern int schema_version; +extern int output_expressions; + + +int total_types_num; +int total_constructors_num; +int total_functions_num; + + +/*char *tstrdup (const char *s) { + assert (s); + char *r = talloc (strlen (s) + 1); + memcpy (r, s, strlen (s) + 1); + return r; +}*/ + +#define talloc(a) malloc(a) +#define tfree(a,b) free (a) +#define talloc0(a) calloc(a,1) +#define tstrdup(a) strdup(a) + +typedef char error_int_must_be_4_byte[(sizeof (int) == 4) ? 1 : -1]; +typedef char error_long_long_must_be_8_byte[(sizeof (long long) == 8) ? 1 : -1]; + +char curch; +struct parse parse; + +struct tree *tree; + +struct tree *tree_alloc (void) { + struct tree *T = talloc (sizeof (*T)); + assert (T); + memset (T, 0, sizeof (*T)); + return T; +} + +void tree_add_child (struct tree *P, struct tree *C) { + if (P->nc == P->size) { + void **t = talloc (sizeof (void *) * (++P->size)); + memcpy (t, P->c, sizeof (void *) * (P->size - 1)); + if (P->c) { + tfree (P->c, sizeof (void *) * (P->size - 1)); + } + P->c = (void *)t; + assert (P->c); + } + P->c[P->nc ++] = C; +} + +void tree_delete (struct tree *T) { + assert (T); + int i; + for (i = 0; i < T->nc; i++) { + assert (T->c[i]); + tree_delete (T->c[i]); + } + if (T->c) { + tfree (T->c, sizeof (void *) * T->nc); + } + tfree (T, sizeof (*T)); +} + +void tree_del_child (struct tree *P) { + assert (P->nc); + tree_delete (P->c[--P->nc]); +} + + +char nextch (void) { + if (parse.pos < parse.len - 1) { + curch = parse.text[++parse.pos]; + } else { + curch = 0; + } + if (curch == 10) { + parse.line ++; + parse.line_pos = 0; + } else { + if (curch) { + parse.line_pos ++; + } + } + return curch; +} + + +struct parse save_parse (void) { + return parse; +} + +void load_parse (struct parse _parse) { + parse = _parse; + curch = parse.pos > parse.len ? 0: parse.text[parse.pos] ; +} + +int is_whitespace (char c) { + return (c <= 32); +} + +int is_uletter (char c) { + return (c >= 'A' && c <= 'Z'); +} + +int is_lletter (char c) { + return (c >= 'a' && c <= 'z'); +} + +int is_letter (char c) { + return is_uletter (c) || is_lletter (c); +} + +int is_digit (char c) { + return (c >= '0' && c <= '9'); +} + +int is_hexdigit (char c) { + return is_digit (c) || (c >= 'a' && c <= 'f'); +} + +int is_ident_char (char c) { + return is_digit (c) || is_letter (c) || c == '_'; +} + +int last_error_pos; +int last_error_line; +int last_error_line_pos; +char *last_error; + +void parse_error (const char *e) { + if (parse.pos > last_error_pos) { + last_error_pos = parse.pos; + last_error_line = parse.line; + last_error_line_pos = parse.line_pos; + if (last_error) { + tfree (last_error, strlen (last_error) + 1); + } + last_error = tstrdup (e); + } +} + +void tl_print_parse_error (void) { + fprintf (stderr, "Error near line %d pos %d: `%s`\n", last_error_line + 1, last_error_line_pos + 1, last_error); +} + +char *parse_lex (void) { + while (1) { + while (curch && is_whitespace (curch)) { nextch (); } + if (curch == '/' && nextch () == '/') { + while (nextch () != 10); + nextch (); + } else { + break; + } + } + if (!curch) { + parse.lex.len = 0; + parse.lex.type = lex_eof; + return (parse.lex.ptr = 0); + } + char *p = parse.text + parse.pos; + parse.lex.flags = 0; + switch (curch) { + case '-': + if (nextch () != '-' || nextch () != '-') { + parse_error ("Can not parse triple minus"); + parse.lex.type = lex_error; + return (parse.lex.ptr = (void *)-1); + } else { + parse.lex.len = 3; + parse.lex.type = lex_triple_minus; + nextch (); + return (parse.lex.ptr = p); + } + case ':': + case ';': + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case '=': + case '#': + case '?': + case '%': + case '<': + case '>': + case '+': + case ',': + case '*': + case '_': + case '!': + case '.': + nextch (); + parse.lex.len = 1; + parse.lex.type = lex_char; + return (parse.lex.ptr = p); + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + parse.lex.flags = 0; + if (is_uletter (curch)) { + while (is_ident_char (nextch ())); + parse.lex.len = parse.text + parse.pos - p; + parse.lex.ptr = p; + if (parse.lex.len == 5 && !memcmp (parse.lex.ptr, "Final", 5)) { + parse.lex.type = lex_final; + } else if (parse.lex.len == 3 && !memcmp (parse.lex.ptr, "New", 3)) { + parse.lex.type = lex_new; + } else if (parse.lex.len == 5 && !memcmp (parse.lex.ptr, "Empty", 5)) { + parse.lex.type = lex_empty; + } else { + parse.lex.type = lex_uc_ident; + } + return (parse.lex.ptr = p); + } + while (is_ident_char (nextch ())); + if (curch == '.' && !is_letter (parse.text[parse.pos + 1])) { + parse.lex.len = parse.text + parse.pos - p; + parse.lex.type = lex_lc_ident; + return (parse.lex.ptr = p); + } + while (curch == '.') { + parse.lex.flags |= 1; + nextch (); + if (is_uletter (curch)) { + while (is_ident_char (nextch ())); + parse.lex.len = parse.text + parse.pos - p; + parse.lex.type = lex_uc_ident; + return (parse.lex.ptr = p); + } + if (is_lletter (curch)) { + while (is_ident_char (nextch ())); + } else { + parse_error ("Expected letter"); + parse.lex.type = lex_error; + return (parse.lex.ptr = (void *)-1); + } + } + if (curch == '#') { + parse.lex.flags |= 2; + int i; + int ok = 1; + for (i = 0; i < 8; i++) { + if (!is_hexdigit (nextch())) { + if (curch == ' ' && i >= 5) { + ok = 2; + break; + } else { + parse_error ("Hex digit expected"); + parse.lex.type = lex_error; + return (parse.lex.ptr = (void *)-1); + } + } + } + if (ok == 1) { + nextch (); + } + } + parse.lex.len = parse.text + parse.pos - p; + parse.lex.type = lex_lc_ident; + return (parse.lex.ptr = p); + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + while (is_digit (nextch ())); + parse.lex.len = parse.text + parse.pos - p; + parse.lex.type = lex_num; + return (parse.lex.ptr = p); + default: + parse_error ("Unknown lexem"); + parse.lex.type = lex_error; + return (parse.lex.ptr = (void *)-1); + } + +} + +int expect (char *s) { + if (!parse.lex.ptr || parse.lex.ptr == (void *)-1 || parse.lex.type == lex_error || parse.lex.type == lex_none || parse.lex.len != (int)strlen (s) || memcmp (s, parse.lex.ptr, parse.lex.len)) { + static char buf[1000]; + sprintf (buf, "Expected %s", s); + parse_error (buf); + return -1; + } else { + parse_lex (); + } + return 1; +} + +struct parse *tl_init_parse_file (const char *fname) { + FILE *f = fopen (fname, "rb"); + if (f == NULL) { + fprintf (stderr, "Failed to open the input file.\n"); + return NULL; + } + if (fseek (f, 0, SEEK_END) != 0) { + fprintf (stderr, "Can't seek to the end of the input file.\n"); + return NULL; + } + long size = ftell (f); + if (size <= 0 || size > INT_MAX) { + fprintf (stderr, "Size is %ld. Too small or too big.\n", size); + return NULL; + } + fseek (f, 0, SEEK_SET); + + static struct parse save; + save.text = talloc ((size_t)size); + save.len = fread (save.text, 1, (size_t)size, f); + assert (save.len == size); + fclose (f); + save.pos = 0; + save.line = 0; + save.line_pos = 0; + save.lex.ptr = save.text; + save.lex.len = 0; + save.lex.type = lex_none; + return &save; +} + +#define PARSE_INIT(_type) struct parse save = save_parse (); struct tree *T = tree_alloc (); T->type = (_type); T->lex_line = parse.line; T->lex_line_pos = parse.line_pos; struct tree *S __attribute__ ((unused)); +#define PARSE_FAIL load_parse (save); tree_delete (T); return 0; +#define PARSE_OK return T; +#define PARSE_TRY_PES(x) if (!(S = x ())) { PARSE_FAIL; } { tree_add_child (T, S); } +#define PARSE_TRY_OPT(x) if ((S = x ())) { tree_add_child (T, S); PARSE_OK } +#define PARSE_TRY(x) S = x (); +#define PARSE_ADD(_type) S = tree_alloc (); S->type = _type; tree_add_child (T, S); +#define EXPECT(s) if (expect (s) < 0) { PARSE_FAIL; } +#define LEX_CHAR(c) (parse.lex.type == lex_char && *parse.lex.ptr == c) +struct tree *parse_args (void); +struct tree *parse_expr (void); + +struct tree *parse_boxed_type_ident (void) { + PARSE_INIT (type_boxed_type_ident); + if (parse.lex.type != lex_uc_ident) { + parse_error ("Can not parse boxed type"); + PARSE_FAIL; + } else { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } +} + +struct tree *parse_full_combinator_id (void) { + PARSE_INIT (type_full_combinator_id); + if (parse.lex.type == lex_lc_ident || LEX_CHAR('_')) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else { + parse_error ("Can not parse full combinator id"); + PARSE_FAIL; + } +} + +struct tree *parse_combinator_id (void) { + PARSE_INIT (type_combinator_id); + if (parse.lex.type == lex_lc_ident && !(parse.lex.flags & 2)) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else { + parse_error ("Can not parse combinator id"); + PARSE_FAIL; + } +} + +struct tree *parse_var_ident (void) { + PARSE_INIT (type_var_ident); + if ((parse.lex.type == lex_lc_ident || parse.lex.type == lex_uc_ident) && !(parse.lex.flags & 3)) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else { + parse_error ("Can not parse var ident"); + PARSE_FAIL; + } +} + +struct tree *parse_var_ident_opt (void) { + PARSE_INIT (type_var_ident_opt); + if ((parse.lex.type == lex_lc_ident || parse.lex.type == lex_uc_ident)&& !(parse.lex.flags & 3)) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else if (LEX_CHAR ('_')) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else { + parse_error ("Can not parse var ident opt"); + PARSE_FAIL; + } +} + +struct tree *parse_nat_const (void) { + PARSE_INIT (type_nat_const); + if (parse.lex.type == lex_num) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else { + parse_error ("Can not parse nat const"); + PARSE_FAIL; + } +} + +struct tree *parse_type_ident (void) { + PARSE_INIT (type_type_ident); + if (parse.lex.type == lex_uc_ident && !(parse.lex.flags & 2)) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else if (parse.lex.type == lex_lc_ident && !(parse.lex.flags & 2)) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else if (LEX_CHAR ('#')) { + T->text = parse.lex.ptr; + T->len = parse.lex.len; + T->flags = parse.lex.flags; + parse_lex (); + PARSE_OK; + } else { + parse_error ("Can not parse type ident"); + PARSE_FAIL; + } +} + +struct tree *parse_term (void) { + PARSE_INIT (type_term); + while (LEX_CHAR ('%')) { + EXPECT ("%") + PARSE_ADD (type_percent); + } + if (LEX_CHAR ('(')) { + EXPECT ("("); + PARSE_TRY_PES (parse_expr); + EXPECT (")"); + PARSE_OK; + } + PARSE_TRY (parse_type_ident); + if (S) { + tree_add_child (T, S); + if (LEX_CHAR ('<')) { + EXPECT ("<"); + while (1) { + PARSE_TRY_PES (parse_expr); + if (LEX_CHAR ('>')) { break; } + EXPECT (","); + } + EXPECT (">"); + } + PARSE_OK; + } + PARSE_TRY_OPT (parse_type_ident); + PARSE_TRY_OPT (parse_var_ident); + PARSE_TRY_OPT (parse_nat_const); + PARSE_FAIL; +} + +struct tree *parse_nat_term (void) { + PARSE_INIT (type_nat_term); + PARSE_TRY_PES (parse_term); + PARSE_OK; +} + +struct tree *parse_subexpr (void) { + PARSE_INIT (type_subexpr); + int was_term = 0; + int cc = 0; + + while (1) { + PARSE_TRY (parse_nat_const); + if (S) { + tree_add_child (T, S); + } else if (!was_term) { + was_term = 1; + PARSE_TRY (parse_term); + if (S) { + tree_add_child (T, S); + } else { + break; + } + } + cc ++; + if (!LEX_CHAR ('+')) { + break; + } + EXPECT ("+"); + } + if (!cc) { + PARSE_FAIL; + } else { + PARSE_OK; + } +} + +struct tree *parse_expr (void) { + PARSE_INIT (type_expr); + int cc = 0; + while (1) { + PARSE_TRY (parse_subexpr); + if (S) { + tree_add_child (T, S); + cc ++; + } else { + if (cc < 1) { PARSE_FAIL; } + else { PARSE_OK; } + } + } +} + + + +struct tree *parse_final_empty (void) { + PARSE_INIT (type_final_empty); + EXPECT ("Empty"); + PARSE_TRY_PES (parse_boxed_type_ident); + PARSE_OK; +} + +struct tree *parse_final_new (void) { + PARSE_INIT (type_final_new); + EXPECT ("New"); + PARSE_TRY_PES (parse_boxed_type_ident); + PARSE_OK; +} + +struct tree *parse_final_final (void) { + PARSE_INIT (type_final_final); + EXPECT ("Final"); + PARSE_TRY_PES (parse_boxed_type_ident); + PARSE_OK; +} + +struct tree *parse_partial_comb_app_decl (void) { + PARSE_INIT (type_partial_comb_app_decl); + PARSE_TRY_PES (parse_combinator_id); + while (1) { + PARSE_TRY_PES (parse_subexpr); + if (LEX_CHAR (';')) { break; } + } + PARSE_OK; +} + +struct tree *parse_partial_type_app_decl (void) { + PARSE_INIT (type_partial_type_app_decl); + PARSE_TRY_PES (parse_boxed_type_ident); + if (LEX_CHAR ('<')) { + EXPECT ("<"); + while (1) { + PARSE_TRY_PES (parse_expr); + if (LEX_CHAR ('>')) { break; } + EXPECT (","); + } + EXPECT (">"); + PARSE_OK; + } else { + while (1) { + PARSE_TRY_PES (parse_subexpr); + if (LEX_CHAR (';')) { break; } + } + PARSE_OK; + } +} + + + + +struct tree *parse_multiplicity (void) { + PARSE_INIT (type_multiplicity); + PARSE_TRY_PES (parse_nat_term); + PARSE_OK; +} + + +struct tree *parse_type_term (void) { + PARSE_INIT (type_type_term); + PARSE_TRY_PES (parse_term); + PARSE_OK; +} + +struct tree *parse_optional_arg_def (void) { + PARSE_INIT (type_optional_arg_def); + PARSE_TRY_PES (parse_var_ident); + EXPECT ("."); + PARSE_TRY_PES (parse_nat_const); + EXPECT ("?"); + PARSE_OK; +} + +struct tree *parse_args4 (void) { + PARSE_INIT (type_args4); + struct parse so = save_parse (); + PARSE_TRY (parse_optional_arg_def); + if (S) { + tree_add_child (T, S); + } else { + load_parse (so); + } + if (LEX_CHAR ('!')) { + PARSE_ADD (type_exclam); + EXPECT ("!"); + } + PARSE_TRY_PES (parse_type_term); + PARSE_OK; +} + +struct tree *parse_args3 (void) { + PARSE_INIT (type_args3); + PARSE_TRY_PES (parse_var_ident_opt); + EXPECT (":"); + struct parse so = save_parse (); + PARSE_TRY (parse_optional_arg_def); + if (S) { + tree_add_child (T, S); + } else { + load_parse (so); + } + if (LEX_CHAR ('!')) { + PARSE_ADD (type_exclam); + EXPECT ("!"); + } + PARSE_TRY_PES (parse_type_term); + PARSE_OK; +} + +struct tree *parse_args2 (void) { + PARSE_INIT (type_args2); + PARSE_TRY (parse_var_ident_opt); + if (S && LEX_CHAR (':')) { + tree_add_child (T, S); + EXPECT (":"); + } else { + load_parse (save); + } + struct parse so = save_parse (); + PARSE_TRY (parse_optional_arg_def); + if (S) { + tree_add_child (T, S); + } else { + load_parse (so); + } + struct parse save2 = save_parse (); + PARSE_TRY (parse_multiplicity); + if (S && LEX_CHAR ('*')) { + tree_add_child (T, S); + EXPECT ("*"); + } else { + load_parse (save2); + } + EXPECT ("["); + while (1) { + if (LEX_CHAR (']')) { break; } + PARSE_TRY_PES (parse_args); + } + EXPECT ("]"); + PARSE_OK; +} + +struct tree *parse_args1 (void) { + PARSE_INIT (type_args1); + EXPECT ("("); + while (1) { + PARSE_TRY_PES (parse_var_ident_opt); + if (LEX_CHAR(':')) { break; } + } + EXPECT (":"); + struct parse so = save_parse (); + PARSE_TRY (parse_optional_arg_def); + if (S) { + tree_add_child (T, S); + } else { + load_parse (so); + } + if (LEX_CHAR ('!')) { + PARSE_ADD (type_exclam); + EXPECT ("!"); + } + PARSE_TRY_PES (parse_type_term); + EXPECT (")"); + PARSE_OK; +} + +struct tree *parse_args (void) { + PARSE_INIT (type_args); + PARSE_TRY_OPT (parse_args1); + PARSE_TRY_OPT (parse_args2); + PARSE_TRY_OPT (parse_args3); + PARSE_TRY_OPT (parse_args4); + PARSE_FAIL; +} + +struct tree *parse_opt_args (void) { + PARSE_INIT (type_opt_args); + while (1) { + PARSE_TRY_PES (parse_var_ident); + if (parse.lex.type == lex_char && *parse.lex.ptr == ':') { break;} + } + EXPECT (":"); + PARSE_TRY_PES (parse_type_term); + PARSE_OK; +} + +struct tree *parse_final_decl (void) { + PARSE_INIT (type_final_decl); + PARSE_TRY_OPT (parse_final_new); + PARSE_TRY_OPT (parse_final_final); + PARSE_TRY_OPT (parse_final_empty); + PARSE_FAIL; +} + +struct tree *parse_partial_app_decl (void) { + PARSE_INIT (type_partial_app_decl); + PARSE_TRY_OPT (parse_partial_type_app_decl); + PARSE_TRY_OPT (parse_partial_comb_app_decl); + PARSE_FAIL; +} + +struct tree *parse_result_type (void) { + PARSE_INIT (type_result_type); + PARSE_TRY_PES (parse_boxed_type_ident); + if (LEX_CHAR ('<')) { + EXPECT ("<"); + while (1) { + PARSE_TRY_PES (parse_expr); + if (LEX_CHAR ('>')) { break; } + EXPECT (","); + } + EXPECT (">"); + PARSE_OK; + } else { + while (1) { + if (LEX_CHAR (';')) { PARSE_OK; } + PARSE_TRY_PES (parse_subexpr); + } + } +} + +struct tree *parse_combinator_decl (void) { + PARSE_INIT (type_combinator_decl); + PARSE_TRY_PES (parse_full_combinator_id) + while (1) { + if (LEX_CHAR ('{')) { + parse_lex (); + PARSE_TRY_PES (parse_opt_args); + EXPECT ("}"); + } else { + break; + } + } + while (1) { + if (LEX_CHAR ('=')) { break; } + PARSE_TRY_PES (parse_args); + } + EXPECT ("="); + PARSE_ADD (type_equals); + + PARSE_TRY_PES (parse_result_type); + PARSE_OK; +} + +struct tree *parse_builtin_combinator_decl (void) { + PARSE_INIT (type_builtin_combinator_decl); + PARSE_TRY_PES (parse_full_combinator_id) + EXPECT ("?"); + EXPECT ("="); + PARSE_TRY_PES (parse_boxed_type_ident); + PARSE_OK; +} + +struct tree *parse_declaration (void) { + PARSE_INIT (type_declaration); + PARSE_TRY_OPT (parse_combinator_decl); + PARSE_TRY_OPT (parse_partial_app_decl); + PARSE_TRY_OPT (parse_final_decl); + PARSE_TRY_OPT (parse_builtin_combinator_decl); + PARSE_FAIL; +} + +struct tree *parse_constr_declarations (void) { + PARSE_INIT (type_constr_declarations); + if (parse.lex.type == lex_triple_minus || parse.lex.type == lex_eof) { PARSE_OK; } + while (1) { + PARSE_TRY_PES (parse_declaration); + EXPECT (";"); + if (parse.lex.type == lex_eof || parse.lex.type == lex_triple_minus) { PARSE_OK; } + } +} + +struct tree *parse_fun_declarations (void) { + PARSE_INIT (type_fun_declarations); + if (parse.lex.type == lex_triple_minus || parse.lex.type == lex_eof) { PARSE_OK; } + while (1) { + PARSE_TRY_PES (parse_declaration); + EXPECT (";"); + if (parse.lex.type == lex_eof || parse.lex.type == lex_triple_minus) { PARSE_OK; } + } +} + +struct tree *parse_program (void) { + PARSE_INIT (type_tl_program); + while (1) { + PARSE_TRY_PES (parse_constr_declarations); + if (parse.lex.type == lex_eof) { PARSE_OK; } + if (parse.lex.type == lex_error || expect ("---") < 0 || expect ("functions") < 0 || expect ("---") < 0) { PARSE_FAIL; } + + PARSE_TRY_PES (parse_fun_declarations); + if (parse.lex.type == lex_eof) { PARSE_OK; } + if (parse.lex.type == lex_error || expect ("---") < 0 || expect ("types") < 0 || expect ("---") < 0) { PARSE_FAIL; } + } +} + +struct tree *tl_parse_lex (struct parse *_parse) { + assert (_parse); + load_parse (*_parse); + if (parse.lex.type == lex_none) { + parse_lex (); + } + if (parse.lex.type == lex_error) { + return 0; + } + return parse_program (); +} + +int mystrcmp2 (const char *b, int len, const char *a) { + int c = strncmp (b, a, len); + return c ? a[len] ? -1 : 0 : c; +} + +char *mystrdup (const char *a, int len) { + char *z = talloc (len + 1); + memcpy (z, a, len); + z[len] = 0; + return z; +} + +struct tl_program *tl_program_cur; +#define TL_TRY_PES(x) if (!(x)) { return 0; } + +#define tl_type_cmp(a,b) (strcmp (a->id, b->id)) +DEFINE_TREE (tl_type,struct tl_type *,tl_type_cmp,0) +struct tree_tl_type *tl_type_tree; + +DEFINE_TREE (tl_constructor,struct tl_constructor *,tl_type_cmp,0) +struct tree_tl_constructor *tl_constructor_tree; +struct tree_tl_constructor *tl_function_tree; + +DEFINE_TREE (tl_var,struct tl_var *,tl_type_cmp,0) + +struct tl_var_value { + struct tl_combinator_tree *ptr; + struct tl_combinator_tree *val; + int num_val; +}; + +#define tl_var_value_cmp(a,b) (((char *)a.ptr) - ((char *)b.ptr)) +struct tl_var_value empty; +DEFINE_TREE (var_value, struct tl_var_value, tl_var_value_cmp, empty) +//tree_tl_var_t *tl_var_tree; + +DEFINE_TREE (tl_field,char *,strcmp, 0) +//tree_tl_field_t *tl_field_tree; +#define TL_FAIL return 0; +#define TL_INIT(x) struct tl_combinator_tree *x = 0; +#define TL_TRY(f,x) { struct tl_combinator_tree *_t = f; if (!_t) { TL_FAIL;} x = tl_union (x, _t); if (!x) { TL_FAIL; }} +#define TL_ERROR(...) fprintf (stderr, __VA_ARGS__); +#define TL_WARNING(...) fprintf (stderr, __VA_ARGS__); + +void tl_set_var_value (struct tree_var_value **T, struct tl_combinator_tree *var, struct tl_combinator_tree *value) { + struct tl_var_value t = {.ptr = var, .val = value, .num_val = 0}; + if (tree_lookup_var_value (*T, t).ptr) { + *T = tree_delete_var_value (*T, t); + } + *T = tree_insert_var_value (*T, t, lrand48 ()); +} + +void tl_set_var_value_num (struct tree_var_value **T, struct tl_combinator_tree *var, struct tl_combinator_tree *value, long long num_value) { + struct tl_var_value t = {.ptr = var, .val = value, .num_val = num_value}; + if (tree_lookup_var_value (*T, t).ptr) { + *T = tree_delete_var_value (*T, t); + } + *T = tree_insert_var_value (*T, t, lrand48 ()); +} + +struct tl_combinator_tree *tl_get_var_value (struct tree_var_value **T, struct tl_combinator_tree *var) { + struct tl_var_value t = {.ptr = var, .val = 0, .num_val = 0}; + struct tl_var_value r = tree_lookup_var_value (*T, t); + return r.ptr ? r.val : 0; +} + +int tl_get_var_value_num (struct tree_var_value **T, struct tl_combinator_tree *var) { + struct tl_var_value t = {.ptr = var, .val = 0}; + struct tl_var_value r = tree_lookup_var_value (*T, t); + return r.ptr ? r.num_val : 0; +} + +int namespace_level; + +struct tree_tl_var *vars[10]; +struct tree_tl_field *fields[10]; +struct tl_var *last_num_var[10]; + +int tl_is_type_name (const char *id, int len) { + if (len == 1 && *id == '#') { return 1;} + int ok = id[0] >= 'A' && id[0] <= 'Z'; + int i; + for (i = 0; i < len - 1; i++) if (id[i] == '.') { + ok = id[i + 1] >= 'A' && id[i + 1] <= 'Z'; + } + return ok; +} + +int tl_add_field (char *id) { + assert (namespace_level < 10); + assert (namespace_level >= 0); + if (tree_lookup_tl_field (fields[namespace_level], id)) { + return 0; + } + fields[namespace_level] = tree_insert_tl_field (fields[namespace_level], id, lrand48 ()); + return 1; +} + +void tl_clear_fields (void) { +// tree_act_tl_field (fields[namespace_level], (void *)free); + fields[namespace_level] = tree_clear_tl_field (fields[namespace_level]); +} + +struct tl_var *tl_add_var (char *id, struct tl_combinator_tree *ptr, int type) { + struct tl_var *v = talloc (sizeof (*v)); + v->id = tstrdup (id); + v->type = type; + v->ptr = ptr; + v->flags = 0; + if (tree_lookup_tl_var (vars[namespace_level], v)) { + return 0; + } + vars[namespace_level] = tree_insert_tl_var (vars[namespace_level], v, lrand48 ()); + if (type) { + last_num_var[namespace_level] = v; + } + return v; +} + +void tl_del_var (struct tl_var *v) { +// free (v->id); + tfree (v, sizeof (*v)); +} + +void tl_clear_vars (void) { + tree_act_tl_var (vars[namespace_level], tl_del_var); + vars[namespace_level] = tree_clear_tl_var (vars[namespace_level]); + last_num_var[namespace_level] = 0; +} + +struct tl_var *tl_get_last_num_var (void) { + return last_num_var[namespace_level]; +} + +struct tl_var *tl_get_var (char *_id, int len) { + char *id = mystrdup (_id, len); + struct tl_var v = {.id = id}; + int i; + for (i = namespace_level; i >= 0; i--) { + struct tl_var *w = tree_lookup_tl_var (vars[i], &v); + if (w) { + tfree (id, len + 1); + return w; + } + } + tfree (id, len + 1); + return 0; +} + +void namespace_push (void) { + namespace_level ++; + assert (namespace_level < 10); + tl_clear_vars (); + tl_clear_fields (); +} + +void namespace_pop (void) { + namespace_level --; + assert (namespace_level >= 0); +} + +struct tl_type *tl_get_type (const char *_id, int len) { + char *id = mystrdup (_id, len); + struct tl_type _t = {.id = id}; + struct tl_type *r = tree_lookup_tl_type (tl_type_tree, &_t); + tfree (id, len + 1); + return r; +} + +struct tl_type *tl_add_type (const char *_id, int len, int params_num, long long params_types) { + char *id = talloc (len + 1); + memcpy (id, _id, len); + id[len] = 0; + struct tl_type _t = {.id = id}; + struct tl_type *_r = 0; + if ((_r = tree_lookup_tl_type (tl_type_tree, &_t))) { + tfree (id, len + 1); + if (params_num >= 0 && (_r->params_num != params_num || _r->params_types != params_types)) { + TL_ERROR ("Wrong params_num or types for type %s\n", _r->id); + return 0; + } + return _r; + } + struct tl_type *t = talloc (sizeof (*t)); + t->id = id; + t->print_id = tstrdup (t->id); + int i; + for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') { + t->print_id[i] = '$'; + } + t->name = 0; + t->constructors_num = 0; + t->constructors = 0; + t->flags = 0; + t->real_id = 0; + if (params_num >= 0) { + assert (params_num <= 64); + t->params_num = params_num; + t->params_types = params_types; + } else { + t->flags |= 4; + t->params_num = -1; + } + tl_type_tree = tree_insert_tl_type (tl_type_tree, t, lrand48 ()); + total_types_num ++; + return t; +} + +void tl_add_type_param (struct tl_type *t, int x) { + assert (t->flags & 4); + assert (t->params_num <= 64); + if (x) { + t->params_types |= (1ull << (t->params_num ++)); + } else { + t->params_num ++; + } +} + +int tl_type_set_params (struct tl_type *t, int x, long long y) { + if (t->flags & 4) { + t->params_num = x; + t->params_types = y; + t->flags &= ~4; + } else { + if (t->params_num != x || t->params_types != y) { + fprintf (stderr, "Wrong num of params (type %s)\n", t->id); + return 0; + } + } + return 1; +} + +void tl_type_finalize (struct tl_type *t) { + t->flags &= ~4; +} + +struct tl_constructor *tl_get_constructor (const char *_id, int len) { + char *id = mystrdup (_id, len); + struct tl_constructor _t = {.id = id}; + struct tl_constructor *r = tree_lookup_tl_constructor (tl_constructor_tree, &_t); + tfree (id, len + 1); + return r; +} + +struct tl_constructor *tl_add_constructor (struct tl_type *a, const char *_id, int len, int force_magic) { + assert (a); + if (a->flags & 1) { + TL_ERROR ("New constructor for type `%s` after final statement\n", a->id); + return 0; + } + int x = 0; + while (x < len && (_id[x] != '#' || force_magic)) { x++; } + char *id = talloc (x + 1); + memcpy (id, _id, x); + id[x] = 0; + + unsigned magic = 0; + if (x < len) { + assert (len - x >= 6 && len - x <= 9); + int i; + for (i = 1; i < len - x; i++) { + magic = (magic << 4) + (_id[x + i] <= '9' ? _id[x + i] - '0' : _id[x + i] - 'a' + 10); + } + assert (magic && magic != (unsigned)-1); + } + + len = x; + if (*id != '_') { + struct tl_constructor _t = {.id = id}; + if (tree_lookup_tl_constructor (tl_constructor_tree, &_t)) { + TL_ERROR ("Duplicate constructor id `%s`\n", id); + tfree (id, len + 1); + return 0; + } + } else { + assert (len == 1); + } + + struct tl_constructor *t = talloc (sizeof (*t)); + t->type = a; + t->name = magic; + t->id = id; + t->print_id = tstrdup (id); + t->real_id = 0; + + int i; + for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') { + t->print_id[i] = '$'; + } + + t->left = t->right = 0; + a->constructors = realloc (a->constructors, sizeof (void *) * (a->constructors_num + 1)); + assert (a->constructors); + a->constructors[a->constructors_num ++] = t; + if (*id != '_') { + tl_constructor_tree = tree_insert_tl_constructor (tl_constructor_tree, t, lrand48 ()); + } else { + a->flags |= FLAG_DEFAULT_CONSTRUCTOR; + } + total_constructors_num ++; + return t; +} + +struct tl_constructor *tl_get_function (const char *_id, int len) { + char *id = mystrdup (_id, len); + struct tl_constructor _t = {.id = id}; + struct tl_constructor *r = tree_lookup_tl_constructor (tl_function_tree, &_t); + tfree (id, len + 1); + return r; +} + +struct tl_constructor *tl_add_function (struct tl_type *a, const char *_id, int len, int force_magic) { +// assert (a); + int x = 0; + while (x < len && ((_id[x] != '#') || force_magic)) { x++; } + char *id = talloc (x + 1); + memcpy (id, _id, x); + id[x] = 0; + + unsigned magic = 0; + if (x < len) { + assert (len - x >= 6 && len - x <= 9); + int i; + for (i = 1; i < len - x; i++) { + magic = (magic << 4) + (_id[x + i] <= '9' ? _id[x + i] - '0' : _id[x + i] - 'a' + 10); + } + assert (magic && magic != (unsigned)-1); + } + + len = x; + + struct tl_constructor _t = {.id = id}; + if (tree_lookup_tl_constructor (tl_function_tree, &_t)) { + TL_ERROR ("Duplicate function id `%s`\n", id); + tfree (id, len + 1); + return 0; + } + + struct tl_constructor *t = talloc (sizeof (*t)); + t->type = a; + t->name = magic; + t->id = id; + t->print_id = tstrdup (id); + t->real_id = 0; + + int i; + for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') { + t->print_id[i] = '$'; + } + + t->left = t->right = 0; + tl_function_tree = tree_insert_tl_constructor (tl_function_tree, t, lrand48 ()); + total_functions_num ++; + return t; +} + +static char buf[(1 << 20)]; +int buf_pos; + +struct tl_combinator_tree *alloc_ctree_node (void) { + struct tl_combinator_tree *T = talloc (sizeof (*T)); + assert (T); + memset (T, 0, sizeof (*T)); + return T; +} + +struct tl_combinator_tree *tl_tree_dup (struct tl_combinator_tree *T) { + if (!T) { return 0; } + struct tl_combinator_tree *S = talloc (sizeof (*S)); + memcpy (S, T, sizeof (*S)); + S->left = tl_tree_dup (T->left); + S->right = tl_tree_dup (T->right); + return S; +} + +struct tl_type *tl_tree_get_type (struct tl_combinator_tree *T) { + assert (T->type == type_type); + if (T->act == act_array) { return 0;} + while (T->left) { + T = T->left; + if (T->act == act_array) { return 0;} + assert (T->type == type_type); + } + assert (T->act == act_type || T->act == act_var || T->act == act_array); + return T->act == act_type ? T->data : 0; +} + +void tl_tree_set_len (struct tl_combinator_tree *T) { + TL_INIT (H); + H = T; + while (H->left) { + H->left->type_len = H->type_len + 1; + H = H->left; + } + assert (H->type == type_type); + struct tl_type *t = H->data; + assert (t); + assert (H->type_len == t->params_num); +} + +void tl_buf_reset (void) { + buf_pos = 0; +} + +void tl_buf_add_string (char *s, int len) { + if (len < 0) { len = strlen (s); } + buf[buf_pos ++] = ' '; + memcpy (buf + buf_pos, s, len); buf_pos += len; + buf[buf_pos] = 0; +} + +void tl_buf_add_string_nospace (char *s, int len) { + if (len < 0) { len = strlen (s); } +// if (buf_pos) { buf[buf_pos ++] = ' '; } + memcpy (buf + buf_pos, s, len); buf_pos += len; + buf[buf_pos] = 0; +} + +void tl_buf_add_string_q (char *s, int len, int x) { + if (x) { + tl_buf_add_string (s, len); + } else { + tl_buf_add_string_nospace (s, len); + } +} + + +void tl_buf_add_tree (struct tl_combinator_tree *T, int x) { + if (!T) { return; } + assert (T != (void *)-1l && T != (void *)-2l); + switch (T->act) { + case act_question_mark: + tl_buf_add_string_q ("?", -1, x); + return; + case act_type: + if ((T->flags & 1) && !(T->flags & 4)) { + tl_buf_add_string_q ("%", -1, x); + x = 0; + } + if (T->flags & 2) { + tl_buf_add_string_q ((char *)T->data, -1, x); + } else { + struct tl_type *t = T->data; + if (T->flags & 4) { + assert (t->constructors_num == 1); + tl_buf_add_string_q (t->constructors[0]->real_id ? t->constructors[0]->real_id : t->constructors[0]->id, -1, x); + } else { + tl_buf_add_string_q (t->real_id ? t->real_id : t->id, -1, x); + } + } + return; + case act_field: + if (T->data) { + tl_buf_add_string_q ((char *)T->data, -1, x); + x = 0; + tl_buf_add_string_q (":", -1, 0); + } + tl_buf_add_tree (T->left, x); + tl_buf_add_tree (T->right, 1); + return; + case act_union: + tl_buf_add_tree (T->left, x); + tl_buf_add_tree (T->right, 1); + return; + case act_var: + { + if (T->data == (void *)-1l) { return; } + struct tl_combinator_tree *v = T->data; + tl_buf_add_string_q ((char *)v->data, -1, x); + if (T->type == type_num && T->type_flags) { + static char _buf[30]; + sprintf (_buf, "+%lld", T->type_flags); + tl_buf_add_string_q (_buf, -1, 0); + } + } + return; + case act_arg: + tl_buf_add_tree (T->left, x); + tl_buf_add_tree (T->right, 1); + return; + case act_array: + if (T->left && !(T->left->flags & 128)) { + tl_buf_add_tree (T->left, x); + x = 0; + tl_buf_add_string_q ("*", -1, x); + } + tl_buf_add_string_q ("[", -1, x); + tl_buf_add_tree (T->right, 1); + tl_buf_add_string_q ("]", -1, 1); + return; + case act_plus: + tl_buf_add_tree (T->left, x); + tl_buf_add_string_q ("+", -1, 0); + tl_buf_add_tree (T->right, 0); + return; + case act_nat_const: + { + static char _buf[30]; + snprintf (_buf, 29, "%lld", T->type_flags); + tl_buf_add_string_q (_buf, -1, x); + return; + } + case act_opt_field: + { + struct tl_combinator_tree *v = T->left->data; + tl_buf_add_string_q ((char *)v->data, -1, x); + tl_buf_add_string_q (".", -1, 0); + static char _buf[30]; + sprintf (_buf, "%lld", T->left->type_flags); + tl_buf_add_string_q (_buf, -1, 0); + tl_buf_add_string_q ("?", -1, 0); + tl_buf_add_tree (T->right, 0); + return; + } + + default: + fprintf (stderr, "%s %s\n", TL_ACT (T->act), TL_TYPE (T->type)); + assert (0); + return; + } +} + +int tl_count_combinator_name (struct tl_constructor *c) { + assert (c); + tl_buf_reset (); + tl_buf_add_string_nospace (c->real_id ? c->real_id : c->id, -1); + tl_buf_add_tree (c->left, 1); + tl_buf_add_string ("=", -1); + tl_buf_add_tree (c->right, 1); + //fprintf (stderr, "%.*s\n", buf_pos, buf); + if (!c->name) { + c->name = compute_crc32 (buf, buf_pos); + } + return c->name; +} + +int tl_print_combinator (struct tl_constructor *c) { + tl_buf_reset (); + tl_buf_add_string_nospace (c->real_id ? c->real_id : c->id, -1); + static char _buf[10]; + sprintf (_buf, "#%08x", c->name); + tl_buf_add_string_nospace (_buf, -1); + tl_buf_add_tree (c->left, 1); + tl_buf_add_string ("=", -1); + tl_buf_add_tree (c->right, 1); + if (output_expressions >= 1) { + fprintf (stderr, "%.*s\n", buf_pos, buf); + } +/* if (!c->name) { + c->name = compute_crc32 (buf, buf_pos); + }*/ + return c->name; +} + +int _tl_finish_subtree (struct tl_combinator_tree *R, int x, long long y) { + assert (R->type == type_type); + assert (R->type_len < 0); + assert (R->act == act_arg || R->act == act_type); + R->type_len = x; + R->type_flags = y; + if (R->act == act_type) { + struct tl_type *t = R->data; + assert (t); + return tl_type_set_params (t, x, y); + } + assert ((R->right->type == type_type && R->right->type_len == 0) || R->right->type == type_num || R->right->type == type_num_value); + return _tl_finish_subtree (R->left, x + 1, y * 2 + (R->right->type == type_num || R->right->type == type_num_value)); +} + +int tl_finish_subtree (struct tl_combinator_tree *R) { + assert (R); + if (R->type != type_type) { + return 1; + } + if (R->type_len >= 0) { + if (R->type_len > 0) { + TL_ERROR ("Not enough params\n"); + return 0; + } + return 1; + } + return _tl_finish_subtree (R, 0, 0); +} + +struct tl_combinator_tree *tl_union (struct tl_combinator_tree *L, struct tl_combinator_tree *R) { + if (!L) { return R; } + if (!R) { return L; } + TL_INIT (v); + v = alloc_ctree_node (); + v->left = L; + v->right = R; + switch (L->type) { + case type_num: + if (R->type != type_num_value) { + TL_ERROR ("Union: type mistmatch\n"); + return 0; + } + tfree (v, sizeof (*v)); + L->type_flags += R->type_flags; + return L; + case type_num_value: + if (R->type != type_num_value && R->type != type_num) { + TL_ERROR ("Union: type mistmatch\n"); + return 0; + } + tfree (v, sizeof (*v)); + R->type_flags += L->type_flags; + return R; + case type_list_item: + case type_list: + if (R->type != type_list_item) { + TL_ERROR ("Union: type mistmatch\n"); + return 0; + } + v->type = type_list; + v->act = act_union; + return v; + case type_type: + if (L->type_len == 0) { + TL_ERROR ("Arguments number exceeds type arity\n"); + return 0; + } + if (R->type != type_num && R->type != type_type && R->type != type_num_value) { + TL_ERROR ("Union: type mistmatch\n"); + return 0; + } + if (R->type_len < 0) { + if (!tl_finish_subtree (R)) { + return 0; + } + } + if (R->type_len > 0) { + TL_ERROR ("Argument type must have full number of arguments\n"); + return 0; + } + if (L->type_len > 0 && ((L->type_flags & 1) != (R->type == type_num || R->type == type_num_value))) { + TL_ERROR ("Argument types mistmatch: L->type_flags = %lld, R->type = %s\n", L->flags, TL_TYPE (R->type)); + return 0; + } + v->type = type_type; + v->act = act_arg; + v->type_len = L->type_len > 0 ? L->type_len - 1 : -1; + v->type_flags = L->type_flags >> 1; + return v; + default: + assert (0); + return 0; + } +} + +struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s); +struct tl_combinator_tree *tl_parse_term (struct tree *T, int s) { + assert (T->type == type_term); + int i = 0; + while (i < T->nc && T->c[i]->type == type_percent) { i ++; s ++; } + assert (i < T->nc); + TL_INIT (L); + while (i < T->nc) { + TL_TRY (tl_parse_any_term (T->c[i], s), L); + s = 0; + i ++; + } + return L; +} + + +struct tl_combinator_tree *tl_parse_type_term (struct tree *T, int s) { + assert (T->type == type_type_term); + assert (T->nc == 1); + struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s); + if (!Z || Z->type != type_type) { if (Z) { TL_ERROR ("type_term: found type %s\n", TL_TYPE (Z->type)); } TL_FAIL; } + return Z; +} + +struct tl_combinator_tree *tl_parse_nat_term (struct tree *T, int s) { + assert (T->type == type_nat_term); + assert (T->nc == 1); + struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s); + if (!Z || (Z->type != type_num && Z->type != type_num_value)) { if (Z) { TL_ERROR ("nat_term: found type %s\n", TL_TYPE (Z->type)); }TL_FAIL; } + return Z; +} + +struct tl_combinator_tree *tl_parse_subexpr (struct tree *T, int s) { + assert (T->type == type_subexpr); + assert (T->nc >= 1); + int i; + TL_INIT (L); + for (i = 0; i < T->nc; i++) { + TL_TRY (tl_parse_any_term (T->c[i], s), L); + s = 0; + } + return L; +} + +struct tl_combinator_tree *tl_parse_expr (struct tree *T, int s) { + assert (T->type == type_expr); + assert (T->nc >= 1); + int i; + TL_INIT (L); + for (i = 0; i < T->nc; i++) { + TL_TRY (tl_parse_subexpr (T->c[i], s), L); + s = 0; + } + return L; +} + +struct tl_combinator_tree *tl_parse_nat_const (struct tree *T, int s) { + assert (T->type == type_nat_const); + assert (!T->nc); + if (s > 0) { + TL_ERROR ("Nat const can not preceed with %%\n"); + TL_FAIL; + } + assert (T->type == type_nat_const); + assert (!T->nc); + TL_INIT (L); + L = alloc_ctree_node (); + L->act = act_nat_const; + L->type = type_num_value; + int i; + long long x = 0; + for (i = 0; i < T->len; i++) { + x = x * 10 + T->text[i] - '0'; + } + L->type_flags = x; + return L; +} + +struct tl_combinator_tree *tl_parse_ident (struct tree *T, int s) { + assert (T->type == type_type_ident || T->type == type_var_ident || T->type == type_boxed_type_ident); + assert (!T->nc); + struct tl_var *v = tl_get_var (T->text, T->len); + TL_INIT (L); + if (v) { + L = alloc_ctree_node (); + L->act = act_var; + L->type = v->type ? type_num : type_type; + if (L->type == type_num && s) { + TL_ERROR ("Nat var can not preceed with %%\n"); + TL_FAIL; + } else { + if (s) { + L->flags |= 1; + } + } + L->type_len = 0; + L->type_flags = 0; + L->data = v->ptr; + return L; + } + +/* if (!mystrcmp2 (T->text, T->len, "#") || !mystrcmp2 (T->text, T->len, "Type")) { + L = alloc_ctree_node (); + L->act = act_type; + L->flags |= 2; + L->data = tl_get_type (T->text, T->len); + assert (L->data); + L->type = type_type; + L->type_len = 0; + L->type_flags = 0; + return L; + }*/ + + struct tl_constructor *c = tl_get_constructor (T->text, T->len); + if (c) { + assert (c->type); + if (c->type->constructors_num != 1) { + TL_ERROR ("Constructor can be used only if it is the only constructor of the type\n"); + return 0; + } + c->type->flags |= 1; + L = alloc_ctree_node (); + L->act = act_type; + L->flags |= 5; + L->data = c->type; + L->type = type_type; + L->type_len = c->type->params_num; + L->type_flags = c->type->params_types; + return L; + } + int x = tl_is_type_name (T->text, T->len); + if (x) { + struct tl_type *t = tl_add_type (T->text, T->len, -1, 0); + L = alloc_ctree_node (); + if (s) { + L->flags |= 1; + t->flags |= 8; + } + L->act = act_type; + L->data = t; + L->type = type_type; + L->type_len = t->params_num; + L->type_flags = t->params_types; + return L; + } else { + TL_ERROR ("Not a type/var ident `%.*s`\n", T->len, T->text); + return 0; + } +} + +struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s) { + switch (T->type) { + case type_type_term: + return tl_parse_type_term (T, s); + case type_nat_term: + return tl_parse_nat_term (T, s); + case type_term: + return tl_parse_term (T, s); + case type_expr: + return tl_parse_expr (T, s); + case type_subexpr: + return tl_parse_subexpr (T, s); + case type_nat_const: + return tl_parse_nat_const (T, s); + case type_type_ident: + case type_var_ident: + return tl_parse_ident (T, s); + default: + fprintf (stderr, "type = %d\n", T->type); + assert (0); + return 0; + } +} + +struct tl_combinator_tree *tl_parse_multiplicity (struct tree *T) { + assert (T->type == type_multiplicity); + assert (T->nc == 1); + return tl_parse_nat_term (T->c[0], 0); +} + +struct tl_combinator_tree *tl_parse_opt_args (struct tree *T) { + assert (T); + assert (T->type == type_opt_args); + assert (T->nc >= 2); + TL_INIT (R); + TL_TRY (tl_parse_type_term (T->c[T->nc - 1], 0), R); + assert (R->type == type_type && !R->type_len); + assert (tl_finish_subtree (R)); + struct tl_type *t = tl_tree_get_type (R); + //assert (t); + int tt = -1; + if (t && !strcmp (t->id, "#")) { + tt = 1; + } else if (t && !strcmp (t->id, "Type")) { + tt = 0; + } + if (tt < 0) { + TL_ERROR ("Optargs can be only of type # or Type\n"); + TL_FAIL; + } + + int i; + for (i = 0; i < T->nc - 1; i++) { + if (T->c[i]->type != type_var_ident) { + TL_ERROR ("Variable name expected\n"); + TL_FAIL; + } + if (T->c[i]->len == 1 && *T->c[i]->text == '_') { + TL_ERROR ("Variables can not be unnamed\n"); + TL_FAIL; + } + } + TL_INIT (H); +// for (i = T->nc - 2; i >= (T->nc >= 2 ? 0 : -1); i--) { + for (i = 0; i <= T->nc - 2; i++) { + TL_INIT (S); S = alloc_ctree_node (); + S->left = (i == T->nc - 2) ? R : tl_tree_dup (R) ; S->right = 0; + S->type = type_list_item; + S->type_len = 0; + S->act = act_field; + S->data = i >= 0 ? mystrdup (T->c[i]->text, T->c[i]->len) : 0; + if (tt >= 0) { + assert (S->data); + tl_add_var (S->data, S, tt); + } + S->flags = 33; + H = tl_union (H, S); + } + return H; +} + +struct tl_combinator_tree *tl_parse_args (struct tree *T); +struct tl_combinator_tree *tl_parse_args2 (struct tree *T) { + assert (T); + assert (T->type == type_args2); + assert (T->nc >= 1); + TL_INIT (R); + TL_INIT (L); + int x = 0; + char *field_name = 0; + if (T->c[x]->type == type_var_ident_opt || T->c[x]->type == type_var_ident) { + field_name = mystrdup (T->c[x]->text, T->c[x]->len); + if (!tl_add_field (field_name)) { + TL_ERROR ("Duplicate field name %s\n", field_name); + TL_FAIL; + } + x ++; + } + //fprintf (stderr, "%d %d\n", x, T->nc); + if (T->c[x]->type == type_multiplicity) { + L = tl_parse_multiplicity (T->c[x]); + if (!L) { TL_FAIL;} + x ++; + } else { + struct tl_var *v = tl_get_last_num_var (); + if (!v) { + TL_ERROR ("Expected multiplicity or nat var\n"); + TL_FAIL; + } + L = alloc_ctree_node (); + L->act = act_var; + L->type = type_num; + L->flags |= 128; + L->type_len = 0; + L->type_flags = 0; + L->data = v->ptr; + ((struct tl_combinator_tree *)(v->ptr))->flags |= 256; + } + namespace_push (); + while (x < T->nc) { + TL_TRY (tl_parse_args (T->c[x]), R); + x ++; + } + namespace_pop (); + struct tl_combinator_tree *S = alloc_ctree_node (); + S->type = type_type; + S->type_len = 0; + S->act = act_array; + S->left = L; + S->right = R; + //S->data = field_name; + + struct tl_combinator_tree *H = alloc_ctree_node (); + H->type = type_list_item; + H->act = act_field; + H->left = S; + H->right = 0; + H->data = field_name; + H->type_len = 0; + + return H; +} + +void tl_mark_vars (struct tl_combinator_tree *T); +struct tl_combinator_tree *tl_parse_args134 (struct tree *T) { + assert (T); + assert (T->type == type_args1 || T->type == type_args3 || T->type == type_args4); + assert (T->nc >= 1); + TL_INIT (R); + TL_TRY (tl_parse_type_term (T->c[T->nc - 1], 0), R); + assert (tl_finish_subtree (R)); + assert (R->type == type_type && !R->type_len); + struct tl_type *t = tl_tree_get_type (R); + //assert (t); + int tt = -1; + if (t && !strcmp (t->id, "#")) { + tt = 1; + } else if (t && !strcmp (t->id, "Type")) { + tt = 0; + } + +/* if (tt >= 0 && T->nc == 1) { + TL_ERROR ("Variables can not be unnamed (type %d)\n", tt); + }*/ + int last = T->nc - 2; + int excl = 0; + if (last >= 0 && T->c[last]->type == type_exclam) { + excl ++; + tl_mark_vars (R); + last --; + } + if (last >= 0 && T->c[last]->type == type_optional_arg_def) { + assert (T->c[last]->nc == 2); + TL_INIT (E); E = alloc_ctree_node (); + E->type = type_type; + E->act = act_opt_field; + E->left = tl_parse_ident (T->c[last]->c[0], 0); + int i; + long long x = 0; + for (i = 0; i < T->c[last]->c[1]->len; i++) { + x = x * 10 + T->c[last]->c[1]->text[i] - '0'; + } + E->left->type_flags = x; + E->type_flags = R->type_flags; + E->type_len = R->type_len; + E->right = R; + R = E; + last --; + } + int i; + for (i = 0; i < last; i++) { + if (T->c[i]->type != type_var_ident && T->c[i]->type != type_var_ident_opt) { + TL_ERROR ("Variable name expected\n"); + TL_FAIL; + } +/* if (tt >= 0 && (T->nc == 1 || (T->c[i]->len == 1 && *T->c[i]->text == '_'))) { + TL_ERROR ("Variables can not be unnamed\n"); + TL_FAIL; + }*/ + } + TL_INIT (H); +// for (i = T->nc - 2; i >= (T->nc >= 2 ? 0 : -1); i--) { + for (i = (last >= 0 ? 0 : -1); i <= last; i++) { + TL_INIT (S); S = alloc_ctree_node (); + S->left = (i == last) ? R : tl_tree_dup (R) ; S->right = 0; + S->type = type_list_item; + S->type_len = 0; + S->act = act_field; + S->data = i >= 0 ? mystrdup (T->c[i]->text, T->c[i]->len) : 0; + if (excl) { + S->flags |= FLAG_EXCL; + } + if (S->data && (T->c[i]->len >= 2 || *T->c[i]->text != '_')) { + if (!tl_add_field (S->data)) { + TL_ERROR ("Duplicate field name %s\n", (char *)S->data); + TL_FAIL; + } + } + if (tt >= 0) { + //assert (S->data); + char *name = S->data; + if (!name) { + static char s[20]; + sprintf (s, "%lld", lrand48 () * (1ll << 32) + lrand48 ()); + name = s; + } + struct tl_var *v = tl_add_var (name, S, tt); + if (!v) {TL_FAIL;} + v->flags |= 2; + } + + H = tl_union (H, S); + } + return H; +} + + +struct tl_combinator_tree *tl_parse_args (struct tree *T) { + assert (T->type == type_args); + assert (T->nc == 1); + switch (T->c[0]->type) { + case type_args1: + return tl_parse_args134 (T->c[0]); + case type_args2: + return tl_parse_args2 (T->c[0]); + case type_args3: + return tl_parse_args134 (T->c[0]); + case type_args4: + return tl_parse_args134 (T->c[0]); + default: + assert (0); + return 0; + } +} + +void tl_mark_vars (struct tl_combinator_tree *T) { + if (!T) { return; } + if (T->act == act_var) { + char *id = ((struct tl_combinator_tree *)(T->data))->data; + struct tl_var *v = tl_get_var (id, strlen (id)); + assert (v); + v->flags |= 1; + } + tl_mark_vars (T->left); + tl_mark_vars (T->right); +} + +struct tl_combinator_tree *tl_parse_result_type (struct tree *T) { + assert (T->type == type_result_type); + assert (T->nc >= 1); + assert (T->nc <= 64); + + TL_INIT (L); + + if (tl_get_var (T->c[0]->text, T->c[0]->len)) { + if (T->nc != 1) { + TL_ERROR ("Variable can not take params\n"); + TL_FAIL; + } + L = alloc_ctree_node (); + L->act = act_var; + L->type = type_type; + struct tl_var *v = tl_get_var (T->c[0]->text, T->c[0]->len); + if (v->type) { + TL_ERROR ("Type mistmatch\n"); + TL_FAIL; + } + L->data = v->ptr; +// assert (v->ptr); + } else { + L = alloc_ctree_node (); + L->act = act_type; + L->type = type_type; + struct tl_type *t = tl_add_type (T->c[0]->text, T->c[0]->len, -1, 0); + assert (t); + L->type_len = t->params_num; + L->type_flags = t->params_types; + L->data = t; + + int i; + for (i = 1; i < T->nc; i++) { + TL_TRY (tl_parse_any_term (T->c[i], 0), L); + assert (L->right); + assert (L->right->type == type_num || L->right->type == type_num_value || (L->right->type == type_type && L->right->type_len == 0)); + } + } + + if (!tl_finish_subtree (L)) { + TL_FAIL; + } + + tl_mark_vars (L); + return L; +} + +int __ok; +void tl_var_check_used (struct tl_var *v) { + __ok = __ok && (v->flags & 3); +} + +int tl_parse_combinator_decl (struct tree *T, int fun) { + assert (T->type == type_combinator_decl); + assert (T->nc >= 3); + namespace_level = 0; + tl_clear_vars (); + tl_clear_fields (); + TL_INIT (L); + TL_INIT (R); + + int i = 1; + while (i < T->nc - 2 && T->c[i]->type == type_opt_args) { + TL_TRY (tl_parse_opt_args (T->c[i]), L); + i++; + } + while (i < T->nc - 2 && T->c[i]->type == type_args) { + TL_TRY (tl_parse_args (T->c[i]), L); + i++; + } + assert (i == T->nc - 2 && T->c[i]->type == type_equals); + i ++; + + R = tl_parse_result_type (T->c[i]); + if (!R) { TL_FAIL; } + + struct tl_type *t = tl_tree_get_type (R); + if (!fun && !t) { + TL_ERROR ("Only functions can return variables\n"); + } + assert (t || fun); + + assert (namespace_level == 0); + __ok = 1; + tree_act_tl_var (vars[0], tl_var_check_used); + if (!__ok) { + TL_ERROR ("Not all variables are used in right side\n"); + TL_FAIL; + } + + if (tl_get_constructor (T->c[0]->text, T->c[0]->len) || tl_get_function (T->c[0]->text, T->c[0]->len)) { + TL_ERROR ("Duplicate combinator id %.*s\n", T->c[0]->len, T->c[0]->text); + return 0; + } + struct tl_constructor *c = !fun ? tl_add_constructor (t, T->c[0]->text, T->c[0]->len, 0) : tl_add_function (t, T->c[0]->text, T->c[0]->len, 0); + if (!c) { TL_FAIL; } + c->left = L; + c->right = R; + + if (!c->name) { + tl_count_combinator_name (c); + } + tl_print_combinator (c); + + return 1; +} + +void change_var_ptrs (struct tl_combinator_tree *O, struct tl_combinator_tree *D, struct tree_var_value **V) { + if (!O || !D) { + assert (!O && !D); + return; + } + if (O->act == act_field) { + struct tl_type *t = tl_tree_get_type (O->left); + if (t && (!strcmp (t->id, "#") || !strcmp (t->id, "Type"))) { + tl_set_var_value (V, O, D); + } + } + if (O->act == act_var) { + assert (D->data == O->data); + D->data = tl_get_var_value (V, O->data); + assert (D->data); + } + change_var_ptrs (O->left, D->left, V); + change_var_ptrs (O->right, D->right, V); +} + +struct tl_combinator_tree *change_first_var (struct tl_combinator_tree *O, struct tl_combinator_tree **X, struct tl_combinator_tree *Y) { + if (!O) { return (void *)-2l; }; + if (O->act == act_field && !*X) { + struct tl_type *t = tl_tree_get_type (O->left); + if (t && !strcmp (t->id, "#")) { + if (Y->type != type_num && Y->type != type_num_value) { + TL_ERROR ("change_var: Type mistmatch\n"); + return 0; + } else { + *X = O; + return (void *)-1l; + } + } + if (t && !strcmp (t->id, "Type")) { + if (Y->type != type_type || Y->type_len != 0) { + TL_ERROR ("change_var: Type mistmatch\n"); + return 0; + } else { + *X = O; + return (void *)-1l; + } + } + } + if (O->act == act_var) { + if (O->data == *X) { + struct tl_combinator_tree *R = tl_tree_dup (Y); + if (O->type == type_num || O->type == type_num_value) { R->type_flags += O->type_flags; } + return R; + } + } + struct tl_combinator_tree *t; + t = change_first_var (O->left, X, Y); + if (!t) { return 0;} + if (t == (void *)-1l) { + t = change_first_var (O->right, X, Y); + if (!t) { return 0;} + if (t == (void *)-1l) { return (void *)-1l; } + if (t != (void *)-2l) { return t;} + return (void *)-1l; + } + if (t != (void *)-2l) { + O->left = t; + } + t = change_first_var (O->right, X, Y); + if (!t) { return 0;} + if (t == (void *)-1l) { + return O->left; + } + if (t != (void *)-2l) { + O->right = t; + } + return O; +} + + +int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T); +struct tree_var_value **_T; +int __tok; +void check_nat_val (struct tl_var_value v) { + if (!__tok) { return; } + long long x = v.num_val; + struct tl_combinator_tree *L = v.val; + if (L->type == type_type) { return;} + while (1) { + if (L->type == type_num_value) { + if (x + L->type_flags < 0) { + __tok = 0; + return; + } else { + return; + } + } + assert (L->type == type_num); + x += L->type_flags; + x += tl_get_var_value_num (_T, L->data); + L = tl_get_var_value (_T, L->data); + if (!L) { return;} + } +} + +int check_constructors_equal (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T) { + if (!uniformize (L, R, T)) { return 0; } + __tok = 1; + _T = T; + tree_act_var_value (*T, check_nat_val); + return __tok; +} + +struct tl_combinator_tree *reduce_type (struct tl_combinator_tree *A, struct tl_type *t) { + assert (A); + if (A->type_len == t->params_num) { + assert (A->type_flags == t->params_types); + A->act = act_type; + A->type = type_type; + A->left = A->right = 0; + A->data = t; + return A; + } + A->left = reduce_type (A->left, t); + return A; +} + +struct tl_combinator_tree *change_value_var (struct tl_combinator_tree *O, struct tree_var_value **X) { + if (!O) { return (void *)-2l; }; + while (O->act == act_var) { + assert (O->data); + if (!tl_get_var_value (X, O->data)) { + break; + } + if (O->type == type_type) { + O = tl_tree_dup (tl_get_var_value (X, O->data)); + } else { + long long n = tl_get_var_value_num (X, O->data); + struct tl_combinator_tree *T = tl_get_var_value (X, O->data); + O->data = T->data; + O->type = T->type; + O->act = T->act; + O->type_flags = O->type_flags + n + T->type_flags; + } + } + if (O->act == act_field) { + if (tl_get_var_value (X, O)) { return (void *)-1l; } + } + struct tl_combinator_tree *t; + t = change_value_var (O->left, X); + if (!t) { return 0;} + if (t == (void *)-1l) { + t = change_value_var (O->right, X); + if (!t) { return 0;} + if (t == (void *)-1l) { return (void *)-1l; } + if (t != (void *)-2l) { return t;} + return (void *)-1l; + } + if (t != (void *)-2l) { + O->left = t; + } + t = change_value_var (O->right, X); + if (!t) { return 0;} + if (t == (void *)-1l) { + return O->left; + } + if (t != (void *)-2l) { + O->right = t; + } + return O; +} + +int tl_parse_partial_type_app_decl (struct tree *T) { + assert (T->type == type_partial_type_app_decl); + assert (T->nc >= 1); + + assert (T->c[0]->type == type_boxed_type_ident); + struct tl_type *t = tl_get_type (T->c[0]->text, T->c[0]->len); + if (!t) { + TL_ERROR ("Can not make partial app for unknown type\n"); + return 0; + } + + tl_type_finalize (t); + + struct tl_combinator_tree *L = tl_parse_ident (T->c[0], 0); + assert (L); + int i; + tl_buf_reset (); + int cc = T->nc - 1; + for (i = 1; i < T->nc; i++) { + TL_TRY (tl_parse_any_term (T->c[i], 0), L); + tl_buf_add_tree (L->right, 1); + } + + while (L->type_len) { + struct tl_combinator_tree *C = alloc_ctree_node (); + C->act = act_var; + C->type = (L->type_flags & 1) ? type_num : type_type; + C->type_len = 0; + C->type_flags = 0; + C->data = (void *)-1l; + L = tl_union (L, C); + if (!L) { return 0; } + } + + + static char _buf[100000]; + snprintf (_buf, 100000, "%s%.*s", t->id, buf_pos, buf); + struct tl_type *nt = tl_add_type (_buf, strlen (_buf), t->params_num - cc, t->params_types >> cc); + assert (nt); + //snprintf (_buf, 100000, "%s #", t->id); + //nt->real_id = strdup (_buf); + + for (i = 0; i < t->constructors_num; i++) { + struct tl_constructor *c = t->constructors[i]; + struct tree_var_value *V = 0; + TL_INIT (A); + TL_INIT (B); + A = tl_tree_dup (c->left); + B = tl_tree_dup (c->right); + + struct tree_var_value *W = 0; + change_var_ptrs (c->left, A, &W); + change_var_ptrs (c->right, B, &W); + + + if (!check_constructors_equal (B, L, &V)) { continue; } + B = reduce_type (B, nt); + A = change_value_var (A, &V); + if (A == (void *)-1l) { A = 0;} + B = change_value_var (B, &V); + assert (B != (void *)-1l); + snprintf (_buf, 100000, "%s%.*s", c->id, buf_pos, buf); + + struct tl_constructor *r = tl_add_constructor (nt, _buf, strlen (_buf), 1); + snprintf (_buf, 100000, "%s", c->id); + r->real_id = tstrdup (_buf); + + r->left = A; + r->right = B; + if (!r->name) { + tl_count_combinator_name (r); + } + tl_print_combinator (r); + } + + return 1; +} + +int tl_parse_partial_comb_app_decl (struct tree *T, int fun) { + assert (T->type == type_partial_comb_app_decl); + + struct tl_constructor *c = !fun ? tl_get_constructor (T->c[0]->text, T->c[0]->len) : tl_get_function (T->c[0]->text, T->c[0]->len); + if (!c) { + TL_ERROR ("Can not make partial app for undefined combinator\n"); + return 0; + } + + //TL_INIT (K); + //static char buf[1000]; + //int x = sprintf (buf, "%s", c->id); + TL_INIT (L); + TL_INIT (R); + L = tl_tree_dup (c->left); + R = tl_tree_dup (c->right); + + + struct tree_var_value *V = 0; + change_var_ptrs (c->left, L, &V); + change_var_ptrs (c->right, R, &V); + V = tree_clear_var_value (V); + + int i; + tl_buf_reset (); + for (i = 1; i < T->nc; i++) { + TL_INIT (X); + TL_INIT (Z); + X = tl_parse_any_term (T->c[i], 0); + struct tl_combinator_tree *K = 0; + if (!(Z = change_first_var (L, &K, X))) { + TL_FAIL; + } + L = Z; + if (!K) { + TL_ERROR ("Partial app: not enougth variables (i = %d)\n", i); + TL_FAIL; + } + if (!(Z = change_first_var (R, &K, X))) { + TL_FAIL; + } + assert (Z == R); + tl_buf_add_tree (X, 1); + } + + static char _buf[100000]; + snprintf (_buf, 100000, "%s%.*s", c->id, buf_pos, buf); +// fprintf (stderr, "Local id: %s\n", _buf); + + struct tl_constructor *r = !fun ? tl_add_constructor (c->type, _buf, strlen (_buf), 1) : tl_add_function (c->type, _buf, strlen (_buf), 1); + r->left = L; + r->right = R; + snprintf (_buf, 100000, "%s", c->id); + r->real_id = tstrdup (_buf); + if (!r->name) { + tl_count_combinator_name (r); + } + tl_print_combinator (r); + return 1; +} + + +int tl_parse_partial_app_decl (struct tree *T, int fun) { + assert (T->type == type_partial_app_decl); + assert (T->nc == 1); + if (T->c[0]->type == type_partial_comb_app_decl) { + return tl_parse_partial_comb_app_decl (T->c[0], fun); + } else { + if (fun) { + TL_ERROR ("Partial type app in functions block\n"); + TL_FAIL; + } + return tl_parse_partial_type_app_decl (T->c[0]); + } +} + +int tl_parse_final_final (struct tree *T) { + assert (T->type == type_final_final); + assert (T->nc == 1); + struct tl_type *R; + if ((R = tl_get_type (T->c[0]->text, T->c[0]->len))) { + R->flags |= 1; + return 1; + } else { + TL_ERROR ("Final statement for type `%.*s` before declaration\n", T->c[0]->len, T->c[0]->text); + TL_FAIL; + } +} + +int tl_parse_final_new (struct tree *T) { + assert (T->type == type_final_new); + assert (T->nc == 1); + if (tl_get_type (T->c[0]->text, T->c[0]->len)) { + TL_ERROR ("New statement: type `%.*s` already declared\n", T->c[0]->len, T->c[0]->text); + TL_FAIL; + } else { + return 1; + } +} + +int tl_parse_final_empty (struct tree *T) { + assert (T->type == type_final_empty); + assert (T->nc == 1); + if (tl_get_type (T->c[0]->text, T->c[0]->len)) { + TL_ERROR ("New statement: type `%.*s` already declared\n", T->c[0]->len, T->c[0]->text); + TL_FAIL; + } + struct tl_type *t = tl_add_type (T->c[0]->text, T->c[0]->len, 0, 0); + assert (t); + t->flags |= 1 | FLAG_EMPTY; + return 1; +} + +int tl_parse_final_decl (struct tree *T, int fun) { + assert (T->type == type_final_decl); + assert (!fun); + assert (T->nc == 1); + switch (T->c[0]->type) { + case type_final_new: + return tl_parse_final_new (T->c[0]); + case type_final_final: + return tl_parse_final_final (T->c[0]); + case type_final_empty: + return tl_parse_final_empty (T->c[0]); + default: + assert (0); + return 0; + } +} + +int tl_parse_builtin_combinator_decl (struct tree *T, int fun) { + if (fun) { + TL_ERROR ("Builtin type can not be described in function block\n"); + return -1; + } + assert (T->type == type_builtin_combinator_decl); + assert (T->nc == 2); + assert (T->c[0]->type == type_full_combinator_id); + assert (T->c[1]->type == type_boxed_type_ident); + + + if ((!mystrcmp2 (T->c[0]->text, T->c[0]->len, "int") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Int")) || + (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "long") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Long")) || + (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "double") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Double")) || + (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "object") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Object")) || + (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "function") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Function")) || + (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "string") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "String"))) { + struct tl_type *t = tl_add_type (T->c[1]->text, T->c[1]->len, 0, 0); + if (!t) { + return 0; + } + struct tl_constructor *c = tl_add_constructor (t, T->c[0]->text, T->c[0]->len, 0); + if (!c) { + return 0; + } + + c->left = alloc_ctree_node (); + c->left->act = act_question_mark; + c->left->type = type_list_item; + + c->right = alloc_ctree_node (); + c->right->act = act_type; + c->right->data = t; + c->right->type = type_type; + + if (!c->name) { + tl_count_combinator_name (c); + } + tl_print_combinator (c); + } else { + TL_ERROR ("Unknown builting type `%.*s`\n", T->c[0]->len, T->c[0]->text); + return 0; + } + + return 1; +} + +int tl_parse_declaration (struct tree *T, int fun) { + assert (T->type == type_declaration); + assert (T->nc == 1); + switch (T->c[0]->type) { + case type_combinator_decl: + return tl_parse_combinator_decl (T->c[0], fun); + case type_partial_app_decl: + return tl_parse_partial_app_decl (T->c[0], fun); + case type_final_decl: + return tl_parse_final_decl (T->c[0], fun); + case type_builtin_combinator_decl: + return tl_parse_builtin_combinator_decl (T->c[0], fun); + default: + assert (0); + return 0; + } +} + +int tl_parse_constr_declarations (struct tree *T) { + assert (T->type == type_constr_declarations); + int i; + for (i = 0; i < T->nc; i++) { + TL_TRY_PES (tl_parse_declaration (T->c[i], 0)); + } + return 1; +} + +int tl_parse_fun_declarations (struct tree *T) { + assert (T->type == type_fun_declarations); + int i; + for (i = 0; i < T->nc; i++) { + TL_TRY_PES (tl_parse_declaration (T->c[i], 1)); + } + return 1; +} + +int tl_tree_lookup_value (struct tl_combinator_tree *L, void *var, struct tree_var_value **T) { + if (!L) { + return -1; + } + if (L->act == act_var && L->data == var) { + return 0; + } + if (L->act == act_var) { + struct tl_combinator_tree *E = tl_get_var_value (T, L->data); + if (!E) { return -1;} + else { return tl_tree_lookup_value (E, var, T); } + } + if (tl_tree_lookup_value (L->left, var, T) >= 0) { return 1; } + if (tl_tree_lookup_value (L->right, var, T) >= 0) { return 1; } + return -1; +} + +int tl_tree_lookup_value_nat (struct tl_combinator_tree *L, void *var, long long x, struct tree_var_value **T) { + assert (L); + if (L->type == type_num_value) { return -1; } + assert (L->type == type_num); + assert (L->act == act_var); + if (L->data == var) { + return x == L->type_flags ? 0 : 1; + } else { + if (!tl_get_var_value (T, L->data)) { + return -1; + } + return tl_tree_lookup_value_nat (tl_get_var_value (T, L->data), var, x + tl_get_var_value_num (T, L->data), T); + } + +} + +int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T) { + if (!L || !R) { + assert (!L && !R); + return 1; + } + if (R->act == act_var) { + struct tl_combinator_tree *_ = R; R = L; L = _; + } + + if (L->type == type_type) { + if (R->type != type_type || L->type_len != R->type_len || L->type_flags != R->type_flags) { + return 0; + } + if (R->data == (void *)-1l || L->data == (void *)-1l) { return 1;} + if (L->act == act_var) { + int x = tl_tree_lookup_value (R, L->data, T); + if (x > 0) { +// if (tl_tree_lookup_value (R, L->data, T) > 0) { + return 0; + } + if (x == 0) { + return 1; + } + struct tl_combinator_tree *E = tl_get_var_value (T, L->data); + if (!E) { + tl_set_var_value (T, L->data, R); + return 1; + } else { + return uniformize (E, R, T); + } + } else { + if (L->act != R->act || L->data != R->data) { + return 0; + } + return uniformize (L->left, R->left, T) && uniformize (L->right, R->right, T); + } + } else { + assert (L->type == type_num || L->type == type_num_value); + if (R->type != type_num && R->type != type_num_value) { + return 0; + } + assert (R->type == type_num || R->type == type_num_value); + if (R->data == (void *)-1l || L->data == (void *)-1l) { return 1;} + long long x = 0; + struct tl_combinator_tree *K = L; + while (1) { + x += K->type_flags; + if (K->type == type_num_value) { + break; + } + if (!tl_get_var_value (T, K->data)) { + int s = tl_tree_lookup_value_nat (R, K->data, K->type_flags, T); + if (s > 0) { + return 0; + } + if (s == 0) { + return 1; + } + /*tl_set_var_value_num (T, K->data, R, -x); + return 1;*/ + break; + } + x += tl_get_var_value_num (T, K->data); + K = tl_get_var_value (T, K->data); + } + long long y = 0; + struct tl_combinator_tree *M = R; + while (1) { + y += M->type_flags; + if (M->type == type_num_value) { + break; + } + if (!tl_get_var_value (T, M->data)) { + int s = tl_tree_lookup_value_nat (L, M->data, M->type_flags, T); + if (s > 0) { + return 0; + } + if (s == 0) { + return 1; + } + /*tl_set_var_value_num (T, M->data, L, -y); + return 1;*/ + break; + } + y += tl_get_var_value_num (T, M->data); + M = tl_get_var_value (T, M->data); + } + if (K->type == type_num_value && M->type == type_num_value) { + return x == y; + } + if (M->type == type_num_value) { + tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags)); + return 1; + } else if (K->type == type_num_value) { + tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags)); + return 1; + } else { + if (x >= y) { + tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags)); + } else { + tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags)); + } + return 1; + } + } + return 0; +} + + +void tl_type_check (struct tl_type *t) { + if (!__ok) return; + if (!strcmp (t->id, "#")) { t->name = 0x70659eff; return; } + if (!strcmp (t->id, "Type")) { t->name = 0x2cecf817; return; } + if (t->constructors_num <= 0 && !(t->flags & FLAG_EMPTY)) { + TL_ERROR ("Type %s has no constructors\n", t->id); + __ok = 0; + return; + } + int i, j; + t->name = 0; + for (i = 0; i < t->constructors_num; i++) { + t->name ^= t->constructors[i]->name; + } + for (i = 0; i < t->constructors_num; i++) { + for (j = i + 1; j < t->constructors_num; j++) { + struct tree_var_value *v = 0; + if (check_constructors_equal (t->constructors[i]->right, t->constructors[j]->right, &v)) { + t->flags |= 16; + } + } + } + if ((t->flags & 24) == 24) { + TL_WARNING ("Warning: Type %s has overlapping costructors, but it is used with `%%`\n", t->id); + } + int z = 0; + int sid = 0; + for (i = 0; i < t->constructors_num; i++) if (*t->constructors[i]->id == '_') { + z ++; + sid = i; + } + if (z > 1) { + TL_ERROR ("Type %s has %d default constructors\n", t->id, z); + __ok = 0; + return; + } + if (z == 1 && (t->flags & 8)) { + TL_ERROR ("Type %s has default constructors and used bare\n", t->id); + __ok = 0; + return; + } + if (z) { + struct tl_constructor *c; + c = t->constructors[sid]; + t->constructors[sid] = t->constructors[t->constructors_num - 1]; + t->constructors[t->constructors_num - 1] = c; + } +} + +struct tl_program *tl_parse (struct tree *T) { + assert (T); + assert (T->type == type_tl_program); + int i; + tl_program_cur = talloc (sizeof (*tl_program_cur)); + tl_add_type ("#", 1, 0, 0); + tl_add_type ("Type", 4, 0, 0); + for (i = 0; i < T->nc; i++) { + if (T->c[i]->type == type_constr_declarations) { TL_TRY_PES (tl_parse_constr_declarations (T->c[i])); } + else { TL_TRY_PES (tl_parse_fun_declarations (T->c[i])) } + } + __ok = 1; + tree_act_tl_type (tl_type_tree, tl_type_check); + if (!__ok) { + return 0; + } + return tl_program_cur; +} + +FILE *__f; +int num = 0; + +void wint (int a) { +// printf ("%d ", a); + a = htole32 (a); + assert (fwrite (&a, 1, 4, __f) == 4); +} + +void wdata (const void *x, int len) { + assert (fwrite (x, 1, len, __f) == len); +} + +void wstr (const char *s) { + if (s) { +// printf ("\"%s\" ", s); + int x = strlen (s); + if (x <= 254) { + unsigned char x_c = (unsigned char)x; + assert (fwrite (&x_c, 1, 1, __f) == 1); + } else { + fprintf (stderr, "String is too big...\n"); + assert (0); + } + wdata (s, x); + x ++; // The header, containing the length, which is 1 byte + int t = 0; + if (x & 3) { + // Let's hope it's truly zero on every platform + wdata (&t, 4 - (x & 3)); + } + } else { +// printf (" "); + wint (0); + } +} + +void wll (long long a) { +// printf ("%lld ", a); + a = htole64 (a); + assert (fwrite (&a, 1, 8, __f) == 8); +} + +int count_list_size (struct tl_combinator_tree *T) { + assert (T->type == type_list || T->type == type_list_item); + if (T->type == type_list_item) { + return 1; + } else { + return count_list_size (T->left) + count_list_size (T->right); + } +} + +void write_type_flags (long long flags) { + int new_flags = 0; + if (flags & 1) { + new_flags |= FLAG_BARE; + } + if (flags & FLAG_DEFAULT_CONSTRUCTOR) { + new_flags |= FLAG_DEFAULT_CONSTRUCTOR; + } + wint (new_flags); +} + +void write_field_flags (long long flags) { + int new_flags = 0; + //fprintf (stderr, "%lld\n", flags); + if (flags & 1) { + new_flags |= FLAG_BARE; + } + if (flags & 32) { + new_flags |= FLAG_OPT_VAR; + } + if (flags & FLAG_EXCL) { + new_flags |= FLAG_EXCL; + } + if (flags & FLAG_OPT_FIELD) { + // new_flags |= FLAG_OPT_FIELD; + new_flags |= 2; + } + if (flags & (1 << 21)) { + new_flags |= 4; + } + wint (new_flags); +} + +void write_var_type_flags (long long flags) { + int new_flags = 0; + if (flags & 1) { + new_flags |= FLAG_BARE; + } + if (new_flags & FLAG_BARE) { + TL_ERROR ("Sorry, bare vars are not (yet ?) supported.\n"); + assert (!(new_flags & FLAG_BARE)); + } + wint (new_flags); +} + +void write_tree (struct tl_combinator_tree *T, int extra, struct tree_var_value **v, int *last_var); +void write_args (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) { + assert (T->type == type_list || T->type == type_list_item); + if (T->type == type_list) { + assert (T->act == act_union); + assert (T->left); + assert (T->right); + write_args (T->left, v, last_var); + write_args (T->right, v, last_var); + return; + } + wint (TLS_ARG_V2); + assert (T->act == act_field); + assert (T->left); + wstr (T->data && strcmp (T->data, "_") ? T->data : 0); + long long f = T->flags; + if (T->left->act == act_opt_field) { + f |= (1 << 20); + } + if (T->left->act == act_type && T->left->data && (!strcmp (((struct tl_type *)T->left->data)->id, "#") || !strcmp (((struct tl_type *)T->left->data)->id, "Type"))) { + write_field_flags (f | (1 << 21)); + wint (*last_var); + *last_var = (*last_var) + 1; + tl_set_var_value_num (v, T, 0, (*last_var) - 1); + } else { + write_field_flags (f); + } + write_tree (T->left, 0, v, last_var); +} + +void write_array (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) { + wint (TLS_ARRAY); + write_tree (T->left, 0, v, last_var); + write_tree (T->right, 0, v, last_var); +} + +void write_type_rec (struct tl_combinator_tree *T, int cc, struct tree_var_value **v, int *last_var) { + if (T->act == act_arg) { + write_type_rec (T->left, cc + 1, v, last_var); + if (T->right->type == type_num_value || T->right->type == type_num) { + wint (TLS_EXPR_NAT); + } else { + wint (TLS_EXPR_TYPE); + } + write_tree (T->right, 0, v, last_var); + } else { + assert (T->act == act_var || T->act == act_type); + if (T->act == act_var) { + assert (!cc); + wint (TLS_TYPE_VAR); + wint (tl_get_var_value_num (v, T->data)); + write_var_type_flags (T->flags); + //wint (T->flags); + } else { + wint (TLS_TYPE_EXPR); + struct tl_type *t = T->data; + wint (t->name); + write_type_flags (T->flags); +// wint (T->flags); + wint (cc); +// fprintf (stderr, "cc = %d\n", cc); + } + } +} + +void write_opt_type (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) { + wint (tl_get_var_value_num (v, T->left->data)); + wint (T->left->type_flags); +// write_tree (T->right, 0, v, last_var); + assert (T); + T = T->right; + switch (T->type) { + case type_type: + if (T->act == act_array) { + write_array (T, v, last_var); + } else if (T->act == act_type || T->act == act_var || T->act == act_arg) { + write_type_rec (T, 0, v, last_var); + } else { + assert (0); + } + break; + default: + assert (0); + } +} + +void write_tree (struct tl_combinator_tree *T, int extra, struct tree_var_value **v, int *last_var) { + assert (T); + switch (T->type) { + case type_list_item: + case type_list: + if (extra) { + wint (TLS_COMBINATOR_RIGHT_V2); + } + wint (count_list_size (T)); + write_args (T, v, last_var); + break; + case type_num_value: + wint ((int)TLS_NAT_CONST); + wint (T->type_flags); + break; + case type_num: + wint ((int)TLS_NAT_VAR); + wint (T->type_flags); + wint (tl_get_var_value_num (v, T->data)); + break; + case type_type: + if (T->act == act_array) { + write_array (T, v, last_var); + } else if (T->act == act_type || T->act == act_var || T->act == act_arg) { + write_type_rec (T, 0, v, last_var); + } else { + assert (T->act == act_opt_field); + write_opt_type (T, v, last_var); + } + break; + default: + assert (0); + } +} + +void write_type (struct tl_type *t) { + wint (TLS_TYPE); + wint (t->name); + wstr (t->id); + wint (t->constructors_num); + wint (t->flags); + wint (t->params_num); + wll (t->params_types); +} + +int is_builtin_type (const char *id) { + return !strcmp (id, "int") || !strcmp (id, "long") || !strcmp (id, "double") || !strcmp (id, "string") + || !strcmp(id, "object") || !strcmp(id, "function"); +} + +void write_combinator (struct tl_constructor *c) { + wint (c->name); + wstr (c->id); + wint (c->type ? c->type->name : 0); + struct tree_var_value *T = 0; + int x = 0; + assert (c->right); + if (c->left) { + if (is_builtin_type (c->id)) { + wint (TLS_COMBINATOR_LEFT_BUILTIN); + } else { + wint (TLS_COMBINATOR_LEFT); + // FIXME: What is that? +// wint (count_list_size (c->left)); + write_tree (c->left, 0, &T, &x); + } + } else { + wint (TLS_COMBINATOR_LEFT); + wint (0); + } + wint (TLS_COMBINATOR_RIGHT_V2); + write_tree (c->right, 1, &T, &x); +} + +void write_constructor (struct tl_constructor *c) { + wint (TLS_COMBINATOR); + write_combinator (c); +} + +void write_function (struct tl_constructor *c) { + wint (TLS_COMBINATOR); + write_combinator (c); +} + +void write_type_constructors (struct tl_type *t) { + int i; + for (i = 0; i < t->constructors_num; i++) { + write_constructor (t->constructors[i]); + } +} + +void write_types (FILE *f) { + __f = f; + wint (TLS_SCHEMA_V2); + wint (0); +#ifdef TL_PARSER_NEED_TIME + wint (time (0)); +#else + /* Make the tlo reproducible by default. Rationale: https://wiki.debian.org/ReproducibleBuilds/Howto#Introduction */ + wint (0); +#endif + num = 0; + wint (total_types_num); + tree_act_tl_type (tl_type_tree, write_type); + wint (total_constructors_num); + tree_act_tl_type (tl_type_tree, write_type_constructors); + wint (total_functions_num); + tree_act_tl_constructor (tl_function_tree, write_function); +} diff --git a/lib/tgchat/ext/td/td/generate/tl-parser/tl-parser.h b/lib/tgchat/ext/td/td/generate/tl-parser/tl-parser.h new file mode 100644 index 00000000..59209d4a --- /dev/null +++ b/lib/tgchat/ext/td/td/generate/tl-parser/tl-parser.h @@ -0,0 +1,223 @@ +/* + This file is part of tgl-libary/tlc + + Tgl-library/tlc is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Tgl-library/tlc is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this tgl-library/tlc. If not, see . + + Copyright Vitaly Valtman 2014 + + It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) + Copyright 2012-2013 Vkontakte Ltd + 2012-2013 Vitaliy Valtman + +*/ + +#ifndef __TL_PARSER_NEW_H__ +#define __TL_PARSER_NEW_H__ + +#include + +enum lex_type { + lex_error, + lex_char, + lex_triple_minus, + lex_uc_ident, + lex_lc_ident, + lex_eof, + lex_final, + lex_new, + lex_none, + lex_num, + lex_empty +}; + + +struct curlex { + char *ptr; + int len; + enum lex_type type; + int flags; +}; + +struct parse { + char *text; + int pos; + int len; + int line; + int line_pos; + struct curlex lex; +}; + + +enum tree_type { + type_tl_program, + type_fun_declarations, + type_constr_declarations, + type_declaration, + type_combinator_decl, + type_equals, + type_partial_app_decl, + type_final_decl, + type_full_combinator_id, + type_opt_args, + type_args, + type_args1, + type_args2, + type_args3, + type_args4, + type_boxed_type_ident, + type_subexpr, + type_partial_comb_app_decl, + type_partial_type_app_decl, + type_final_new, + type_final_final, + type_final_empty, +// type_type, + type_var_ident, + type_var_ident_opt, + type_multiplicity, + type_type_term, + type_term, + type_percent, + type_result_type, + type_expr, + type_nat_term, + type_combinator_id, + type_nat_const, + type_type_ident, + type_builtin_combinator_decl, + type_exclam, + type_optional_arg_def +}; + +struct tree { + char *text; + int len; + enum tree_type type; + int lex_line; + int lex_line_pos; + int flags; + int size; + int nc; + struct tree **c; +}; + + +#define TL_ACT(x) (x == act_var ? "act_var" : x == act_field ? "act_field" : x == act_plus ? "act_plus" : x == act_type ? "act_type" : x == act_nat_const ? "act_nat_const" : x == act_array ? "act_array" : x == act_question_mark ? "act_question_mark" : \ + x == act_union ? "act_union" : x == act_arg ? "act_arg" : x == act_opt_field ? "act_opt_field" : "act_unknown") + +#define TL_TYPE(x) (x == type_num ? "type_num" : x == type_type ? "type_type" : x == type_list_item ? "type_list_item" : x == type_list ? "type_list" : x == type_num_value ? "type_num_value" : "type_unknown") +enum combinator_tree_action { + act_var, + act_field, + act_plus, + act_type, + act_nat_const, + act_array, + act_question_mark, + act_union, + act_arg, + act_opt_field +}; + +enum combinator_tree_type { + type_num, + type_num_value, + type_type, + type_list_item, + type_list +}; + +struct tl_combinator_tree { + enum combinator_tree_action act; + struct tl_combinator_tree *left, *right; + char *name; + void *data; + long long flags; + enum combinator_tree_type type; + int type_len; + long long type_flags; +}; + + +struct tl_program { + int types_num; + int functions_num; + int constructors_num; + struct tl_type **types; + struct tl_function **functions; +// struct tl_constuctor **constructors; +}; + +struct tl_type { + char *id; + char *print_id; + char *real_id; + unsigned name; + int flags; + + int params_num; + long long params_types; + + int constructors_num; + struct tl_constructor **constructors; +}; + +struct tl_constructor { + char *id; + char *print_id; + char *real_id; + unsigned name; + struct tl_type *type; + + struct tl_combinator_tree *left; + struct tl_combinator_tree *right; +}; + +struct tl_var { + char *id; + struct tl_combinator_tree *ptr; + int type; + int flags; +}; + +struct parse *tl_init_parse_file (const char *fname); +struct tree *tl_parse_lex (struct parse *P); +void tl_print_parse_error (void); +struct tl_program *tl_parse (struct tree *T); + +void write_types (FILE *f); + +#define FLAG_BARE 1 +#define FLAG_OPT_VAR (1 << 17) +#define FLAG_EXCL (1 << 18) +#define FLAG_OPT_FIELD (1 << 20) +#define FLAG_IS_VAR (1 << 21) +#define FLAG_DEFAULT_CONSTRUCTOR (1 << 25) +#define FLAG_EMPTY (1 << 10) + +#ifdef NDEBUG +#undef assert +#define assert(x) if (!(x)) { fprintf(stderr, "Assertion error!\n"); abort(); } +#endif + +#ifdef _WIN32 +#include "wgetopt.h" + +#define __attribute__(x) + +#define lrand48() rand() +#define strdup _strdup +#endif + +#endif diff --git a/lib/tgchat/ext/td/td/generate/tl-parser/tl-tl.h b/lib/tgchat/ext/td/td/generate/tl-parser/tl-tl.h new file mode 100644 index 00000000..8bc0a707 --- /dev/null +++ b/lib/tgchat/ext/td/td/generate/tl-parser/tl-tl.h @@ -0,0 +1,55 @@ +/* + This file is part of VK/KittenPHP-DB-Engine. + + VK/KittenPHP-DB-Engine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + VK/KittenPHP-DB-Engine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VK/KittenPHP-DB-Engine. If not, see . + + This program is released under the GPL with the additional exemption + that compiling, linking, and/or using OpenSSL is allowed. + You are free to remove this exemption from derived works. + + Copyright 2012-2013 Vkontakte Ltd + 2012-2013 Vitaliy Valtman +*/ + +#ifndef __TL_TL_H__ +#define __TL_TL_H__ + +// Current tl-tl schema is V2 +// See https://core.telegram.org/mtproto/TL-tl + +#define TLS_SCHEMA_V2 0x3a2f9be2 +#define TLS_TYPE 0x12eb4386 +#define TLS_COMBINATOR 0x5c0a1ed5 +#define TLS_COMBINATOR_LEFT_BUILTIN 0xcd211f63 +#define TLS_COMBINATOR_LEFT 0x4c12c6d9 +#define TLS_COMBINATOR_RIGHT_V2 0x2c064372 +#define TLS_ARG_V2 0x29dfe61b + +#define TLS_EXPR_TYPE 0xecc9da78 +#define TLS_EXPR_NAT 0xdcb49bd8 + +#define TLS_NAT_CONST 0xdcb49bd8 +#define TLS_NAT_VAR 0x4e8a14f0 +#define TLS_TYPE_VAR 0x0142ceae +#define TLS_ARRAY 0xd9fb20de +#define TLS_TYPE_EXPR 0xc1863d08 + +/* Deprecated (old versions), read-only */ +#define TLS_TREE_NAT_CONST 0xc09f07d7 +#define TLS_TREE_NAT_VAR 0x90ea6f58 +#define TLS_TREE_TYPE_VAR 0x1caa237a +#define TLS_TREE_ARRAY 0x80479360 +#define TLS_TREE_TYPE 0x10f32190 + +#endif diff --git a/lib/tgchat/ext/td/td/generate/tl-parser/tlc.c b/lib/tgchat/ext/td/td/generate/tl-parser/tlc.c new file mode 100644 index 00000000..faddf940 --- /dev/null +++ b/lib/tgchat/ext/td/td/generate/tl-parser/tlc.c @@ -0,0 +1,165 @@ +/* + This file is part of tl-parser + + tl-parser is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + tl-parser is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this tl-parser. If not, see . + + Copyright Vitaly Valtman 2014 + + It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) + Copyright 2012-2013 Vkontakte Ltd + 2012-2013 Vitaliy Valtman + +*/ + +#include +#include +#include + +#include "tl-parser.h" + +#ifndef _WIN32 +#include +#endif + +#include +#include +#include + +#include + +#ifdef HAVE_EXECINFO_H +#include +#endif +#include + +int verbosity; +int output_expressions; +void usage (void) { + printf ("usage: tl-parser [-v] [-h] \n" + "\tTL compiler\n" + "\t-v\toutput statistical and debug information into stderr\n" + "\t-E\twhenever is possible output to stdout expressions\n" + "\t-e \texport serialized schema to file\n" + ); + exit (2); +} + +int vkext_write (const char *filename) { + FILE *f = fopen(filename, "wb"); + assert (f != NULL); + write_types (f); + fclose (f); + return 0; +} + +void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); +void logprintf (const char *format __attribute__ ((unused)), ...) { + va_list ap; + va_start (ap, format); + vfprintf (stderr, format, ap); + va_end (ap); +} + +void hexdump (int *in_ptr, int *in_end) { + int *ptr = in_ptr; + while (ptr < in_end) { printf (" %08x", *(ptr ++)); } + printf ("\n"); +} + +#ifdef HAVE_EXECINFO_H +void print_backtrace (void) { + void *buffer[255]; + const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *)); + backtrace_symbols_fd (buffer, calls, 1); +} +#else +void print_backtrace (void) { + if (fwrite ("No libexec. Backtrace disabled\n", 32, 1, stderr) < 0) { + // Sad thing + } +} +#endif + +void sig_segv_handler (int signum __attribute__ ((unused))) { + if (fwrite ("SIGSEGV received\n", 18, 1, stderr) < 0) { + // Sad thing + } + print_backtrace (); + exit (EXIT_FAILURE); +} + +void sig_abrt_handler (int signum __attribute__ ((unused))) { + if (fwrite ("SIGABRT received\n", 18, 1, stderr) < 0) { + // Sad thing + } + print_backtrace (); + exit (EXIT_FAILURE); +} + +int main (int argc, char **argv) { + signal (SIGSEGV, sig_segv_handler); + signal (SIGABRT, sig_abrt_handler); + int i; + char *vkext_file = 0; + while ((i = getopt (argc, argv, "Ehve:w:")) != -1) { + switch (i) { + case 'E': + output_expressions++; + break; + case 'h': + usage (); + return 2; + case 'e': + vkext_file = optarg; + break; + case 'v': + verbosity++; + break; + } + } + + if (argc != optind + 1) { + usage (); + } + + + struct parse *P = tl_init_parse_file (argv[optind]); + if (!P) { + return 1; + } + struct tree *T; + if (!(T = tl_parse_lex (P))) { + fprintf (stderr, "Error in parse:\n"); + tl_print_parse_error (); + return 1; + } else { + if (verbosity) { + fprintf (stderr, "Parse ok\n"); + } + if (!tl_parse (T)) { + if (verbosity) { + fprintf (stderr, "Fail\n"); + } + return 1; + } else { + if (verbosity) { + fprintf (stderr, "Ok\n"); + } + } + } + if (vkext_file) { + vkext_write (vkext_file); + } + return 0; +} diff --git a/lib/tgchat/ext/td/td/generate/tl-parser/wgetopt.c b/lib/tgchat/ext/td/td/generate/tl-parser/wgetopt.c new file mode 100644 index 00000000..4557b921 --- /dev/null +++ b/lib/tgchat/ext/td/td/generate/tl-parser/wgetopt.c @@ -0,0 +1,1274 @@ +/* Getopt for GNU. +NOTE: getopt is now part of the C library, so if you don't know what +"Keep this file name-space clean" means, talk to drepper@gnu.org +before changing it! +Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 +Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with the GNU C Library; if not, write to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . +Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems +reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not +actually compiling the library itself. This code is part of the GNU C +Library, but also included in many other GNU distributions. Compiling +and linking in this code is a waste when using the GNU C library +(especially if it is a shared library). Rather than having every GNU +program understand `configure --with-gnu-libc' and omit the object files, +it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include +to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them +contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. */ +# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include +# ifndef _ +# define _(msgid) gettext (msgid) +# endif +# else +# define _(msgid) (msgid) +# endif +# if defined _LIBC && defined USE_IN_LIBIO +# include +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' +but it behaves differently for the user, since it allows the user +to intersperse the options with the other arguments. + +As `getopt' works, it permutes the elements of ARGV so that, +when it is done, all the options precede everything else. Thus +all application programs are extended to handle flexible argument order. + +Setting the environment variable POSIXLY_CORRECT disables permutation. +Then the behavior is completely standard. + +GNU application programs can use a third alternative mode in which +they can distinguish the relative order of options and other arguments. */ + +#include "wgetopt.h" + +/* For communication from `getopt' to the caller. +When `getopt' finds an option that takes an argument, +the argument value is returned here. +Also, when `ordering' is RETURN_IN_ORDER, +each non-option ARGV-element is returned here. */ + +char *optarg; + +/* Index in ARGV of the next element to be scanned. +This is used for communication to and from the caller +and for communication between successive calls to `getopt'. + +On entry to `getopt', zero means this is the first call; initialize. + +When `getopt' returns -1, this is the index of the first of the +non-option elements that the caller should itself scan. + +Otherwise, `optind' communicates from one call to the next +how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which +causes problems with re-calling getopt as programs generally don't +know that. */ + +int __getopt_initialized; + +/* The next char to be scanned in the option-element +in which the last option character we returned was found. +This allows us to pick up the scan where we left off. + +If this is zero, or a null string, it means resume the scan +by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message +for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. +This must be initialized on some systems to avoid linking in the +system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + +If the caller did not specify anything, +the default is REQUIRE_ORDER if the environment variable +POSIXLY_CORRECT is defined, PERMUTE otherwise. + +REQUIRE_ORDER means don't recognize them as options; +stop option processing when the first non-option is seen. +This is what Unix does. +This mode of operation is selected by either setting the environment +variable POSIXLY_CORRECT, or using `+' as the first character +of the list of option characters. + +PERMUTE is the default. We permute the contents of ARGV as we scan, +so that eventually all the non-options are at the end. This allows options +to be given in any order, even with programs that were not written to +expect this. + +RETURN_IN_ORDER is an option available to programs that were written +to expect options and other ARGV-elements in any order and that care about +the ordering of the two. We describe each non-option ARGV-element +as if it were the argument of an option with character code 1. +Using `-' as the first character of the list of option characters +selects this mode of operation. + +The special argument `--' forces an end of option-scanning regardless +of the value of `ordering'. In the case of RETURN_IN_ORDER, only +`--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries +because there are many ways it can cause trouble. +On some systems, it contains special magic macros that don't work +in GCC. */ +# include +# define my_index strchr +#else + +#define HAVE_STRING_H 1 +# if HAVE_STRING_H +# include +# else +# include +# endif + +/* Avoid depending on library functions or files +whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv(); +#endif + +static char * +my_index(str, chr) +const char *str; +int chr; +{ + while (*str) + { + if (*str == chr) + return (char *)str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. +If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. +That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, +and has done so at least since version 2.4.5. -- rms. */ +extern int strlen(const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have +been skipped. `first_nonopt' is the index in ARGV of the first of them; +`last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Stored original parameters. +XXX This is no good solution. We should rather copy the args so +that we can compare them later. But we must not use malloc(3). */ +extern int __libc_argc; +extern char **__libc_argv; + +/* Bash 2.0 gives us an environment variable containing flags +indicating ARGV elements that should not be considered arguments. */ + +# ifdef USE_NONOPTION_FLAGS +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; +# endif + +# ifdef USE_NONOPTION_FLAGS +# define SWAP_FLAGS(ch1, ch2) \ +if (nonoption_flags_len > 0) \ +{ \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ +} +# else +# define SWAP_FLAGS(ch1, ch2) +# endif +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. +One subsequence is elements [first_nonopt,last_nonopt) +which contains all the non-options that have been skipped so far. +The other is elements [last_nonopt,optind), which contains all +the options processed since those non-options were skipped. + +`first_nonopt' and `last_nonopt' are relocated so that they describe +the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange(char **); +#endif + +static void +exchange(argv) +char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc(top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset(__mempcpy(new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS(bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS(bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize(int, char *const *, const char *); +#endif +static const char * +_getopt_initialize(argc, argv, optstring) +int argc; +char *const *argv; +const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + if (posixly_correct == NULL + && argc == __libc_argc && argv == __libc_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen(orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *)malloc(nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset(__mempcpy(__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters +given in OPTSTRING. + +If an element of ARGV starts with '-', and is not exactly "-" or "--", +then it is an option element. The characters of this element +(aside from the initial '-') are option characters. If `getopt' +is called repeatedly, it returns successively each of the option characters +from each of the option elements. + +If `getopt' finds another option character, it returns that character, +updating `optind' and `nextchar' so that the next call to `getopt' can +resume the scan with the following option character or ARGV-element. + +If there are no more option characters, `getopt' returns -1. +Then `optind' is the index in ARGV of the first ARGV-element +that is not an option. (The ARGV-elements have been permuted +so that those that are not options now come last.) + +OPTSTRING is a string containing the legitimate option characters. +If an option character is seen that is not listed in OPTSTRING, +return '?' after printing an error message. If you set `opterr' to +zero, the error message is suppressed but we still return '?'. + +If a char in OPTSTRING is followed by a colon, that means it wants an arg, +so the following text in the same ARGV-element, or the text of the following +ARGV-element, is returned in `optarg'. Two colons mean an option that +wants an optional arg; if there is text in the current ARGV-element, +it is returned in `optarg', otherwise `optarg' is set to zero. + +If OPTSTRING starts with `-' or `+', it requests different methods of +handling the non-option ARGV-elements. +See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + +Long-named options begin with `--' instead of `-'. +Their names may be abbreviated as long as the abbreviation is unique +or is an exact match for some defined option. If they have an +argument, it follows the option name in the same ARGV-element, separated +from the option name by a `=', or else the in next ARGV-element. +When `getopt' finds a long-named option, it returns 0 if that option's +`flag' field is nonzero, the value of the option's `val' field +if the `flag' field is zero. + +The elements of ARGV aren't really const, because we permute them. +But we pretend they're const in the prototype to be compatible +with other systems. + +LONGOPTS is a vector of `struct option' terminated by an +element containing a name which is zero. + +LONGIND returns the index in LONGOPT of the long-named option found. +It is only valid when a long-named option has been found by the most +recent call. + +If LONG_ONLY is nonzero, '-' as well as '--' can introduce +long-named options. */ + +int +_getopt_internal(argc, argv, optstring, longopts, longind, long_only) +int argc; +char *const *argv; +const char *optstring; +const struct option *longopts; +int *longind; +int long_only; +{ + int print_errors = opterr; + if (optstring[0] == ':') + print_errors = 0; + + if (argc < 1) + return -1; + + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize(argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#if defined _LIBC && defined USE_NONOPTION_FLAGS +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange((char **)argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp(argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange((char **)argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index(optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int)(nameend - nextchar) + == (unsigned int)strlen(p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else if (long_only + || pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); +#endif + } + nextchar += strlen(nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; +#endif + + if (argv[optind - 1][1] == '-') + { + /* --option */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("\ + %s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); +#else + fprintf(stderr, _("\ + %s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); +#endif + } + else + { + /* +option or -option */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("\ + %s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], + pfound->name); +#else + fprintf(stderr, _("\ + %s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#endif + } + + nextchar += strlen(nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); +#endif + } + nextchar += strlen(nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen(nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index(optstring, *nextchar) == NULL) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; +#endif + + if (argv[optind][1] == '-') + { + /* --option */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); +#else + fprintf(stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); +#endif + } + else + { + /* +option or -option */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); +#else + fprintf(stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#endif + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index(optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; +#endif + + if (posixly_correct) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: illegal option -- %c\n"), + argv[0], c); +#else + fprintf(stderr, _("%s: illegal option -- %c\n"), argv[0], c); +#endif + } + else + { +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: invalid option -- %c\n"), + argv[0], c); +#else + fprintf(stderr, _("%s: invalid option -- %c\n"), argv[0], c); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#endif + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("%s: option requires an argument -- %c\n"), + argv[0], c); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); +#endif + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int)(nameend - nextchar) == strlen(p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); +#endif + } + nextchar += strlen(nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("\ + %s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, _("\ + %s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); +#endif + } + + nextchar += strlen(nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("\ + %s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); +#endif + } + nextchar += strlen(nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen(nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); +#endif + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt(argc, argv, optstring) +int argc; +char *const *argv; +const char *optstring; +{ + return _getopt_internal(argc, argv, optstring, + (const struct option *) 0, + (int *)0, + 0); +} + + + + +int +getopt_long(int argc, char *const *argv, const char *options, +const struct option *long_options, int *opt_index) +{ + return _getopt_internal(argc, argv, options, long_options, opt_index, 0, 0); +} + +int +getopt_long_only(int argc, char *const *argv, const char *options, +const struct option *long_options, int *opt_index) +{ + return _getopt_internal(argc, argv, options, long_options, opt_index, 1, 0); +} + + + + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing +the above definition of `getopt'. */ + +int +main(argc, argv) +int argc; +char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt(argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf("option %c\n", c); + break; + + case 'a': + printf("option a\n"); + break; + + case 'b': + printf("option b\n"); + break; + + case 'c': + printf("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf("non-option ARGV-elements: "); + while (optind < argc) + printf("%s ", argv[optind++]); + printf("\n"); + } + + exit(0); +} + +#endif /* TEST */ diff --git a/lib/tgchat/ext/td/td/generate/tl-parser/wgetopt.h b/lib/tgchat/ext/td/td/generate/tl-parser/wgetopt.h new file mode 100644 index 00000000..6e2fa271 --- /dev/null +++ b/lib/tgchat/ext/td/td/generate/tl-parser/wgetopt.h @@ -0,0 +1,193 @@ +/* Declarations for getopt. + Copyright (C) 1989-1994,1996-1999,2001,2003,2004,2009,2010 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _GETOPT_H + +#ifndef __need_getopt +# define _GETOPT_H 1 +#endif + +/* If __GNU_LIBRARY__ is not already defined, either we are being used + standalone, or this is the first header included in the source file. + If we are being used with glibc, we need to include , but + that does not exist if we are standalone. So: if __GNU_LIBRARY__ is + not defined, include , which will pull in for us + if it's from glibc. (Why ctype.h? It's guaranteed to exist and it + doesn't flood the namespace with stuff the way some other headers do.) */ +#if !defined __GNU_LIBRARY__ +# include +#endif + +#ifndef __THROW +# ifndef __GNUC_PREREQ +# define __GNUC_PREREQ(maj, min) (0) +# endif +# if defined __cplusplus && __GNUC_PREREQ (2,8) +# define __THROW throw () +# else +# define __THROW +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#ifndef __need_getopt +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) + __THROW; + +# if defined __need_getopt && defined __USE_POSIX2 \ + && !defined __USE_POSIX_IMPLICITLY && !defined __USE_GNU +/* The GNU getopt has more functionality than the standard version. The + additional functionality can be disable at runtime. This redirection + helps to also do this at runtime. */ +# ifdef __REDIRECT + extern int __REDIRECT_NTH (getopt, (int ___argc, char *const *___argv, + const char *__shortopts), + __posix_getopt); +# else +extern int __posix_getopt (int ___argc, char *const *___argv, + const char *__shortopts) __THROW; +# define getopt __posix_getopt +# endif +# endif +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ + +#ifndef __need_getopt +extern int getopt_long (int ___argc, char *const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind) + __THROW; +extern int getopt_long_only (int ___argc, char *const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind) + __THROW; + +#endif + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_getopt + +#endif /* getopt.h */ diff --git a/lib/tgchat/ext/td/td/generate/tl_json_converter.cpp b/lib/tgchat/ext/td/td/generate/tl_json_converter.cpp index d9890647..5068dc94 100644 --- a/lib/tgchat/ext/td/td/generate/tl_json_converter.cpp +++ b/lib/tgchat/ext/td/td/generate/tl_json_converter.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -11,8 +11,8 @@ #include "td/utils/buffer.h" #include "td/utils/common.h" #include "td/utils/filesystem.h" -#include "td/utils/logging.h" #include "td/utils/Slice.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/StringBuilder.h" #include diff --git a/lib/tgchat/ext/td/td/generate/tl_json_converter.h b/lib/tgchat/ext/td/td/generate/tl_json_converter.h index 862053ce..04e05cb8 100644 --- a/lib/tgchat/ext/td/td/generate/tl_json_converter.h +++ b/lib/tgchat/ext/td/td/generate/tl_json_converter.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_c.h b/lib/tgchat/ext/td/td/generate/tl_writer_c.h index 1f23711e..a85f00c0 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_c.h +++ b/lib/tgchat/ext/td/td/generate/tl_writer_c.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,7 +16,7 @@ namespace td { -class TlWriterCCommon : public tl::TL_writer { +class TlWriterCCommon final : public tl::TL_writer { public: int is_header_; std::string prefix_; @@ -24,47 +24,47 @@ class TlWriterCCommon : public tl::TL_writer { : TL_writer(name), is_header_(is_header), prefix_(prefix) { } - int get_max_arity() const override { + int get_max_arity() const final { return 0; } - bool is_built_in_simple_type(const std::string &name) const override { + bool is_built_in_simple_type(const std::string &name) const final { return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Double" || name == "String" || name == "Bytes"; } - bool is_built_in_complex_type(const std::string &name) const override { + bool is_built_in_complex_type(const std::string &name) const final { return name == "Vector"; } - bool is_type_bare(const tl::tl_type *t) const override { + bool is_type_bare(const tl::tl_type *t) const final { return t->simple_constructors <= 1 || (is_built_in_simple_type(t->name) && t->name != "Bool") || is_built_in_complex_type(t->name); } - std::vector get_parsers() const override { + std::vector get_parsers() const final { return {}; } - int get_parser_type(const tl::tl_combinator *t, const std::string &name) const override { + int get_parser_type(const tl::tl_combinator *t, const std::string &name) const final { return 0; } - std::vector get_storers() const override { + std::vector get_storers() const final { return {}; } - std::vector get_additional_functions() const override { + std::vector get_additional_functions() const final { return {"TdConvertToInternal", "TdConvertFromInternal", "TdSerialize", "TdToString", "TdDestroyObject", "TdStackStorer", "TdStackFetcher", "enum"}; } - int get_storer_type(const tl::tl_combinator *t, const std::string &name) const override { + int get_storer_type(const tl::tl_combinator *t, const std::string &name) const final { return name == "to_string" || name == "to_cpp_string"; } - std::string gen_base_tl_class_name() const override { + std::string gen_base_tl_class_name() const final { return "Object"; } - std::string gen_base_type_class_name(int arity) const override { + std::string gen_base_type_class_name(int arity) const final { assert(arity == 0); return "Object"; } - std::string gen_base_function_class_name() const override { + std::string gen_base_function_class_name() const final { return "Function"; } @@ -118,13 +118,13 @@ class TlWriterCCommon : public tl::TL_writer { return name; } - std::string gen_class_name(std::string name) const override { + std::string gen_class_name(std::string name) const final { if (name == "Object" || name == "#") { assert(false); } return to_CamelCase(name); } - std::string gen_field_name(std::string name) const override { + std::string gen_field_name(std::string name) const final { return gen_native_field_name(name); } @@ -220,10 +220,10 @@ class TlWriterCCommon : public tl::TL_writer { return !force ? ("struct Td" + gen_main_class_name(t) + " *") : gen_main_class_name(t); } - std::string gen_type_name(const tl::tl_tree_type *tree_type) const override { + std::string gen_type_name(const tl::tl_tree_type *tree_type) const final { return gen_type_name(tree_type, false); } - std::string gen_output_begin() const override { + std::string gen_output_begin() const final { if (is_header_ == 1) { return "#pragma once\n" "#ifdef __cplusplus\n" @@ -242,7 +242,7 @@ class TlWriterCCommon : public tl::TL_writer { "TDC_VECTOR(Int,int)\n" "TDC_VECTOR(Long,long long)\n" "TDC_VECTOR(String,char *)\n" - "TDC_VECTOR(Bytes,TdBytes)\n" + "TDC_VECTOR(Bytes,struct TdBytes)\n" "struct TdStackStorerMethods {\n" " void (*pack_string)(const char *s);\n" " void (*pack_bytes)(const unsigned char *s, int len);\n" @@ -276,10 +276,9 @@ class TlWriterCCommon : public tl::TL_writer { "#include \"td/utils/logging.h\"\n" "#include \"td/utils/misc.h\"\n" "#include \"td/utils/Slice.h\"\n" - "#include \"td/utils/tl_storers.h\"\n" "\n"; } - std::string gen_output_end() const override { + std::string gen_output_end() const final { if (is_header_ == 1) { return "#ifdef __cplusplus\n" "}\n" @@ -290,7 +289,7 @@ class TlWriterCCommon : public tl::TL_writer { return ""; } - std::string gen_forward_class_declaration(const std::string &class_name, bool is_proxy) const override { + std::string gen_forward_class_declaration(const std::string &class_name, bool is_proxy) const final { if (is_header_ != 1 || class_name == "") { return ""; } @@ -304,7 +303,7 @@ class TlWriterCCommon : public tl::TL_writer { } std::string gen_class_begin(const std::string &class_name, const std::string &base_class_name, - bool is_proxy) const override { + bool is_proxy) const final { if (is_header_ != 1 || class_name == "") { return ""; } @@ -315,12 +314,12 @@ class TlWriterCCommon : public tl::TL_writer { } return "struct Td" + class_name + " {\n" + " int ID;\n int refcnt;\n" + tail; } - std::string gen_class_end() const override { + std::string gen_class_end() const final { return ""; } std::string gen_field_definition(const std::string &class_name, const std::string &type_name, - const std::string &field_name) const override { + const std::string &field_name) const final { if (is_header_ != 1 || class_name == "") { return ""; } @@ -328,14 +327,14 @@ class TlWriterCCommon : public tl::TL_writer { } std::string gen_store_function_begin(const std::string &storer_name, const std::string &class_name, int arity, - std::vector &vars, int storer_type) const override { + std::vector &vars, int storer_type) const final { return ""; } - std::string gen_store_function_end(const std::vector &vars, int storer_type) const override { + std::string gen_store_function_end(const std::vector &vars, int storer_type) const final { return ""; } - std::string gen_constructor_begin(int field_count, const std::string &class_name, bool is_default) const override { + std::string gen_constructor_begin(int field_count, const std::string &class_name, bool is_default) const final { if (!is_default || is_header_ == -1 || class_name == "") { return ""; } @@ -348,7 +347,7 @@ class TlWriterCCommon : public tl::TL_writer { return ss.str(); } std::string gen_constructor_parameter(int field_num, const std::string &class_name, const tl::arg &a, - bool is_default) const override { + bool is_default) const final { if (!is_default || is_header_ == -1) { return ""; } @@ -359,10 +358,10 @@ class TlWriterCCommon : public tl::TL_writer { return ss.str(); } std::string gen_constructor_field_init(int field_num, const std::string &class_name, const tl::arg &a, - bool is_default) const override { + bool is_default) const final { return ""; } - std::string gen_constructor_end(const tl::tl_combinator *t, int field_count, bool is_default) const override { + std::string gen_constructor_end(const tl::tl_combinator *t, int field_count, bool is_default) const final { if (!is_default || is_header_ == -1) { return ""; } @@ -389,7 +388,7 @@ class TlWriterCCommon : public tl::TL_writer { return ss.str(); } std::string gen_additional_function(const std::string &function_name, const tl::tl_combinator *t, - bool is_function) const override { + bool is_function) const final { std::stringstream ss; if (function_name == "enum") { return ss.str(); @@ -547,11 +546,11 @@ class TlWriterCCommon : public tl::TL_writer { } }; - struct file_store_methods_to_td : public file_store_methods { + struct file_store_methods_to_td final : public file_store_methods { explicit file_store_methods_to_td(const class TlWriterCCommon *cl) : cl(cl) { } void store_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string type_name) const override { + std::string type_name) const final { if (type_name == "String") { ss << offset << res_var << " = (" << var << ") ? " << var << ": \"\";\n"; } else if (type_name == "Bytes") { @@ -563,35 +562,35 @@ class TlWriterCCommon : public tl::TL_writer { } } void store_common_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string type_name) const override { + std::string type_name) const final { ss << offset << res_var << " = TdConvertToInternal (" << var << ");\n"; } void store_array_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { } void store_array_el(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string idx) const override { + std::string idx) const final { ss << offset << res_var << ".push_back (std::move (" << var << "));\n"; } void store_array_finish(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { } - void store_nil(std::stringstream &ss, std::string offset) const override { + void store_nil(std::stringstream &ss, std::string offset) const final { ss << offset << "return nullptr;\n"; } std::string store_field_start(std::stringstream &ss, std::string offset, int depth, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { std::string res_var = "v" + int_to_string(depth); ss << offset << cl->gen_native_type_name(tree_type, true) << " " << res_var << ";\n"; return res_var; } - void store_field_finish(std::stringstream &ss, std::string offset, std::string res_var) const override { + void store_field_finish(std::stringstream &ss, std::string offset, std::string res_var) const final { } void store_arg_finish(std::stringstream &ss, std::string offset, std::string arg_name, - std::string res_var) const override { + std::string res_var) const final { } void store_constructor_finish(std::stringstream &ss, std::string offset, const tl::tl_combinator *t, - std::vector res_var) const override { + std::vector res_var) const final { auto native_class_name = cl->gen_native_class_name(t->name); ss << offset << "return td::td_api::make_object("; bool is_first = true; @@ -609,11 +608,11 @@ class TlWriterCCommon : public tl::TL_writer { const class TlWriterCCommon *cl; }; - struct file_store_methods_destroy : public file_store_methods { + struct file_store_methods_destroy final : public file_store_methods { explicit file_store_methods_destroy(const class TlWriterCCommon *cl) : cl(cl) { } void store_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string type_name) const override { + std::string type_name) const final { if (type_name == "String") { ss << offset << "free (" << var << ");\n"; } else if (type_name == "Bytes") { @@ -621,32 +620,32 @@ class TlWriterCCommon : public tl::TL_writer { } } void store_common_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string type_name) const override { + std::string type_name) const final { ss << offset << "TdDestroyObject (" << var << ");\n"; } void store_array_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { } void store_array_el(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string idx) const override { + std::string idx) const final { } void store_array_finish(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { ss << offset << "delete[] " << var << "->data;\n" << offset << "delete " << var << ";\n"; } - void store_nil(std::stringstream &ss, std::string offset) const override { + void store_nil(std::stringstream &ss, std::string offset) const final { ss << offset << "return;\n"; } std::string store_field_start(std::stringstream &ss, std::string offset, int depth, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { return ""; } - void store_field_finish(std::stringstream &ss, std::string offset, std::string res_var) const override { + void store_field_finish(std::stringstream &ss, std::string offset, std::string res_var) const final { } void store_arg_finish(std::stringstream &ss, std::string offset, std::string arg_name, - std::string res_var) const override { + std::string res_var) const final { } - void store_constructor_start(std::stringstream &ss, std::string offset, const tl::tl_combinator *t) const override { + void store_constructor_start(std::stringstream &ss, std::string offset, const tl::tl_combinator *t) const final { ss << "#if TD_MSVC\n"; ss << offset << "static_assert (sizeof (long) == sizeof (var->refcnt), \"Illegal InterlockedDecrement\");\n"; ss << offset << "int ref = InterlockedDecrement (reinterpret_cast(&var->refcnt));\n"; @@ -661,16 +660,16 @@ class TlWriterCCommon : public tl::TL_writer { ss << offset << "}\n"; } void store_constructor_finish(std::stringstream &ss, std::string offset, const tl::tl_combinator *t, - std::vector res_var) const override { + std::vector res_var) const final { ss << offset << "delete var;\n"; } const class TlWriterCCommon *cl; }; - struct file_store_methods_stack : public file_store_methods { + struct file_store_methods_stack final : public file_store_methods { explicit file_store_methods_stack(const class TlWriterCCommon *cl) : cl(cl) { } void store_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string type_name) const override { + std::string type_name) const final { if (type_name == "String") { ss << offset << "M->pack_string (" << var << ");\n"; } else if (type_name == "Bytes") { @@ -686,41 +685,41 @@ class TlWriterCCommon : public tl::TL_writer { } } void store_common_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string type_name) const override { + std::string type_name) const final { ss << offset << "TdStackStorer (" << var << ", M);\n"; } void store_array_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { ss << offset << "M->new_array ();\n"; } void store_array_el(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string idx) const override { + std::string idx) const final { ss << offset << "M->new_arr_field (" << idx << ");\n"; } void store_array_finish(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { } - void store_nil(std::stringstream &ss, std::string offset) const override { + void store_nil(std::stringstream &ss, std::string offset) const final { ss << offset << "M->pack_bool (0);\n" << offset << "return;\n"; } std::string store_field_start(std::stringstream &ss, std::string offset, int depth, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { return ""; } - void store_field_finish(std::stringstream &ss, std::string offset, std::string res_var) const override { + void store_field_finish(std::stringstream &ss, std::string offset, std::string res_var) const final { } void store_arg_finish(std::stringstream &ss, std::string offset, std::string arg_name, - std::string res_var) const override { + std::string res_var) const final { ss << offset << "M->new_field (\"" << arg_name << "\");\n"; } - void store_constructor_start(std::stringstream &ss, std::string offset, const tl::tl_combinator *t) const override { + void store_constructor_start(std::stringstream &ss, std::string offset, const tl::tl_combinator *t) const final { ss << offset << "M->new_table ();\n"; auto class_name = cl->gen_class_name(t->name); ss << offset << "M->pack_string (\"" << class_name << "\");\n"; ss << offset << "M->new_field (\"ID\");\n"; } void store_constructor_finish(std::stringstream &ss, std::string offset, const tl::tl_combinator *t, - std::vector res_var) const override { + std::vector res_var) const final { } const class TlWriterCCommon *cl; }; @@ -767,15 +766,15 @@ class TlWriterCCommon : public tl::TL_writer { } }; - struct file_fetch_methods_from_td : public file_fetch_methods { + struct file_fetch_methods_from_td final : public file_fetch_methods { explicit file_fetch_methods_from_td(const class TlWriterCCommon *cl) : cl(cl) { } std::string fetch_field_start(std::stringstream &ss, std::string offset, int depth, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { return ""; } void fetch_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string type_name) const override { + std::string type_name) const final { if (type_name == "String") { ss << offset << res_var << " = (" << var << ".length ()) ? td::str_dup (" << var << ") : nullptr;\n"; } else if (type_name == "Bytes") { @@ -791,7 +790,7 @@ class TlWriterCCommon : public tl::TL_writer { } } void fetch_common_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { auto native_type_name = cl->gen_native_type_name(tree_type, false); ss << offset << "if (!" << var << ") {\n" << offset << " " << res_var << " = nullptr;\n" @@ -801,32 +800,32 @@ class TlWriterCCommon : public tl::TL_writer { << offset << "}\n"; } void fetch_array_size(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { ss << offset << res_var << " = (int)" << var << ".size ();\n"; } std::string fetch_array_field_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string idx, const tl::tl_tree_type *tree_type) const override { + std::string idx, const tl::tl_tree_type *tree_type) const final { return var + "[" + idx + "]"; } std::string fetch_dict_field_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string key, const tl::tl_tree_type *tree_type) const override { + std::string key, const tl::tl_tree_type *tree_type) const final { return var + "." + key; } void fetch_field_finish(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { } const class TlWriterCCommon *cl; }; - struct file_fetch_methods_stack : public file_fetch_methods { + struct file_fetch_methods_stack final : public file_fetch_methods { explicit file_fetch_methods_stack(const class TlWriterCCommon *cl) : cl(cl) { } std::string fetch_field_start(std::stringstream &ss, std::string offset, int depth, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { return ""; } void fetch_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string type_name) const override { + std::string type_name) const final { if (type_name == "String") { ss << offset << res_var << " = M->get_string ();\n"; } else if (type_name == "Bytes") { @@ -842,7 +841,7 @@ class TlWriterCCommon : public tl::TL_writer { } } void fetch_common_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { auto class_name = cl->gen_main_class_name(tree_type->type); ss << offset << "if (M->is_nil ()) {\n" << offset << " " << res_var << " = nullptr;\n" @@ -851,21 +850,21 @@ class TlWriterCCommon : public tl::TL_writer { << offset << "}\n"; } void fetch_array_size(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { ss << offset << res_var << " = M->get_arr_size ();\n"; } std::string fetch_array_field_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string idx, const tl::tl_tree_type *tree_type) const override { + std::string idx, const tl::tl_tree_type *tree_type) const final { ss << offset << " M->get_arr_field (" << idx << ");\n"; return ""; } std::string fetch_dict_field_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - std::string key, const tl::tl_tree_type *tree_type) const override { + std::string key, const tl::tl_tree_type *tree_type) const final { ss << offset << "M->get_field (\"" << key << "\");\n"; return ""; } void fetch_field_finish(std::stringstream &ss, std::string offset, std::string res_var, std::string var, - const tl::tl_tree_type *tree_type) const override { + const tl::tl_tree_type *tree_type) const final { ss << offset << "M->pop ();\n"; } const class TlWriterCCommon *cl; @@ -949,74 +948,74 @@ class TlWriterCCommon : public tl::TL_writer { << "}\n"; } - std::string gen_array_type_name(const tl::tl_tree_array *arr, const std::string &field_name) const override { + std::string gen_array_type_name(const tl::tl_tree_array *arr, const std::string &field_name) const final { assert(false); return std::string(); } - std::string gen_var_type_name() const override { + std::string gen_var_type_name() const final { assert(false); return std::string(); } - std::string gen_int_const(const tl::tl_tree *tree_c, const std::vector &vars) const override { + std::string gen_int_const(const tl::tl_tree *tree_c, const std::vector &vars) const final { assert(false); return std::string(); } - std::string gen_var_name(const tl::var_description &desc) const override { + std::string gen_var_name(const tl::var_description &desc) const final { assert(false); return ""; } - std::string gen_parameter_name(int index) const override { + std::string gen_parameter_name(int index) const final { assert(false); return ""; } - std::string gen_class_alias(const std::string &class_name, const std::string &alias_name) const override { + std::string gen_class_alias(const std::string &class_name, const std::string &alias_name) const final { return ""; } std::string gen_vars(const tl::tl_combinator *t, const tl::tl_tree_type *result_type, - std::vector &vars) const override { + std::vector &vars) const final { assert(vars.empty()); return ""; } - std::string gen_function_vars(const tl::tl_combinator *t, std::vector &vars) const override { + std::string gen_function_vars(const tl::tl_combinator *t, std::vector &vars) const final { assert(vars.empty()); return ""; } std::string gen_uni(const tl::tl_tree_type *result_type, std::vector &vars, - bool check_negative) const override { + bool check_negative) const final { assert(result_type->children.empty()); return ""; } - std::string gen_constructor_id_store(std::int32_t id, int storer_type) const override { + std::string gen_constructor_id_store(std::int32_t id, int storer_type) const final { return ""; } std::string gen_field_fetch(int field_num, const tl::arg &a, std::vector &vars, bool flat, - int parser_type) const override { + int parser_type) const final { return ""; } std::string gen_field_store(const tl::arg &a, std::vector &vars, bool flat, - int storer_type) const override { + int storer_type) const final { return ""; } std::string gen_type_fetch(const std::string &field_name, const tl::tl_tree_type *tree_type, - const std::vector &vars, int parser_type) const override { + const std::vector &vars, int parser_type) const final { assert(vars.empty()); return ""; } std::string gen_type_store(const std::string &field_name, const tl::tl_tree_type *tree_type, - const std::vector &vars, int storer_type) const override { + const std::vector &vars, int storer_type) const final { return ""; } - std::string gen_var_type_fetch(const tl::arg &a) const override { + std::string gen_var_type_fetch(const tl::arg &a) const final { assert(false); return ""; } - std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const override { + std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const final { if (is_proxy || is_header_ != 1) { return ""; } @@ -1024,47 +1023,47 @@ class TlWriterCCommon : public tl::TL_writer { return ""; } - std::string gen_function_result_type(const tl::tl_tree *result) const override { + std::string gen_function_result_type(const tl::tl_tree *result) const final { return ""; } std::string gen_fetch_function_begin(const std::string &parser_name, const std::string &class_name, const std::string &parent_class_name, int arity, int field_count, - std::vector &vars, int parser_type) const override { + std::vector &vars, int parser_type) const final { return ""; } std::string gen_fetch_function_end(bool has_parent, int field_count, const std::vector &vars, - int parser_type) const override { + int parser_type) const final { return ""; } std::string gen_fetch_function_result_begin(const std::string &parser_name, const std::string &class_name, - const tl::tl_tree *result) const override { + const tl::tl_tree *result) const final { return ""; } - std::string gen_fetch_function_result_end() const override { + std::string gen_fetch_function_result_end() const final { return ""; } std::string gen_fetch_function_result_any_begin(const std::string &parser_name, const std::string &class_name, - bool is_proxy) const override { + bool is_proxy) const final { return ""; } - std::string gen_fetch_function_result_any_end(bool is_proxy) const override { + std::string gen_fetch_function_result_any_end(bool is_proxy) const final { return ""; } - std::string gen_fetch_switch_begin() const override { + std::string gen_fetch_switch_begin() const final { return ""; } - std::string gen_fetch_switch_case(const tl::tl_combinator *t, int arity) const override { + std::string gen_fetch_switch_case(const tl::tl_combinator *t, int arity) const final { return ""; } - std::string gen_fetch_switch_end() const override { + std::string gen_fetch_switch_end() const final { return ""; } std::string gen_additional_proxy_function_begin(const std::string &function_name, const tl::tl_type *type, - const std::string &name, int arity, bool is_function) const override { + const std::string &name, int arity, bool is_function) const final { std::stringstream ss; std::string class_name; std::string native_class_name; @@ -1208,7 +1207,7 @@ class TlWriterCCommon : public tl::TL_writer { } std::string gen_additional_proxy_function_case(const std::string &function_name, const tl::tl_type *type, - const std::string &class_name, int arity) const override { + const std::string &class_name, int arity) const final { if (is_header_ != (function_name == "enum" ? 1 : 0)) { return ""; } @@ -1243,8 +1242,7 @@ class TlWriterCCommon : public tl::TL_writer { } std::string gen_additional_proxy_function_case(const std::string &function_name, const tl::tl_type *type, - const tl::tl_combinator *t, int arity, - bool is_function) const override { + const tl::tl_combinator *t, int arity, bool is_function) const final { if (is_header_ != (function_name == "enum" ? 1 : 0)) { return ""; } @@ -1321,7 +1319,7 @@ class TlWriterCCommon : public tl::TL_writer { } } std::string gen_additional_proxy_function_end(const std::string &function_name, const tl::tl_type *type, - bool is_function) const override { + bool is_function) const final { if (is_header_ != (function_name == "enum" ? 1 : 0)) { return ""; } @@ -1352,7 +1350,7 @@ class TlWriterCCommon : public tl::TL_writer { } } - int get_additional_function_type(const std::string &additional_function_name) const override { + int get_additional_function_type(const std::string &additional_function_name) const final { return 2; } }; diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_cpp.cpp b/lib/tgchat/ext/td/td/generate/tl_writer_cpp.cpp index 044a228d..adb9b7e8 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_cpp.cpp +++ b/lib/tgchat/ext/td/td/generate/tl_writer_cpp.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -23,8 +23,10 @@ std::string TD_TL_writer_cpp::gen_output_begin() const { "#include \"td/utils/common.h\"\n" "#include \"td/utils/format.h\"\n" "#include \"td/utils/logging.h\"\n" + "#include \"td/utils/SliceBuilder.h\"\n" "#include \"td/utils/tl_parsers.h\"\n" - "#include \"td/utils/tl_storers.h\"\n\n" + "#include \"td/utils/tl_storers.h\"\n" + "#include \"td/utils/TlStorerToString.h\"\n\n" "namespace td {\n" "namespace " + tl_name + @@ -32,7 +34,7 @@ std::string TD_TL_writer_cpp::gen_output_begin() const { "std::string to_string(const BaseObject &value) {\n" " TlStorerToString storer;\n" " value.store(storer, \"\");\n" - " return storer.move_as_str();\n" + " return storer.move_as_string();\n" "}\n"; } @@ -282,7 +284,7 @@ std::string TD_TL_writer_cpp::gen_var_type_fetch(const tl::arg &a) const { } std::string TD_TL_writer_cpp::get_pretty_field_name(std::string field_name) const { - if (!field_name.empty() && field_name.back() == ']') { + if (!field_name.empty() && field_name[0] == '_') { return ""; } auto equals_pos = field_name.find('='); @@ -299,21 +301,22 @@ std::string TD_TL_writer_cpp::get_pretty_field_name(std::string field_name) cons } std::string TD_TL_writer_cpp::get_pretty_class_name(std::string class_name) const { + if (tl_name != "mtproto_api") { + for (std::size_t i = 0; i < class_name.size(); i++) { + if (class_name[i] == '_') { + class_name[i] = '.'; + } + } + } return class_name; } std::string TD_TL_writer_cpp::gen_vector_store(const std::string &field_name, const tl::tl_tree_type *t, const std::vector &vars, int storer_type) const { - std::string num = field_name.back() == ']' ? "2" : ""; - return "{ const array<" + gen_type_name(t) + "> &v" + num + " = " + field_name + - "; const std::uint32_t multiplicity" + num + " = static_cast(v" + num + - ".size()); const auto vector_name" + num + " = \"" + get_pretty_class_name("vector") + - "[\" + td::to_string(multiplicity" + num + ")+ \"]\"; s.store_class_begin(\"" + - get_pretty_field_name(field_name) + "\", vector_name" + num + - ".c_str()); " - "for (std::uint32_t i" + - num + " = 0; i" + num + " < multiplicity" + num + "; i" + num + "++) { " + - gen_type_store("v" + num + "[i" + num + "]", t, vars, storer_type) + " } s.store_class_end(); }"; + std::string num = !field_name.empty() && field_name[0] == '_' ? "2" : ""; + return "{ s.store_vector_begin(\"" + get_pretty_field_name(field_name) + "\", " + field_name + + ".size()); for (const auto &_value" + num + " : " + field_name + ") { " + + gen_type_store("_value" + num, t, vars, storer_type) + " } s.store_class_end(); }"; } std::string TD_TL_writer_cpp::gen_store_class_name(const tl::tl_tree_type *tree_type) const { @@ -328,7 +331,8 @@ std::string TD_TL_writer_cpp::gen_store_class_name(const tl::tl_tree_type *tree_ return "TlStoreBool"; } if (name == "True") { - return "TlStoreTrue"; + assert(false); + return ""; } if (name == "String" || name == "Bytes") { return "TlStoreString"; @@ -403,8 +407,8 @@ std::string TD_TL_writer_cpp::gen_type_store(const std::string &field_name, cons return gen_vector_store(field_name, child, vars, storer_type); } else { assert(tree_type->children.empty()); - return "if (" + field_name + " == nullptr) { s.store_field(\"" + get_pretty_field_name(field_name) + - "\", \"null\"); } else { " + field_name + "->store(s, \"" + get_pretty_field_name(field_name) + "\"); }"; + return "s.store_object_field(\"" + get_pretty_field_name(field_name) + "\", static_cast(" + + field_name + ".get()));"; } } @@ -442,6 +446,13 @@ std::string TD_TL_writer_cpp::gen_field_store(const tl::arg &a, std::vector= 0 && a.var_num < 0 && a.type->get_type() == tl::NODE_TYPE_TYPE) { + const tl::tl_tree_type *tree_type = static_cast(a.type); + if (tree_type->type->name == "True") { + return ""; + } + } + if (a.exist_var_num >= 0) { assert(a.exist_var_num < static_cast(vars.size())); assert(vars[a.exist_var_num].is_stored); diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_cpp.h b/lib/tgchat/ext/td/td/generate/tl_writer_cpp.h index f757ea7f..63941eea 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_cpp.h +++ b/lib/tgchat/ext/td/td/generate/tl_writer_cpp.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_dotnet.h b/lib/tgchat/ext/td/td/generate/tl_writer_dotnet.h index d3ac7aa3..62dd0b1d 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_dotnet.h +++ b/lib/tgchat/ext/td/td/generate/tl_writer_dotnet.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -17,59 +17,59 @@ namespace td { namespace tl { -class TlWriterDotNet : public TL_writer { +class TlWriterDotNet final : public TL_writer { public: bool is_header_; std::string prefix_; TlWriterDotNet(const std::string &name, bool is_header, const std::string &prefix = "") : TL_writer(name), is_header_(is_header), prefix_(prefix) { } - int get_max_arity(void) const override { + int get_max_arity(void) const final { return 0; } - bool is_built_in_simple_type(const std::string &name) const override { + bool is_built_in_simple_type(const std::string &name) const final { return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Double" || name == "String" || name == "Bytes"; } - bool is_built_in_complex_type(const std::string &name) const override { + bool is_built_in_complex_type(const std::string &name) const final { return name == "Vector"; } - bool is_type_bare(const tl_type *t) const override { + bool is_type_bare(const tl_type *t) const final { return t->simple_constructors <= 1 || (is_built_in_simple_type(t->name) && t->name != "Bool") || is_built_in_complex_type(t->name); } - std::vector get_parsers(void) const override { + std::vector get_parsers(void) const final { return {"FromUnmanaged"}; } - int get_parser_type(const tl_combinator *t, const std::string &name) const override { + int get_parser_type(const tl_combinator *t, const std::string &name) const final { return 0; } - Mode get_parser_mode(int type) const override { + Mode get_parser_mode(int type) const final { return All; // Server; } - std::vector get_storers(void) const override { + std::vector get_storers(void) const final { return {"ToUnmanaged", "ToString"}; } - std::vector get_additional_functions(void) const override { + std::vector get_additional_functions(void) const final { return {"ToUnmanaged", "FromUnmanaged"}; } - int get_storer_type(const tl_combinator *t, const std::string &name) const override { + int get_storer_type(const tl_combinator *t, const std::string &name) const final { return name == "ToString"; } - Mode get_storer_mode(int type) const override { + Mode get_storer_mode(int type) const final { return type <= 1 ? All : Server; } - std::string gen_base_tl_class_name(void) const override { + std::string gen_base_tl_class_name(void) const final { return "BaseObject"; } - std::string gen_base_type_class_name(int arity) const override { + std::string gen_base_type_class_name(int arity) const final { assert(arity == 0); return "Object"; } - std::string gen_base_function_class_name(void) const override { + std::string gen_base_function_class_name(void) const final { return "Function"; } @@ -123,19 +123,19 @@ class TlWriterDotNet : public TL_writer { return name; } - std::string gen_class_name(std::string name) const override { + std::string gen_class_name(std::string name) const final { if (name == "Object" || name == "#") { assert(0); } return to_CamelCase(name); } - std::string gen_field_name(std::string name) const override { + std::string gen_field_name(std::string name) const final { assert(name.size() > 0); assert(is_alnum(name.back())); return to_CamelCase(name); } - std::string gen_type_name(const tl_tree_type *tree_type) const override { + std::string gen_type_name(const tl_tree_type *tree_type) const final { const tl_type *t = tree_type->type; const std::string &name = t->name; @@ -178,20 +178,20 @@ class TlWriterDotNet : public TL_writer { return gen_main_class_name(t) + "^"; } - std::string gen_output_begin(void) const override { + std::string gen_output_begin(void) const final { return prefix_ + "#include \"td/tl/tl_dotnet_object.h\"\n\n" "namespace Telegram {\n" "namespace Td {\n" "namespace Api {\n"; } - std::string gen_output_end() const override { + std::string gen_output_end() const final { return "}\n" "}\n" "}\n"; } - std::string gen_forward_class_declaration(const std::string &class_name, bool is_proxy) const override { + std::string gen_forward_class_declaration(const std::string &class_name, bool is_proxy) const final { if (!is_header_) { return ""; } @@ -201,7 +201,7 @@ class TlWriterDotNet : public TL_writer { } std::string gen_class_begin(const std::string &class_name, const std::string &base_class_name, - bool is_proxy) const override { + bool is_proxy) const final { if (!is_header_) { return ""; } @@ -212,12 +212,12 @@ class TlWriterDotNet : public TL_writer { << " public:\n"; return ss.str(); } - std::string gen_class_end(void) const override { + std::string gen_class_end(void) const final { return ""; } std::string gen_field_definition(const std::string &class_name, const std::string &type_name, - const std::string &field_name) const override { + const std::string &field_name) const final { if (!is_header_) { return ""; } @@ -245,7 +245,7 @@ class TlWriterDotNet : public TL_writer { } std::string gen_store_function_begin(const std::string &storer_name, const std::string &class_name, int arity, - std::vector &vars, int storer_type) const override { + std::vector &vars, int storer_type) const final { if (storer_type < 0) { return ""; } @@ -266,18 +266,18 @@ class TlWriterDotNet : public TL_writer { } return ss.str(); } - std::string gen_store_function_end(const std::vector &vars, int storer_type) const override { + std::string gen_store_function_end(const std::vector &vars, int storer_type) const final { return ""; } - std::string gen_constructor_begin(int field_count, const std::string &class_name, bool is_default) const override { + std::string gen_constructor_begin(int field_count, const std::string &class_name, bool is_default) const final { std::stringstream ss; ss << "\n"; ss << (is_header_ ? " " : gen_class_name(class_name) + "::") << gen_class_name(class_name) << "("; return ss.str(); } std::string gen_constructor_parameter(int field_num, const std::string &class_name, const arg &a, - bool is_default) const override { + bool is_default) const final { if (is_default) { return ""; } @@ -296,7 +296,7 @@ class TlWriterDotNet : public TL_writer { return ss.str(); } std::string gen_constructor_field_init(int field_num, const std::string &class_name, const arg &a, - bool is_default) const override { + bool is_default) const final { if (is_default || is_header_) { return ""; } @@ -313,7 +313,7 @@ class TlWriterDotNet : public TL_writer { return ss.str(); } - std::string gen_constructor_end(const tl_combinator *t, int field_count, bool is_default) const override { + std::string gen_constructor_end(const tl_combinator *t, int field_count, bool is_default) const final { if (is_header_) { return ");\n"; } @@ -325,7 +325,7 @@ class TlWriterDotNet : public TL_writer { return ss.str(); } std::string gen_additional_function(const std::string &function_name, const tl_combinator *t, - bool is_function) const override { + bool is_function) const final { std::stringstream ss; if (is_header_ && function_name == "ToUnmanaged") { ss << "};\n"; @@ -390,124 +390,124 @@ class TlWriterDotNet : public TL_writer { ss << ");\n}\n"; } - std::string gen_array_type_name(const tl_tree_array *arr, const std::string &field_name) const override { + std::string gen_array_type_name(const tl_tree_array *arr, const std::string &field_name) const final { assert(0); return std::string(); } - std::string gen_var_type_name(void) const override { + std::string gen_var_type_name(void) const final { assert(0); return std::string(); } - std::string gen_int_const(const tl_tree *tree_c, const std::vector &vars) const override { + std::string gen_int_const(const tl_tree *tree_c, const std::vector &vars) const final { assert(0); return std::string(); } - std::string gen_var_name(const var_description &desc) const override { + std::string gen_var_name(const var_description &desc) const final { assert(0); return ""; } - std::string gen_parameter_name(int index) const override { + std::string gen_parameter_name(int index) const final { assert(0); return ""; } - std::string gen_class_alias(const std::string &class_name, const std::string &alias_name) const override { + std::string gen_class_alias(const std::string &class_name, const std::string &alias_name) const final { return ""; } std::string gen_vars(const tl_combinator *t, const tl_tree_type *result_type, - std::vector &vars) const override { + std::vector &vars) const final { assert(vars.empty()); return ""; } - std::string gen_function_vars(const tl_combinator *t, std::vector &vars) const override { + std::string gen_function_vars(const tl_combinator *t, std::vector &vars) const final { assert(vars.empty()); return ""; } std::string gen_uni(const tl_tree_type *result_type, std::vector &vars, - bool check_negative) const override { + bool check_negative) const final { assert(result_type->children.empty()); return ""; } - std::string gen_constructor_id_store(std::int32_t id, int storer_type) const override { + std::string gen_constructor_id_store(std::int32_t id, int storer_type) const final { return ""; } std::string gen_field_fetch(int field_num, const arg &a, std::vector &vars, bool flat, - int parser_type) const override { + int parser_type) const final { return ""; // std::stringstream ss; // ss << gen_field_name(a.name) << " = from_unmanaged(from->" << // gen_native_field_name(a.name) << ");\n"; return ss.str(); } std::string gen_field_store(const arg &a, std::vector &vars, bool flat, - int storer_type) const override { + int storer_type) const final { return ""; // std::stringstream ss; // ss << "to_unmanaged(" << gen_field_name(a.name) << ")"; // return ss.str(); } std::string gen_type_fetch(const std::string &field_name, const tl_tree_type *tree_type, - const std::vector &vars, int parser_type) const override { + const std::vector &vars, int parser_type) const final { assert(vars.empty()); return ""; } std::string gen_type_store(const std::string &field_name, const tl_tree_type *tree_type, - const std::vector &vars, int storer_type) const override { + const std::vector &vars, int storer_type) const final { return ""; } - std::string gen_var_type_fetch(const arg &a) const override { + std::string gen_var_type_fetch(const arg &a) const final { assert(0); return ""; } - std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const override { + std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const final { return ""; } - std::string gen_function_result_type(const tl_tree *result) const override { + std::string gen_function_result_type(const tl_tree *result) const final { return ""; } std::string gen_fetch_function_begin(const std::string &parser_name, const std::string &class_name, const std::string &parent_class_name, int arity, int field_count, - std::vector &vars, int parser_type) const override { + std::vector &vars, int parser_type) const final { return ""; } std::string gen_fetch_function_end(bool has_parent, int field_count, const std::vector &vars, - int parser_type) const override { + int parser_type) const final { return ""; } std::string gen_fetch_function_result_begin(const std::string &parser_name, const std::string &class_name, - const tl_tree *result) const override { + const tl_tree *result) const final { return ""; } - std::string gen_fetch_function_result_end(void) const override { + std::string gen_fetch_function_result_end(void) const final { return ""; } std::string gen_fetch_function_result_any_begin(const std::string &parser_name, const std::string &class_name, - bool is_proxy) const override { + bool is_proxy) const final { return ""; } - std::string gen_fetch_function_result_any_end(bool is_proxy) const override { + std::string gen_fetch_function_result_any_end(bool is_proxy) const final { return ""; } - std::string gen_fetch_switch_begin(void) const override { + std::string gen_fetch_switch_begin(void) const final { return ""; } - std::string gen_fetch_switch_case(const tl_combinator *t, int arity) const override { + std::string gen_fetch_switch_case(const tl_combinator *t, int arity) const final { return ""; } - std::string gen_fetch_switch_end(void) const override { + std::string gen_fetch_switch_end(void) const final { return ""; } std::string gen_additional_proxy_function_begin(const std::string &function_name, const tl_type *type, - const std::string &name, int arity, bool is_function) const override { + const std::string &name, int arity, bool is_function) const final { std::stringstream ss; if (is_header_ && function_name == "ToUnmanaged") { ss << "};\n"; @@ -542,15 +542,15 @@ class TlWriterDotNet : public TL_writer { return ss.str(); } std::string gen_additional_proxy_function_case(const std::string &function_name, const tl_type *type, - const std::string &class_name, int arity) const override { + const std::string &class_name, int arity) const final { return ""; } std::string gen_additional_proxy_function_case(const std::string &function_name, const tl_type *type, - const tl_combinator *t, int arity, bool is_function) const override { + const tl_combinator *t, int arity, bool is_function) const final { return ""; } std::string gen_additional_proxy_function_end(const std::string &function_name, const tl_type *type, - bool is_function) const override { + bool is_function) const final { return ""; } }; diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_h.cpp b/lib/tgchat/ext/td/td/generate/tl_writer_h.cpp index d7e701cb..3a4760ad 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_h.cpp +++ b/lib/tgchat/ext/td/td/generate/tl_writer_h.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -94,6 +94,20 @@ std::string TD_TL_writer_h::gen_output_begin() const { " }\n" "\n" " return to_string(*value);\n" + "}\n\n" + + "template \n" + "std::string to_string(const std::vector> &values) {\n" + " std::string result = \"{\\n\";\n" + " for (const auto &value : values) {\n" + " if (value == nullptr) {\n" + " result += \"null\\n\";\n" + " } else {\n" + " result += to_string(*value);\n" + " }\n" + " }\n" + " result += \"}\\n\";\n" + " return result;\n" "}\n\n"; } @@ -150,13 +164,34 @@ std::string TD_TL_writer_h::gen_function_vars(const tl::tl_combinator *t, return res; } -std::string TD_TL_writer_h::gen_flags_definitions(const tl::tl_combinator *t) const { +bool TD_TL_writer_h::need_arg_mask(const tl::arg &a, bool can_be_stored) const { + if (a.exist_var_num == -1) { + return false; + } + + if (can_be_stored) { + return true; + } + + if (a.type->get_type() != tl::NODE_TYPE_TYPE) { + return true; + } + const tl::tl_tree_type *tree_type = static_cast(a.type); + const std::string &name = tree_type->type->name; + + if (!is_built_in_simple_type(name) || name == "True") { + return false; + } + return true; +} + +std::string TD_TL_writer_h::gen_flags_definitions(const tl::tl_combinator *t, bool can_be_stored) const { std::vector> flags; for (std::size_t i = 0; i < t->args.size(); i++) { const tl::arg &a = t->args[i]; - if (a.exist_var_num != -1) { + if (need_arg_mask(a, can_be_stored)) { auto name = a.name; for (auto &c : name) { c = to_upper(c); @@ -166,7 +201,7 @@ std::string TD_TL_writer_h::gen_flags_definitions(const tl::tl_combinator *t) co } std::string res; if (!flags.empty()) { - res += " enum Flags : std::int32_t {"; + res += " enum Flags : std::int32_t { "; bool first = true; for (auto &p : flags) { if (first) { @@ -176,7 +211,7 @@ std::string TD_TL_writer_h::gen_flags_definitions(const tl::tl_combinator *t) co } res += p.first + "_MASK = " + int_to_string(1 << p.second); } - res += "};\n"; + res += " };\n"; } return res; } diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_h.h b/lib/tgchat/ext/td/td/generate/tl_writer_h.h index 98e3c416..9e253836 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_h.h +++ b/lib/tgchat/ext/td/td/generate/tl_writer_h.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -20,6 +20,8 @@ class TD_TL_writer_h : public TD_TL_writer { static std::string forward_declaration(std::string type); + bool need_arg_mask(const tl::arg &a, bool can_be_stored) const; + public: TD_TL_writer_h(const std::string &tl_name, const std::string &string_type, const std::string &bytes_type, const std::vector &ext_include) @@ -40,7 +42,7 @@ class TD_TL_writer_h : public TD_TL_writer { std::string gen_field_definition(const std::string &class_name, const std::string &type_name, const std::string &field_name) const override; - std::string gen_flags_definitions(const tl::tl_combinator *t) const override; + std::string gen_flags_definitions(const tl::tl_combinator *t, bool can_be_stored) const override; std::string gen_vars(const tl::tl_combinator *t, const tl::tl_tree_type *result_type, std::vector &vars) const override; std::string gen_function_vars(const tl::tl_combinator *t, std::vector &vars) const override; diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_hpp.cpp b/lib/tgchat/ext/td/td/generate/tl_writer_hpp.cpp index 473a97a3..fed9d23f 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_hpp.cpp +++ b/lib/tgchat/ext/td/td/generate/tl_writer_hpp.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_hpp.h b/lib/tgchat/ext/td/td/generate/tl_writer_hpp.h index 6f7dca0a..04b96d8d 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_hpp.h +++ b/lib/tgchat/ext/td/td/generate/tl_writer_hpp.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -14,95 +14,94 @@ namespace td { -class TD_TL_writer_hpp : public TD_TL_writer { +class TD_TL_writer_hpp final : public TD_TL_writer { public: TD_TL_writer_hpp(const std::string &tl_name, const std::string &string_type, const std::string &bytes_type) : TD_TL_writer(tl_name, string_type, bytes_type) { } - bool is_documentation_generated() const override; + bool is_documentation_generated() const final; - int get_additional_function_type(const std::string &additional_function_name) const override; - std::vector get_additional_functions() const override; + int get_additional_function_type(const std::string &additional_function_name) const final; + std::vector get_additional_functions() const final; - std::string gen_base_type_class_name(int arity) const override; - std::string gen_base_tl_class_name() const override; + std::string gen_base_type_class_name(int arity) const final; + std::string gen_base_tl_class_name() const final; - std::string gen_output_begin() const override; - std::string gen_output_end() const override; + std::string gen_output_begin() const final; + std::string gen_output_end() const final; - std::string gen_forward_class_declaration(const std::string &class_name, bool is_proxy) const override; + std::string gen_forward_class_declaration(const std::string &class_name, bool is_proxy) const final; std::string gen_class_begin(const std::string &class_name, const std::string &base_class_name, - bool is_proxy) const override; - std::string gen_class_end() const override; + bool is_proxy) const final; + std::string gen_class_end() const final; - std::string gen_class_alias(const std::string &class_name, const std::string &alias_name) const override; + std::string gen_class_alias(const std::string &class_name, const std::string &alias_name) const final; std::string gen_field_definition(const std::string &class_name, const std::string &type_name, - const std::string &field_name) const override; + const std::string &field_name) const final; std::string gen_vars(const tl::tl_combinator *t, const tl::tl_tree_type *result_type, - std::vector &vars) const override; - std::string gen_function_vars(const tl::tl_combinator *t, std::vector &vars) const override; + std::vector &vars) const final; + std::string gen_function_vars(const tl::tl_combinator *t, std::vector &vars) const final; std::string gen_uni(const tl::tl_tree_type *result_type, std::vector &vars, - bool check_negative) const override; - std::string gen_constructor_id_store(std::int32_t id, int storer_type) const override; + bool check_negative) const final; + std::string gen_constructor_id_store(std::int32_t id, int storer_type) const final; std::string gen_field_fetch(int field_num, const tl::arg &a, std::vector &vars, bool flat, - int parser_type) const override; + int parser_type) const final; std::string gen_field_store(const tl::arg &a, std::vector &vars, bool flat, - int storer_type) const override; + int storer_type) const final; std::string gen_type_fetch(const std::string &field_name, const tl::tl_tree_type *tree_type, - const std::vector &vars, int parser_type) const override; + const std::vector &vars, int parser_type) const final; std::string gen_type_store(const std::string &field_name, const tl::tl_tree_type *tree_type, - const std::vector &vars, int storer_type) const override; - std::string gen_var_type_fetch(const tl::arg &a) const override; + const std::vector &vars, int storer_type) const final; + std::string gen_var_type_fetch(const tl::arg &a) const final; - std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const override; + std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const final; - std::string gen_function_result_type(const tl::tl_tree *result) const override; + std::string gen_function_result_type(const tl::tl_tree *result) const final; std::string gen_fetch_function_begin(const std::string &parser_name, const std::string &class_name, const std::string &parent_class_name, int arity, int field_count, - std::vector &vars, int parser_type) const override; + std::vector &vars, int parser_type) const final; std::string gen_fetch_function_end(bool has_parent, int field_count, const std::vector &vars, - int parser_type) const override; + int parser_type) const final; std::string gen_fetch_function_result_begin(const std::string &parser_name, const std::string &class_name, - const tl::tl_tree *result) const override; - std::string gen_fetch_function_result_end() const override; + const tl::tl_tree *result) const final; + std::string gen_fetch_function_result_end() const final; std::string gen_fetch_function_result_any_begin(const std::string &parser_name, const std::string &class_name, - bool is_proxy) const override; - std::string gen_fetch_function_result_any_end(bool is_proxy) const override; + bool is_proxy) const final; + std::string gen_fetch_function_result_any_end(bool is_proxy) const final; std::string gen_store_function_begin(const std::string &storer_name, const std::string &class_name, int arity, - std::vector &vars, int storer_type) const override; - std::string gen_store_function_end(const std::vector &vars, int storer_type) const override; + std::vector &vars, int storer_type) const final; + std::string gen_store_function_end(const std::vector &vars, int storer_type) const final; - std::string gen_fetch_switch_begin() const override; - std::string gen_fetch_switch_case(const tl::tl_combinator *t, int arity) const override; - std::string gen_fetch_switch_end() const override; + std::string gen_fetch_switch_begin() const final; + std::string gen_fetch_switch_case(const tl::tl_combinator *t, int arity) const final; + std::string gen_fetch_switch_end() const final; - std::string gen_constructor_begin(int field_count, const std::string &class_name, bool is_default) const override; + std::string gen_constructor_begin(int field_count, const std::string &class_name, bool is_default) const final; std::string gen_constructor_parameter(int field_num, const std::string &class_name, const tl::arg &a, - bool is_default) const override; + bool is_default) const final; std::string gen_constructor_field_init(int field_num, const std::string &class_name, const tl::arg &a, - bool is_default) const override; - std::string gen_constructor_end(const tl::tl_combinator *t, int field_count, bool is_default) const override; + bool is_default) const final; + std::string gen_constructor_end(const tl::tl_combinator *t, int field_count, bool is_default) const final; std::string gen_additional_function(const std::string &function_name, const tl::tl_combinator *t, - bool is_function) const override; + bool is_function) const final; std::string gen_additional_proxy_function_begin(const std::string &function_name, const tl::tl_type *type, const std::string &class_name, int arity, - bool is_function) const override; + bool is_function) const final; std::string gen_additional_proxy_function_case(const std::string &function_name, const tl::tl_type *type, - const std::string &class_name, int arity) const override; + const std::string &class_name, int arity) const final; std::string gen_additional_proxy_function_case(const std::string &function_name, const tl::tl_type *type, - const tl::tl_combinator *t, int arity, - bool is_function) const override; + const tl::tl_combinator *t, int arity, bool is_function) const final; std::string gen_additional_proxy_function_end(const std::string &function_name, const tl::tl_type *type, - bool is_function) const override; + bool is_function) const final; }; } // namespace td diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_java.cpp b/lib/tgchat/ext/td/td/generate/tl_writer_java.cpp index 8bb677de..fd70589b 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_java.cpp +++ b/lib/tgchat/ext/td/td/generate/tl_writer_java.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_java.h b/lib/tgchat/ext/td/td/generate/tl_writer_java.h index 06360fc5..6a3a17f7 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_java.h +++ b/lib/tgchat/ext/td/td/generate/tl_writer_java.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -14,7 +14,7 @@ namespace td { -class TD_TL_writer_java : public tl::TL_writer { +class TD_TL_writer_java final : public tl::TL_writer { static const int MAX_ARITY = 0; static const std::string base_type_class_names[MAX_ARITY + 1]; @@ -28,92 +28,92 @@ class TD_TL_writer_java : public tl::TL_writer { : TL_writer(tl_name), package_name(package_name) { } - int get_max_arity() const override; + int get_max_arity() const final; - bool is_built_in_simple_type(const std::string &name) const override; - bool is_built_in_complex_type(const std::string &name) const override; - bool is_type_bare(const tl::tl_type *t) const override; - bool is_combinator_supported(const tl::tl_combinator *constructor) const override; + bool is_built_in_simple_type(const std::string &name) const final; + bool is_built_in_complex_type(const std::string &name) const final; + bool is_type_bare(const tl::tl_type *t) const final; + bool is_combinator_supported(const tl::tl_combinator *constructor) const final; - int get_parser_type(const tl::tl_combinator *t, const std::string &parser_name) const override; - int get_storer_type(const tl::tl_combinator *t, const std::string &storer_name) const override; - std::vector get_parsers() const override; - std::vector get_storers() const override; + int get_parser_type(const tl::tl_combinator *t, const std::string &parser_name) const final; + int get_storer_type(const tl::tl_combinator *t, const std::string &storer_name) const final; + std::vector get_parsers() const final; + std::vector get_storers() const final; - std::string gen_base_tl_class_name() const override; - std::string gen_base_type_class_name(int arity) const override; - std::string gen_base_function_class_name() const override; - std::string gen_class_name(std::string name) const override; - std::string gen_field_name(std::string name) const override; - std::string gen_var_name(const tl::var_description &desc) const override; - std::string gen_parameter_name(int index) const override; - std::string gen_type_name(const tl::tl_tree_type *tree_type) const override; - std::string gen_array_type_name(const tl::tl_tree_array *arr, const std::string &field_name) const override; - std::string gen_var_type_name() const override; + std::string gen_base_tl_class_name() const final; + std::string gen_base_type_class_name(int arity) const final; + std::string gen_base_function_class_name() const final; + std::string gen_class_name(std::string name) const final; + std::string gen_field_name(std::string name) const final; + std::string gen_var_name(const tl::var_description &desc) const final; + std::string gen_parameter_name(int index) const final; + std::string gen_type_name(const tl::tl_tree_type *tree_type) const final; + std::string gen_array_type_name(const tl::tl_tree_array *arr, const std::string &field_name) const final; + std::string gen_var_type_name() const final; - std::string gen_int_const(const tl::tl_tree *tree_c, const std::vector &vars) const override; + std::string gen_int_const(const tl::tl_tree *tree_c, const std::vector &vars) const final; - std::string gen_output_begin() const override; - std::string gen_output_end() const override; + std::string gen_output_begin() const final; + std::string gen_output_end() const final; - std::string gen_forward_class_declaration(const std::string &class_name, bool is_proxy) const override; + std::string gen_forward_class_declaration(const std::string &class_name, bool is_proxy) const final; std::string gen_class_begin(const std::string &class_name, const std::string &base_class_name, - bool is_proxy) const override; - std::string gen_class_end() const override; + bool is_proxy) const final; + std::string gen_class_end() const final; - std::string gen_class_alias(const std::string &class_name, const std::string &alias_name) const override; + std::string gen_class_alias(const std::string &class_name, const std::string &alias_name) const final; std::string gen_field_definition(const std::string &class_name, const std::string &type_name, - const std::string &field_name) const override; + const std::string &field_name) const final; std::string gen_vars(const tl::tl_combinator *t, const tl::tl_tree_type *result_type, - std::vector &vars) const override; - std::string gen_function_vars(const tl::tl_combinator *t, std::vector &vars) const override; + std::vector &vars) const final; + std::string gen_function_vars(const tl::tl_combinator *t, std::vector &vars) const final; std::string gen_uni(const tl::tl_tree_type *result_type, std::vector &vars, - bool check_negative) const override; - std::string gen_constructor_id_store(std::int32_t id, int storer_type) const override; + bool check_negative) const final; + std::string gen_constructor_id_store(std::int32_t id, int storer_type) const final; std::string gen_field_fetch(int field_num, const tl::arg &a, std::vector &vars, bool flat, - int parser_type) const override; + int parser_type) const final; std::string gen_field_store(const tl::arg &a, std::vector &vars, bool flat, - int storer_type) const override; + int storer_type) const final; std::string gen_type_fetch(const std::string &field_name, const tl::tl_tree_type *tree_type, - const std::vector &vars, int parser_type) const override; + const std::vector &vars, int parser_type) const final; std::string gen_type_store(const std::string &field_name, const tl::tl_tree_type *tree_type, - const std::vector &vars, int storer_type) const override; - std::string gen_var_type_fetch(const tl::arg &a) const override; + const std::vector &vars, int storer_type) const final; + std::string gen_var_type_fetch(const tl::arg &a) const final; - std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const override; + std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const final; - std::string gen_function_result_type(const tl::tl_tree *result) const override; + std::string gen_function_result_type(const tl::tl_tree *result) const final; std::string gen_fetch_function_begin(const std::string &parser_name, const std::string &class_name, const std::string &parent_class_name, int arity, int field_count, - std::vector &vars, int parser_type) const override; + std::vector &vars, int parser_type) const final; std::string gen_fetch_function_end(bool has_parent, int field_count, const std::vector &vars, - int parser_type) const override; + int parser_type) const final; std::string gen_fetch_function_result_begin(const std::string &parser_name, const std::string &class_name, - const tl::tl_tree *result) const override; - std::string gen_fetch_function_result_end() const override; + const tl::tl_tree *result) const final; + std::string gen_fetch_function_result_end() const final; std::string gen_fetch_function_result_any_begin(const std::string &parser_name, const std::string &class_name, - bool is_proxy) const override; - std::string gen_fetch_function_result_any_end(bool is_proxy) const override; + bool is_proxy) const final; + std::string gen_fetch_function_result_any_end(bool is_proxy) const final; std::string gen_store_function_begin(const std::string &storer_name, const std::string &class_name, int arity, - std::vector &vars, int storer_type) const override; - std::string gen_store_function_end(const std::vector &vars, int storer_type) const override; + std::vector &vars, int storer_type) const final; + std::string gen_store_function_end(const std::vector &vars, int storer_type) const final; - std::string gen_fetch_switch_begin() const override; - std::string gen_fetch_switch_case(const tl::tl_combinator *t, int arity) const override; - std::string gen_fetch_switch_end() const override; + std::string gen_fetch_switch_begin() const final; + std::string gen_fetch_switch_case(const tl::tl_combinator *t, int arity) const final; + std::string gen_fetch_switch_end() const final; - std::string gen_constructor_begin(int field_count, const std::string &class_name, bool is_default) const override; + std::string gen_constructor_begin(int field_count, const std::string &class_name, bool is_default) const final; std::string gen_constructor_parameter(int field_num, const std::string &class_name, const tl::arg &a, - bool is_default) const override; + bool is_default) const final; std::string gen_constructor_field_init(int field_num, const std::string &class_name, const tl::arg &a, - bool is_default) const override; - std::string gen_constructor_end(const tl::tl_combinator *t, int field_count, bool is_default) const override; + bool is_default) const final; + std::string gen_constructor_end(const tl::tl_combinator *t, int field_count, bool is_default) const final; }; } // namespace td diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_jni_cpp.cpp b/lib/tgchat/ext/td/td/generate/tl_writer_jni_cpp.cpp index a0f2137b..330194e6 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_jni_cpp.cpp +++ b/lib/tgchat/ext/td/td/generate/tl_writer_jni_cpp.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -126,7 +126,7 @@ std::string TD_TL_writer_jni_cpp::gen_type_fetch(const std::string &field_name, if (!(tree_type->flags & tl::FLAG_BARE)) { if (is_type_bare(t)) { - if (field_name != "") { + if (!field_name.empty()) { std::fprintf(stderr, "Do not use non-bare fields with bare type %s\n", name.c_str()); // assert(false); } @@ -174,7 +174,7 @@ std::string TD_TL_writer_jni_cpp::gen_type_fetch(const std::string &field_name, const tl::tl_tree_type *child = static_cast(tree_type->children[0]); res = gen_vector_fetch(field_name, child, vars, parser_type); } else { - if (field_name == "") { + if (field_name.empty()) { return gen_main_class_name(tree_type->type) + "::fetch(env, p)"; } res = "jni::fetch_tl_object<" + gen_main_class_name(tree_type->type) + ">(env, jni::fetch_object(env, p, " + @@ -322,8 +322,8 @@ std::string TD_TL_writer_jni_cpp::gen_type_store(const std::string &field_name, res = gen_vector_store(field_name, child, vars, storer_type); } else { if (storer_type == 1) { - res = "if (" + field_name + " == nullptr) { s.store_field(\"" + get_pretty_field_name(field_name) + - "\", \"null\"); } else { " + field_name + "->store(s, \"" + get_pretty_field_name(field_name) + "\"); }"; + res = "s.store_object_field(\"" + get_pretty_field_name(field_name) + "\", static_cast(" + + field_name + ".get()));"; } else { res = "if (" + field_name + " != nullptr) { jobject next; " + field_name + "->store(env, next); if (next) { env->SetObjectField(s, " + field_name + @@ -565,14 +565,14 @@ std::string TD_TL_writer_jni_cpp::gen_additional_function(const std::string &fun " " + class_name_class + " = jni::get_jclass(env, " + gen_java_class_name(gen_class_name(t->name)) + ");\n"; - if (t->args.size()) { + if (!t->args.empty()) { for (std::size_t i = 0; i < t->args.size(); i++) { const tl::arg &a = t->args[i]; assert(a.type->get_type() == tl::NODE_TYPE_TYPE); const tl::tl_tree_type *tree_type = static_cast(a.type); std::string field_name = gen_field_name(a.name); - assert(field_name.size()); + assert(!field_name.empty()); std::string java_field_name = gen_java_field_name(std::string(field_name, 0, field_name.size() - 1)); std::string type_signature = gen_type_signature(tree_type); diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_jni_cpp.h b/lib/tgchat/ext/td/td/generate/tl_writer_jni_cpp.h index 3916bb60..18e47afe 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_jni_cpp.h +++ b/lib/tgchat/ext/td/td/generate/tl_writer_jni_cpp.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,7 +15,7 @@ namespace td { -class TD_TL_writer_jni_cpp : public TD_TL_writer_cpp { +class TD_TL_writer_jni_cpp final : public TD_TL_writer_cpp { std::string gen_vector_fetch(std::string field_name, const tl::tl_tree_type *t, const std::vector &vars, int parser_type) const; @@ -32,9 +32,9 @@ class TD_TL_writer_jni_cpp : public TD_TL_writer_cpp { std::string gen_type_signature(const tl::tl_tree_type *tree_type) const; - std::string get_pretty_field_name(std::string field_name) const override; + std::string get_pretty_field_name(std::string field_name) const final; - std::string get_pretty_class_name(std::string class_name) const override; + std::string get_pretty_class_name(std::string class_name) const final; public: TD_TL_writer_jni_cpp(const std::string &tl_name, const std::string &string_type, const std::string &bytes_type, @@ -42,69 +42,68 @@ class TD_TL_writer_jni_cpp : public TD_TL_writer_cpp { : TD_TL_writer_cpp(tl_name, string_type, bytes_type, ext_include) { } - bool is_built_in_simple_type(const std::string &name) const override; - bool is_built_in_complex_type(const std::string &name) const override; + bool is_built_in_simple_type(const std::string &name) const final; + bool is_built_in_complex_type(const std::string &name) const final; - int get_parser_type(const tl::tl_combinator *t, const std::string &parser_name) const override; - int get_additional_function_type(const std::string &additional_function_name) const override; - std::vector get_parsers() const override; - std::vector get_storers() const override; - std::vector get_additional_functions() const override; + int get_parser_type(const tl::tl_combinator *t, const std::string &parser_name) const final; + int get_additional_function_type(const std::string &additional_function_name) const final; + std::vector get_parsers() const final; + std::vector get_storers() const final; + std::vector get_additional_functions() const final; - std::string gen_base_type_class_name(int arity) const override; - std::string gen_base_tl_class_name() const override; + std::string gen_base_type_class_name(int arity) const final; + std::string gen_base_tl_class_name() const final; std::string gen_class_begin(const std::string &class_name, const std::string &base_class_name, - bool is_proxy) const override; + bool is_proxy) const final; std::string gen_field_definition(const std::string &class_name, const std::string &type_name, - const std::string &field_name) const override; + const std::string &field_name) const final; - std::string gen_constructor_id_store(std::int32_t id, int storer_type) const override; + std::string gen_constructor_id_store(std::int32_t id, int storer_type) const final; std::string gen_field_fetch(int field_num, const tl::arg &a, std::vector &vars, bool flat, - int parser_type) const override; + int parser_type) const final; std::string gen_field_store(const tl::arg &a, std::vector &vars, bool flat, - int storer_type) const override; + int storer_type) const final; std::string gen_type_fetch(const std::string &field_name, const tl::tl_tree_type *tree_type, - const std::vector &vars, int parser_type) const override; + const std::vector &vars, int parser_type) const final; std::string gen_type_store(const std::string &field_name, const tl::tl_tree_type *tree_type, - const std::vector &vars, int storer_type) const override; + const std::vector &vars, int storer_type) const final; - std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const override; + std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const final; std::string gen_fetch_function_begin(const std::string &parser_name, const std::string &class_name, const std::string &parent_class_name, int arity, int field_count, - std::vector &vars, int parser_type) const override; + std::vector &vars, int parser_type) const final; std::string gen_fetch_function_end(bool has_parent, int field_count, const std::vector &vars, - int parser_type) const override; + int parser_type) const final; std::string gen_fetch_function_result_begin(const std::string &parser_name, const std::string &class_name, - const tl::tl_tree *result) const override; - std::string gen_fetch_function_result_end() const override; + const tl::tl_tree *result) const final; + std::string gen_fetch_function_result_end() const final; std::string gen_fetch_function_result_any_begin(const std::string &parser_name, const std::string &class_name, - bool is_proxy) const override; - std::string gen_fetch_function_result_any_end(bool is_proxy) const override; + bool is_proxy) const final; + std::string gen_fetch_function_result_any_end(bool is_proxy) const final; std::string gen_store_function_begin(const std::string &storer_name, const std::string &class_name, int arity, - std::vector &vars, int storer_type) const override; + std::vector &vars, int storer_type) const final; - std::string gen_fetch_switch_begin() const override; - std::string gen_fetch_switch_case(const tl::tl_combinator *t, int arity) const override; - std::string gen_fetch_switch_end() const override; + std::string gen_fetch_switch_begin() const final; + std::string gen_fetch_switch_case(const tl::tl_combinator *t, int arity) const final; + std::string gen_fetch_switch_end() const final; std::string gen_additional_function(const std::string &function_name, const tl::tl_combinator *t, - bool is_function) const override; + bool is_function) const final; std::string gen_additional_proxy_function_begin(const std::string &function_name, const tl::tl_type *type, const std::string &class_name, int arity, - bool is_function) const override; + bool is_function) const final; std::string gen_additional_proxy_function_case(const std::string &function_name, const tl::tl_type *type, - const std::string &class_name, int arity) const override; + const std::string &class_name, int arity) const final; std::string gen_additional_proxy_function_case(const std::string &function_name, const tl::tl_type *type, - const tl::tl_combinator *t, int arity, - bool is_function) const override; + const tl::tl_combinator *t, int arity, bool is_function) const final; std::string gen_additional_proxy_function_end(const std::string &function_name, const tl::tl_type *type, - bool is_function) const override; + bool is_function) const final; }; } // namespace td diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_jni_h.cpp b/lib/tgchat/ext/td/td/generate/tl_writer_jni_h.cpp index 42aa7cd6..592b7c74 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_jni_h.cpp +++ b/lib/tgchat/ext/td/td/generate/tl_writer_jni_h.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_jni_h.h b/lib/tgchat/ext/td/td/generate/tl_writer_jni_h.h index 04e06508..97059f78 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_jni_h.h +++ b/lib/tgchat/ext/td/td/generate/tl_writer_jni_h.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,45 +13,44 @@ namespace td { -class TD_TL_writer_jni_h : public TD_TL_writer_h { +class TD_TL_writer_jni_h final : public TD_TL_writer_h { public: TD_TL_writer_jni_h(const std::string &tl_name, const std::string &string_type, const std::string &bytes_type, const std::vector &ext_include) : TD_TL_writer_h(tl_name, string_type, bytes_type, ext_include) { } - bool is_built_in_simple_type(const std::string &name) const override; - bool is_built_in_complex_type(const std::string &name) const override; + bool is_built_in_simple_type(const std::string &name) const final; + bool is_built_in_complex_type(const std::string &name) const final; - int get_parser_type(const tl::tl_combinator *t, const std::string &parser_name) const override; - int get_additional_function_type(const std::string &additional_function_name) const override; - std::vector get_parsers() const override; - std::vector get_storers() const override; - std::vector get_additional_functions() const override; + int get_parser_type(const tl::tl_combinator *t, const std::string &parser_name) const final; + int get_additional_function_type(const std::string &additional_function_name) const final; + std::vector get_parsers() const final; + std::vector get_storers() const final; + std::vector get_additional_functions() const final; - std::string gen_base_type_class_name(int arity) const override; - std::string gen_base_tl_class_name() const override; + std::string gen_base_type_class_name(int arity) const final; + std::string gen_base_tl_class_name() const final; - std::string gen_output_begin() const override; + std::string gen_output_begin() const final; std::string gen_class_begin(const std::string &class_name, const std::string &base_class_name, - bool is_proxy) const override; + bool is_proxy) const final; std::string gen_field_definition(const std::string &class_name, const std::string &type_name, - const std::string &field_name) const override; + const std::string &field_name) const final; std::string gen_additional_function(const std::string &function_name, const tl::tl_combinator *t, - bool is_function) const override; + bool is_function) const final; std::string gen_additional_proxy_function_begin(const std::string &function_name, const tl::tl_type *type, const std::string &class_name, int arity, - bool is_function) const override; + bool is_function) const final; std::string gen_additional_proxy_function_case(const std::string &function_name, const tl::tl_type *type, - const std::string &class_name, int arity) const override; + const std::string &class_name, int arity) const final; std::string gen_additional_proxy_function_case(const std::string &function_name, const tl::tl_type *type, - const tl::tl_combinator *t, int arity, - bool is_function) const override; + const tl::tl_combinator *t, int arity, bool is_function) const final; std::string gen_additional_proxy_function_end(const std::string &function_name, const tl::tl_type *type, - bool is_function) const override; + bool is_function) const final; }; } // namespace td diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_td.cpp b/lib/tgchat/ext/td/td/generate/tl_writer_td.cpp index 3d5447c4..5b128357 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_td.cpp +++ b/lib/tgchat/ext/td/td/generate/tl_writer_td.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -49,8 +49,21 @@ bool TD_TL_writer::is_combinator_supported(const tl::tl_combinator *constructor) return true; } -bool TD_TL_writer::is_default_constructor_generated(const tl::tl_combinator *t, bool is_function) const { - return tl_name == "td_api" || tl_name == "TdApi" || (t->var_count > 0 && !is_function); +bool TD_TL_writer::is_default_constructor_generated(const tl::tl_combinator *t, bool can_be_parsed, + bool can_be_stored) const { + return tl_name == "td_api" || tl_name == "TdApi" || (t->var_count > 0 && can_be_parsed) || t->name == "updates"; +} + +bool TD_TL_writer::is_full_constructor_generated(const tl::tl_combinator *t, bool can_be_parsed, + bool can_be_stored) const { + return tl_name == "td_api" || tl_name == "TdApi" || can_be_stored || t->name == "phone.groupParticipants" || + t->name == "user" || t->name == "userProfilePhoto" || t->name == "channelForbidden" || + t->name == "photoSizeEmpty" || t->name == "photoSize" || t->name == "photoCachedSize" || + t->name == "document" || t->name == "updateDeleteMessages" || t->name == "updateEditChannelMessage" || + t->name == "encryptedChatWaiting" || t->name == "encryptedChatRequested" || t->name == "encryptedChat" || + t->name == "langPackString" || t->name == "langPackStringPluralized" || t->name == "langPackStringDeleted" || + t->name == "peerUser" || t->name == "peerChat" || t->name == "updateServiceNotification" || + t->name == "updateNewMessage" || t->name == "message" || t->name == "updateChannelTooLong"; } int TD_TL_writer::get_storer_type(const tl::tl_combinator *t, const std::string &storer_name) const { @@ -137,9 +150,9 @@ std::string TD_TL_writer::gen_field_name(std::string name) const { name[i] = '_'; } } - assert(name.size() > 0); + assert(!name.empty()); assert(name[name.size() - 1] != '_'); - return name + "_"; + return name + '_'; } std::string TD_TL_writer::gen_var_name(const tl::var_description &desc) const { @@ -248,9 +261,8 @@ std::string TD_TL_writer::gen_constructor_parameter(int field_num, const std::st } else if (field_type == "UInt128 " || field_type == "UInt256 " || field_type == "string " || (string_type == bytes_type && field_type == "bytes ")) { res += field_type + "const &"; - } else if (field_type.compare(0, 5, "array") == 0 || field_type == "bytes ") { - res += field_type + "&&"; - } else if (field_type.compare(0, 10, "object_ptr") == 0) { + } else if (field_type.compare(0, 5, "array") == 0 || field_type == "bytes " || + field_type.compare(0, 10, "object_ptr") == 0) { res += field_type + "&&"; } else { assert(false && "unreachable"); diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_td.h b/lib/tgchat/ext/td/td/generate/tl_writer_td.h index a2e530fb..b7aea597 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_td.h +++ b/lib/tgchat/ext/td/td/generate/tl_writer_td.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -35,7 +35,9 @@ class TD_TL_writer : public tl::TL_writer { bool is_built_in_complex_type(const std::string &name) const override; bool is_type_bare(const tl::tl_type *t) const override; bool is_combinator_supported(const tl::tl_combinator *constructor) const override; - bool is_default_constructor_generated(const tl::tl_combinator *t, bool is_function) const override; + bool is_default_constructor_generated(const tl::tl_combinator *t, bool can_be_parsed, + bool can_be_stored) const override; + bool is_full_constructor_generated(const tl::tl_combinator *t, bool can_be_parsed, bool can_be_stored) const override; int get_storer_type(const tl::tl_combinator *t, const std::string &storer_name) const override; Mode get_parser_mode(int type) const override; diff --git a/lib/tgchat/ext/td/td/mtproto/AuthData.cpp b/lib/tgchat/ext/td/td/mtproto/AuthData.cpp index 61e7e1a2..00c946f9 100644 --- a/lib/tgchat/ext/td/td/mtproto/AuthData.cpp +++ b/lib/tgchat/ext/td/td/mtproto/AuthData.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,6 +9,7 @@ #include "td/utils/format.h" #include "td/utils/logging.h" #include "td/utils/Random.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Time.h" #include @@ -16,26 +17,31 @@ namespace td { namespace mtproto { -Status MessageIdDuplicateChecker::check(int64 message_id) { +Status check_message_id_duplicates(int64 *saved_message_ids, size_t max_size, size_t &end_pos, int64 message_id) { // In addition, the identifiers (msg_id) of the last N messages received from the other side must be stored, and if // a message comes in with msg_id lower than all or equal to any of the stored values, that message is to be // ignored. Otherwise, the new message msg_id is added to the set, and, if the number of stored msg_id values is // greater than N, the oldest (i. e. the lowest) is forgotten. - if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS) { - auto oldest_message_id = *saved_message_ids_.begin(); - if (message_id < oldest_message_id) { - return Status::Error(2, PSLICE() << "Ignore very old message_id " << tag("oldest message_id", oldest_message_id) - << tag("got message_id", message_id)); - } + if (end_pos == 2 * max_size) { + std::copy_n(&saved_message_ids[max_size], max_size, &saved_message_ids[0]); + end_pos = max_size; } - if (saved_message_ids_.count(message_id) != 0) { - return Status::Error(1, PSLICE() << "Ignore duplicated message_id " << tag("message_id", message_id)); + if (end_pos == 0 || message_id > saved_message_ids[end_pos - 1]) { + // fast path + saved_message_ids[end_pos++] = message_id; + return Status::OK(); } - - saved_message_ids_.insert(message_id); - if (saved_message_ids_.size() > MAX_SAVED_MESSAGE_IDS) { - saved_message_ids_.erase(saved_message_ids_.begin()); + if (end_pos >= max_size && message_id < saved_message_ids[0]) { + return Status::Error(2, PSLICE() << "Ignore very old message_id " << tag("oldest message_id", saved_message_ids[0]) + << tag("got message_id", message_id)); + } + auto it = std::lower_bound(&saved_message_ids[0], &saved_message_ids[end_pos], message_id); + if (*it == message_id) { + return Status::Error(1, PSLICE() << "Ignore duplicated message_id " << tag("message_id", message_id)); } + std::copy_backward(it, &saved_message_ids[end_pos], &saved_message_ids[end_pos + 1]); + *it = message_id; + ++end_pos; return Status::OK(); } @@ -72,7 +78,7 @@ bool AuthData::update_server_time_difference(double diff) { } else { return false; } - LOG(DEBUG) << "SERVER_TIME: " << format::as_hex(static_cast(get_server_time(Time::now_cached()))); + LOG(DEBUG) << "SERVER_TIME: " << format::as_hex(static_cast(get_server_time(Time::now_cached()))); return true; } @@ -94,7 +100,7 @@ std::vector AuthData::get_future_salts() const { int64 AuthData::next_message_id(double now) { double server_time = get_server_time(now); - int64 t = static_cast(server_time * (1ll << 32)); + auto t = static_cast(server_time * (1ll << 32)); // randomize lower bits for clocks with low precision // TODO(perf) do not do this for systems with good precision?.. @@ -113,13 +119,13 @@ int64 AuthData::next_message_id(double now) { bool AuthData::is_valid_outbound_msg_id(int64 id, double now) const { double server_time = get_server_time(now); - auto id_time = static_cast(id / (1ll << 32)); - return server_time - 300 / 2 < id_time && id_time < server_time + 60 / 2; + auto id_time = static_cast(id) / static_cast(1ll << 32); + return server_time - 150 < id_time && id_time < server_time + 30; } bool AuthData::is_valid_inbound_msg_id(int64 id, double now) const { double server_time = get_server_time(now); - auto id_time = static_cast(id / (1ll << 32)); + auto id_time = static_cast(id) / static_cast(1ll << 32); return server_time - 300 < id_time && id_time < server_time + 30; } diff --git a/lib/tgchat/ext/td/td/mtproto/AuthData.h b/lib/tgchat/ext/td/td/mtproto/AuthData.h index a87d3d8f..ef44aca8 100644 --- a/lib/tgchat/ext/td/td/mtproto/AuthData.h +++ b/lib/tgchat/ext/td/td/mtproto/AuthData.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -12,7 +12,7 @@ #include "td/utils/Slice.h" #include "td/utils/Status.h" -#include +#include namespace td { namespace mtproto { @@ -37,13 +37,18 @@ void parse(ServerSalt &salt, ParserT &parser) { salt.valid_until = parser.fetch_double(); } +Status check_message_id_duplicates(int64 *saved_message_ids, size_t max_size, size_t &end_pos, int64 message_id); + +template class MessageIdDuplicateChecker { public: - Status check(int64 message_id); + Status check(int64 message_id) { + return check_message_id_duplicates(&saved_message_ids_[0], max_size, end_pos_, message_id); + } private: - static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000; - std::set saved_message_ids_; + std::array saved_message_ids_; + size_t end_pos_ = 0; }; class AuthData { @@ -240,6 +245,10 @@ class AuthData { return updates_duplicate_checker_.check(message_id); } + Status recheck_update(int64 message_id) { + return updates_duplicate_rechecker_.check(message_id); + } + int32 next_seq_no(bool is_content_related) { int32 res = seq_no_; if (is_content_related) { @@ -274,8 +283,9 @@ class AuthData { std::vector future_salts_; - MessageIdDuplicateChecker duplicate_checker_; - MessageIdDuplicateChecker updates_duplicate_checker_; + MessageIdDuplicateChecker<1000> duplicate_checker_; + MessageIdDuplicateChecker<1000> updates_duplicate_checker_; + MessageIdDuplicateChecker<100> updates_duplicate_rechecker_; void update_salt(double now); }; diff --git a/lib/tgchat/ext/td/td/mtproto/AuthKey.h b/lib/tgchat/ext/td/td/mtproto/AuthKey.h index e35121f9..20eb414e 100644 --- a/lib/tgchat/ext/td/td/mtproto/AuthKey.h +++ b/lib/tgchat/ext/td/td/mtproto/AuthKey.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -34,11 +34,7 @@ class AuthKey { bool auth_flag() const { return auth_flag_; } - bool was_auth_flag() const { - return was_auth_flag_; - } void set_auth_flag(bool new_auth_flag) { - was_auth_flag_ |= new_auth_flag; auth_flag_ = new_auth_flag; } @@ -67,15 +63,13 @@ class AuthKey { } static constexpr int32 AUTH_FLAG = 1; - static constexpr int32 WAS_AUTH_FLAG = 2; static constexpr int32 HAS_CREATED_AT = 4; template void store(StorerT &storer) const { storer.store_binary(auth_key_id_); bool has_created_at = created_at_ != 0; - storer.store_binary(static_cast((auth_flag_ ? AUTH_FLAG : 0) | (was_auth_flag_ ? WAS_AUTH_FLAG : 0) | - (has_created_at ? HAS_CREATED_AT : 0))); + storer.store_binary(static_cast((auth_flag_ ? AUTH_FLAG : 0) | (has_created_at ? HAS_CREATED_AT : 0))); storer.store_string(auth_key_); if (has_created_at) { storer.store_binary(created_at_); @@ -87,7 +81,6 @@ class AuthKey { auth_key_id_ = parser.fetch_long(); auto flags = parser.fetch_int(); auth_flag_ = (flags & AUTH_FLAG) != 0; - was_auth_flag_ = (flags & WAS_AUTH_FLAG) != 0 || auth_flag_; auth_key_ = parser.template fetch_string(); if ((flags & HAS_CREATED_AT) != 0) { created_at_ = parser.fetch_double(); @@ -100,7 +93,6 @@ class AuthKey { uint64 auth_key_id_{0}; string auth_key_; bool auth_flag_{false}; - bool was_auth_flag_{false}; bool need_header_{true}; double expires_at_{0}; double created_at_{0}; diff --git a/lib/tgchat/ext/td/td/mtproto/ConnectionManager.cpp b/lib/tgchat/ext/td/td/mtproto/ConnectionManager.cpp new file mode 100644 index 00000000..5cbc251a --- /dev/null +++ b/lib/tgchat/ext/td/td/mtproto/ConnectionManager.cpp @@ -0,0 +1,37 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/mtproto/ConnectionManager.h" + +namespace td { +namespace mtproto { + +void ConnectionManager::inc_connect() { + auto &cnt = get_link_token() == 1 ? connect_cnt_ : connect_proxy_cnt_; + cnt++; + if (cnt == 1) { + loop(); + } +} + +void ConnectionManager::dec_connect() { + auto &cnt = get_link_token() == 1 ? connect_cnt_ : connect_proxy_cnt_; + CHECK(cnt > 0); + cnt--; + if (cnt == 0) { + loop(); + } +} + +ConnectionManager::ConnectionToken ConnectionManager::connection_impl(ActorId connection_manager, + int mode) { + auto actor = ActorShared(connection_manager, mode); + send_closure(actor, &ConnectionManager::inc_connect); + return ConnectionToken(std::move(actor)); +} + +} // namespace mtproto +} // namespace td diff --git a/lib/tgchat/ext/td/td/mtproto/ConnectionManager.h b/lib/tgchat/ext/td/td/mtproto/ConnectionManager.h new file mode 100644 index 00000000..ef392632 --- /dev/null +++ b/lib/tgchat/ext/td/td/mtproto/ConnectionManager.h @@ -0,0 +1,70 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/actor/actor.h" + +#include "td/utils/common.h" + +namespace td { +namespace mtproto { + +class ConnectionManager : public Actor { + public: + class ConnectionToken { + public: + ConnectionToken() = default; + explicit ConnectionToken(ActorShared connection_manager) + : connection_manager_(std::move(connection_manager)) { + } + ConnectionToken(const ConnectionToken &) = delete; + ConnectionToken &operator=(const ConnectionToken &) = delete; + ConnectionToken(ConnectionToken &&) = default; + ConnectionToken &operator=(ConnectionToken &&other) noexcept { + reset(); + connection_manager_ = std::move(other.connection_manager_); + return *this; + } + ~ConnectionToken() { + reset(); + } + + void reset() { + if (!connection_manager_.empty()) { + send_closure(connection_manager_, &ConnectionManager::dec_connect); + connection_manager_.reset(); + } + } + + bool empty() const { + return connection_manager_.empty(); + } + + private: + ActorShared connection_manager_; + }; + + static ConnectionToken connection(ActorId connection_manager) { + return connection_impl(connection_manager, 1); + } + static ConnectionToken connection_proxy(ActorId connection_manager) { + return connection_impl(connection_manager, 2); + } + + protected: + uint32 connect_cnt_ = 0; + uint32 connect_proxy_cnt_ = 0; + + private: + void inc_connect(); + void dec_connect(); + + static ConnectionToken connection_impl(ActorId connection_manager, int mode); +}; + +} // namespace mtproto +} // namespace td diff --git a/lib/tgchat/ext/td/td/mtproto/CryptoStorer.h b/lib/tgchat/ext/td/td/mtproto/CryptoStorer.h index 03587a80..568a3920 100644 --- a/lib/tgchat/ext/td/td/mtproto/CryptoStorer.h +++ b/lib/tgchat/ext/td/td/mtproto/CryptoStorer.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -7,8 +7,8 @@ #pragma once #include "td/mtproto/AuthData.h" +#include "td/mtproto/MtprotoQuery.h" #include "td/mtproto/PacketStorer.h" -#include "td/mtproto/Query.h" #include "td/mtproto/utils.h" #include "td/mtproto/mtproto_api.h" @@ -112,8 +112,7 @@ class QueryImpl { void do_store(StorerT &storer) const { storer.store_binary(query_.message_id); storer.store_binary(query_.seq_no); - Slice header = this->header_; - Slice invoke_header = Slice(); + Slice invoke_header; // TODO(refactor): // invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -138,7 +137,7 @@ class QueryImpl { const Storer &data_storer = query_.gzip_flag ? static_cast(gzip_storer) : static_cast(plain_storer); auto invoke_header_storer = create_storer(invoke_header); - auto header_storer = create_storer(header); + auto header_storer = create_storer(header_); auto suff_storer = create_storer(invoke_header_storer, data_storer); auto all_storer = create_storer(header_storer, suff_storer); @@ -192,8 +191,9 @@ class CryptoImpl { public: CryptoImpl(const vector &to_send, Slice header, vector &&to_ack, int64 ping_id, int ping_timeout, int max_delay, int max_after, int max_wait, int future_salt_n, vector get_info, - vector resend, vector cancel, bool destroy_key, AuthData *auth_data, uint64 *container_id, - uint64 *get_info_id, uint64 *resend_id, uint64 *ping_message_id, uint64 *parent_message_id) + vector resend, const vector &cancel, bool destroy_key, AuthData *auth_data, + uint64 *container_id, uint64 *get_info_id, uint64 *resend_id, uint64 *ping_message_id, + uint64 *parent_message_id) : query_storer_(to_send, header) , ack_empty_(to_ack.empty()) , ack_storer_(!ack_empty_, mtproto_api::msgs_ack(std::move(to_ack)), auth_data) @@ -206,7 +206,7 @@ class CryptoImpl { , resend_storer_(resend_not_empty_, mtproto_api::msg_resend_req(std::move(resend)), auth_data, true) , cancel_not_empty_(!cancel.empty()) , cancel_cnt_(static_cast(cancel.size())) - , cancel_storer_(cancel_not_empty_, std::move(cancel), auth_data, true) + , cancel_storer_(cancel_not_empty_, cancel, auth_data, true) , destroy_key_storer_(destroy_key, mtproto_api::destroy_auth_key(), auth_data, true) , tmp_storer_(query_storer_, ack_storer_) , tmp2_storer_(tmp_storer_, http_wait_storer_) diff --git a/lib/tgchat/ext/td/td/mtproto/DhCallback.h b/lib/tgchat/ext/td/td/mtproto/DhCallback.h new file mode 100644 index 00000000..c26cd50e --- /dev/null +++ b/lib/tgchat/ext/td/td/mtproto/DhCallback.h @@ -0,0 +1,29 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/utils/Slice.h" + +namespace td { +namespace mtproto { + +class DhCallback { + public: + DhCallback() = default; + DhCallback(const DhCallback &) = delete; + DhCallback &operator=(const DhCallback &) = delete; + DhCallback(DhCallback &&) = delete; + DhCallback &operator=(DhCallback &&) = delete; + virtual ~DhCallback() = default; + + virtual int is_good_prime(Slice prime_str) const = 0; + virtual void add_good_prime(Slice prime_str) const = 0; + virtual void add_bad_prime(Slice prime_str) const = 0; +}; + +} // namespace mtproto +} // namespace td diff --git a/lib/tgchat/ext/td/td/mtproto/DhHandshake.cpp b/lib/tgchat/ext/td/td/mtproto/DhHandshake.cpp index 51a5d00a..dfcdea28 100644 --- a/lib/tgchat/ext/td/td/mtproto/DhHandshake.cpp +++ b/lib/tgchat/ext/td/td/mtproto/DhHandshake.cpp @@ -1,11 +1,13 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include "td/mtproto/DhHandshake.h" +#include "td/mtproto/DhCallback.h" + #include "td/utils/as.h" #include "td/utils/crypto.h" #include "td/utils/logging.h" @@ -14,6 +16,7 @@ #include "td/utils/UInt.h" namespace td { +namespace mtproto { Status DhHandshake::check_config(Slice prime_str, const BigNum &prime, int32 g_int, BigNumContext &ctx, DhCallback *callback) { @@ -225,4 +228,5 @@ int64 DhHandshake::calc_key_id(Slice auth_key) { return as(auth_key_sha1.raw + 12); } +} // namespace mtproto } // namespace td diff --git a/lib/tgchat/ext/td/td/mtproto/DhHandshake.h b/lib/tgchat/ext/td/td/mtproto/DhHandshake.h index c26f63bb..bd94a275 100644 --- a/lib/tgchat/ext/td/td/mtproto/DhHandshake.h +++ b/lib/tgchat/ext/td/td/mtproto/DhHandshake.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -14,21 +14,9 @@ #include namespace td { +namespace mtproto { -/*** DH ***/ -class DhCallback { - public: - DhCallback() = default; - DhCallback(const DhCallback &) = delete; - DhCallback &operator=(const DhCallback &) = delete; - DhCallback(DhCallback &&) = delete; - DhCallback &operator=(DhCallback &&) = delete; - virtual ~DhCallback() = default; - - virtual int is_good_prime(Slice prime_str) const = 0; - virtual void add_good_prime(Slice prime_str) const = 0; - virtual void add_bad_prime(Slice prime_str) const = 0; -}; +class DhCallback; class DhHandshake { public: @@ -117,7 +105,7 @@ class DhHandshake { string prime_str_; BigNum prime_; BigNum g_; - int32 g_int_; + int32 g_int_ = 0; BigNum b_; BigNum g_b_; BigNum g_a_; @@ -132,4 +120,5 @@ class DhHandshake { BigNumContext ctx_; }; +} // namespace mtproto } // namespace td diff --git a/lib/tgchat/ext/td/td/mtproto/Handshake.cpp b/lib/tgchat/ext/td/td/mtproto/Handshake.cpp index 4563268a..421ad578 100644 --- a/lib/tgchat/ext/td/td/mtproto/Handshake.cpp +++ b/lib/tgchat/ext/td/td/mtproto/Handshake.cpp @@ -1,15 +1,16 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include "td/mtproto/Handshake.h" +#include "td/mtproto/DhCallback.h" +#include "td/mtproto/DhHandshake.h" #include "td/mtproto/KDF.h" -#include "td/mtproto/utils.h" - #include "td/mtproto/mtproto_api.h" +#include "td/mtproto/utils.h" #include "td/utils/as.h" #include "td/utils/buffer.h" @@ -18,10 +19,12 @@ #include "td/utils/format.h" #include "td/utils/logging.h" #include "td/utils/Random.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Status.h" #include "td/utils/Time.h" #include "td/utils/tl_parsers.h" -#include "td/utils/tl_storers.h" + +#include namespace td { namespace mtproto { @@ -43,94 +46,115 @@ static Result fetch_result(Slice message, bool check_end return std::move(result); } +AuthKeyHandshake::AuthKeyHandshake(int32 dc_id, int32 expires_in) + : mode_(expires_in == 0 ? Mode::Main : Mode::Temp) + , dc_id_(dc_id) + , expires_in_(expires_in) + , start_time_(Time::now()) + , timeout_in_(1e9) { +} + +void AuthKeyHandshake::set_timeout_in(double timeout_in) { + start_time_ = Time::now(); + timeout_in_ = timeout_in; +} + void AuthKeyHandshake::clear() { last_query_ = BufferSlice(); state_ = Start; + start_time_ = Time::now(); + timeout_in_ = 1e9; } -bool AuthKeyHandshake::is_ready_for_start() const { - return state_ == Start; -} -bool AuthKeyHandshake::is_ready_for_message(const UInt128 &message_nonce) const { - return state_ != Finish && state_ != Start && nonce == message_nonce; -} bool AuthKeyHandshake::is_ready_for_finish() const { return state_ == Finish; } + void AuthKeyHandshake::on_finish() { clear(); } -template -Result AuthKeyHandshake::fill_data_with_hash(uint8 *data_with_hash, const DataT &data) { - // data_with_hash := SHA1(data) + data + (any random bytes); such that the length equal 255 bytes; - uint8 *data_ptr = data_with_hash + 20; - size_t data_size = tl_calc_length(data); - if (data_size + 20 + 4 > 255) { - return Status::Error("Too big data"); - } - as(data_ptr) = data.get_id(); - auto real_size = tl_store_unsafe(data, data_ptr + 4); - CHECK(real_size == data_size); - sha1(Slice(data_ptr, data_size + 4), data_with_hash); - return data_size + 20 + 4; +string AuthKeyHandshake::store_object(const mtproto_api::Object &object) { + auto storer = create_storer(object); + size_t size = storer.size(); + string result(size, '\0'); + auto real_size = storer.store(MutableSlice(result).ubegin()); + CHECK(real_size == size); + return result; } Status AuthKeyHandshake::on_res_pq(Slice message, Callback *connection, PublicRsaKeyInterface *public_rsa_key) { + if (Time::now() >= start_time_ + timeout_in_ * 0.6) { + return Status::Error("Handshake ResPQ timeout expired"); + } + TRY_RESULT(res_pq, fetch_result(message, false)); - if (res_pq->nonce_ != nonce) { + if (res_pq->nonce_ != nonce_) { return Status::Error("Nonce mismatch"); } - server_nonce = res_pq->server_nonce_; + server_nonce_ = res_pq->server_nonce_; - auto r_rsa = public_rsa_key->get_rsa(res_pq->server_public_key_fingerprints_); - if (r_rsa.is_error()) { + auto r_rsa_key = public_rsa_key->get_rsa_key(res_pq->server_public_key_fingerprints_); + if (r_rsa_key.is_error()) { public_rsa_key->drop_keys(); - return r_rsa.move_as_error(); + return r_rsa_key.move_as_error(); } - int64 rsa_fingerprint = r_rsa.ok().second; - RSA rsa = std::move(r_rsa.ok_ref().first); + auto rsa_key = r_rsa_key.move_as_ok(); - string p, q; + string p; + string q; if (pq_factorize(res_pq->pq_, &p, &q) == -1) { return Status::Error("Failed to factorize"); } - Random::secure_bytes(new_nonce.raw, sizeof(new_nonce)); + Random::secure_bytes(new_nonce_.raw, sizeof(new_nonce_)); - alignas(8) uint8 data_with_hash[255]; - Result r_data_size = 0; + string data; switch (mode_) { case Mode::Main: - r_data_size = fill_data_with_hash( - data_with_hash, mtproto_api::p_q_inner_data_dc(res_pq->pq_, p, q, nonce, server_nonce, new_nonce, dc_id_)); + data = store_object(mtproto_api::p_q_inner_data_dc(res_pq->pq_, p, q, nonce_, server_nonce_, new_nonce_, dc_id_)); break; case Mode::Temp: - r_data_size = fill_data_with_hash( - data_with_hash, - mtproto_api::p_q_inner_data_temp_dc(res_pq->pq_, p, q, nonce, server_nonce, new_nonce, dc_id_, expires_in_)); + data = store_object(mtproto_api::p_q_inner_data_temp_dc(res_pq->pq_, p, q, nonce_, server_nonce_, new_nonce_, + dc_id_, expires_in_)); expires_at_ = Time::now() + expires_in_; break; - case Mode::Unknown: default: UNREACHABLE(); - r_data_size = Status::Error(500, "Unreachable"); } - if (r_data_size.is_error()) { - return r_data_size.move_as_error(); + + string encrypted_data(256, '\0'); + auto data_size = data.size(); + if (data_size > 144) { + return Status::Error("Too big data"); } - size_t size = r_data_size.ok(); - // encrypted_data := RSA (data_with_hash, server_public_key); a 255-byte long number (big endian) - // is raised to the requisite power over the requisite modulus, and the result is stored as a 256-byte number. - string encrypted_data(256, 0); - rsa.encrypt(data_with_hash, size, sizeof(data_with_hash), reinterpret_cast(&encrypted_data[0]), - encrypted_data.size()); + data.resize(192); + Random::secure_bytes(MutableSlice(data).substr(data_size)); + + while (true) { + string aes_key(32, '\0'); + Random::secure_bytes(MutableSlice(aes_key)); - // req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long - // encrypted_data:string = Server_DH_Params - mtproto_api::req_DH_params req_dh_params(nonce, server_nonce, p, q, rsa_fingerprint, encrypted_data); + string data_with_hash = PSTRING() << data << sha256(aes_key + data); + std::reverse(data_with_hash.begin(), data_with_hash.begin() + data.size()); + + string decrypted_data(256, '\0'); + string aes_iv(32, '\0'); + aes_ige_encrypt(aes_key, aes_iv, data_with_hash, MutableSlice(decrypted_data).substr(32)); + + auto hash = sha256(MutableSlice(decrypted_data).substr(32)); + for (size_t i = 0; i < 32; i++) { + decrypted_data[i] = static_cast(aes_key[i] ^ hash[i]); + } + + if (rsa_key.rsa.encrypt(decrypted_data, encrypted_data)) { + break; + } + } + + mtproto_api::req_DH_params req_dh_params(nonce_, server_nonce_, p, q, rsa_key.fingerprint, encrypted_data); send(connection, create_storer(req_dh_params)); state_ = ServerDHParams; @@ -138,30 +162,26 @@ Status AuthKeyHandshake::on_res_pq(Slice message, Callback *connection, PublicRs } Status AuthKeyHandshake::on_server_dh_params(Slice message, Callback *connection, DhCallback *dh_callback) { - TRY_RESULT(server_dh_params, fetch_result(message, false)); - switch (server_dh_params->get_id()) { - case mtproto_api::server_DH_params_ok::ID: - break; - case mtproto_api::server_DH_params_fail::ID: - return Status::Error("Server dh params fail"); - default: - return Status::Error("Unknown result"); + if (Time::now() >= start_time_ + timeout_in_ * 0.8) { + return Status::Error("Handshake DH params timeout expired"); } - auto dh_params = move_tl_object_as(server_dh_params); + TRY_RESULT(dh_params, fetch_result(message, false)); // server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; - if (dh_params->nonce_ != nonce) { + if (dh_params->nonce_ != nonce_) { return Status::Error("Nonce mismatch"); } - if (dh_params->server_nonce_ != server_nonce) { + if (dh_params->server_nonce_ != server_nonce_) { return Status::Error("Server nonce mismatch"); } if (dh_params->encrypted_answer_.size() & 15) { return Status::Error("Bad padding for encrypted part"); } - tmp_KDF(server_nonce, new_nonce, &tmp_aes_key, &tmp_aes_iv); + UInt256 tmp_aes_key; + UInt256 tmp_aes_iv; + tmp_KDF(server_nonce_, new_nonce_, &tmp_aes_key, &tmp_aes_iv); auto save_tmp_aes_iv = tmp_aes_iv; // encrypted_answer := AES256_ige_encrypt (answer_with_hash, tmp_aes_key, tmp_aes_iv); MutableSlice answer(const_cast(dh_params->encrypted_answer_.begin()), dh_params->encrypted_answer_.size()); @@ -192,10 +212,10 @@ Status AuthKeyHandshake::on_server_dh_params(Slice message, Callback *connection return Status::Error("SHA1 mismatch"); } - if (dh_inner_data.nonce_ != nonce) { + if (dh_inner_data.nonce_ != nonce_) { return Status::Error("Nonce mismatch"); } - if (dh_inner_data.server_nonce_ != server_nonce) { + if (dh_inner_data.server_nonce_ != server_nonce_) { return Status::Error("Server nonce mismatch"); } @@ -208,22 +228,19 @@ Status AuthKeyHandshake::on_server_dh_params(Slice message, Callback *connection string g_b = handshake.get_g_b(); auto auth_key_params = handshake.gen_key(); - mtproto_api::client_DH_inner_data data(nonce, server_nonce, 0, g_b); - size_t data_size = 4 + tl_calc_length(data); - size_t encrypted_data_size = 20 + data_size; + auto data = store_object(mtproto_api::client_DH_inner_data(nonce_, server_nonce_, 0, g_b)); + size_t encrypted_data_size = 20 + data.size(); size_t encrypted_data_size_with_pad = (encrypted_data_size + 15) & -16; - string encrypted_data_str(encrypted_data_size_with_pad, 0); + string encrypted_data_str(encrypted_data_size_with_pad, '\0'); MutableSlice encrypted_data = encrypted_data_str; - as(encrypted_data.begin() + 20) = data.get_id(); - auto real_size = tl_store_unsafe(data, encrypted_data.ubegin() + 20 + 4); - CHECK(real_size + 4 == data_size); - sha1(encrypted_data.substr(20, data_size), encrypted_data.ubegin()); + sha1(data, encrypted_data.ubegin()); + encrypted_data.substr(20, data.size()).copy_from(data); Random::secure_bytes(encrypted_data.ubegin() + encrypted_data_size, encrypted_data_size_with_pad - encrypted_data_size); - tmp_KDF(server_nonce, new_nonce, &tmp_aes_key, &tmp_aes_iv); + tmp_KDF(server_nonce_, new_nonce_, &tmp_aes_key, &tmp_aes_iv); aes_ige_encrypt(as_slice(tmp_aes_key), as_slice(tmp_aes_iv), encrypted_data, encrypted_data); - mtproto_api::set_client_DH_params set_client_dh_params(nonce, server_nonce, encrypted_data); + mtproto_api::set_client_DH_params set_client_dh_params(nonce_, server_nonce_, encrypted_data); send(connection, create_storer(set_client_dh_params)); auth_key_ = AuthKey(auth_key_params.first, std::move(auth_key_params.second)); @@ -232,7 +249,7 @@ Status AuthKeyHandshake::on_server_dh_params(Slice message, Callback *connection } auth_key_.set_created_at(dh_inner_data.server_time_); - server_salt_ = as(new_nonce.raw) ^ as(server_nonce.raw); + server_salt_ = as(new_nonce_.raw) ^ as(server_nonce_.raw); state_ = DHGenResponse; return Status::OK(); @@ -241,17 +258,32 @@ Status AuthKeyHandshake::on_server_dh_params(Slice message, Callback *connection Status AuthKeyHandshake::on_dh_gen_response(Slice message, Callback *connection) { TRY_RESULT(answer, fetch_result(message, false)); switch (answer->get_id()) { - case mtproto_api::dh_gen_ok::ID: + case mtproto_api::dh_gen_ok::ID: { + auto dh_gen_ok = move_tl_object_as(answer); + if (dh_gen_ok->nonce_ != nonce_) { + return Status::Error("Nonce mismatch"); + } + if (dh_gen_ok->server_nonce_ != server_nonce_) { + return Status::Error("Server nonce mismatch"); + } + + UInt<160> auth_key_sha1; + sha1(auth_key_.key(), auth_key_sha1.raw); + auto new_nonce_hash = sha1(PSLICE() << new_nonce_.as_slice() << '\x01' << auth_key_sha1.as_slice().substr(0, 8)); + if (dh_gen_ok->new_nonce_hash1_.as_slice() != Slice(new_nonce_hash).substr(4)) { + return Status::Error("New nonce hash mismatch"); + } state_ = Finish; - break; + return Status::OK(); + } case mtproto_api::dh_gen_fail::ID: return Status::Error("DhGenFail"); case mtproto_api::dh_gen_retry::ID: return Status::Error("DhGenRetry"); default: + UNREACHABLE(); return Status::Error("Unknown set_client_DH_params response"); } - return Status::OK(); } void AuthKeyHandshake::send(Callback *connection, const Storer &storer) { @@ -267,17 +299,6 @@ void AuthKeyHandshake::do_send(Callback *connection, const Storer &storer) { return connection->send_no_crypto(storer); } -Status AuthKeyHandshake::start_main(Callback *connection) { - mode_ = Mode::Main; - return on_start(connection); -} - -Status AuthKeyHandshake::start_tmp(Callback *connection, int32 expires_in) { - mode_ = Mode::Temp; - expires_in_ = expires_in; - return on_start(connection); -} - void AuthKeyHandshake::resume(Callback *connection) { if (state_ == Start) { return on_start(connection).ignore(); @@ -290,7 +311,7 @@ void AuthKeyHandshake::resume(Callback *connection) { LOG(ERROR) << "Last query empty! UNREACHABLE " << state_; return clear(); } - LOG(INFO) << "RESUME"; + LOG(INFO) << "Resume handshake"; do_send(connection, create_storer(last_query_.as_slice())); } @@ -299,8 +320,8 @@ Status AuthKeyHandshake::on_start(Callback *connection) { clear(); return Status::Error(PSLICE() << "on_start called after start " << tag("state", state_)); } - Random::secure_bytes(nonce.raw, sizeof(nonce)); - send(connection, create_storer(mtproto_api::req_pq_multi(nonce))); + Random::secure_bytes(nonce_.raw, sizeof(nonce_)); + send(connection, create_storer(mtproto_api::req_pq_multi(nonce_))); state_ = ResPQ; return Status::OK(); diff --git a/lib/tgchat/ext/td/td/mtproto/Handshake.h b/lib/tgchat/ext/td/td/mtproto/Handshake.h index 9669cb4c..5baf7657 100644 --- a/lib/tgchat/ext/td/td/mtproto/Handshake.h +++ b/lib/tgchat/ext/td/td/mtproto/Handshake.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -7,7 +7,6 @@ #pragma once #include "td/mtproto/AuthKey.h" -#include "td/mtproto/DhHandshake.h" #include "td/mtproto/RSA.h" #include "td/utils/buffer.h" @@ -17,8 +16,15 @@ #include "td/utils/UInt.h" namespace td { + +namespace mtproto_api { +class Object; +} // namespace mtproto_api + namespace mtproto { +class DhCallback; + class AuthKeyHandshakeContext { public: virtual ~AuthKeyHandshakeContext() = default; @@ -27,8 +33,6 @@ class AuthKeyHandshakeContext { }; class AuthKeyHandshake { - enum class Mode { Unknown, Main, Temp }; - public: class Callback { public: @@ -39,44 +43,18 @@ class AuthKeyHandshake { virtual void send_no_crypto(const Storer &storer) = 0; }; - AuthKeyHandshake(int32 dc_id, int32 expires_in) { - dc_id_ = dc_id; - if (expires_in == 0) { - mode_ = Mode::Main; - } else { - mode_ = Mode::Temp; - expires_in_ = expires_in; - } - } - - bool is_ready_for_start() const; - Status start_main(Callback *connection) TD_WARN_UNUSED_RESULT; - Status start_tmp(Callback *connection, int32 expires_in) TD_WARN_UNUSED_RESULT; + AuthKeyHandshake(int32 dc_id, int32 expires_in); - bool is_ready_for_message(const UInt128 &message_nonce) const; + void set_timeout_in(double timeout_in); bool is_ready_for_finish() const; - void on_finish(); - void init_main() { - clear(); - mode_ = Mode::Main; - } - - void init_temp(int32 expires_in) { - clear(); - mode_ = Mode::Temp; - expires_in_ = expires_in; - } + void on_finish(); void resume(Callback *connection); Status on_message(Slice message, Callback *connection, AuthKeyHandshakeContext *context) TD_WARN_UNUSED_RESULT; - bool is_ready() const { - return is_ready_for_finish(); - } - void clear(); const AuthKey &get_auth_key() const { @@ -96,30 +74,31 @@ class AuthKeyHandshake { } private: - using State = enum { Start, ResPQ, ServerDHParams, DHGenResponse, Finish }; + enum State : int32 { Start, ResPQ, ServerDHParams, DHGenResponse, Finish }; State state_ = Start; - Mode mode_ = Mode::Unknown; + enum class Mode : int32 { Main, Temp }; + Mode mode_ = Mode::Main; int32 dc_id_ = 0; int32 expires_in_ = 0; double expires_at_ = 0; + double start_time_ = 0; + double timeout_in_ = 0; + AuthKey auth_key_; double server_time_diff_ = 0; uint64 server_salt_ = 0; - UInt128 nonce; - UInt128 server_nonce; - UInt256 new_nonce; - UInt256 tmp_aes_key; - UInt256 tmp_aes_iv; + UInt128 nonce_; + UInt128 server_nonce_; + UInt256 new_nonce_; BufferSlice last_query_; - template - Result fill_data_with_hash(uint8 *data_with_hash, const DataT &data) TD_WARN_UNUSED_RESULT; + static string store_object(const mtproto_api::Object &object); void send(Callback *connection, const Storer &storer); - void do_send(Callback *connection, const Storer &storer); + static void do_send(Callback *connection, const Storer &storer); Status on_start(Callback *connection) TD_WARN_UNUSED_RESULT; Status on_res_pq(Slice message, Callback *connection, PublicRsaKeyInterface *public_rsa_key) TD_WARN_UNUSED_RESULT; diff --git a/lib/tgchat/ext/td/td/mtproto/HandshakeActor.cpp b/lib/tgchat/ext/td/td/mtproto/HandshakeActor.cpp index efcfb8ba..1f9c14b1 100644 --- a/lib/tgchat/ext/td/td/mtproto/HandshakeActor.cpp +++ b/lib/tgchat/ext/td/td/mtproto/HandshakeActor.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,7 +9,7 @@ #include "td/mtproto/HandshakeConnection.h" #include "td/utils/common.h" -#include "td/utils/logging.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Status.h" namespace td { @@ -27,13 +27,14 @@ HandshakeActor::HandshakeActor(unique_ptr handshake, unique_pt } void HandshakeActor::close() { - finish(Status::Error("Cancelled")); + finish(Status::Error("Canceled")); stop(); } void HandshakeActor::start_up() { Scheduler::subscribe(connection_->get_poll_info().extract_pollable_fd(this)); set_timeout_in(timeout_); + handshake_->set_timeout_in(timeout_); yield(); } @@ -49,14 +50,34 @@ void HandshakeActor::loop() { } } +void HandshakeActor::hangup() { + finish(Status::Error(1, "Canceled")); + stop(); +} + +void HandshakeActor::timeout_expired() { + finish(Status::Error("Timeout expired")); + stop(); +} + +void HandshakeActor::tear_down() { + finish(Status::OK()); +} + +void HandshakeActor::finish(Status status) { + // NB: order may be important for parent + return_connection(std::move(status)); + return_handshake(); +} + void HandshakeActor::return_connection(Status status) { auto raw_connection = connection_->move_as_raw_connection(); if (!raw_connection) { CHECK(!raw_connection_promise_); return; } - if (status.is_error() && !raw_connection->debug_str_.empty()) { - status = Status::Error(status.code(), PSLICE() << status.message() << " : " << raw_connection->debug_str_); + if (status.is_error() && !raw_connection->extra().debug_str.empty()) { + status = status.move_as_error_suffix(PSLICE() << " : " << raw_connection->extra().debug_str); } Scheduler::unsubscribe(raw_connection->get_poll_info().get_pollable_fd_ref()); if (raw_connection_promise_) { diff --git a/lib/tgchat/ext/td/td/mtproto/HandshakeActor.h b/lib/tgchat/ext/td/td/mtproto/HandshakeActor.h index 652fed1a..61b5010e 100644 --- a/lib/tgchat/ext/td/td/mtproto/HandshakeActor.h +++ b/lib/tgchat/ext/td/td/mtproto/HandshakeActor.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -18,8 +18,8 @@ namespace td { namespace mtproto { -// Has Raw connection. Generates new auth key. And returns it and raw_connection. Or error... -class HandshakeActor : public Actor { +// Owns RawConnection. Generates new auth key. And returns it and RawConnection. Or error... +class HandshakeActor final : public Actor { public: HandshakeActor(unique_ptr handshake, unique_ptr raw_connection, unique_ptr context, double timeout, @@ -35,27 +35,20 @@ class HandshakeActor : public Actor { Promise> raw_connection_promise_; Promise> handshake_promise_; - void start_up() override; - void tear_down() override { - finish(Status::OK()); - } - void hangup() override { - finish(Status::Error(1, "Cancelled")); - stop(); - } - void timeout_expired() override { - finish(Status::Error("Timeout expired")); - stop(); - } - void loop() override; - - void finish(Status status) { - // NB: order may be important for parent - return_connection(std::move(status)); - return_handshake(); - } + void start_up() final; + + void tear_down() final; + + void hangup() final; + + void timeout_expired() final; + + void loop() final; + + void finish(Status status); void return_connection(Status status); + void return_handshake(); }; diff --git a/lib/tgchat/ext/td/td/mtproto/HandshakeConnection.h b/lib/tgchat/ext/td/td/mtproto/HandshakeConnection.h index 9bd8f60a..49ef722b 100644 --- a/lib/tgchat/ext/td/td/mtproto/HandshakeConnection.h +++ b/lib/tgchat/ext/td/td/mtproto/HandshakeConnection.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -24,7 +24,7 @@ namespace td { namespace mtproto { -class HandshakeConnection +class HandshakeConnection final : private RawConnection::Callback , private AuthKeyHandshake::Callback { public: @@ -60,12 +60,12 @@ class HandshakeConnection AuthKeyHandshake *handshake_; unique_ptr context_; - void send_no_crypto(const Storer &storer) override { + void send_no_crypto(const Storer &storer) final { raw_connection_->send_no_crypto(PacketStorer(0, storer)); } - Status on_raw_packet(const PacketInfo &packet_info, BufferSlice packet) override { - if (packet_info.no_crypto_flag == false) { + Status on_raw_packet(const PacketInfo &packet_info, BufferSlice packet) final { + if (!packet_info.no_crypto_flag) { return Status::Error("Expected not encrypted packet"); } diff --git a/lib/tgchat/ext/td/td/mtproto/HttpTransport.cpp b/lib/tgchat/ext/td/td/mtproto/HttpTransport.cpp index 63ee0bd7..49fcf730 100644 --- a/lib/tgchat/ext/td/td/mtproto/HttpTransport.cpp +++ b/lib/tgchat/ext/td/td/mtproto/HttpTransport.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,6 +13,7 @@ #include "td/utils/logging.h" #include "td/utils/misc.h" #include "td/utils/Slice.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Status.h" // TODO: do I need \r\n as delimiter? diff --git a/lib/tgchat/ext/td/td/mtproto/HttpTransport.h b/lib/tgchat/ext/td/td/mtproto/HttpTransport.h index b96bf7ed..25db3810 100644 --- a/lib/tgchat/ext/td/td/mtproto/HttpTransport.h +++ b/lib/tgchat/ext/td/td/mtproto/HttpTransport.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -21,35 +21,35 @@ namespace td { namespace mtproto { namespace http { -class Transport : public IStreamTransport { +class Transport final : public IStreamTransport { public: explicit Transport(string secret) : secret_(std::move(secret)) { } - Result read_next(BufferSlice *message, uint32 *quick_ack) override TD_WARN_UNUSED_RESULT; - bool support_quick_ack() const override { + Result read_next(BufferSlice *message, uint32 *quick_ack) final TD_WARN_UNUSED_RESULT; + bool support_quick_ack() const final { return false; } - void write(BufferWriter &&message, bool quick_ack) override; - bool can_read() const override; - bool can_write() const override; - void init(ChainBufferReader *input, ChainBufferWriter *output) override { + void write(BufferWriter &&message, bool quick_ack) final; + bool can_read() const final; + bool can_write() const final; + void init(ChainBufferReader *input, ChainBufferWriter *output) final { reader_.init(input); output_ = output; } - size_t max_prepend_size() const override; - size_t max_append_size() const override; - TransportType get_type() const override { + size_t max_prepend_size() const final; + size_t max_append_size() const final; + TransportType get_type() const final { return {TransportType::Http, 0, ProxySecret::from_raw(secret_)}; } - bool use_random_padding() const override; + bool use_random_padding() const final; private: string secret_; HttpReader reader_; HttpQuery http_query_; - ChainBufferWriter *output_; + ChainBufferWriter *output_ = nullptr; enum { Write, Read } turn_ = Write; }; diff --git a/lib/tgchat/ext/td/td/mtproto/IStreamTransport.cpp b/lib/tgchat/ext/td/td/mtproto/IStreamTransport.cpp index 4f3aed7b..e3e96e6c 100644 --- a/lib/tgchat/ext/td/td/mtproto/IStreamTransport.cpp +++ b/lib/tgchat/ext/td/td/mtproto/IStreamTransport.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/mtproto/IStreamTransport.h b/lib/tgchat/ext/td/td/mtproto/IStreamTransport.h index 74621aec..ea49a1c0 100644 --- a/lib/tgchat/ext/td/td/mtproto/IStreamTransport.h +++ b/lib/tgchat/ext/td/td/mtproto/IStreamTransport.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/mtproto/KDF.cpp b/lib/tgchat/ext/td/td/mtproto/KDF.cpp index f77cac0c..aafd81a0 100644 --- a/lib/tgchat/ext/td/td/mtproto/KDF.cpp +++ b/lib/tgchat/ext/td/td/mtproto/KDF.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/mtproto/KDF.h b/lib/tgchat/ext/td/td/mtproto/KDF.h index d01e261d..41266d9c 100644 --- a/lib/tgchat/ext/td/td/mtproto/KDF.h +++ b/lib/tgchat/ext/td/td/mtproto/KDF.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/mtproto/MtprotoQuery.h b/lib/tgchat/ext/td/td/mtproto/MtprotoQuery.h new file mode 100644 index 00000000..933900e9 --- /dev/null +++ b/lib/tgchat/ext/td/td/mtproto/MtprotoQuery.h @@ -0,0 +1,25 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/utils/buffer.h" +#include "td/utils/common.h" + +namespace td { +namespace mtproto { + +struct MtprotoQuery { + int64 message_id; + int32 seq_no; + BufferSlice packet; + bool gzip_flag; + uint64 invoke_after_id; + bool use_quick_ack; +}; + +} // namespace mtproto +} // namespace td diff --git a/lib/tgchat/ext/td/td/mtproto/NoCryptoStorer.h b/lib/tgchat/ext/td/td/mtproto/NoCryptoStorer.h index c3ffb7d8..a8e536ce 100644 --- a/lib/tgchat/ext/td/td/mtproto/NoCryptoStorer.h +++ b/lib/tgchat/ext/td/td/mtproto/NoCryptoStorer.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/mtproto/PacketInfo.h b/lib/tgchat/ext/td/td/mtproto/PacketInfo.h index 2370dc86..4407101f 100644 --- a/lib/tgchat/ext/td/td/mtproto/PacketInfo.h +++ b/lib/tgchat/ext/td/td/mtproto/PacketInfo.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -14,17 +14,17 @@ namespace mtproto { struct PacketInfo { enum { Common, EndToEnd } type = Common; - uint64 auth_key_id; - uint32 message_ack; + uint64 auth_key_id{0}; + uint32 message_ack{0}; UInt128 message_key; - uint64 salt; - uint64 session_id; + uint64 salt{0}; + uint64 session_id{0}; - uint64 message_id; - int32 seq_no; + uint64 message_id{0}; + int32 seq_no{0}; int32 version{1}; - bool no_crypto_flag; + bool no_crypto_flag{false}; bool is_creator{false}; bool check_mod4{true}; bool use_random_padding{false}; diff --git a/lib/tgchat/ext/td/td/mtproto/PacketStorer.h b/lib/tgchat/ext/td/td/mtproto/PacketStorer.h index e5ce2673..c71b33f8 100644 --- a/lib/tgchat/ext/td/td/mtproto/PacketStorer.h +++ b/lib/tgchat/ext/td/td/mtproto/PacketStorer.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,11 @@ namespace td { namespace mtproto { template -class PacketStorer +class PacketStorer final : public Storer , public Impl { public: - size_t size() const override { + size_t size() const final { if (size_ != std::numeric_limits::max()) { return size_; } @@ -28,7 +28,7 @@ class PacketStorer return size_ = storer.get_length(); } - size_t store(uint8 *ptr) const override { + size_t store(uint8 *ptr) const final { TlStorerUnsafe storer(ptr); this->do_store(storer); return static_cast(storer.get_buf() - ptr); diff --git a/lib/tgchat/ext/td/td/mtproto/Ping.cpp b/lib/tgchat/ext/td/td/mtproto/Ping.cpp index 082efdb0..f92368c5 100644 --- a/lib/tgchat/ext/td/td/mtproto/Ping.cpp +++ b/lib/tgchat/ext/td/td/mtproto/Ping.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,15 +13,15 @@ #include "td/actor/actor.h" #include "td/actor/PromiseFuture.h" -#include "td/utils/logging.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Status.h" namespace td { namespace mtproto { -ActorOwn<> create_ping_actor(string debug, unique_ptr raw_connection, unique_ptr auth_data, +ActorOwn<> create_ping_actor(Slice actor_name, unique_ptr raw_connection, unique_ptr auth_data, Promise> promise, ActorShared<> parent) { - class PingActor : public Actor { + class PingActor final : public Actor { public: PingActor(unique_ptr raw_connection, unique_ptr auth_data, Promise> promise, ActorShared<> parent) @@ -38,22 +38,22 @@ ActorOwn<> create_ping_actor(string debug, unique_ptr raw_connect Promise> promise_; ActorShared<> parent_; - void start_up() override { + void start_up() final { Scheduler::subscribe(ping_connection_->get_poll_info().extract_pollable_fd(this)); set_timeout_in(10); yield(); } - void hangup() override { - finish(Status::Error("Cancelled")); + void hangup() final { + finish(Status::Error("Canceled")); stop(); } - void tear_down() override { + void tear_down() final { finish(Status::OK()); } - void loop() override { + void loop() final { auto status = ping_connection_->flush(); if (status.is_error()) { finish(std::move(status)); @@ -65,7 +65,7 @@ ActorOwn<> create_ping_actor(string debug, unique_ptr raw_connect } } - void timeout_expired() override { + void timeout_expired() final { finish(Status::Error("Pong timeout expired")); stop(); } @@ -85,7 +85,7 @@ ActorOwn<> create_ping_actor(string debug, unique_ptr raw_connect raw_connection->close(); promise_.set_error(std::move(status)); } else { - raw_connection->rtt_ = ping_connection_->rtt(); + raw_connection->extra().rtt = ping_connection_->rtt(); if (raw_connection->stats_callback()) { raw_connection->stats_callback()->on_pong(); } @@ -99,7 +99,7 @@ ActorOwn<> create_ping_actor(string debug, unique_ptr raw_connect } } }; - return ActorOwn<>(create_actor(PSLICE() << "PingActor<" << debug << ">", std::move(raw_connection), + return ActorOwn<>(create_actor(PSLICE() << "PingActor<" << actor_name << ">", std::move(raw_connection), std::move(auth_data), std::move(promise), std::move(parent))); } diff --git a/lib/tgchat/ext/td/td/mtproto/Ping.h b/lib/tgchat/ext/td/td/mtproto/Ping.h index 471be12d..3d7e7943 100644 --- a/lib/tgchat/ext/td/td/mtproto/Ping.h +++ b/lib/tgchat/ext/td/td/mtproto/Ping.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,11 +13,12 @@ #include "td/actor/PromiseFuture.h" #include "td/utils/common.h" +#include "td/utils/Slice.h" namespace td { namespace mtproto { -ActorOwn<> create_ping_actor(string debug, unique_ptr raw_connection, unique_ptr auth_data, +ActorOwn<> create_ping_actor(Slice actor_name, unique_ptr raw_connection, unique_ptr auth_data, Promise> promise, ActorShared<> parent); } // namespace mtproto diff --git a/lib/tgchat/ext/td/td/mtproto/PingConnection.cpp b/lib/tgchat/ext/td/td/mtproto/PingConnection.cpp index 561125ab..8d8659c4 100644 --- a/lib/tgchat/ext/td/td/mtproto/PingConnection.cpp +++ b/lib/tgchat/ext/td/td/mtproto/PingConnection.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -27,7 +27,7 @@ namespace td { namespace mtproto { namespace detail { -class PingConnectionReqPQ +class PingConnectionReqPQ final : public PingConnection , private RawConnection::Callback { public: @@ -35,15 +35,15 @@ class PingConnectionReqPQ : raw_connection_(std::move(raw_connection)), ping_count_(ping_count) { } - PollableFdInfo &get_poll_info() override { + PollableFdInfo &get_poll_info() final { return raw_connection_->get_poll_info(); } - unique_ptr move_as_raw_connection() override { + unique_ptr move_as_raw_connection() final { return std::move(raw_connection_); } - Status flush() override { + Status flush() final { if (!was_ping_) { UInt128 nonce; Random::secure_bytes(nonce.raw, sizeof(nonce)); @@ -55,14 +55,14 @@ class PingConnectionReqPQ } return raw_connection_->flush(AuthKey(), *this); } - bool was_pong() const override { + bool was_pong() const final { return finish_time_ > 0; } - double rtt() const override { + double rtt() const final { return finish_time_ - start_time_; } - Status on_raw_packet(const PacketInfo &packet_info, BufferSlice packet) override { + Status on_raw_packet(const PacketInfo &packet_info, BufferSlice packet) final { if (packet.size() < 12) { return Status::Error("Result is too small"); } @@ -86,7 +86,7 @@ class PingConnectionReqPQ bool was_ping_ = false; }; -class PingConnectionPingPong +class PingConnectionPingPong final : public PingConnection , private SessionConnection::Callback { public: @@ -105,31 +105,31 @@ class PingConnectionPingPong double rtt_; bool is_closed_{false}; Status status_; - void on_connected() override { + void on_connected() final { } - void on_closed(Status status) override { + void on_closed(Status status) final { is_closed_ = true; CHECK(status.is_error()); status_ = std::move(status); } - void on_auth_key_updated() override { + void on_auth_key_updated() final { } - void on_tmp_auth_key_updated() override { + void on_tmp_auth_key_updated() final { } - void on_server_salt_updated() override { + void on_server_salt_updated() final { } - void on_server_time_difference_updated() override { + void on_server_time_difference_updated() final { } - void on_session_created(uint64 unique_id, uint64 first_id) override { + void on_session_created(uint64 unique_id, uint64 first_id) final { } - void on_session_failed(Status status) override { + void on_session_failed(Status status) final { } - void on_container_sent(uint64 container_id, vector msgs_id) override { + void on_container_sent(uint64 container_id, vector msgs_id) final { } - Status on_pong() override { + Status on_pong() final { pong_cnt_++; if (pong_cnt_ == 1) { rtt_ = Time::now(); @@ -140,30 +140,33 @@ class PingConnectionPingPong return Status::OK(); } - void on_message_ack(uint64 id) override { + Status on_update(BufferSlice packet) final { + return Status::OK(); + } + void on_message_ack(uint64 id) final { } - Status on_message_result_ok(uint64 id, BufferSlice packet, size_t original_size) override { + Status on_message_result_ok(uint64 id, BufferSlice packet, size_t original_size) final { LOG(ERROR) << "Unexpected message"; return Status::OK(); } - void on_message_result_error(uint64 id, int code, BufferSlice descr) override { + void on_message_result_error(uint64 id, int code, string message) final { } - void on_message_failed(uint64 id, Status status) override { + void on_message_failed(uint64 id, Status status) final { } - void on_message_info(uint64 id, int32 state, uint64 answer_id, int32 answer_size) override { + void on_message_info(uint64 id, int32 state, uint64 answer_id, int32 answer_size) final { } - Status on_destroy_auth_key() override { + Status on_destroy_auth_key() final { LOG(ERROR) << "Destroy auth key"; return Status::OK(); } - PollableFdInfo &get_poll_info() override { + PollableFdInfo &get_poll_info() final { return connection_->get_poll_info(); } - unique_ptr move_as_raw_connection() override { + unique_ptr move_as_raw_connection() final { return connection_->move_as_raw_connection(); } - Status flush() override { + Status flush() final { if (was_pong()) { return Status::OK(); } @@ -175,10 +178,10 @@ class PingConnectionPingPong } return Status::OK(); } - bool was_pong() const override { + bool was_pong() const final { return pong_cnt_ >= 2; } - double rtt() const override { + double rtt() const final { return rtt_; } }; diff --git a/lib/tgchat/ext/td/td/mtproto/PingConnection.h b/lib/tgchat/ext/td/td/mtproto/PingConnection.h index 01afaf90..b7750974 100644 --- a/lib/tgchat/ext/td/td/mtproto/PingConnection.h +++ b/lib/tgchat/ext/td/td/mtproto/PingConnection.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/mtproto/ProxySecret.cpp b/lib/tgchat/ext/td/td/mtproto/ProxySecret.cpp index 571cd8f7..3373d5cb 100644 --- a/lib/tgchat/ext/td/td/mtproto/ProxySecret.cpp +++ b/lib/tgchat/ext/td/td/mtproto/ProxySecret.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/mtproto/ProxySecret.h b/lib/tgchat/ext/td/td/mtproto/ProxySecret.h index 199d02a6..fb88ff25 100644 --- a/lib/tgchat/ext/td/td/mtproto/ProxySecret.h +++ b/lib/tgchat/ext/td/td/mtproto/ProxySecret.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -32,9 +32,9 @@ class ProxySecret { } Slice get_proxy_secret() const { - auto proxy_secret = Slice(secret_).truncate(17); - if (proxy_secret.size() == 17) { - proxy_secret.remove_prefix(1); + Slice proxy_secret(secret_); + if (proxy_secret.size() >= 17) { + return proxy_secret.substr(1, 16); } return proxy_secret; } diff --git a/lib/tgchat/ext/td/td/mtproto/RSA.cpp b/lib/tgchat/ext/td/td/mtproto/RSA.cpp index a5825c2a..918f28f1 100644 --- a/lib/tgchat/ext/td/td/mtproto/RSA.cpp +++ b/lib/tgchat/ext/td/td/mtproto/RSA.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -12,7 +12,6 @@ #include "td/utils/common.h" #include "td/utils/crypto.h" #include "td/utils/misc.h" -#include "td/utils/Random.h" #include "td/utils/ScopeGuard.h" #include "td/utils/Slice.h" #include "td/utils/Status.h" @@ -20,10 +19,14 @@ #include #include +#include #include +#if OPENSSL_VERSION_NUMBER < 0x30000000L || defined(LIBRESSL_VERSION_NUMBER) #include +#endif namespace td { +namespace mtproto { RSA::RSA(BigNum n, BigNum e) : n_(std::move(n)), e_(std::move(e)) { } @@ -44,25 +47,55 @@ Result RSA::from_pem_public_key(Slice pem) { BIO_free(bio); }; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) + EVP_PKEY *rsa = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); +#else auto rsa = PEM_read_bio_RSAPublicKey(bio, nullptr, nullptr, nullptr); +#endif if (rsa == nullptr) { - return Status::Error("Error while reading rsa pubkey"); + return Status::Error("Error while reading RSA public key"); } SCOPE_EXIT { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) + EVP_PKEY_free(rsa); +#else RSA_free(rsa); +#endif }; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) + if (!EVP_PKEY_is_a(rsa, "RSA")) { + return Status::Error("Key is not an RSA key"); + } + if (EVP_PKEY_size(rsa) != 256) { + return Status::Error("EVP_PKEY_size != 256"); + } +#else if (RSA_size(rsa) != 256) { return Status::Error("RSA_size != 256"); } +#endif +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) + BIGNUM *n_num = nullptr; + BIGNUM *e_num = nullptr; + + int res = EVP_PKEY_get_bn_param(rsa, "n", &n_num); + CHECK(res == 1 && n_num != nullptr); + res = EVP_PKEY_get_bn_param(rsa, "e", &e_num); + CHECK(res == 1 && e_num != nullptr); + + auto n = static_cast(n_num); + auto e = static_cast(e_num); +#else const BIGNUM *n_num; const BIGNUM *e_num; -#if OPENSSL_VERSION_NUMBER < 0x10100000L + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + RSA_get0_key(rsa, &n_num, &e_num, nullptr); +#else n_num = rsa->n; e_num = rsa->e; -#else - RSA_get0_key(rsa, &n_num, &e_num, nullptr); #endif auto n = static_cast(BN_dup(n_num)); @@ -70,6 +103,7 @@ Result RSA::from_pem_public_key(Slice pem) { if (n == nullptr || e == nullptr) { return Status::Error("Cannot dup BIGNUM"); } +#endif return RSA(BigNum::from_raw(n), BigNum::from_raw(e)); } @@ -93,26 +127,22 @@ size_t RSA::size() const { return 256; } -size_t RSA::encrypt(unsigned char *from, size_t from_len, size_t max_from_len, unsigned char *to, size_t to_len) const { - CHECK(from_len > 0 && from_len <= 2550); - size_t pad = (25500 - from_len - 32) % 255 + 32; - size_t chunks = (from_len + pad) / 255; +bool RSA::encrypt(Slice from, MutableSlice to) const { + CHECK(from.size() == 256) + CHECK(to.size() == 256) int bits = n_.get_num_bits(); CHECK(bits >= 2041 && bits <= 2048); - CHECK(chunks * 255 == from_len + pad); - CHECK(from_len + pad <= max_from_len); - CHECK(chunks * 256 <= to_len); - Random::secure_bytes(from + from_len, pad); + + BigNum x = BigNum::from_binary(from); + if (BigNum::compare(x, n_) >= 0) { + return false; + } BigNumContext ctx; BigNum y; - while (chunks-- > 0) { - BigNum x = BigNum::from_binary(Slice(from, 255)); - BigNum::mod_exp(y, x, e_, n_, ctx); - MutableSlice(to, 256).copy_from(y.to_binary(256)); - to += 256; - } - return chunks * 256; + BigNum::mod_exp(y, x, e_, n_, ctx); + to.copy_from(y.to_binary(256)); + return true; } void RSA::decrypt_signature(Slice from, MutableSlice to) const { @@ -124,4 +154,5 @@ void RSA::decrypt_signature(Slice from, MutableSlice to) const { to.copy_from(y.to_binary(256)); } +} // namespace mtproto } // namespace td diff --git a/lib/tgchat/ext/td/td/mtproto/RSA.h b/lib/tgchat/ext/td/td/mtproto/RSA.h index 68ea42b7..36a45351 100644 --- a/lib/tgchat/ext/td/td/mtproto/RSA.h +++ b/lib/tgchat/ext/td/td/mtproto/RSA.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -11,16 +11,16 @@ #include "td/utils/Slice.h" #include "td/utils/Status.h" -#include - namespace td { +namespace mtproto { class RSA { public: RSA clone() const; int64 get_fingerprint() const; size_t size() const; - size_t encrypt(unsigned char *from, size_t from_len, size_t max_from_len, unsigned char *to, size_t to_len) const; + + bool encrypt(Slice from, MutableSlice to) const; void decrypt_signature(Slice from, MutableSlice to) const; @@ -35,8 +35,15 @@ class RSA { class PublicRsaKeyInterface { public: virtual ~PublicRsaKeyInterface() = default; - virtual Result> get_rsa(const vector &fingerprints) = 0; + + struct RsaKey { + RSA rsa; + int64 fingerprint; + }; + virtual Result get_rsa_key(const vector &fingerprints) = 0; + virtual void drop_keys() = 0; }; +} // namespace mtproto } // namespace td diff --git a/lib/tgchat/ext/td/td/mtproto/RawConnection.cpp b/lib/tgchat/ext/td/td/mtproto/RawConnection.cpp index c49675a7..77af4b90 100644 --- a/lib/tgchat/ext/td/td/mtproto/RawConnection.cpp +++ b/lib/tgchat/ext/td/td/mtproto/RawConnection.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -7,156 +7,458 @@ #include "td/mtproto/RawConnection.h" #include "td/mtproto/AuthKey.h" +#include "td/mtproto/IStreamTransport.h" +#include "td/mtproto/ProxySecret.h" #include "td/mtproto/Transport.h" +#if TD_DARWIN_WATCH_OS +#include "td/net/DarwinHttp.h" +#endif + #include "td/utils/format.h" #include "td/utils/logging.h" #include "td/utils/misc.h" +#include "td/utils/MpscPollableQueue.h" +#include "td/utils/port/EventFd.h" +#include "td/utils/Slice.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Status.h" #include "td/utils/StorerBase.h" +#include +#include #include namespace td { namespace mtproto { -void RawConnection::send_crypto(const Storer &storer, int64 session_id, int64 salt, const AuthKey &auth_key, - uint64 quick_ack_token) { - PacketInfo info; - info.version = 2; - info.no_crypto_flag = false; - info.salt = salt; - info.session_id = session_id; - info.use_random_padding = transport_->use_random_padding(); +class RawConnectionDefault final : public RawConnection { + public: + RawConnectionDefault(BufferedFd buffered_socket_fd, TransportType transport_type, + unique_ptr stats_callback) + : socket_fd_(std::move(buffered_socket_fd)) + , transport_(create_transport(std::move(transport_type))) + , stats_callback_(std::move(stats_callback)) { + transport_->init(&socket_fd_.input_buffer(), &socket_fd_.output_buffer()); + } + + void set_connection_token(ConnectionManager::ConnectionToken connection_token) final { + connection_token_ = std::move(connection_token); + } + + bool can_send() const final { + return transport_->can_write(); + } + TransportType get_transport_type() const final { + return transport_->get_type(); + } + void send_crypto(const Storer &storer, int64 session_id, int64 salt, const AuthKey &auth_key, + uint64 quick_ack_token) final { + PacketInfo info; + info.version = 2; + info.no_crypto_flag = false; + info.salt = salt; + info.session_id = session_id; + info.use_random_padding = transport_->use_random_padding(); - auto packet = BufferWriter{Transport::write(storer, auth_key, &info), transport_->max_prepend_size(), - transport_->max_append_size()}; - Transport::write(storer, auth_key, &info, packet.as_slice()); + auto packet = BufferWriter{Transport::write(storer, auth_key, &info), transport_->max_prepend_size(), + transport_->max_append_size()}; + Transport::write(storer, auth_key, &info, packet.as_slice()); - bool use_quick_ack = false; - if (quick_ack_token != 0 && transport_->support_quick_ack()) { - auto tmp = quick_ack_to_token_.emplace(info.message_ack, quick_ack_token); - if (tmp.second) { - use_quick_ack = true; - } else { - LOG(ERROR) << "Quick ack " << info.message_ack << " collision"; + bool use_quick_ack = false; + if (quick_ack_token != 0 && transport_->support_quick_ack()) { + auto tmp = quick_ack_to_token_.emplace(info.message_ack, quick_ack_token); + if (tmp.second) { + use_quick_ack = true; + } else { + LOG(ERROR) << "Quick ack " << info.message_ack << " collision"; + } } + + transport_->write(std::move(packet), use_quick_ack); } - transport_->write(std::move(packet), use_quick_ack); -} + uint64 send_no_crypto(const Storer &storer) final { + PacketInfo info; -uint64 RawConnection::send_no_crypto(const Storer &storer) { - PacketInfo info; + info.no_crypto_flag = true; + auto packet = BufferWriter{Transport::write(storer, AuthKey(), &info), transport_->max_prepend_size(), + transport_->max_append_size()}; + Transport::write(storer, AuthKey(), &info, packet.as_slice()); + LOG(INFO) << "Send handshake packet: " << format::as_hex_dump<4>(packet.as_slice()); + transport_->write(std::move(packet), false); + return info.message_id; + } - info.no_crypto_flag = true; - auto packet = BufferWriter{Transport::write(storer, AuthKey(), &info), transport_->max_prepend_size(), - transport_->max_append_size()}; - Transport::write(storer, AuthKey(), &info, packet.as_slice()); - LOG(INFO) << "Send handshake packet: " << format::as_hex_dump<4>(packet.as_slice()); - transport_->write(std::move(packet), false); - return info.message_id; -} + PollableFdInfo &get_poll_info() final { + return socket_fd_.get_poll_info(); + } + + StatsCallback *stats_callback() final { + return stats_callback_.get(); + } + + // NB: After first returned error, all subsequent calls will return error too. + Status flush(const AuthKey &auth_key, Callback &callback) final { + auto status = do_flush(auth_key, callback); + if (status.is_error()) { + if (stats_callback_ && status.code() != 2) { + stats_callback_->on_error(); + } + has_error_ = true; + } + return status; + } + + bool has_error() const final { + return has_error_; + } + + void close() final { + transport_.reset(); + socket_fd_.close(); + } + + PublicFields &extra() final { + return extra_; + } + const PublicFields &extra() const final { + return extra_; + } + + private: + PublicFields extra_; + BufferedFd socket_fd_; + unique_ptr transport_; + std::unordered_map quick_ack_to_token_; + bool has_error_{false}; + + unique_ptr stats_callback_; + + ConnectionManager::ConnectionToken connection_token_; -Status RawConnection::flush_read(const AuthKey &auth_key, Callback &callback) { - auto r = socket_fd_.flush_read(); - if (r.is_ok()) { - if (stats_callback_) { - stats_callback_->on_read(r.ok()); - } - callback.on_read(r.ok()); - } - while (transport_->can_read()) { - BufferSlice packet; - uint32 quick_ack = 0; - TRY_RESULT(wait_size, transport_->read_next(&packet, &quick_ack)); - if (!is_aligned_pointer<4>(packet.as_slice().ubegin())) { - BufferSlice new_packet(packet.size()); - new_packet.as_slice().copy_from(packet.as_slice()); - packet = std::move(new_packet); - } - LOG_CHECK(is_aligned_pointer<4>(packet.as_slice().ubegin())) - << packet.as_slice().ubegin() << ' ' << packet.size() << ' ' << wait_size; - if (wait_size != 0) { - constexpr size_t MAX_PACKET_SIZE = (1 << 22) + 1024; - if (wait_size > MAX_PACKET_SIZE) { - return Status::Error(PSLICE() << "Expected packet size is too big: " << wait_size); + Status flush_read(const AuthKey &auth_key, Callback &callback) { + auto r = socket_fd_.flush_read(); + if (r.is_ok()) { + if (stats_callback_) { + stats_callback_->on_read(r.ok()); } - break; + callback.on_read(r.ok()); } + while (transport_->can_read()) { + BufferSlice packet; + uint32 quick_ack = 0; + TRY_RESULT(wait_size, transport_->read_next(&packet, &quick_ack)); + if (!is_aligned_pointer<4>(packet.as_slice().ubegin())) { + BufferSlice new_packet(packet.size()); + new_packet.as_slice().copy_from(packet.as_slice()); + packet = std::move(new_packet); + } + LOG_CHECK(is_aligned_pointer<4>(packet.as_slice().ubegin())) + << packet.as_slice().ubegin() << ' ' << packet.size() << ' ' << wait_size; + if (wait_size != 0) { + constexpr size_t MAX_PACKET_SIZE = (1 << 22) + 1024; + if (wait_size > MAX_PACKET_SIZE) { + return Status::Error(PSLICE() << "Expected packet size is too big: " << wait_size); + } + break; + } + + if (quick_ack != 0) { + TRY_STATUS(on_quick_ack(quick_ack, callback)); + continue; + } + + PacketInfo info; + info.version = 2; + + TRY_RESULT(read_result, Transport::read(packet.as_slice(), auth_key, &info)); + switch (read_result.type()) { + case Transport::ReadResult::Quickack: { + TRY_STATUS(on_quick_ack(read_result.quick_ack(), callback)); + break; + } + case Transport::ReadResult::Error: { + TRY_STATUS(on_read_mtproto_error(read_result.error())); + break; + } + case Transport::ReadResult::Packet: { + // If a packet was successfully decrypted, then it is ok to assume that the connection is alive + if (!auth_key.empty()) { + if (stats_callback_) { + stats_callback_->on_pong(); + } + } + + TRY_STATUS(callback.on_raw_packet(info, packet.from_slice(read_result.packet()))); + break; + } + case Transport::ReadResult::Nop: + break; + default: + UNREACHABLE(); + } + } + + TRY_STATUS(std::move(r)); + return Status::OK(); + } + + Status on_read_mtproto_error(int32 error_code) { + if (error_code == -429) { + if (stats_callback_) { + stats_callback_->on_mtproto_error(); + } + return Status::Error(500, PSLICE() << "MTProto error: " << error_code); + } + if (error_code == -404) { + return Status::Error(-404, PSLICE() << "MTProto error: " << error_code); + } + return Status::Error(PSLICE() << "MTProto error: " << error_code); + } + + Status on_quick_ack(uint32 quick_ack, Callback &callback) { + auto it = quick_ack_to_token_.find(quick_ack); + if (it == quick_ack_to_token_.end()) { + LOG(WARNING) << Status::Error(PSLICE() << "Unknown quick_ack " << quick_ack); + return Status::OK(); + // TODO: return Status::Error(PSLICE() << "Unknown quick_ack " << quick_ack); + } + auto token = it->second; + quick_ack_to_token_.erase(it); + callback.on_quick_ack(token).ignore(); + return Status::OK(); + } + + Status flush_write() { + TRY_RESULT(size, socket_fd_.flush_write()); + if (size > 0 && stats_callback_) { + stats_callback_->on_write(size); + } + return Status::OK(); + } - if (quick_ack != 0) { - TRY_STATUS(on_quick_ack(quick_ack, callback)); - continue; + Status do_flush(const AuthKey &auth_key, Callback &callback) TD_WARN_UNUSED_RESULT { + if (has_error_) { + return Status::Error("Connection has already failed"); } + sync_with_poll(socket_fd_); + + // read/write + // EINVAL may be returned in linux kernel < 2.6.28. And on some new kernels too. + // just close connection and hope that read or write will not return this error too. + TRY_STATUS(socket_fd_.get_pending_error()); + TRY_STATUS(flush_read(auth_key, callback)); + TRY_STATUS(callback.before_write()); + TRY_STATUS(flush_write()); + if (can_close_local(socket_fd_)) { + return Status::Error("Connection closed"); + } + return Status::OK(); + } +}; + +#if TD_DARWIN_WATCH_OS +class RawConnectionHttp final : public RawConnection { + public: + RawConnectionHttp(IPAddress ip_address, unique_ptr stats_callback) + : ip_address_(std::move(ip_address)), stats_callback_(std::move(stats_callback)) { + answers_ = std::make_shared>>(); + answers_->init(); + } + + void set_connection_token(ConnectionManager::ConnectionToken connection_token) final { + connection_token_ = std::move(connection_token); + } + + bool can_send() const final { + return mode_ == Send; + } + TransportType get_transport_type() const final { + return mtproto::TransportType{mtproto::TransportType::Http, 0, mtproto::ProxySecret()}; + } + void send_crypto(const Storer &storer, int64 session_id, int64 salt, const AuthKey &auth_key, + uint64 quick_ack_token) final { PacketInfo info; info.version = 2; + info.no_crypto_flag = false; + info.salt = salt; + info.session_id = session_id; + info.use_random_padding = false; - TRY_RESULT(read_result, Transport::read(packet.as_slice(), auth_key, &info)); - switch (read_result.type()) { - case Transport::ReadResult::Quickack: { - TRY_STATUS(on_quick_ack(read_result.quick_ack(), callback)); - break; + auto packet = BufferWriter{Transport::write(storer, auth_key, &info), 0, 0}; + Transport::write(storer, auth_key, &info, packet.as_slice()); + + send_packet(packet.as_buffer_slice()); + } + + uint64 send_no_crypto(const Storer &storer) final { + PacketInfo info; + + info.no_crypto_flag = true; + auto packet = BufferWriter{Transport::write(storer, AuthKey(), &info), 0, 0}; + Transport::write(storer, AuthKey(), &info, packet.as_slice()); + LOG(INFO) << "Send handshake packet: " << format::as_hex_dump<4>(packet.as_slice()); + send_packet(packet.as_buffer_slice()); + return info.message_id; + } + + PollableFdInfo &get_poll_info() final { + return answers_->reader_get_event_fd().get_poll_info(); + } + + StatsCallback *stats_callback() final { + return stats_callback_.get(); + } + + // NB: After first returned error, all subsequent calls will return error too. + Status flush(const AuthKey &auth_key, Callback &callback) final { + auto status = do_flush(auth_key, callback); + if (status.is_error()) { + if (stats_callback_ && status.code() != 2) { + stats_callback_->on_error(); } - case Transport::ReadResult::Error: { - TRY_STATUS(on_read_mtproto_error(read_result.error())); + has_error_ = true; + } + return status; + } + + bool has_error() const final { + return has_error_; + } + + void close() final { + } + + PublicFields &extra() final { + return extra_; + } + const PublicFields &extra() const final { + return extra_; + } + + private: + PublicFields extra_; + IPAddress ip_address_; + bool has_error_{false}; + EventFd event_fd_; + + enum Mode { Send, Receive } mode_{Send}; + + unique_ptr stats_callback_; + + ConnectionManager::ConnectionToken connection_token_; + std::shared_ptr>> answers_; + std::vector to_send_; + + void send_packet(BufferSlice packet) { + CHECK(mode_ == Send); + mode_ = Receive; + to_send_.push_back(std::move(packet)); + } + + Status flush_read(const AuthKey &auth_key, Callback &callback) { + while (true) { + auto packets_n = answers_->reader_wait_nonblock(); + if (packets_n == 0) { break; } - case Transport::ReadResult::Packet: { - // If a packet was successfully decrypted, then it is ok to assume that the connection is alive - if (!auth_key.empty()) { - if (stats_callback_) { - stats_callback_->on_pong(); - } + for (int i = 0; i < packets_n; i++) { + TRY_RESULT(packet, answers_->reader_get_unsafe()); + if (stats_callback_) { + stats_callback_->on_read(packet.size()); } + callback.on_read(packet.size()); + CHECK(mode_ == Receive); + mode_ = Send; - TRY_STATUS(callback.on_raw_packet(info, packet.from_slice(read_result.packet()))); - break; + PacketInfo info; + info.version = 2; + + TRY_RESULT(read_result, Transport::read(packet.as_slice(), auth_key, &info)); + switch (read_result.type()) { + case Transport::ReadResult::Quickack: { + break; + } + case Transport::ReadResult::Error: { + TRY_STATUS(on_read_mtproto_error(read_result.error())); + break; + } + case Transport::ReadResult::Packet: { + // If a packet was successfully decrypted, then it is ok to assume that the connection is alive + if (!auth_key.empty()) { + if (stats_callback_) { + stats_callback_->on_pong(); + } + } + + TRY_STATUS(callback.on_raw_packet(info, packet.from_slice(read_result.packet()))); + break; + } + case Transport::ReadResult::Nop: + break; + default: + UNREACHABLE(); + } } - case Transport::ReadResult::Nop: - break; - default: - UNREACHABLE(); } - } - TRY_STATUS(std::move(r)); - return Status::OK(); -} + return Status::OK(); + } -Status RawConnection::on_read_mtproto_error(int32 error_code) { - if (error_code == -429) { - if (stats_callback_) { - stats_callback_->on_mtproto_error(); + Status on_read_mtproto_error(int32 error_code) { + if (error_code == -429) { + if (stats_callback_) { + stats_callback_->on_mtproto_error(); + } + return Status::Error(500, PSLICE() << "MTProto error: " << error_code); } - return Status::Error(500, PSLICE() << "MTProto error: " << error_code); + if (error_code == -404) { + return Status::Error(-404, PSLICE() << "MTProto error: " << error_code); + } + return Status::Error(PSLICE() << "MTProto error: " << error_code); } - if (error_code == -404) { - return Status::Error(-404, PSLICE() << "MTProto error: " << error_code); + + Status flush_write() { + for (auto &packet : to_send_) { + TRY_STATUS(do_send(packet.as_slice())); + if (packet.size() > 0 && stats_callback_) { + stats_callback_->on_write(packet.size()); + } + } + to_send_.clear(); + return Status::OK(); } - return Status::Error(PSLICE() << "MTProto error: " << error_code); -} -Status RawConnection::on_quick_ack(uint32 quick_ack, Callback &callback) { - auto it = quick_ack_to_token_.find(quick_ack); - if (it == quick_ack_to_token_.end()) { - LOG(WARNING) << Status::Error(PSLICE() << "Unknown quick_ack " << quick_ack); + Status do_send(Slice data) { + DarwinHttp::post(PSLICE() << "http://" << ip_address_.get_ip_str() << ":" << ip_address_.get_port() << "/api", data, + [answers = answers_](auto res) { answers->writer_put(std::move(res)); }); return Status::OK(); - // TODO: return Status::Error(PSLICE() << "Unknown quick_ack " << quick_ack); } - auto token = it->second; - quick_ack_to_token_.erase(it); - callback.on_quick_ack(token).ignore(); - return Status::OK(); -} -Status RawConnection::flush_write() { - TRY_RESULT(size, socket_fd_.flush_write()); - if (size > 0 && stats_callback_) { - stats_callback_->on_write(size); + Status do_flush(const AuthKey &auth_key, Callback &callback) TD_WARN_UNUSED_RESULT { + if (has_error_) { + return Status::Error("Connection has already failed"); + } + + TRY_STATUS(flush_read(auth_key, callback)); + TRY_STATUS(callback.before_write()); + TRY_STATUS(flush_write()); + return Status::OK(); } - return Status::OK(); +}; +#endif + +unique_ptr RawConnection::create(IPAddress ip_address, BufferedFd buffered_socket_fd, + TransportType transport_type, + unique_ptr stats_callback) { +#if TD_DARWIN_WATCH_OS + return td::make_unique(std::move(ip_address), std::move(stats_callback)); +#else + return td::make_unique(std::move(buffered_socket_fd), std::move(transport_type), + std::move(stats_callback)); +#endif } } // namespace mtproto diff --git a/lib/tgchat/ext/td/td/mtproto/RawConnection.h b/lib/tgchat/ext/td/td/mtproto/RawConnection.h index 13fdbf7e..ef31d9f3 100644 --- a/lib/tgchat/ext/td/td/mtproto/RawConnection.h +++ b/lib/tgchat/ext/td/td/mtproto/RawConnection.h @@ -1,12 +1,12 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #pragma once -#include "td/mtproto/IStreamTransport.h" +#include "td/mtproto/ConnectionManager.h" #include "td/mtproto/PacketInfo.h" #include "td/mtproto/TransportType.h" @@ -14,14 +14,11 @@ #include "td/utils/BufferedFd.h" #include "td/utils/common.h" #include "td/utils/port/detail/PollableFd.h" +#include "td/utils/port/IPAddress.h" #include "td/utils/port/SocketFd.h" #include "td/utils/Status.h" #include "td/utils/StorerBase.h" -#include "td/telegram/StateManager.h" - -#include - namespace td { namespace mtproto { @@ -40,33 +37,23 @@ class RawConnection { virtual void on_mtproto_error() = 0; }; RawConnection() = default; - RawConnection(SocketFd socket_fd, TransportType transport_type, unique_ptr stats_callback) - : socket_fd_(std::move(socket_fd)) - , transport_(create_transport(transport_type)) - , stats_callback_(std::move(stats_callback)) { - transport_->init(&socket_fd_.input_buffer(), &socket_fd_.output_buffer()); - } - - void set_connection_token(StateManager::ConnectionToken connection_token) { - connection_token_ = std::move(connection_token); - } - - bool can_send() const { - return transport_->can_write(); - } - TransportType get_transport_type() const { - return transport_->get_type(); - } - void send_crypto(const Storer &storer, int64 session_id, int64 salt, const AuthKey &auth_key, - uint64 quick_ack_token = 0); - uint64 send_no_crypto(const Storer &storer); - - PollableFdInfo &get_poll_info() { - return socket_fd_.get_poll_info(); - } - StatsCallback *stats_callback() { - return stats_callback_.get(); - } + RawConnection(const RawConnection &) = delete; + RawConnection &operator=(const RawConnection &) = delete; + virtual ~RawConnection() = default; + + static unique_ptr create(IPAddress ip_address, BufferedFd buffered_socket_fd, + TransportType transport_type, unique_ptr stats_callback); + + virtual void set_connection_token(ConnectionManager::ConnectionToken connection_token) = 0; + + virtual bool can_send() const = 0; + virtual TransportType get_transport_type() const = 0; + virtual void send_crypto(const Storer &storer, int64 session_id, int64 salt, const AuthKey &auth_key, + uint64 quick_ack_token) = 0; + virtual uint64 send_no_crypto(const Storer &storer) = 0; + + virtual PollableFdInfo &get_poll_info() = 0; + virtual StatsCallback *stats_callback() = 0; class Callback { public: @@ -76,7 +63,7 @@ class RawConnection { virtual ~Callback() = default; virtual Status on_raw_packet(const PacketInfo &info, BufferSlice packet) = 0; virtual Status on_quick_ack(uint64 quick_ack_token) { - return Status::Error("Quick acks unsupported fully, but still used"); + return Status::Error("Quick acknowledgements are unsupported by the callback"); } virtual Status before_write() { return Status::OK(); @@ -86,65 +73,19 @@ class RawConnection { }; // NB: After first returned error, all subsequent calls will return error too. - Status flush(const AuthKey &auth_key, Callback &callback) TD_WARN_UNUSED_RESULT { - auto status = do_flush(auth_key, callback); - if (status.is_error()) { - if (stats_callback_ && status.code() != 2) { - stats_callback_->on_error(); - } - has_error_ = true; - } - return status; - } - - bool has_error() const { - return has_error_; - } + virtual Status flush(const AuthKey &auth_key, Callback &callback) TD_WARN_UNUSED_RESULT = 0; + virtual bool has_error() const = 0; - void close() { - transport_.reset(); - socket_fd_.close(); - } + virtual void close() = 0; - uint32 extra_{0}; - string debug_str_; - double rtt_{0}; - - private: - BufferedFd socket_fd_; - unique_ptr transport_; - std::map quick_ack_to_token_; - bool has_error_{false}; - - unique_ptr stats_callback_; - - StateManager::ConnectionToken connection_token_; - - Status flush_read(const AuthKey &auth_key, Callback &callback); - Status flush_write(); - - Status on_quick_ack(uint32 quick_ack, Callback &callback); - Status on_read_mtproto_error(int32 error_code); + struct PublicFields { + uint32 extra{0}; + string debug_str; + double rtt{0}; + }; - Status do_flush(const AuthKey &auth_key, Callback &callback) TD_WARN_UNUSED_RESULT { - if (has_error_) { - return Status::Error("Connection has already failed"); - } - sync_with_poll(socket_fd_); - - // read/write - // EINVAL may be returned in linux kernel < 2.6.28. And on some new kernels too. - // just close connection and hope that read or write will not return this error too. - TRY_STATUS(socket_fd_.get_pending_error()); - - TRY_STATUS(flush_read(auth_key, callback)); - TRY_STATUS(callback.before_write()); - TRY_STATUS(flush_write()); - if (can_close_local(socket_fd_)) { - return Status::Error("Connection closed"); - } - return Status::OK(); - } + virtual PublicFields &extra() = 0; + virtual const PublicFields &extra() const = 0; }; } // namespace mtproto diff --git a/lib/tgchat/ext/td/td/mtproto/SessionConnection.cpp b/lib/tgchat/ext/td/td/mtproto/SessionConnection.cpp index 7ee267f5..eff073db 100644 --- a/lib/tgchat/ext/td/td/mtproto/SessionConnection.cpp +++ b/lib/tgchat/ext/td/td/mtproto/SessionConnection.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,10 +9,13 @@ #include "td/mtproto/AuthData.h" #include "td/mtproto/AuthKey.h" #include "td/mtproto/CryptoStorer.h" +#include "td/mtproto/mtproto_api.h" +#include "td/mtproto/mtproto_api.hpp" #include "td/mtproto/PacketStorer.h" #include "td/mtproto/Transport.h" #include "td/mtproto/utils.h" +#include "td/utils/algorithm.h" #include "td/utils/as.h" #include "td/utils/common.h" #include "td/utils/format.h" @@ -21,11 +24,10 @@ #include "td/utils/misc.h" #include "td/utils/Random.h" #include "td/utils/ScopeGuard.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Time.h" #include "td/utils/tl_parsers.h" - -#include "td/mtproto/mtproto_api.h" -#include "td/mtproto/mtproto_api.hpp" +#include "td/utils/TlDowncastHelper.h" #include #include @@ -170,27 +172,11 @@ namespace mtproto { * */ -class OnPacket { - const MsgInfo &info_; - SessionConnection *connection_; - Status *status_; - - public: - OnPacket(const MsgInfo &info, SessionConnection *connection, Status *status) - : info_(info), connection_(connection), status_(status) { - } - - template - void operator()(const T &func) const { - *status_ = connection_->on_packet(info_, func); - } -}; - unique_ptr SessionConnection::move_as_raw_connection() { + was_moved_ = true; return std::move(raw_connection_); } -/*** SessionConnection ***/ BufferSlice SessionConnection::as_buffer_slice(Slice packet) { return current_buffer_slice_->from_slice(packet); } @@ -230,7 +216,6 @@ Status SessionConnection::on_packet_container(const MsgInfo &info, Slice packet) }; TlParser parser(packet); - parser.fetch_int(); int32 size = parser.fetch_int(); if (parser.get_error()) { return Status::Error(PSLICE() << "Failed to parse mtproto_api::rpc_container: " << parser.get_error()); @@ -243,32 +228,40 @@ Status SessionConnection::on_packet_container(const MsgInfo &info, Slice packet) Status SessionConnection::on_packet_rpc_result(const MsgInfo &info, Slice packet) { TlParser parser(packet); - parser.fetch_int(); uint64 req_msg_id = parser.fetch_long(); if (parser.get_error()) { return Status::Error(PSLICE() << "Failed to parse mtproto_api::rpc_result: " << parser.get_error()); } + if (req_msg_id == 0) { + LOG(ERROR) << "Receive an update in rpc_result: message_id = " << info.message_id << ", seq_no = " << info.seq_no; + return Status::Error("Receive an update in rpc_result"); + } - auto object_begin_pos = packet.size() - parser.get_left_len(); - int32 id = parser.fetch_int(); - if (id == mtproto_api::rpc_error::ID) { - mtproto_api::rpc_error rpc_error(parser); - if (parser.get_error()) { - return Status::Error(PSLICE() << "Failed to parse mtproto_api::rpc_error: " << parser.get_error()); + switch (parser.fetch_int()) { + case mtproto_api::rpc_error::ID: { + mtproto_api::rpc_error rpc_error(parser); + if (parser.get_error()) { + return Status::Error(PSLICE() << "Failed to parse mtproto_api::rpc_error: " << parser.get_error()); + } + VLOG(mtproto) << "ERROR " << tag("code", rpc_error.error_code_) << tag("message", rpc_error.error_message_) + << tag("req_msg_id", req_msg_id); + callback_->on_message_result_error(req_msg_id, rpc_error.error_code_, rpc_error.error_message_.str()); + return Status::OK(); } - return on_packet(info, req_msg_id, rpc_error); - } else if (id == mtproto_api::gzip_packed::ID) { - mtproto_api::gzip_packed gzip(parser); - if (parser.get_error()) { - return Status::Error(PSLICE() << "Failed to parse mtproto_api::gzip_packed: " << parser.get_error()); + case mtproto_api::gzip_packed::ID: { + mtproto_api::gzip_packed gzip(parser); + if (parser.get_error()) { + return Status::Error(PSLICE() << "Failed to parse mtproto_api::gzip_packed: " << parser.get_error()); + } + // yep, gzip in rpc_result + BufferSlice object = gzdecode(gzip.packed_data_); + // send header no more optimization + return callback_->on_message_result_ok(req_msg_id, std::move(object), info.size); } - // yep, gzip in rpc_result - BufferSlice object = gzdecode(gzip.packed_data_); - // send header no more optimization - return callback_->on_message_result_ok(req_msg_id, std::move(object), info.size); + default: + packet.remove_prefix(sizeof(req_msg_id)); + return callback_->on_message_result_ok(req_msg_id, as_buffer_slice(packet), info.size); } - - return callback_->on_message_result_ok(req_msg_id, as_buffer_slice(packet.substr(object_begin_pos)), info.size); } template @@ -276,12 +269,15 @@ Status SessionConnection::on_packet(const MsgInfo &info, const T &packet) { LOG(ERROR) << "Unsupported: " << to_string(packet); return Status::OK(); } + Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::destroy_auth_key_ok &destroy_auth_key) { return on_destroy_auth_key(destroy_auth_key); } + Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::destroy_auth_key_none &destroy_auth_key) { return on_destroy_auth_key(destroy_auth_key); } + Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::destroy_auth_key_fail &destroy_auth_key) { return on_destroy_auth_key(destroy_auth_key); } @@ -293,18 +289,7 @@ Status SessionConnection::on_destroy_auth_key(const mtproto_api::DestroyAuthKeyR } Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::rpc_error &rpc_error) { - return on_packet(info, 0, rpc_error); -} - -Status SessionConnection::on_packet(const MsgInfo &info, uint64 req_msg_id, const mtproto_api::rpc_error &rpc_error) { - VLOG(mtproto) << "ERROR " << tag("code", rpc_error.error_code_) << tag("message", rpc_error.error_message_) - << tag("req_msg_id", req_msg_id); - if (req_msg_id != 0) { - callback_->on_message_result_error(req_msg_id, rpc_error.error_code_, as_buffer_slice(rpc_error.error_message_)); - } else { - LOG(WARNING) << "Receive rpc_error as update: [" << rpc_error.error_code_ << "][" << rpc_error.error_message_ - << "]"; - } + LOG(ERROR) << "Receive rpc_error as update: [" << rpc_error.error_code_ << "][" << rpc_error.error_message_ << "]"; return Status::OK(); } @@ -424,7 +409,7 @@ Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::pong } Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::future_salts &salts) { VLOG(mtproto) << "FUTURE_SALTS"; - std::vector new_salts; + vector new_salts; for (auto &it : salts.salts_) { new_salts.push_back( ServerSalt{it->salt_, static_cast(it->valid_since_), static_cast(it->valid_until_)}); @@ -435,7 +420,7 @@ Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::futu return Status::OK(); } -Status SessionConnection::on_msgs_state_info(const std::vector &ids, Slice info) { +Status SessionConnection::on_msgs_state_info(const vector &ids, Slice info) { if (ids.size() != info.size()) { return Status::Error(PSLICE() << tag("ids.size()", ids.size()) << " != " << tag("info.size()", info.size())); } @@ -481,41 +466,66 @@ Status SessionConnection::on_slice_packet(const MsgInfo &info, Slice packet) { if (info.seq_no & 1) { send_ack(info.message_id); } - TlParser parser(packet); - tl_object_ptr object = mtproto_api::Object::fetch(parser); - parser.fetch_end(); - if (parser.get_error()) { - // msg_container is not real tl object - if (packet.size() >= 4 && as(packet.begin()) == mtproto_api::msg_container::ID) { - return on_packet_container(info, packet); - } - if (packet.size() >= 4 && as(packet.begin()) == mtproto_api::rpc_result::ID) { - return on_packet_rpc_result(info, packet); - } + if (packet.size() < 4) { + callback_->on_session_failed(Status::Error("Receive too small packet")); + return Status::Error(PSLICE() << "Receive packet of size " << packet.size()); + } - // It is an update... I hope. - auto status = auth_data_->check_update(info.message_id); - if (status.is_error()) { - if (status.code() == 2) { - LOG(WARNING) << "Receive too old update: " << status; - callback_->on_session_failed(Status::Error("Receive too old update")); - return status; - } - VLOG(mtproto) << "Skip update " << info.message_id << " from " << get_name() << " created in " - << (Time::now() - created_at_) << ": " << status; - return Status::OK(); + int32 constructor_id = as(packet.begin()); + if (constructor_id == mtproto_api::msg_container::ID) { + return on_packet_container(info, packet.substr(4)); + } + if (constructor_id == mtproto_api::rpc_result::ID) { + return on_packet_rpc_result(info, packet.substr(4)); + } + + TlDowncastHelper helper(constructor_id); + Status status; + bool is_mtproto_api = downcast_call(static_cast(helper), [&](auto &dummy) { + // a constructor from mtproto_api + using Type = std::decay_t; + TlParser parser(packet.substr(4)); + auto object = Type::fetch(parser); + parser.fetch_end(); + if (parser.get_error()) { + status = parser.get_status(); } else { - VLOG(mtproto) << "Got update from " << get_name() << " created in " << (Time::now() - created_at_) - << " in container " << container_id_ << " from session " << auth_data_->get_session_id() - << " with message_id " << info.message_id << ", main_message_id = " << main_message_id_ - << ", seq_no = " << info.seq_no << " and original size " << info.size; - return callback_->on_message_result_ok(0, as_buffer_slice(packet), info.size); + status = this->on_packet(info, static_cast(*object)); } + }); + if (is_mtproto_api) { + return status; } - Status status; - downcast_call(*object, OnPacket(info, this, &status)); - return status; + // It is an update... I hope. + status = auth_data_->check_update(info.message_id); + auto recheck_status = auth_data_->recheck_update(info.message_id); + if (recheck_status.is_error() && recheck_status.code() == 2) { + LOG(WARNING) << "Receive very old update from " << get_name() << " created in " << (Time::now() - created_at_) + << " in container " << container_id_ << " from session " << auth_data_->get_session_id() + << " with message_id " << info.message_id << ", main_message_id = " << main_message_id_ + << ", seq_no = " << info.seq_no << " and original size " << info.size << ": " << status << ' ' + << recheck_status; + } + if (status.is_error()) { + if (status.code() == 2) { + LOG(WARNING) << "Receive too old update from " << get_name() << " created in " << (Time::now() - created_at_) + << " in container " << container_id_ << " from session " << auth_data_->get_session_id() + << " with message_id " << info.message_id << ", main_message_id = " << main_message_id_ + << ", seq_no = " << info.seq_no << " and original size " << info.size << ": " << status; + callback_->on_session_failed(Status::Error("Receive too old update")); + return status; + } + VLOG(mtproto) << "Skip update " << info.message_id << " of size " << info.size << " with seq_no " << info.seq_no + << " from " << get_name() << " created in " << (Time::now() - created_at_) << ": " << status; + return Status::OK(); + } else { + VLOG(mtproto) << "Got update from " << get_name() << " created in " << (Time::now() - created_at_) + << " in container " << container_id_ << " from session " << auth_data_->get_session_id() + << " with message_id " << info.message_id << ", main_message_id = " << main_message_id_ + << ", seq_no = " << info.seq_no << " and original size " << info.size; + return callback_->on_update(as_buffer_slice(packet)); + } } Status SessionConnection::parse_packet(TlParser &parser) { @@ -570,6 +580,7 @@ void SessionConnection::on_message_failed(uint64 id, Status status) { on_message_failed_inner(id); } } + void SessionConnection::on_message_failed_inner(uint64 id) { auto it = service_queries_.find(id); if (it == service_queries_.end()) { @@ -651,6 +662,7 @@ bool SessionConnection::must_flush_packet() { } Status SessionConnection::before_write() { + CHECK(raw_connection_); while (must_flush_packet()) { flush_packet(); } @@ -704,12 +716,14 @@ void SessionConnection::on_read(size_t size) { SessionConnection::SessionConnection(Mode mode, unique_ptr raw_connection, AuthData *auth_data) : raw_connection_(std::move(raw_connection)), auth_data_(auth_data) { + CHECK(raw_connection_); state_ = Init; mode_ = mode; created_at_ = Time::now(); } PollableFdInfo &SessionConnection::get_poll_info() { + CHECK(raw_connection_); return raw_connection_->get_poll_info(); } @@ -863,7 +877,7 @@ void SessionConnection::flush_packet() { max_after = HTTP_MAX_AFTER; auto time_to_disconnect = min(ping_disconnect_delay() + last_pong_at_, read_disconnect_delay() + last_read_at_) - Time::now_cached(); - max_wait = min(http_max_wait(), static_cast(1000 * max(0.1, time_to_disconnect - rtt()))); + max_wait = static_cast(1000 * clamp(time_to_disconnect - rtt(), 0.1, http_max_wait())); } else if (mode_ == Mode::Http) { max_delay = HTTP_MAX_DELAY; max_after = HTTP_MAX_AFTER; @@ -880,7 +894,8 @@ void SessionConnection::flush_packet() { } } - size_t send_till = 0, send_size = 0; + size_t send_till = 0; + size_t send_size = 0; // send at most 1020 queries, of total size 2^15 // don't send anything if have no salt if (has_salt) { @@ -889,7 +904,7 @@ void SessionConnection::flush_packet() { send_till++; } } - std::vector queries; + vector queries; if (send_till == to_send_.size()) { queries = std::move(to_send_); } else if (send_till != 0) { @@ -914,14 +929,16 @@ void SessionConnection::flush_packet() { << tag("resend", to_resend_answer_.size()) << tag("cancel", to_cancel_answer_.size()) << tag("destroy_key", destroy_auth_key) << tag("auth_id", auth_data_->get_auth_key().id()); - auto cut_tail = [](auto &v, size_t size, Slice name) { + auto cut_tail = [](vector &v, size_t size, Slice name) { if (size >= v.size()) { - return std::move(v); + auto result = std::move(v); + v.clear(); + return result; } - LOG(WARNING) << "Too much ids in container: " << v.size() << " " << name; - std::decay_t res(std::make_move_iterator(v.end() - size), std::make_move_iterator(v.end())); + LOG(WARNING) << "Too much message identifiers in container " << name << ": " << v.size() << " instead of " << size; + vector result(v.end() - size, v.end()); v.resize(v.size() - size); - return res; + return result; }; // no more than 8192 ids per container.. @@ -991,7 +1008,10 @@ void SessionConnection::send_before(double tm) { } Status SessionConnection::do_flush() { - CHECK(raw_connection_); + LOG_CHECK(raw_connection_) << was_moved_ << ' ' << state_ << ' ' << static_cast(mode_) << ' ' + << connected_flag_ << ' ' << is_main_ << ' ' << need_destroy_auth_key_ << ' ' + << sent_destroy_auth_key_ << ' ' << callback_ << ' ' << (Time::now() - created_at_) << ' ' + << (Time::now() - last_read_at_); CHECK(state_ != Closed); if (state_ == Init) { TRY_STATUS(init()); diff --git a/lib/tgchat/ext/td/td/mtproto/SessionConnection.h b/lib/tgchat/ext/td/td/mtproto/SessionConnection.h index 220bd16e..413defd6 100644 --- a/lib/tgchat/ext/td/td/mtproto/SessionConnection.h +++ b/lib/tgchat/ext/td/td/mtproto/SessionConnection.h @@ -1,13 +1,13 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #pragma once +#include "td/mtproto/MtprotoQuery.h" #include "td/mtproto/PacketInfo.h" -#include "td/mtproto/Query.h" #include "td/mtproto/RawConnection.h" #include "td/utils/buffer.h" @@ -65,12 +65,17 @@ inline StringBuilder &operator<<(StringBuilder &stream, const MsgInfo &id) { << "] [seq_no:" << format::as_hex(id.seq_no) << "]"; } -class SessionConnection +class SessionConnection final : public Named , private RawConnection::Callback { public: - enum class Mode { Tcp, Http, HttpLongPoll }; + enum class Mode : int32 { Tcp, Http, HttpLongPoll }; SessionConnection(Mode mode, unique_ptr raw_connection, AuthData *auth_data); + SessionConnection(const SessionConnection &) = delete; + SessionConnection &operator=(const SessionConnection &) = delete; + SessionConnection(SessionConnection &&) = delete; + SessionConnection &operator=(SessionConnection &&) = delete; + ~SessionConnection() = default; PollableFdInfo &get_poll_info(); unique_ptr move_as_raw_connection(); @@ -87,7 +92,6 @@ class SessionConnection void set_online(bool online_flag, bool is_main); - // Callback class Callback { public: Callback() = default; @@ -109,9 +113,11 @@ class SessionConnection virtual void on_container_sent(uint64 container_id, vector msgs_id) = 0; virtual Status on_pong() = 0; + virtual Status on_update(BufferSlice packet) = 0; + virtual void on_message_ack(uint64 id) = 0; virtual Status on_message_result_ok(uint64 id, BufferSlice packet, size_t original_size) = 0; - virtual void on_message_result_error(uint64 id, int code, BufferSlice descr) = 0; + virtual void on_message_result_error(uint64 id, int code, string message) = 0; virtual void on_message_failed(uint64 id, Status status) = 0; virtual void on_message_info(uint64 id, int32 state, uint64 answer_id, int32 answer_size) = 0; @@ -130,9 +136,10 @@ class SessionConnection bool online_flag_ = false; bool is_main_ = false; + bool was_moved_ = false; int rtt() const { - return max(2, static_cast(raw_connection_->rtt_ * 1.5 + 1)); + return max(2, static_cast(raw_connection_->extra().rtt * 1.5 + 1)); } int32 read_disconnect_delay() const { @@ -151,8 +158,8 @@ class SessionConnection return online_flag_ ? rtt() : 60; } - int http_max_wait() const { - return 25 * 1000; // 25s. Longer could be closed by proxy + double http_max_wait() const { + return 25.0; // 25s. Longer could be closed by proxy } static constexpr int HTTP_MAX_AFTER = 10; // 0.01s static constexpr int HTTP_MAX_DELAY = 30; // 0.03s @@ -164,15 +171,15 @@ class SessionConnection struct ServiceQuery { enum Type { GetStateInfo, ResendAnswer } type; - std::vector message_ids; + vector message_ids; }; - std::vector to_resend_answer_; - std::vector to_cancel_answer_; - std::vector to_get_state_info_; + vector to_resend_answer_; + vector to_cancel_answer_; + vector to_get_state_info_; std::unordered_map service_queries_; // nobody cleans up this map. But it should be really small. - std::unordered_map> container_to_service_msg_; + std::unordered_map> container_to_service_msg_; double last_read_at_ = 0; double last_ping_at_ = 0; @@ -181,8 +188,8 @@ class SessionConnection uint64 last_ping_message_id_ = 0; uint64 last_ping_container_id_ = 0; - bool need_destroy_auth_key_{false}; - bool sent_destroy_auth_key_{false}; + bool need_destroy_auth_key_ = false; + bool sent_destroy_auth_key_ = false; double wakeup_at_ = 0; double flush_packet_at_ = 0; @@ -199,9 +206,7 @@ class SessionConnection unique_ptr raw_connection_; AuthData *auth_data_; SessionConnection::Callback *callback_ = nullptr; - BufferSlice *current_buffer_slice_; - - friend class OnPacket; + BufferSlice *current_buffer_slice_ = nullptr; BufferSlice as_buffer_slice(Slice packet); auto set_buffer_slice(BufferSlice *buffer_slice) TD_WARN_UNUSED_RESULT { @@ -212,12 +217,11 @@ class SessionConnection }; } - Status parse_message(TlParser &parser, MsgInfo *info, Slice *packet, bool crypto_flag = true) TD_WARN_UNUSED_RESULT; + static Status parse_message(TlParser &parser, MsgInfo *info, Slice *packet, + bool crypto_flag = true) TD_WARN_UNUSED_RESULT; Status parse_packet(TlParser &parser) TD_WARN_UNUSED_RESULT; Status on_packet_container(const MsgInfo &info, Slice packet) TD_WARN_UNUSED_RESULT; Status on_packet_rpc_result(const MsgInfo &info, Slice packet) TD_WARN_UNUSED_RESULT; - Status on_packet(const MsgInfo &info, uint64 req_msg_id, - const mtproto_api::rpc_error &rpc_error) TD_WARN_UNUSED_RESULT; template Status on_packet(const MsgInfo &info, const T &packet) TD_WARN_UNUSED_RESULT; @@ -233,7 +237,7 @@ class SessionConnection Status on_packet(const MsgInfo &info, const mtproto_api::pong &pong) TD_WARN_UNUSED_RESULT; Status on_packet(const MsgInfo &info, const mtproto_api::future_salts &salts) TD_WARN_UNUSED_RESULT; - Status on_msgs_state_info(const std::vector &ids, Slice info) TD_WARN_UNUSED_RESULT; + Status on_msgs_state_info(const vector &ids, Slice info) TD_WARN_UNUSED_RESULT; Status on_packet(const MsgInfo &info, const mtproto_api::msgs_state_info &msgs_state_info) TD_WARN_UNUSED_RESULT; Status on_packet(const MsgInfo &info, const mtproto_api::msgs_all_info &msgs_all_info) TD_WARN_UNUSED_RESULT; Status on_packet(const MsgInfo &info, const mtproto_api::msg_detailed_info &msg_detailed_info) TD_WARN_UNUSED_RESULT; @@ -264,10 +268,10 @@ class SessionConnection Status init() TD_WARN_UNUSED_RESULT; Status do_flush() TD_WARN_UNUSED_RESULT; - Status before_write() override TD_WARN_UNUSED_RESULT; - Status on_raw_packet(const PacketInfo &info, BufferSlice packet) override; - Status on_quick_ack(uint64 quick_ack_token) override; - void on_read(size_t size) override; + Status before_write() final TD_WARN_UNUSED_RESULT; + Status on_raw_packet(const PacketInfo &info, BufferSlice packet) final; + Status on_quick_ack(uint64 quick_ack_token) final; + void on_read(size_t size) final; }; } // namespace mtproto diff --git a/lib/tgchat/ext/td/td/mtproto/TcpTransport.cpp b/lib/tgchat/ext/td/td/mtproto/TcpTransport.cpp index 93452612..2570403d 100644 --- a/lib/tgchat/ext/td/td/mtproto/TcpTransport.cpp +++ b/lib/tgchat/ext/td/td/mtproto/TcpTransport.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -63,7 +63,7 @@ void IntermediateTransport::write_prepare_inplace(BufferWriter *message, bool qu size_t append_size = 0; if (with_padding()) { append_size = Random::secure_uint32() % 16; - MutableSlice append = message->prepare_append().truncate(append_size); + MutableSlice append = message->prepare_append().substr(0, append_size); CHECK(append.size() == append_size); Random::secure_bytes(append); message->confirm_append(append.size()); @@ -272,8 +272,8 @@ void ObfuscatedTransport::do_write_tls(BufferBuilder &&builder) { do_write(builder.extract()); } -void ObfuscatedTransport::do_write(BufferSlice &&slice) { - output_->append(std::move(slice)); +void ObfuscatedTransport::do_write(BufferSlice &&message) { + output_->append(std::move(message)); } } // namespace tcp diff --git a/lib/tgchat/ext/td/td/mtproto/TcpTransport.h b/lib/tgchat/ext/td/td/mtproto/TcpTransport.h index 88d81da9..9e392ae7 100644 --- a/lib/tgchat/ext/td/td/mtproto/TcpTransport.h +++ b/lib/tgchat/ext/td/td/mtproto/TcpTransport.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -49,24 +49,24 @@ class ITransport { virtual ~ITransport() = default; }; -class AbridgedTransport : public ITransport { +class AbridgedTransport final : public ITransport { public: - size_t read_from_stream(ChainBufferReader *stream, BufferSlice *message, uint32 *quick_ack) override; - void write_prepare_inplace(BufferWriter *message, bool quick_ack) override; - void init_output_stream(ChainBufferWriter *stream) override; - bool support_quick_ack() const override { + size_t read_from_stream(ChainBufferReader *stream, BufferSlice *message, uint32 *quick_ack) final; + void write_prepare_inplace(BufferWriter *message, bool quick_ack) final; + void init_output_stream(ChainBufferWriter *stream) final; + bool support_quick_ack() const final { return false; } }; -class IntermediateTransport : ITransport { +class IntermediateTransport final : public ITransport { public: explicit IntermediateTransport(bool with_padding) : with_padding_(with_padding) { } - size_t read_from_stream(ChainBufferReader *stream, BufferSlice *message, uint32 *quick_ack) override; - void write_prepare_inplace(BufferWriter *message, bool quick_ack) override; - void init_output_stream(ChainBufferWriter *stream) override; - bool support_quick_ack() const override { + size_t read_from_stream(ChainBufferReader *stream, BufferSlice *message, uint32 *quick_ack) final; + void write_prepare_inplace(BufferWriter *message, bool quick_ack) final; + void init_output_stream(ChainBufferWriter *stream) final; + bool support_quick_ack() const final { return true; } bool with_padding() const { @@ -79,78 +79,78 @@ class IntermediateTransport : ITransport { using TransportImpl = IntermediateTransport; -class OldTransport : public IStreamTransport { +class OldTransport final : public IStreamTransport { public: OldTransport() = default; - Result read_next(BufferSlice *message, uint32 *quick_ack) override TD_WARN_UNUSED_RESULT { + Result read_next(BufferSlice *message, uint32 *quick_ack) final TD_WARN_UNUSED_RESULT { return impl_.read_from_stream(input_, message, quick_ack); } - bool support_quick_ack() const override { + bool support_quick_ack() const final { return impl_.support_quick_ack(); } - void write(BufferWriter &&message, bool quick_ack) override { + void write(BufferWriter &&message, bool quick_ack) final { impl_.write_prepare_inplace(&message, quick_ack); output_->append(message.as_buffer_slice()); } - void init(ChainBufferReader *input, ChainBufferWriter *output) override { + void init(ChainBufferReader *input, ChainBufferWriter *output) final { input_ = input; output_ = output; impl_.init_output_stream(output_); } - bool can_read() const override { + bool can_read() const final { return true; } - bool can_write() const override { + bool can_write() const final { return true; } - size_t max_prepend_size() const override { + size_t max_prepend_size() const final { return 4; } - size_t max_append_size() const override { + size_t max_append_size() const final { return 15; } - TransportType get_type() const override { + TransportType get_type() const final { return TransportType{TransportType::Tcp, 0, ProxySecret()}; } - bool use_random_padding() const override { + bool use_random_padding() const final { return false; } private: TransportImpl impl_{false}; - ChainBufferReader *input_; - ChainBufferWriter *output_; + ChainBufferReader *input_{nullptr}; + ChainBufferWriter *output_{nullptr}; }; -class ObfuscatedTransport : public IStreamTransport { +class ObfuscatedTransport final : public IStreamTransport { public: - ObfuscatedTransport(int16 dc_id, const ProxySecret &secret) - : dc_id_(dc_id), secret_(secret), impl_(secret_.use_random_padding()) { + ObfuscatedTransport(int16 dc_id, ProxySecret secret) + : dc_id_(dc_id), secret_(std::move(secret)), impl_(secret_.use_random_padding()) { } - Result read_next(BufferSlice *message, uint32 *quick_ack) override TD_WARN_UNUSED_RESULT; + Result read_next(BufferSlice *message, uint32 *quick_ack) final TD_WARN_UNUSED_RESULT; - bool support_quick_ack() const override { + bool support_quick_ack() const final { return impl_.support_quick_ack(); } - void write(BufferWriter &&message, bool quick_ack) override; + void write(BufferWriter &&message, bool quick_ack) final; - void init(ChainBufferReader *input, ChainBufferWriter *output) override; + void init(ChainBufferReader *input, ChainBufferWriter *output) final; - bool can_read() const override { + bool can_read() const final { return true; } - bool can_write() const override { + bool can_write() const final { return true; } - size_t max_prepend_size() const override { + size_t max_prepend_size() const final { size_t res = 4; if (secret_.emulate_tls()) { res += 5; @@ -165,14 +165,15 @@ class ObfuscatedTransport : public IStreamTransport { return res; } - size_t max_append_size() const override { + size_t max_append_size() const final { return 15; } - TransportType get_type() const override { + TransportType get_type() const final { return TransportType{TransportType::ObfuscatedTcp, dc_id_, secret_}; } - bool use_random_padding() const override { + + bool use_random_padding() const final { return secret_.use_random_padding(); } @@ -194,7 +195,7 @@ class ObfuscatedTransport : public IStreamTransport { // The other problem is that first 56 bytes must be sent unencrypted. UInt256 output_key_; AesCtrState output_state_; - ChainBufferWriter *output_; + ChainBufferWriter *output_ = nullptr; void do_write_tls(BufferWriter &&message); void do_write_tls(BufferBuilder &&builder); diff --git a/lib/tgchat/ext/td/td/mtproto/TlsInit.cpp b/lib/tgchat/ext/td/td/mtproto/TlsInit.cpp index 4efd153d..a41dd1a3 100644 --- a/lib/tgchat/ext/td/td/mtproto/TlsInit.cpp +++ b/lib/tgchat/ext/td/td/mtproto/TlsInit.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -12,8 +12,8 @@ #include "td/utils/BigNum.h" #include "td/utils/common.h" #include "td/utils/crypto.h" -#include "td/utils/logging.h" #include "td/utils/Random.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Span.h" #include "td/utils/Time.h" @@ -99,9 +99,13 @@ class TlsHello { Op::zero(32), Op::string("\x20"), Op::random(32), - Op::string("\x00\x34\x13\x03\x13\x01\x13\x02\xc0\x2c\xc0\x2b\xc0\x24\xc0\x23\xc0\x0a\xc0\x09\xcc\xa9\xc0\x30" - "\xc0\x2f\xc0\x28\xc0\x27\xc0\x14\xc0\x13\xcc\xa8\x00\x9d\x00\x9c\x00\x3d\x00\x3c\x00\x35\x00\x2f" - "\xc0\x08\xc0\x12\x00\x0a\x01\x00\x01\x7f\xff\x01\x00\x01\x00\x00\x00"), + Op::string("\x00\x36"), + Op::grease(0), + Op::string("\x13\x01\x13\x02\x13\x03\xc0\x2c\xc0\x2b\xcc\xa9\xc0\x30\xc0\x2f\xcc\xa8\xc0\x24\xc0\x23\xc0\x0a" + "\xc0\x09\xc0\x28\xc0\x27\xc0\x14\xc0\x13\x00\x9d\x00\x9c\x00\x3d\x00\x3c\x00\x35\x00\x2f\xc0\x08" + "\xc0\x12\x00\x0a\x01\x00\x01\x7d"), + Op::grease(2), + Op::string("\x00\x00\x00\x00"), Op::begin_scope(), Op::begin_scope(), Op::string("\x00"), @@ -110,15 +114,20 @@ class TlsHello { Op::end_scope(), Op::end_scope(), Op::end_scope(), - Op::string("\x00\x17\x00\x00\x00\x0d\x00\x18\x00\x16\x04\x03\x08\x04\x04\x01\x05\x03\x02\x03\x08\x05\x08\x05" - "\x05\x01\x08\x06\x06\x01\x02\x01\x00\x05\x00\x05\x01\x00\x00\x00\x00\x33\x74\x00\x00\x00\x12\x00" - "\x00\x00\x10\x00\x30\x00\x2e\x02\x68\x32\x05\x68\x32\x2d\x31\x36\x05\x68\x32\x2d\x31\x35\x05\x68" - "\x32\x2d\x31\x34\x08\x73\x70\x64\x79\x2f\x33\x2e\x31\x06\x73\x70\x64\x79\x2f\x33\x08\x68\x74\x74" - "\x70\x2f\x31\x2e\x31\x00\x0b\x00\x02\x01\x00\x00\x33\x00\x26\x00\x24\x00\x1d\x00\x20"), + Op::string("\x00\x17\x00\x00\xff\x01\x00\x01\x00\x00\x0a\x00\x0c\x00\x0a"), + Op::grease(4), + Op::string("\x00\x1d\x00\x17\x00\x18\x00\x19\x00\x0b\x00\x02\x01\x00\x00\x10\x00\x0e\x00\x0c\x02\x68\x32\x08" + "\x68\x74\x74\x70\x2f\x31\x2e\x31\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\x0d\x00\x18\x00\x16\x04" + "\x03\x08\x04\x04\x01\x05\x03\x02\x03\x08\x05\x08\x05\x05\x01\x08\x06\x06\x01\x02\x01\x00\x12\x00" + "\x00\x00\x33\x00\x2b\x00\x29"), + Op::grease(4), + Op::string("\x00\x01\x00\x00\x1d\x00\x20"), Op::key(), - Op::string("\x00\x2d\x00\x02\x01\x01\x00\x2b\x00\x09\x08\x03\x04\x03\x03\x03\x02\x03\x01\x00\x0a\x00\x0a\x00" - "\x08\x00\x1d\x00\x17\x00\x18\x00\x19\x00\x15")}; - res.grease_size_ = 0; + Op::string("\x00\x2d\x00\x02\x01\x01\x00\x2b\x00\x0b\x0a"), + Op::grease(6), + Op::string("\x03\x04\x03\x03\x03\x02\x03\x01"), + Op::grease(3), + Op::string("\x00\x01\x00\x00\x15")}; #else res.ops_ = { Op::string("\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03"), @@ -153,7 +162,6 @@ class TlsHello { Op::string("\x03\x04\x03\x03\x03\x02\x03\x01\x00\x1b\x00\x03\x02\x00\x02"), Op::grease(3), Op::string("\x00\x01\x00\x00\x15")}; - res.grease_size_ = 7; #endif return res; }(); @@ -170,7 +178,7 @@ class TlsHello { private: std::vector ops_; - size_t grease_size_; + size_t grease_size_ = 7; }; class TlsHelloContext { diff --git a/lib/tgchat/ext/td/td/mtproto/TlsInit.h b/lib/tgchat/ext/td/td/mtproto/TlsInit.h index b93f76c2..c9a0fa4a 100644 --- a/lib/tgchat/ext/td/td/mtproto/TlsInit.h +++ b/lib/tgchat/ext/td/td/mtproto/TlsInit.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -23,7 +23,7 @@ class Grease { static void init(MutableSlice res); }; -class TlsInit : public TransparentProxy { +class TlsInit final : public TransparentProxy { public: TlsInit(SocketFd socket_fd, string domain, string secret, unique_ptr callback, ActorShared<> parent, double server_time_difference) @@ -43,7 +43,7 @@ class TlsInit : public TransparentProxy { void send_hello(); Status wait_hello_response(); - Status loop_impl() override; + Status loop_impl() final; }; } // namespace mtproto diff --git a/lib/tgchat/ext/td/td/mtproto/TlsReaderByteFlow.cpp b/lib/tgchat/ext/td/td/mtproto/TlsReaderByteFlow.cpp index d7fd8594..33a5f117 100644 --- a/lib/tgchat/ext/td/td/mtproto/TlsReaderByteFlow.cpp +++ b/lib/tgchat/ext/td/td/mtproto/TlsReaderByteFlow.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/mtproto/TlsReaderByteFlow.h b/lib/tgchat/ext/td/td/mtproto/TlsReaderByteFlow.h index e0570483..e8575b87 100644 --- a/lib/tgchat/ext/td/td/mtproto/TlsReaderByteFlow.h +++ b/lib/tgchat/ext/td/td/mtproto/TlsReaderByteFlow.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,7 +13,7 @@ namespace mtproto { class TlsReaderByteFlow final : public ByteFlowBase { public: - bool loop() override; + bool loop() final; }; } // namespace mtproto diff --git a/lib/tgchat/ext/td/td/mtproto/Transport.cpp b/lib/tgchat/ext/td/td/mtproto/Transport.cpp index 62db5190..d429a570 100644 --- a/lib/tgchat/ext/td/td/mtproto/Transport.cpp +++ b/lib/tgchat/ext/td/td/mtproto/Transport.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,6 +15,7 @@ #include "td/utils/logging.h" #include "td/utils/misc.h" #include "td/utils/Random.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Status.h" #include @@ -127,7 +128,7 @@ struct NoCryptoHeader { #endif #pragma pack(pop) -// mtproto v1.0 +// MTProto v1.0 template std::pair Transport::calc_message_ack_and_key(const HeaderT &head, size_t data_size) { Slice part(head.encrypt_begin(), head.data + data_size); @@ -143,7 +144,7 @@ size_t Transport::calc_crypto_size(size_t data_size) { return raw_size + ((enc_size + data_size + 15) & ~15); } -// mtproto v2.0 +// MTProto v2.0 std::pair Transport::calc_message_key2(const AuthKey &auth_key, int X, Slice to_encrypt) { // msg_key_large = SHA256 (substr (auth_key, 88+x, 32) + plaintext + random_padding); Sha256State state; @@ -206,7 +207,7 @@ size_t Transport::calc_no_crypto_size(size_t data_size) { Status Transport::read_no_crypto(MutableSlice message, PacketInfo *info, MutableSlice *data) { if (message.size() < sizeof(NoCryptoHeader)) { - return Status::Error(PSLICE() << "Invalid mtproto message: too small [message.size() = " << message.size() + return Status::Error(PSLICE() << "Invalid MTProto message: too small [message.size() = " << message.size() << "] < [sizeof(NoCryptoHeader) = " << sizeof(NoCryptoHeader) << "]"); } size_t data_size = message.size() - sizeof(NoCryptoHeader); @@ -219,21 +220,17 @@ template Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &auth_key, HeaderT **header_ptr, PrefixT **prefix_ptr, MutableSlice *data, PacketInfo *info) { if (message.size() < sizeof(HeaderT)) { - return Status::Error(PSLICE() << "Invalid mtproto message: too small [message.size() = " << message.size() + return Status::Error(PSLICE() << "Invalid MTProto message: too small [message.size() = " << message.size() << "] < [sizeof(HeaderT) = " << sizeof(HeaderT) << "]"); } //FIXME: rewrite without reinterpret cast auto *header = reinterpret_cast(message.begin()); *header_ptr = header; auto to_decrypt = MutableSlice(header->encrypt_begin(), message.uend()); - to_decrypt = to_decrypt.truncate(to_decrypt.size() & ~15); - if (to_decrypt.size() % 16 != 0) { - return Status::Error(PSLICE() << "Invalid mtproto message: size of encrypted part is not multiple of 16 [size = " - << to_decrypt.size() << "]"); - } + to_decrypt.remove_suffix(to_decrypt.size() & 15); if (header->auth_key_id != auth_key.id()) { - return Status::Error(PSLICE() << "Invalid mtproto message: auth_key_id mismatch [found = " + return Status::Error(PSLICE() << "Invalid MTProto message: auth_key_id mismatch [found = " << format::as_hex(header->auth_key_id) << "] [expected = " << format::as_hex(auth_key.id()) << "]"); } @@ -256,50 +253,49 @@ Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &a auto *prefix = reinterpret_cast(header->data); *prefix_ptr = prefix; size_t data_size = prefix->message_data_length + sizeof(PrefixT); - bool is_length_ok = true; + bool is_length_bad = false; UInt128 real_message_key; if (info->version == 1) { - is_length_ok &= !info->check_mod4 || prefix->message_data_length % 4 == 0; + is_length_bad |= info->check_mod4 && prefix->message_data_length % 4 != 0; auto expected_size = calc_crypto_size(data_size); - is_length_ok = (is_length_ok & (expected_size == message.size())) != 0; - auto check_size = data_size * is_length_ok + tail_size * (1 - is_length_ok); + is_length_bad |= expected_size != message.size(); + auto check_size = data_size * (1 - is_length_bad) + tail_size * is_length_bad; std::tie(info->message_ack, real_message_key) = calc_message_ack_and_key(*header, check_size); } else { std::tie(info->message_ack, real_message_key) = calc_message_key2(auth_key, X, to_decrypt); } - bool is_key_ok = true; + int is_key_bad = false; for (size_t i = 0; i < sizeof(real_message_key.raw); i++) { - is_key_ok &= real_message_key.raw[i] == header->message_key.raw[i]; + is_key_bad |= real_message_key.raw[i] ^ header->message_key.raw[i]; } - - if (!is_key_ok) { - return Status::Error(PSLICE() << "Invalid mtproto message: message_key mismatch [found = " + if (is_key_bad != 0) { + return Status::Error(PSLICE() << "Invalid MTProto message: message_key mismatch [found = " << format::as_hex_dump(header->message_key) << "] [expected = " << format::as_hex_dump(real_message_key) << "]"); } if (info->version == 2) { if (info->check_mod4 && prefix->message_data_length % 4 != 0) { - return Status::Error(PSLICE() << "Invalid mtproto message: invalid length (not divisible by four)" + return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (not divisible by four)" << tag("total_size", message.size()) << tag("message_data_length", prefix->message_data_length)); } if (tail_size - sizeof(PrefixT) < prefix->message_data_length) { - return Status::Error(PSLICE() << "Invalid mtproto message: invalid length (message_data_length is too big)" + return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (message_data_length is too big)" << tag("total_size", message.size()) << tag("message_data_length", prefix->message_data_length)); } size_t pad_size = tail_size - data_size; if (pad_size < 12 || pad_size > 1024) { - return Status::Error(PSLICE() << "Invalid mtproto message: invalid length (invalid padding length)" + return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (invalid padding length)" << tag("padding_size", pad_size) << tag("total_size", message.size()) << tag("message_data_length", prefix->message_data_length)); } } else { - if (!is_length_ok) { - return Status::Error(PSLICE() << "Invalid mtproto message: invalid length " << tag("total_size", message.size()) + if (is_length_bad) { + return Status::Error(PSLICE() << "Invalid MTProto message: invalid length " << tag("total_size", message.size()) << tag("message_data_length", prefix->message_data_length)); } } @@ -431,7 +427,7 @@ size_t Transport::write_e2e_crypto(const Storer &storer, const AuthKey &auth_key Result Transport::read_auth_key_id(Slice message) { if (message.size() < 8) { - return Status::Error(PSLICE() << "Invalid mtproto message: smaller than 8 bytes [size = " << message.size() << "]"); + return Status::Error(PSLICE() << "Invalid MTProto message: smaller than 8 bytes [size = " << message.size() << "]"); } return as(message.begin()); } @@ -439,7 +435,7 @@ Result Transport::read_auth_key_id(Slice message) { Result Transport::read(MutableSlice message, const AuthKey &auth_key, PacketInfo *info) { if (message.size() < 12) { if (message.size() < 4) { - return Status::Error(PSLICE() << "Invalid mtproto message: smaller than 4 bytes [size = " << message.size() + return Status::Error(PSLICE() << "Invalid MTProto message: smaller than 4 bytes [size = " << message.size() << "]"); } @@ -462,7 +458,7 @@ Result Transport::read(MutableSlice message, const AuthKe TRY_STATUS(read_no_crypto(message, info, &data)); } else { if (auth_key.empty()) { - return Status::Error("Failed to decrypt mtproto message: auth key is empty"); + return Status::Error("Failed to decrypt MTProto message: auth key is empty"); } TRY_STATUS(read_crypto(message, auth_key, info, &data)); } diff --git a/lib/tgchat/ext/td/td/mtproto/Transport.h b/lib/tgchat/ext/td/td/mtproto/Transport.h index 0fd0dbec..068b46f8 100644 --- a/lib/tgchat/ext/td/td/mtproto/Transport.h +++ b/lib/tgchat/ext/td/td/mtproto/Transport.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -80,10 +80,10 @@ class Transport { static Result read_auth_key_id(Slice message); - // Reads mtproto packet from [message] and saves into [data]. + // Reads MTProto packet from [message] and saves it into [data]. // If message is encrypted, [auth_key] is used. // Decryption and unpacking is made inplace, so [data] will be subslice of [message]. - // Returns size of mtproto packet. + // Returns size of MTProto packet. // If dest.size() >= size, the packet is also written into [dest]. // If auth_key is nonempty, encryption will be used. static Result read(MutableSlice message, const AuthKey &auth_key, PacketInfo *info) TD_WARN_UNUSED_RESULT; @@ -91,12 +91,12 @@ class Transport { static size_t write(const Storer &storer, const AuthKey &auth_key, PacketInfo *info, MutableSlice dest = MutableSlice()); + static std::pair calc_message_key2(const AuthKey &auth_key, int X, Slice to_encrypt); + private: template static std::pair calc_message_ack_and_key(const HeaderT &head, size_t data_size); - static std::pair calc_message_key2(const AuthKey &auth_key, int X, Slice to_encrypt); - template static size_t calc_crypto_size(size_t data_size); diff --git a/lib/tgchat/ext/td/td/mtproto/TransportType.h b/lib/tgchat/ext/td/td/mtproto/TransportType.h index 19987ebe..596622d1 100644 --- a/lib/tgchat/ext/td/td/mtproto/TransportType.h +++ b/lib/tgchat/ext/td/td/mtproto/TransportType.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/mtproto/utils.cpp b/lib/tgchat/ext/td/td/mtproto/utils.cpp index 13e981ae..50bf5ecf 100644 --- a/lib/tgchat/ext/td/td/mtproto/utils.cpp +++ b/lib/tgchat/ext/td/td/mtproto/utils.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,6 +9,7 @@ #include "td/mtproto/mtproto_api.h" namespace td { +namespace mtproto { TLStorer create_storer(const mtproto_api::Function &function) { return TLStorer(function); @@ -18,4 +19,5 @@ TLObjectStorer create_storer(const mtproto_api::Object &obj return TLObjectStorer(object); } +} // namespace mtproto } // namespace td diff --git a/lib/tgchat/ext/td/td/mtproto/utils.h b/lib/tgchat/ext/td/td/mtproto/utils.h index 4e5e3ae7..445943fa 100644 --- a/lib/tgchat/ext/td/td/mtproto/utils.h +++ b/lib/tgchat/ext/td/td/mtproto/utils.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -18,7 +18,7 @@ template using TLStorer = DefaultStorer; template -class TLObjectStorer : public Storer { +class TLObjectStorer final : public Storer { mutable size_t size_ = std::numeric_limits::max(); const T &object_; @@ -26,7 +26,7 @@ class TLObjectStorer : public Storer { explicit TLObjectStorer(const T &object) : object_(object) { } - size_t size() const override { + size_t size() const final { if (size_ == std::numeric_limits::max()) { TlStorerCalcLength storer; storer.store_binary(object_.get_id()); @@ -35,7 +35,7 @@ class TLObjectStorer : public Storer { } return size_; } - size_t store(uint8 *ptr) const override { + size_t store(uint8 *ptr) const final { TlStorerUnsafe storer(ptr); storer.store_binary(object_.get_id()); object_.store(storer); @@ -48,8 +48,11 @@ class Object; class Function; } // namespace mtproto_api +namespace mtproto { + TLStorer create_storer(const mtproto_api::Function &function); TLObjectStorer create_storer(const mtproto_api::Object &object); +} // namespace mtproto } // namespace td diff --git a/lib/tgchat/ext/td/td/telegram/AccessRights.h b/lib/tgchat/ext/td/td/telegram/AccessRights.h index bc6fe813..aa316352 100644 --- a/lib/tgchat/ext/td/td/telegram/AccessRights.h +++ b/lib/tgchat/ext/td/td/telegram/AccessRights.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/telegram/Account.cpp b/lib/tgchat/ext/td/td/telegram/Account.cpp new file mode 100644 index 00000000..ed83b2a6 --- /dev/null +++ b/lib/tgchat/ext/td/td/telegram/Account.cpp @@ -0,0 +1,371 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/Account.h" + +#include "td/telegram/ContactsManager.h" +#include "td/telegram/DeviceTokenManager.h" +#include "td/telegram/Global.h" +#include "td/telegram/net/NetQueryCreator.h" +#include "td/telegram/Td.h" +#include "td/telegram/telegram_api.h" +#include "td/telegram/UserId.h" + +#include "td/actor/actor.h" + +#include "td/utils/algorithm.h" +#include "td/utils/base64.h" +#include "td/utils/buffer.h" +#include "td/utils/logging.h" +#include "td/utils/misc.h" +#include "td/utils/Slice.h" +#include "td/utils/Status.h" + +#include + +namespace td { + +static td_api::object_ptr convert_authorization_object( + tl_object_ptr &&authorization) { + CHECK(authorization != nullptr); + return td_api::make_object( + authorization->hash_, authorization->current_, authorization->password_pending_, authorization->api_id_, + authorization->app_name_, authorization->app_version_, authorization->official_app_, authorization->device_model_, + authorization->platform_, authorization->system_version_, authorization->date_created_, + authorization->date_active_, authorization->ip_, authorization->country_, authorization->region_); +} + +class SetAccountTtlQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit SetAccountTtlQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(int32 account_ttl) { + send_query(G()->net_query_creator().create( + telegram_api::account_setAccountTTL(make_tl_object(account_ttl)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.move_as_ok(); + if (!result) { + return on_error(Status::Error(500, "Internal Server Error: failed to set account TTL")); + } + + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class GetAccountTtlQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit GetAccountTtlQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send() { + send_query(G()->net_query_creator().create(telegram_api::account_getAccountTTL())); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for GetAccountTtlQuery: " << to_string(ptr); + + promise_.set_value(std::move(ptr->days_)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class AcceptLoginTokenQuery final : public Td::ResultHandler { + Promise> promise_; + + public: + explicit AcceptLoginTokenQuery(Promise> &&promise) + : promise_(std::move(promise)) { + } + + void send(const string &login_token) { + send_query(G()->net_query_creator().create(telegram_api::auth_acceptLoginToken(BufferSlice(login_token)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + LOG(DEBUG) << "Receive result for AcceptLoginTokenQuery: " << to_string(result_ptr.ok()); + promise_.set_value(convert_authorization_object(result_ptr.move_as_ok())); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class GetAuthorizationsQuery final : public Td::ResultHandler { + Promise> promise_; + + public: + explicit GetAuthorizationsQuery(Promise> &&promise) + : promise_(std::move(promise)) { + } + + void send() { + send_query(G()->net_query_creator().create(telegram_api::account_getAuthorizations())); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for GetAuthorizationsQuery: " << to_string(ptr); + + auto results = + td_api::make_object(transform(std::move(ptr->authorizations_), convert_authorization_object)); + std::sort(results->sessions_.begin(), results->sessions_.end(), + [](const td_api::object_ptr &lhs, const td_api::object_ptr &rhs) { + if (lhs->is_current_ != rhs->is_current_) { + return lhs->is_current_; + } + if (lhs->is_password_pending_ != rhs->is_password_pending_) { + return lhs->is_password_pending_; + } + return lhs->last_active_date_ > rhs->last_active_date_; + }); + + promise_.set_value(std::move(results)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class ResetAuthorizationQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit ResetAuthorizationQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(int64 authorization_id) { + send_query(G()->net_query_creator().create(telegram_api::account_resetAuthorization(authorization_id))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.move_as_ok(); + LOG_IF(WARNING, !result) << "Failed to terminate session"; + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class ResetAuthorizationsQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit ResetAuthorizationsQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send() { + send_query(G()->net_query_creator().create(telegram_api::auth_resetAuthorizations())); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.move_as_ok(); + LOG_IF(WARNING, !result) << "Failed to terminate all sessions"; + send_closure(td_->device_token_manager_, &DeviceTokenManager::reregister_device); + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class GetWebAuthorizationsQuery final : public Td::ResultHandler { + Promise> promise_; + + public: + explicit GetWebAuthorizationsQuery(Promise> &&promise) + : promise_(std::move(promise)) { + } + + void send() { + send_query(G()->net_query_creator().create(telegram_api::account_getWebAuthorizations())); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for GetWebAuthorizationsQuery: " << to_string(ptr); + + td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetWebAuthorizationsQuery"); + + auto results = td_api::make_object(); + results->websites_.reserve(ptr->authorizations_.size()); + for (auto &authorization : ptr->authorizations_) { + CHECK(authorization != nullptr); + UserId bot_user_id(authorization->bot_id_); + if (!bot_user_id.is_valid()) { + LOG(ERROR) << "Receive invalid bot " << bot_user_id; + bot_user_id = UserId(); + } + + results->websites_.push_back(td_api::make_object( + authorization->hash_, authorization->domain_, + td_->contacts_manager_->get_user_id_object(bot_user_id, "GetWebAuthorizationsQuery"), authorization->browser_, + authorization->platform_, authorization->date_created_, authorization->date_active_, authorization->ip_, + authorization->region_)); + } + + promise_.set_value(std::move(results)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class ResetWebAuthorizationQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit ResetWebAuthorizationQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(int64 hash) { + send_query(G()->net_query_creator().create(telegram_api::account_resetWebAuthorization(hash))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.move_as_ok(); + LOG_IF(WARNING, !result) << "Failed to disconnect website"; + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class ResetWebAuthorizationsQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit ResetWebAuthorizationsQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send() { + send_query(G()->net_query_creator().create(telegram_api::account_resetWebAuthorizations())); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.move_as_ok(); + LOG_IF(WARNING, !result) << "Failed to disconnect all websites"; + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +void set_account_ttl(Td *td, int32 account_ttl, Promise &&promise) { + td->create_handler(std::move(promise))->send(account_ttl); +} + +void get_account_ttl(Td *td, Promise &&promise) { + td->create_handler(std::move(promise))->send(); +} + +void confirm_qr_code_authentication(Td *td, const string &link, + Promise> &&promise) { + Slice prefix("tg://login?token="); + if (!begins_with(to_lower(link), prefix)) { + return promise.set_error(Status::Error(400, "AUTH_TOKEN_INVALID")); + } + auto r_token = base64url_decode(Slice(link).substr(prefix.size())); + if (r_token.is_error()) { + return promise.set_error(Status::Error(400, "AUTH_TOKEN_INVALID")); + } + td->create_handler(std::move(promise))->send(r_token.ok()); +} + +void get_active_sessions(Td *td, Promise> &&promise) { + td->create_handler(std::move(promise))->send(); +} + +void terminate_session(Td *td, int64 session_id, Promise &&promise) { + td->create_handler(std::move(promise))->send(session_id); +} + +void terminate_all_other_sessions(Td *td, Promise &&promise) { + td->create_handler(std::move(promise))->send(); +} + +void get_connected_websites(Td *td, Promise> &&promise) { + td->create_handler(std::move(promise))->send(); +} + +void disconnect_website(Td *td, int64 website_id, Promise &&promise) { + td->create_handler(std::move(promise))->send(website_id); +} + +void disconnect_all_websites(Td *td, Promise &&promise) { + td->create_handler(std::move(promise))->send(); +} + +} // namespace td diff --git a/lib/tgchat/ext/td/td/telegram/Account.h b/lib/tgchat/ext/td/td/telegram/Account.h new file mode 100644 index 00000000..6ac45d64 --- /dev/null +++ b/lib/tgchat/ext/td/td/telegram/Account.h @@ -0,0 +1,37 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/td_api.h" + +#include "td/actor/PromiseFuture.h" + +#include "td/utils/common.h" + +namespace td { + +class Td; + +void set_account_ttl(Td *td, int32 account_ttl, Promise &&promise); + +void get_account_ttl(Td *td, Promise &&promise); + +void confirm_qr_code_authentication(Td *td, const string &link, Promise> &&promise); + +void get_active_sessions(Td *td, Promise> &&promise); + +void terminate_session(Td *td, int64 session_id, Promise &&promise); + +void terminate_all_other_sessions(Td *td, Promise &&promise); + +void get_connected_websites(Td *td, Promise> &&promise); + +void disconnect_website(Td *td, int64 website_id, Promise &&promise); + +void disconnect_all_websites(Td *td, Promise &&promise); + +} // namespace td diff --git a/lib/tgchat/ext/td/td/telegram/AffectedHistory.h b/lib/tgchat/ext/td/td/telegram/AffectedHistory.h new file mode 100644 index 00000000..fd601e55 --- /dev/null +++ b/lib/tgchat/ext/td/td/telegram/AffectedHistory.h @@ -0,0 +1,33 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/telegram_api.h" + +#include "td/utils/common.h" + +namespace td { + +struct AffectedHistory { + int32 pts_; + int32 pts_count_; + bool is_final_; + + explicit AffectedHistory(tl_object_ptr &&affected_history) + : pts_(affected_history->pts_) + , pts_count_(affected_history->pts_count_) + , is_final_(affected_history->offset_ <= 0) { + } + + explicit AffectedHistory(tl_object_ptr &&affected_history) + : pts_(affected_history->pts_) + , pts_count_(affected_history->pts_count_) + , is_final_(affected_history->offset_ <= 0) { + } +}; + +} // namespace td diff --git a/lib/tgchat/ext/td/td/telegram/AnimationsManager.cpp b/lib/tgchat/ext/td/td/telegram/AnimationsManager.cpp index c42e9485..33af53ef 100644 --- a/lib/tgchat/ext/td/td/telegram/AnimationsManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/AnimationsManager.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -17,18 +17,18 @@ #include "td/telegram/Global.h" #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/misc.h" -#include "td/telegram/SecretChatActor.h" -#include "td/telegram/Td.h" -#include "td/telegram/TdDb.h" - #include "td/telegram/secret_api.h" +#include "td/telegram/Td.h" #include "td/telegram/td_api.h" +#include "td/telegram/TdDb.h" +#include "td/telegram/TdParameters.h" #include "td/telegram/telegram_api.h" -#include "td/actor/PromiseFuture.h" - #include "td/db/SqliteKeyValueAsync.h" +#include "td/actor/PromiseFuture.h" + +#include "td/utils/algorithm.h" #include "td/utils/logging.h" #include "td/utils/misc.h" #include "td/utils/Random.h" @@ -39,35 +39,34 @@ namespace td { -class GetSavedGifsQuery : public Td::ResultHandler { +class GetSavedGifsQuery final : public Td::ResultHandler { bool is_repair_ = false; public: - void send(bool is_repair, int32 hash) { + void send(bool is_repair, int64 hash) { is_repair_ = is_repair; - LOG(INFO) << "Send get saved animations request with hash = " << hash; send_query(G()->net_query_creator().create(telegram_api::messages_getSavedGifs(hash))); } - void on_result(uint64 id, BufferSlice packet) override { + void on_result(BufferSlice packet) final { auto result_ptr = fetch_result(packet); if (result_ptr.is_error()) { - return on_error(id, result_ptr.move_as_error()); + return on_error(result_ptr.move_as_error()); } auto ptr = result_ptr.move_as_ok(); - td->animations_manager_->on_get_saved_animations(is_repair_, std::move(ptr)); + td_->animations_manager_->on_get_saved_animations(is_repair_, std::move(ptr)); } - void on_error(uint64 id, Status status) override { + void on_error(Status status) final { if (!G()->is_expected_error(status)) { LOG(ERROR) << "Receive error for get saved animations: " << status; } - td->animations_manager_->on_get_saved_animations_failed(is_repair_, std::move(status)); + td_->animations_manager_->on_get_saved_animations_failed(is_repair_, std::move(status)); } }; -class SaveGifQuery : public Td::ResultHandler { +class SaveGifQuery final : public Td::ResultHandler { FileId file_id_; string file_reference_; bool unsave_ = false; @@ -87,26 +86,26 @@ class SaveGifQuery : public Td::ResultHandler { send_query(G()->net_query_creator().create(telegram_api::messages_saveGif(std::move(input_document), unsave))); } - void on_result(uint64 id, BufferSlice packet) override { + void on_result(BufferSlice packet) final { auto result_ptr = fetch_result(packet); if (result_ptr.is_error()) { - return on_error(id, result_ptr.move_as_error()); + return on_error(result_ptr.move_as_error()); } bool result = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for save GIF: " << result; if (!result) { - td->animations_manager_->reload_saved_animations(true); + td_->animations_manager_->reload_saved_animations(true); } promise_.set_value(Unit()); } - void on_error(uint64 id, Status status) override { - if (!td->auth_manager_->is_bot() && FileReferenceManager::is_file_reference_error(status)) { + void on_error(Status status) final { + if (!td_->auth_manager_->is_bot() && FileReferenceManager::is_file_reference_error(status)) { VLOG(file_references) << "Receive " << status << " for " << file_id_; - td->file_manager_->delete_file_reference(file_id_, file_reference_); - td->file_reference_manager_->repair_file_reference( + td_->file_manager_->delete_file_reference(file_id_, file_reference_); + td_->file_reference_manager_->repair_file_reference( file_id_, PromiseCreator::lambda([animation_id = file_id_, unsave = unsave_, promise = std::move(promise_)](Result result) mutable { if (result.is_error()) { @@ -122,7 +121,7 @@ class SaveGifQuery : public Td::ResultHandler { if (!G()->is_expected_error(status)) { LOG(ERROR) << "Receive error for save GIF: " << status; } - td->animations_manager_->reload_saved_animations(true); + td_->animations_manager_->reload_saved_animations(true); promise_.set_error(std::move(status)); } }; @@ -151,16 +150,15 @@ int32 AnimationsManager::get_animation_duration(FileId file_id) const { return it->second->duration; } -tl_object_ptr AnimationsManager::get_animation_object(FileId file_id, const char *source) { +tl_object_ptr AnimationsManager::get_animation_object(FileId file_id) const { if (!file_id.is_valid()) { return nullptr; } - auto &animation = animations_[file_id]; - LOG_CHECK(animation != nullptr) << source << " " << file_id << " " - << static_cast(td_->file_manager_->get_file_view(file_id).get_type()); - // TODO can we make that function const? - animation->is_changed = false; + auto it = animations_.find(file_id); + CHECK(it != animations_.end()); + auto animation = it->second.get(); + CHECK(animation != nullptr); auto thumbnail = animation->animated_thumbnail.file_id.is_valid() ? get_thumbnail_object(td_->file_manager_.get(), animation->animated_thumbnail, PhotoFormat::Mpeg4) @@ -184,26 +182,21 @@ FileId AnimationsManager::on_get_animation(unique_ptr new_animation, if (a->mime_type != new_animation->mime_type) { LOG(DEBUG) << "Animation " << file_id << " info has changed"; a->mime_type = new_animation->mime_type; - a->is_changed = true; } if (a->file_name != new_animation->file_name) { LOG(DEBUG) << "Animation " << file_id << " file name has changed"; a->file_name = std::move(new_animation->file_name); - a->is_changed = true; } if (a->dimensions != new_animation->dimensions) { - LOG(DEBUG) << "Animation " << file_id << " dimensions has changed"; + LOG(DEBUG) << "Animation " << file_id << " dimensions have changed"; a->dimensions = new_animation->dimensions; - a->is_changed = true; } if (a->duration != new_animation->duration) { LOG(DEBUG) << "Animation " << file_id << " duration has changed"; a->duration = new_animation->duration; - a->is_changed = true; } if (a->minithumbnail != new_animation->minithumbnail) { a->minithumbnail = std::move(new_animation->minithumbnail); - a->is_changed = true; } if (a->thumbnail != new_animation->thumbnail) { if (!a->thumbnail.file_id.is_valid()) { @@ -213,7 +206,6 @@ FileId AnimationsManager::on_get_animation(unique_ptr new_animation, << new_animation->thumbnail; } a->thumbnail = new_animation->thumbnail; - a->is_changed = true; } if (a->animated_thumbnail != new_animation->animated_thumbnail) { if (!a->animated_thumbnail.file_id.is_valid()) { @@ -223,15 +215,12 @@ FileId AnimationsManager::on_get_animation(unique_ptr new_animation, << " to " << new_animation->animated_thumbnail; } a->animated_thumbnail = new_animation->animated_thumbnail; - a->is_changed = true; } if (a->has_stickers != new_animation->has_stickers && new_animation->has_stickers) { a->has_stickers = new_animation->has_stickers; - a->is_changed = true; } if (a->sticker_file_ids != new_animation->sticker_file_ids && !new_animation->sticker_file_ids.empty()) { a->sticker_file_ids = std::move(new_animation->sticker_file_ids); - a->is_changed = true; } } @@ -281,23 +270,18 @@ FileId AnimationsManager::dup_animation(FileId new_id, FileId old_id) { return new_id; } -bool AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_delete_old) { - if (!old_id.is_valid()) { - LOG(ERROR) << "Old file id is invalid"; - return true; - } +void AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_delete_old) { + CHECK(old_id.is_valid() && new_id.is_valid()); + CHECK(new_id != old_id); LOG(INFO) << "Merge animations " << new_id << " and " << old_id; const Animation *old_ = get_animation(old_id); CHECK(old_ != nullptr); - if (old_id == new_id) { - return old_->is_changed; - } + bool need_merge = true; auto new_it = animations_.find(new_id); if (new_it == animations_.end()) { auto &old = animations_[old_id]; - old->is_changed = true; if (!can_delete_old) { dup_animation(new_id, old_id); } else { @@ -308,16 +292,19 @@ bool AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_ Animation *new_ = new_it->second.get(); CHECK(new_ != nullptr); - new_->is_changed = true; if (old_->thumbnail != new_->thumbnail) { // LOG_STATUS(td_->file_manager_->merge(new_->thumbnail.file_id, old_->thumbnail.file_id)); } + if (new_->file_name.size() == old_->file_name.size() + 4 && new_->file_name == old_->file_name + ".mp4") { + need_merge = false; + } + } + if (need_merge) { + LOG_STATUS(td_->file_manager_->merge(new_id, old_id)); } - LOG_STATUS(td_->file_manager_->merge(new_id, old_id)); if (can_delete_old) { animations_.erase(old_id); } - return true; } void AnimationsManager::create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail, @@ -330,7 +317,9 @@ void AnimationsManager::create_animation(FileId file_id, string minithumbnail, P a->mime_type = std::move(mime_type); a->duration = max(duration, 0); a->dimensions = dimensions; - a->minithumbnail = std::move(minithumbnail); + if (!td_->auth_manager_->is_bot()) { + a->minithumbnail = std::move(minithumbnail); + } a->thumbnail = std::move(thumbnail); a->animated_thumbnail = std::move(animated_thumbnail); a->has_stickers = has_stickers; @@ -346,7 +335,8 @@ tl_object_ptr AnimationsManager::get_input_media( return nullptr; } if (file_view.has_remote_location() && !file_view.main_remote_location().is_web() && input_file == nullptr) { - return make_tl_object(0, file_view.main_remote_location().as_input_document(), 0); + return make_tl_object(0, file_view.main_remote_location().as_input_document(), 0, + string()); } if (file_view.has_url()) { return make_tl_object(0, file_view.url(), 0); @@ -383,7 +373,7 @@ tl_object_ptr AnimationsManager::get_input_media( } return make_tl_object( flags, false /*ignored*/, false /*ignored*/, std::move(input_file), std::move(input_thumbnail), mime_type, - std::move(attributes), vector>(), 0); + std::move(attributes), std::move(added_stickers), 0); } else { CHECK(!file_view.has_remote_location()); } @@ -393,8 +383,7 @@ tl_object_ptr AnimationsManager::get_input_media( SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file_id, tl_object_ptr input_file, - const string &caption, BufferSlice thumbnail, - int32 layer) const { + const string &caption, BufferSlice thumbnail) const { auto *animation = get_animation(animation_file_id); CHECK(animation != nullptr); auto file_view = td_->file_manager_->get_file_view(animation_file_id); @@ -416,13 +405,8 @@ SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file attributes.push_back(make_tl_object(animation->file_name)); } if (animation->duration != 0 && animation->mime_type == "video/mp4") { - if (layer >= SecretChatActor::VIDEO_NOTES_LAYER) { - attributes.push_back(make_tl_object( - 0, false, animation->duration, animation->dimensions.width, animation->dimensions.height)); - } else { - attributes.push_back(make_tl_object( - animation->duration, animation->dimensions.width, animation->dimensions.height)); - } + attributes.push_back(make_tl_object( + 0, false, animation->duration, animation->dimensions.width, animation->dimensions.height)); } if (animation->dimensions.width != 0 && animation->dimensions.height != 0) { attributes.push_back(make_tl_object(animation->dimensions.width, @@ -534,7 +518,7 @@ void AnimationsManager::reload_saved_animations(bool force) { void AnimationsManager::repair_saved_animations(Promise &&promise) { if (td_->auth_manager_->is_bot()) { - return promise.set_error(Status::Error(400, "Bots has no saved animations")); + return promise.set_error(Status::Error(400, "Bots have no saved animations")); } repair_saved_animations_queries_.push_back(std::move(promise)); @@ -680,9 +664,9 @@ void AnimationsManager::on_get_saved_animations_failed(bool is_repair, Status er } } -int32 AnimationsManager::get_saved_animations_hash(const char *source) const { - vector numbers; - numbers.reserve(saved_animation_ids_.size() * 2); +int64 AnimationsManager::get_saved_animations_hash(const char *source) const { + vector numbers; + numbers.reserve(saved_animation_ids_.size()); for (auto animation_id : saved_animation_ids_) { auto animation = get_animation(animation_id); CHECK(animation != nullptr); @@ -692,18 +676,13 @@ int32 AnimationsManager::get_saved_animations_hash(const char *source) const { LOG(ERROR) << "Saved animation remote location is not document: " << source << " " << file_view.remote_location(); continue; } - auto id = static_cast(file_view.remote_location().get_id()); - numbers.push_back(static_cast(id >> 32)); - numbers.push_back(static_cast(id & 0xFFFFFFFF)); + numbers.push_back(file_view.remote_location().get_id()); } return get_vector_hash(numbers); } void AnimationsManager::add_saved_animation(const tl_object_ptr &input_file, Promise &&promise) { - if (td_->auth_manager_->is_bot()) { - return promise.set_error(Status::Error(7, "Method is not available for bots")); - } if (!are_saved_animations_loaded_) { load_saved_animations(std::move(promise)); return; @@ -711,16 +690,14 @@ void AnimationsManager::add_saved_animation(const tl_object_ptrfile_manager_->get_input_file_id(FileType::Animation, input_file, DialogId(), false, false); if (r_file_id.is_error()) { - return promise.set_error(Status::Error(7, r_file_id.error().message())); // TODO do not drop error code + return promise.set_error(Status::Error(400, r_file_id.error().message())); // TODO do not drop error code } add_saved_animation_impl(r_file_id.ok(), true, std::move(promise)); } void AnimationsManager::send_save_gif_query(FileId animation_id, bool unsave, Promise &&promise) { - if (G()->close_flag()) { - return promise.set_error(Status::Error(500, "Request aborted")); - } + TRY_STATUS_PROMISE(promise, G()->close_status()); // TODO invokeAfter and log event auto file_view = td_->file_manager_->get_file_view(animation_id); @@ -747,7 +724,7 @@ void AnimationsManager::add_saved_animation_impl(FileId animation_id, bool add_o auto file_view = td_->file_manager_->get_file_view(animation_id); if (file_view.empty()) { - return promise.set_error(Status::Error(7, "Animation file not found")); + return promise.set_error(Status::Error(400, "Animation file not found")); } LOG(INFO) << "Add saved animation " << animation_id << " with main file " << file_view.file_id(); @@ -781,20 +758,20 @@ void AnimationsManager::add_saved_animation_impl(FileId animation_id, bool add_o auto animation = get_animation(animation_id); if (animation == nullptr) { - return promise.set_error(Status::Error(7, "Animation not found")); + return promise.set_error(Status::Error(400, "Animation not found")); } if (animation->mime_type != "video/mp4") { - return promise.set_error(Status::Error(7, "Only MPEG4 animations can be saved")); + return promise.set_error(Status::Error(400, "Only MPEG4 animations can be saved")); } if (!file_view.has_remote_location()) { - return promise.set_error(Status::Error(7, "Can save only sent animations")); + return promise.set_error(Status::Error(400, "Can save only sent animations")); } if (file_view.remote_location().is_web()) { - return promise.set_error(Status::Error(7, "Can't save web animations")); + return promise.set_error(Status::Error(400, "Can't save web animations")); } if (!file_view.remote_location().is_document()) { - return promise.set_error(Status::Error(7, "Can't save encrypted animations")); + return promise.set_error(Status::Error(400, "Can't save encrypted animations")); } auto it = std::find_if(saved_animation_ids_.begin(), saved_animation_ids_.end(), is_equal); @@ -820,9 +797,6 @@ void AnimationsManager::add_saved_animation_impl(FileId animation_id, bool add_o void AnimationsManager::remove_saved_animation(const tl_object_ptr &input_file, Promise &&promise) { - if (td_->auth_manager_->is_bot()) { - return promise.set_error(Status::Error(7, "Method is not available for bots")); - } if (!are_saved_animations_loaded_) { load_saved_animations(std::move(promise)); return; @@ -830,7 +804,7 @@ void AnimationsManager::remove_saved_animation(const tl_object_ptrfile_manager_->get_input_file_id(FileType::Animation, input_file, DialogId(), false, false); if (r_file_id.is_error()) { - return promise.set_error(Status::Error(7, r_file_id.error().message())); // TODO do not drop error code + return promise.set_error(Status::Error(400, r_file_id.error().message())); // TODO do not drop error code } FileId file_id = r_file_id.ok(); @@ -840,7 +814,7 @@ void AnimationsManager::remove_saved_animation(const tl_object_ptr parent); int32 get_animation_duration(FileId file_id) const; - tl_object_ptr get_animation_object(FileId file_id, const char *source); + tl_object_ptr get_animation_object(FileId file_id) const; void create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail, AnimationSize animated_thumbnail, bool has_stickers, vector &&sticker_file_ids, string file_name, string mime_type, @@ -45,7 +44,7 @@ class AnimationsManager : public Actor { SecretInputMedia get_secret_input_media(FileId animation_file_id, tl_object_ptr input_file, - const string &caption, BufferSlice thumbnail, int32 layer) const; + const string &caption, BufferSlice thumbnail) const; FileId get_animation_thumbnail_file_id(FileId file_id) const; @@ -55,7 +54,7 @@ class AnimationsManager : public Actor { FileId dup_animation(FileId new_id, FileId old_id); - bool merge_animations(FileId new_id, FileId old_id, bool can_delete_old); + void merge_animations(FileId new_id, FileId old_id, bool can_delete_old); void on_update_animation_search_emojis(string animation_search_emojis); @@ -110,15 +109,13 @@ class AnimationsManager : public Actor { vector sticker_file_ids; FileId file_id; - - bool is_changed = true; }; const Animation *get_animation(FileId file_id) const; FileId on_get_animation(unique_ptr new_animation, bool replace); - int32 get_saved_animations_hash(const char *source) const; + int64 get_saved_animations_hash(const char *source) const; void add_saved_animation_impl(FileId animation_id, bool add_on_server, Promise &&promise); @@ -138,7 +135,7 @@ class AnimationsManager : public Actor { void save_saved_animations_to_database(); - void tear_down() override; + void tear_down() final; class AnimationListLogEvent; diff --git a/lib/tgchat/ext/td/td/telegram/AnimationsManager.hpp b/lib/tgchat/ext/td/td/telegram/AnimationsManager.hpp index 60b45a9e..388ef5ab 100644 --- a/lib/tgchat/ext/td/td/telegram/AnimationsManager.hpp +++ b/lib/tgchat/ext/td/td/telegram/AnimationsManager.hpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/lib/tgchat/ext/td/td/telegram/AudiosManager.cpp b/lib/tgchat/ext/td/td/telegram/AudiosManager.cpp index dd0bc539..68b57098 100644 --- a/lib/tgchat/ext/td/td/telegram/AudiosManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/AudiosManager.cpp @@ -1,20 +1,19 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include "td/telegram/AudiosManager.h" +#include "td/telegram/AuthManager.h" #include "td/telegram/files/FileManager.h" -#include "td/telegram/Td.h" - #include "td/telegram/secret_api.h" -#include "td/telegram/td_api.h" -#include "td/telegram/telegram_api.h" +#include "td/telegram/Td.h" #include "td/utils/logging.h" #include "td/utils/misc.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Status.h" namespace td { @@ -28,14 +27,15 @@ int32 AudiosManager::get_audio_duration(FileId file_id) const { return it->second->duration; } -tl_object_ptr AudiosManager::get_audio_object(FileId file_id) { +tl_object_ptr AudiosManager::get_audio_object(FileId file_id) const { if (!file_id.is_valid()) { return nullptr; } - auto &audio = audios_[file_id]; + auto it = audios_.find(file_id); + CHECK(it != audios_.end()); + auto audio = it->second.get(); CHECK(audio != nullptr); - audio->is_changed = false; return make_tl_object( audio->duration, audio->title, audio->performer, audio->file_name, audio->mime_type, get_minithumbnail_object(audio->minithumbnail), @@ -55,23 +55,19 @@ FileId AudiosManager::on_get_audio(unique_ptr