Merge latest commits

This commit is contained in:
Andrea Cavalli 2021-03-11 18:25:39 +01:00
commit 1ea79d2739
103 changed files with 7325 additions and 2702 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
project(TDLib VERSION 1.7.0 LANGUAGES CXX C)
project(TDLib VERSION 1.7.2 LANGUAGES CXX C)
if (NOT DEFINED CMAKE_MODULE_PATH)
set(CMAKE_MODULE_PATH "")
@ -201,7 +201,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()
@ -295,6 +294,7 @@ set(TDLIB_SOURCE
td/telegram/DialogDb.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
@ -343,6 +343,7 @@ set(TDLIB_SOURCE
td/telegram/MessagesDb.cpp
td/telegram/MessageSearchFilter.cpp
td/telegram/MessagesManager.cpp
td/telegram/MessageTtlSetting.cpp
td/telegram/misc.cpp
td/telegram/net/AuthDataShared.cpp
td/telegram/net/ConnectionCreator.cpp
@ -374,6 +375,7 @@ set(TDLIB_SOURCE
td/telegram/PollManager.cpp
td/telegram/QueryCombiner.cpp
td/telegram/ReplyMarkup.cpp
td/telegram/ReportReason.cpp
td/telegram/RestrictionReason.cpp
td/telegram/SecretChatActor.cpp
td/telegram/SecretChatDb.cpp
@ -461,6 +463,7 @@ set(TDLIB_SOURCE
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
@ -523,6 +526,7 @@ set(TDLIB_SOURCE
td/telegram/MessagesDb.h
td/telegram/MessageSearchFilter.h
td/telegram/MessagesManager.h
td/telegram/MessageTtlSetting.h
td/telegram/misc.h
td/telegram/net/AuthDataShared.h
td/telegram/net/ConnectionCreator.h
@ -567,6 +571,7 @@ set(TDLIB_SOURCE
td/telegram/PublicDialogType.h
td/telegram/QueryCombiner.h
td/telegram/ReplyMarkup.h
td/telegram/ReportReason.h
td/telegram/RequestActor.h
td/telegram/RestrictionReason.h
td/telegram/ScheduledServerMessageId.h

View File

@ -216,7 +216,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.2 REQUIRED)
target_link_libraries(YourTarget PRIVATE Td::TdStatic)
```
See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/tree/master/example/cpp/CMakeLists.txt).

View File

@ -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();
}
@ -285,7 +298,7 @@ function split_file($file, $chunks, $undo) {
'[>](td_db[(][)]|get_td_db_impl[(])|TdDb[^A-Za-z]' => 'TdDb',
'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');

View File

@ -715,7 +715,7 @@ function onOptionsChanged() {
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');

View File

@ -169,10 +169,10 @@ 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) 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.
<a name="erlang"></a>

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
project(TdExample VERSION 1.0 LANGUAGES CXX)
find_package(Td 1.7.0 REQUIRED)
find_package(Td 1.7.2 REQUIRED)
add_executable(tdjson_example tdjson_example.cpp)
target_link_libraries(tdjson_example PRIVATE Td::TdJson)

View File

@ -1,6 +1,6 @@
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
<Metadata>
<Identity Id="Telegram.Td.UWP" Version="1.7.0" Language="en-US" Publisher="Telegram LLC" />
<Identity Id="Telegram.Td.UWP" Version="1.7.2" Language="en-US" Publisher="Telegram LLC" />
<DisplayName>TDLib for Universal Windows Platform</DisplayName>
<Description>TDLib is a library for building Telegram clients</Description>
<MoreInfo>https://core.telegram.org/tdlib</MoreInfo>

View File

@ -6,147 +6,92 @@ 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)
set(TD_AUTO_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/auto/td)
set(TL_TD_AUTO_SOURCE
${TD_AUTO_INCLUDE_DIR}/mtproto/mtproto_api.cpp
${TD_AUTO_INCLUDE_DIR}/mtproto/mtproto_api.h
${TD_AUTO_INCLUDE_DIR}/mtproto/mtproto_api.hpp
${TD_AUTO_INCLUDE_DIR}/telegram/telegram_api.cpp
${TD_AUTO_INCLUDE_DIR}/telegram/telegram_api.h
${TD_AUTO_INCLUDE_DIR}/telegram/telegram_api.hpp
${TD_AUTO_INCLUDE_DIR}/telegram/secret_api.cpp
${TD_AUTO_INCLUDE_DIR}/telegram/secret_api.h
${TD_AUTO_INCLUDE_DIR}/telegram/secret_api.hpp
PARENT_SCOPE
)
${TD_AUTO_INCLUDE_DIR}/mtproto/mtproto_api.cpp
${TD_AUTO_INCLUDE_DIR}/mtproto/mtproto_api.h
${TD_AUTO_INCLUDE_DIR}/mtproto/mtproto_api.hpp
${TD_AUTO_INCLUDE_DIR}/telegram/telegram_api.cpp
${TD_AUTO_INCLUDE_DIR}/telegram/telegram_api.h
${TD_AUTO_INCLUDE_DIR}/telegram/telegram_api.hpp
${TD_AUTO_INCLUDE_DIR}/telegram/secret_api.cpp
${TD_AUTO_INCLUDE_DIR}/telegram/secret_api.h
${TD_AUTO_INCLUDE_DIR}/telegram/secret_api.hpp
PARENT_SCOPE
)
set(TL_TD_API_AUTO_SOURCE
${TD_AUTO_INCLUDE_DIR}/telegram/td_api.cpp
${TD_AUTO_INCLUDE_DIR}/telegram/td_api.h
${TD_AUTO_INCLUDE_DIR}/telegram/td_api.hpp
PARENT_SCOPE
)
${TD_AUTO_INCLUDE_DIR}/telegram/td_api.cpp
${TD_AUTO_INCLUDE_DIR}/telegram/td_api.h
${TD_AUTO_INCLUDE_DIR}/telegram/td_api.hpp
PARENT_SCOPE
)
set(TL_TD_JSON_AUTO_SOURCE
${TD_AUTO_INCLUDE_DIR}/telegram/td_api_json.cpp
${TD_AUTO_INCLUDE_DIR}/telegram/td_api_json.h
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)
${TD_AUTO_INCLUDE_DIR}/telegram/td_api_json.cpp
${TD_AUTO_INCLUDE_DIR}/telegram/td_api_json.h
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
${TD_AUTO_INCLUDE_DIR}/telegram/td_tdc_api_inner.h
PARENT_SCOPE
)
${TD_AUTO_INCLUDE_DIR}/telegram/td_tdc_api.cpp
${TD_AUTO_INCLUDE_DIR}/telegram/td_tdc_api.h
${TD_AUTO_INCLUDE_DIR}/telegram/td_tdc_api_inner.h
PARENT_SCOPE
)
set(TL_DOTNET_AUTO_SOURCE
${TD_AUTO_INCLUDE_DIR}/telegram/TdDotNetApi.cpp
${TD_AUTO_INCLUDE_DIR}/telegram/TdDotNetApi.h
PARENT_SCOPE
)
${TD_AUTO_INCLUDE_DIR}/telegram/TdDotNetApi.cpp
${TD_AUTO_INCLUDE_DIR}/telegram/TdDotNetApi.h
PARENT_SCOPE
)
set(TL_GENERATE_COMMON_SOURCE
generate_common.cpp
generate_common.cpp
tl_writer_cpp.cpp
tl_writer_h.cpp
tl_writer_hpp.cpp
tl_writer_jni_cpp.cpp
tl_writer_jni_h.cpp
tl_writer_td.cpp
tl_writer_cpp.cpp
tl_writer_h.cpp
tl_writer_hpp.cpp
tl_writer_jni_cpp.cpp
tl_writer_jni_h.cpp
tl_writer_td.cpp
tl_writer_cpp.h
tl_writer_h.h
tl_writer_hpp.h
tl_writer_jni_cpp.h
tl_writer_jni_h.h
tl_writer_td.h
)
tl_writer_cpp.h
tl_writer_h.h
tl_writer_hpp.h
tl_writer_jni_cpp.h
tl_writer_jni_h.h
tl_writer_td.h
)
set(TL_GENERATE_C_SOURCE
generate_c.cpp
generate_c.cpp
tl_writer_c.h
)
tl_writer_c.h
)
set(TL_GENERATE_JAVA_SOURCE
generate_java.cpp
generate_java.cpp
tl_writer_java.cpp
tl_writer_java.cpp
tl_writer_java.h
)
tl_writer_java.h
)
set(TL_GENERATE_JSON_SOURCE
generate_json.cpp
generate_json.cpp
tl_json_converter.cpp
tl_json_converter.cpp
tl_json_converter.h
)
tl_json_converter.h
)
if (NOT CMAKE_CROSSCOMPILING)
# Start of .tlo update
add_custom_target(prepare_tl_parser ALL
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/tl-parser/build)
add_custom_target(configure_tl_parser
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tl-parser/build
COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ../
COMMENT "Configure tl-parser"
DEPENDS scheme/mtproto_api.tl scheme/telegram_api.tl scheme/secret_api.tl scheme/td_api.tl
)
add_dependencies(configure_tl_parser prepare_tl_parser)
add_custom_target(build_tl_parser
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tl-parser/build
COMMAND ${CMAKE_COMMAND} --build .
COMMENT "Build tl-parser"
DEPENDS scheme/mtproto_api.tl scheme/telegram_api.tl scheme/secret_api.tl scheme/td_api.tl
)
add_dependencies(build_tl_parser configure_tl_parser)
set(TL_PARSER_BIN ./tl-parser/build/tl-parser)
add_custom_target(generate_mtproto_api_tlo
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TL_PARSER_BIN} -v -e scheme/mtproto_api.tlo scheme/mtproto_api.tl
COMMENT "Build tl-parser"
DEPENDS scheme/mtproto_api.tl
)
add_dependencies(generate_mtproto_api_tlo build_tl_parser)
add_custom_target(generate_secret_api_tlo
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TL_PARSER_BIN} -v -e scheme/secret_api.tlo scheme/secret_api.tl
COMMENT "Build tl-parser"
DEPENDS scheme/secret_api.tl
)
add_dependencies(generate_secret_api_tlo build_tl_parser)
add_custom_target(generate_telegram_api_tlo
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TL_PARSER_BIN} -v -e scheme/telegram_api.tlo scheme/telegram_api.tl
COMMENT "Build tl-parser"
DEPENDS scheme/telegram_api.tl
)
add_dependencies(generate_telegram_api_tlo build_tl_parser)
add_custom_target(generate_td_api_tlo
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TL_PARSER_BIN} -v -e scheme/td_api.tlo scheme/td_api.tl
COMMENT "Build tl-parser"
DEPENDS scheme/td_api.tl
)
add_dependencies(generate_td_api_tlo build_tl_parser)
# End of .tlo update
find_program(PHP_EXECUTABLE php)
if ((CMAKE_SYSTEM_NAME MATCHES "FreeBSD") AND (CMAKE_SYSTEM_VERSION MATCHES "HBSD"))
@ -159,14 +104,27 @@ 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)
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})
add_dependencies(generate_common generate_mtproto_api_tlo generate_secret_api_tlo generate_telegram_api_tlo generate_td_api_tlo)
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 DoxygenTlDocumentationGenerator.php
COMMENT "Generate common TL source files"
DEPENDS generate_common tl_generate_tlo ${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 ${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)
@ -178,12 +136,11 @@ if (NOT CMAKE_CROSSCOMPILING)
add_executable(generate_c ${TL_GENERATE_C_SOURCE})
target_link_libraries(generate_c PRIVATE tdtl)
add_custom_target(tl_generate_c
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND generate_c
COMMENT "Generate C tl source files"
DEPENDS generate_c generate_td_api_tlo
)
add_dependencies(tl_generate_c generate_td_api_tlo)
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND generate_c
COMMENT "Generate C TL source files"
DEPENDS generate_c tl_generate_tlo ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl
)
add_executable(td_generate_java_api ${TL_GENERATE_JAVA_SOURCE})
target_link_libraries(td_generate_java_api PRIVATE tdtl)
@ -191,34 +148,33 @@ if (NOT CMAKE_CROSSCOMPILING)
add_executable(generate_json ${TL_GENERATE_JSON_SOURCE})
target_link_libraries(generate_json PRIVATE tdtl tdutils)
add_custom_target(tl_generate_json
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND generate_json
COMMENT "Generate JSON tl source files"
DEPENDS generate_json generate_td_api_tlo
)
add_dependencies(tl_generate_json generate_td_api_tlo)
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND generate_json
COMMENT "Generate JSON TL source files"
DEPENDS generate_json tl_generate_tlo ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo ${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 ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo && ${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 ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo)
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}
COMMENT "Generate .NET API files"
DEPENDS td_generate_dotnet_api generate_td_api_tlo DotnetTlDocumentationGenerator.php
)
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${GENERATE_DOTNET_API_CMD}
COMMENT "Generate .NET API files"
DEPENDS td_generate_dotnet_api tl_generate_tlo ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl ${CMAKE_CURRENT_SOURCE_DIR}/DotnetTlDocumentationGenerator.php
)
endif()
add_executable(remove_documentation remove_documentation.cpp)

View File

@ -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",

View File

@ -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<std::string> &ext_cpp_includes,
const std::vector<std::string> &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));

View File

@ -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);
}

View File

@ -237,7 +237,7 @@ maskPosition point:MaskPoint x_shift:double y_shift:double scale:double = MaskPo
closedVectorPath commands:vector<VectorPathCommand> = 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
//@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;
@ -249,7 +249,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;
@ -308,7 +308,7 @@ 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
@ -377,7 +377,7 @@ chatPhotos total_count:int32 photos:vector<chatPhoto> = 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
@ -403,10 +403,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: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 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
@ -454,17 +455,18 @@ chatMemberStatusCreator custom_title:string is_anonymous:Bool is_member:Bool = C
//@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, ban unprivileged members, and manage voice 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 supergoups 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_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_voice_chats True, if the administrator can manage voice chats; applicable to groups only
//@can_manage_voice_chats True, if the administrator can manage voice chats; applicable to basic groups and supergroups only
//@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 can_manage_voice_chats: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_voice_chats:Bool is_anonymous:Bool = ChatMemberStatus;
//@description The user is a member of a chat, without any additional privileges or restrictions
chatMemberStatusMember = ChatMemberStatus;
@ -479,7 +481,7 @@ chatMemberStatusRestricted is_member:Bool restricted_until_date:int32 permission
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
//@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;
@ -545,6 +547,46 @@ supergroupMembersFilterMention query:string message_thread_id:int53 = Supergroup
supergroupMembersFilterBots = SupergroupMembersFilter;
//@description Contains a chat invite link @invite_link Chat invite 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 Maximum number of members, which can join the chat using the link simultaneously; 0 if not limited
//@member_count Number of chat members, which joined the chat using the link
//@is_primary True, if the link is primary. Primary invite link can't have 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 creator_user_id:int32 date:int32 edit_date:int32 expire_date:int32 member_limit:int32 member_count:int32 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<chatInviteLink> = 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:int32 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 linkcounts
chatInviteLinkCounts invite_link_counts:vector<chatInviteLinkCount> = 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
chatInviteLinkMember user_id:int32 joined_chat_date:int32 = 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<chatInviteLinkMember> = 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 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<int32> is_public:Bool = ChatInviteLinkInfo;
//@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
@ -555,11 +597,11 @@ basicGroup id:int32 member_count:int32 status:ChatMemberStatus is_active:Bool up
//@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<chatMember> 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
basicGroupFullInfo photo:chatPhoto description:string creator_user_id:int32 members:vector<chatMember> invite_link:chatInviteLink = 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
@ -573,10 +615,12 @@ basicGroupFullInfo photo:chatPhoto description:string creator_user_id:int32 memb
//@sign_messages True, if messages sent to the channel should 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: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_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
@ -596,10 +640,10 @@ 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
//@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 upgraded_from_basic_group_id:int32 upgraded_from_max_message_id:int53 = SupergroupFullInfo;
//@class SecretChatState @description Describes the current secret chat state
@ -619,11 +663,10 @@ 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;
secretChat id:int32 user_id:int32 state:SecretChatState is_outbound:Bool key_hash:bytes layer:int32 = SecretChat;
//@class MessageSender @description Contains information about the sender of a message
@ -658,6 +701,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
@ -858,20 +904,21 @@ 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
//@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
//@action_bar Describes actions which should be possible to do through a chat action bar; may be null
//@voice_chat_group_call_id Group call identifier of an active voice chat; 0 if none or unknown. The voice chat can be received through the method getGroupCall
//@is_voice_chat_empty True, if an active voice chat is empty
//@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<chatPosition> 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 voice_chat_group_call_id:int32 is_voice_chat_empty:Bool reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat;
chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector<chatPosition> 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 action_bar:ChatActionBar voice_chat_group_call_id:int32 is_voice_chat_empty:Bool 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<int53> = Chats;
@ -884,21 +931,6 @@ chatNearby chat_id:int53 distance:int32 = ChatNearby;
chatsNearby users_nearby:vector<chatNearby> supergroups_nearby:vector<chatNearby> = 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<int32> is_public:Bool = ChatInviteLinkInfo;
//@class PublicChatType @description Describes a type of public chats
//@description The chat is public, because it has username
@ -917,6 +949,9 @@ 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 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 blockUser, 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
@ -1290,12 +1325,12 @@ 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
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;
@ -1360,7 +1395,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
@ -1678,7 +1713,7 @@ 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 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
@ -1851,7 +1886,7 @@ inputMessageGame bot_user_id:int32 game_short_name:string = InputMessageContent;
//@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
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
@ -2080,9 +2115,9 @@ groupCallRecentSpeaker user_id:int32 is_speaking:Bool = GroupCallRecentSpeaker;
//@loaded_all_participants True, if all group call participants are loaded
//@recent_speakers Recently speaking users in the group call
//@mute_new_participants True, if only group call administrators can unmute new participants
//@allowed_change_mute_new_participants True, if group call administrators can enable or disable mute_new_participants setting
//@can_change_mute_new_participants True, if the current user can enable or disable mute_new_participants setting
//@duration Call duration; for ended calls only
groupCall id:int32 is_active:Bool is_joined:Bool need_rejoin:Bool can_unmute_self:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector<groupCallRecentSpeaker> mute_new_participants:Bool allowed_change_mute_new_participants:Bool duration:int32 = GroupCall;
groupCall id:int32 is_active:Bool is_joined:Bool need_rejoin:Bool can_unmute_self:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector<groupCallRecentSpeaker> mute_new_participants:Bool can_change_mute_new_participants:Bool duration:int32 = GroupCall;
//@description Describes a payload fingerprint for interaction with tgcalls @hash Value of the field hash @setup Value of the field setup @fingerprint Value of the field fingerprint
groupCallPayloadFingerprint hash:string setup:string fingerprint:string = GroupCallPayloadFingerprint;
@ -2102,12 +2137,16 @@ groupCallJoinResponse payload:groupCallPayload candidates:vector<groupCallJoinRe
//@user_id Identifier of the user
//@source User's synchronization source
//@is_speaking True, if the participant is speaking as set by setGroupCallParticipantIsSpeaking
//@can_be_muted True, if the current user can mute the participant
//@can_be_unmuted True, if the current user can allow the participant to unmute themself or unmute the participant (only for self)
//@is_muted True, if the participant is muted
//@can_unmute_self True, if the participant can unmute themself
//@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 themself 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 themself
//@volume_level Participant's volume level; 1-20000 in hundreds of percents
//@order User's order in the group call participant list. The bigger is order, the higher is user in the list. If order is 0, the user must be removed from the participant list
groupCallParticipant user_id:int32 source:int32 is_speaking:Bool can_be_muted:Bool can_be_unmuted:Bool is_muted:Bool can_unmute_self:Bool order:int64 = GroupCallParticipant;
groupCallParticipant user_id:int32 source:int32 is_speaking: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:int64 = GroupCallParticipant;
//@class CallProblem @description Describes the exact type of a problem with a call
@ -2345,6 +2384,9 @@ 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 member left the chat
chatEventMemberLeft = ChatEventAction;
@ -2381,6 +2423,9 @@ chatEventLinkedChatChanged old_linked_chat_id:int53 new_linked_chat_id:int53 = C
//@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
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;
@ -2393,6 +2438,15 @@ 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 voice chat was created @group_call_id Identifier of the voice chat. The voice chat can be received through the method getGroupCall
chatEventVoiceChatCreated group_call_id:int32 = ChatEventAction;
@ -2402,6 +2456,9 @@ chatEventVoiceChatDiscarded group_call_id:int32 = ChatEventAction;
//@description A voice chat participant was muted or unmuted @user_id Identifier of the affected user @is_muted New value of is_muted
chatEventVoiceChatParticipantIsMutedToggled user_id:int32 is_muted:Bool = ChatEventAction;
//@description A voice chat participant volume level was changed @user_id Identifier of the affected user @volume_level New value of volume_level; 1-20000 in hundreds of percents
chatEventVoiceChatParticipantVolumeLevelChanged user_id:int32 volume_level:int32 = ChatEventAction;
//@description The mute_new_participants setting of a voice chat was toggled @mute_new_participants New value of the mute_new_participants setting
chatEventVoiceChatMuteNewParticipantsToggled mute_new_participants:Bool = ChatEventAction;
@ -2422,8 +2479,9 @@ chatEvents events:vector<chatEvent> = ChatEvents;
//@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
//@invite_link_changes True, if changes to invite links should be returned
//@voice_chat_changes True, if voice chat actions 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 voice_chat_changes:Bool = ChatEventLogFilters;
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 voice_chat_changes:Bool = ChatEventLogFilters;
//@class LanguagePackStringValue @description Represents the value of a string in a language pack
@ -2520,7 +2578,7 @@ 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
//@intensity Intensity of the pattern when it is shown above the filled background; 0-100
//@is_moving True, if the background needs to be slightly moved when device is tilted
backgroundTypePattern fill:BackgroundFill intensity:int32 is_moving:Bool = BackgroundType;
@ -2588,6 +2646,18 @@ checkChatUsernameResultPublicChatsTooMuch = CheckChatUsernameResult;
checkChatUsernameResultPublicGroupsUnavailable = CheckChatUsernameResult;
//@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
@ -2867,8 +2937,11 @@ 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;
//@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
@ -3081,6 +3154,12 @@ suggestedActionEnableArchiveAndMuteNewChats = SuggestedAction;
//@description Suggests the user to check authorization phone number 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:int32 = SuggestedAction;
//@description Contains a counter @count Count
count count:int32 = Count;
@ -3330,6 +3409,9 @@ 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;
@ -3525,6 +3607,11 @@ 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<int32> = 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:int32 date:int32 invite_link:chatInviteLink old_chat_member:chatMember new_chat_member:chatMember = Update;
//@description Contains a list of updates @updates List of updates
updates updates:vector<Update> = Updates;
@ -3802,6 +3889,9 @@ getMessageThreadHistory chat_id:int53 message_id:int53 from_message_id:int53 off
//@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
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
//@chat_id Identifier of the chat in which to search messages
@ -3840,6 +3930,9 @@ searchSecretMessages chat_id:int53 query:string offset:string limit:int32 filter
//@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
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;
@ -3930,9 +4023,6 @@ forwardMessages chat_id:int53 from_chat_id:int53 message_ids:vector<int53> optio
//@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<int53> = 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;
@ -4125,6 +4215,9 @@ viewMessages chat_id:int53 message_thread_id:int53 message_ids:vector<int53> for
//@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 Returns an HTTP URL to open when user clicks on a given HTTP link. This method can be used to automatically login user on a Telegram site @link The HTTP link
getExternalLink link:string = HttpUrl;
//@description Marks all mentions in a chat as read @chat_id Chat identifier
readAllChatMentions chat_id:int53 = Ok;
@ -4145,8 +4238,13 @@ 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<int32> 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
//@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;
@ -4184,14 +4282,19 @@ 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
//@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, 604800 unless 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;
@ -4212,10 +4315,10 @@ 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;
@ -4245,18 +4348,25 @@ joinChat chat_id:int53 = Ok;
//@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
//@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
addChatMember chat_id:int53 user_id:int32 forward_limit:int32 = 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. Members will not be added until the chat state has been synchronized with the server
//@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<int32> = 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
//@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
//@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 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
//@user_id Identifier of the user
//@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. Always true for supergroups and channels
banChatMember chat_id:int53 user_id:int32 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;
@ -4346,14 +4456,76 @@ 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 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 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<InputFile> = 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 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
//@expire_date Point in time (Unix timestamp) when the link will expire; pass 0 if never
//@member_limit Maximum number of chat members that can join the chat by the link simultaneously; 0-99999; pass 0 if not limited
createChatInviteLink chat_id:int53 expire_date:int32 member_limit:int32 = 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
//@expire_date Point in time (Unix timestamp) when the link will expire; pass 0 if never
//@member_limit Maximum number of chat members that can join the chat by the link simultaneously; 0-99999; pass 0 if not limited
editChatInviteLink chat_id:int53 invite_link:string expire_date:int32 member_limit:int32 = 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 Maximum number of invite links to return
getChatInviteLinks chat_id:int53 creator_user_id:int32 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; use null to get results from the beginning @limit Maximum number of chat members to return
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:int32 = 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; must have URL "t.me", "telegram.me", or "telegram.dog" and query beginning with "/joinchat/" or "/+"
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 import; must have URL "t.me", "telegram.me", or "telegram.dog" and query beginning with "/joinchat/" or "/+"
joinChatByInviteLink invite_link:string = Chat;
@ -4385,7 +4557,7 @@ getGroupCall group_call_id:int32 = GroupCall;
//@description Joins a group call @group_call_id Group call identifier @payload Group join payload, received from tgcalls. Use null to cancel previous joinGroupCall request @source Caller synchronization source identifier; received from tgcalls @is_muted True, if the user's microphone is muted
joinGroupCall group_call_id:int32 payload:groupCallPayload source:int32 is_muted:Bool = GroupCallJoinResponse;
//@description Toggles whether new participants of a group call can be unmuted only by administrators of the group call. Requires can_manage_voice_chats rights in the corresponding chat and allowed_change_mute_mew_participants group call flag
//@description Toggles whether new participants of a group call can be unmuted only by administrators of the group call. Requires groupCall.can_change_mute_new_participants group call flag
//@group_call_id Group call identifier @mute_new_participants New value of the mute_new_participants setting
toggleGroupCallMuteNewParticipants group_call_id:int32 mute_new_participants:Bool = Ok;
@ -4401,6 +4573,10 @@ setGroupCallParticipantIsSpeaking group_call_id:int32 source:int32 is_speaking:B
//@group_call_id Group call identifier @user_id User identifier @is_muted Pass true if the user must be muted and false otherwise
toggleGroupCallParticipantIsMuted group_call_id:int32 user_id:int32 is_muted:Bool = Ok;
//@description Changes a group call participant's volume level. If the current user can manage the group call, then the participant's volume level will be changed for all users with default volume level
//@group_call_id Group call identifier @user_id User identifier @volume_level New participant's volume level; 1-20000 in hundreds of percents
setGroupCallParticipantVolumeLevel group_call_id:int32 user_id:int32 volume_level:int32 = Ok;
//@description Loads more group call participants. The loaded participants will be received through updates. Use the field groupCall.loaded_all_participants to check whether all participants has 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 Maximum number of participants to load
@ -4409,7 +4585,7 @@ 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 can_manage_voice_chats rights in the corresponding chat @group_call_id Group call identifier
//@description Discards a group call. Requires groupCall.can_be_managed @group_call_id Group call identifier
discardGroupCall group_call_id:int32 = Ok;
@ -4620,15 +4796,18 @@ 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;
//@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
//@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:int32 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
//@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:int32 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
//@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:int32 is_all_history_available:Bool = Ok;
//@description Upgrades supergroup to a broadcast group; requires owner privileges in the supergroup @supergroup_id Identifier of the supergroup
toggleSupergroupIsBroadcastGroup supergroup_id:int32 = 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<int53> = Ok;
@ -4636,9 +4815,6 @@ reportSupergroupSpam supergroup_id:int32 user_id:int32 message_ids:vector<int53>
//@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 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 Closes a secret chat, effectively transferring its state to secretChatStateClosed @secret_chat_id Secret chat identifier
closeSecretChat secret_chat_id:int32 = Ok;
@ -4771,9 +4947,13 @@ 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<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 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<int53> 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;
@ -4999,7 +5179,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;
@ -5029,7 +5209,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;

View File

@ -96,7 +96,7 @@ 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<RestrictionReason> bot_inline_placeholder:flags.19?string lang_code:flags.22?string = 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 fake:flags.26?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<RestrictionReason> 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;
@ -111,11 +111,11 @@ 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 call_active:flags.23?true call_not_empty:flags.24?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 call_active:flags.23?true call_not_empty:flags.24?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<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = 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 call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?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<RestrictionReason> 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;
chatFull#dc8c181 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<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall = ChatFull;
channelFull#ef3a6acd 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<BotInfo> 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 call:flags.21?InputGroupCall = ChatFull;
chatFull#f06c4018 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:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int = ChatFull;
channelFull#2548c037 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:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> 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 call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
@ -127,9 +127,9 @@ chatParticipants#3f460fed chat_id:int participants:Vector<ChatParticipant> versi
chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#d20b9f3c flags:# has_video:flags.0?true photo_small:FileLocation photo_big:FileLocation 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<MessageEntity> 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<RestrictionReason> = 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#bce383d2 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<MessageEntity> 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<RestrictionReason> 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;
@ -171,6 +171,7 @@ 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#76b9f11a call:InputGroupCall users:Vector<int> = MessageAction;
messageActionSetMessagesTTL#aa1afbfd period:int = 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;
@ -204,7 +205,7 @@ 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;
@ -213,11 +214,12 @@ 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#139a9a77 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 = UserFull;
contact#f911c994 user_id:int mutual:Bool = Contact;
@ -344,7 +346,6 @@ updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update;
updateDialogFilterOrder#a5d72105 order:Vector<int> = 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;
@ -355,6 +356,10 @@ updatePinnedChannelMessages#8588878b flags:# pinned:flags.0?true channel_id:int
updateChat#1330a196 chat_id:int = Update;
updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector<GroupCallParticipant> version:int = Update;
updateGroupCall#a45eb99b chat_id:int call:GroupCall = Update;
updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update;
updateChatParticipant#f3b3781f flags:# chat_id:int date:int actor_id:int user_id:int prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update;
updateChannelParticipant#7fecb1ec flags:# channel_id:int date:int actor_id:int user_id:int prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update;
updateBotStopped#7f9488a user_id:int date:int stopped:Bool qts:int = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -364,12 +369,12 @@ updates.differenceSlice#a8fb1981 new_messages:Vector<Message> 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<MessageEntity> = 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<MessageEntity> = Updates;
updateShortMessage#faeff833 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<MessageEntity> ttl_period:flags.25?int = Updates;
updateShortChatMessage#1157b858 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<MessageEntity> ttl_period:flags.25?int = Updates;
updateShort#78d4dec1 update:Update date:int = Updates;
updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates;
updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> 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<MessageEntity> = 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<MessageEntity> ttl_period:flags.25?int = Updates;
photos.photos#8dca6aa5 photos:Vector<Photo> users:Vector<User> = photos.Photos;
photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> = photos.Photos;
@ -394,7 +399,7 @@ 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;
encryptedChatDiscarded#1e1c7c45 flags:# history_deleted:flags.0?true id:int = EncryptedChat;
inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat;
@ -442,6 +447,7 @@ sendMessageGamePlayAction#dd6a8f48 = SendMessageAction;
sendMessageRecordRoundAction#88f27fbc = SendMessageAction;
sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction;
speakingInGroupCallAction#d92c2285 = SendMessageAction;
sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction;
contacts.found#b3134d9d my_results:Vector<Peer> results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found;
@ -522,8 +528,7 @@ auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery;
receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage;
chatInviteEmpty#69df3769 = ExportedChatInvite;
chatInviteExported#fc2e05bc link:string = ExportedChatInvite;
chatInviteExported#6e24fc9d flags:# revoked:flags.0?true permanent:flags.5?true link:string admin_id:int date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int = 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<User> = ChatInvite;
@ -648,7 +653,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;
@ -807,7 +812,7 @@ payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_inf
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;
@ -872,12 +877,18 @@ channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = Channe
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;
channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = 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 group_call:flags.14?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;
@ -1035,7 +1046,7 @@ 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 manage_call:flags.11?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;
@ -1182,7 +1193,7 @@ groupCall#55903081 flags:# join_muted:flags.1?true can_change_join_muted:flags.2
inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall;
groupCallParticipant#56b087c9 flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true user_id:int date:int active_date:flags.3?int source:int = GroupCallParticipant;
groupCallParticipant#64c62a15 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 user_id:int date:int active_date:flags.3?int source:int volume:flags.7?int = GroupCallParticipant;
phone.groupCall#66ab0bfc call:GroupCall participants:Vector<GroupCallParticipant> participants_next_offset:string users:Vector<User> = phone.GroupCall;
@ -1194,6 +1205,27 @@ 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<int> = messages.AffectedFoundMessages;
chatInviteImporter#1e3e6680 user_id:int date:int = ChatInviteImporter;
messages.exportedChatInvites#bdc62dcc count:int invites:Vector<ExportedChatInvite> users:Vector<User> = messages.ExportedChatInvites;
messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector<User> = messages.ExportedChatInvite;
messages.exportedChatInviteReplaced#222600ef invite:ExportedChatInvite new_invite:ExportedChatInvite users:Vector<User> = messages.ExportedChatInvite;
messages.chatInviteImporters#81b6b00a count:int importers:Vector<ChatInviteImporter> users:Vector<User> = messages.ChatInviteImporters;
chatAdminWithInvites#dfd2330f admin_id:int invites_count:int revoked_invites_count:int = ChatAdminWithInvites;
messages.chatAdminsWithInvites#b69b72d7 admins:Vector<ChatAdminWithInvites> users:Vector<User> = messages.ChatAdminsWithInvites;
messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -1231,7 +1263,7 @@ 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.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;
@ -1290,6 +1322,7 @@ account.getContentSettings#8b9b4dae = account.ContentSettings;
account.getMultiWallPapers#65ad71dc wallpapers:Vector<InputWallPaper> = Vector<WallPaper>;
account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings;
account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings;
account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
@ -1330,18 +1363,18 @@ messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true
messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> 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<int> reason:ReportReason = Bool;
messages.report#8953ab4e peer:InputPeer id:Vector<int> reason:ReportReason message:string = Bool;
messages.getChats#3c6aa187 id:Vector<int> = 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.deleteChatUser#c534459a flags:# revoke_history:flags.0?true chat_id:int user_id:InputUser = Updates;
messages.createChat#9cb126e users:Vector<InputUser> 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;
@ -1353,7 +1386,7 @@ messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages
messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers;
messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia;
messages.exportChatInvite#df7534c peer:InputPeer = ExportedChatInvite;
messages.exportChatInvite#14b9bcd7 flags:# legacy_revoke_permanent:flags.2?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int = ExportedChatInvite;
messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
messages.importChatInvite#6c50051c hash:string = Updates;
messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
@ -1443,6 +1476,21 @@ messages.getReplies#24b581ba peer:InputPeer msg_id:int offset_id:int offset_date
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#83247d11 chat_id:int = 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#2e4ffbe flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int = 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#26fb7289 peer:InputPeer link: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;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@ -1482,7 +1530,7 @@ help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo;
help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector<MessageEntity> = 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;
@ -1494,7 +1542,7 @@ channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipant
channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant;
channels.getChannels#a7f6bbb id:Vector<InputChannel> = 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;
@ -1520,6 +1568,7 @@ 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;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
@ -1551,7 +1600,7 @@ phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool;
phone.createGroupCall#bd3dabe0 peer:InputPeer random_id:int = Updates;
phone.joinGroupCall#5f9c8e62 flags:# muted:flags.0?true call:InputGroupCall params:DataJSON = Updates;
phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates;
phone.editGroupCallMember#63146ae4 flags:# muted:flags.0?true call:InputGroupCall user_id:InputUser = Updates;
phone.editGroupCallMember#a5e76cd8 flags:# muted:flags.0?true call:InputGroupCall user_id:InputUser volume:flags.1?int = Updates;
phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector<InputUser> = Updates;
phone.discardGroupCall#7a777135 call:InputGroupCall = Updates;
phone.toggleGroupCallSettings#74bbb43d flags:# call:InputGroupCall join_muted:flags.0?Bool = Updates;

@ -1 +0,0 @@
Subproject commit 3df9f70d5947282836ea454609fc6dcc1e8f546c

View File

@ -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 <class StorerT>
void store(StorerT &storer) const {
storer.store_binary(auth_key_id_);
bool has_created_at = created_at_ != 0;
storer.store_binary(static_cast<int32>((auth_flag_ ? AUTH_FLAG : 0) | (was_auth_flag_ ? WAS_AUTH_FLAG : 0) |
(has_created_at ? HAS_CREATED_AT : 0)));
storer.store_binary(static_cast<int32>((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<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};

View File

@ -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;
}

View File

@ -22,7 +22,7 @@
#include <openssl/bn.h>
#include <openssl/opensslv.h>
#include <openssl/pem.h>
#if OPENSSL_VERSION_NUMBER < 0x30000000L
#if OPENSSL_VERSION_NUMBER < 0x30000000L || defined(LIBRESSL_VERSION_NUMBER)
#include <openssl/rsa.h>
#endif
@ -47,7 +47,7 @@ Result<RSA> RSA::from_pem_public_key(Slice pem) {
BIO_free(bio);
};
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#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);
@ -56,14 +56,14 @@ Result<RSA> RSA::from_pem_public_key(Slice pem) {
return Status::Error("Error while reading RSA public key");
}
SCOPE_EXIT {
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
EVP_PKEY_free(rsa);
#else
RSA_free(rsa);
#endif
};
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#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");
}
@ -76,7 +76,7 @@ Result<RSA> RSA::from_pem_public_key(Slice pem) {
}
#endif
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
BIGNUM *n_num = nullptr;
BIGNUM *e_num = nullptr;

View File

@ -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());

View File

@ -226,7 +226,7 @@ Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &a
auto *header = reinterpret_cast<HeaderT *>(message.begin());
*header_ptr = header;
auto to_decrypt = MutableSlice(header->encrypt_begin(), message.uend());
to_decrypt = to_decrypt.truncate(to_decrypt.size() & ~15);
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() << "]");

View File

@ -91,11 +91,11 @@ class Transport {
static size_t write(const Storer &storer, const AuthKey &auth_key, PacketInfo *info,
MutableSlice dest = MutableSlice());
static std::pair<uint32, UInt128> calc_message_key2(const AuthKey &auth_key, int X, Slice to_encrypt);
private:
template <class HeaderT>
static std::pair<uint32, UInt128> calc_message_ack_and_key(const HeaderT &head, size_t data_size);
static std::pair<uint32, UInt128> calc_message_key2(const AuthKey &auth_key, int X, Slice to_encrypt);
template <class HeaderT>
static size_t calc_crypto_size(size_t data_size);

View File

@ -310,6 +310,7 @@ bool AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_
return old_->is_changed;
}
bool need_merge = true;
auto new_it = animations_.find(new_id);
if (new_it == animations_.end() || new_it->second == nullptr) {
auto &old = animations_[old_id];
@ -328,8 +329,13 @@ bool AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_
if (old_->thumbnail != new_->thumbnail) {
// LOG_STATUS(td_->file_manager_->merge(new_->thumbnail.file_id, old_->thumbnail.file_id));
}
if (old_->mime_type == "image/gif" && new_->mime_type == "video/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);
}
@ -402,7 +408,7 @@ tl_object_ptr<telegram_api::InputMedia> AnimationsManager::get_input_media(
}
return make_tl_object<telegram_api::inputMediaUploadedDocument>(
flags, false /*ignored*/, false /*ignored*/, std::move(input_file), std::move(input_thumbnail), mime_type,
std::move(attributes), vector<tl_object_ptr<telegram_api::InputDocument>>(), 0);
std::move(attributes), std::move(added_stickers), 0);
} else {
CHECK(!file_view.has_remote_location());
}

View File

@ -729,7 +729,7 @@ void AuthManager::on_get_authorization(tl_object_ptr<telegram_api::auth_Authoriz
td->schedule_get_promo_data(0);
G()->td_db()->get_binlog_pmc()->set("fetched_marks_as_unread", "1");
} else {
send_closure(G()->state_manager(), &StateManager::on_online, true);
td->set_is_bot_online(true);
}
send_closure(G()->config_manager(), &ConfigManager::request_config);
if (query_id_ != 0) {

View File

@ -189,8 +189,8 @@ void CallActor::send_call_signaling_data(string &&data, Promise<> promise) {
auto query = G()->net_query_creator().create(
telegram_api::phone_sendSignalingData(get_input_phone_call("send_call_signaling_data"), BufferSlice(data)));
send_with_promise(std::move(query),
PromiseCreator::lambda([promise = std::move(promise)](NetQueryPtr net_query) mutable {
auto res = fetch_result<telegram_api::phone_sendSignalingData>(std::move(net_query));
PromiseCreator::lambda([promise = std::move(promise)](Result<NetQueryPtr> r_net_query) mutable {
auto res = fetch_result<telegram_api::phone_sendSignalingData>(std::move(r_net_query));
if (res.is_error()) {
promise.set_error(res.move_as_error());
} else {
@ -298,14 +298,15 @@ void CallActor::rate_call(int32 rating, string comment, vector<td_api::object_pt
auto tl_query = telegram_api::phone_setCallRating(0, false /*ignored*/, get_input_phone_call("rate_call"), rating,
std::move(comment));
auto query = G()->net_query_creator().create(tl_query);
send_with_promise(std::move(query), PromiseCreator::lambda([actor_id = actor_id(this)](NetQueryPtr net_query) {
send_closure(actor_id, &CallActor::on_set_rating_query_result, std::move(net_query));
send_with_promise(std::move(query),
PromiseCreator::lambda([actor_id = actor_id(this)](Result<NetQueryPtr> r_net_query) {
send_closure(actor_id, &CallActor::on_set_rating_query_result, std::move(r_net_query));
}));
loop();
}
void CallActor::on_set_rating_query_result(NetQueryPtr net_query) {
auto res = fetch_result<telegram_api::phone_setCallRating>(std::move(net_query));
void CallActor::on_set_rating_query_result(Result<NetQueryPtr> r_net_query) {
auto res = fetch_result<telegram_api::phone_setCallRating>(std::move(r_net_query));
if (res.is_error()) {
return on_error(res.move_as_error());
}
@ -321,14 +322,15 @@ void CallActor::send_call_debug_information(string data, Promise<> promise) {
auto tl_query = telegram_api::phone_saveCallDebug(get_input_phone_call("send_call_debug_information"),
make_tl_object<telegram_api::dataJSON>(std::move(data)));
auto query = G()->net_query_creator().create(tl_query);
send_with_promise(std::move(query), PromiseCreator::lambda([actor_id = actor_id(this)](NetQueryPtr net_query) {
send_closure(actor_id, &CallActor::on_set_debug_query_result, std::move(net_query));
send_with_promise(std::move(query),
PromiseCreator::lambda([actor_id = actor_id(this)](Result<NetQueryPtr> r_net_query) {
send_closure(actor_id, &CallActor::on_set_debug_query_result, std::move(r_net_query));
}));
loop();
}
void CallActor::on_set_debug_query_result(NetQueryPtr net_query) {
auto res = fetch_result<telegram_api::phone_saveCallDebug>(std::move(net_query));
void CallActor::on_set_debug_query_result(Result<NetQueryPtr> r_net_query) {
auto res = fetch_result<telegram_api::phone_saveCallDebug>(std::move(r_net_query));
if (res.is_error()) {
return on_error(res.move_as_error());
}
@ -603,13 +605,14 @@ void CallActor::do_load_dh_config(Promise<std::shared_ptr<DhConfig>> promise) {
void CallActor::send_received_query() {
auto tl_query = telegram_api::phone_receivedCall(get_input_phone_call("send_received_query"));
auto query = G()->net_query_creator().create(tl_query);
send_with_promise(std::move(query), PromiseCreator::lambda([actor_id = actor_id(this)](NetQueryPtr net_query) {
send_closure(actor_id, &CallActor::on_received_query_result, std::move(net_query));
send_with_promise(std::move(query),
PromiseCreator::lambda([actor_id = actor_id(this)](Result<NetQueryPtr> r_net_query) {
send_closure(actor_id, &CallActor::on_received_query_result, std::move(r_net_query));
}));
}
void CallActor::on_received_query_result(NetQueryPtr net_query) {
auto res = fetch_result<telegram_api::phone_receivedCall>(std::move(net_query));
void CallActor::on_received_query_result(Result<NetQueryPtr> r_net_query) {
auto res = fetch_result<telegram_api::phone_receivedCall>(std::move(r_net_query));
if (res.is_error()) {
return on_error(res.move_as_error());
}
@ -637,13 +640,14 @@ void CallActor::try_send_request_query() {
set_timeout_in(timeout);
query->total_timeout_limit_ = max(timeout, 10.0);
request_query_ref_ = query.get_weak();
send_with_promise(std::move(query), PromiseCreator::lambda([actor_id = actor_id(this)](NetQueryPtr net_query) {
send_closure(actor_id, &CallActor::on_request_query_result, std::move(net_query));
send_with_promise(std::move(query),
PromiseCreator::lambda([actor_id = actor_id(this)](Result<NetQueryPtr> r_net_query) {
send_closure(actor_id, &CallActor::on_request_query_result, std::move(r_net_query));
}));
}
void CallActor::on_request_query_result(NetQueryPtr net_query) {
auto res = fetch_result<telegram_api::phone_requestCall>(std::move(net_query));
void CallActor::on_request_query_result(Result<NetQueryPtr> r_net_query) {
auto res = fetch_result<telegram_api::phone_requestCall>(std::move(r_net_query));
if (res.is_error()) {
return on_error(res.move_as_error());
}
@ -666,13 +670,14 @@ void CallActor::try_send_accept_query() {
call_state_.protocol.get_input_phone_call_protocol());
auto query = G()->net_query_creator().create(tl_query);
state_ = State::WaitAcceptResult;
send_with_promise(std::move(query), PromiseCreator::lambda([actor_id = actor_id(this)](NetQueryPtr net_query) {
send_closure(actor_id, &CallActor::on_accept_query_result, std::move(net_query));
send_with_promise(std::move(query),
PromiseCreator::lambda([actor_id = actor_id(this)](Result<NetQueryPtr> r_net_query) {
send_closure(actor_id, &CallActor::on_accept_query_result, std::move(r_net_query));
}));
}
void CallActor::on_accept_query_result(NetQueryPtr net_query) {
auto res = fetch_result<telegram_api::phone_acceptCall>(std::move(net_query));
void CallActor::on_accept_query_result(Result<NetQueryPtr> r_net_query) {
auto res = fetch_result<telegram_api::phone_acceptCall>(std::move(r_net_query));
if (res.is_error()) {
return on_error(res.move_as_error());
}
@ -690,13 +695,14 @@ void CallActor::try_send_confirm_query() {
call_state_.protocol.get_input_phone_call_protocol());
auto query = G()->net_query_creator().create(tl_query);
state_ = State::WaitConfirmResult;
send_with_promise(std::move(query), PromiseCreator::lambda([actor_id = actor_id(this)](NetQueryPtr net_query) {
send_closure(actor_id, &CallActor::on_confirm_query_result, std::move(net_query));
send_with_promise(std::move(query),
PromiseCreator::lambda([actor_id = actor_id(this)](Result<NetQueryPtr> r_net_query) {
send_closure(actor_id, &CallActor::on_confirm_query_result, std::move(r_net_query));
}));
}
void CallActor::on_confirm_query_result(NetQueryPtr net_query) {
auto res = fetch_result<telegram_api::phone_confirmCall>(std::move(net_query));
void CallActor::on_confirm_query_result(Result<NetQueryPtr> r_net_query) {
auto res = fetch_result<telegram_api::phone_confirmCall>(std::move(r_net_query));
if (res.is_error()) {
return on_error(res.move_as_error());
}
@ -720,13 +726,14 @@ void CallActor::try_send_discard_query() {
get_input_phone_call_discard_reason(call_state_.discard_reason), connection_id_);
auto query = G()->net_query_creator().create(tl_query);
state_ = State::WaitDiscardResult;
send_with_promise(std::move(query), PromiseCreator::lambda([actor_id = actor_id(this)](NetQueryPtr net_query) {
send_closure(actor_id, &CallActor::on_discard_query_result, std::move(net_query));
send_with_promise(std::move(query),
PromiseCreator::lambda([actor_id = actor_id(this)](Result<NetQueryPtr> r_net_query) {
send_closure(actor_id, &CallActor::on_discard_query_result, std::move(r_net_query));
}));
}
void CallActor::on_discard_query_result(NetQueryPtr net_query) {
auto res = fetch_result<telegram_api::phone_discardCall>(std::move(net_query));
void CallActor::on_discard_query_result(Result<NetQueryPtr> r_net_query) {
auto res = fetch_result<telegram_api::phone_discardCall>(std::move(r_net_query));
if (res.is_error()) {
return on_error(res.move_as_error());
}
@ -768,13 +775,14 @@ void CallActor::flush_call_state() {
void CallActor::start_up() {
auto tl_query = telegram_api::phone_getCallConfig();
auto query = G()->net_query_creator().create(tl_query);
send_with_promise(std::move(query), PromiseCreator::lambda([actor_id = actor_id(this)](NetQueryPtr net_query) {
send_closure(actor_id, &CallActor::on_get_call_config_result, std::move(net_query));
send_with_promise(std::move(query),
PromiseCreator::lambda([actor_id = actor_id(this)](Result<NetQueryPtr> r_net_query) {
send_closure(actor_id, &CallActor::on_get_call_config_result, std::move(r_net_query));
}));
}
void CallActor::on_get_call_config_result(NetQueryPtr net_query) {
auto res = fetch_result<telegram_api::phone_getCallConfig>(std::move(net_query));
void CallActor::on_get_call_config_result(Result<NetQueryPtr> r_net_query) {
auto res = fetch_result<telegram_api::phone_getCallConfig>(std::move(r_net_query));
if (res.is_error()) {
return on_error(res.move_as_error());
}

View File

@ -164,28 +164,28 @@ class CallActor : public NetQueryCallback {
Status do_update_call(telegram_api::phoneCallDiscarded &call);
void send_received_query();
void on_received_query_result(NetQueryPtr net_query);
void on_received_query_result(Result<NetQueryPtr> r_net_query);
void try_send_request_query();
void on_request_query_result(NetQueryPtr net_query);
void on_request_query_result(Result<NetQueryPtr> r_net_query);
void try_send_accept_query();
void on_accept_query_result(NetQueryPtr net_query);
void on_accept_query_result(Result<NetQueryPtr> r_net_query);
void try_send_confirm_query();
void on_confirm_query_result(NetQueryPtr net_query);
void on_confirm_query_result(Result<NetQueryPtr> r_net_query);
void try_send_discard_query();
void on_discard_query_result(NetQueryPtr net_query);
void on_discard_query_result(Result<NetQueryPtr> r_net_query);
void on_begin_exchanging_key();
void on_call_discarded(CallDiscardReason reason, bool need_rating, bool need_debug, bool is_video);
void on_set_rating_query_result(NetQueryPtr net_query);
void on_set_debug_query_result(NetQueryPtr net_query);
void on_set_rating_query_result(Result<NetQueryPtr> r_net_query);
void on_set_debug_query_result(Result<NetQueryPtr> r_net_query);
void on_get_call_config_result(NetQueryPtr net_query);
void on_get_call_config_result(Result<NetQueryPtr> r_net_query);
void flush_call_state();

View File

@ -45,6 +45,7 @@
#include "td/utils/common.h"
#include "td/utils/crypto.h"
#include "td/utils/format.h"
#include "td/utils/HttpUrl.h"
#include "td/utils/JsonBuilder.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
@ -56,7 +57,6 @@
#include "td/utils/tl_parsers.h"
#include "td/utils/UInt.h"
#include <algorithm>
#include <functional>
#include <memory>
#include <unordered_map>
@ -100,7 +100,7 @@ Result<int32> HttpDate::to_unix_time(int32 year, int32 month, int32 day, int32 h
return res;
}
Result<int32> HttpDate::parse_http_date(std::string slice) {
Result<int32> HttpDate::parse_http_date(string slice) {
Parser p(slice);
p.read_till(','); // ignore week day
p.skip(',');
@ -434,10 +434,8 @@ ActorOwn<> get_full_config(DcOption option, Promise<FullConfig> promise, ActorSh
}
return res;
}
std::pair<AuthKeyState, bool> get_auth_key_state() override {
auto auth_key = get_auth_key();
AuthKeyState state = AuthDataShared::get_auth_key_state(auth_key);
return std::make_pair(state, auth_key.was_auth_flag());
AuthKeyState get_auth_key_state() override {
return AuthDataShared::get_auth_key_state(get_auth_key());
}
void set_auth_key(const mtproto::AuthKey &auth_key) override {
G()->td_db()->get_binlog_pmc()->set(auth_key_key(), serialize(auth_key));
@ -890,6 +888,9 @@ void ConfigManager::start_up() {
expire_time_ = expire_time;
set_timeout_in(expire_time_.in());
}
autologin_update_time_ = Time::now() - 365 * 86400;
autologin_domains_ = full_split(G()->td_db()->get_binlog_pmc()->get("autologin_domains"), '\xFF');
}
ActorShared<> ConfigManager::create_reference() {
@ -966,6 +967,60 @@ void ConfigManager::get_app_config(Promise<td_api::object_ptr<td_api::JsonValue>
}
}
void ConfigManager::get_external_link(string &&link, Promise<string> &&promise) {
if (G()->close_flag()) {
return promise.set_value(std::move(link));
}
auto r_url = parse_url(link);
if (r_url.is_error()) {
return promise.set_value(std::move(link));
}
if (!td::contains(autologin_domains_, r_url.ok().host_)) {
return promise.set_value(std::move(link));
}
if (autologin_update_time_ < Time::now() - 10000) {
auto query_promise = PromiseCreator::lambda([link = std::move(link), promise = std::move(promise)](
Result<td_api::object_ptr<td_api::JsonValue>> &&result) mutable {
if (result.is_error()) {
return promise.set_value(std::move(link));
}
send_closure(G()->config_manager(), &ConfigManager::get_external_link, std::move(link), std::move(promise));
});
return get_app_config(std::move(query_promise));
}
if (autologin_token_.empty()) {
return promise.set_value(std::move(link));
}
auto url = r_url.move_as_ok();
url.protocol_ = HttpUrl::Protocol::Https;
Slice path = url.query_;
path.truncate(url.query_.find_first_of("?#"));
Slice parameters_hash = Slice(url.query_).substr(path.size());
Slice parameters = parameters_hash;
parameters.truncate(parameters.find('#'));
Slice hash = parameters_hash.substr(parameters.size());
string added_parameter;
if (parameters.empty()) {
added_parameter = '?';
} else if (parameters.size() == 1) {
CHECK(parameters == "?");
} else {
added_parameter = '&';
}
added_parameter += "autologin_token=";
added_parameter += autologin_token_;
url.query_ = PSTRING() << path << parameters << added_parameter << hash;
promise.set_value(url.get_url());
}
void ConfigManager::get_content_settings(Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
@ -1025,7 +1080,7 @@ void ConfigManager::set_archive_and_mute(bool archive_and_mute, Promise<Unit> &&
return promise.set_error(Status::Error(500, "Request aborted"));
}
if (archive_and_mute) {
do_dismiss_suggested_action(SuggestedAction::EnableArchiveAndMuteNewChats);
remove_suggested_action(suggested_actions_, SuggestedAction{SuggestedAction::Type::EnableArchiveAndMuteNewChats});
}
last_set_archive_and_mute_ = archive_and_mute;
@ -1070,22 +1125,13 @@ void ConfigManager::do_set_ignore_sensitive_content_restrictions(bool ignore_sen
void ConfigManager::do_set_archive_and_mute(bool archive_and_mute) {
if (archive_and_mute) {
do_dismiss_suggested_action(SuggestedAction::EnableArchiveAndMuteNewChats);
remove_suggested_action(suggested_actions_, SuggestedAction{SuggestedAction::Type::EnableArchiveAndMuteNewChats});
}
G()->shared_config().set_option_boolean("archive_and_mute_new_chats_from_unknown_users", archive_and_mute);
}
td_api::object_ptr<td_api::updateSuggestedActions> ConfigManager::get_update_suggested_actions(
const vector<SuggestedAction> &added_actions, const vector<SuggestedAction> &removed_actions) {
return td_api::make_object<td_api::updateSuggestedActions>(transform(added_actions, get_suggested_action_object),
transform(removed_actions, get_suggested_action_object));
}
void ConfigManager::dismiss_suggested_action(SuggestedAction suggested_action, Promise<Unit> &&promise) {
if (suggested_action == SuggestedAction::Empty) {
return promise.set_error(Status::Error(400, "Action must be non-empty"));
}
auto action_str = get_suggested_action_str(suggested_action);
auto action_str = suggested_action.get_suggested_action_str();
if (action_str.empty()) {
return promise.set_value(Unit());
}
@ -1095,27 +1141,24 @@ void ConfigManager::dismiss_suggested_action(SuggestedAction suggested_action, P
}
dismiss_suggested_action_request_count_++;
auto &queries = dismiss_suggested_action_queries_[suggested_action];
auto type = static_cast<int32>(suggested_action.type_);
auto &queries = dismiss_suggested_action_queries_[type];
queries.push_back(std::move(promise));
if (queries.size() == 1) {
G()->net_query_dispatcher().dispatch_with_callback(
G()->net_query_creator().create(telegram_api::help_dismissSuggestion(action_str)),
actor_shared(this, 100 + static_cast<int32>(suggested_action)));
}
}
void ConfigManager::do_dismiss_suggested_action(SuggestedAction suggested_action) {
if (td::remove(suggested_actions_, suggested_action)) {
send_closure(G()->td(), &Td::send_update, get_update_suggested_actions({}, {suggested_action}));
G()->net_query_creator().create(
telegram_api::help_dismissSuggestion(make_tl_object<telegram_api::inputPeerEmpty>(), action_str)),
actor_shared(this, 100 + type));
}
}
void ConfigManager::on_result(NetQueryPtr res) {
auto token = get_link_token();
if (token >= 100 && token <= 200) {
SuggestedAction suggested_action = static_cast<SuggestedAction>(static_cast<int32>(token - 100));
auto promises = std::move(dismiss_suggested_action_queries_[suggested_action]);
dismiss_suggested_action_queries_.erase(suggested_action);
auto type = static_cast<int32>(token - 100);
SuggestedAction suggested_action{static_cast<SuggestedAction::Type>(type)};
auto promises = std::move(dismiss_suggested_action_queries_[type]);
dismiss_suggested_action_queries_.erase(type);
CHECK(!promises.empty());
CHECK(dismiss_suggested_action_request_count_ >= promises.size());
dismiss_suggested_action_request_count_ -= promises.size();
@ -1127,7 +1170,7 @@ void ConfigManager::on_result(NetQueryPtr res) {
}
return;
}
do_dismiss_suggested_action(suggested_action);
remove_suggested_action(suggested_actions_, suggested_action);
get_app_config(Auto());
for (auto &promise : promises) {
@ -1476,6 +1519,11 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
const bool archive_and_mute =
G()->shared_config().get_option_boolean("archive_and_mute_new_chats_from_unknown_users");
autologin_token_.clear();
auto old_autologin_domains = std::move(autologin_domains_);
autologin_domains_.clear();
autologin_update_time_ = Time::now();
vector<tl_object_ptr<telegram_api::jsonObjectValue>> new_values;
string ignored_restriction_reasons;
vector<string> dice_emojis;
@ -1613,10 +1661,11 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
CHECK(action != nullptr);
if (action->get_id() == telegram_api::jsonString::ID) {
Slice action_str = static_cast<telegram_api::jsonString *>(action.get())->value_;
auto suggested_action = get_suggested_action(action_str);
if (suggested_action != SuggestedAction::Empty) {
if (archive_and_mute && suggested_action == SuggestedAction::EnableArchiveAndMuteNewChats) {
LOG(INFO) << "Skip SuggestedAction::EnableArchiveAndMuteNewChats";
SuggestedAction suggested_action(action_str);
if (!suggested_action.is_empty()) {
if (archive_and_mute &&
suggested_action == SuggestedAction{SuggestedAction::Type::EnableArchiveAndMuteNewChats}) {
LOG(INFO) << "Skip EnableArchiveAndMuteNewChats suggested action";
} else {
suggested_actions.push_back(suggested_action);
}
@ -1641,6 +1690,30 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
}
continue;
}
if (key == "autologin_token") {
if (value->get_id() == telegram_api::jsonString::ID) {
autologin_token_ = url_encode(static_cast<telegram_api::jsonString *>(value)->value_);
} else {
LOG(ERROR) << "Receive unexpected autologin_token " << to_string(*value);
}
continue;
}
if (key == "autologin_domains") {
if (value->get_id() == telegram_api::jsonArray::ID) {
auto domains = std::move(static_cast<telegram_api::jsonArray *>(value)->value_);
for (auto &domain : domains) {
CHECK(domain != nullptr);
if (domain->get_id() == telegram_api::jsonString::ID) {
autologin_domains_.push_back(std::move(static_cast<telegram_api::jsonString *>(domain.get())->value_));
} else {
LOG(ERROR) << "Receive unexpected autologin domain " << to_string(domain);
}
}
} else {
LOG(ERROR) << "Receive unexpected autologin_domains " << to_string(*value);
}
continue;
}
new_values.push_back(std::move(key_value));
}
@ -1649,6 +1722,10 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
}
config = make_tl_object<telegram_api::jsonObject>(std::move(new_values));
if (autologin_domains_ != old_autologin_domains) {
G()->td_db()->get_binlog_pmc()->set("autologin_domains", implode(autologin_domains_, '\xFF'));
}
ConfigShared &shared_config = G()->shared_config();
if (ignored_restriction_reasons.empty()) {
@ -1700,34 +1777,13 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
// do not update suggested actions while changing content settings or dismissing an action
if (!is_set_content_settings_request_sent_ && dismiss_suggested_action_request_count_ == 0) {
td::unique(suggested_actions);
if (suggested_actions != suggested_actions_) {
vector<SuggestedAction> added_actions;
vector<SuggestedAction> removed_actions;
auto old_it = suggested_actions_.begin();
auto new_it = suggested_actions.begin();
while (old_it != suggested_actions_.end() || new_it != suggested_actions.end()) {
if (old_it != suggested_actions_.end() &&
(new_it == suggested_actions.end() || std::less<SuggestedAction>()(*old_it, *new_it))) {
removed_actions.push_back(*old_it++);
} else if (old_it == suggested_actions_.end() || std::less<SuggestedAction>()(*new_it, *old_it)) {
added_actions.push_back(*new_it++);
} else {
old_it++;
new_it++;
}
}
CHECK(!added_actions.empty() || !removed_actions.empty());
suggested_actions_ = std::move(suggested_actions);
send_closure(G()->td(), &Td::send_update,
get_update_suggested_actions(std::move(added_actions), std::move(removed_actions)));
}
update_suggested_actions(suggested_actions_, std::move(suggested_actions));
}
}
void ConfigManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {
if (!suggested_actions_.empty()) {
updates.push_back(get_update_suggested_actions(suggested_actions_, {}));
updates.push_back(get_update_suggested_actions_object(suggested_actions_, {}));
}
}

View File

@ -93,6 +93,8 @@ class ConfigManager : public NetQueryCallback {
void get_app_config(Promise<td_api::object_ptr<td_api::JsonValue>> &&promise);
void get_external_link(string &&link, Promise<string> &&promise);
void get_content_settings(Promise<Unit> &&promise);
void set_content_settings(bool ignore_sensitive_content_restrictions, Promise<Unit> &&promise);
@ -114,6 +116,10 @@ class ConfigManager : public NetQueryCallback {
int ref_cnt_{1};
Timestamp expire_time_;
string autologin_token_;
vector<string> autologin_domains_;
double autologin_update_time_ = 0.0;
FloodControlStrict lazy_request_flood_control_;
vector<Promise<td_api::object_ptr<td_api::JsonValue>>> get_app_config_queries_;
@ -130,7 +136,7 @@ class ConfigManager : public NetQueryCallback {
vector<SuggestedAction> suggested_actions_;
size_t dismiss_suggested_action_request_count_ = 0;
std::map<SuggestedAction, vector<Promise<Unit>>> dismiss_suggested_action_queries_;
std::map<int32, vector<Promise<Unit>>> dismiss_suggested_action_queries_;
static constexpr uint64 REFCNT_TOKEN = std::numeric_limits<uint64>::max() - 2;
@ -151,11 +157,6 @@ class ConfigManager : public NetQueryCallback {
void do_set_archive_and_mute(bool archive_and_mute);
static td_api::object_ptr<td_api::updateSuggestedActions> get_update_suggested_actions(
const vector<SuggestedAction> &added_actions, const vector<SuggestedAction> &removed_actions);
void do_dismiss_suggested_action(SuggestedAction suggested_action);
static Timestamp load_config_expire_time();
static void save_config_expire(Timestamp timestamp);
static void save_dc_options_update(DcOptions dc_options);

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,7 @@
#include "td/telegram/Contact.h"
#include "td/telegram/DialogAdministrator.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/DialogInviteLink.h"
#include "td/telegram/DialogLocation.h"
#include "td/telegram/DialogParticipant.h"
#include "td/telegram/files/FileId.h"
@ -30,6 +31,7 @@
#include "td/telegram/RestrictionReason.h"
#include "td/telegram/SecretChatId.h"
#include "td/telegram/StickerSetId.h"
#include "td/telegram/SuggestedAction.h"
#include "td/telegram/UserId.h"
#include "td/actor/actor.h"
@ -39,9 +41,9 @@
#include "td/utils/common.h"
#include "td/utils/Hints.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/Time.h"
#include <functional>
#include <memory>
@ -53,6 +55,9 @@ namespace td {
struct BinlogEvent;
class DialogInviteLink;
class DialogLocation;
class Td;
struct BotData {
@ -76,6 +81,11 @@ struct CanTransferOwnershipResult {
class ContactsManager : public Actor {
public:
ContactsManager(Td *td, ActorShared<> parent);
ContactsManager(const ContactsManager &) = delete;
ContactsManager &operator=(const ContactsManager &) = delete;
ContactsManager(ContactsManager &&) = delete;
ContactsManager &operator=(ContactsManager &&) = delete;
~ContactsManager() override;
static UserId load_my_id();
@ -160,7 +170,7 @@ class ContactsManager : public Actor {
void on_binlog_channel_event(BinlogEvent &&event);
void on_binlog_secret_chat_event(BinlogEvent &&event);
void on_get_user_full(tl_object_ptr<telegram_api::userFull> &&user_full);
void on_get_user_full(tl_object_ptr<telegram_api::userFull> &&user);
void on_get_user_photos(UserId user_id, int32 offset, int32 limit, int32 total_count,
vector<tl_object_ptr<telegram_api::Photo>> photos);
@ -206,14 +216,19 @@ class ContactsManager : public Actor {
Promise<Unit> &&promise);
void on_update_channel_default_permissions(ChannelId channel_id, RestrictedRights default_permissions);
void on_update_channel_administrator_count(ChannelId channel_id, int32 administrator_count);
void on_update_channel_participant(ChannelId channel_id, UserId user_id, int32 date,
void on_update_bot_stopped(UserId user_id, int32 date, bool is_stopped);
void on_update_chat_participant(ChatId chat_id, UserId user_id, int32 date, DialogInviteLink invite_link,
tl_object_ptr<telegram_api::ChatParticipant> old_participant,
tl_object_ptr<telegram_api::ChatParticipant> new_participant);
void on_update_channel_participant(ChannelId channel_id, UserId user_id, int32 date, DialogInviteLink invite_link,
tl_object_ptr<telegram_api::ChannelParticipant> old_participant,
tl_object_ptr<telegram_api::ChannelParticipant> new_participant);
int32 on_update_peer_located(vector<tl_object_ptr<telegram_api::PeerLocated>> &&peers, bool from_update);
void on_update_dialog_administrators(DialogId dialog_id, vector<DialogAdministrator> &&administrators,
bool have_access);
bool have_access, bool from_database);
void speculative_add_channel_participants(ChannelId channel_id, const vector<UserId> &added_user_ids,
UserId inviter_user_id, int32 date, bool by_me);
@ -224,19 +239,7 @@ class ContactsManager : public Actor {
bool on_get_channel_error(ChannelId channel_id, const Status &status, const string &source);
void on_get_channel_participants_success(ChannelId channel_id, ChannelParticipantsFilter filter, int32 offset,
int32 limit, int64 random_id, int32 total_count,
vector<tl_object_ptr<telegram_api::ChannelParticipant>> &&participants);
void on_get_channel_participants_fail(ChannelId channel_id, ChannelParticipantsFilter filter, int32 offset,
int32 limit, int64 random_id);
static Slice get_dialog_invite_link_hash(const string &invite_link);
void on_get_chat_invite_link(ChatId chat_id, tl_object_ptr<telegram_api::ExportedChatInvite> &&invite_link_ptr);
void on_get_channel_invite_link(ChannelId channel_id,
tl_object_ptr<telegram_api::ExportedChatInvite> &&invite_link_ptr);
void on_get_permanent_dialog_invite_link(DialogId dialog_id, const DialogInviteLink &invite_link);
void on_get_dialog_invite_link_info(const string &invite_link,
tl_object_ptr<telegram_api::ChatInvite> &&chat_invite_ptr,
@ -360,6 +363,8 @@ class ContactsManager : public Actor {
void toggle_channel_is_all_history_available(ChannelId channel_id, bool is_all_history_available,
Promise<Unit> &&promise);
void convert_channel_to_gigagroup(ChannelId channel_id, Promise<Unit> &&promise);
void set_channel_description(ChannelId channel_id, const string &description, Promise<Unit> &&promise);
void set_channel_discussion_group(DialogId dialog_id, DialogId discussion_dialog_id, Promise<Unit> &&promise);
@ -371,7 +376,7 @@ class ContactsManager : public Actor {
void report_channel_spam(ChannelId channel_id, UserId user_id, const vector<MessageId> &message_ids,
Promise<Unit> &&promise);
void delete_channel(ChannelId channel_id, Promise<Unit> &&promise);
void delete_dialog(DialogId dialog_id, Promise<Unit> &&promise);
void get_channel_statistics(DialogId dialog_id, bool is_dark,
Promise<td_api::object_ptr<td_api::ChatStatistics>> &&promise);
@ -384,19 +389,6 @@ class ContactsManager : public Actor {
void load_statistics_graph(DialogId dialog_id, const string &token, int64 x,
Promise<td_api::object_ptr<td_api::StatisticalGraph>> &&promise);
void add_chat_participant(ChatId chat_id, UserId user_id, int32 forward_limit, Promise<Unit> &&promise);
void add_channel_participant(ChannelId channel_id, UserId user_id, Promise<Unit> &&promise,
DialogParticipantStatus old_status = DialogParticipantStatus::Left());
void add_channel_participants(ChannelId channel_id, const vector<UserId> &user_ids, Promise<Unit> &&promise);
void change_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status,
Promise<Unit> &&promise);
void change_channel_participant_status(ChannelId channel_id, UserId user_id, DialogParticipantStatus status,
Promise<Unit> &&promise);
void can_transfer_ownership(Promise<CanTransferOwnershipResult> &&promise);
static td_api::object_ptr<td_api::CanTransferOwnershipResult> get_can_transfer_ownership_result_object(
@ -404,18 +396,37 @@ class ContactsManager : public Actor {
void transfer_dialog_ownership(DialogId dialog_id, UserId user_id, const string &password, Promise<Unit> &&promise);
void export_chat_invite_link(ChatId chat_id, Promise<Unit> &&promise);
void export_dialog_invite_link(DialogId dialog_id, int32 expire_date, int32 usage_limit, bool is_permanent,
Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise);
void export_channel_invite_link(ChannelId channel_id, Promise<Unit> &&promise);
void edit_dialog_invite_link(DialogId dialog_id, const string &link, int32 expire_date, int32 usage_limit,
Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise);
void get_dialog_invite_link(DialogId dialog_id, const string &invite_link,
Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise);
void get_dialog_invite_link_counts(DialogId dialog_id,
Promise<td_api::object_ptr<td_api::chatInviteLinkCounts>> &&promise);
void get_dialog_invite_links(DialogId dialog_id, UserId creator_user_id, bool is_revoked, int32 offset_date,
const string &offset_invite_link, int32 limit,
Promise<td_api::object_ptr<td_api::chatInviteLinks>> &&promise);
void get_dialog_invite_link_users(DialogId dialog_id, const string &invite_link,
td_api::object_ptr<td_api::chatInviteLinkMember> offset_member, int32 limit,
Promise<td_api::object_ptr<td_api::chatInviteLinkMembers>> &&promise);
void revoke_dialog_invite_link(DialogId dialog_id, const string &link,
Promise<td_api::object_ptr<td_api::chatInviteLinks>> &&promise);
void delete_revoked_dialog_invite_link(DialogId dialog_id, const string &invite_link, Promise<Unit> &&promise);
void delete_all_revoked_dialog_invite_links(DialogId dialog_id, UserId creator_user_id, Promise<Unit> &&promise);
void check_dialog_invite_link(const string &invite_link, Promise<Unit> &&promise) const;
void import_dialog_invite_link(const string &invite_link, Promise<DialogId> &&promise);
string get_chat_invite_link(ChatId chat_id) const;
string get_channel_invite_link(ChannelId channel_id);
ChannelId migrate_chat_to_megagroup(ChatId chat_id, Promise<Unit> &promise);
vector<DialogId> get_created_public_dialogs(PublicDialogType type, Promise<Unit> &&promise);
@ -426,7 +437,9 @@ class ContactsManager : public Actor {
vector<DialogId> get_inactive_channels(Promise<Unit> &&promise);
bool is_user_contact(UserId user_id) const;
void dismiss_suggested_action(SuggestedAction action, Promise<Unit> &&promise);
bool is_user_contact(UserId user_id, bool is_mutual = false) const;
bool is_user_deleted(UserId user_id) const;
@ -501,29 +514,28 @@ class ContactsManager : public Actor {
ChannelId get_channel_linked_channel_id(ChannelId channel_id);
int32 get_channel_slow_mode_delay(ChannelId channel_id);
std::pair<int32, vector<UserId>> search_among_users(const vector<UserId> &user_ids, const string &query, int32 limit);
void add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, Promise<Unit> &&promise);
DialogParticipant get_chat_participant(ChatId chat_id, UserId user_id, bool force, Promise<Unit> &&promise);
void add_dialog_participants(DialogId dialog_id, const vector<UserId> &user_ids, Promise<Unit> &&promise);
std::pair<int32, vector<DialogParticipant>> search_chat_participants(ChatId chat_id, const string &query, int32 limit,
DialogParticipantsFilter filter, bool force,
Promise<Unit> &&promise);
void set_dialog_participant_status(DialogId dialog_id, UserId user_id,
const tl_object_ptr<td_api::ChatMemberStatus> &chat_member_status,
Promise<Unit> &&promise);
DialogParticipant get_channel_participant(ChannelId channel_id, UserId user_id, int64 &random_id, bool force,
Promise<Unit> &&promise);
void ban_dialog_participant(DialogId dialog_id, UserId user_id, int32 banned_until_date, bool revoke_messages,
Promise<Unit> &&promise);
std::pair<int32, vector<DialogParticipant>> get_channel_participants(
ChannelId channel_id, const tl_object_ptr<td_api::SupergroupMembersFilter> &filter,
const string &additional_query, int32 offset, int32 limit, int32 additional_limit, int64 &random_id,
bool without_bot_info, bool force, Promise<Unit> &&promise);
DialogParticipant get_dialog_participant(DialogId dialog_id, UserId user_id, int64 &random_id, bool force,
Promise<Unit> &&promise);
void send_get_channel_participants_query(ChannelId channel_id, ChannelParticipantsFilter filter, int32 offset,
int32 limit, int64 random_id, Promise<Unit> &&promise);
void search_dialog_participants(DialogId dialog_id, const string &query, int32 limit, DialogParticipantsFilter filter,
bool without_bot_info, Promise<DialogParticipants> &&promise);
DialogParticipant get_dialog_participant(ChannelId channel_id,
tl_object_ptr<telegram_api::ChannelParticipant> &&participant_ptr) const;
vector<DialogAdministrator> get_dialog_administrators(DialogId dialog_id, int left_tries, Promise<Unit> &&promise);
vector<DialogAdministrator> get_dialog_administrators(DialogId chat_id, int left_tries, Promise<Unit> &&promise);
void get_channel_participants(ChannelId channel_id, tl_object_ptr<td_api::SupergroupMembersFilter> &&filter,
string additional_query, int32 offset, int32 limit, int32 additional_limit,
bool without_bot_info, Promise<DialogParticipants> &&promise);
int32 get_user_id_object(UserId user_id, const char *source) const;
@ -609,7 +621,7 @@ class ContactsManager : public Actor {
std::unordered_map<DialogId, int32, DialogIdHash> online_member_dialogs; // id -> time
static constexpr uint32 CACHE_VERSION = 3;
static constexpr uint32 CACHE_VERSION = 4;
uint32 cache_version = 0;
bool is_min_access_hash = true;
@ -623,6 +635,7 @@ class ContactsManager : public Actor {
bool is_inline_bot = false;
bool need_location_bot = false;
bool is_scam = false;
bool is_fake = false;
bool is_contact = false;
bool is_mutual_contact = false;
bool need_apply_min_photo = false;
@ -658,26 +671,6 @@ class ContactsManager : public Actor {
void parse(ParserT &parser);
};
struct BotInfo {
int32 version = -1;
string description;
vector<std::pair<string, string>> commands;
bool is_changed = true;
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
};
struct UserPhotos {
vector<Photo> photos;
int32 count = -1;
int32 offset = -1;
bool getting_now = false;
};
// do not forget to update drop_user_full and on_get_user_full
struct UserFull {
Photo photo;
@ -700,7 +693,9 @@ class ContactsManager : public Actor {
double expires_at = 0.0;
bool is_expired() const;
bool is_expired() const {
return expires_at < Time::now();
}
template <class StorerT>
void store(StorerT &storer) const;
@ -763,7 +758,7 @@ class ContactsManager : public Actor {
string description;
string invite_link;
DialogInviteLink invite_link;
bool can_set_username = false;
@ -789,7 +784,7 @@ class ContactsManager : public Actor {
int32 date = 0;
int32 participant_count = 0;
static constexpr uint32 CACHE_VERSION = 6;
static constexpr uint32 CACHE_VERSION = 7;
uint32 cache_version = 0;
bool has_linked_channel = false;
@ -798,8 +793,10 @@ class ContactsManager : public Actor {
bool is_slow_mode_enabled = false;
bool is_megagroup = false;
bool is_gigagroup = false;
bool is_verified = false;
bool is_scam = false;
bool is_fake = false;
bool is_title_changed = true;
bool is_username_changed = true;
@ -839,7 +836,8 @@ class ContactsManager : public Actor {
int32 administrator_count = 0;
int32 restricted_count = 0;
int32 banned_count = 0;
string invite_link;
DialogInviteLink invite_link;
uint32 speculative_version = 1;
uint32 repair_request_version = 0;
@ -874,7 +872,10 @@ class ContactsManager : public Actor {
bool need_save_to_database = true; // have new changes that need only to be saved to the database
double expires_at = 0.0;
bool is_expired() const;
bool is_expired() const {
return expires_at < Time::now();
}
template <class StorerT>
void store(StorerT &storer) const;
@ -895,6 +896,7 @@ class ContactsManager : public Actor {
bool is_outbound = false;
bool is_ttl_changed = true;
bool is_state_changed = true;
bool is_changed = true; // have new changes that need to be sent to the client and database
bool need_save_to_database = true; // have new changes that need only to be saved to the database
@ -911,6 +913,19 @@ class ContactsManager : public Actor {
void parse(ParserT &parser);
};
struct BotInfo {
int32 version = -1;
string description;
vector<std::pair<string, string>> commands;
bool is_changed = true;
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
};
struct InviteLinkInfo {
// known dialog
DialogId dialog_id;
@ -926,6 +941,13 @@ class ContactsManager : public Actor {
bool is_megagroup = false;
};
struct UserPhotos {
vector<Photo> photos;
int32 count = -1;
int32 offset = -1;
bool getting_now = false;
};
struct DialogNearby {
DialogId dialog_id;
int32 distance;
@ -981,6 +1003,7 @@ class ContactsManager : public Actor {
static constexpr int32 USER_FLAG_IS_SUPPORT = 1 << 23;
static constexpr int32 USER_FLAG_IS_SCAM = 1 << 24;
static constexpr int32 USER_FLAG_NEED_APPLY_MIN_PHOTO = 1 << 25;
static constexpr int32 USER_FLAG_IS_FAKE = 1 << 26;
static constexpr int32 USER_FULL_FLAG_IS_BLOCKED = 1 << 0;
static constexpr int32 USER_FULL_FLAG_HAS_ABOUT = 1 << 1;
@ -990,6 +1013,7 @@ class ContactsManager : public Actor {
static constexpr int32 USER_FULL_FLAG_CAN_PIN_MESSAGE = 1 << 7;
static constexpr int32 USER_FULL_FLAG_HAS_FOLDER_ID = 1 << 11;
static constexpr int32 USER_FULL_FLAG_HAS_SCHEDULED_MESSAGES = 1 << 12;
static constexpr int32 USER_FULL_FLAG_HAS_MESSAGE_TTL = 1 << 14;
static constexpr int32 CHAT_FLAG_USER_IS_CREATOR = 1 << 0;
static constexpr int32 CHAT_FLAG_USER_WAS_KICKED = 1 << 1;
@ -1005,6 +1029,7 @@ class ContactsManager : public Actor {
static constexpr int32 CHAT_FULL_FLAG_HAS_SCHEDULED_MESSAGES = 1 << 8;
static constexpr int32 CHAT_FULL_FLAG_HAS_FOLDER_ID = 1 << 11;
static constexpr int32 CHAT_FULL_FLAG_HAS_ACTIVE_GROUP_CALL = 1 << 12;
static constexpr int32 CHAT_FULL_FLAG_HAS_MESSAGE_TTL = 1 << 14;
static constexpr int32 CHANNEL_FLAG_USER_IS_CREATOR = 1 << 0;
static constexpr int32 CHANNEL_FLAG_USER_HAS_LEFT = 1 << 2;
@ -1027,6 +1052,8 @@ class ContactsManager : public Actor {
static constexpr int32 CHANNEL_FLAG_IS_SLOW_MODE_ENABLED = 1 << 22;
static constexpr int32 CHANNEL_FLAG_HAS_ACTIVE_GROUP_CALL = 1 << 23;
static constexpr int32 CHANNEL_FLAG_IS_GROUP_CALL_NON_EMPTY = 1 << 24;
static constexpr int32 CHANNEL_FLAG_IS_FAKE = 1 << 25;
static constexpr int32 CHANNEL_FLAG_IS_GIGAGROUP = 1 << 26;
static constexpr int32 CHANNEL_FULL_FLAG_HAS_PARTICIPANT_COUNT = 1 << 0;
static constexpr int32 CHANNEL_FULL_FLAG_HAS_ADMINISTRATOR_COUNT = 1 << 1;
@ -1051,6 +1078,8 @@ class ContactsManager : public Actor {
static constexpr int32 CHANNEL_FULL_FLAG_CAN_VIEW_STATISTICS = 1 << 20;
static constexpr int32 CHANNEL_FULL_FLAG_HAS_ACTIVE_GROUP_CALL = 1 << 21;
static constexpr int32 CHANNEL_FULL_FLAG_IS_BLOCKED = 1 << 22;
static constexpr int32 CHANNEL_FULL_FLAG_HAS_EXPORTED_INVITE = 1 << 23;
static constexpr int32 CHANNEL_FULL_FLAG_HAS_MESSAGE_TTL = 1 << 24;
static constexpr int32 CHAT_INVITE_FLAG_IS_CHANNEL = 1 << 0;
static constexpr int32 CHAT_INVITE_FLAG_IS_BROADCAST = 1 << 1;
@ -1065,8 +1094,6 @@ class ContactsManager : public Actor {
static constexpr int32 ACCOUNT_UPDATE_LAST_NAME = 1 << 1;
static constexpr int32 ACCOUNT_UPDATE_ABOUT = 1 << 2;
static const CSlice INVITE_LINK_URLS[3];
void memory_cleanup(bool full);
static bool have_input_peer_user(const User *u, AccessRights access_rights);
@ -1194,7 +1221,7 @@ class ContactsManager : public Actor {
void on_update_chat_full_participants(ChatFull *chat_full, ChatId chat_id, vector<DialogParticipant> participants,
int32 version, bool from_update);
void on_update_chat_full_invite_link(ChatFull *chat_full,
tl_object_ptr<telegram_api::ExportedChatInvite> &&invite_link_ptr);
tl_object_ptr<telegram_api::chatInviteExported> &&invite_link);
void on_update_channel_photo(Channel *c, ChannelId channel_id,
tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr);
@ -1207,7 +1234,7 @@ class ContactsManager : public Actor {
void on_update_channel_full_photo(ChannelFull *channel_full, ChannelId channel_id, Photo photo);
void on_update_channel_full_invite_link(ChannelFull *channel_full,
tl_object_ptr<telegram_api::ExportedChatInvite> &&invite_link_ptr);
tl_object_ptr<telegram_api::chatInviteExported> &&invite_link);
void on_update_channel_full_linked_channel_id(ChannelFull *channel_full, ChannelId channel_id,
ChannelId linked_channel_id);
void on_update_channel_full_location(ChannelFull *channel_full, ChannelId channel_id, const DialogLocation &location);
@ -1323,7 +1350,7 @@ class ContactsManager : public Actor {
bool is_chat_full_outdated(const ChatFull *chat_full, const Chat *c, ChatId chat_id);
bool is_user_contact(const User *u, UserId user_id) const;
bool is_user_contact(const User *u, UserId user_id, bool is_mutual) const;
int32 get_user_was_online(const User *u, UserId user_id) const;
@ -1350,6 +1377,10 @@ class ContactsManager : public Actor {
void on_clear_imported_contacts(vector<Contact> &&contacts, vector<size_t> contacts_unique_id,
std::pair<vector<size_t>, vector<Contact>> &&to_add, Promise<Unit> &&promise);
void send_update_chat_member(DialogId dialog_id, UserId agent_user_id, int32 date, DialogInviteLink invite_link,
const DialogParticipant &old_dialog_participant,
const DialogParticipant &new_dialog_participant);
static vector<td_api::object_ptr<td_api::chatNearby>> get_chats_nearby_object(
const vector<DialogNearby> &dialogs_nearby);
@ -1368,15 +1399,36 @@ class ContactsManager : public Actor {
static bool is_channel_public(const Channel *c);
void export_dialog_invite_link_impl(DialogId dialog_id, int32 expire_date, int32 usage_limit, bool is_permanent,
Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise);
void remove_dialog_access_by_invite_link(DialogId dialog_id);
static bool is_valid_invite_link(const string &invite_link);
Status can_manage_dialog_invite_links(DialogId dialog_id, bool creator_only = false);
bool update_invite_link(string &invite_link, tl_object_ptr<telegram_api::ExportedChatInvite> &&invite_link_ptr);
bool update_permanent_invite_link(DialogInviteLink &invite_link, DialogInviteLink new_invite_link);
void add_chat_participant(ChatId chat_id, UserId user_id, int32 forward_limit, Promise<Unit> &&promise);
void add_channel_participant(ChannelId channel_id, UserId user_id, Promise<Unit> &&promise,
DialogParticipantStatus old_status = DialogParticipantStatus::Left());
void add_channel_participants(ChannelId channel_id, const vector<UserId> &user_ids, Promise<Unit> &&promise);
const DialogParticipant *get_chat_participant(ChatId chat_id, UserId user_id) const;
static const DialogParticipant *get_chat_participant(const ChatFull *chat_full, UserId user_id);
static const DialogParticipant *get_chat_full_participant(const ChatFull *chat_full, UserId user_id);
std::pair<int32, vector<UserId>> search_among_users(const vector<UserId> &user_ids, const string &query,
int32 limit) const;
DialogParticipants search_private_chat_participants(UserId my_user_id, UserId peer_user_id, const string &query,
int32 limit, DialogParticipantsFilter filter) const;
DialogParticipant get_chat_participant(ChatId chat_id, UserId user_id, bool force, Promise<Unit> &&promise);
DialogParticipant get_channel_participant(ChannelId channel_id, UserId user_id, int64 &random_id, bool force,
Promise<Unit> &&promise);
static string get_dialog_administrators_database_key(DialogId dialog_id);
@ -1389,6 +1441,10 @@ class ContactsManager : public Actor {
void reload_dialog_administrators(DialogId dialog_id, int32 hash, Promise<Unit> &&promise);
void remove_dialog_suggested_action(SuggestedAction action);
void on_dismiss_suggested_action(SuggestedAction action, Result<Unit> &&result);
static td_api::object_ptr<td_api::updateUser> get_update_unknown_user_object(UserId user_id);
td_api::object_ptr<td_api::UserStatus> get_user_status_object(UserId user_id, const User *u) const;
@ -1429,7 +1485,28 @@ class ContactsManager : public Actor {
void update_dialogs_for_discussion(DialogId dialog_id, bool is_suitable);
void delete_chat_participant(ChatId chat_id, UserId user_id, Promise<Unit> &&promise);
void change_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status,
Promise<Unit> &&promise);
void change_channel_participant_status(ChannelId channel_id, UserId user_id, DialogParticipantStatus status,
Promise<Unit> &&promise);
void delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages, Promise<Unit> &&promise);
void search_chat_participants(ChatId chat_id, const string &query, int32 limit, DialogParticipantsFilter filter,
Promise<DialogParticipants> &&promise);
void do_search_chat_participants(ChatId chat_id, const string &query, int32 limit, DialogParticipantsFilter filter,
Promise<DialogParticipants> &&promise);
void do_get_channel_participants(ChannelId channel_id, ChannelParticipantsFilter &&filter, string additional_query,
int32 offset, int32 limit, int32 additional_limit,
Promise<DialogParticipants> &&promise);
void on_get_channel_participants(ChannelId channel_id, ChannelParticipantsFilter filter, int32 offset, int32 limit,
string additional_query, int32 additional_limit,
tl_object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
Promise<DialogParticipants> &&promise);
void change_channel_participant_status_impl(ChannelId channel_id, UserId user_id, DialogParticipantStatus status,
DialogParticipantStatus old_status, Promise<Unit> &&promise);
@ -1444,6 +1521,10 @@ class ContactsManager : public Actor {
tl_object_ptr<telegram_api::InputCheckPasswordSRP> input_check_password,
Promise<Unit> &&promise);
void delete_chat(ChatId chat_id, Promise<Unit> &&promise);
void delete_channel(ChannelId channel_id, Promise<Unit> &&promise);
void get_channel_statistics_dc_id(DialogId dialog_id, bool for_full_statistics, Promise<DcId> &&promise);
void get_channel_statistics_dc_id_impl(ChannelId channel_id, bool for_full_statistics, Promise<DcId> &&promise);
@ -1517,7 +1598,6 @@ class ContactsManager : public Actor {
std::unordered_set<string> invite_links;
int32 accessible_before = 0;
};
std::unordered_map<DialogId, string, DialogIdHash> dialog_invite_links_; // in-memory cache for invite links
std::unordered_map<string, unique_ptr<InviteLinkInfo>> invite_link_infos_;
std::unordered_map<DialogId, DialogAccessByInviteLink, DialogIdHash> dialog_access_by_invite_link_;
@ -1552,6 +1632,9 @@ class ContactsManager : public Actor {
std::unordered_map<DialogId, vector<DialogAdministrator>, DialogIdHash> dialog_administrators_;
std::unordered_map<DialogId, vector<SuggestedAction>, DialogIdHash> dialog_suggested_actions_;
std::unordered_map<DialogId, vector<Promise<Unit>>, DialogIdHash> dismiss_suggested_action_queries_;
class UploadProfilePhotoCallback;
std::shared_ptr<UploadProfilePhotoCallback> upload_profile_photo_callback_;
@ -1573,7 +1656,6 @@ class ContactsManager : public Actor {
std::unordered_map<int64, std::pair<vector<UserId>, vector<int32>>> imported_contacts_;
std::unordered_map<int64, DialogParticipant> received_channel_participant_;
std::unordered_map<int64, std::pair<int32, vector<DialogParticipant>>> received_channel_participants_;
std::unordered_map<ChannelId, vector<DialogParticipant>, ChannelIdHash> cached_channel_participants_;

View File

@ -6,6 +6,8 @@
//
#include "td/telegram/DialogAction.h"
#include "td/utils/misc.h"
namespace td {
void DialogAction::init(Type type) {
@ -14,11 +16,8 @@ void DialogAction::init(Type type) {
}
void DialogAction::init(Type type, int32 progress) {
if (progress < 0 || progress > 100) {
progress = 0;
}
type_ = type;
progress_ = progress;
progress_ = clamp(progress, 0, 100);
}
DialogAction::DialogAction(Type type, int32 progress) {
@ -140,6 +139,11 @@ DialogAction::DialogAction(tl_object_ptr<telegram_api::SendMessageAction> &&acti
case telegram_api::speakingInGroupCallAction::ID:
init(Type::SpeakingInVoiceChat);
break;
case telegram_api::sendMessageHistoryImportAction::ID: {
auto history_import_action = move_tl_object_as<telegram_api::sendMessageHistoryImportAction>(action);
init(Type::ImportingMessages, history_import_action->progress_);
break;
}
default:
UNREACHABLE();
break;
@ -176,6 +180,8 @@ tl_object_ptr<telegram_api::SendMessageAction> DialogAction::get_input_send_mess
return make_tl_object<telegram_api::sendMessageUploadRoundAction>(progress_);
case Type::SpeakingInVoiceChat:
return make_tl_object<telegram_api::speakingInGroupCallAction>();
case Type::ImportingMessages:
return make_tl_object<telegram_api::sendMessageHistoryImportAction>(progress_);
default:
UNREACHABLE();
return nullptr;
@ -212,6 +218,8 @@ tl_object_ptr<secret_api::SendMessageAction> DialogAction::get_secret_input_send
return make_tl_object<secret_api::sendMessageUploadRoundAction>();
case Type::SpeakingInVoiceChat:
return make_tl_object<secret_api::sendMessageTypingAction>();
case Type::ImportingMessages:
return make_tl_object<secret_api::sendMessageTypingAction>();
default:
UNREACHABLE();
return nullptr;
@ -246,6 +254,7 @@ tl_object_ptr<td_api::ChatAction> DialogAction::get_chat_action_object() const {
return td_api::make_object<td_api::chatActionRecordingVideoNote>();
case Type::UploadingVideoNote:
return td_api::make_object<td_api::chatActionUploadingVideoNote>(progress_);
case Type::ImportingMessages:
case Type::SpeakingInVoiceChat:
default:
UNREACHABLE();
@ -350,6 +359,13 @@ DialogAction DialogAction::get_speaking_action() {
return DialogAction(Type::SpeakingInVoiceChat, 0);
}
int32 DialogAction::get_importing_messages_action_progress() const {
if (type_ != Type::ImportingMessages) {
return -1;
}
return progress_;
}
StringBuilder &operator<<(StringBuilder &string_builder, const DialogAction &action) {
string_builder << "ChatAction";
const char *type = [action_type = action.type_] {
@ -382,6 +398,8 @@ StringBuilder &operator<<(StringBuilder &string_builder, const DialogAction &act
return "UploadingVideoNote";
case DialogAction::Type::SpeakingInVoiceChat:
return "SpeakingInVoiceChat";
case DialogAction::Type::ImportingMessages:
return "ImportingMessages";
default:
UNREACHABLE();
return "Cancel";

View File

@ -31,7 +31,8 @@ class DialogAction {
StartPlayingGame,
RecordingVideoNote,
UploadingVideoNote,
SpeakingInVoiceChat
SpeakingInVoiceChat,
ImportingMessages
};
Type type_ = Type::Cancel;
int32 progress_ = 0;
@ -63,6 +64,8 @@ class DialogAction {
static DialogAction get_speaking_action();
int32 get_importing_messages_action_progress() const;
friend bool operator==(const DialogAction &lhs, const DialogAction &rhs) {
return lhs.type_ == rhs.type_ && lhs.progress_ == rhs.progress_;
}

View File

@ -22,7 +22,7 @@ class DialogAdministrator {
string rank_;
bool is_creator_ = false;
friend StringBuilder &operator<<(StringBuilder &string_builder, const DialogAdministrator &location);
friend StringBuilder &operator<<(StringBuilder &string_builder, const DialogAdministrator &administrator);
public:
DialogAdministrator() = default;

View File

@ -0,0 +1,134 @@
//
// 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/DialogInviteLink.h"
#include "td/telegram/ContactsManager.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
namespace td {
const CSlice DialogInviteLink::INVITE_LINK_URLS[12] = {
"t.me/joinchat/", "telegram.me/joinchat/", "telegram.dog/joinchat/",
"t.me/+", "telegram.me/+", "telegram.dog/+",
"t.me/ ", "telegram.me/ ", "telegram.dog/ ",
"t.me/%20", "telegram.me/%20", "telegram.dog/%20"};
DialogInviteLink::DialogInviteLink(tl_object_ptr<telegram_api::chatInviteExported> exported_invite) {
if (exported_invite == nullptr) {
return;
}
invite_link_ = std::move(exported_invite->link_);
LOG_IF(ERROR, !is_valid_invite_link(invite_link_)) << "Unsupported invite link " << invite_link_;
creator_user_id_ = UserId(exported_invite->admin_id_);
if (!creator_user_id_.is_valid()) {
LOG(ERROR) << "Receive invalid " << creator_user_id_ << " as creator of a link " << invite_link_;
creator_user_id_ = UserId();
}
date_ = exported_invite->date_;
if (date_ < 1000000000) {
LOG(ERROR) << "Receive wrong date " << date_ << " as a creation date of a link " << invite_link_;
date_ = 0;
}
if ((exported_invite->flags_ & telegram_api::chatInviteExported::EXPIRE_DATE_MASK) != 0) {
expire_date_ = exported_invite->expire_date_;
if (expire_date_ < 1000000000) {
LOG(ERROR) << "Receive wrong date " << expire_date_ << " as an expire date of a link " << invite_link_;
expire_date_ = 0;
}
}
if ((exported_invite->flags_ & telegram_api::chatInviteExported::USAGE_LIMIT_MASK) != 0) {
usage_limit_ = exported_invite->usage_limit_;
if (usage_limit_ < 0) {
LOG(ERROR) << "Receive wrong usage limit " << usage_limit_ << " for a link " << invite_link_;
usage_limit_ = 0;
}
}
if ((exported_invite->flags_ & telegram_api::chatInviteExported::USAGE_MASK) != 0) {
usage_count_ = exported_invite->usage_;
if (usage_count_ < 0) {
LOG(ERROR) << "Receive wrong usage count " << usage_count_ << " for a link " << invite_link_;
usage_count_ = 0;
}
}
if ((exported_invite->flags_ & telegram_api::chatInviteExported::START_DATE_MASK) != 0) {
edit_date_ = exported_invite->start_date_;
if (edit_date_ < 1000000000) {
LOG(ERROR) << "Receive wrong date " << edit_date_ << " as an edit date of a link " << invite_link_;
edit_date_ = 0;
}
}
is_revoked_ = exported_invite->revoked_;
is_permanent_ = exported_invite->permanent_;
if (is_permanent_ && (usage_limit_ > 0 || expire_date_ > 0 || edit_date_ > 0)) {
LOG(ERROR) << "Receive wrong permanent " << *this;
expire_date_ = 0;
usage_limit_ = 0;
edit_date_ = 0;
}
}
bool DialogInviteLink::is_valid_invite_link(Slice invite_link) {
return !get_dialog_invite_link_hash(invite_link).empty();
}
Slice DialogInviteLink::get_dialog_invite_link_hash(Slice invite_link) {
auto lower_cased_invite_link_str = to_lower(invite_link);
Slice lower_cased_invite_link = lower_cased_invite_link_str;
size_t offset = 0;
if (begins_with(lower_cased_invite_link, "https://")) {
offset = 8;
} else if (begins_with(lower_cased_invite_link, "http://")) {
offset = 7;
}
lower_cased_invite_link.remove_prefix(offset);
for (auto &url : INVITE_LINK_URLS) {
if (begins_with(lower_cased_invite_link, url)) {
Slice hash = invite_link.substr(url.size() + offset);
hash.truncate(hash.find('#'));
hash.truncate(hash.find('?'));
return hash;
}
}
return Slice();
}
td_api::object_ptr<td_api::chatInviteLink> DialogInviteLink::get_chat_invite_link_object(
const ContactsManager *contacts_manager) const {
CHECK(contacts_manager != nullptr);
if (!is_valid()) {
return nullptr;
}
return td_api::make_object<td_api::chatInviteLink>(
invite_link_, contacts_manager->get_user_id_object(creator_user_id_, "get_chat_invite_link_object"), date_,
edit_date_, expire_date_, usage_limit_, usage_count_, is_permanent_, is_revoked_);
}
bool operator==(const DialogInviteLink &lhs, const DialogInviteLink &rhs) {
return lhs.invite_link_ == rhs.invite_link_ && lhs.creator_user_id_ == rhs.creator_user_id_ &&
lhs.date_ == rhs.date_ && lhs.edit_date_ == rhs.edit_date_ && lhs.expire_date_ == rhs.expire_date_ &&
lhs.usage_limit_ == rhs.usage_limit_ && lhs.usage_count_ == rhs.usage_count_ &&
lhs.is_permanent_ == rhs.is_permanent_ && lhs.is_revoked_ == rhs.is_revoked_;
}
bool operator!=(const DialogInviteLink &lhs, const DialogInviteLink &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const DialogInviteLink &invite_link) {
return string_builder << "ChatInviteLink[" << invite_link.invite_link_ << " by " << invite_link.creator_user_id_
<< " created at " << invite_link.date_ << " edited at " << invite_link.edit_date_
<< " expiring at " << invite_link.expire_date_ << " used by " << invite_link.usage_count_
<< " with usage limit " << invite_link.usage_limit_ << "]";
}
} // namespace td

View File

@ -0,0 +1,137 @@
//
// 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/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
#include "td/utils/common.h"
#include "td/utils/Slice.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/tl_helpers.h"
namespace td {
class ContactsManager;
class DialogInviteLink {
string invite_link_;
UserId creator_user_id_;
int32 date_ = 0;
int32 edit_date_ = 0;
int32 expire_date_ = 0;
int32 usage_limit_ = 0;
int32 usage_count_ = 0;
bool is_revoked_ = false;
bool is_permanent_ = false;
friend bool operator==(const DialogInviteLink &lhs, const DialogInviteLink &rhs);
friend StringBuilder &operator<<(StringBuilder &string_builder, const DialogInviteLink &invite_link);
static const CSlice INVITE_LINK_URLS[12];
public:
DialogInviteLink() = default;
explicit DialogInviteLink(tl_object_ptr<telegram_api::chatInviteExported> exported_invite);
static bool is_valid_invite_link(Slice invite_link);
static Slice get_dialog_invite_link_hash(Slice invite_link);
td_api::object_ptr<td_api::chatInviteLink> get_chat_invite_link_object(const ContactsManager *contacts_manager) const;
bool is_valid() const {
return !invite_link_.empty() && creator_user_id_.is_valid() && date_ > 0;
}
bool is_permanent() const {
return is_permanent_;
}
const string &get_invite_link() const {
return invite_link_;
}
UserId get_creator_user_id() const {
return creator_user_id_;
}
template <class StorerT>
void store(StorerT &storer) const {
using td::store;
bool has_expire_date = expire_date_ != 0;
bool has_usage_limit = usage_limit_ != 0;
bool has_usage_count = usage_count_ != 0;
bool has_edit_date = edit_date_ != 0;
BEGIN_STORE_FLAGS();
STORE_FLAG(is_revoked_);
STORE_FLAG(is_permanent_);
STORE_FLAG(has_expire_date);
STORE_FLAG(has_usage_limit);
STORE_FLAG(has_usage_count);
STORE_FLAG(has_edit_date);
END_STORE_FLAGS();
store(invite_link_, storer);
store(creator_user_id_, storer);
store(date_, storer);
if (has_expire_date) {
store(expire_date_, storer);
}
if (has_usage_limit) {
store(usage_limit_, storer);
}
if (has_usage_count) {
store(usage_count_, storer);
}
if (has_edit_date) {
store(edit_date_, storer);
}
}
template <class ParserT>
void parse(ParserT &parser) {
using td::parse;
bool has_expire_date;
bool has_usage_limit;
bool has_usage_count;
bool has_edit_date;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_revoked_);
PARSE_FLAG(is_permanent_);
PARSE_FLAG(has_expire_date);
PARSE_FLAG(has_usage_limit);
PARSE_FLAG(has_usage_count);
PARSE_FLAG(has_edit_date);
END_PARSE_FLAGS();
parse(invite_link_, parser);
parse(creator_user_id_, parser);
parse(date_, parser);
if (has_expire_date) {
parse(expire_date_, parser);
}
if (has_usage_limit) {
parse(usage_limit_, parser);
}
if (has_usage_count) {
parse(usage_count_, parser);
}
if (has_edit_date) {
parse(edit_date_, parser);
}
}
};
bool operator==(const DialogInviteLink &lhs, const DialogInviteLink &rhs);
bool operator!=(const DialogInviteLink &lhs, const DialogInviteLink &rhs);
StringBuilder &operator<<(StringBuilder &string_builder, const DialogInviteLink &invite_link);
} // namespace td

View File

@ -6,8 +6,10 @@
//
#include "td/telegram/DialogParticipant.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/misc.h"
#include "td/telegram/Td.h"
#include "td/utils/common.h"
#include "td/utils/logging.h"
@ -35,12 +37,13 @@ DialogParticipantStatus DialogParticipantStatus::Creator(bool is_member, bool is
}
DialogParticipantStatus DialogParticipantStatus::Administrator(bool is_anonymous, string rank, bool 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 can_manage_calls) {
bool can_manage_dialog, 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_calls) {
uint32 flags = (static_cast<uint32>(can_be_edited) * CAN_BE_EDITED) |
(static_cast<uint32>(can_manage_dialog) * CAN_MANAGE_DIALOG) |
(static_cast<uint32>(can_change_info) * CAN_CHANGE_INFO_AND_SETTINGS_ADMIN) |
(static_cast<uint32>(can_post_messages) * CAN_POST_MESSAGES) |
(static_cast<uint32>(can_edit_messages) * CAN_EDIT_MESSAGES) |
@ -54,6 +57,7 @@ DialogParticipantStatus DialogParticipantStatus::Administrator(bool is_anonymous
if (flags == 0 || flags == CAN_BE_EDITED) {
return Member();
}
flags |= CAN_MANAGE_DIALOG;
return DialogParticipantStatus(Type::Administrator, IS_MEMBER | ALL_RESTRICTED_RIGHTS | flags, 0, std::move(rank));
}
@ -92,14 +96,14 @@ DialogParticipantStatus DialogParticipantStatus::Banned(int32 banned_until_date)
}
DialogParticipantStatus DialogParticipantStatus::GroupAdministrator(bool is_creator) {
return Administrator(false, string(), is_creator, true, false, false, true, true, true, true, false, true);
return Administrator(false, string(), is_creator, true, true, false, false, true, true, true, true, false, true);
}
DialogParticipantStatus DialogParticipantStatus::ChannelAdministrator(bool is_creator, bool is_megagroup) {
if (is_megagroup) {
return Administrator(false, string(), is_creator, true, false, false, true, true, true, true, false, false);
return Administrator(false, string(), is_creator, true, true, false, false, true, true, true, true, false, false);
} else {
return Administrator(false, string(), is_creator, false, true, true, true, false, true, false, false, false);
return Administrator(false, string(), is_creator, true, false, true, true, true, false, true, false, false, false);
}
}
@ -115,9 +119,9 @@ tl_object_ptr<td_api::ChatMemberStatus> DialogParticipantStatus::get_chat_member
return td_api::make_object<td_api::chatMemberStatusCreator>(rank_, is_anonymous(), is_member());
case Type::Administrator:
return td_api::make_object<td_api::chatMemberStatusAdministrator>(
rank_, can_be_edited(), can_change_info_and_settings(), can_post_messages(), can_edit_messages(),
can_delete_messages(), can_invite_users(), can_restrict_members(), can_pin_messages(), can_promote_members(),
can_manage_calls(), is_anonymous());
rank_, can_be_edited(), can_manage_dialog(), can_change_info_and_settings(), can_post_messages(),
can_edit_messages(), can_delete_messages(), can_invite_users(), can_restrict_members(), can_pin_messages(),
can_promote_members(), can_manage_calls(), is_anonymous());
case Type::Member:
return td_api::make_object<td_api::chatMemberStatusMember>();
case Type::Restricted:
@ -165,11 +169,14 @@ tl_object_ptr<telegram_api::chatAdminRights> DialogParticipantStatus::get_chat_a
if (is_anonymous()) {
flags |= telegram_api::chatAdminRights::ANONYMOUS_MASK;
}
if (can_manage_dialog()) {
flags |= telegram_api::chatAdminRights::OTHER_MASK;
}
LOG(INFO) << "Create chat admin rights " << flags;
return make_tl_object<telegram_api::chatAdminRights>(
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/);
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/);
}
tl_object_ptr<telegram_api::chatBannedRights> DialogParticipantStatus::get_chat_banned_rights() const {
@ -295,6 +302,9 @@ StringBuilder &operator<<(StringBuilder &string_builder, const DialogParticipant
return string_builder;
case DialogParticipantStatus::Type::Administrator:
string_builder << "Administrator: ";
if (status.can_manage_dialog()) {
string_builder << "(manage)";
}
if (status.can_change_info_and_settings()) {
string_builder << "(change)";
}
@ -402,7 +412,7 @@ DialogParticipantStatus get_dialog_participant_status(const tl_object_ptr<td_api
case td_api::chatMemberStatusAdministrator::ID: {
auto st = static_cast<const td_api::chatMemberStatusAdministrator *>(status.get());
return DialogParticipantStatus::Administrator(
st->is_anonymous_, st->custom_title_, true /*st->can_be_edited_*/, st->can_change_info_,
st->is_anonymous_, st->custom_title_, true /*st->can_be_edited_*/, st->can_manage_chat_, st->can_change_info_,
st->can_post_messages_, st->can_edit_messages_, st->can_delete_messages_, st->can_invite_users_,
st->can_restrict_members_, st->can_pin_messages_, st->can_promote_members_, st->can_manage_voice_chats_);
}
@ -447,10 +457,14 @@ DialogParticipantStatus get_dialog_participant_status(bool can_be_edited,
bool can_promote_members = (admin_rights->flags_ & telegram_api::chatAdminRights::ADD_ADMINS_MASK) != 0;
bool can_manage_calls = (admin_rights->flags_ & telegram_api::chatAdminRights::MANAGE_CALL_MASK) != 0;
bool is_anonymous = (admin_rights->flags_ & telegram_api::chatAdminRights::ANONYMOUS_MASK) != 0;
return DialogParticipantStatus::Administrator(is_anonymous, std::move(rank), can_be_edited, can_change_info,
can_post_messages, can_edit_messages, can_delete_messages,
can_invite_users, can_restrict_members, can_pin_messages,
can_promote_members, can_manage_calls);
bool can_manage_dialog = (admin_rights->flags_ & telegram_api::chatAdminRights::OTHER_MASK) != 0;
if (!can_manage_dialog) {
LOG(ERROR) << "Receive wrong other flag in " << to_string(admin_rights);
}
return DialogParticipantStatus::Administrator(is_anonymous, std::move(rank), can_be_edited, can_manage_dialog,
can_change_info, can_post_messages, can_edit_messages,
can_delete_messages, can_invite_users, can_restrict_members,
can_pin_messages, can_promote_members, can_manage_calls);
}
DialogParticipantStatus get_dialog_participant_status(
@ -641,8 +655,33 @@ DialogParticipant::DialogParticipant(UserId user_id, UserId inviter_user_id, int
}
}
DialogParticipant::DialogParticipant(tl_object_ptr<telegram_api::ChannelParticipant> &&participant_ptr,
DialogParticipantStatus my_status) {
DialogParticipant::DialogParticipant(tl_object_ptr<telegram_api::ChatParticipant> &&participant_ptr,
int32 chat_creation_date, bool is_creator) {
switch (participant_ptr->get_id()) {
case telegram_api::chatParticipant::ID: {
auto participant = move_tl_object_as<telegram_api::chatParticipant>(participant_ptr);
*this = {UserId(participant->user_id_), UserId(participant->inviter_id_), participant->date_,
DialogParticipantStatus::Member()};
break;
}
case telegram_api::chatParticipantCreator::ID: {
auto participant = move_tl_object_as<telegram_api::chatParticipantCreator>(participant_ptr);
*this = {UserId(participant->user_id_), UserId(participant->user_id_), chat_creation_date,
DialogParticipantStatus::Creator(true, false, string())};
break;
}
case telegram_api::chatParticipantAdmin::ID: {
auto participant = move_tl_object_as<telegram_api::chatParticipantAdmin>(participant_ptr);
*this = {UserId(participant->user_id_), UserId(participant->inviter_id_), participant->date_,
DialogParticipantStatus::GroupAdministrator(is_creator)};
break;
}
default:
UNREACHABLE();
}
}
DialogParticipant::DialogParticipant(tl_object_ptr<telegram_api::ChannelParticipant> &&participant_ptr) {
CHECK(participant_ptr != nullptr);
switch (participant_ptr->get_id()) {
case telegram_api::channelParticipant::ID: {
@ -653,7 +692,7 @@ DialogParticipant::DialogParticipant(tl_object_ptr<telegram_api::ChannelParticip
case telegram_api::channelParticipantSelf::ID: {
auto participant = move_tl_object_as<telegram_api::channelParticipantSelf>(participant_ptr);
*this = {UserId(participant->user_id_), UserId(participant->inviter_id_), participant->date_,
std::move(my_status)};
DialogParticipantStatus::Member()};
break;
}
case telegram_api::channelParticipantCreator::ID: {
@ -705,6 +744,16 @@ StringBuilder &operator<<(StringBuilder &string_builder, const DialogParticipant
<< ']';
}
td_api::object_ptr<td_api::chatMembers> DialogParticipants::get_chat_members_object(Td *td) const {
vector<tl_object_ptr<td_api::chatMember>> chat_members;
chat_members.reserve(participants_.size());
for (auto &participant : participants_) {
chat_members.push_back(td->contacts_manager_->get_chat_member_object(participant));
}
return td_api::make_object<td_api::chatMembers>(total_count_, std::move(chat_members));
}
tl_object_ptr<telegram_api::ChannelParticipantsFilter>
ChannelParticipantsFilter::get_input_channel_participants_filter() const {
switch (type) {
@ -721,7 +770,7 @@ ChannelParticipantsFilter::get_input_channel_participants_filter() const {
if (!query.empty()) {
flags |= telegram_api::channelParticipantsMentions::Q_MASK;
}
if (!top_thread_message_id.is_valid()) {
if (top_thread_message_id.is_valid()) {
flags |= telegram_api::channelParticipantsMentions::TOP_MSG_ID_MASK;
}
return make_tl_object<telegram_api::channelParticipantsMentions>(

View File

@ -17,6 +17,8 @@
namespace td {
class Td;
class RestrictedRights {
static constexpr uint32 CAN_SEND_MESSAGES = 1 << 16;
static constexpr uint32 CAN_SEND_MEDIA = 1 << 17;
@ -119,6 +121,7 @@ class DialogParticipantStatus {
static constexpr uint32 CAN_PIN_MESSAGES_ADMIN = 1 << 7;
static constexpr uint32 CAN_PROMOTE_MEMBERS = 1 << 8;
static constexpr uint32 CAN_MANAGE_CALLS = 1 << 9;
static constexpr uint32 CAN_MANAGE_DIALOG = 1 << 10;
static constexpr uint32 CAN_BE_EDITED = 1 << 15;
@ -142,9 +145,10 @@ class DialogParticipantStatus {
static constexpr int TYPE_SHIFT = 28;
static constexpr uint32 HAS_UNTIL_DATE = 1u << 31;
static constexpr uint32 ALL_ADMINISTRATOR_RIGHTS =
CAN_CHANGE_INFO_AND_SETTINGS_ADMIN | CAN_POST_MESSAGES | CAN_EDIT_MESSAGES | CAN_DELETE_MESSAGES |
CAN_INVITE_USERS_ADMIN | CAN_RESTRICT_MEMBERS | CAN_PIN_MESSAGES_ADMIN | CAN_PROMOTE_MEMBERS | CAN_MANAGE_CALLS;
static constexpr uint32 ALL_ADMINISTRATOR_RIGHTS = CAN_CHANGE_INFO_AND_SETTINGS_ADMIN | CAN_POST_MESSAGES |
CAN_EDIT_MESSAGES | CAN_DELETE_MESSAGES | CAN_INVITE_USERS_ADMIN |
CAN_RESTRICT_MEMBERS | CAN_PIN_MESSAGES_ADMIN |
CAN_PROMOTE_MEMBERS | CAN_MANAGE_CALLS | CAN_MANAGE_DIALOG;
static constexpr uint32 ALL_ADMIN_PERMISSION_RIGHTS =
CAN_CHANGE_INFO_AND_SETTINGS_BANNED | CAN_INVITE_USERS_BANNED | CAN_PIN_MESSAGES_BANNED;
@ -169,9 +173,10 @@ class DialogParticipantStatus {
public:
static DialogParticipantStatus Creator(bool is_member, bool is_anonymous, string rank);
static DialogParticipantStatus Administrator(bool is_anonymous, string rank, bool 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,
static DialogParticipantStatus Administrator(bool is_anonymous, string rank, bool can_be_edited,
bool can_manage_dialog, 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_calls);
static DialogParticipantStatus Member();
@ -206,6 +211,10 @@ class DialogParticipantStatus {
// unrestricts user if restriction time expired. Should be called before all privileges checks
void update_restrictions() const;
bool can_manage_dialog() const {
return (flags_ & CAN_MANAGE_DIALOG) != 0;
}
bool can_change_info_and_settings() const {
return (flags_ & CAN_CHANGE_INFO_AND_SETTINGS_ADMIN) != 0 || (flags_ & CAN_CHANGE_INFO_AND_SETTINGS_BANNED) != 0;
}
@ -357,6 +366,8 @@ class DialogParticipantStatus {
if (is_creator()) {
flags_ |= ALL_ADMINISTRATOR_RIGHTS | ALL_PERMISSION_RIGHTS;
} else if (is_administrator()) {
flags_ |= CAN_MANAGE_DIALOG;
}
}
@ -381,8 +392,10 @@ struct DialogParticipant {
DialogParticipant(UserId user_id, UserId inviter_user_id, int32 joined_date, DialogParticipantStatus status);
DialogParticipant(tl_object_ptr<telegram_api::ChannelParticipant> &&participant_ptr,
DialogParticipantStatus my_status);
DialogParticipant(tl_object_ptr<telegram_api::ChatParticipant> &&participant_ptr, int32 chat_creation_date,
bool is_creator);
explicit DialogParticipant(tl_object_ptr<telegram_api::ChannelParticipant> &&participant_ptr);
static DialogParticipant left(UserId user_id) {
return {user_id, UserId(), 0, DialogParticipantStatus::Left()};
@ -409,6 +422,18 @@ struct DialogParticipant {
StringBuilder &operator<<(StringBuilder &string_builder, const DialogParticipant &dialog_participant);
struct DialogParticipants {
int32 total_count_ = 0;
vector<DialogParticipant> participants_;
DialogParticipants() = default;
DialogParticipants(int32 total_count, vector<DialogParticipant> &&participants)
: total_count_(total_count), participants_(std::move(participants)) {
}
td_api::object_ptr<td_api::chatMembers> get_chat_members_object(Td *td) const;
};
class ChannelParticipantsFilter {
enum class Type : int32 { Recent, Contacts, Administrators, Search, Mention, Restricted, Banned, Bots } type;
string query;

View File

@ -82,7 +82,7 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
switch (attribute->get_id()) {
case telegram_api::documentAttributeImageSize::ID: {
auto image_size = move_tl_object_as<telegram_api::documentAttributeImageSize>(attribute);
dimensions = get_dimensions(image_size->w_, image_size->h_);
dimensions = get_dimensions(image_size->w_, image_size->h_, "documentAttributeImageSize");
break;
}
case telegram_api::documentAttributeAnimated::ID:
@ -114,8 +114,12 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
int32 video_duration = 0;
if (video != nullptr) {
video_duration = video->duration_;
if (dimensions.width == 0) {
dimensions = get_dimensions(video->w_, video->h_);
auto video_dimensions = get_dimensions(video->w_, video->h_, "documentAttributeVideo");
if (dimensions.width == 0 || (video_dimensions.width != 0 && video_dimensions != dimensions)) {
if (dimensions.width != 0) {
LOG(ERROR) << "Receive ambiguous video dimensions " << dimensions << " and " << video_dimensions;
}
dimensions = video_dimensions;
}
if (animated != nullptr) {
@ -167,9 +171,6 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
default_extension = Slice("webp");
owner_dialog_id = DialogId();
file_name.clear();
if (td_->stickers_manager_->has_webp_thumbnail(sticker) && remote_document.secret_file == nullptr) {
thumbnail_format = PhotoFormat::Webp;
}
} else if (video != nullptr || default_document_type == Document::Type::Video ||
default_document_type == Document::Type::VideoNote) {
bool is_video_note = default_document_type == Document::Type::VideoNote;
@ -252,6 +253,9 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
mime_type = std::move(document->mime_type_);
file_reference = document->file_reference_.as_slice().str();
if (document_type == Document::Type::Sticker && StickersManager::has_webp_thumbnail(document->thumbs_)) {
thumbnail_format = PhotoFormat::Webp;
}
fix_animated_sticker_type();
if (owner_dialog_id.get_type() == DialogType::SecretChat) {
@ -265,9 +269,9 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
if (document_type != Document::Type::VoiceNote) {
for (auto &thumb : document->thumbs_) {
auto photo_size = get_photo_size(td_->file_manager_.get(), {FileType::Thumbnail, 0}, id, access_hash,
file_reference, DcId::create(dc_id), owner_dialog_id, std::move(thumb),
thumbnail_format, document_type != Document::Type::Sticker);
auto photo_size =
get_photo_size(td_->file_manager_.get(), {FileType::Thumbnail, 0}, id, access_hash, file_reference,
DcId::create(dc_id), owner_dialog_id, std::move(thumb), thumbnail_format);
if (photo_size.get_offset() == 0) {
if (!thumbnail.file_id.is_valid()) {
thumbnail = std::move(photo_size.get<0>());
@ -435,6 +439,9 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
std::move(mime_type), !is_web);
break;
case Document::Type::Sticker:
if (thumbnail_format == PhotoFormat::Jpeg) {
minithumbnail = string();
}
td_->stickers_manager_->create_sticker(file_id, std::move(minithumbnail), std::move(thumbnail), dimensions,
std::move(sticker), is_animated_sticker, load_data_multipromise_ptr);
break;

View File

@ -215,7 +215,7 @@ DcId Global::get_webfile_dc_id() const {
return DcId::internal(dc_id);
}
bool Global::ignore_backgrond_updates() const {
bool Global::ignore_background_updates() const {
return !parameters_.use_file_db && !parameters_.use_secret_chats &&
shared_config_->get_option_boolean("ignore_background_updates");
}

View File

@ -101,7 +101,7 @@ class Global : public ActorContext {
return parameters_.use_test_dc;
}
bool ignore_backgrond_updates() const;
bool ignore_background_updates() const;
NetQueryCreator &net_query_creator() {
return *net_query_creator_.get();

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@
#pragma once
#include "td/telegram/DialogId.h"
#include "td/telegram/DialogParticipant.h"
#include "td/telegram/GroupCallId.h"
#include "td/telegram/GroupCallParticipant.h"
#include "td/telegram/InputGroupCallId.h"
@ -51,20 +52,24 @@ class GroupCallManager : public Actor {
void reload_group_call(InputGroupCallId input_group_call_id,
Promise<td_api::object_ptr<td_api::groupCall>> &&promise);
void join_group_call(GroupCallId group_call_id, td_api::object_ptr<td_api::groupCallPayload> &&payload, int32 source,
bool is_muted, Promise<td_api::object_ptr<td_api::groupCallJoinResponse>> &&promise);
void join_group_call(GroupCallId group_call_id, td_api::object_ptr<td_api::groupCallPayload> &&payload,
int32 audio_source, bool is_muted,
Promise<td_api::object_ptr<td_api::groupCallJoinResponse>> &&promise);
void toggle_group_call_mute_new_participants(GroupCallId group_call_id, bool mute_new_participants,
Promise<Unit> &&promise);
void invite_group_call_participants(GroupCallId group_call_id, vector<UserId> &&user_ids, Promise<Unit> &&promise);
void set_group_call_participant_is_speaking(GroupCallId group_call_id, int32 source, bool is_speaking,
void set_group_call_participant_is_speaking(GroupCallId group_call_id, int32 audio_source, bool is_speaking,
Promise<Unit> &&promise, int32 date = 0);
void toggle_group_call_participant_is_muted(GroupCallId group_call_id, UserId user_id, bool is_muted,
Promise<Unit> &&promise);
void set_group_call_participant_volume_level(GroupCallId group_call_id, UserId user_id, int32 volume_level,
Promise<Unit> &&promise);
void load_group_call_participants(GroupCallId group_call_id, int32 limit, Promise<Unit> &&promise);
void leave_group_call(GroupCallId group_call_id, Promise<Unit> &&promise);
@ -133,16 +138,23 @@ class GroupCallManager : public Actor {
void finish_get_group_call(InputGroupCallId input_group_call_id,
Result<tl_object_ptr<telegram_api::phone_groupCall>> &&result);
void finish_check_group_call_is_joined(InputGroupCallId input_group_call_id, int32 source, Result<Unit> &&result);
void finish_check_group_call_is_joined(InputGroupCallId input_group_call_id, int32 audio_source,
Result<Unit> &&result);
static bool get_group_call_mute_new_participants(const GroupCall *group_call);
bool need_group_call_participants(InputGroupCallId input_group_call_id) const;
bool need_group_call_participants(InputGroupCallId input_group_call_id, const GroupCall *group_call) const;
bool process_pending_group_call_participant_updates(InputGroupCallId input_group_call_id);
void sync_group_call_participants(InputGroupCallId input_group_call_id);
void on_sync_group_call_participants_failed(InputGroupCallId input_group_call_id);
int64 get_real_participant_order(const GroupCallParticipant &participant, int64 min_order) const;
void process_group_call_participants(InputGroupCallId group_call_id,
vector<tl_object_ptr<telegram_api::groupCallParticipant>> &&participants,
bool is_load, bool is_sync);
@ -157,22 +169,42 @@ class GroupCallManager : public Actor {
void try_load_group_call_administrators(InputGroupCallId input_group_call_id, DialogId dialog_id);
void finish_load_group_call_administrators(InputGroupCallId input_group_call_id, int64 random_id,
Result<Unit> &&result);
void finish_load_group_call_administrators(InputGroupCallId input_group_call_id, Result<DialogParticipants> &&result);
int32 cancel_join_group_call_request(InputGroupCallId input_group_call_id);
bool on_join_group_call_response(InputGroupCallId input_group_call_id, string json_response);
void finish_join_group_call(InputGroupCallId input_group_call_id, uint64 generation, Status error);
void process_group_call_after_join_requests(InputGroupCallId input_group_call_id);
GroupCallParticipants *add_group_call_participants(InputGroupCallId input_group_call_id);
void on_group_call_left(InputGroupCallId input_group_call_id, int32 source, bool need_rejoin);
GroupCallParticipant *get_group_call_participant(InputGroupCallId input_group_call_id, UserId user_id);
static GroupCallParticipant *get_group_call_participant(GroupCallParticipants *group_call_participants,
UserId user_id);
void send_toggle_group_call_mute_new_participants_query(InputGroupCallId input_group_call_id,
bool mute_new_participants);
void on_toggle_group_call_mute_new_participants(InputGroupCallId input_group_call_id, bool mute_new_participants,
Result<Unit> &&result);
void on_toggle_group_call_participant_is_muted(InputGroupCallId input_group_call_id, UserId user_id,
uint64 generation, Promise<Unit> &&promise);
void on_set_group_call_participant_volume_level(InputGroupCallId input_group_call_id, UserId user_id,
uint64 generation, Promise<Unit> &&promise);
void on_group_call_left(InputGroupCallId input_group_call_id, int32 audio_source, bool need_rejoin);
void on_group_call_left_impl(GroupCall *group_call, bool need_rejoin);
InputGroupCallId update_group_call(const tl_object_ptr<telegram_api::GroupCall> &group_call_ptr, DialogId dialog_id);
void on_receive_group_call_version(InputGroupCallId input_group_call_id, int32 version);
void on_receive_group_call_version(InputGroupCallId input_group_call_id, int32 version, bool immediate_sync = false);
void on_participant_speaking_in_group_call(InputGroupCallId input_group_call_id,
const GroupCallParticipant &participant);
@ -181,7 +213,7 @@ class GroupCallManager : public Actor {
void on_group_call_recent_speakers_updated(const GroupCall *group_call, GroupCallRecentSpeakers *recent_speakers);
UserId set_group_call_participant_is_speaking_by_source(InputGroupCallId input_group_call_id, int32 source,
UserId set_group_call_participant_is_speaking_by_source(InputGroupCallId input_group_call_id, int32 audio_source,
bool is_speaking, int32 date);
static Result<td_api::object_ptr<td_api::groupCallJoinResponse>> get_group_call_join_response_object(
@ -230,6 +262,10 @@ class GroupCallManager : public Actor {
std::unordered_map<InputGroupCallId, unique_ptr<PendingJoinRequest>, InputGroupCallIdHash> pending_join_requests_;
uint64 join_group_request_generation_ = 0;
uint64 set_volume_level_generation_ = 0;
uint64 toggle_is_muted_generation_ = 0;
MultiTimeout check_group_call_is_joined_timeout_{"CheckGroupCallIsJoinedTimeout"};
MultiTimeout pending_send_speaking_action_timeout_{"PendingSendSpeakingActionTimeout"};
MultiTimeout recent_speaker_update_timeout_{"RecentSpeakerUpdateTimeout"};

View File

@ -15,9 +15,18 @@ namespace td {
GroupCallParticipant::GroupCallParticipant(const tl_object_ptr<telegram_api::groupCallParticipant> &participant) {
CHECK(participant != nullptr);
user_id = UserId(participant->user_id_);
source = participant->source_;
is_muted = participant->muted_;
can_self_unmute = participant->can_self_unmute_;
audio_source = participant->source_;
server_is_muted_by_themselves = participant->can_self_unmute_;
server_is_muted_by_admin = participant->muted_ && !participant->can_self_unmute_;
server_is_muted_locally = participant->muted_by_you_;
if ((participant->flags_ & telegram_api::groupCallParticipant::VOLUME_MASK) != 0) {
volume_level = participant->volume_;
if (volume_level < MIN_VOLUME_LEVEL || volume_level > MAX_VOLUME_LEVEL) {
LOG(ERROR) << "Receive " << to_string(participant);
volume_level = 10000;
}
is_volume_level_local = (participant->flags_ & telegram_api::groupCallParticipant::VOLUME_BY_ADMIN_MASK) == 0;
}
if (!participant->left_) {
joined_date = participant->date_;
if ((participant->flags_ & telegram_api::groupCallParticipant::ACTIVE_DATE_MASK) != 0) {
@ -30,38 +39,168 @@ GroupCallParticipant::GroupCallParticipant(const tl_object_ptr<telegram_api::gro
}
}
is_just_joined = participant->just_joined_;
is_min = (participant->flags_ & telegram_api::groupCallParticipant::MIN_MASK) != 0;
}
bool GroupCallParticipant::is_versioned_update(const tl_object_ptr<telegram_api::groupCallParticipant> &participant) {
return participant->just_joined_ || participant->left_ || participant->versioned_;
}
bool GroupCallParticipant::update_can_be_muted(bool can_manage, bool is_self, bool is_admin) {
bool new_can_be_muted = false;
bool new_can_be_unmuted = false;
if (is_self) {
// current user can be muted if !is_muted; after that is_muted && can_self_unmute
// current user can be unmuted if is_muted && can_self_unmute; after that !is_muted
new_can_be_muted = !is_muted;
new_can_be_unmuted = is_muted && can_self_unmute;
} else if (is_admin) {
// admin user can be muted if can_manage && !is_muted; after that is_muted && can_self_unmute
// admin user can't be unmuted
new_can_be_muted = can_manage && !is_muted;
} else {
// other user can be muted if can_manage; after that is_muted && !can_self_unmute
// other user can be unmuted if can_manage && is_muted && !can_self_unmute; after that is_muted && can_self_unmute
new_can_be_muted = can_manage && (!is_muted || can_self_unmute);
new_can_be_unmuted = can_manage && is_muted && !can_self_unmute;
bool GroupCallParticipant::get_is_muted_by_themselves() const {
return have_pending_is_muted ? pending_is_muted_by_themselves : server_is_muted_by_themselves;
}
bool GroupCallParticipant::get_is_muted_by_admin() const {
return have_pending_is_muted ? pending_is_muted_by_admin : server_is_muted_by_admin;
}
bool GroupCallParticipant::get_is_muted_locally() const {
return have_pending_is_muted ? pending_is_muted_locally : server_is_muted_locally;
}
bool GroupCallParticipant::get_is_muted_for_all_users() const {
return get_is_muted_by_admin() || get_is_muted_by_themselves();
}
int32 GroupCallParticipant::get_volume_level() const {
return pending_volume_level != 0 ? pending_volume_level : volume_level;
}
void GroupCallParticipant::update_from(const GroupCallParticipant &old_participant) {
CHECK(!old_participant.is_min);
if (joined_date < old_participant.joined_date) {
LOG(ERROR) << "Join date decreased from " << old_participant.joined_date << " to " << joined_date;
joined_date = old_participant.joined_date;
}
if (new_can_be_muted != can_be_muted || new_can_be_unmuted != can_be_unmuted) {
can_be_muted = new_can_be_muted;
can_be_unmuted = new_can_be_unmuted;
if (active_date < old_participant.active_date) {
active_date = old_participant.active_date;
}
local_active_date = old_participant.local_active_date;
is_speaking = old_participant.is_speaking;
if (is_min) {
server_is_muted_locally = old_participant.server_is_muted_locally;
if (old_participant.is_volume_level_local && !is_volume_level_local) {
is_volume_level_local = true;
volume_level = old_participant.volume_level;
}
}
is_min = false;
pending_volume_level = old_participant.pending_volume_level;
pending_volume_level_generation = old_participant.pending_volume_level_generation;
have_pending_is_muted = old_participant.have_pending_is_muted;
pending_is_muted_by_themselves = old_participant.pending_is_muted_by_themselves;
pending_is_muted_by_admin = old_participant.pending_is_muted_by_admin;
pending_is_muted_locally = old_participant.pending_is_muted_locally;
pending_is_muted_generation = old_participant.pending_is_muted_generation;
}
bool GroupCallParticipant::update_can_be_muted(bool can_manage, bool is_self, bool is_admin) {
bool is_muted_by_admin = get_is_muted_by_admin();
bool is_muted_by_themselves = get_is_muted_by_themselves();
bool is_muted_locally = get_is_muted_locally();
CHECK(!is_muted_by_admin || !is_muted_by_themselves);
bool new_can_be_muted_for_all_users = false;
bool new_can_be_unmuted_for_all_users = false;
bool new_can_be_muted_only_for_self = !can_manage && !is_muted_locally;
bool new_can_be_unmuted_only_for_self = !can_manage && is_muted_locally;
if (is_self) {
// current user can be muted if !is_muted_by_themselves && !is_muted_by_admin; after that is_muted_by_themselves
// current user can be unmuted if is_muted_by_themselves; after that !is_muted
new_can_be_muted_for_all_users = !is_muted_by_themselves && !is_muted_by_admin;
new_can_be_unmuted_for_all_users = is_muted_by_themselves;
new_can_be_muted_only_for_self = false;
new_can_be_unmuted_only_for_self = false;
} else if (is_admin) {
// admin user can be muted if can_manage && !is_muted_by_themselves; after that is_muted_by_themselves
// admin user can't be unmuted
new_can_be_muted_for_all_users = can_manage && !is_muted_by_themselves;
} else {
// other users can be muted if can_manage && !is_muted_by_admin; after that is_muted_by_admin
// other users can be unmuted if can_manage && is_muted_by_admin; after that is_muted_by_themselves
new_can_be_muted_for_all_users = can_manage && !is_muted_by_admin;
new_can_be_unmuted_for_all_users = can_manage && is_muted_by_admin;
}
CHECK(static_cast<int>(new_can_be_muted_for_all_users) + static_cast<int>(new_can_be_unmuted_for_all_users) +
static_cast<int>(new_can_be_muted_only_for_self) + static_cast<int>(new_can_be_unmuted_only_for_self) <=
1);
if (new_can_be_muted_for_all_users != can_be_muted_for_all_users ||
new_can_be_unmuted_for_all_users != can_be_unmuted_for_all_users ||
new_can_be_muted_only_for_self != can_be_muted_only_for_self ||
new_can_be_unmuted_only_for_self != can_be_unmuted_only_for_self) {
can_be_muted_for_all_users = new_can_be_muted_for_all_users;
can_be_unmuted_for_all_users = new_can_be_unmuted_for_all_users;
can_be_muted_only_for_self = new_can_be_muted_only_for_self;
can_be_unmuted_only_for_self = new_can_be_unmuted_only_for_self;
return true;
}
return false;
}
bool GroupCallParticipant::set_pending_is_muted(bool is_muted, bool can_manage, bool is_self, bool is_admin) {
update_can_be_muted(can_manage, is_self, is_admin);
if (is_muted) {
if (!can_be_muted_for_all_users && !can_be_muted_only_for_self) {
return false;
}
CHECK(!can_be_muted_for_all_users || !can_be_muted_only_for_self);
} else {
if (!can_be_unmuted_for_all_users && !can_be_unmuted_only_for_self) {
return false;
}
CHECK(!can_be_unmuted_for_all_users || !can_be_unmuted_only_for_self);
}
if (is_self) {
pending_is_muted_by_themselves = is_muted;
pending_is_muted_by_admin = false;
pending_is_muted_locally = false;
} else {
pending_is_muted_by_themselves = get_is_muted_by_themselves();
pending_is_muted_by_admin = get_is_muted_by_admin();
pending_is_muted_locally = get_is_muted_locally();
if (is_muted) {
if (can_be_muted_only_for_self) {
// local mute
pending_is_muted_locally = true;
} else {
// admin mute
CHECK(can_be_muted_for_all_users);
CHECK(can_manage);
if (is_admin) {
CHECK(!pending_is_muted_by_themselves);
pending_is_muted_by_admin = false;
pending_is_muted_by_themselves = true;
} else {
CHECK(!pending_is_muted_by_admin);
pending_is_muted_by_admin = true;
pending_is_muted_by_themselves = false;
}
}
} else {
if (can_be_unmuted_only_for_self) {
// local unmute
pending_is_muted_locally = false;
} else {
// admin unmute
CHECK(can_be_unmuted_for_all_users);
CHECK(can_manage);
CHECK(!is_admin);
pending_is_muted_by_admin = false;
pending_is_muted_by_themselves = true;
}
}
}
have_pending_is_muted = true;
update_can_be_muted(can_manage, is_self, is_admin);
return true;
}
td_api::object_ptr<td_api::groupCallParticipant> GroupCallParticipant::get_group_call_participant_object(
ContactsManager *contacts_manager) const {
if (!is_valid()) {
@ -69,14 +208,22 @@ td_api::object_ptr<td_api::groupCallParticipant> GroupCallParticipant::get_group
}
return td_api::make_object<td_api::groupCallParticipant>(
contacts_manager->get_user_id_object(user_id, "get_group_call_participant_object"), source, is_speaking,
can_be_muted, can_be_unmuted, is_muted, can_self_unmute, order);
contacts_manager->get_user_id_object(user_id, "get_group_call_participant_object"), audio_source, is_speaking,
can_be_muted_for_all_users, can_be_unmuted_for_all_users, can_be_muted_only_for_self,
can_be_unmuted_only_for_self, get_is_muted_for_all_users(), get_is_muted_locally(), get_is_muted_by_themselves(),
get_volume_level(), order);
}
bool operator==(const GroupCallParticipant &lhs, const GroupCallParticipant &rhs) {
return lhs.user_id == rhs.user_id && lhs.source == rhs.source && lhs.can_be_muted == rhs.can_be_muted &&
lhs.can_be_unmuted == rhs.can_be_unmuted && lhs.is_muted == rhs.is_muted &&
lhs.can_self_unmute == rhs.can_self_unmute && lhs.is_speaking == rhs.is_speaking && lhs.order == rhs.order;
return lhs.user_id == rhs.user_id && lhs.audio_source == rhs.audio_source &&
lhs.can_be_muted_for_all_users == rhs.can_be_muted_for_all_users &&
lhs.can_be_unmuted_for_all_users == rhs.can_be_unmuted_for_all_users &&
lhs.can_be_muted_only_for_self == rhs.can_be_muted_only_for_self &&
lhs.can_be_unmuted_only_for_self == rhs.can_be_unmuted_only_for_self &&
lhs.get_is_muted_for_all_users() == rhs.get_is_muted_for_all_users() &&
lhs.get_is_muted_locally() == rhs.get_is_muted_locally() &&
lhs.get_is_muted_by_themselves() == rhs.get_is_muted_by_themselves() && lhs.is_speaking == rhs.is_speaking &&
lhs.get_volume_level() == rhs.get_volume_level() && lhs.order == rhs.order;
}
bool operator!=(const GroupCallParticipant &lhs, const GroupCallParticipant &rhs) {
@ -84,8 +231,8 @@ bool operator!=(const GroupCallParticipant &lhs, const GroupCallParticipant &rhs
}
StringBuilder &operator<<(StringBuilder &string_builder, const GroupCallParticipant &group_call_participant) {
return string_builder << '[' << group_call_participant.user_id << " with source " << group_call_participant.source
<< " and order " << group_call_participant.order << ']';
return string_builder << '[' << group_call_participant.user_id << " with source "
<< group_call_participant.audio_source << " and order " << group_call_participant.order << ']';
}
} // namespace td

View File

@ -19,28 +19,51 @@ class ContactsManager;
struct GroupCallParticipant {
UserId user_id;
int32 source = 0;
int32 audio_source = 0;
int32 joined_date = 0;
int32 active_date = 0;
bool is_muted = false;
bool can_self_unmute = false;
int32 volume_level = 10000;
bool is_volume_level_local = false;
bool server_is_muted_by_themselves = false;
bool server_is_muted_by_admin = false;
bool server_is_muted_locally = false;
bool can_be_muted = false;
bool can_be_unmuted = false;
bool can_be_muted_for_all_users = false;
bool can_be_unmuted_for_all_users = false;
bool can_be_muted_only_for_self = false;
bool can_be_unmuted_only_for_self = false;
bool is_min = false;
bool is_fake = false;
bool is_just_joined = false;
bool is_speaking = false;
int32 local_active_date = 0;
int64 order = 0;
int32 pending_volume_level = 0;
uint64 pending_volume_level_generation = 0;
bool have_pending_is_muted = false;
bool pending_is_muted_by_themselves = false;
bool pending_is_muted_by_admin = false;
bool pending_is_muted_locally = false;
uint64 pending_is_muted_generation = 0;
static constexpr int32 MIN_VOLUME_LEVEL = 1;
static constexpr int32 MAX_VOLUME_LEVEL = 20000;
GroupCallParticipant() = default;
explicit GroupCallParticipant(const tl_object_ptr<telegram_api::groupCallParticipant> &participant);
static bool is_versioned_update(const tl_object_ptr<telegram_api::groupCallParticipant> &participant);
void update_from(const GroupCallParticipant &old_participant);
bool update_can_be_muted(bool can_manage, bool is_self, bool is_admin);
bool set_pending_is_muted(bool is_muted, bool can_manage, bool is_self, bool is_admin);
int64 get_real_order() const {
return (static_cast<int64>(max(active_date, local_active_date)) << 32) + joined_date;
}
@ -49,6 +72,16 @@ struct GroupCallParticipant {
return user_id.is_valid();
}
bool get_is_muted_by_themselves() const;
bool get_is_muted_by_admin() const;
bool get_is_muted_locally() const;
bool get_is_muted_for_all_users() const;
int32 get_volume_level() const;
td_api::object_ptr<td_api::groupCallParticipant> get_group_call_participant_object(
ContactsManager *contacts_manager) const;
};

View File

@ -1583,8 +1583,8 @@ static Result<InputMessageContent> create_input_message_content(
string mime_type;
if (file_id.is_valid()) {
file_view = td->file_manager_->get_file_view(file_id);
auto suggested_name = file_view.suggested_name();
const PathView path_view(suggested_name);
auto suggested_path = file_view.suggested_path();
const PathView path_view(suggested_path);
file_name = path_view.file_name().str();
mime_type = MimeType::from_extension(path_view.extension());
}
@ -1621,7 +1621,7 @@ static Result<InputMessageContent> create_input_message_content(
td->animations_manager_->create_animation(
file_id, string(), thumbnail, AnimationSize(), has_stickers, std::move(sticker_file_ids),
std::move(file_name), std::move(mime_type), input_animation->duration_,
get_dimensions(input_animation->width_, input_animation->height_), false);
get_dimensions(input_animation->width_, input_animation->height_, "inputMessageAnimation"), false);
content = make_unique<MessageAnimation>(file_id, std::move(caption));
break;
@ -1690,7 +1690,7 @@ static Result<InputMessageContent> create_input_message_content(
PhotoSize s;
s.type = type;
s.dimensions = get_dimensions(input_photo->width_, input_photo->height_);
s.dimensions = get_dimensions(input_photo->width_, input_photo->height_, "inputMessagePhoto");
s.size = static_cast<int32>(file_view.size());
s.file_id = file_id;
@ -1713,9 +1713,10 @@ static Result<InputMessageContent> create_input_message_content(
emoji = std::move(input_sticker->emoji_);
td->stickers_manager_->create_sticker(file_id, string(), thumbnail,
get_dimensions(input_sticker->width_, input_sticker->height_), nullptr,
false, nullptr);
td->stickers_manager_->create_sticker(
file_id, string(), thumbnail,
get_dimensions(input_sticker->width_, input_sticker->height_, "inputMessageSticker"), nullptr, false,
nullptr);
content = make_unique<MessageSticker>(file_id);
break;
@ -1726,10 +1727,11 @@ static Result<InputMessageContent> create_input_message_content(
ttl = input_video->ttl_;
bool has_stickers = !sticker_file_ids.empty();
td->videos_manager_->create_video(
file_id, string(), thumbnail, AnimationSize(), has_stickers, std::move(sticker_file_ids),
std::move(file_name), std::move(mime_type), input_video->duration_,
get_dimensions(input_video->width_, input_video->height_), input_video->supports_streaming_, false);
td->videos_manager_->create_video(file_id, string(), thumbnail, AnimationSize(), has_stickers,
std::move(sticker_file_ids), std::move(file_name), std::move(mime_type),
input_video->duration_,
get_dimensions(input_video->width_, input_video->height_, "inputMessageVideo"),
input_video->supports_streaming_, false);
content = make_unique<MessageVideo>(file_id, std::move(caption));
break;
@ -1743,7 +1745,7 @@ static Result<InputMessageContent> create_input_message_content(
}
td->video_notes_manager_->create_video_note(file_id, string(), thumbnail, input_video_note->duration_,
get_dimensions(length, length), false);
get_dimensions(length, length, "inputMessageVideoNote"), false);
content = make_unique<MessageVideoNote>(file_id, false);
break;
@ -1834,7 +1836,8 @@ static Result<InputMessageContent> create_input_message_content(
PhotoSize s;
s.type = 'n';
s.dimensions = get_dimensions(input_invoice->photo_width_, input_invoice->photo_height_);
s.dimensions =
get_dimensions(input_invoice->photo_width_, input_invoice->photo_height_, "inputMessageInvoice");
s.size = input_invoice->photo_size_; // TODO use invoice_file_id size
s.file_id = invoice_file_id;
@ -2075,7 +2078,7 @@ Result<InputMessageContent> get_input_message_content(
LOG(WARNING) << "Ignore thumbnail file: " << r_thumbnail_file_id.error().message();
} else {
thumbnail.type = 't';
thumbnail.dimensions = get_dimensions(input_thumbnail->width_, input_thumbnail->height_);
thumbnail.dimensions = get_dimensions(input_thumbnail->width_, input_thumbnail->height_, "inputThumbnail");
thumbnail.file_id = r_thumbnail_file_id.ok();
CHECK(thumbnail.file_id.is_valid());
@ -2493,6 +2496,42 @@ tl_object_ptr<telegram_api::InputMedia> get_input_media(const MessageContent *co
return input_media;
}
tl_object_ptr<telegram_api::InputMedia> get_fake_input_media(Td *td, tl_object_ptr<telegram_api::InputFile> input_file,
FileId file_id) {
FileView file_view = td->file_manager_->get_file_view(file_id);
auto file_type = file_view.get_type();
switch (file_type) {
case FileType::Animation:
case FileType::Audio:
case FileType::Document:
case FileType::Sticker:
case FileType::Video:
case FileType::VoiceNote: {
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
auto file_path = file_view.suggested_path();
const PathView path_view(file_path);
Slice file_name = path_view.file_name();
if (!file_name.empty()) {
attributes.push_back(make_tl_object<telegram_api::documentAttributeFilename>(file_name.str()));
}
string mime_type = MimeType::from_extension(path_view.extension());
int32 flags = 0;
if (file_type == FileType::Video) {
flags |= telegram_api::inputMediaUploadedDocument::NOSOUND_VIDEO_MASK;
}
return make_tl_object<telegram_api::inputMediaUploadedDocument>(
flags, false /*ignored*/, false /*ignored*/, std::move(input_file), nullptr, mime_type, std::move(attributes),
vector<tl_object_ptr<telegram_api::InputDocument>>(), 0);
}
case FileType::Photo:
return make_tl_object<telegram_api::inputMediaUploadedPhoto>(
0, std::move(input_file), vector<tl_object_ptr<telegram_api::InputDocument>>(), 0);
default:
UNREACHABLE();
}
return nullptr;
}
void delete_message_content_thumbnail(MessageContent *content, Td *td) {
switch (content->get_type()) {
case MessageContentType::Animation: {
@ -4146,7 +4185,7 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
if (to_secret && !file_view.is_encrypted_secret()) {
auto download_file_id = file_manager->dup_file_id(file_id);
file_id = file_manager
->register_generate(FileType::Encrypted, FileLocationSource::FromServer, file_view.suggested_name(),
->register_generate(FileType::Encrypted, FileLocationSource::FromServer, file_view.suggested_path(),
PSTRING() << "#file_id#" << download_file_id.get(), dialog_id, file_view.size())
.ok();
}
@ -4486,6 +4525,10 @@ unique_ptr<MessageContent> get_action_message_content(Td *td, tl_object_ptr<tele
auto duration =
(phone_call->flags_ & telegram_api::messageActionPhoneCall::DURATION_MASK) != 0 ? phone_call->duration_ : 0;
auto is_video = (phone_call->flags_ & telegram_api::messageActionPhoneCall::VIDEO_MASK) != 0;
if (duration < 0) {
LOG(ERROR) << "Receive invalid " << oneline(to_string(phone_call));
break;
}
return make_unique<MessageCall>(phone_call->call_id_, duration, get_call_discard_reason(phone_call->reason_),
is_video);
}
@ -4583,6 +4626,14 @@ unique_ptr<MessageContent> get_action_message_content(Td *td, tl_object_ptr<tele
return td::make_unique<MessageInviteToGroupCall>(InputGroupCallId(invite_to_group_call->call_),
std::move(user_ids));
}
case telegram_api::messageActionSetMessagesTTL::ID: {
auto set_messages_ttl = move_tl_object_as<telegram_api::messageActionSetMessagesTTL>(action);
if (set_messages_ttl->period_ < 0) {
LOG(ERROR) << "Receive wrong TTL = " << set_messages_ttl->period_;
break;
}
return td::make_unique<MessageChatSetTtl>(set_messages_ttl->period_);
}
default:
UNREACHABLE();
}

View File

@ -117,6 +117,9 @@ tl_object_ptr<telegram_api::InputMedia> get_input_media(const MessageContent *co
tl_object_ptr<telegram_api::InputMedia> get_input_media(const MessageContent *content, Td *td, int32 ttl,
const string &emoji, bool force);
tl_object_ptr<telegram_api::InputMedia> get_fake_input_media(Td *td, tl_object_ptr<telegram_api::InputFile> input_file,
FileId file_id);
void delete_message_content_thumbnail(MessageContent *content, Td *td);
bool can_forward_message_content(const MessageContent *content);

View File

@ -677,9 +677,7 @@ static vector<Slice> match_urls(Slice str) {
url_begin_ptr = url_begin_ptr - 7;
} else if (ends_with(protocol, "https")) {
url_begin_ptr = url_begin_ptr - 8;
} else if (ends_with(protocol, "sftp")) {
url_begin_ptr = url_begin_ptr - 7;
} else if (ends_with(protocol, "ftp") && protocol != "tftp") {
} else if (ends_with(protocol, "ftp") && protocol != "tftp" && protocol != "sftp") {
url_begin_ptr = url_begin_ptr - 6;
} else {
is_bad = true;
@ -983,8 +981,7 @@ Slice fix_url(Slice str) {
bool has_protocol = false;
auto str_begin = to_lower(str.substr(0, 8));
if (begins_with(str_begin, "http://") || begins_with(str_begin, "https://") || begins_with(str_begin, "sftp://") ||
begins_with(str_begin, "ftp://")) {
if (begins_with(str_begin, "http://") || begins_with(str_begin, "https://") || begins_with(str_begin, "ftp://")) {
auto pos = str.find(':');
str = str.substr(pos + 3);
has_protocol = true;
@ -3032,6 +3029,7 @@ Result<vector<MessageEntity>> get_message_entities(const ContactsManager *contac
vector<tl_object_ptr<td_api::textEntity>> &&input_entities,
bool allow_all) {
vector<MessageEntity> entities;
entities.reserve(input_entities.size());
for (auto &entity : input_entities) {
if (entity == nullptr || entity->type_ == nullptr) {
continue;
@ -3756,23 +3754,32 @@ static void merge_new_entities(vector<MessageEntity> &entities, vector<MessageEn
Status fix_formatted_text(string &text, vector<MessageEntity> &entities, bool allow_empty, bool skip_new_entities,
bool skip_bot_commands, bool for_draft) {
if (!check_utf8(text)) {
return Status::Error(400, "Strings must be encoded in UTF-8");
}
for (auto &entity : entities) {
if (entity.offset < 0 || entity.offset > 1000000) {
return Status::Error(400, PSLICE() << "Receive an entity with incorrect offset " << entity.offset);
string result;
if (entities.empty()) {
// fast path
if (!clean_input_string(text)) {
return Status::Error(400, "Strings must be encoded in UTF-8");
}
if (entity.length < 0 || entity.length > 1000000) {
return Status::Error(400, PSLICE() << "Receive an entity with incorrect length " << entity.length);
result = std::move(text);
} else {
if (!check_utf8(text)) {
return Status::Error(400, "Strings must be encoded in UTF-8");
}
for (auto &entity : entities) {
if (entity.offset < 0 || entity.offset > 1000000) {
return Status::Error(400, PSLICE() << "Receive an entity with incorrect offset " << entity.offset);
}
if (entity.length < 0 || entity.length > 1000000) {
return Status::Error(400, PSLICE() << "Receive an entity with incorrect length " << entity.length);
}
}
td::remove_if(entities, [](const MessageEntity &entity) { return entity.length == 0; });
fix_entities(entities);
TRY_RESULT_ASSIGN(result, clean_input_string_with_entities(text, entities));
}
td::remove_if(entities, [](const MessageEntity &entity) { return entity.length == 0; });
fix_entities(entities);
TRY_RESULT(result, clean_input_string_with_entities(text, entities));
// now entities are still sorted by offset and length, but not type,
// because some characters could be deleted and after that some entities begin to share a common end

View File

@ -0,0 +1,27 @@
//
// 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/MessageTtlSetting.h"
namespace td {
bool MessageTtlSetting::is_empty() const {
return ttl_period_ == 0;
}
int32 MessageTtlSetting::get_message_ttl_setting_object() const {
return ttl_period_;
}
bool operator==(const MessageTtlSetting &lhs, const MessageTtlSetting &rhs) {
return lhs.ttl_period_ == rhs.ttl_period_;
}
StringBuilder &operator<<(StringBuilder &string_builder, const MessageTtlSetting &message_ttl_setting) {
return string_builder << "MessageTtlSetting[" << message_ttl_setting.ttl_period_ << "]";
}
} // namespace td

View File

@ -0,0 +1,56 @@
//
// 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/common.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/tl_helpers.h"
#include <type_traits>
namespace td {
class MessageTtlSetting {
int32 ttl_period_ = 0;
friend StringBuilder &operator<<(StringBuilder &string_builder, const MessageTtlSetting &message_ttl_setting);
friend bool operator==(const MessageTtlSetting &lhs, const MessageTtlSetting &rhs);
public:
MessageTtlSetting() = default;
template <class T, typename = std::enable_if_t<std::is_convertible<T, int32>::value>>
MessageTtlSetting(T ttl_period) = delete;
explicit MessageTtlSetting(int32 ttl_period) : ttl_period_(ttl_period) {
}
bool is_empty() const;
int32 get_message_ttl_setting_object() const;
template <class StorerT>
void store(StorerT &storer) const {
td::store(ttl_period_, storer);
}
template <class ParserT>
void parse(ParserT &parser) {
td::parse(ttl_period_, parser);
}
};
bool operator==(const MessageTtlSetting &lhs, const MessageTtlSetting &rhs);
inline bool operator!=(const MessageTtlSetting &lhs, const MessageTtlSetting &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const MessageTtlSetting &message_ttl_setting);
} // namespace td

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,6 @@
#include "td/telegram/ChannelId.h"
#include "td/telegram/Dependencies.h"
#include "td/telegram/DialogAction.h"
#include "td/telegram/DialogAdministrator.h"
#include "td/telegram/DialogDate.h"
#include "td/telegram/DialogDb.h"
#include "td/telegram/DialogFilterId.h"
@ -33,6 +32,7 @@
#include "td/telegram/MessageReplyInfo.h"
#include "td/telegram/MessagesDb.h"
#include "td/telegram/MessageSearchFilter.h"
#include "td/telegram/MessageTtlSetting.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/Notification.h"
#include "td/telegram/NotificationGroupId.h"
@ -41,6 +41,7 @@
#include "td/telegram/NotificationId.h"
#include "td/telegram/NotificationSettings.h"
#include "td/telegram/ReplyMarkup.h"
#include "td/telegram/ReportReason.h"
#include "td/telegram/RestrictionReason.h"
#include "td/telegram/ScheduledServerMessageId.h"
#include "td/telegram/SecretChatId.h"
@ -118,6 +119,7 @@ class MessagesManager : public Actor {
static constexpr int32 MESSAGE_FLAG_IS_RESTRICTED = 1 << 22;
static constexpr int32 MESSAGE_FLAG_HAS_REPLY_INFO = 1 << 23;
static constexpr int32 MESSAGE_FLAG_IS_PINNED = 1 << 24;
static constexpr int32 MESSAGE_FLAG_HAS_TTL_PERIOD = 1 << 25;
static constexpr int32 SEND_MESSAGE_FLAG_IS_REPLY = 1 << 0;
static constexpr int32 SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW = 1 << 1;
@ -238,7 +240,8 @@ class MessagesManager : public Actor {
void delete_secret_messages(SecretChatId secret_chat_id, std::vector<int64> random_ids, Promise<> promise);
void delete_secret_chat_history(SecretChatId secret_chat_id, MessageId last_message_id, Promise<> promise);
void delete_secret_chat_history(SecretChatId secret_chat_id, bool remove_from_dialog_list, MessageId last_message_id,
Promise<> promise);
void read_secret_chat_outbox(SecretChatId secret_chat_id, int32 up_to_date, int32 read_date);
@ -291,6 +294,8 @@ class MessagesManager : public Actor {
void on_update_dialog_group_call_id(DialogId dialog_id, InputGroupCallId input_group_call_id);
void on_update_dialog_message_ttl_setting(DialogId dialog_id, MessageTtlSetting message_ttl_setting);
void on_update_dialog_filters();
void on_update_service_notification(tl_object_ptr<telegram_api::updateServiceNotification> &&update,
@ -342,9 +347,11 @@ class MessagesManager : public Actor {
void delete_dialog_history(DialogId dialog_id, bool remove_from_dialog_list, bool revoke, Promise<Unit> &&promise);
void delete_all_call_messages(bool revoke, Promise<Unit> &&promise);
void delete_dialog_messages_from_user(DialogId dialog_id, UserId user_id, Promise<Unit> &&promise);
void delete_dialog(DialogId dialog_id);
void on_dialog_deleted(DialogId dialog_id, Promise<Unit> &&promise);
void on_update_dialog_group_call_rights(DialogId dialog_id);
@ -386,7 +393,7 @@ class MessagesManager : public Actor {
Result<vector<MessageId>> resend_messages(DialogId dialog_id, vector<MessageId> message_ids) TD_WARN_UNUSED_RESULT;
Result<MessageId> send_dialog_set_ttl_message(DialogId dialog_id, int32 ttl);
void set_dialog_message_ttl_setting(DialogId dialog_id, int32 ttl, Promise<Unit> &&promise);
Status send_screenshot_taken_notification_message(DialogId dialog_id);
@ -395,6 +402,17 @@ class MessagesManager : public Actor {
tl_object_ptr<td_api::InputMessageContent> &&input_message_content)
TD_WARN_UNUSED_RESULT;
void get_message_file_type(const string &message_file_head,
Promise<td_api::object_ptr<td_api::MessageFileType>> &&promise);
void get_message_import_confirmation_text(DialogId dialog_id, Promise<string> &&promise);
void import_messages(DialogId dialog_id, const td_api::object_ptr<td_api::InputFile> &message_file,
const vector<td_api::object_ptr<td_api::InputFile>> &attached_files, Promise<Unit> &&promise);
void start_import_messages(DialogId dialog_id, int64 import_id, vector<FileId> &&attached_file_ids,
Promise<Unit> &&promise);
void edit_message_text(FullMessageId full_message_id, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
tl_object_ptr<td_api::InputMessageContent> &&input_message_content, Promise<Unit> &&promise);
@ -470,28 +488,6 @@ class MessagesManager : public Actor {
void unpin_all_dialog_messages(DialogId dialog_id, Promise<Unit> &&promise);
void add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, Promise<Unit> &&promise);
void add_dialog_participants(DialogId dialog_id, const vector<UserId> &user_ids, Promise<Unit> &&promise);
void set_dialog_participant_status(DialogId dialog_id, UserId user_id,
const tl_object_ptr<td_api::ChatMemberStatus> &chat_member_status,
Promise<Unit> &&promise);
DialogParticipant get_dialog_participant(DialogId dialog_id, UserId user_id, int64 &random_id, bool force,
Promise<Unit> &&promise);
std::pair<int32, vector<DialogParticipant>> search_dialog_participants(DialogId dialog_id, const string &query,
int32 limit, DialogParticipantsFilter filter,
int64 &random_id, bool without_bot_info,
bool force, Promise<Unit> &&promise);
vector<DialogAdministrator> get_dialog_administrators(DialogId dialog_id, int left_tries, Promise<Unit> &&promise);
void export_dialog_invite_link(DialogId dialog_id, Promise<Unit> &&promise);
string get_dialog_invite_link(DialogId dialog_id);
void get_dialog_info_full(DialogId dialog_id, Promise<Unit> &&promise);
int64 get_dialog_event_log(DialogId dialog_id, const string &query, int64 from_event_id, int32 limit,
@ -632,7 +628,8 @@ class MessagesManager : public Actor {
Promise<Unit> &&promise);
DialogId create_new_channel_chat(const string &title, bool is_megagroup, const string &description,
const DialogLocation &location, int64 &random_id, Promise<Unit> &&promise);
const DialogLocation &location, bool for_import, int64 &random_id,
Promise<Unit> &&promise);
void create_new_secret_chat(UserId user_id, Promise<SecretChatId> &&promise);
@ -754,7 +751,7 @@ class MessagesManager : public Actor {
bool is_update_about_username_change_received(DialogId dialog_id) const;
void on_dialog_bots_updated(DialogId dialog_id, vector<UserId> bot_user_ids);
void on_dialog_bots_updated(DialogId dialog_id, vector<UserId> bot_user_ids, bool from_database);
void on_dialog_photo_updated(DialogId dialog_id);
void on_dialog_title_updated(DialogId dialog_id);
@ -785,8 +782,10 @@ class MessagesManager : public Actor {
void reget_dialog_action_bar(DialogId dialog_id, const char *source);
void report_dialog(DialogId dialog_id, const tl_object_ptr<td_api::ChatReportReason> &reason,
const vector<MessageId> &message_ids, Promise<Unit> &&promise);
void report_dialog(DialogId dialog_id, const vector<MessageId> &message_ids, ReportReason &&reason,
Promise<Unit> &&promise);
void report_dialog_photo(DialogId dialog_id, FileId file_id, ReportReason &&reason, Promise<Unit> &&promise);
void on_get_peer_settings(DialogId dialog_id, tl_object_ptr<telegram_api::peerSettings> &&peer_settings,
bool ignore_privacy_exception = false);
@ -813,8 +812,8 @@ class MessagesManager : public Actor {
void check_send_message_result(int64 random_id, DialogId dialog_id, const telegram_api::Updates *updates_ptr,
const char *source);
FullMessageId on_send_message_success(int64 random_id, MessageId new_message_id, int32 date, FileId new_file_id,
const char *source);
FullMessageId on_send_message_success(int64 random_id, MessageId new_message_id, int32 date, int32 ttl_period,
FileId new_file_id, const char *source);
void on_send_message_file_part_missing(int64 random_id, int bad_part);
@ -938,6 +937,7 @@ class MessagesManager : public Actor {
UserId sender_user_id;
DialogId sender_dialog_id;
int32 date = 0;
int32 ttl_period = 0;
int32 ttl = 0;
int64 random_id = 0;
tl_object_ptr<telegram_api::messageFwdHeader> forward_header;
@ -967,12 +967,13 @@ class MessagesManager : public Actor {
DialogId from_dialog_id;
MessageId from_message_id;
string psa_type;
bool is_imported = false;
MessageForwardInfo() = default;
MessageForwardInfo(UserId sender_user_id, int32 date, DialogId sender_dialog_id, MessageId message_id,
string author_signature, string sender_name, DialogId from_dialog_id, MessageId from_message_id,
string psa_type)
string psa_type, bool is_imported)
: sender_user_id(sender_user_id)
, date(date)
, sender_dialog_id(sender_dialog_id)
@ -981,14 +982,15 @@ class MessagesManager : public Actor {
, sender_name(std::move(sender_name))
, from_dialog_id(from_dialog_id)
, from_message_id(from_message_id)
, psa_type(psa_type) {
, psa_type(psa_type)
, is_imported(is_imported) {
}
bool operator==(const MessageForwardInfo &rhs) const {
return sender_user_id == rhs.sender_user_id && date == rhs.date && sender_dialog_id == rhs.sender_dialog_id &&
message_id == rhs.message_id && author_signature == rhs.author_signature &&
sender_name == rhs.sender_name && from_dialog_id == rhs.from_dialog_id &&
from_message_id == rhs.from_message_id && psa_type == rhs.psa_type;
from_message_id == rhs.from_message_id && psa_type == rhs.psa_type && is_imported == rhs.is_imported;
}
bool operator!=(const MessageForwardInfo &rhs) const {
@ -996,11 +998,13 @@ class MessagesManager : public Actor {
}
friend StringBuilder &operator<<(StringBuilder &string_builder, const MessageForwardInfo &forward_info) {
return string_builder << "MessageForwardInfo[sender " << forward_info.sender_user_id << "("
<< forward_info.author_signature << "/" << forward_info.sender_name << "), psa_type "
<< forward_info.psa_type << ", source " << forward_info.sender_dialog_id << ", source "
<< forward_info.message_id << ", from " << forward_info.from_dialog_id << ", from "
<< forward_info.from_message_id << " at " << forward_info.date << "]";
return string_builder << "MessageForwardInfo[" << (forward_info.is_imported ? "imported " : "") << "sender "
<< forward_info.sender_user_id << "(" << forward_info.author_signature << "/"
<< forward_info.sender_name << "), psa_type " << forward_info.psa_type << ", source "
<< forward_info.sender_dialog_id << ", source " << forward_info.message_id << ", from "
<< forward_info.from_dialog_id << ", from " << forward_info.from_message_id << " at "
<< forward_info.date << " "
<< "]";
}
};
@ -1078,8 +1082,9 @@ class MessagesManager : public Actor {
string send_error_message;
double try_resend_at = 0;
int32 ttl = 0;
double ttl_expires_at = 0;
int32 ttl_period = 0; // counted from message send date
int32 ttl = 0; // counted from message content view date
double ttl_expires_at = 0; // only for ttl
int64 media_album_id = 0;
@ -1152,6 +1157,7 @@ class MessagesManager : public Actor {
MessageId last_pinned_message_id;
MessageId reply_markup_message_id;
DialogNotificationSettings notification_settings;
MessageTtlSetting message_ttl_setting;
unique_ptr<DraftMessage> draft_message;
LogEventIdWithGeneration save_draft_message_log_event_id;
LogEventIdWithGeneration save_notification_settings_log_event_id;
@ -1206,6 +1212,7 @@ class MessagesManager : public Actor {
bool can_report_location = false;
bool can_unarchive = false;
bool hide_distance = false;
bool can_invite_members = false;
bool is_opened = false;
@ -1232,10 +1239,12 @@ class MessagesManager : public Actor {
bool had_last_yet_unsent_message = false; // whether the dialog was stored to database without last message
bool has_active_group_call = false;
bool is_group_call_empty = false;
bool is_message_ttl_setting_inited = false;
bool increment_view_counter = false;
bool is_update_new_chat_sent = false;
bool has_unload_timeout = false;
int32 pts = 0; // for channels only
std::multimap<int32, PendingPtsUpdate> postponed_channel_updates; // for channels only
@ -1582,6 +1591,7 @@ class MessagesManager : public Actor {
DialogId dialog_id;
vector<int64> random_ids;
MessageId last_message_id;
bool remove_from_dialog_list = false;
Promise<> success_promise;
};
@ -1601,6 +1611,7 @@ class MessagesManager : public Actor {
class ChangeDialogReportSpamStateOnServerLogEvent;
class DeleteAllChannelMessagesFromUserOnServerLogEvent;
class DeleteDialogHistoryFromServerLogEvent;
class DeleteAllCallMessagesFromServerLogEvent;
class DeleteMessageLogEvent;
class DeleteMessagesFromServerLogEvent;
class DeleteScheduledMessagesFromServerLogEvent;
@ -1709,13 +1720,17 @@ class MessagesManager : public Actor {
DialogId get_my_dialog_id() const;
void on_resolve_secret_chat_message_via_bot_username(const string &via_bot_username, MessageInfo *message_info_ptr,
Promise<Unit> &&promise);
void add_secret_message(unique_ptr<PendingSecretMessage> pending_secret_message, Promise<Unit> lock_promise = Auto());
void finish_add_secret_message(unique_ptr<PendingSecretMessage> pending_secret_message);
void finish_delete_secret_messages(DialogId dialog_id, std::vector<int64> random_ids, Promise<> promise);
void finish_delete_secret_chat_history(DialogId dialog_id, MessageId last_message_id, Promise<> promise);
void finish_delete_secret_chat_history(DialogId dialog_id, bool remove_from_dialog_list, MessageId last_message_id,
Promise<> promise);
MessageInfo parse_telegram_api_message(tl_object_ptr<telegram_api::Message> message_ptr, bool is_scheduled,
const char *source) const;
@ -1724,6 +1739,8 @@ class MessagesManager : public Actor {
MessageId find_old_message_id(DialogId dialog_id, MessageId message_id) const;
void delete_update_message_id(DialogId dialog_id, MessageId message_id);
FullMessageId on_get_message(MessageInfo &&message_info, bool from_update, bool is_channel_message,
bool have_previous, bool have_next, const char *source);
@ -1787,8 +1804,8 @@ class MessagesManager : public Actor {
void delete_messages_from_updates(const vector<MessageId> &message_ids);
void delete_dialog_messages_from_updates(DialogId dialog_id, const vector<MessageId> &message_ids,
bool skip_update_for_not_found_messages);
void delete_dialog_messages(DialogId dialog_id, const vector<MessageId> &message_ids, bool from_updates,
bool skip_update_for_not_found_messages);
void update_dialog_pinned_messages_from_updates(DialogId dialog_id, const vector<MessageId> &message_ids,
bool is_pin);
@ -1895,6 +1912,8 @@ class MessagesManager : public Actor {
void delete_dialog_history_from_server(DialogId dialog_id, MessageId max_message_id, bool remove_from_dialog_list,
bool revoke, bool allow_error, uint64 log_event_id, Promise<Unit> &&promise);
void delete_all_call_messages_from_server(bool revoke, uint64 log_event_id, Promise<Unit> &&promise);
void block_message_sender_from_replies_on_server(MessageId message_id, bool delete_message, bool delete_all_messages,
bool report_spam, uint64 log_event_id, Promise<Unit> &&promise);
@ -2213,6 +2232,8 @@ class MessagesManager : public Actor {
void send_update_chat_voice_chat(const Dialog *d);
void send_update_chat_message_ttl_setting(const Dialog *d);
void send_update_chat_has_scheduled_messages(Dialog *d, bool from_deletion);
void send_update_user_chat_action(DialogId dialog_id, MessageId top_thread_message_id, UserId user_id,
@ -2408,7 +2429,7 @@ class MessagesManager : public Actor {
void on_get_dialogs_from_database(FolderId folder_id, int32 limit, DialogDbGetDialogsResult &&dialogs,
Promise<Unit> &&promise);
void send_get_dialog_query(DialogId dialog_id, Promise<Unit> &&promise, uint64 log_event_id = 0);
void send_get_dialog_query(DialogId dialog_id, Promise<Unit> &&promise, uint64 log_event_id, const char *source);
void send_search_public_dialogs_query(const string &query, Promise<Unit> &&promise);
@ -2516,10 +2537,6 @@ class MessagesManager : public Actor {
DialogFolder *get_dialog_folder(FolderId folder_id);
const DialogFolder *get_dialog_folder(FolderId folder_id) const;
std::pair<int32, vector<DialogParticipant>> search_private_chat_participants(UserId my_user_id, UserId peer_user_id,
const string &query, int32 limit,
DialogParticipantsFilter filter) const;
static unique_ptr<Message> *treap_find_message(unique_ptr<Message> *v, MessageId message_id);
static const unique_ptr<Message> *treap_find_message(const unique_ptr<Message> *v, MessageId message_id);
@ -2593,7 +2610,9 @@ class MessagesManager : public Actor {
void ttl_on_view(const Dialog *d, Message *m, double view_date, double now);
bool ttl_on_open(Dialog *d, Message *m, double now, bool is_local_read);
void ttl_register_message(DialogId dialog_id, const Message *m, double now);
void ttl_unregister_message(DialogId dialog_id, const Message *m, double now, const char *source);
void ttl_unregister_message(DialogId dialog_id, const Message *m, const char *source);
void ttl_period_register_message(DialogId dialog_id, const Message *m, double server_time);
void ttl_period_unregister_message(DialogId dialog_id, const Message *m);
void ttl_loop(double now);
void ttl_update_timeout(double now);
@ -2817,6 +2836,22 @@ class MessagesManager : public Actor {
tl_object_ptr<telegram_api::InputChatPhoto> &&input_chat_photo,
Promise<Unit> &&promise);
void upload_imported_messages(DialogId dialog_id, FileId file_id, vector<FileId> attached_file_ids, bool is_reupload,
Promise<Unit> &&promise, vector<int> bad_parts = {});
void on_upload_imported_messages(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file);
void on_upload_imported_messages_error(FileId file_id, Status status);
void upload_imported_message_attachment(DialogId dialog_id, int64 import_id, FileId file_id, bool is_reupload,
Promise<Unit> &&promise, vector<int> bad_parts = {});
void on_upload_imported_message_attachment(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file);
void on_upload_imported_message_attachment_error(FileId file_id, Status status);
void on_imported_message_attachments_uploaded(int64 random_id, Result<Unit> &&result);
Status can_import_messages(DialogId dialog_id);
void add_sponsored_dialog(const Dialog *d, DialogSource source);
void save_sponsored_dialog();
@ -2892,6 +2927,8 @@ class MessagesManager : public Actor {
uint64 save_delete_dialog_history_from_server_log_event(DialogId dialog_id, MessageId max_message_id,
bool remove_from_dialog_list, bool revoke);
uint64 save_delete_all_call_messages_from_server_log_event(bool revoke);
uint64 save_block_message_sender_from_replies_on_server_log_event(MessageId message_id, bool delete_message,
bool delete_all_messages, bool report_spam);
@ -2947,10 +2984,14 @@ class MessagesManager : public Actor {
class UploadMediaCallback;
class UploadThumbnailCallback;
class UploadDialogPhotoCallback;
class UploadImportedMessagesCallback;
class UploadImportedMessageAttachmentCallback;
std::shared_ptr<UploadMediaCallback> upload_media_callback_;
std::shared_ptr<UploadThumbnailCallback> upload_thumbnail_callback_;
std::shared_ptr<UploadDialogPhotoCallback> upload_dialog_photo_callback_;
std::shared_ptr<UploadImportedMessagesCallback> upload_imported_messages_callback_;
std::shared_ptr<UploadImportedMessageAttachmentCallback> upload_imported_message_attachment_callback_;
double last_channel_pts_jump_warning_time_ = 0;
@ -2973,10 +3014,12 @@ class MessagesManager : public Actor {
// TTL
class TtlNode : private HeapNode {
public:
TtlNode(DialogId dialog_id, MessageId message_id) : full_message_id(dialog_id, message_id) {
TtlNode(DialogId dialog_id, MessageId message_id, bool by_ttl_period)
: full_message_id_(dialog_id, message_id), by_ttl_period_(by_ttl_period) {
}
FullMessageId full_message_id;
FullMessageId full_message_id_;
bool by_ttl_period_;
HeapNode *as_heap_node() const {
return const_cast<HeapNode *>(static_cast<const HeapNode *>(this));
@ -2986,12 +3029,12 @@ class MessagesManager : public Actor {
}
bool operator==(const TtlNode &other) const {
return full_message_id == other.full_message_id;
return full_message_id_ == other.full_message_id_;
}
};
struct TtlNodeHash {
std::size_t operator()(const TtlNode &ttl_node) const {
return FullMessageIdHash()(ttl_node.full_message_id);
return FullMessageIdHash()(ttl_node.full_message_id_) * 2 + static_cast<size_t>(ttl_node.by_ttl_period_);
}
};
std::unordered_set<TtlNode, TtlNodeHash> ttl_nodes_;
@ -3031,7 +3074,45 @@ class MessagesManager : public Actor {
, promise(std::move(promise)) {
}
};
std::unordered_map<FileId, UploadedDialogPhotoInfo, FileIdHash> being_uploaded_dialog_photos_; // file_id -> ...
std::unordered_map<FileId, UploadedDialogPhotoInfo, FileIdHash> being_uploaded_dialog_photos_;
struct UploadedImportedMessagesInfo {
DialogId dialog_id;
vector<FileId> attached_file_ids;
bool is_reupload;
Promise<Unit> promise;
UploadedImportedMessagesInfo(DialogId dialog_id, vector<FileId> &&attached_file_ids, bool is_reupload,
Promise<Unit> &&promise)
: dialog_id(dialog_id)
, attached_file_ids(std::move(attached_file_ids))
, is_reupload(is_reupload)
, promise(std::move(promise)) {
}
};
std::unordered_map<FileId, unique_ptr<UploadedImportedMessagesInfo>, FileIdHash> being_uploaded_imported_messages_;
struct UploadedImportedMessageAttachmentInfo {
DialogId dialog_id;
int64 import_id;
bool is_reupload;
Promise<Unit> promise;
UploadedImportedMessageAttachmentInfo(DialogId dialog_id, int64 import_id, bool is_reupload,
Promise<Unit> &&promise)
: dialog_id(dialog_id), import_id(import_id), is_reupload(is_reupload), promise(std::move(promise)) {
}
};
std::unordered_map<FileId, unique_ptr<UploadedImportedMessageAttachmentInfo>, FileIdHash>
being_uploaded_imported_message_attachments_;
struct PendingMessageImport {
MultiPromiseActor upload_files_multipromise{"UploadAttachedFilesMultiPromiseActor"};
DialogId dialog_id;
int64 import_id = 0;
Promise<Unit> promise;
};
std::unordered_map<int64, unique_ptr<PendingMessageImport>> pending_message_imports_;
struct PendingMessageGroupSend {
DialogId dialog_id;

View File

@ -3273,9 +3273,9 @@ Status NotificationManager::process_push_notification_payload(string payload, bo
auto user = telegram_api::make_object<telegram_api::user>(
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, sender_user_id.get(),
sender_access_hash, user_name, string(), string(), string(), std::move(sender_photo), nullptr, 0, Auto(),
string(), string());
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
sender_user_id.get(), sender_access_hash, user_name, string(), string(), string(), std::move(sender_photo),
nullptr, 0, Auto(), string(), string());
td_->contacts_manager_->on_get_user(std::move(user), "process_push_notification_payload");
}
@ -3610,8 +3610,9 @@ void NotificationManager::add_message_push_notification(DialogId dialog_id, Mess
auto user = telegram_api::make_object<telegram_api::user>(
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, sender_user_id.get(), 0, user_name,
string(), string(), string(), nullptr, nullptr, 0, Auto(), string(), string());
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
sender_user_id.get(), 0, user_name, string(), string(), string(), nullptr, nullptr, 0, Auto(), string(),
string());
td_->contacts_manager_->on_get_user(std::move(user), "add_message_push_notification");
}

View File

@ -859,10 +859,10 @@ void send_payment_form(ServerMessageId server_message_id, const string &order_in
flags, false /*ignored*/, make_tl_object<telegram_api::dataJSON>(credentials_new->data_));
break;
}
case td_api::inputCredentialsAndroidPay::ID: {
auto credentials_android_pay = static_cast<const td_api::inputCredentialsAndroidPay *>(credentials.get());
input_credentials = make_tl_object<telegram_api::inputPaymentCredentialsAndroidPay>(
make_tl_object<telegram_api::dataJSON>(credentials_android_pay->data_), string());
case td_api::inputCredentialsGooglePay::ID: {
auto credentials_google_pay = static_cast<const td_api::inputCredentialsGooglePay *>(credentials.get());
input_credentials = make_tl_object<telegram_api::inputPaymentCredentialsGooglePay>(
make_tl_object<telegram_api::dataJSON>(credentials_google_pay->data_));
break;
}
case td_api::inputCredentialsApplePay::ID: {

View File

@ -30,18 +30,18 @@
namespace td {
static uint16 get_dimension(int32 size) {
static uint16 get_dimension(int32 size, const char *source) {
if (size < 0 || size > 65535) {
LOG(ERROR) << "Wrong image dimension = " << size;
LOG(ERROR) << "Wrong image dimension = " << size << " from " << source;
return 0;
}
return narrow_cast<uint16>(size);
}
Dimensions get_dimensions(int32 width, int32 height) {
Dimensions get_dimensions(int32 width, int32 height, const char *source) {
Dimensions result;
result.width = get_dimension(width);
result.height = get_dimension(height);
result.width = get_dimension(width, source);
result.height = get_dimension(height, source);
if (result.width == 0 || result.height == 0) {
result.width = 0;
result.height = 0;
@ -339,7 +339,7 @@ PhotoSize get_secret_thumbnail_photo_size(FileManager *file_manager, BufferSlice
}
PhotoSize res;
res.type = 't';
res.dimensions = get_dimensions(width, height);
res.dimensions = get_dimensions(width, height, "get_secret_thumbnail_photo_size");
res.size = narrow_cast<int32>(bytes.size());
// generate some random remote location to save
@ -360,7 +360,7 @@ PhotoSize get_secret_thumbnail_photo_size(FileManager *file_manager, BufferSlice
Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSource source, int64 id,
int64 access_hash, std::string file_reference, DcId dc_id,
DialogId owner_dialog_id, tl_object_ptr<telegram_api::PhotoSize> &&size_ptr,
PhotoFormat format, bool expect_jpeg_minithumbnail) {
PhotoFormat format) {
CHECK(size_ptr != nullptr);
tl_object_ptr<telegram_api::fileLocationToBeDeprecated> location;
@ -375,7 +375,7 @@ Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSo
type = std::move(size->type_);
location = std::move(size->location_);
res.dimensions = get_dimensions(size->w_, size->h_);
res.dimensions = get_dimensions(size->w_, size->h_, "photoSize");
res.size = size->size_;
break;
@ -386,7 +386,7 @@ Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSo
type = std::move(size->type_);
location = std::move(size->location_);
CHECK(size->bytes_.size() <= static_cast<size_t>(std::numeric_limits<int32>::max()));
res.dimensions = get_dimensions(size->w_, size->h_);
res.dimensions = get_dimensions(size->w_, size->h_, "photoCachedSize");
res.size = static_cast<int32>(size->bytes_.size());
content = std::move(size->bytes_);
@ -395,11 +395,11 @@ Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSo
}
case telegram_api::photoStrippedSize::ID: {
auto size = move_tl_object_as<telegram_api::photoStrippedSize>(size_ptr);
if (!expect_jpeg_minithumbnail) {
if (format != PhotoFormat::Jpeg) {
if (G()->shared_config().get_option_boolean("disable_minithumbnails")) {
LOG(DEBUG) << "Receive unexpected JPEG minithumbnail";
} else {
LOG(ERROR) << "Receive unexpected JPEG minithumbnail";
LOG(ERROR) << "Receive unexpected JPEG minithumbnail in photo of format " << format;
}
return std::move(res);
}
@ -416,7 +416,7 @@ Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSo
type = std::move(size->type_);
location = std::move(size->location_);
res.dimensions = get_dimensions(size->w_, size->h_);
res.dimensions = get_dimensions(size->w_, size->h_, "photoSizeProgressive");
res.size = size->sizes_.back();
size->sizes_.pop_back();
res.progressive_sizes = std::move(size->sizes_);
@ -425,8 +425,8 @@ Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSo
}
case telegram_api::photoPathSize::ID: {
auto size = move_tl_object_as<telegram_api::photoPathSize>(size_ptr);
if (expect_jpeg_minithumbnail) {
LOG(ERROR) << "Receive unexpected SVG minithumbnail";
if (format != PhotoFormat::Tgs && format != PhotoFormat::Webp) {
LOG(ERROR) << "Receive unexpected SVG minithumbnail in photo of format " << format;
return std::move(res);
}
return size->bytes_.as_slice().str();
@ -468,7 +468,7 @@ AnimationSize get_animation_size(FileManager *file_manager, PhotoSizeSource sour
LOG(ERROR) << "Wrong videoSize \"" << size->type_ << "\" in " << to_string(size);
}
res.type = static_cast<uint8>(size->type_[0]);
res.dimensions = get_dimensions(size->w_, size->h_);
res.dimensions = get_dimensions(size->w_, size->h_, "get_animation_size");
res.size = size->size_;
if ((size->flags_ & telegram_api::videoSize::VIDEO_START_TS_MASK) != 0) {
res.main_frame_timestamp = size->video_start_ts_;
@ -542,7 +542,7 @@ PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_t
switch (attribute->get_id()) {
case telegram_api::documentAttributeImageSize::ID: {
auto image_size = move_tl_object_as<telegram_api::documentAttributeImageSize>(attribute);
dimensions = get_dimensions(image_size->w_, image_size->h_);
dimensions = get_dimensions(image_size->w_, image_size->h_, "web documentAttributeImageSize");
break;
}
case telegram_api::documentAttributeAnimated::ID:
@ -692,7 +692,7 @@ Photo get_encrypted_file_photo(FileManager *file_manager, tl_object_ptr<telegram
PhotoSize s;
s.type = 'i';
s.dimensions = get_dimensions(photo->w_, photo->h_);
s.dimensions = get_dimensions(photo->w_, photo->h_, "get_encrypted_file_photo");
s.size = photo->size_;
s.file_id = file_id;
res.photos.push_back(s);
@ -725,7 +725,7 @@ Photo get_photo(FileManager *file_manager, tl_object_ptr<telegram_api::photo> &&
for (auto &size_ptr : photo->sizes_) {
auto photo_size = get_photo_size(file_manager, {FileType::Photo, 0}, photo->id_, photo->access_hash_,
photo->file_reference_.as_slice().str(), dc_id, owner_dialog_id,
std::move(size_ptr), PhotoFormat::Jpeg, true);
std::move(size_ptr), PhotoFormat::Jpeg);
if (photo_size.get_offset() == 0) {
PhotoSize &size = photo_size.get<0>();
if (size.type == 0 || size.type == 't' || size.type == 'i' || size.type == 'u' || size.type == 'v') {
@ -842,7 +842,7 @@ tl_object_ptr<telegram_api::InputMedia> photo_get_input_media(FileManager *file_
if (ttl != 0) {
flags |= telegram_api::inputMediaPhotoExternal::TTL_SECONDS_MASK;
}
LOG(INFO) << "Create inputMediaPhotoExternal with a URL " << file_view.url() << " and ttl " << ttl;
LOG(INFO) << "Create inputMediaPhotoExternal with a URL " << file_view.url() << " and TTL " << ttl;
return make_tl_object<telegram_api::inputMediaPhotoExternal>(flags, file_view.url(), ttl);
}
if (input_file == nullptr) {

View File

@ -71,7 +71,7 @@ struct Photo {
}
};
Dimensions get_dimensions(int32 width, int32 height);
Dimensions get_dimensions(int32 width, int32 height, const char *source);
bool operator==(const Dimensions &lhs, const Dimensions &rhs);
bool operator!=(const Dimensions &lhs, const Dimensions &rhs);
@ -113,7 +113,7 @@ PhotoSize get_secret_thumbnail_photo_size(FileManager *file_manager, BufferSlice
Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSource source, int64 id,
int64 access_hash, string file_reference, DcId dc_id,
DialogId owner_dialog_id, tl_object_ptr<telegram_api::PhotoSize> &&size_ptr,
PhotoFormat format, bool expect_jpeg_minithumbnail);
PhotoFormat format);
AnimationSize get_animation_size(FileManager *file_manager, PhotoSizeSource source, int64 id, int64 access_hash,
string file_reference, DcId dc_id, DialogId owner_dialog_id,
tl_object_ptr<telegram_api::videoSize> &&size);

View File

@ -224,7 +224,7 @@ class StopPollActor : public NetActorOnce {
}
auto result = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for StopPollQuery: " << to_string(result);
LOG(INFO) << "Receive result for StopPoll: " << to_string(result);
td->updates_manager_->on_get_updates(std::move(result), std::move(promise_));
}

View File

@ -0,0 +1,97 @@
//
// 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/ReportReason.h"
#include "td/telegram/misc.h"
namespace td {
Result<ReportReason> ReportReason::get_report_reason(td_api::object_ptr<td_api::ChatReportReason> reason,
string &&message) {
if (!clean_input_string(message)) {
return Status::Error(400, "Report text must be encoded in UTF-8");
}
if (reason == nullptr) {
return Status::Error(400, "Reason must be non-empty");
}
auto type = [&] {
switch (reason->get_id()) {
case td_api::chatReportReasonSpam::ID:
return ReportReason::Type::Spam;
case td_api::chatReportReasonViolence::ID:
return ReportReason::Type::Violence;
case td_api::chatReportReasonPornography::ID:
return ReportReason::Type::Pornography;
case td_api::chatReportReasonChildAbuse::ID:
return ReportReason::Type::ChildAbuse;
case td_api::chatReportReasonCopyright::ID:
return ReportReason::Type::Copyright;
case td_api::chatReportReasonUnrelatedLocation::ID:
return ReportReason::Type::UnrelatedLocation;
case td_api::chatReportReasonFake::ID:
return ReportReason::Type::Fake;
case td_api::chatReportReasonCustom::ID:
return ReportReason::Type::Custom;
default:
UNREACHABLE();
return ReportReason::Type::Custom;
}
}();
return ReportReason(type, std::move(message));
}
tl_object_ptr<telegram_api::ReportReason> ReportReason::get_input_report_reason() const {
switch (type_) {
case ReportReason::Type::Spam:
return make_tl_object<telegram_api::inputReportReasonSpam>();
case ReportReason::Type::Violence:
return make_tl_object<telegram_api::inputReportReasonViolence>();
case ReportReason::Type::Pornography:
return make_tl_object<telegram_api::inputReportReasonPornography>();
case ReportReason::Type::ChildAbuse:
return make_tl_object<telegram_api::inputReportReasonChildAbuse>();
case ReportReason::Type::Copyright:
return make_tl_object<telegram_api::inputReportReasonCopyright>();
case ReportReason::Type::UnrelatedLocation:
return make_tl_object<telegram_api::inputReportReasonGeoIrrelevant>();
case ReportReason::Type::Fake:
return make_tl_object<telegram_api::inputReportReasonFake>();
case ReportReason::Type::Custom:
return make_tl_object<telegram_api::inputReportReasonOther>();
default:
UNREACHABLE();
return nullptr;
}
}
StringBuilder &operator<<(StringBuilder &string_builder, const ReportReason &report_reason) {
string_builder << "ReportReason";
switch (report_reason.type_) {
case ReportReason::Type::Spam:
return string_builder << "Spam";
case ReportReason::Type::Violence:
return string_builder << "Violence";
case ReportReason::Type::Pornography:
return string_builder << "Pornography";
case ReportReason::Type::ChildAbuse:
return string_builder << "ChildAbuse";
case ReportReason::Type::Copyright:
return string_builder << "Copyright";
case ReportReason::Type::UnrelatedLocation:
return string_builder << "UnrelatedLocation";
case ReportReason::Type::Fake:
return string_builder << "Fake";
case ReportReason::Type::Custom:
return string_builder << "Custom";
default:
UNREACHABLE();
}
return string_builder;
}
} // namespace td

View File

@ -0,0 +1,50 @@
//
// 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/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/Status.h"
#include "td/utils/StringBuilder.h"
namespace td {
class ReportReason {
enum class Type : int32 { Spam, Violence, Pornography, ChildAbuse, Copyright, UnrelatedLocation, Fake, Custom };
Type type_ = Type::Spam;
string message_;
friend StringBuilder &operator<<(StringBuilder &string_builder, const ReportReason &report_reason);
ReportReason(Type type, string &&message) : type_(type), message_(std::move(message)) {
}
public:
ReportReason() = default;
static Result<ReportReason> get_report_reason(td_api::object_ptr<td_api::ChatReportReason> reason, string &&message);
tl_object_ptr<telegram_api::ReportReason> get_input_report_reason() const;
const string &get_message() const {
return message_;
}
bool is_spam() const {
return type_ == Type::Spam;
}
bool is_unrelated_location() const {
return type_ == Type::UnrelatedLocation;
}
};
StringBuilder &operator<<(StringBuilder &string_builder, const ReportReason &report_reason);
} // namespace td

View File

@ -115,7 +115,7 @@ void SecretChatActor::on_result_resendable(NetQueryPtr net_query, Promise<NetQue
auto key = UniqueId::extract_key(net_query->id());
if (close_flag_) {
if (key == static_cast<uint8>(QueryType::DiscardEncryption)) {
on_discard_encryption_result(std::move(net_query));
discard_encryption_promise_.set_value(Unit());
}
return;
}
@ -140,7 +140,7 @@ void SecretChatActor::on_result_resendable(NetQueryPtr net_query, Promise<NetQue
}
void SecretChatActor::replay_close_chat(unique_ptr<log_event::CloseSecretChat> event) {
do_close_chat_impl(std::move(event));
do_close_chat_impl(event->delete_history, event->is_already_discarded, event->log_event_id(), Promise<Unit>());
}
void SecretChatActor::replay_create_chat(unique_ptr<log_event::CreateSecretChat> event) {
@ -709,10 +709,10 @@ void SecretChatActor::check_status(Status status) {
void SecretChatActor::on_fatal_error(Status status) {
LOG(ERROR) << "Fatal error: " << status;
cancel_chat(Promise<>());
cancel_chat(false, false, Promise<>());
}
void SecretChatActor::cancel_chat(Promise<> promise) {
void SecretChatActor::cancel_chat(bool delete_history, bool is_already_discarded, Promise<> promise) {
if (close_flag_) {
promise.set_value(Unit());
return;
@ -735,37 +735,73 @@ void SecretChatActor::cancel_chat(Promise<> promise) {
auto event = make_unique<log_event::CloseSecretChat>();
event->chat_id = auth_state_.id;
event->set_log_event_id(binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*event)));
auto log_event_id = binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*event));
auto on_sync = PromiseCreator::lambda(
[actor_id = actor_id(this), event = std::move(event), promise = std::move(promise)](Result<Unit> result) mutable {
if (result.is_ok()) {
send_closure(actor_id, &SecretChatActor::do_close_chat_impl, std::move(event));
promise.set_value(Unit());
} else {
promise.set_error(result.error().clone());
send_closure(actor_id, &SecretChatActor::on_promise_error, result.move_as_error(), "do_close_chat_impl");
}
});
auto on_sync = PromiseCreator::lambda([actor_id = actor_id(this), delete_history, is_already_discarded, log_event_id,
promise = std::move(promise)](Result<Unit> result) mutable {
if (result.is_ok()) {
send_closure(actor_id, &SecretChatActor::do_close_chat_impl, delete_history, is_already_discarded, log_event_id,
std::move(promise));
} else {
promise.set_error(result.error().clone());
send_closure(actor_id, &SecretChatActor::on_promise_error, result.move_as_error(), "cancel_chat");
}
});
context_->binlog()->force_sync(std::move(on_sync));
yield();
}
void SecretChatActor::do_close_chat_impl(unique_ptr<log_event::CloseSecretChat> event) {
void SecretChatActor::do_close_chat_impl(bool delete_history, bool is_already_discarded, uint64 log_event_id,
Promise<Unit> &&promise) {
close_flag_ = true;
close_log_event_id_ = event->log_event_id();
LOG(INFO) << "Send messages.discardEncryption";
auth_state_.state = State::Closed;
context_->secret_chat_db()->set_value(auth_state_);
context_->secret_chat_db()->erase_value(config_state_);
context_->secret_chat_db()->erase_value(pfs_state_);
context_->secret_chat_db()->erase_value(seq_no_state_);
auto query = create_net_query(QueryType::DiscardEncryption, telegram_api::messages_discardEncryption(auth_state_.id));
MultiPromiseActorSafe mpas{"DeleteMessagesFromServerMultiPromiseActor"};
mpas.add_promise(
PromiseCreator::lambda([actor_id = actor_id(this), log_event_id, promise = std::move(promise)](Unit) mutable {
send_closure(actor_id, &SecretChatActor::on_closed, log_event_id, std::move(promise));
}));
auto lock = mpas.get_promise();
if (delete_history) {
context_->on_flush_history(true, MessageId::max(), mpas.get_promise());
}
send_update_secret_chat();
context_->send_net_query(std::move(query), actor_shared(this), true);
if (!is_already_discarded) {
int32 flags = 0;
if (delete_history) {
flags |= telegram_api::messages_discardEncryption::DELETE_HISTORY_MASK;
}
auto query = create_net_query(QueryType::DiscardEncryption,
telegram_api::messages_discardEncryption(flags, false /*ignored*/, auth_state_.id));
query->total_timeout_limit_ = 60 * 60 * 24 * 365;
context_->send_net_query(std::move(query), actor_shared(this), true);
discard_encryption_promise_ = mpas.get_promise();
}
lock.set_value(Unit());
}
void SecretChatActor::on_closed(uint64 log_event_id, Promise<Unit> &&promise) {
CHECK(close_flag_);
if (context_->close_flag()) {
return;
}
LOG(INFO) << "Finish closing";
context_->secret_chat_db()->erase_value(auth_state_);
binlog_erase(context_->binlog(), log_event_id);
promise.set_value(Unit());
// skip flush
stop();
}
void SecretChatActor::do_create_chat_impl(unique_ptr<log_event::CreateSecretChat> event) {
@ -788,18 +824,6 @@ void SecretChatActor::do_create_chat_impl(unique_ptr<log_event::CreateSecretChat
create_log_event_id_ = 0;
}
}
void SecretChatActor::on_discard_encryption_result(NetQueryPtr result) {
CHECK(close_flag_);
CHECK(close_log_event_id_ != 0);
if (context_->close_flag()) {
return;
}
LOG(INFO) << "Got result for messages.discardEncryption";
context_->secret_chat_db()->erase_value(auth_state_);
binlog_erase(context_->binlog(), close_log_event_id_);
// skip flush
stop();
}
telegram_api::object_ptr<telegram_api::inputUser> SecretChatActor::get_input_user() {
return telegram_api::make_object<telegram_api::inputUser>(auth_state_.user_id, auth_state_.user_access_hash);
@ -1325,7 +1349,8 @@ Status SecretChatActor::do_inbound_message_decrypted(unique_ptr<log_event::Inbou
std::move(save_message_finish));
break;
case secret_api::decryptedMessageActionFlushHistory::ID:
context_->on_flush_history(MessageId(ServerMessageId(message->message_id)), std::move(save_message_finish));
context_->on_flush_history(false, MessageId(ServerMessageId(message->message_id)),
std::move(save_message_finish));
break;
case secret_api::decryptedMessageActionReadMessages::ID: {
const auto &random_ids =
@ -1899,7 +1924,8 @@ Status SecretChatActor::on_update_chat(telegram_api::encryptedChat &update) {
return Status::OK();
}
Status SecretChatActor::on_update_chat(telegram_api::encryptedChatDiscarded &update) {
return Status::Error("Chat discarded");
cancel_chat(update.history_deleted_, true, Promise<Unit>());
return Status::OK();
}
Status SecretChatActor::on_update_chat(NetQueryPtr query) {
@ -2015,7 +2041,7 @@ void SecretChatActor::calc_key_hash() {
auto sha256_slice = MutableSlice(sha256_buf, 32);
sha256(pfs_state_.auth_key.key(), sha256_slice);
auth_state_.key_hash = sha1_slice.truncate(16).str() + sha256_slice.truncate(20).str();
auth_state_.key_hash = PSTRING() << sha1_slice.substr(0, 16) << sha256_slice.substr(0, 20);
}
void SecretChatActor::send_update_secret_chat() {

View File

@ -55,7 +55,8 @@ class SecretChatActor : public NetQueryCallback {
VIDEO_NOTES_LAYER = 66,
MTPROTO_2_LAYER = 73,
NEW_ENTITIES_LAYER = 101,
MY_LAYER = NEW_ENTITIES_LAYER
DELETE_MESSAGES_ON_CLOSE_LAYER = 123,
MY_LAYER = DELETE_MESSAGES_ON_CLOSE_LAYER
};
class Context {
@ -96,7 +97,7 @@ class SecretChatActor : public NetQueryCallback {
tl_object_ptr<telegram_api::encryptedFile> file,
tl_object_ptr<secret_api::decryptedMessage> message, Promise<> promise) = 0;
virtual void on_delete_messages(std::vector<int64> random_id, Promise<> promise) = 0;
virtual void on_flush_history(MessageId message_id, Promise<> promise) = 0;
virtual void on_flush_history(bool remove_from_dialog_list, MessageId message_id, Promise<> promise) = 0;
virtual void on_read_message(int64 random_id, Promise<> promise) = 0;
virtual void on_screenshot_taken(UserId user_id, MessageId message_id, int32 date, int64 random_id,
Promise<> promise) = 0;
@ -112,10 +113,11 @@ class SecretChatActor : public NetQueryCallback {
SecretChatActor(int32 id, unique_ptr<Context> context, bool can_be_empty);
// First query to new chat must be on of these two
// First query to new chat must be one of these two
void update_chat(telegram_api::object_ptr<telegram_api::EncryptedChat> chat);
void create_chat(int32 user_id, int64 user_access_hash, int32 random_id, Promise<SecretChatId> promise);
void cancel_chat(Promise<> promise);
void cancel_chat(bool delete_history, bool is_already_discarded, Promise<> promise);
// Inbound messages
// Logevent is created by SecretChatsManager, because it must contain qts
@ -461,7 +463,7 @@ class SecretChatActor : public NetQueryCallback {
bool binlog_replay_finish_flag_ = false;
bool close_flag_ = false;
LogEvent::Id close_log_event_id_ = 0;
Promise<Unit> discard_encryption_promise_;
LogEvent::Id create_log_event_id_ = 0;
@ -637,8 +639,8 @@ class SecretChatActor : public NetQueryCallback {
// DiscardEncryption
void on_fatal_error(Status status);
void do_close_chat_impl(unique_ptr<log_event::CloseSecretChat> event);
void on_discard_encryption_result(NetQueryPtr result);
void do_close_chat_impl(bool delete_history, bool is_already_discarded, uint64 log_event_id, Promise<Unit> &&promise);
void on_closed(uint64 log_event_id, Promise<Unit> &&promise);
// Other
template <class T>

View File

@ -106,10 +106,10 @@ void SecretChatsManager::create_chat(int32 user_id, int64 user_access_hash, Prom
send_closure(actor, &SecretChatActor::create_chat, user_id, user_access_hash, random_id, std::move(promise));
}
void SecretChatsManager::cancel_chat(SecretChatId secret_chat_id, Promise<> promise) {
void SecretChatsManager::cancel_chat(SecretChatId secret_chat_id, bool delete_history, Promise<> promise) {
auto actor = get_chat_actor(secret_chat_id.get());
auto safe_promise = SafePromise<>(std::move(promise), Unit());
send_closure(actor, &SecretChatActor::cancel_chat, std::move(safe_promise));
send_closure(actor, &SecretChatActor::cancel_chat, delete_history, false, std::move(safe_promise));
}
void SecretChatsManager::send_message(SecretChatId secret_chat_id, tl_object_ptr<secret_api::decryptedMessage> message,
@ -235,8 +235,9 @@ void SecretChatsManager::replay_binlog_event(BinlogEvent &&binlog_event) {
case log_event::SecretChatEvent::Type::CreateSecretChat:
return replay_create_chat(
unique_ptr<log_event::CreateSecretChat>(static_cast<log_event::CreateSecretChat *>(message.release())));
default:
LOG(FATAL) << "Unknown log event type " << tag("type", format::as_hex(static_cast<int32>(message->get_type())));
}
LOG(FATAL) << "Unknown log event type " << tag("type", format::as_hex(static_cast<int32>(message->get_type())));
}
void SecretChatsManager::binlog_replay_finish() {
@ -372,9 +373,9 @@ unique_ptr<SecretChatActor::Context> SecretChatsManager::make_secret_chat_contex
send_closure(G()->messages_manager(), &MessagesManager::delete_secret_messages, secret_chat_id_,
std::move(random_ids), std::move(promise));
}
void on_flush_history(MessageId message_id, Promise<> promise) override {
send_closure(G()->messages_manager(), &MessagesManager::delete_secret_chat_history, secret_chat_id_, message_id,
std::move(promise));
void on_flush_history(bool remove_from_dialog_list, MessageId message_id, Promise<> promise) override {
send_closure(G()->messages_manager(), &MessagesManager::delete_secret_chat_history, secret_chat_id_,
remove_from_dialog_list, message_id, std::move(promise));
}
void on_read_message(int64 random_id, Promise<> promise) override {
send_closure(G()->messages_manager(), &MessagesManager::open_secret_message, secret_chat_id_, random_id,

View File

@ -30,13 +30,12 @@ class SecretChatsManager : public Actor {
public:
explicit SecretChatsManager(ActorShared<> parent);
// Proxy query to corrensponding SecretChatActor.
// Look for more info in SecretChatActor.h
// Proxy query to corrensponding SecretChatActor
void on_update_chat(tl_object_ptr<telegram_api::updateEncryption> update);
void on_new_message(tl_object_ptr<telegram_api::EncryptedMessage> &&message_ptr, Promise<Unit> &&promise);
void create_chat(int32 user_id, int64 user_access_hash, Promise<SecretChatId> promise);
void cancel_chat(SecretChatId, Promise<> promise);
void cancel_chat(SecretChatId secret_chat_id, bool delete_history, Promise<> promise);
void send_message(SecretChatId secret_chat_id, tl_object_ptr<secret_api::decryptedMessage> message,
tl_object_ptr<telegram_api::InputEncryptedFile> file, Promise<> promise);
void send_message_action(SecretChatId secret_chat_id, tl_object_ptr<secret_api::SendMessageAction> action);

View File

@ -546,7 +546,7 @@ void SetSecureValue::start_upload(FileManager *file_manager, FileId &file_id, Se
auto download_file_id = file_manager->dup_file_id(file_id);
file_id =
file_manager
->register_generate(FileType::Secure, FileLocationSource::FromServer, file_view.suggested_name(),
->register_generate(FileType::Secure, FileLocationSource::FromServer, file_view.suggested_path(),
PSTRING() << "#file_id#" << download_file_id.get(), DialogId(), file_view.size())
.ok();
}

View File

@ -434,7 +434,7 @@ static td_api::object_ptr<td_api::datedFile> get_dated_file_object(FileManager *
file_view.remote_location().get_access_hash(),
file_view.remote_location().get_dc_id(), ""),
FileLocationSource::FromServer, DialogId(), file_view.size(),
file_view.expected_size(), file_view.suggested_name());
file_view.expected_size(), file_view.suggested_path());
return get_dated_file_object(file_manager, dated_file);
}

View File

@ -1341,7 +1341,8 @@ tl_object_ptr<td_api::MaskPoint> StickersManager::get_mask_point_object(int32 po
}
}
vector<td_api::object_ptr<td_api::closedVectorPath>> StickersManager::get_sticker_minithumbnail(CSlice path) {
vector<td_api::object_ptr<td_api::closedVectorPath>> StickersManager::get_sticker_minithumbnail(
CSlice path, StickerSetId sticker_set_id, int64 document_id) {
if (path.empty()) {
return {};
}
@ -1435,7 +1436,7 @@ vector<td_api::object_ptr<td_api::closedVectorPath>> StickersManager::get_sticke
while (!is_closed) {
skip_commas();
if (path[pos] == '\0') {
LOG(ERROR) << "Receive unclosed path " << path;
LOG(ERROR) << "Receive unclosed path " << path << " in a sticker " << document_id << " from " << sticker_set_id;
return {};
}
if (is_alpha(path[pos])) {
@ -1522,7 +1523,8 @@ vector<td_api::object_ptr<td_api::closedVectorPath>> StickersManager::get_sticke
is_closed = true;
break;
default:
LOG(ERROR) << "Receive invalid command " << command << " at pos " << pos << " in " << path;
LOG(ERROR) << "Receive invalid command " << command << " at pos " << pos << " in a sticker " << document_id
<< " from " << sticker_set_id << ": " << path;
return {};
}
}
@ -1602,18 +1604,31 @@ tl_object_ptr<td_api::sticker> StickersManager::get_sticker_object(FileId file_i
const PhotoSize &thumbnail = sticker->m_thumbnail.file_id.is_valid() ? sticker->m_thumbnail : sticker->s_thumbnail;
auto thumbnail_format = PhotoFormat::Webp;
int64 document_id = -1;
if (!sticker->set_id.is_valid()) {
auto file_view = td_->file_manager_->get_file_view(sticker->file_id);
if (file_view.is_encrypted()) {
auto sticker_file_view = td_->file_manager_->get_file_view(sticker->file_id);
if (sticker_file_view.is_encrypted()) {
// uploaded to secret chats stickers have JPEG thumbnail instead of server-generated WEBP
thumbnail_format = PhotoFormat::Jpeg;
} else {
if (sticker_file_view.has_remote_location() && sticker_file_view.remote_location().is_document()) {
document_id = sticker_file_view.remote_location().get_id();
}
if (thumbnail.file_id.is_valid()) {
auto thumbnail_file_view = td_->file_manager_->get_file_view(thumbnail.file_id);
if (ends_with(thumbnail_file_view.suggested_path(), ".jpg")) {
thumbnail_format = PhotoFormat::Jpeg;
}
}
}
}
auto thumbnail_object = get_thumbnail_object(td_->file_manager_.get(), thumbnail, thumbnail_format);
return make_tl_object<td_api::sticker>(sticker->set_id.get(), sticker->dimensions.width, sticker->dimensions.height,
sticker->alt, sticker->is_animated, sticker->is_mask, std::move(mask_position),
get_sticker_minithumbnail(sticker->minithumbnail), std::move(thumbnail_object),
td_->file_manager_->get_file_object(file_id));
return make_tl_object<td_api::sticker>(
sticker->set_id.get(), sticker->dimensions.width, sticker->dimensions.height, sticker->alt, sticker->is_animated,
sticker->is_mask, std::move(mask_position),
get_sticker_minithumbnail(sticker->minithumbnail, sticker->set_id, document_id), std::move(thumbnail_object),
td_->file_manager_->get_file_object(file_id));
}
tl_object_ptr<td_api::stickers> StickersManager::get_stickers_object(const vector<FileId> &sticker_ids) const {
@ -1719,9 +1734,9 @@ tl_object_ptr<td_api::stickerSet> StickersManager::get_sticker_set_object(Sticke
sticker_set->is_animated ? PhotoFormat::Tgs : PhotoFormat::Webp);
return make_tl_object<td_api::stickerSet>(
sticker_set->id.get(), sticker_set->title, sticker_set->short_name, std::move(thumbnail),
get_sticker_minithumbnail(sticker_set->minithumbnail), sticker_set->is_installed && !sticker_set->is_archived,
sticker_set->is_archived, sticker_set->is_official, sticker_set->is_animated, sticker_set->is_masks,
sticker_set->is_viewed, std::move(stickers), std::move(emojis));
get_sticker_minithumbnail(sticker_set->minithumbnail, sticker_set->id, -2),
sticker_set->is_installed && !sticker_set->is_archived, sticker_set->is_archived, sticker_set->is_official,
sticker_set->is_animated, sticker_set->is_masks, sticker_set->is_viewed, std::move(stickers), std::move(emojis));
}
tl_object_ptr<td_api::stickerSets> StickersManager::get_sticker_sets_object(int32 total_count,
@ -1765,9 +1780,9 @@ tl_object_ptr<td_api::stickerSetInfo> StickersManager::get_sticker_set_info_obje
sticker_set->is_animated ? PhotoFormat::Tgs : PhotoFormat::Webp);
return make_tl_object<td_api::stickerSetInfo>(
sticker_set->id.get(), sticker_set->title, sticker_set->short_name, std::move(thumbnail),
get_sticker_minithumbnail(sticker_set->minithumbnail), sticker_set->is_installed && !sticker_set->is_archived,
sticker_set->is_archived, sticker_set->is_official, sticker_set->is_animated, sticker_set->is_masks,
sticker_set->is_viewed,
get_sticker_minithumbnail(sticker_set->minithumbnail, sticker_set->id, -3),
sticker_set->is_installed && !sticker_set->is_archived, sticker_set->is_archived, sticker_set->is_official,
sticker_set->is_animated, sticker_set->is_masks, sticker_set->is_viewed,
sticker_set->was_loaded ? narrow_cast<int32>(sticker_set->sticker_ids.size()) : sticker_set->sticker_count,
std::move(stickers));
}
@ -1842,8 +1857,19 @@ FileId StickersManager::on_get_sticker(unique_ptr<Sticker> new_sticker, bool rep
return file_id;
}
bool StickersManager::has_webp_thumbnail(const tl_object_ptr<telegram_api::documentAttributeSticker> &sticker) {
// server tries to always replace user-provided thumbnail with server-side webp thumbnail
bool StickersManager::has_webp_thumbnail(const vector<tl_object_ptr<telegram_api::PhotoSize>> &thumbnails) {
// server tries to always replace user-provided thumbnail with server-side WEBP thumbnail
// but there can be some old sticker documents or some big stickers
for (auto &size : thumbnails) {
switch (size->get_id()) {
case telegram_api::photoStrippedSize::ID:
case telegram_api::photoSizeProgressive::ID:
// WEBP thumbnail can't have stripped size or be progressive
return false;
default:
break;
}
}
return true;
}
@ -1869,7 +1895,7 @@ std::pair<int64, FileId> StickersManager::on_get_sticker_document(
switch (attribute->get_id()) {
case telegram_api::documentAttributeImageSize::ID: {
auto image_size = move_tl_object_as<telegram_api::documentAttributeImageSize>(attribute);
dimensions = get_dimensions(image_size->w_, image_size->h_);
dimensions = get_dimensions(image_size->w_, image_size->h_, "sticker documentAttributeImageSize");
break;
}
case telegram_api::documentAttributeSticker::ID:
@ -1896,18 +1922,20 @@ std::pair<int64, FileId> StickersManager::on_get_sticker_document(
PhotoSize thumbnail;
string minithumbnail;
auto thumbnail_format = has_webp_thumbnail(document->thumbs_) ? PhotoFormat::Webp : PhotoFormat::Jpeg;
for (auto &thumb : document->thumbs_) {
auto photo_size =
get_photo_size(td_->file_manager_.get(), {FileType::Thumbnail, 0}, document_id, document->access_hash_,
document->file_reference_.as_slice().str(), dc_id, DialogId(), std::move(thumb),
has_webp_thumbnail(sticker) ? PhotoFormat::Webp : PhotoFormat::Jpeg, false);
auto photo_size = get_photo_size(td_->file_manager_.get(), {FileType::Thumbnail, 0}, document_id,
document->access_hash_, document->file_reference_.as_slice().str(), dc_id,
DialogId(), std::move(thumb), thumbnail_format);
if (photo_size.get_offset() == 0) {
if (!thumbnail.file_id.is_valid()) {
thumbnail = std::move(photo_size.get<0>());
}
break;
} else {
minithumbnail = std::move(photo_size.get<1>());
if (thumbnail_format == PhotoFormat::Webp) {
minithumbnail = std::move(photo_size.get<1>());
}
}
}
@ -2414,8 +2442,8 @@ tl_object_ptr<telegram_api::InputMedia> StickersManager::get_input_media(
}
auto mime_type = get_sticker_mime_type(s);
if (!s->is_animated && !s->set_id.is_valid()) {
auto suggested_name = file_view.suggested_name();
const PathView path_view(suggested_name);
auto suggested_path = file_view.suggested_path();
const PathView path_view(suggested_path);
if (path_view.extension() == "tgs") {
mime_type = "application/x-tgsticker";
}
@ -2447,7 +2475,7 @@ StickerSetId StickersManager::on_get_sticker_set(tl_object_ptr<telegram_api::sti
for (auto &thumb : set->thumbs_) {
auto photo_size = get_photo_size(td_->file_manager_.get(), {set_id.get(), s->access_hash}, 0, 0, "",
DcId::create(set->thumb_dc_id_), DialogId(), std::move(thumb),
is_animated ? PhotoFormat::Tgs : PhotoFormat::Webp, false);
is_animated ? PhotoFormat::Tgs : PhotoFormat::Webp);
if (photo_size.get_offset() == 0) {
if (!thumbnail.file_id.is_valid()) {
thumbnail = std::move(photo_size.get<0>());
@ -4608,7 +4636,8 @@ Result<std::tuple<FileId, bool, bool, bool>> StickersManager::prepare_input_file
if (is_animated) {
int32 width = for_thumbnail ? 100 : 512;
create_sticker(file_id, string(), PhotoSize(), get_dimensions(width, width), nullptr, true, nullptr);
create_sticker(file_id, string(), PhotoSize(), get_dimensions(width, width, "prepare_input_file"), nullptr, true,
nullptr);
} else {
td_->documents_manager_->create_document(file_id, string(), PhotoSize(), "sticker.png", "image/png", false);
}

View File

@ -94,7 +94,7 @@ class StickersManager : public Actor {
vector<StickerSetId> get_installed_sticker_sets(bool is_masks, Promise<Unit> &&promise);
bool has_webp_thumbnail(const tl_object_ptr<telegram_api::documentAttributeSticker> &sticker);
static bool has_webp_thumbnail(const vector<tl_object_ptr<telegram_api::PhotoSize>> &thumbnails);
StickerSetId get_sticker_set_id(const tl_object_ptr<telegram_api::InputStickerSet> &set_ptr);
@ -398,7 +398,9 @@ class StickersManager : public Actor {
class UploadStickerFileCallback;
static vector<td_api::object_ptr<td_api::closedVectorPath>> get_sticker_minithumbnail(CSlice path);
static vector<td_api::object_ptr<td_api::closedVectorPath>> get_sticker_minithumbnail(CSlice path,
StickerSetId sticker_set_id,
int64 document_id);
static tl_object_ptr<td_api::MaskPoint> get_mask_point_object(int32 point);

View File

@ -6,50 +6,136 @@
//
#include "td/telegram/SuggestedAction.h"
#include "td/telegram/ChannelId.h"
#include "td/telegram/Global.h"
#include "td/telegram/Td.h"
#include "td/actor/actor.h"
#include "td/utils/algorithm.h"
#include <algorithm>
namespace td {
SuggestedAction get_suggested_action(Slice action_str) {
if (action_str == Slice("AUTOARCHIVE_POPULAR")) {
return SuggestedAction::EnableArchiveAndMuteNewChats;
}
return SuggestedAction::Empty;
void SuggestedAction::init(Type type) {
type_ = type;
}
string get_suggested_action_str(SuggestedAction action) {
switch (action) {
case SuggestedAction::EnableArchiveAndMuteNewChats:
SuggestedAction::SuggestedAction(Slice action_str) {
if (action_str == Slice("AUTOARCHIVE_POPULAR")) {
init(Type::EnableArchiveAndMuteNewChats);
} else if (action_str == Slice("NEWCOMER_TICKS")) {
init(Type::SeeTicksHint);
}
}
SuggestedAction::SuggestedAction(Slice action_str, DialogId dialog_id) {
CHECK(dialog_id.is_valid());
if (action_str == Slice("CONVERT_GIGAGROUP")) {
type_ = Type::ConvertToGigagroup;
dialog_id_ = dialog_id;
}
}
SuggestedAction::SuggestedAction(const td_api::object_ptr<td_api::SuggestedAction> &suggested_action) {
if (suggested_action == nullptr) {
return;
}
switch (suggested_action->get_id()) {
case td_api::suggestedActionEnableArchiveAndMuteNewChats::ID:
init(Type::EnableArchiveAndMuteNewChats);
break;
case td_api::suggestedActionCheckPhoneNumber::ID:
init(Type::CheckPhoneNumber);
break;
case td_api::suggestedActionSeeTicksHint::ID:
init(Type::SeeTicksHint);
break;
case td_api::suggestedActionConvertToBroadcastGroup::ID: {
auto action = static_cast<const td_api::suggestedActionConvertToBroadcastGroup *>(suggested_action.get());
ChannelId channel_id(action->supergroup_id_);
if (channel_id.is_valid()) {
type_ = Type::ConvertToGigagroup;
dialog_id_ = DialogId(channel_id);
}
break;
}
default:
UNREACHABLE();
}
}
string SuggestedAction::get_suggested_action_str() const {
switch (type_) {
case Type::EnableArchiveAndMuteNewChats:
return "AUTOARCHIVE_POPULAR";
case Type::SeeTicksHint:
return "NEWCOMER_TICKS";
case Type::ConvertToGigagroup:
return "CONVERT_GIGAGROUP";
default:
return string();
}
}
SuggestedAction get_suggested_action(const td_api::object_ptr<td_api::SuggestedAction> &action_object) {
if (action_object == nullptr) {
return SuggestedAction::Empty;
}
switch (action_object->get_id()) {
case td_api::suggestedActionEnableArchiveAndMuteNewChats::ID:
return SuggestedAction::EnableArchiveAndMuteNewChats;
case td_api::suggestedActionCheckPhoneNumber::ID:
return SuggestedAction::CheckPhoneNumber;
td_api::object_ptr<td_api::SuggestedAction> SuggestedAction::get_suggested_action_object() const {
switch (type_) {
case Type::Empty:
return nullptr;
case Type::EnableArchiveAndMuteNewChats:
return td_api::make_object<td_api::suggestedActionEnableArchiveAndMuteNewChats>();
case Type::CheckPhoneNumber:
return td_api::make_object<td_api::suggestedActionCheckPhoneNumber>();
case Type::SeeTicksHint:
return td_api::make_object<td_api::suggestedActionSeeTicksHint>();
case Type::ConvertToGigagroup:
return td_api::make_object<td_api::suggestedActionConvertToBroadcastGroup>(dialog_id_.get_channel_id().get());
default:
UNREACHABLE();
return SuggestedAction::Empty;
return nullptr;
}
}
td_api::object_ptr<td_api::SuggestedAction> get_suggested_action_object(SuggestedAction action) {
switch (action) {
case SuggestedAction::Empty:
return nullptr;
case SuggestedAction::EnableArchiveAndMuteNewChats:
return td_api::make_object<td_api::suggestedActionEnableArchiveAndMuteNewChats>();
case SuggestedAction::CheckPhoneNumber:
return td_api::make_object<td_api::suggestedActionCheckPhoneNumber>();
default:
UNREACHABLE();
return nullptr;
td_api::object_ptr<td_api::updateSuggestedActions> get_update_suggested_actions_object(
const vector<SuggestedAction> &added_actions, const vector<SuggestedAction> &removed_actions) {
auto get_object = [](const SuggestedAction &action) {
return action.get_suggested_action_object();
};
return td_api::make_object<td_api::updateSuggestedActions>(transform(added_actions, get_object),
transform(removed_actions, get_object));
}
void update_suggested_actions(vector<SuggestedAction> &suggested_actions,
vector<SuggestedAction> &&new_suggested_actions) {
td::unique(new_suggested_actions);
if (new_suggested_actions == suggested_actions) {
return;
}
vector<SuggestedAction> added_actions;
vector<SuggestedAction> removed_actions;
auto old_it = suggested_actions.begin();
auto new_it = new_suggested_actions.begin();
while (old_it != suggested_actions.end() || new_it != new_suggested_actions.end()) {
if (old_it != suggested_actions.end() && (new_it == new_suggested_actions.end() || *old_it < *new_it)) {
removed_actions.push_back(*old_it++);
} else if (old_it == suggested_actions.end() || *new_it < *old_it) {
added_actions.push_back(*new_it++);
} else {
old_it++;
new_it++;
}
}
CHECK(!added_actions.empty() || !removed_actions.empty());
suggested_actions = std::move(new_suggested_actions);
send_closure(G()->td(), &Td::send_update,
get_update_suggested_actions_object(std::move(added_actions), std::move(removed_actions)));
}
void remove_suggested_action(vector<SuggestedAction> &suggested_actions, SuggestedAction suggested_action) {
if (td::remove(suggested_actions, suggested_action)) {
send_closure(G()->td(), &Td::send_update, get_update_suggested_actions_object({}, {suggested_action}));
}
}

View File

@ -6,6 +6,7 @@
//
#pragma once
#include "td/telegram/DialogId.h"
#include "td/telegram/td_api.h"
#include "td/utils/common.h"
@ -13,14 +14,53 @@
namespace td {
enum class SuggestedAction : int32 { Empty, EnableArchiveAndMuteNewChats, CheckPhoneNumber };
struct SuggestedAction {
enum class Type : int32 { Empty, EnableArchiveAndMuteNewChats, CheckPhoneNumber, SeeTicksHint, ConvertToGigagroup };
Type type_ = Type::Empty;
DialogId dialog_id_;
SuggestedAction get_suggested_action(Slice action_str);
void init(Type type);
string get_suggested_action_str(SuggestedAction action);
SuggestedAction() = default;
SuggestedAction get_suggested_action(const td_api::object_ptr<td_api::SuggestedAction> &action_object);
explicit SuggestedAction(Type type, DialogId dialog_id = DialogId()) : type_(type), dialog_id_(dialog_id) {
}
td_api::object_ptr<td_api::SuggestedAction> get_suggested_action_object(SuggestedAction action);
explicit SuggestedAction(Slice action_str);
SuggestedAction(Slice action_str, DialogId dialog_id);
explicit SuggestedAction(const td_api::object_ptr<td_api::SuggestedAction> &suggested_action);
bool is_empty() const {
return type_ == Type::Empty;
}
string get_suggested_action_str() const;
td_api::object_ptr<td_api::SuggestedAction> get_suggested_action_object() const;
};
inline bool operator==(const SuggestedAction &lhs, const SuggestedAction &rhs) {
CHECK(lhs.dialog_id_ == rhs.dialog_id_);
return lhs.type_ == rhs.type_;
}
inline bool operator!=(const SuggestedAction &lhs, const SuggestedAction &rhs) {
return !(lhs == rhs);
}
inline bool operator<(const SuggestedAction &lhs, const SuggestedAction &rhs) {
CHECK(lhs.dialog_id_ == rhs.dialog_id_);
return static_cast<int32>(lhs.type_) < static_cast<int32>(rhs.type_);
}
td_api::object_ptr<td_api::updateSuggestedActions> get_update_suggested_actions_object(
const vector<SuggestedAction> &added_actions, const vector<SuggestedAction> &removed_actions);
void update_suggested_actions(vector<SuggestedAction> &suggested_actions,
vector<SuggestedAction> &&new_suggested_actions);
void remove_suggested_action(vector<SuggestedAction> &suggested_actions, SuggestedAction suggested_action);
} // namespace td

View File

@ -80,6 +80,7 @@
#include "td/telegram/PollManager.h"
#include "td/telegram/PrivacyManager.h"
#include "td/telegram/PublicDialogType.h"
#include "td/telegram/ReportReason.h"
#include "td/telegram/RequestActor.h"
#include "td/telegram/SecretChatId.h"
#include "td/telegram/SecretChatsManager.h"
@ -526,8 +527,6 @@ class SaveAppLogQuery : public Td::ResultHandler {
}
};
/*** Td ***/
/** Td queries **/
class TestQuery : public Td::ResultHandler {
public:
explicit TestQuery(uint64 request_id) : request_id_(request_id) {
@ -1875,7 +1874,7 @@ class CreateNewSecretChatRequest : public RequestActor<SecretChatId> {
// But since the update may still be on its way, we will update essential fields here.
td->contacts_manager_->on_update_secret_chat(
secret_chat_id_, 0 /* no access_hash */, user_id_, SecretChatState::Unknown, true /* it is outbound chat */,
-1 /* unknown ttl */, 0 /* unknown creation date */, "" /* no key_hash */, 0, FolderId());
-1 /* unknown TTL */, 0 /* unknown creation date */, "" /* no key_hash */, 0, FolderId());
DialogId dialog_id(secret_chat_id_);
td->messages_manager_->force_create_dialog(dialog_id, "create new secret chat", true);
send_result(td->messages_manager_->get_chat_object(dialog_id));
@ -1892,13 +1891,14 @@ class CreateNewSupergroupChatRequest : public RequestActor<> {
bool is_megagroup_;
string description_;
DialogLocation location_;
bool for_import_;
int64 random_id_;
DialogId dialog_id_;
void do_run(Promise<Unit> &&promise) override {
dialog_id_ = td->messages_manager_->create_new_channel_chat(title_, is_megagroup_, description_, location_,
random_id_, std::move(promise));
for_import_, random_id_, std::move(promise));
}
void do_send_result() override {
@ -1908,12 +1908,14 @@ class CreateNewSupergroupChatRequest : public RequestActor<> {
public:
CreateNewSupergroupChatRequest(ActorShared<Td> td, uint64 request_id, string title, bool is_megagroup,
string description, td_api::object_ptr<td_api::chatLocation> &&location)
string description, td_api::object_ptr<td_api::chatLocation> &&location,
bool for_import)
: RequestActor(std::move(td), request_id)
, title_(std::move(title))
, is_megagroup_(is_megagroup)
, description_(std::move(description))
, location_(std::move(location))
, for_import_(for_import)
, random_id_(0) {
}
};
@ -1947,7 +1949,7 @@ class GetChatMemberRequest : public RequestActor<> {
DialogParticipant dialog_participant_;
void do_run(Promise<Unit> &&promise) override {
dialog_participant_ = td->messages_manager_->get_dialog_participant(dialog_id_, user_id_, random_id_,
dialog_participant_ = td->contacts_manager_->get_dialog_participant(dialog_id_, user_id_, random_id_,
get_tries() < 3, std::move(promise));
}
@ -1965,50 +1967,13 @@ class GetChatMemberRequest : public RequestActor<> {
}
};
class SearchChatMembersRequest : public RequestActor<> {
DialogId dialog_id_;
string query_;
int32 limit_;
DialogParticipantsFilter filter_;
int64 random_id_ = 0;
std::pair<int32, vector<DialogParticipant>> participants_;
void do_run(Promise<Unit> &&promise) override {
participants_ = td->messages_manager_->search_dialog_participants(dialog_id_, query_, limit_, filter_, random_id_,
false, get_tries() < 3, std::move(promise));
}
void do_send_result() override {
// TODO create function get_chat_members_object
vector<tl_object_ptr<td_api::chatMember>> result;
result.reserve(participants_.second.size());
for (auto participant : participants_.second) {
result.push_back(td->contacts_manager_->get_chat_member_object(participant));
}
send_result(make_tl_object<td_api::chatMembers>(participants_.first, std::move(result)));
}
public:
SearchChatMembersRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, string &&query, int32 limit,
DialogParticipantsFilter filter)
: RequestActor(std::move(td), request_id)
, dialog_id_(dialog_id)
, query_(std::move(query))
, limit_(limit)
, filter_(filter) {
set_tries(3);
}
};
class GetChatAdministratorsRequest : public RequestActor<> {
DialogId dialog_id_;
vector<DialogAdministrator> administrators_;
void do_run(Promise<Unit> &&promise) override {
administrators_ = td->messages_manager_->get_dialog_administrators(dialog_id_, get_tries(), std::move(promise));
administrators_ = td->contacts_manager_->get_dialog_administrators(dialog_id_, get_tries(), std::move(promise));
}
void do_send_result() override {
@ -2026,23 +1991,6 @@ class GetChatAdministratorsRequest : public RequestActor<> {
}
};
class GenerateChatInviteLinkRequest : public RequestOnceActor {
DialogId dialog_id_;
void do_run(Promise<Unit> &&promise) override {
td->messages_manager_->export_dialog_invite_link(dialog_id_, std::move(promise));
}
void do_send_result() override {
send_result(make_tl_object<td_api::chatInviteLink>(td->messages_manager_->get_dialog_invite_link(dialog_id_)));
}
public:
GenerateChatInviteLinkRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id)
: RequestOnceActor(std::move(td), request_id), dialog_id_(dialog_id) {
}
};
class CheckChatInviteLinkRequest : public RequestActor<> {
string invite_link_;
@ -2282,43 +2230,6 @@ class GetRecentInlineBotsRequest : public RequestActor<> {
}
};
class GetSupergroupMembersRequest : public RequestActor<> {
ChannelId channel_id_;
tl_object_ptr<td_api::SupergroupMembersFilter> filter_;
int32 offset_;
int32 limit_;
int64 random_id_ = 0;
std::pair<int32, vector<DialogParticipant>> participants_;
void do_run(Promise<Unit> &&promise) override {
participants_ = td->contacts_manager_->get_channel_participants(
channel_id_, filter_, string(), offset_, limit_, -1, random_id_, false, get_tries() < 3, std::move(promise));
}
void do_send_result() override {
// TODO create function get_chat_members_object
vector<tl_object_ptr<td_api::chatMember>> result;
result.reserve(participants_.second.size());
for (auto participant : participants_.second) {
result.push_back(td->contacts_manager_->get_chat_member_object(participant));
}
send_result(make_tl_object<td_api::chatMembers>(participants_.first, std::move(result)));
}
public:
GetSupergroupMembersRequest(ActorShared<Td> td, uint64 request_id, int32 channel_id,
tl_object_ptr<td_api::SupergroupMembersFilter> &&filter, int32 offset, int32 limit)
: RequestActor(std::move(td), request_id)
, channel_id_(channel_id)
, filter_(std::move(filter))
, offset_(offset)
, limit_(limit) {
set_tries(3);
}
};
class GetUserProfilePhotosRequest : public RequestActor<> {
UserId user_id_;
int32 offset_;
@ -3124,6 +3035,7 @@ void Td::on_alarm_timeout(int64 alarm_id) {
updates_manager_->ping_server();
alarm_timeout_.set_timeout_in(PING_SERVER_ALARM_ID,
PING_SERVER_TIMEOUT + Random::fast(0, PING_SERVER_TIMEOUT / 5));
set_is_bot_online(false);
}
return;
}
@ -3231,7 +3143,7 @@ void Td::on_get_promo_data(Result<telegram_api::object_ptr<telegram_api::help_Pr
}
if (r_promo_data.is_error()) {
LOG(ERROR) << "Receive error for GetPromoDataQuery: " << r_promo_data.error();
LOG(ERROR) << "Receive error for GetPromoData: " << r_promo_data.error();
return schedule_get_promo_data(60);
}
@ -3264,7 +3176,7 @@ void Td::on_get_promo_data(Result<telegram_api::object_ptr<telegram_api::help_Pr
}
void Td::schedule_get_promo_data(int32 expires_in) {
expires_in = clamp(expires_in, 60, 86400);
expires_in = expires_in <= 0 ? 0 : clamp(expires_in, 60, 86400);
if (!close_flag_ && auth_manager_->is_authorized() && !auth_manager_->is_bot()) {
LOG(INFO) << "Schedule getPromoData in " << expires_in;
alarm_timeout_.set_timeout_in(PROMO_DATA_ALARM_ID, expires_in);
@ -3282,6 +3194,15 @@ bool Td::is_online() const {
return is_online_;
}
void Td::set_is_bot_online(bool is_bot_online) {
if (is_bot_online == is_bot_online_) {
return;
}
is_bot_online_ = is_bot_online;
send_closure(G()->state_manager(), &StateManager::on_online, is_bot_online_);
}
bool Td::is_authentication_request(int32 id) {
switch (id) {
case td_api::setTdlibParameters::ID:
@ -3632,6 +3553,7 @@ void Td::on_result(NetQueryPtr query) {
if (auth_manager_->is_bot() && auth_manager_->is_authorized()) {
alarm_timeout_.set_timeout_in(PING_SERVER_ALARM_ID,
PING_SERVER_TIMEOUT + Random::fast(0, PING_SERVER_TIMEOUT / 5));
set_is_bot_online(true);
}
}
return;
@ -4292,7 +4214,7 @@ Status Td::init(DbKey key) {
on_online_updated(true, true);
}
if (auth_manager_->is_bot()) {
send_closure(G()->state_manager(), &StateManager::on_online, true);
set_is_bot_online(true);
}
// Send binlog events to managers
@ -5367,10 +5289,10 @@ void Td::on_request(uint64 id, td_api::optimizeStorage &request) {
}
void Td::on_request(uint64 id, td_api::getNetworkStatistics &request) {
CREATE_REQUEST_PROMISE();
if (!request.only_current_ && G()->shared_config().get_option_boolean("disable_persistent_network_statistics")) {
return send_error_raw(id, 400, "Persistent network statistics is disabled");
}
CREATE_REQUEST_PROMISE();
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<NetworkStats> result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
@ -5453,23 +5375,23 @@ void Td::on_request(uint64 id, const td_api::getAutoDownloadSettingsPresets &req
void Td::on_request(uint64 id, const td_api::setAutoDownloadSettings &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
if (request.settings_ == nullptr) {
return send_error_raw(id, 400, "New settings must be non-empty");
}
CREATE_OK_REQUEST_PROMISE();
set_auto_download_settings(this, get_net_type(request.type_), get_auto_download_settings(request.settings_),
std::move(promise));
}
void Td::on_request(uint64 id, td_api::getTopChats &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
if (request.category_ == nullptr) {
return promise.set_error(Status::Error(400, "Top chat category must be non-empty"));
return send_error_raw(id, 400, "Top chat category must be non-empty");
}
if (request.limit_ <= 0) {
return promise.set_error(Status::Error(400, "Limit must be positive"));
return send_error_raw(id, 400, "Limit must be positive");
}
CREATE_REQUEST_PROMISE();
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<vector<DialogId>> result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
@ -5611,6 +5533,21 @@ void Td::on_request(uint64 id, const td_api::openMessageContent &request) {
id, messages_manager_->open_message_content({DialogId(request.chat_id_), MessageId(request.message_id_)}));
}
void Td::on_request(uint64 id, td_api::getExternalLink &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.link_);
CREATE_REQUEST_PROMISE();
auto query_promise = [promise = std::move(promise)](Result<string> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(td_api::make_object<td_api::httpUrl>(result.ok()));
}
};
send_closure_later(G()->config_manager(), &ConfigManager::get_external_link, std::move(request.link_),
std::move(query_promise));
}
void Td::on_request(uint64 id, const td_api::getChatHistory &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetChatHistoryRequest, request.chat_id_, request.from_message_id_, request.offset_, request.limit_,
@ -5624,6 +5561,21 @@ void Td::on_request(uint64 id, const td_api::deleteChatHistory &request) {
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::deleteChat &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
DialogId dialog_id(request.chat_id_);
auto query_promise = [actor_id = messages_manager_actor_.get(), dialog_id,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &MessagesManager::on_dialog_deleted, dialog_id, std::move(promise));
}
};
contacts_manager_->delete_dialog(dialog_id, std::move(query_promise));
}
void Td::on_request(uint64 id, const td_api::getMessageThreadHistory &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetMessageThreadHistoryRequest, request.chat_id_, request.message_id_, request.from_message_id_,
@ -5663,6 +5615,12 @@ void Td::on_request(uint64 id, td_api::searchCallMessages &request) {
CREATE_REQUEST(SearchCallMessagesRequest, request.from_message_id_, request.limit_, request.only_missed_);
}
void Td::on_request(uint64 id, const td_api::deleteAllCallMessages &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
messages_manager_->delete_all_call_messages(request.revoke_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::searchChatRecentLocationMessages &request) {
CHECK_IS_USER();
CREATE_REQUEST(SearchChatRecentLocationMessagesRequest, request.chat_id_, request.limit_);
@ -5789,18 +5747,6 @@ void Td::on_request(uint64 id, td_api::sendInlineQueryResultMessage &request) {
messages_manager_->get_message_object({dialog_id, r_new_message_id.ok()}));
}
void Td::on_request(uint64 id, const td_api::sendChatSetTtlMessage &request) {
DialogId dialog_id(request.chat_id_);
auto r_new_message_id = messages_manager_->send_dialog_set_ttl_message(dialog_id, request.ttl_);
if (r_new_message_id.is_error()) {
return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error());
}
CHECK(r_new_message_id.ok().is_valid());
send_closure(actor_id(this), &Td::send_result, id,
messages_manager_->get_message_object({dialog_id, r_new_message_id.ok()}));
}
void Td::on_request(uint64 id, td_api::addLocalMessage &request) {
CHECK_IS_USER();
@ -6003,7 +5949,7 @@ void Td::on_request(uint64 id, td_api::createNewSupergroupChat &request) {
CLEAN_INPUT_STRING(request.title_);
CLEAN_INPUT_STRING(request.description_);
CREATE_REQUEST(CreateNewSupergroupChatRequest, std::move(request.title_), !request.is_channel_,
std::move(request.description_), std::move(request.location_));
std::move(request.description_), std::move(request.location_), request.for_import_);
}
void Td::on_request(uint64 id, td_api::createNewSecretChat &request) {
CREATE_REQUEST(CreateNewSecretChatRequest, request.user_id_);
@ -6011,6 +5957,21 @@ void Td::on_request(uint64 id, td_api::createNewSecretChat &request) {
void Td::on_request(uint64 id, const td_api::createCall &request) {
CHECK_IS_USER();
if (request.protocol_ == nullptr) {
return send_error_raw(id, 400, "Call protocol must be non-empty");
}
UserId user_id(request.user_id_);
auto input_user = contacts_manager_->get_input_user(user_id);
if (input_user == nullptr) {
return send_error_raw(id, 400, "User not found");
}
if (!G()->shared_config().get_option_boolean("calls_enabled")) {
return send_error_raw(id, 400, "Calls are not enabled for the current user");
}
CREATE_REQUEST_PROMISE();
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<CallId> result) mutable {
if (result.is_error()) {
@ -6019,31 +5980,16 @@ void Td::on_request(uint64 id, const td_api::createCall &request) {
promise.set_value(result.ok().get_call_id_object());
}
});
if (!request.protocol_) {
return query_promise.set_error(Status::Error(5, "Call protocol must be non-empty"));
}
UserId user_id(request.user_id_);
auto input_user = contacts_manager_->get_input_user(user_id);
if (input_user == nullptr) {
return query_promise.set_error(Status::Error(6, "User not found"));
}
if (!G()->shared_config().get_option_boolean("calls_enabled")) {
return query_promise.set_error(Status::Error(7, "Calls are not enabled for the current user"));
}
send_closure(G()->call_manager(), &CallManager::create_call, user_id, std::move(input_user),
CallProtocol(*request.protocol_), request.is_video_, std::move(query_promise));
}
void Td::on_request(uint64 id, const td_api::acceptCall &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
if (!request.protocol_) {
return promise.set_error(Status::Error(5, "Call protocol must be non-empty"));
if (request.protocol_ == nullptr) {
return send_error_raw(id, 400, "Call protocol must be non-empty");
}
CREATE_OK_REQUEST_PROMISE();
send_closure(G()->call_manager(), &CallManager::accept_call, CallId(request.call_id_),
CallProtocol(*request.protocol_), std::move(promise));
}
@ -6136,6 +6082,13 @@ void Td::on_request(uint64 id, const td_api::toggleGroupCallParticipantIsMuted &
GroupCallId(request.group_call_id_), UserId(request.user_id_), request.is_muted_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::setGroupCallParticipantVolumeLevel &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
group_call_manager_->set_group_call_participant_volume_level(
GroupCallId(request.group_call_id_), UserId(request.user_id_), request.volume_level_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::loadGroupCallParticipants &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
@ -6233,6 +6186,11 @@ void Td::on_request(uint64 id, const td_api::setChatPhoto &request) {
messages_manager_->set_dialog_photo(DialogId(request.chat_id_), request.photo_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::setChatMessageTtlSetting &request) {
CREATE_OK_REQUEST_PROMISE();
messages_manager_->set_dialog_message_ttl_setting(DialogId(request.chat_id_), request.ttl_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::setChatPermissions &request) {
CREATE_OK_REQUEST_PROMISE();
messages_manager_->set_dialog_permissions(DialogId(request.chat_id_), request.permissions_, std::move(promise));
@ -6328,7 +6286,7 @@ void Td::on_request(uint64 id, const td_api::unpinAllChatMessages &request) {
void Td::on_request(uint64 id, const td_api::joinChat &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
messages_manager_->add_dialog_participant(DialogId(request.chat_id_), contacts_manager_->get_my_id(), 0,
contacts_manager_->add_dialog_participant(DialogId(request.chat_id_), contacts_manager_->get_my_id(), 0,
std::move(promise));
}
@ -6347,14 +6305,14 @@ void Td::on_request(uint64 id, const td_api::leaveChat &request) {
td_api::make_object<td_api::chatMemberStatusCreator>(status.get_rank(), status.is_anonymous(), false);
}
}
messages_manager_->set_dialog_participant_status(dialog_id, contacts_manager_->get_my_id(), std::move(new_status),
contacts_manager_->set_dialog_participant_status(dialog_id, contacts_manager_->get_my_id(), std::move(new_status),
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::addChatMember &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
messages_manager_->add_dialog_participant(DialogId(request.chat_id_), UserId(request.user_id_),
contacts_manager_->add_dialog_participant(DialogId(request.chat_id_), UserId(request.user_id_),
request.forward_limit_, std::move(promise));
}
@ -6365,15 +6323,21 @@ void Td::on_request(uint64 id, const td_api::addChatMembers &request) {
for (auto &user_id : request.user_ids_) {
user_ids.emplace_back(user_id);
}
messages_manager_->add_dialog_participants(DialogId(request.chat_id_), user_ids, std::move(promise));
contacts_manager_->add_dialog_participants(DialogId(request.chat_id_), user_ids, std::move(promise));
}
void Td::on_request(uint64 id, td_api::setChatMemberStatus &request) {
CREATE_OK_REQUEST_PROMISE();
messages_manager_->set_dialog_participant_status(DialogId(request.chat_id_), UserId(request.user_id_),
contacts_manager_->set_dialog_participant_status(DialogId(request.chat_id_), UserId(request.user_id_),
request.status_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::banChatMember &request) {
CREATE_OK_REQUEST_PROMISE();
contacts_manager_->ban_dialog_participant(DialogId(request.chat_id_), UserId(request.user_id_),
request.banned_until_date_, request.revoke_messages_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::canTransferOwnership &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
@ -6390,8 +6354,8 @@ void Td::on_request(uint64 id, const td_api::canTransferOwnership &request) {
void Td::on_request(uint64 id, td_api::transferChatOwnership &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
CLEAN_INPUT_STRING(request.password_);
CREATE_OK_REQUEST_PROMISE();
contacts_manager_->transfer_dialog_ownership(DialogId(request.chat_id_), UserId(request.user_id_), request.password_,
std::move(promise));
}
@ -6402,16 +6366,92 @@ void Td::on_request(uint64 id, const td_api::getChatMember &request) {
void Td::on_request(uint64 id, td_api::searchChatMembers &request) {
CLEAN_INPUT_STRING(request.query_);
CREATE_REQUEST(SearchChatMembersRequest, request.chat_id_, std::move(request.query_), request.limit_,
get_dialog_participants_filter(request.filter_));
CREATE_REQUEST_PROMISE();
auto query_promise =
PromiseCreator::lambda([promise = std::move(promise), td = this](Result<DialogParticipants> result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(result.ok().get_chat_members_object(td));
}
});
contacts_manager_->search_dialog_participants(DialogId(request.chat_id_), request.query_, request.limit_,
get_dialog_participants_filter(request.filter_), false,
std::move(query_promise));
}
void Td::on_request(uint64 id, td_api::getChatAdministrators &request) {
CREATE_REQUEST(GetChatAdministratorsRequest, request.chat_id_);
}
void Td::on_request(uint64 id, const td_api::generateChatInviteLink &request) {
CREATE_REQUEST(GenerateChatInviteLinkRequest, request.chat_id_);
void Td::on_request(uint64 id, const td_api::replacePrimaryChatInviteLink &request) {
CREATE_REQUEST_PROMISE();
contacts_manager_->export_dialog_invite_link(DialogId(request.chat_id_), 0, 0, true, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::createChatInviteLink &request) {
CREATE_REQUEST_PROMISE();
contacts_manager_->export_dialog_invite_link(DialogId(request.chat_id_), request.expire_date_, request.member_limit_,
false, std::move(promise));
}
void Td::on_request(uint64 id, td_api::editChatInviteLink &request) {
CLEAN_INPUT_STRING(request.invite_link_);
CREATE_REQUEST_PROMISE();
contacts_manager_->edit_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, request.expire_date_,
request.member_limit_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::getChatInviteLink &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.invite_link_);
CREATE_REQUEST_PROMISE();
contacts_manager_->get_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getChatInviteLinkCounts &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
contacts_manager_->get_dialog_invite_link_counts(DialogId(request.chat_id_), std::move(promise));
}
void Td::on_request(uint64 id, td_api::getChatInviteLinks &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.offset_invite_link_);
CREATE_REQUEST_PROMISE();
contacts_manager_->get_dialog_invite_links(DialogId(request.chat_id_), UserId(request.creator_user_id_),
request.is_revoked_, request.offset_date_, request.offset_invite_link_,
request.limit_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::getChatInviteLinkMembers &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.invite_link_);
CREATE_REQUEST_PROMISE();
contacts_manager_->get_dialog_invite_link_users(DialogId(request.chat_id_), request.invite_link_,
std::move(request.offset_member_), request.limit_,
std::move(promise));
}
void Td::on_request(uint64 id, td_api::revokeChatInviteLink &request) {
CLEAN_INPUT_STRING(request.invite_link_);
CREATE_REQUEST_PROMISE();
contacts_manager_->revoke_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::deleteRevokedChatInviteLink &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.invite_link_);
CREATE_OK_REQUEST_PROMISE();
contacts_manager_->delete_revoked_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_,
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::deleteAllRevokedChatInviteLinks &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
contacts_manager_->delete_all_revoked_dialog_invite_links(DialogId(request.chat_id_),
UserId(request.creator_user_id_), std::move(promise));
}
void Td::on_request(uint64 id, td_api::checkChatInviteLink &request) {
@ -6592,6 +6632,33 @@ void Td::on_request(uint64 id, const td_api::deleteFile &request) {
"td_api::deleteFile");
}
void Td::on_request(uint64 id, td_api::getMessageFileType &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.message_file_head_);
CREATE_REQUEST_PROMISE();
messages_manager_->get_message_file_type(request.message_file_head_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getMessageImportConfirmationText &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<string> result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(make_tl_object<td_api::text>(result.move_as_ok()));
}
});
messages_manager_->get_message_import_confirmation_text(DialogId(request.chat_id_), std::move(query_promise));
}
void Td::on_request(uint64 id, const td_api::importMessages &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
messages_manager_->import_messages(DialogId(request.chat_id_), request.message_file_, request.attached_files_,
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::blockMessageSenderFromReplies &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
@ -6758,6 +6825,12 @@ void Td::on_request(uint64 id, const td_api::toggleSupergroupIsAllHistoryAvailab
request.is_all_history_available_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::toggleSupergroupIsBroadcastGroup &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
contacts_manager_->convert_channel_to_gigagroup(ChannelId(request.supergroup_id_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::reportSupergroupSpam &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
@ -6766,19 +6839,22 @@ void Td::on_request(uint64 id, const td_api::reportSupergroupSpam &request) {
}
void Td::on_request(uint64 id, td_api::getSupergroupMembers &request) {
CREATE_REQUEST(GetSupergroupMembersRequest, request.supergroup_id_, std::move(request.filter_), request.offset_,
request.limit_);
}
void Td::on_request(uint64 id, const td_api::deleteSupergroup &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
contacts_manager_->delete_channel(ChannelId(request.supergroup_id_), std::move(promise));
CREATE_REQUEST_PROMISE();
auto query_promise =
PromiseCreator::lambda([promise = std::move(promise), td = this](Result<DialogParticipants> result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(result.ok().get_chat_members_object(td));
}
});
contacts_manager_->get_channel_participants(ChannelId(request.supergroup_id_), std::move(request.filter_), string(),
request.offset_, request.limit_, -1, false, std::move(query_promise));
}
void Td::on_request(uint64 id, td_api::closeSecretChat &request) {
CREATE_OK_REQUEST_PROMISE();
send_closure(secret_chats_manager_, &SecretChatsManager::cancel_chat, SecretChatId(request.secret_chat_id_),
send_closure(secret_chats_manager_, &SecretChatsManager::cancel_chat, SecretChatId(request.secret_chat_id_), false,
std::move(promise));
}
@ -6987,15 +7063,30 @@ void Td::on_request(uint64 id, const td_api::removeChatActionBar &request) {
void Td::on_request(uint64 id, td_api::reportChat &request) {
CHECK_IS_USER();
auto r_report_reason = ReportReason::get_report_reason(std::move(request.reason_), std::move(request.text_));
if (r_report_reason.is_error()) {
return send_error_raw(id, r_report_reason.error().code(), r_report_reason.error().message());
}
CREATE_OK_REQUEST_PROMISE();
messages_manager_->report_dialog(DialogId(request.chat_id_), request.reason_,
MessagesManager::get_message_ids(request.message_ids_), std::move(promise));
messages_manager_->report_dialog(DialogId(request.chat_id_), MessagesManager::get_message_ids(request.message_ids_),
r_report_reason.move_as_ok(), std::move(promise));
}
void Td::on_request(uint64 id, td_api::reportChatPhoto &request) {
CHECK_IS_USER();
auto r_report_reason = ReportReason::get_report_reason(std::move(request.reason_), std::move(request.text_));
if (r_report_reason.is_error()) {
return send_error_raw(id, r_report_reason.error().code(), r_report_reason.error().message());
}
CREATE_OK_REQUEST_PROMISE();
messages_manager_->report_dialog_photo(DialogId(request.chat_id_), FileId(request.file_id_, 0),
r_report_reason.move_as_ok(), std::move(promise));
}
void Td::on_request(uint64 id, td_api::getChatStatisticsUrl &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
CLEAN_INPUT_STRING(request.parameters_);
CREATE_REQUEST_PROMISE();
messages_manager_->get_dialog_statistics_url(DialogId(request.chat_id_), request.parameters_, request.is_dark_,
std::move(promise));
}
@ -7015,8 +7106,8 @@ void Td::on_request(uint64 id, const td_api::getMessageStatistics &request) {
void Td::on_request(uint64 id, td_api::getStatisticalGraph &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
CLEAN_INPUT_STRING(request.token_);
CREATE_REQUEST_PROMISE();
contacts_manager_->load_statistics_graph(DialogId(request.chat_id_), request.token_, request.x_, std::move(promise));
}
@ -7584,8 +7675,7 @@ void Td::on_request(uint64 id, td_api::stopPoll &request) {
void Td::on_request(uint64 id, const td_api::hideSuggestedAction &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
send_closure_later(config_manager_, &ConfigManager::dismiss_suggested_action, get_suggested_action(request.action_),
std::move(promise));
contacts_manager_->dismiss_suggested_action(SuggestedAction(request.action_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getLoginUrlInfo &request) {
@ -7730,11 +7820,11 @@ void Td::on_request(uint64 id, td_api::getAllPassportElements &request) {
void Td::on_request(uint64 id, td_api::setPassportElement &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.password_);
CREATE_REQUEST_PROMISE();
auto r_secure_value = get_secure_value(file_manager_.get(), std::move(request.element_));
if (r_secure_value.is_error()) {
return promise.set_error(r_secure_value.move_as_error());
return send_error_raw(id, 400, r_secure_value.error().message());
}
CREATE_REQUEST_PROMISE();
send_closure(secure_manager_, &SecureManager::set_secure_value, std::move(request.password_),
r_secure_value.move_as_ok(), std::move(promise));
}
@ -8085,7 +8175,7 @@ void Td::on_request(uint64 id, const td_api::getProxyLink &request) {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(make_tl_object<td_api::text>(result.move_as_ok()));
promise.set_value(make_tl_object<td_api::httpUrl>(result.move_as_ok()));
}
});
send_closure(G()->connection_creator(), &ConnectionCreator::get_proxy_link, request.proxy_id_,

View File

@ -134,6 +134,8 @@ class Td final : public NetQueryCallback {
bool is_online() const;
void set_is_bot_online(bool is_bot_online);
template <class ActorT, class... ArgsT>
ActorId<ActorT> create_net_actor(ArgsT &&... args) {
auto slot_id = request_actors_.create(ActorOwn<>(), RequestActorIdType);
@ -247,7 +249,7 @@ class Td final : public NetQueryCallback {
static td_api::object_ptr<td_api::Object> static_request(td_api::object_ptr<td_api::Function> function);
private:
static constexpr const char *TDLIB_VERSION = "1.7.0";
static constexpr const char *TDLIB_VERSION = "1.7.2";
static constexpr int64 ONLINE_ALARM_ID = 0;
static constexpr int64 PING_SERVER_ALARM_ID = -1;
static constexpr int32 PING_SERVER_TIMEOUT = 300;
@ -299,6 +301,7 @@ class Td final : public NetQueryCallback {
Container<ActorOwn<Actor>> request_actors_;
bool is_online_ = false;
bool is_bot_online_ = false;
NetQueryRef update_status_query_;
int64 alarm_id_ = 1;
@ -590,10 +593,14 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::openMessageContent &request);
void on_request(uint64 id, td_api::getExternalLink &request);
void on_request(uint64 id, const td_api::getChatHistory &request);
void on_request(uint64 id, const td_api::deleteChatHistory &request);
void on_request(uint64 id, const td_api::deleteChat &request);
void on_request(uint64 id, const td_api::getMessageThreadHistory &request);
void on_request(uint64 id, td_api::searchChatMessages &request);
@ -604,6 +611,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, td_api::searchCallMessages &request);
void on_request(uint64 id, const td_api::deleteAllCallMessages &request);
void on_request(uint64 id, const td_api::searchChatRecentLocationMessages &request);
void on_request(uint64 id, const td_api::getActiveLiveLocationMessages &request);
@ -634,8 +643,6 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, td_api::sendInlineQueryResultMessage &request);
void on_request(uint64 id, const td_api::sendChatSetTtlMessage &request);
void on_request(uint64 id, td_api::addLocalMessage &request);
void on_request(uint64 id, td_api::editMessageText &request);
@ -722,6 +729,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::toggleGroupCallParticipantIsMuted &request);
void on_request(uint64 id, const td_api::setGroupCallParticipantVolumeLevel &request);
void on_request(uint64 id, const td_api::loadGroupCallParticipants &request);
void on_request(uint64 id, const td_api::leaveGroupCall &request);
@ -750,6 +759,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::setChatPhoto &request);
void on_request(uint64 id, const td_api::setChatMessageTtlSetting &request);
void on_request(uint64 id, const td_api::setChatPermissions &request);
void on_request(uint64 id, td_api::setChatDraftMessage &request);
@ -790,6 +801,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, td_api::setChatMemberStatus &request);
void on_request(uint64 id, const td_api::banChatMember &request);
void on_request(uint64 id, const td_api::canTransferOwnership &request);
void on_request(uint64 id, td_api::transferChatOwnership &request);
@ -800,7 +813,25 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, td_api::getChatAdministrators &request);
void on_request(uint64 id, const td_api::generateChatInviteLink &request);
void on_request(uint64 id, const td_api::replacePrimaryChatInviteLink &request);
void on_request(uint64 id, const td_api::createChatInviteLink &request);
void on_request(uint64 id, td_api::editChatInviteLink &request);
void on_request(uint64 id, td_api::getChatInviteLink &request);
void on_request(uint64 id, const td_api::getChatInviteLinkCounts &request);
void on_request(uint64 id, td_api::getChatInviteLinks &request);
void on_request(uint64 id, td_api::getChatInviteLinkMembers &request);
void on_request(uint64 id, td_api::revokeChatInviteLink &request);
void on_request(uint64 id, td_api::deleteRevokedChatInviteLink &request);
void on_request(uint64 id, const td_api::deleteAllRevokedChatInviteLinks &request);
void on_request(uint64 id, td_api::checkChatInviteLink &request);
@ -830,6 +861,12 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::deleteFile &request);
void on_request(uint64 id, td_api::getMessageFileType &request);
void on_request(uint64 id, const td_api::getMessageImportConfirmationText &request);
void on_request(uint64 id, const td_api::importMessages &request);
void on_request(uint64 id, const td_api::blockMessageSenderFromReplies &request);
void on_request(uint64 id, const td_api::getBlockedMessageSenders &request);
@ -878,12 +915,12 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::toggleSupergroupIsAllHistoryAvailable &request);
void on_request(uint64 id, const td_api::toggleSupergroupIsBroadcastGroup &request);
void on_request(uint64 id, const td_api::reportSupergroupSpam &request);
void on_request(uint64 id, td_api::getSupergroupMembers &request);
void on_request(uint64 id, const td_api::deleteSupergroup &request);
void on_request(uint64 id, td_api::closeSecretChat &request);
void on_request(uint64 id, td_api::getStickers &request);
@ -964,6 +1001,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, td_api::reportChat &request);
void on_request(uint64 id, td_api::reportChatPhoto &request);
void on_request(uint64 id, td_api::getChatStatisticsUrl &request);
void on_request(uint64 id, const td_api::getChatStatistics &request);

View File

@ -116,6 +116,7 @@ Status init_binlog(Binlog &binlog, string path, BinlogKeyValue<Binlog> &binlog_p
case LogEvent::HandlerType::ReadMessageThreadHistoryOnServer:
case LogEvent::HandlerType::BlockMessageSenderFromRepliesOnServer:
case LogEvent::HandlerType::UnpinAllDialogMessagesOnServer:
case LogEvent::HandlerType::DeleteAllCallMessagesFromServer:
events.to_messages_manager.push_back(event.clone());
break;
case LogEvent::HandlerType::AddMessagePushNotification:

View File

@ -20,6 +20,7 @@
#include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogAction.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/DialogInviteLink.h"
#include "td/telegram/FolderId.h"
#include "td/telegram/Global.h"
#include "td/telegram/GroupCallManager.h"
@ -28,6 +29,7 @@
#include "td/telegram/Location.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/MessageTtlSetting.h"
#include "td/telegram/net/DcOptions.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/NotificationManager.h"
@ -50,14 +52,15 @@
#include "td/utils/algorithm.h"
#include "td/utils/buffer.h"
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/Random.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/Time.h"
#include <iterator>
#include <limits>
namespace td {
@ -198,11 +201,22 @@ void UpdatesManager::fill_seq_gap(void *td) {
}
void UpdatesManager::fill_qts_gap(void *td) {
fill_gap(td, "qts");
CHECK(td != nullptr);
if (G()->close_flag()) {
return;
}
auto td_ptr = static_cast<Td *>(td);
auto qts = std::numeric_limits<int32>::max();
if (!td_ptr->updates_manager_->pending_qts_updates_.empty()) {
qts = td_ptr->updates_manager_->pending_qts_updates_.begin()->first;
}
string source = PSTRING() << "qts from " << td_ptr->updates_manager_->get_qts() << " to " << qts;
fill_gap(td, source.c_str());
}
void UpdatesManager::fill_get_difference_gap(void *td) {
fill_gap(td, "getDifference");
fill_gap(td, "rare getDifference calls");
}
void UpdatesManager::fill_gap(void *td, const char *source) {
@ -315,13 +329,13 @@ void UpdatesManager::on_qts_ack(PtsManager::PtsId ack_token) {
void UpdatesManager::save_pts(int32 pts) {
if (pts == std::numeric_limits<int32>::max()) {
G()->td_db()->get_binlog_pmc()->erase("updates.pts");
} else if (!G()->ignore_backgrond_updates()) {
} else if (!G()->ignore_background_updates()) {
G()->td_db()->get_binlog_pmc()->set("updates.pts", to_string(pts));
}
}
void UpdatesManager::save_qts(int32 qts) {
if (!G()->ignore_backgrond_updates()) {
if (!G()->ignore_background_updates()) {
G()->td_db()->get_binlog_pmc()->set("updates.qts", to_string(qts));
}
}
@ -343,7 +357,7 @@ Promise<> UpdatesManager::set_pts(int32 pts, const char *source) {
}
result = add_pts(pts);
if (last_get_difference_pts_ + FORCED_GET_DIFFERENCE_PTS_DIFF < get_pts()) {
if (last_get_difference_pts_ < get_pts() - FORCED_GET_DIFFERENCE_PTS_DIFF) {
last_get_difference_pts_ = get_pts();
schedule_get_difference("set_pts");
}
@ -375,7 +389,7 @@ void UpdatesManager::set_date(int32 date, bool from_update, string date_source)
date_ = date;
date_source_ = std::move(date_source);
if (!G()->ignore_backgrond_updates()) {
if (!G()->ignore_background_updates()) {
G()->td_db()->get_binlog_pmc()->set("updates.date", to_string(date));
}
} else if (date < date_) {
@ -607,6 +621,7 @@ bool UpdatesManager::is_acceptable_message(const telegram_api::Message *message_
case telegram_api::messageActionSecureValuesSentMe::ID:
case telegram_api::messageActionContactSignUp::ID:
case telegram_api::messageActionGroupCall::ID:
case telegram_api::messageActionSetMessagesTTL::ID:
break;
case telegram_api::messageActionChatCreate::ID: {
auto chat_create = static_cast<const telegram_api::messageActionChatCreate *>(action);
@ -788,7 +803,8 @@ void UpdatesManager::on_get_updates(tl_object_ptr<telegram_api::Updates> &&updat
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, update->id_,
make_tl_object<telegram_api::peerUser>(from_id), make_tl_object<telegram_api::peerUser>(update->user_id_),
std::move(update->fwd_from_), update->via_bot_id_, std::move(update->reply_to_), update->date_,
update->message_, nullptr, nullptr, std::move(update->entities_), 0, 0, nullptr, 0, string(), 0, Auto());
update->message_, nullptr, nullptr, std::move(update->entities_), 0, 0, nullptr, 0, string(), 0, Auto(),
update->ttl_period_);
on_pending_update(
make_tl_object<telegram_api::updateNewMessage>(std::move(message), update->pts_, update->pts_count_), 0,
std::move(promise), "telegram_api::updatesShortMessage");
@ -812,7 +828,7 @@ void UpdatesManager::on_get_updates(tl_object_ptr<telegram_api::Updates> &&updat
make_tl_object<telegram_api::peerUser>(update->from_id_),
make_tl_object<telegram_api::peerChat>(update->chat_id_), std::move(update->fwd_from_), update->via_bot_id_,
std::move(update->reply_to_), update->date_, update->message_, nullptr, nullptr, std::move(update->entities_),
0, 0, nullptr, 0, string(), 0, Auto());
0, 0, nullptr, 0, string(), 0, Auto(), update->ttl_period_);
on_pending_update(
make_tl_object<telegram_api::updateNewMessage>(std::move(message), update->pts_, update->pts_count_), 0,
std::move(promise), "telegram_api::updatesShortChatMessage");
@ -1110,7 +1126,7 @@ void UpdatesManager::init_state() {
}
auto pmc = G()->td_db()->get_binlog_pmc();
if (G()->ignore_backgrond_updates()) {
if (G()->ignore_background_updates()) {
// just in case
pmc->erase("updates.pts");
pmc->erase("updates.qts");
@ -1195,6 +1211,10 @@ void UpdatesManager::process_get_difference_updates(
CHECK(!running_get_difference_);
}
if (constructor_id == telegram_api::updateChat::ID) {
update = nullptr;
}
if (constructor_id == telegram_api::updateChannel::ID) {
update = nullptr;
}
@ -1310,9 +1330,9 @@ void UpdatesManager::on_get_difference(tl_object_ptr<telegram_api::updates_Diffe
auto state = std::move(difference->intermediate_state_);
if (get_pts() != std::numeric_limits<int32>::max() && state->date_ == get_date() &&
(state->pts_ == get_pts() ||
(min_postponed_update_pts_ != 0 && state->pts_ >= min_postponed_update_pts_ + 1000)) &&
(min_postponed_update_pts_ != 0 && state->pts_ - 1000 >= min_postponed_update_pts_)) &&
(state->qts_ == get_qts() ||
(min_postponed_update_qts_ != 0 && state->qts_ >= min_postponed_update_qts_ + 1000))) {
(min_postponed_update_qts_ != 0 && state->qts_ - 1000 >= min_postponed_update_qts_))) {
on_get_updates_state(std::move(state), "get difference final slice");
VLOG(get_difference) << "Trying to switch back from getDifference to update processing";
break;
@ -1639,7 +1659,7 @@ void UpdatesManager::add_pending_qts_update(tl_object_ptr<telegram_api::Update>
int32 old_qts = get_qts();
LOG(INFO) << "Process update with qts = " << qts << ", current qts = " << old_qts;
if (qts < old_qts - 1000001) {
if (qts < old_qts - 100001) {
LOG(WARNING) << "Restore qts after qts overflow from " << old_qts << " to " << qts << " by "
<< oneline(to_string(update));
add_qts(qts - 1).set_value(Unit());
@ -1656,7 +1676,7 @@ void UpdatesManager::add_pending_qts_update(tl_object_ptr<telegram_api::Update>
CHECK(!running_get_difference_);
if (qts > old_qts + 1) {
if (qts - 1 > old_qts && old_qts > 0) {
LOG(INFO) << "Postpone update with qts = " << qts;
if (pending_qts_updates_.empty()) {
set_qts_gap_timeout(MAX_UNFILLED_GAP_TIME);
@ -1842,7 +1862,7 @@ void UpdatesManager::add_pending_pts_update(tl_object_ptr<telegram_api::Update>
}
}
if (new_pts <= old_pts || (old_pts >= 1 && new_pts > old_pts + 500000000)) {
if (new_pts <= old_pts || (old_pts >= 1 && new_pts - 500000000 > old_pts)) {
td_->messages_manager_->skip_old_pending_pts_update(std::move(update), new_pts, old_pts, pts_count, source);
return promise.set_value(Unit());
}
@ -1856,7 +1876,7 @@ void UpdatesManager::add_pending_pts_update(tl_object_ptr<telegram_api::Update>
return;
}
if (old_pts + pts_count > new_pts) {
if (old_pts > new_pts - pts_count) {
LOG(WARNING) << "Have old_pts (= " << old_pts << ") + pts_count (= " << pts_count << ") > new_pts (= " << new_pts
<< "). Logged in " << G()->shared_config().get_option_integer("authorization_date") << ". Update from "
<< source << " = " << oneline(to_string(update));
@ -1870,7 +1890,7 @@ void UpdatesManager::add_pending_pts_update(tl_object_ptr<telegram_api::Update>
accumulated_pts_ = new_pts;
}
if (old_pts + accumulated_pts_count_ > accumulated_pts_) {
if (old_pts > accumulated_pts_ - accumulated_pts_count_) {
LOG(WARNING) << "Have old_pts (= " << old_pts << ") + accumulated_pts_count (= " << accumulated_pts_count_
<< ") > accumulated_pts (= " << accumulated_pts_ << "). new_pts = " << new_pts
<< ", pts_count = " << pts_count << ". Logged in "
@ -1883,7 +1903,7 @@ void UpdatesManager::add_pending_pts_update(tl_object_ptr<telegram_api::Update>
LOG_IF(INFO, pts_count == 0 && update->get_id() != dummyUpdate::ID) << "Skip useless update " << to_string(update);
if (pending_pts_updates_.empty() && old_pts + accumulated_pts_count_ == accumulated_pts_ &&
if (pending_pts_updates_.empty() && old_pts == accumulated_pts_ - accumulated_pts_count_ &&
!pts_gap_timeout_.has_timeout()) {
if (pts_count > 0) {
td_->messages_manager_->process_pts_update(std::move(update));
@ -1899,15 +1919,14 @@ void UpdatesManager::add_pending_pts_update(tl_object_ptr<telegram_api::Update>
pending_pts_updates_.emplace(new_pts, PendingPtsUpdate(std::move(update), new_pts, pts_count, std::move(promise)));
if (old_pts + accumulated_pts_count_ < accumulated_pts_) {
if (old_pts < accumulated_pts_ - accumulated_pts_count_) {
set_pts_gap_timeout(MAX_UNFILLED_GAP_TIME);
last_pts_gap_time_ = Time::now();
return;
}
CHECK(old_pts + accumulated_pts_count_ == accumulated_pts_);
if (!pending_pts_updates_.empty()) {
process_pending_pts_updates();
}
CHECK(old_pts == accumulated_pts_ - accumulated_pts_count_);
process_pending_pts_updates();
}
void UpdatesManager::postpone_pts_update(tl_object_ptr<telegram_api::Update> &&update, int32 pts, int32 pts_count,
@ -1937,9 +1956,11 @@ void UpdatesManager::process_seq_updates(int32 seq_end, int32 date,
void UpdatesManager::process_qts_update(tl_object_ptr<telegram_api::Update> &&update_ptr, int32 qts,
Promise<Unit> &&promise) {
LOG(DEBUG) << "Process " << to_string(update_ptr);
if (last_get_difference_qts_ + FORCED_GET_DIFFERENCE_PTS_DIFF < qts) {
if (last_get_difference_qts_ < qts - FORCED_GET_DIFFERENCE_PTS_DIFF) {
if (last_get_difference_qts_ != 0) {
schedule_get_difference("process_qts_update");
}
last_get_difference_qts_ = qts;
schedule_get_difference("process_qts_update");
}
switch (update_ptr->get_id()) {
case telegram_api::updateNewEncryptedMessage::ID: {
@ -1948,11 +1969,29 @@ void UpdatesManager::process_qts_update(tl_object_ptr<telegram_api::Update> &&up
add_qts(qts));
break;
}
case telegram_api::updateBotStopped::ID: {
auto update = move_tl_object_as<telegram_api::updateBotStopped>(update_ptr);
td_->contacts_manager_->on_update_bot_stopped(UserId(update->user_id_), update->date_,
std::move(update->stopped_));
add_qts(qts).set_value(Unit());
break;
}
case telegram_api::updateChatParticipant::ID: {
auto update = move_tl_object_as<telegram_api::updateChatParticipant>(update_ptr);
td_->contacts_manager_->on_update_chat_participant(ChatId(update->chat_id_), UserId(update->actor_id_),
update->date_, DialogInviteLink(std::move(update->invite_)),
std::move(update->prev_participant_),
std::move(update->new_participant_));
add_qts(qts).set_value(Unit());
break;
}
case telegram_api::updateChannelParticipant::ID: {
auto update = move_tl_object_as<telegram_api::updateChannelParticipant>(update_ptr);
td_->contacts_manager_->on_update_channel_participant(ChannelId(update->channel_id_), UserId(update->user_id_),
update->date_, std::move(update->prev_participant_),
td_->contacts_manager_->on_update_channel_participant(ChannelId(update->channel_id_), UserId(update->actor_id_),
update->date_, DialogInviteLink(std::move(update->invite_)),
std::move(update->prev_participant_),
std::move(update->new_participant_));
add_qts(qts).set_value(Unit());
break;
}
default:
@ -1968,8 +2007,17 @@ void UpdatesManager::process_pending_pts_updates() {
update.second.promise.set_value(Unit());
}
set_pts(accumulated_pts_, "process pending updates")
.set_value(Unit()); // TODO can't set until get messages really stored on persistent storage
if (last_pts_gap_time_ != 0) {
auto diff = Time::now() - last_pts_gap_time_;
last_pts_gap_time_ = 0;
if (diff > 0.1) {
VLOG(get_difference) << "Gap in pts from " << accumulated_pts_ - accumulated_pts_count_ << " to "
<< accumulated_pts_ << " has been filled in " << diff << " seconds";
}
}
set_pts(accumulated_pts_, "postpone_pending_pts_update")
.set_value(Unit()); // TODO can't set until updates are stored on persistent storage
drop_pending_pts_updates();
}
@ -2284,6 +2332,15 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updatePeerSettings> u
promise.set_value(Unit());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updatePeerHistoryTTL> update, Promise<Unit> &&promise) {
MessageTtlSetting message_ttl_setting;
if ((update->flags_ & telegram_api::updatePeerHistoryTTL::TTL_PERIOD_MASK) != 0) {
message_ttl_setting = MessageTtlSetting(update->ttl_period_);
}
td_->messages_manager_->on_update_dialog_message_ttl_setting(DialogId(update->peer_), message_ttl_setting);
promise.set_value(Unit());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updatePeerLocated> update, Promise<Unit> &&promise) {
td_->contacts_manager_->on_update_peer_located(std::move(update->peers_), true);
promise.set_value(Unit());
@ -2429,6 +2486,8 @@ int32 UpdatesManager::get_update_pts(const telegram_api::Update *update) {
bool UpdatesManager::is_qts_update(const telegram_api::Update *update) {
switch (update->get_id()) {
case telegram_api::updateNewEncryptedMessage::ID:
case telegram_api::updateBotStopped::ID:
case telegram_api::updateChatParticipant::ID:
case telegram_api::updateChannelParticipant::ID:
return true;
default:
@ -2440,6 +2499,10 @@ int32 UpdatesManager::get_update_qts(const telegram_api::Update *update) {
switch (update->get_id()) {
case telegram_api::updateNewEncryptedMessage::ID:
return static_cast<const telegram_api::updateNewEncryptedMessage *>(update)->qts_;
case telegram_api::updateBotStopped::ID:
return static_cast<const telegram_api::updateBotStopped *>(update)->qts_;
case telegram_api::updateChatParticipant::ID:
return static_cast<const telegram_api::updateChatParticipant *>(update)->qts_;
case telegram_api::updateChannelParticipant::ID:
return static_cast<const telegram_api::updateChannelParticipant *>(update)->qts_;
default:
@ -2826,6 +2889,16 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateLoginToken> upd
promise.set_value(Unit());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateBotStopped> update, Promise<Unit> &&promise) {
auto qts = update->qts_;
add_pending_qts_update(std::move(update), qts, std::move(promise));
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChatParticipant> update, Promise<Unit> &&promise) {
auto qts = update->qts_;
add_pending_qts_update(std::move(update), qts, std::move(promise));
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelParticipant> update, Promise<Unit> &&promise) {
auto qts = update->qts_;
add_pending_qts_update(std::move(update), qts, std::move(promise));

View File

@ -21,6 +21,7 @@
#include "td/utils/common.h"
#include "td/utils/logging.h"
#include "td/utils/Status.h"
#include "td/utils/tl_storers.h"
#include <map>
@ -58,9 +59,10 @@ class updateSentMessage : public telegram_api::Update {
int64 random_id_;
MessageId message_id_;
int32 date_;
int32 ttl_period_;
updateSentMessage(int64 random_id, MessageId message_id, int32 date)
: random_id_(random_id), message_id_(message_id), date_(date) {
updateSentMessage(int64 random_id, MessageId message_id, int32 date, int32 ttl_period)
: random_id_(random_id), message_id_(message_id), date_(date), ttl_period_(ttl_period) {
}
static constexpr int32 ID = 1234567890;
@ -81,6 +83,7 @@ class updateSentMessage : public telegram_api::Update {
s.store_field("random_id", random_id_);
s.store_field("message_id", message_id_.get());
s.store_field("date", date_);
s.store_field("ttl_period", ttl_period_);
s.store_class_end();
}
};
@ -170,6 +173,7 @@ class UpdatesManager : public Actor {
int32 accumulated_pts_count_ = 0;
int32 accumulated_pts_ = -1;
double last_pts_jump_warning_time_ = 0;
double last_pts_gap_time_ = 0;
std::multimap<int32, PendingPtsUpdate> pending_pts_updates_;
std::multimap<int32, PendingPtsUpdate> postponed_pts_updates_;
@ -333,6 +337,8 @@ class UpdatesManager : public Actor {
void on_update(tl_object_ptr<telegram_api::updateReadHistoryOutbox> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateNotifySettings> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updatePeerSettings> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updatePeerHistoryTTL> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updatePeerLocated> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateWebPage> update, Promise<Unit> &&promise);
@ -446,6 +452,8 @@ class UpdatesManager : public Actor {
void on_update(tl_object_ptr<telegram_api::updateLoginToken> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateBotStopped> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateChatParticipant> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateChannelParticipant> update, Promise<Unit> &&promise);
// unsupported updates

View File

@ -8,7 +8,7 @@
namespace td {
constexpr int32 MTPROTO_LAYER = 122;
constexpr int32 MTPROTO_LAYER = 124;
enum class Version : int32 {
Initial, // 0

View File

@ -1851,7 +1851,7 @@ RichText get_rich_text(tl_object_ptr<telegram_api::RichText> &&rich_text_ptr,
if (it != documents.end()) {
result.type = RichText::Type::Icon;
result.document_file_id = it->second;
Dimensions dimensions = get_dimensions(rich_text->w_, rich_text->h_);
Dimensions dimensions = get_dimensions(rich_text->w_, rich_text->h_, "textImage");
result.content = PSTRING() << (dimensions.width * static_cast<uint32>(65536) + dimensions.height);
} else {
LOG(ERROR) << "Can't find document " << rich_text->document_id_;
@ -2070,7 +2070,7 @@ unique_ptr<WebPageBlock> get_web_page_block(Td *td, tl_object_ptr<telegram_api::
}
Dimensions dimensions;
if (has_dimensions) {
dimensions = get_dimensions(page_block->w_, page_block->h_);
dimensions = get_dimensions(page_block->w_, page_block->h_, "pageBlockEmbed");
}
return td::make_unique<WebPageBlockEmbedded>(
std::move(page_block->url_), std::move(page_block->html_), std::move(poster_photo), dimensions,
@ -2221,7 +2221,7 @@ unique_ptr<WebPageBlock> get_web_page_block(Td *td, tl_object_ptr<telegram_api::
auto page_block = move_tl_object_as<telegram_api::pageBlockMap>(page_block_ptr);
Location location(std::move(page_block->geo_));
auto zoom = page_block->zoom_;
Dimensions dimensions = get_dimensions(page_block->w_, page_block->h_);
Dimensions dimensions = get_dimensions(page_block->w_, page_block->h_, "pageBlockMap");
if (location.empty()) {
LOG(ERROR) << "Receive invalid map location";
break;

View File

@ -489,7 +489,7 @@ WebPageId WebPagesManager::on_get_web_page(tl_object_ptr<telegram_api::WebPage>
page->embed_type = std::move(web_page->embed_type_);
}
if (web_page->flags_ & WEBPAGE_FLAG_HAS_EMBEDDED_PREVIEW_SIZE) {
page->embed_dimensions = get_dimensions(web_page->embed_width_, web_page->embed_height_);
page->embed_dimensions = get_dimensions(web_page->embed_width_, web_page->embed_height_, "webPage");
}
if (web_page->flags_ & WEBPAGE_FLAG_HAS_DURATION) {
page->duration = web_page->duration_;

View File

@ -24,6 +24,7 @@
#include "td/utils/crypto.h"
#include "td/utils/ExitGuard.h"
#include "td/utils/FileLog.h"
#include "td/utils/filesystem.h"
#include "td/utils/format.h"
#include "td/utils/JsonBuilder.h"
#include "td/utils/logging.h"
@ -41,6 +42,7 @@
#include "td/utils/Status.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/Time.h"
#include "td/utils/utf8.h"
#ifndef USE_READLINE
#include "td/utils/find_boundary.h"
@ -453,12 +455,18 @@ class CliClient final : public Actor {
int64 as_chat_id(Slice str) const {
str = trim(str);
if (str == "me") {
return my_id_;
}
if (str[0] == '@') {
auto it = username_to_user_id_.find(to_lower(str.substr(1)));
str.remove_prefix(1);
}
if (is_alpha(str[0])) {
auto it = username_to_user_id_.find(to_lower(str));
if (it != username_to_user_id_.end()) {
return it->second;
}
auto it2 = username_to_supergroup_id_.find(to_lower(str.substr(1)));
auto it2 = username_to_supergroup_id_.find(to_lower(str));
if (it2 != username_to_supergroup_id_.end()) {
auto supergroup_id = it2->second;
return static_cast<int64>(-1000'000'000'000ll) - supergroup_id;
@ -466,9 +474,6 @@ class CliClient final : public Actor {
LOG(ERROR) << "Can't resolve " << str;
return 0;
}
if (str == "me") {
return my_id_;
}
return to_integer<int64>(str);
}
@ -534,17 +539,20 @@ class CliClient final : public Actor {
int32 as_user_id(Slice str) const {
str = trim(str);
if (str == "me") {
return my_id_;
}
if (str[0] == '@') {
auto it = username_to_user_id_.find(to_lower(str.substr(1)));
str.remove_prefix(1);
}
if (is_alpha(str[0])) {
auto it = username_to_user_id_.find(to_lower(str));
if (it != username_to_user_id_.end()) {
return it->second;
}
LOG(ERROR) << "Can't find user " << str;
return 0;
}
if (str == "me") {
return my_id_;
}
return to_integer<int32>(str);
}
@ -561,10 +569,17 @@ class CliClient final : public Actor {
return result;
}
int32 as_supergroup_id(Slice str) {
int32 as_supergroup_id(Slice str) const {
str = trim(str);
if (str[0] == '@') {
return username_to_supergroup_id_[to_lower(str.substr(1))];
str.remove_prefix(1);
}
if (is_alpha(str[0])) {
auto it = username_to_supergroup_id_.find(to_lower(str));
if (it == username_to_supergroup_id_.end()) {
return 0;
}
return it->second;
}
auto result = to_integer<int64>(str);
int64 shift = static_cast<int64>(-1000000000000ll);
@ -820,6 +835,17 @@ class CliClient final : public Actor {
}
break;
}
case td_api::updateNewMessage::ID: {
auto message = static_cast<const td_api::updateNewMessage *>(result.get())->message_.get();
if (message != nullptr && message->content_->get_id() == td_api::messageText::ID) {
auto chat_id = message->chat_id_;
auto text = static_cast<const td_api::messageText *>(message->content_.get())->text_->text_;
if (text == "/start" && use_test_dc_) {
on_cmd(PSTRING() << "sm " << chat_id << " Hi!");
}
}
break;
}
case td_api::file::ID:
on_get_file(*static_cast<const td_api::file *>(result.get()));
break;
@ -1316,6 +1342,9 @@ class CliClient final : public Actor {
static td_api::object_ptr<td_api::ChatReportReason> get_chat_report_reason(MutableSlice reason) {
reason = trim(reason);
if (reason == "null") {
return nullptr;
}
if (reason == "spam") {
return td_api::make_object<td_api::chatReportReasonSpam>();
}
@ -1334,7 +1363,10 @@ class CliClient final : public Actor {
if (reason == "geo" || reason == "location") {
return td_api::make_object<td_api::chatReportReasonUnrelatedLocation>();
}
return td_api::make_object<td_api::chatReportReasonCustom>(reason.str());
if (reason == "fake") {
return td_api::make_object<td_api::chatReportReasonFake>();
}
return td_api::make_object<td_api::chatReportReasonCustom>();
}
static td_api::object_ptr<td_api::NetworkType> get_network_type(MutableSlice type) {
@ -1358,13 +1390,19 @@ class CliClient final : public Actor {
return nullptr;
}
static td_api::object_ptr<td_api::SuggestedAction> as_suggested_action(Slice action) {
td_api::object_ptr<td_api::SuggestedAction> as_suggested_action(Slice action) const {
if (action == "unarchive") {
return td_api::make_object<td_api::suggestedActionEnableArchiveAndMuteNewChats>();
}
if (action == "number") {
return td_api::make_object<td_api::suggestedActionCheckPhoneNumber>();
}
if (action == "ticks") {
return td_api::make_object<td_api::suggestedActionSeeTicksHint>();
}
if (begins_with(action, "giga")) {
return td_api::make_object<td_api::suggestedActionConvertToBroadcastGroup>(as_supergroup_id(action.substr(4)));
}
return nullptr;
}
@ -2011,6 +2049,9 @@ class CliClient final : public Actor {
get_args(args, limit, offset_message_id, only_missed);
send_request(td_api::make_object<td_api::searchCallMessages>(as_message_id(offset_message_id), as_limit(limit),
only_missed));
} else if (op == "DeleteAllCallMessages") {
bool revoke = as_bool(args);
send_request(td_api::make_object<td_api::deleteAllCallMessages>(revoke));
} else if (op == "SCRLM") {
string chat_id;
string limit;
@ -2257,7 +2298,7 @@ class CliClient final : public Actor {
} else if (op == "gatss") {
send_request(td_api::make_object<td_api::getAttachedStickerSets>(as_file_id(args)));
} else if (op == "storage") {
send_request(td_api::make_object<td_api::getStorageStatistics>(as_limit(args)));
send_request(td_api::make_object<td_api::getStorageStatistics>(to_integer<int32>(args)));
} else if (op == "storage_fast") {
send_request(td_api::make_object<td_api::getStorageStatisticsFast>());
} else if (op == "database") {
@ -2536,7 +2577,8 @@ class CliClient final : public Actor {
int32 max_file_id = as_file_id(file_id);
int32 min_file_id = (op == "dff" ? 1 : max_file_id);
for (int32 i = min_file_id; i <= max_file_id; i++) {
send_request(td_api::make_object<td_api::downloadFile>(i, priority, offset, as_limit(limit), op == "dfs"));
send_request(
td_api::make_object<td_api::downloadFile>(i, priority, offset, to_integer<int32>(limit), op == "dfs"));
}
} else if (op == "cdf") {
send_request(td_api::make_object<td_api::cancelDownloadFile>(as_file_id(args), false));
@ -2592,11 +2634,6 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::createNewSecretChat>(as_user_id(args)));
} else if (op == "scstn") {
send_request(td_api::make_object<td_api::sendChatScreenshotTakenNotification>(as_chat_id(args)));
} else if (op == "sscttl" || op == "setSecretChatTtl") {
string chat_id;
int32 ttl;
get_args(args, chat_id, ttl);
send_request(td_api::make_object<td_api::sendChatSetTtlMessage>(as_chat_id(chat_id), ttl));
} else if (op == "closeSC" || op == "cancelSC") {
send_request(td_api::make_object<td_api::closeSecretChat>(as_secret_chat_id(args)));
} else if (op == "cc" || op == "CreateCall") {
@ -2668,6 +2705,13 @@ class CliClient final : public Actor {
get_args(args, group_call_id, user_id, is_muted);
send_request(td_api::make_object<td_api::toggleGroupCallParticipantIsMuted>(as_group_call_id(group_call_id),
as_user_id(user_id), is_muted));
} else if (op == "sgcpvl") {
string group_call_id;
string user_id;
int32 volume_level;
get_args(args, group_call_id, user_id, volume_level);
send_request(td_api::make_object<td_api::setGroupCallParticipantVolumeLevel>(as_group_call_id(group_call_id),
as_user_id(user_id), volume_level));
} else if (op == "lgcp") {
string group_call_id;
string limit;
@ -2678,8 +2722,67 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::leaveGroupCall>(as_group_call_id(args)));
} else if (op == "dgc") {
send_request(td_api::make_object<td_api::discardGroupCall>(as_group_call_id(args)));
} else if (op == "rpcil") {
string chat_id = args;
send_request(td_api::make_object<td_api::replacePrimaryChatInviteLink>(as_chat_id(chat_id)));
} else if (op == "ccilt") {
string chat_id;
int32 expire_date;
int32 member_limit;
get_args(args, chat_id, expire_date, member_limit);
send_request(td_api::make_object<td_api::createChatInviteLink>(as_chat_id(chat_id), expire_date, member_limit));
} else if (op == "ecil") {
string chat_id;
string invite_link;
int32 expire_date;
int32 member_limit;
get_args(args, chat_id, invite_link, expire_date, member_limit);
send_request(
td_api::make_object<td_api::editChatInviteLink>(as_chat_id(chat_id), invite_link, expire_date, member_limit));
} else if (op == "rcil") {
string chat_id;
string invite_link;
get_args(args, chat_id, invite_link);
send_request(td_api::make_object<td_api::revokeChatInviteLink>(as_chat_id(chat_id), invite_link));
} else if (op == "gcilc") {
string chat_id = args;
send_request(td_api::make_object<td_api::getChatInviteLinkCounts>(as_chat_id(chat_id)));
} else if (op == "gcil") {
send_request(td_api::make_object<td_api::generateChatInviteLink>(as_chat_id(args)));
string chat_id;
string invite_link;
get_args(args, chat_id, invite_link);
send_request(td_api::make_object<td_api::getChatInviteLink>(as_chat_id(chat_id), invite_link));
} else if (op == "gcils" || op == "gcilr") {
string chat_id;
string creator_user_id;
int32 offset_date;
string offset_invite_link;
string limit;
get_args(args, chat_id, creator_user_id, offset_date, offset_invite_link, limit);
send_request(td_api::make_object<td_api::getChatInviteLinks>(as_chat_id(chat_id), as_user_id(creator_user_id),
op == "gcilr", offset_date, offset_invite_link,
as_limit(limit)));
} else if (op == "gcilm") {
string chat_id;
string invite_link;
string offset_user_id;
int32 offset_date;
string limit;
get_args(args, chat_id, invite_link, offset_user_id, offset_date, limit);
send_request(td_api::make_object<td_api::getChatInviteLinkMembers>(
as_chat_id(chat_id), invite_link,
td_api::make_object<td_api::chatInviteLinkMember>(as_user_id(offset_user_id), offset_date), as_limit(limit)));
} else if (op == "drcil") {
string chat_id;
string invite_link;
get_args(args, chat_id, invite_link);
send_request(td_api::make_object<td_api::deleteRevokedChatInviteLink>(as_chat_id(chat_id), invite_link));
} else if (op == "darcil") {
string chat_id;
string creator_user_id;
get_args(args, chat_id, creator_user_id);
send_request(td_api::make_object<td_api::deleteAllRevokedChatInviteLinks>(as_chat_id(chat_id),
as_user_id(creator_user_id)));
} else if (op == "ccil") {
send_request(td_api::make_object<td_api::checkChatInviteLink>(args));
} else if (op == "jcbil") {
@ -2796,10 +2899,10 @@ class CliClient final : public Actor {
get_args(args, chat_id, is_marked_as_read);
send_request(td_api::make_object<td_api::toggleChatIsMarkedAsUnread>(as_chat_id(chat_id), is_marked_as_read));
} else if (op == "tmsib") {
string chat_id;
string sender_id;
bool is_blocked;
get_args(args, chat_id, is_blocked);
send_request(td_api::make_object<td_api::toggleMessageSenderIsBlocked>(as_message_sender(chat_id), is_blocked));
get_args(args, sender_id, is_blocked);
send_request(td_api::make_object<td_api::toggleMessageSenderIsBlocked>(as_message_sender(sender_id), is_blocked));
} else if (op == "bmsfr") {
string message_id;
bool delete_message;
@ -2907,6 +3010,30 @@ class CliClient final : public Actor {
as_input_file(document), nullptr, true, as_caption(""));
return content;
})));
} else if (op == "gmft") {
auto r_message_file_head = read_file_str(args, 2 << 10);
if (r_message_file_head.is_error()) {
LOG(ERROR) << r_message_file_head.error();
} else {
auto message_file_head = r_message_file_head.move_as_ok();
while (!check_utf8(message_file_head)) {
message_file_head.pop_back();
}
send_request(td_api::make_object<td_api::getMessageFileType>(message_file_head));
}
} else if (op == "gmict") {
string chat_id;
get_args(args, chat_id);
send_request(td_api::make_object<td_api::getMessageImportConfirmationText>(as_chat_id(chat_id)));
} else if (op == "im") {
string chat_id;
string message_file;
vector<string> attached_files;
get_args(args, chat_id, message_file, args);
attached_files = full_split(args);
send_request(td_api::make_object<td_api::importMessages>(
as_chat_id(chat_id), as_input_file(message_file),
transform(attached_files, [](const string &attached_file) { return as_input_file(attached_file); })));
} else if (op == "em") {
string chat_id;
string message_id;
@ -3351,18 +3478,20 @@ class CliClient final : public Actor {
string title;
get_args(args, user_ids_string, title);
send_request(td_api::make_object<td_api::createNewBasicGroupChat>(as_user_ids(user_ids_string), title));
} else if (op == "cnch") {
send_request(td_api::make_object<td_api::createNewSupergroupChat>(args, true, "Description", nullptr));
} else if (op == "cnsg") {
send_request(td_api::make_object<td_api::createNewSupergroupChat>(args, false, "Description", nullptr));
} else if (op == "cngc") {
} else if (op == "cnchc") {
send_request(td_api::make_object<td_api::createNewSupergroupChat>(args, true, "Description", nullptr, false));
} else if (op == "cnsgc") {
send_request(td_api::make_object<td_api::createNewSupergroupChat>(args, false, "Description", nullptr, false));
} else if (op == "cnsgcloc") {
send_request(td_api::make_object<td_api::createNewSupergroupChat>(
args, false, "Description",
td_api::make_object<td_api::chatLocation>(as_location("40.0", "60.0"), "address")));
args, false, "Description", td_api::make_object<td_api::chatLocation>(as_location("40.0", "60.0"), "address"),
false));
} else if (op == "cnsgcimport") {
send_request(td_api::make_object<td_api::createNewSupergroupChat>(args, false, "Description", nullptr, true));
} else if (op == "UpgradeBasicGroupChatToSupergroupChat") {
send_request(td_api::make_object<td_api::upgradeBasicGroupChatToSupergroupChat>(as_chat_id(args)));
} else if (op == "DeleteSupergroup") {
send_request(td_api::make_object<td_api::deleteSupergroup>(as_supergroup_id(args)));
} else if (op == "DeleteChat") {
send_request(td_api::make_object<td_api::deleteChat>(as_chat_id(args)));
} else if (op == "gcpc") {
send_request(td_api::make_object<td_api::getCreatedPublicChats>());
} else if (op == "gcpcl") {
@ -3449,6 +3578,11 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::setChatPhoto>(
as_chat_id(chat_id), td_api::make_object<td_api::inputChatPhotoAnimation>(as_input_file(animation),
to_double(main_frame_timestamp))));
} else if (op == "scmts") {
string chat_id;
int32 ttl;
get_args(args, chat_id, ttl);
send_request(td_api::make_object<td_api::setChatMessageTtlSetting>(as_chat_id(chat_id), ttl));
} else if (op == "scperm") {
string chat_id;
string permissions;
@ -3478,6 +3612,14 @@ class CliClient final : public Actor {
string user_ids;
get_args(args, chat_id, user_ids);
send_request(td_api::make_object<td_api::addChatMembers>(as_chat_id(chat_id), as_user_ids(user_ids)));
} else if (op == "bcm") {
string chat_id;
string user_id;
int32 banned_until_date;
bool revoke_messages;
get_args(args, chat_id, user_id, banned_until_date, revoke_messages);
send_request(td_api::make_object<td_api::banChatMember>(as_chat_id(chat_id), as_user_id(user_id),
banned_until_date, revoke_messages));
} else if (op == "spolla") {
string chat_id;
string message_id;
@ -3523,30 +3665,30 @@ class CliClient final : public Actor {
status = td_api::make_object<td_api::chatMemberStatusCreator>("", true, true);
} else if (status_str == "uncreator") {
status = td_api::make_object<td_api::chatMemberStatusCreator>("", false, false);
} else if (status_str == "anon") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("anon", true, true, true, true, true, true,
true, true, true, false, true);
} else if (status_str == "anonadmin") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("anon", false, false, false, false, false,
false, false, false, false, false, true);
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("anon", true, true, true, true, true, true,
true, true, true, true, true, true);
} else if (status_str == "anon") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>(
"anon", false, false, false, false, false, false, false, false, false, false, false, true);
} else if (status_str == "addadmin") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("anon", false, false, false, false, false,
false, false, false, true, false, false);
status = td_api::make_object<td_api::chatMemberStatusAdministrator>(
"anon", false, false, false, false, false, false, false, false, false, true, false, false);
} else if (status_str == "calladmin") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("anon", false, false, false, false, false,
false, false, false, false, true, false);
status = td_api::make_object<td_api::chatMemberStatusAdministrator>(
"anon", false, false, false, false, false, false, false, false, false, false, true, false);
} else if (status_str == "admin") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("", true, true, true, true, true, true,
true, true, true, false, false);
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("", true, false, true, true, true, true,
true, true, true, true, true, false);
} else if (status_str == "adminq") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("title", true, true, true, true, true, true,
true, true, true, false, false);
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("title", true, false, true, true, true,
true, true, true, true, true, true, false);
} else if (status_str == "minadmin") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("", true, true, false, false, false, false,
false, false, false, false, false);
false, false, false, false, false, false);
} else if (status_str == "unadmin") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("", true, false, false, false, false, false,
false, false, false, false, false);
false, false, false, false, false, false);
} else if (status_str == "rest") {
status = td_api::make_object<td_api::chatMemberStatusRestricted>(
true, static_cast<int32>(120 + std::time(nullptr)),
@ -3629,6 +3771,10 @@ class CliClient final : public Actor {
get_args(args, supergroup_id, is_all_history_available);
send_request(td_api::make_object<td_api::toggleSupergroupIsAllHistoryAvailable>(as_supergroup_id(supergroup_id),
is_all_history_available));
} else if (op == "ToggleSupergroupIsBroadcastGroup") {
string supergroup_id;
get_args(args, supergroup_id);
send_request(td_api::make_object<td_api::toggleSupergroupIsBroadcastGroup>(as_supergroup_id(supergroup_id)));
} else if (op == "tsgsm") {
string supergroup_id;
bool sign_messages;
@ -3673,7 +3819,7 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::unpinAllChatMessages>(as_chat_id(chat_id)));
} else if (op == "grib") {
send_request(td_api::make_object<td_api::getRecentInlineBots>());
} else if (op == "spc" || op == "su" || op == "sch") {
} else if (op == "spc" || op == "su") {
send_request(td_api::make_object<td_api::searchPublicChat>(args));
} else if (op == "spcs") {
send_request(td_api::make_object<td_api::searchPublicChats>(args));
@ -3745,6 +3891,9 @@ class CliClient final : public Actor {
string message_id;
get_args(args, chat_id, message_id);
send_request(td_api::make_object<td_api::openMessageContent>(as_chat_id(chat_id), as_message_id(message_id)));
} else if (op == "gel") {
string link = args;
send_request(td_api::make_object<td_api::getExternalLink>(link));
} else if (op == "racm") {
string chat_id = args;
send_request(td_api::make_object<td_api::readAllChatMentions>(as_chat_id(chat_id)));
@ -3801,11 +3950,20 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::removeChatActionBar>(as_chat_id(chat_id)));
} else if (op == "rc") {
string chat_id;
string reason;
string message_ids;
get_args(args, chat_id, reason, message_ids);
send_request(td_api::make_object<td_api::reportChat>(as_chat_id(chat_id), get_chat_report_reason(reason),
as_message_ids(message_ids)));
string reason;
string text;
get_args(args, chat_id, message_ids, reason, text);
send_request(td_api::make_object<td_api::reportChat>(as_chat_id(chat_id), as_message_ids(message_ids),
get_chat_report_reason(reason), text));
} else if (op == "rcp") {
string chat_id;
string file_id;
string reason;
string text;
get_args(args, chat_id, file_id, reason, text);
send_request(td_api::make_object<td_api::reportChatPhoto>(as_chat_id(chat_id), as_file_id(file_id),
get_chat_report_reason(reason), text));
} else if (op == "gcsu") {
string chat_id;
string parameters;
@ -3846,7 +4004,7 @@ class CliClient final : public Actor {
int64 x;
get_args(args, chat_id, token, x);
send_request(td_api::make_object<td_api::getStatisticalGraph>(as_chat_id(chat_id), token, x));
} else if (op == "hsa" || op == "glu" || op == "glua") {
} else if (op == "hsa") {
send_request(td_api::make_object<td_api::hideSuggestedAction>(as_suggested_action(args)));
} else if (op == "glui" || op == "glu" || op == "glua") {
string chat_id;

View File

@ -367,7 +367,7 @@ Result<size_t> FileDownloader::process_part(Part part, NetQueryPtr net_query) {
bytes.as_slice());
}
auto slice = bytes.as_slice().truncate(part.size);
auto slice = bytes.as_slice().substr(0, part.size);
TRY_STATUS(acquire_fd());
LOG(INFO) << "Got " << slice.size() << " bytes at offset " << part.offset << " for \"" << path_ << '"';
TRY_RESULT(written, fd_.pwrite(slice, part.offset));

View File

@ -466,7 +466,7 @@ void FileNode::on_info_flushed() {
info_changed_flag_ = false;
}
string FileNode::suggested_name() const {
string FileNode::suggested_path() const {
if (!remote_name_.empty()) {
return remote_name_;
}
@ -685,8 +685,8 @@ const string &FileView::remote_name() const {
return node_->remote_name_;
}
string FileView::suggested_name() const {
return node_->suggested_name();
string FileView::suggested_path() const {
return node_->suggested_path();
}
DialogId FileView::owner_dialog_id() const {
@ -862,7 +862,7 @@ string FileManager::get_file_name(FileType file_type, Slice path) {
break;
case FileType::VoiceNote:
if (extension != "ogg" && extension != "oga" && extension != "mp3" && extension != "mpeg3" &&
extension != "m4a") {
extension != "m4a" && extension != "opus") {
return fix_file_extension(file_name, "voice", "oga");
}
break;
@ -1613,6 +1613,7 @@ Result<FileId> FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sy
}
node->need_load_from_pmc_ |= other_node->need_load_from_pmc_;
node->can_search_locally_ &= other_node->can_search_locally_;
node->upload_prefer_small_ |= other_node->upload_prefer_small_;
if (drop_last_successful_force_reupload_time) {
node->last_successful_force_reupload_time_ = -1e10;
@ -2000,7 +2001,7 @@ bool FileManager::set_content(FileId file_id, BufferSlice bytes) {
node->download_id_ = id;
node->is_download_started_ = true;
send_closure(file_load_manager_, &FileLoadManager::from_bytes, id, node->remote_.full.value().file_type_,
std::move(bytes), node->suggested_name());
std::move(bytes), node->suggested_path());
return true;
}
@ -2317,7 +2318,7 @@ void FileManager::run_download(FileNodePtr node, bool force_update_priority) {
node->download_id_ = id;
node->is_download_started_ = false;
LOG(INFO) << "Run download of file " << file_id << " of size " << node->size_ << " from "
<< node->remote_.full.value() << " with suggested name " << node->suggested_name() << " and encyption key "
<< node->remote_.full.value() << " with suggested name " << node->suggested_path() << " and encyption key "
<< node->encryption_key_;
auto download_offset = node->download_offset_;
auto download_limit = node->download_limit_;
@ -2328,19 +2329,20 @@ void FileManager::run_download(FileNodePtr node, bool force_update_priority) {
download_offset = 0;
}
send_closure(file_load_manager_, &FileLoadManager::download, id, node->remote_.full.value(), node->local_,
node->size_, node->suggested_name(), node->encryption_key_, node->can_search_locally_, download_offset,
node->size_, node->suggested_path(), node->encryption_key_, node->can_search_locally_, download_offset,
download_limit, priority);
}
class FileManager::ForceUploadActor : public Actor {
public:
ForceUploadActor(FileManager *file_manager, FileId file_id, std::shared_ptr<FileManager::UploadCallback> callback,
int32 new_priority, uint64 upload_order, ActorShared<> parent)
int32 new_priority, uint64 upload_order, bool prefer_small, ActorShared<> parent)
: file_manager_(file_manager)
, file_id_(file_id)
, callback_(std::move(callback))
, new_priority_(new_priority)
, upload_order_(upload_order)
, prefer_small_(prefer_small)
, parent_(std::move(parent)) {
}
@ -2350,9 +2352,11 @@ class FileManager::ForceUploadActor : public Actor {
std::shared_ptr<FileManager::UploadCallback> callback_;
int32 new_priority_;
uint64 upload_order_;
bool prefer_small_;
ActorShared<> parent_;
bool is_active_{false};
int attempt_{0};
class UploadCallback : public FileManager::UploadCallback {
public:
explicit UploadCallback(ActorId<ForceUploadActor> callback) : callback_(std::move(callback)) {
@ -2449,7 +2453,7 @@ class FileManager::ForceUploadActor : public Actor {
is_active_ = true;
attempt_++;
send_closure(G()->file_manager(), &FileManager::resume_upload, file_id_, std::vector<int>(), create_callback(),
new_priority_, upload_order_, attempt_ == 2);
new_priority_, upload_order_, attempt_ == 2, prefer_small_);
}
void tear_down() override {
@ -2468,7 +2472,7 @@ void FileManager::on_force_reupload_success(FileId file_id) {
}
void FileManager::resume_upload(FileId file_id, std::vector<int> bad_parts, std::shared_ptr<UploadCallback> callback,
int32 new_priority, uint64 upload_order, bool force) {
int32 new_priority, uint64 upload_order, bool force, bool prefer_small) {
auto node = get_sync_file_node(file_id);
if (!node) {
LOG(INFO) << "File " << file_id << " not found";
@ -2488,7 +2492,7 @@ void FileManager::resume_upload(FileId file_id, std::vector<int> bad_parts, std:
}
create_actor<ForceUploadActor>("ForceUploadActor", this, file_id, std::move(callback), new_priority, upload_order,
context_->create_reference())
prefer_small, context_->create_reference())
.release();
return;
}
@ -2497,6 +2501,9 @@ void FileManager::resume_upload(FileId file_id, std::vector<int> bad_parts, std:
if (force) {
node->remote_.is_full_alive = false;
}
if (prefer_small) {
node->upload_prefer_small_ = true;
}
if (node->upload_pause_ == file_id) {
node->set_upload_pause(FileId());
}
@ -2676,7 +2683,7 @@ void FileManager::run_generate(FileNodePtr node) {
QueryId id = queries_container_.create(Query{file_id, Query::Type::Generate});
node->generate_id_ = id;
send_closure(file_generate_manager_, &FileGenerateManager::generate_file, id, *node->generate_, node->local_,
node->suggested_name(), [file_manager = this, id] {
node->suggested_path(), [file_manager = this, id] {
class Callback : public FileGenerateCallback {
ActorId<FileManager> actor_;
uint64 query_id_;
@ -2806,10 +2813,15 @@ void FileManager::run_upload(FileNodePtr node, std::vector<int> bad_parts) {
auto new_priority = narrow_cast<int8>(bad_parts.empty() ? -priority : priority);
td::remove_if(bad_parts, [](auto part_id) { return part_id < 0; });
auto expected_size = file_view.expected_size(true);
if (node->upload_prefer_small_ && (10 << 20) < expected_size && expected_size < (30 << 20)) {
expected_size = 10 << 20;
}
QueryId id = queries_container_.create(Query{file_id, Query::Type::Upload});
node->upload_id_ = id;
send_closure(file_load_manager_, &FileLoadManager::upload, id, node->local_, node->remote_.partial_or_empty(),
file_view.expected_size(true), node->encryption_key_, new_priority, std::move(bad_parts));
expected_size, node->encryption_key_, new_priority, std::move(bad_parts));
LOG(INFO) << "File " << file_id << " upload request has sent to FileLoadManager";
}
@ -3179,6 +3191,70 @@ Result<FileId> FileManager::get_map_thumbnail_file_id(Location location, int32 z
FileLocationSource::FromUser, string(), std::move(conversion), owner_dialog_id, 0);
}
FileType FileManager::guess_file_type(const tl_object_ptr<td_api::InputFile> &file) {
if (file == nullptr) {
return FileType::Temp;
}
auto guess_file_type_by_path = [](const string &file_path) {
PathView path_view(file_path);
auto file_name = path_view.file_name();
auto extension = path_view.extension();
if (extension == "jpg" || extension == "jpeg") {
return FileType::Photo;
}
if (extension == "ogg" || extension == "oga" || extension == "opus") {
return FileType::VoiceNote;
}
if (extension == "3gp" || extension == "mov") {
return FileType::Video;
}
if (extension == "mp3" || extension == "mpeg3" || extension == "m4a") {
return FileType::Audio;
}
if (extension == "webp" || extension == "tgs") {
return FileType::Sticker;
}
if (extension == "gif") {
return FileType::Animation;
}
if (extension == "mp4" || extension == "mpeg4") {
return to_lower(file_name).find("-gif-") != string::npos ? FileType::Animation : FileType::Video;
}
return FileType::Document;
};
switch (file->get_id()) {
case td_api::inputFileLocal::ID:
return guess_file_type_by_path(static_cast<const td_api::inputFileLocal *>(file.get())->path_);
case td_api::inputFileId::ID: {
FileId file_id(static_cast<const td_api::inputFileId *>(file.get())->id_, 0);
auto file_view = get_file_view(file_id);
if (file_view.empty()) {
return FileType::Temp;
}
return file_view.get_type();
}
case td_api::inputFileRemote::ID: {
const string &file_persistent_id = static_cast<const td_api::inputFileRemote *>(file.get())->id_;
Result<FileId> r_file_id = from_persistent_id(file_persistent_id, FileType::Temp);
if (r_file_id.is_error()) {
return FileType::Temp;
}
auto file_view = get_file_view(r_file_id.ok());
if (file_view.empty()) {
return FileType::Temp;
}
return file_view.get_type();
}
case td_api::inputFileGenerated::ID:
return guess_file_type_by_path(static_cast<const td_api::inputFileGenerated *>(file.get())->original_path_);
default:
UNREACHABLE();
return FileType::Temp;
}
}
vector<tl_object_ptr<telegram_api::InputDocument>> FileManager::get_input_documents(const vector<FileId> &file_ids) {
vector<tl_object_ptr<telegram_api::InputDocument>> result;
result.reserve(file_ids.size());
@ -3436,7 +3512,7 @@ void FileManager::on_upload_ok(QueryId query_id, FileType file_type, const Parti
file_info->download_priority_ = 0;
FileView file_view(file_node);
string file_name = get_file_name(file_type, file_view.suggested_name());
string file_name = get_file_name(file_type, file_view.suggested_path());
if (file_view.is_encrypted_secret()) {
tl_object_ptr<telegram_api::InputEncryptedFile> input_file;

View File

@ -120,7 +120,7 @@ class FileNode {
void on_pmc_flushed();
void on_info_flushed();
string suggested_name() const;
string suggested_path() const;
bool empty = false;
private:
@ -158,6 +158,7 @@ class FileNode {
double last_successful_force_reupload_time_ = -1e10;
FileId upload_pause_;
int8 upload_priority_ = 0;
int8 download_priority_ = 0;
int8 generate_priority_ = 0;
@ -185,6 +186,8 @@ class FileNode {
bool upload_was_update_file_reference_{false};
bool download_was_update_file_reference_{false};
bool upload_prefer_small_{false};
void init_ready_size();
void recalc_ready_prefix_size(int64 prefix_offset, int64 ready_prefix_size);
@ -259,7 +262,7 @@ class FileView {
const string &remote_name() const;
string suggested_name() const;
string suggested_path() const;
DialogId owner_dialog_id() const;
@ -454,7 +457,7 @@ class FileManager : public FileLoadManager::Callback {
int64 limit);
void upload(FileId file_id, std::shared_ptr<UploadCallback> callback, int32 new_priority, uint64 upload_order);
void resume_upload(FileId file_id, std::vector<int> bad_parts, std::shared_ptr<UploadCallback> callback,
int32 new_priority, uint64 upload_order, bool force = false);
int32 new_priority, uint64 upload_order, bool force = false, bool prefer_small = false);
void cancel_upload(FileId file_id);
bool delete_partial_remote_location(FileId file_id);
void delete_file_reference(FileId file_id, std::string file_reference);
@ -484,6 +487,8 @@ class FileManager : public FileLoadManager::Callback {
Result<FileId> get_map_thumbnail_file_id(Location location, int32 zoom, int32 width, int32 height, int32 scale,
DialogId owner_dialog_id) TD_WARN_UNUSED_RESULT;
FileType guess_file_type(const tl_object_ptr<td_api::InputFile> &file);
vector<tl_object_ptr<telegram_api::InputDocument>> get_input_documents(const vector<FileId> &file_ids);
static bool extract_was_uploaded(const tl_object_ptr<telegram_api::InputMedia> &input_media);
@ -505,7 +510,7 @@ class FileManager : public FileLoadManager::Callback {
private:
void destroy_query(int32 file_id);
void memory_cleanup(bool full);
Result<FileId> check_input_file_id(FileType type, Result<FileId> result, bool is_encrypted, bool allow_zero,

View File

@ -184,7 +184,7 @@ Result<FileLoader::PrefixInfo> FileUploader::on_update_local_location(const Loca
}
local_size_ = local_size;
if (expected_size_ < local_size_) {
if (expected_size_ < local_size_ && (expected_size_ != (10 << 20) || local_size_ >= (30 << 20))) {
expected_size_ = local_size_;
}
local_is_ready_ = local_is_ready;

View File

@ -100,6 +100,7 @@ class LogEvent {
ReadMessageThreadHistoryOnServer = 0x119,
BlockMessageSenderFromRepliesOnServer = 0x120,
UnpinAllDialogMessagesOnServer = 0x121,
DeleteAllCallMessagesFromServer = 0x122,
GetChannelDifference = 0x140,
AddMessagePushNotification = 0x200,
EditMessagePushNotification = 0x201,

View File

@ -34,12 +34,8 @@ class SecretChatEvent : public LogEventBase<SecretChatEvent> {
virtual Type get_type() const = 0;
static constexpr LogEvent::HandlerType get_handler_type() {
return LogEvent::HandlerType::SecretChats;
}
static constexpr int32 version() {
return 2;
return 3;
}
template <class F>
@ -354,7 +350,7 @@ class OutboundSecretMessage : public SecretChatLogEventBase<OutboundSecretMessag
store(my_out_seq_no, storer);
store(his_in_seq_no, storer);
bool has_action = static_cast<bool>(action);
bool has_action = action != nullptr;
BEGIN_STORE_FLAGS();
STORE_FLAG(is_sent);
STORE_FLAG(need_notify_user);
@ -414,21 +410,34 @@ class CloseSecretChat : public SecretChatLogEventBase<CloseSecretChat> {
public:
static constexpr Type type = SecretChatEvent::Type::CloseSecretChat;
int32 chat_id = 0;
bool delete_history = false;
bool is_already_discarded = false;
template <class StorerT>
void store(StorerT &storer) const {
using td::store;
BEGIN_STORE_FLAGS();
STORE_FLAG(delete_history);
STORE_FLAG(is_already_discarded);
END_STORE_FLAGS();
store(chat_id, storer);
}
template <class ParserT>
void parse(ParserT &parser) {
using td::parse;
if (parser.version() >= 3) {
BEGIN_PARSE_FLAGS();
PARSE_FLAG(delete_history);
PARSE_FLAG(is_already_discarded);
END_PARSE_FLAGS();
}
parse(chat_id, parser);
}
StringBuilder &print(StringBuilder &sb) const override {
return sb << "[Logevent CloseSecretChat " << tag("id", log_event_id()) << tag("chat_id", chat_id) << "]";
return sb << "[Logevent CloseSecretChat " << tag("id", log_event_id()) << tag("chat_id", chat_id)
<< tag("delete_history", delete_history) << tag("is_already_discarded", is_already_discarded) << "]";
}
};

View File

@ -41,12 +41,9 @@ class AuthDataSharedImpl : public AuthDataShared {
}
return res;
}
using AuthDataShared::get_auth_key_state;
std::pair<AuthKeyState, bool> get_auth_key_state() override {
// TODO (perf):
auto auth_key = get_auth_key();
AuthKeyState state = get_auth_key_state(auth_key);
return std::make_pair(state, auth_key.was_auth_flag());
AuthKeyState get_auth_key_state() override {
return AuthDataShared::get_auth_key_state(get_auth_key());
}
void set_auth_key(const mtproto::AuthKey &auth_key) override {
@ -106,7 +103,8 @@ class AuthDataSharedImpl : public AuthDataShared {
}
void log_auth_key(const mtproto::AuthKey &auth_key) {
LOG(WARNING) << dc_id_ << " " << tag("auth_key_id", auth_key.id()) << tag("state", get_auth_key_state(auth_key))
LOG(WARNING) << dc_id_ << " " << tag("auth_key_id", auth_key.id())
<< tag("state", AuthDataShared::get_auth_key_state(auth_key))
<< tag("created_at", auth_key.created_at());
}
};

View File

@ -51,7 +51,7 @@ class AuthDataShared {
virtual DcId dc_id() const = 0;
virtual const std::shared_ptr<PublicRsaKeyShared> &public_rsa_key() = 0;
virtual mtproto::AuthKey get_auth_key() = 0;
virtual std::pair<AuthKeyState, bool> get_auth_key_state() = 0;
virtual AuthKeyState get_auth_key_state() = 0;
virtual void set_auth_key(const mtproto::AuthKey &auth_key) = 0;
virtual void update_server_time_difference(double diff) = 0;
virtual double get_server_time_difference() = 0;

View File

@ -8,7 +8,6 @@
#include "td/actor/actor.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Global.h"
#include "td/telegram/net/AuthDataShared.h"
#include "td/telegram/net/NetQuery.h"
@ -64,11 +63,8 @@ void DcAuthManager::add_dc(std::shared_ptr<AuthDataShared> auth_data) {
info.dc_id = auth_data->dc_id();
CHECK(info.dc_id.is_exact());
info.shared_auth_data = std::move(auth_data);
auto state_was_auth = info.shared_auth_data->get_auth_key_state();
info.auth_key_state = state_was_auth.first;
VLOG(dc) << "Add " << info.dc_id << " with auth key state " << info.auth_key_state
<< " and was_auth = " << state_was_auth.second;
was_auth_ |= state_was_auth.second;
info.auth_key_state = info.shared_auth_data->get_auth_key_state();
VLOG(dc) << "Add " << info.dc_id << " with auth key state " << info.auth_key_state;
if (!main_dc_id_.is_exact()) {
main_dc_id_ = info.dc_id;
VLOG(dc) << "Set main DcId to " << main_dc_id_;
@ -100,11 +96,8 @@ DcAuthManager::DcInfo *DcAuthManager::find_dc(int32 dc_id) {
void DcAuthManager::update_auth_key_state() {
int32 dc_id = narrow_cast<int32>(get_link_token());
auto &dc = get_dc(dc_id);
auto state_was_auth = dc.shared_auth_data->get_auth_key_state();
VLOG(dc) << "Update " << dc_id << " auth key state from " << dc.auth_key_state << " to " << state_was_auth.first
<< " with was_auth = " << state_was_auth.second;
dc.auth_key_state = state_was_auth.first;
was_auth_ |= state_was_auth.second;
dc.auth_key_state = dc.shared_auth_data->get_auth_key_state();
VLOG(dc) << "Update " << dc_id << " auth key state from " << dc.auth_key_state << " to " << dc.auth_key_state;
loop();
}
@ -239,15 +232,8 @@ void DcAuthManager::loop() {
}
auto main_dc = find_dc(main_dc_id_.get_raw_id());
if (!main_dc || main_dc->auth_key_state != AuthKeyState::OK) {
VLOG(dc) << "Main is " << main_dc_id_ << ", main auth key state is "
<< (main_dc ? main_dc->auth_key_state : AuthKeyState::Empty) << ", was_auth = " << was_auth_;
if (was_auth_) {
G()->shared_config().set_option_boolean("auth", false);
destroy_loop();
}
VLOG(dc) << "Skip loop because auth state of main DcId " << main_dc_id_.get_raw_id() << " is "
<< (main_dc != nullptr ? (PSTRING() << main_dc->auth_key_state) : "unknown");
VLOG(dc) << "Skip loop, because main DC is " << main_dc_id_ << ", main auth key state is "
<< (main_dc != nullptr ? main_dc->auth_key_state : AuthKeyState::Empty);
return;
}
for (auto &dc : dcs_) {

View File

@ -47,7 +47,6 @@ class DcAuthManager : public NetQueryCallback {
ActorShared<> parent_;
std::vector<DcInfo> dcs_;
bool was_auth_{false};
DcId main_dc_id_;
bool close_flag_{false};
Promise<> destroy_promise_;

View File

@ -77,7 +77,7 @@ void PublicRsaKeyWatchdog::on_result(NetQueryPtr net_query) {
has_query_ = false;
yield();
if (net_query->is_error()) {
LOG(ERROR) << "Receive error for GetCdnConfigQuery: " << net_query->move_as_error();
LOG(ERROR) << "Receive error for GetCdnConfig: " << net_query->move_as_error();
return;
}

View File

@ -8,6 +8,7 @@
#include "td/telegram/telegram_api.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/DhCache.h"
#include "td/telegram/Global.h"
#include "td/telegram/net/DcAuthManager.h"
@ -778,6 +779,7 @@ void Session::on_message_result_error(uint64 id, int error_code, BufferSlice mes
LOG(WARNING) << "Lost authorization due to " << tag("msg", message.as_slice());
}
auth_data_.set_auth_flag(false);
G()->shared_config().set_option_boolean("auth", false);
shared_auth_data_->set_auth_key(auth_data_.get_main_auth_key());
on_session_failed(Status::OK());
}

View File

@ -102,7 +102,7 @@ void SessionProxy::start_up() {
private:
ActorShared<SessionProxy> session_proxy_;
};
auth_key_state_ = auth_data_->get_auth_key_state().first;
auth_key_state_ = auth_data_->get_auth_key_state();
auth_data_->add_auth_key_listener(make_unique<Listener>(actor_shared(this)));
open_session();
}
@ -212,7 +212,7 @@ void SessionProxy::open_session(bool force) {
void SessionProxy::update_auth_key_state() {
auto old_auth_key_state = auth_key_state_;
auth_key_state_ = auth_data_->get_auth_key_state().first;
auth_key_state_ = auth_data_->get_auth_key_state();
if (auth_key_state_ != old_auth_key_state && old_auth_key_state == AuthKeyState::OK) {
close_session();
}

View File

@ -28,8 +28,7 @@ Status BinlogEvent::init(BufferSlice &&raw_event, bool check_crc) {
data_ = MutableSlice(const_cast<char *>(slice_data.begin()), slice_data.size());
crc32_ = static_cast<uint32>(parser.fetch_int());
if (check_crc) {
CHECK(size_ >= TAIL_SIZE);
auto calculated_crc = crc32(raw_event.as_slice().truncate(size_ - TAIL_SIZE));
auto calculated_crc = crc32(raw_event.as_slice().substr(0, size_ - TAIL_SIZE));
if (calculated_crc != crc32_) {
return Status::Error(PSLICE() << "crc mismatch " << tag("actual", format::as_hex(calculated_crc))
<< tag("expected", format::as_hex(crc32_)) << public_to_string());
@ -44,7 +43,7 @@ Status BinlogEvent::validate() const {
if (raw_event_.size() < 4) {
return Status::Error("Too small event");
}
uint32 size = TlParser(raw_event_.as_slice().truncate(4)).fetch_int();
uint32 size = TlParser(raw_event_.as_slice().substr(0, 4)).fetch_int();
if (size_ != size) {
return Status::Error(PSLICE() << "Size of event changed: " << tag("was", size_) << tag("now", size));
}

View File

@ -51,7 +51,7 @@ if (NOT CMAKE_CROSSCOMPILING)
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/auto/mime_type_to_extension.cpp
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${MIME_TYPE_TO_EXTENSION_CMD}
DEPENDS auto/mime_type_to_extension.gperf
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/auto/mime_type_to_extension.gperf
)
if (CMAKE_HOST_WIN32)
@ -63,6 +63,6 @@ if (NOT CMAKE_CROSSCOMPILING)
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/auto/extension_to_mime_type.cpp
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${EXTENSION_TO_MIME_TYPE_CMD}
DEPENDS auto/extension_to_mime_type.gperf
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/auto/extension_to_mime_type.gperf
)
endif()

View File

@ -594,7 +594,7 @@ audio/basic au snd
audio/midi mid midi kar rmi
audio/mp4 m4a mp4a
audio/mpeg mpga mp2 mp2a mp3 m2a m3a
audio/ogg oga ogg spx
audio/ogg oga ogg opus spx
audio/s3m s3m
audio/silk sil
audio/vnd.dece.audio uva uvva

View File

@ -147,7 +147,7 @@ bool BigNum::is_bit_set(int num) const {
}
bool BigNum::is_prime(BigNumContext &context) const {
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
int result = BN_check_prime(impl_->big_num, context.impl_->big_num_context, nullptr);
#else
int result =

View File

@ -101,7 +101,8 @@ Result<size_t> BufferedFdBase<FdT>::flush_read(size_t max_read) {
CHECK(read_);
size_t result = 0;
while (::td::can_read_local(*this) && max_read) {
MutableSlice slice = read_->prepare_append().truncate(max_read);
MutableSlice slice = read_->prepare_append();
slice.truncate(max_read);
TRY_RESULT(x, FdT::read(slice));
slice.truncate(x);
read_->confirm_append(x);

View File

@ -36,7 +36,7 @@ class UdpWriter {
}
size_t cnt;
auto status = fd.send_messages(::td::Span<UdpSocketFd::OutboundMessage>(messages).truncate(to_send_n), cnt);
auto status = fd.send_messages(Span<UdpSocketFd::OutboundMessage>(messages).truncate(to_send_n), cnt);
queue.pop_n(cnt);
return status;
}
@ -51,7 +51,7 @@ class UdpReaderHelper {
buffer_ = BufferSlice(RESERVED_SIZE);
}
CHECK(buffer_.size() >= MAX_PACKET_SIZE);
message.data = buffer_.as_slice().truncate(MAX_PACKET_SIZE);
message.data = buffer_.as_slice().substr(0, MAX_PACKET_SIZE);
}
UdpMessage extract_udp_message(UdpSocketFd::InboundMessage &message) {

View File

@ -156,6 +156,9 @@ Result<SecureString> base64_decode_secure(Slice base64) {
Result<string> base64url_decode(Slice base64) {
return base64_decode_impl<true, string>(base64);
}
Result<SecureString> base64url_decode_secure(Slice base64) {
return base64_decode_impl<true, SecureString>(base64);
}
template <bool is_url>
static bool is_base64_impl(Slice input) {

View File

@ -19,6 +19,7 @@ Result<SecureString> base64_decode_secure(Slice base64);
string base64url_encode(Slice input);
Result<string> base64url_decode(Slice base64);
Result<SecureString> base64url_decode_secure(Slice base64);
bool is_base64(Slice input);
bool is_base64url(Slice input);

View File

@ -34,7 +34,7 @@
#include <openssl/sha.h>
#endif
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
#include <openssl/core_names.h>
#include <openssl/params.h>
#endif
@ -680,7 +680,7 @@ void AesCtrState::decrypt(Slice from, MutableSlice to) {
encrypt(from, to);
}
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
static void make_digest(Slice data, MutableSlice output, const EVP_MD *evp_md) {
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
LOG_IF(FATAL, ctx == nullptr);
@ -695,7 +695,7 @@ static void make_digest(Slice data, MutableSlice output, const EVP_MD *evp_md) {
#endif
void sha1(Slice data, unsigned char output[20]) {
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
make_digest(data, MutableSlice(output, 20), EVP_sha1());
#else
auto result = SHA1(data.ubegin(), data.size(), output);
@ -705,7 +705,7 @@ void sha1(Slice data, unsigned char output[20]) {
void sha256(Slice data, MutableSlice output) {
CHECK(output.size() >= 32);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
make_digest(data, output, EVP_sha256());
#else
auto result = SHA256(data.ubegin(), data.size(), output.ubegin());
@ -715,7 +715,7 @@ void sha256(Slice data, MutableSlice output) {
void sha512(Slice data, MutableSlice output) {
CHECK(output.size() >= 64);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
make_digest(data, output, EVP_sha512());
#else
auto result = SHA512(data.ubegin(), data.size(), output.ubegin());
@ -737,7 +737,7 @@ string sha512(Slice data) {
class Sha256State::Impl {
public:
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
EVP_MD_CTX *ctx_;
Impl() {
@ -789,7 +789,7 @@ void Sha256State::init() {
impl_ = make_unique<Sha256State::Impl>();
}
CHECK(!is_inited_);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
int err = EVP_DigestInit_ex(impl_->ctx_, EVP_sha256(), nullptr);
#else
int err = SHA256_Init(&impl_->ctx_);
@ -801,7 +801,7 @@ void Sha256State::init() {
void Sha256State::feed(Slice data) {
CHECK(impl_);
CHECK(is_inited_);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
int err = EVP_DigestUpdate(impl_->ctx_, data.ubegin(), data.size());
#else
int err = SHA256_Update(&impl_->ctx_, data.ubegin(), data.size());
@ -813,7 +813,7 @@ void Sha256State::extract(MutableSlice output, bool destroy) {
CHECK(output.size() >= 32);
CHECK(impl_);
CHECK(is_inited_);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
int err = EVP_DigestFinal_ex(impl_->ctx_, output.ubegin(), nullptr);
#else
int err = SHA256_Final(output.ubegin(), &impl_->ctx_);
@ -827,7 +827,7 @@ void Sha256State::extract(MutableSlice output, bool destroy) {
void md5(Slice input, MutableSlice output) {
CHECK(output.size() >= 16);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
make_digest(input, output, EVP_md5());
#else
auto result = MD5(input.ubegin(), input.size(), output.ubegin());
@ -880,7 +880,7 @@ void pbkdf2_sha512(Slice password, Slice salt, int iteration_count, MutableSlice
pbkdf2_impl(password, salt, iteration_count, dest, EVP_sha512());
}
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
static void hmac_impl(const char *digest, Slice key, Slice message, MutableSlice dest) {
EVP_MAC *hmac = EVP_MAC_fetch(nullptr, "HMAC", nullptr);
LOG_IF(FATAL, hmac == nullptr);
@ -918,7 +918,7 @@ static void hmac_impl(const EVP_MD *evp_md, Slice key, Slice message, MutableSli
void hmac_sha256(Slice key, Slice message, MutableSlice dest) {
CHECK(dest.size() == 256 / 8);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
hmac_impl("SHA256", key, message, dest);
#else
hmac_impl(EVP_sha256(), key, message, dest);
@ -927,7 +927,7 @@ void hmac_sha256(Slice key, Slice message, MutableSlice dest) {
void hmac_sha512(Slice key, Slice message, MutableSlice dest) {
CHECK(dest.size() == 512 / 8);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
hmac_impl("SHA512", key, message, dest);
#else
hmac_impl(EVP_sha512(), key, message, dest);

View File

@ -201,7 +201,8 @@ class BufferedStdinImpl {
size_t result = 0;
::td::sync_with_poll(*this);
while (::td::can_read_local(*this) && max_read) {
MutableSlice slice = writer_.prepare_append().truncate(max_read);
MutableSlice slice = writer_.prepare_append();
slice.truncate(max_read);
TRY_RESULT(x, file_fd_.read(slice));
slice.truncate(x);
writer_.confirm_append(x);

View File

@ -7,7 +7,6 @@
#include "td/utils/translit.h"
#include "td/utils/algorithm.h"
#include "td/utils/format.h"
#include "td/utils/misc.h"
#include "td/utils/utf8.h"

View File

@ -32,6 +32,20 @@ set(TESTS_MAIN
if (NOT CMAKE_CROSSCOMPILING OR EMSCRIPTEN)
#Tests
if (OPENSSL_FOUND)
add_executable(test-crypto EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/crypto.cpp)
target_include_directories(test-crypto SYSTEM PRIVATE ${OPENSSL_INCLUDE_DIR})
target_link_libraries(test-crypto PRIVATE ${OPENSSL_CRYPTO_LIBRARY} ${CMAKE_DL_LIBS} ${ZLIB_LIBRARIES} tdutils tdcore)
if (WIN32)
if (MINGW)
target_link_libraries(test-crypto PRIVATE ws2_32 mswsock crypt32)
else()
target_link_libraries(test-crypto PRIVATE ws2_32 Mswsock Crypt32)
endif()
endif()
endif()
add_executable(test-tdutils EXCLUDE_FROM_ALL ${TESTS_MAIN} ${TDUTILS_TEST_SOURCE})
add_executable(test-online EXCLUDE_FROM_ALL online.cpp)
add_executable(run_all_tests ${TESTS_MAIN} ${TD_TEST_SOURCE})

Some files were not shown because too many files have changed in this diff Show More