diff --git a/CMakeLists.txt b/CMakeLists.txt index c0f36a06..a26dae4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,13 @@ project(TDLib VERSION 1.5.5 LANGUAGES CXX C) if (NOT DEFINED CMAKE_INSTALL_LIBDIR) set(CMAKE_INSTALL_LIBDIR "lib") -endif(NOT DEFINED CMAKE_INSTALL_LIBDIR) +endif() +if (NOT DEFINED CMAKE_INSTALL_BINDIR) + set(CMAKE_INSTALL_BINDIR "bin") +endif() +if (NOT DEFINED CMAKE_INSTALL_INCLUDEDIR) + set(CMAKE_INSTALL_INCLUDEDIR "include") +endif() if (POLICY CMP0054) # do not expand quoted arguments @@ -255,7 +261,7 @@ if (NOT CMAKE_CROSSCOMPILING) add_custom_target(prepare_cross_compiling DEPENDS tl_generate_common tdmime_auto tl_generate_json) if (TD_ENABLE_DOTNET) add_custom_target(remove_cpp_documentation - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND remove_documentation ${TL_TD_AUTO} td/telegram/Client.h td/telegram/Log.h td/tl/TlObject.h COMMENT "Remove C++ documentation from sources" DEPENDS remove_documentation tl_generate_common generate_dotnet_api ${TL_TD_AUTO} td/telegram/Client.h td/telegram/Log.h td/tl/TlObject.h @@ -295,7 +301,6 @@ endif() get_directory_property(HAS_PARENT PARENT_DIRECTORY) if (HAS_PARENT) - set(TL_TD_AUTO_INCLUDES ${TL_TD_AUTO_INCLUDES} PARENT_SCOPE) set(TL_TD_API_TLO ${TL_TD_API_TLO} PARENT_SCOPE) set(TL_TD_JSON_AUTO ${TL_TD_JSON_AUTO} PARENT_SCOPE) set(TD_TEST_SOURCE ${TD_TEST_SOURCE} PARENT_SCOPE) @@ -375,6 +380,7 @@ set(TDLIB_SOURCE td/telegram/Contact.cpp td/telegram/ContactsManager.cpp td/telegram/DelayDispatcher.cpp + td/telegram/Dependencies.cpp td/telegram/DeviceTokenManager.cpp td/telegram/DhCache.cpp td/telegram/DialogAdministrator.cpp @@ -414,6 +420,7 @@ set(TDLIB_SOURCE td/telegram/Location.cpp td/telegram/Logging.cpp td/telegram/MessageContent.cpp + td/telegram/MessageContentType.cpp td/telegram/MessageEntity.cpp td/telegram/MessageId.cpp td/telegram/MessagesDb.cpp @@ -576,6 +583,7 @@ set(TDLIB_SOURCE td/telegram/logevent/SecretChatEvent.h td/telegram/Logging.h td/telegram/MessageContent.h + td/telegram/MessageContentType.h td/telegram/MessageEntity.h td/telegram/MessageId.h td/telegram/MessagesDb.h @@ -647,6 +655,7 @@ set(TDLIB_SOURCE td/telegram/TdDb.h td/telegram/TdParameters.h td/telegram/TermsOfService.h + td/telegram/TopDialogCategory.h td/telegram/TopDialogManager.h td/telegram/UniqueId.h td/telegram/UpdatesManager.h @@ -709,7 +718,7 @@ else() endif() add_custom_target(git_commit ALL - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND ${GIT_COMMIT_CMD} COMMENT "Generate git_commit.h" ) @@ -734,7 +743,7 @@ endif() # tdcore - mostly internal TDLib interface. One should use tdactor for interactions with it. add_library(tdcore STATIC ${TDLIB_SOURCE}) -target_include_directories(tdcore PUBLIC $ $) +target_include_directories(tdcore PUBLIC $ $) target_include_directories(tdcore SYSTEM PRIVATE ${OPENSSL_INCLUDE_DIR}) target_link_libraries(tdcore PUBLIC tdactor tdutils tdnet tddb PRIVATE ${OPENSSL_CRYPTO_LIBRARY} ${CMAKE_DL_LIBS} ${ZLIB_LIBRARIES}) @@ -760,7 +769,7 @@ endif() add_library(tdclient td/telegram/Client.cpp td/telegram/Client.h td/telegram/Log.cpp td/telegram/Log.h) target_include_directories(tdclient PUBLIC $ - $ + $ ) target_link_libraries(tdclient PRIVATE tdcore) @@ -780,7 +789,7 @@ if (TD_ENABLE_DOTNET) set_target_properties(tddotnet PROPERTIES OUTPUT_NAME Telegram.Td) target_link_libraries(tddotnet PRIVATE tdclient tdutils) target_include_directories(tddotnet PUBLIC - $ + $ ) if (NOT CMAKE_CROSSCOMPILING) add_dependencies(tddotnet generate_dotnet_api) @@ -800,7 +809,7 @@ endif() add_library(tdc STATIC EXCLUDE_FROM_ALL ${TL_C_SCHEME_SOURCE} td/telegram/td_c_client.cpp td/telegram/td_c_client.h) target_include_directories(tdc PUBLIC $ - $) + $) target_link_libraries(tdc PRIVATE tdclient tdutils) if (NOT CMAKE_CROSSCOMPILING) add_dependencies(tdc tl_generate_c) @@ -809,7 +818,7 @@ endif() add_library(tdjson_private STATIC ${TL_TD_JSON} td/telegram/ClientJson.cpp td/telegram/ClientJson.h) target_include_directories(tdjson_private PUBLIC $ - $) + $) target_link_libraries(tdjson_private PUBLIC tdclient tdutils) if (NOT CMAKE_CROSSCOMPILING) add_dependencies(tdjson_private tl_generate_common tl_generate_json) @@ -914,35 +923,35 @@ add_library(Td::TdJson ALIAS TdJson) add_library(Td::TdJsonStatic ALIAS TdJsonStatic) install(TARGETS tdjson TdJson tdjson_static TdJsonStatic tdjson_private tdclient tdcore TdStatic EXPORT TdTargets - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION bin - INCLUDES DESTINATION include + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" ) install(EXPORT TdTargets FILE TdTargets.cmake NAMESPACE Td:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Td + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Td" ) -install(FILES ${TD_JSON_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/td/telegram/tdjson_export.h DESTINATION include/td/telegram) -install(FILES td/telegram/Client.h td/telegram/Log.h DESTINATION include/td/telegram) -install(FILES td/tl/TlObject.h DESTINATION include/td/tl) -install(FILES ${TL_TD_AUTO_INCLUDES}/td/telegram/td_api.h ${TL_TD_AUTO_INCLUDES}/td/telegram/td_api.hpp DESTINATION include/td/telegram) +install(FILES ${TD_JSON_HEADERS} "${CMAKE_CURRENT_BINARY_DIR}/td/telegram/tdjson_export.h" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/td/telegram") +install(FILES td/telegram/Client.h td/telegram/Log.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/td/telegram") +install(FILES td/tl/TlObject.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/td/tl") +install(FILES "${TL_TD_AUTO_INCLUDE_DIR}/td/telegram/td_api.h" "${TL_TD_AUTO_INCLUDE_DIR}/td/telegram/td_api.hpp" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/td/telegram") if (TD_ENABLE_JNI) - install(FILES td/tl/tl_jni_object.h DESTINATION include/td/tl) + install(FILES td/tl/tl_jni_object.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/td/tl") endif() include(CMakePackageConfigHelpers) write_basic_package_version_file("TdConfigVersion.cmake" - VERSION ${TDLib_VERSION} + VERSION "${TDLib_VERSION}" COMPATIBILITY ExactVersion ) install(FILES "TdConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/TdConfigVersion.cmake" - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Td + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Td" ) # Add SOVERSION to shared libraries -set_property(TARGET tdclient PROPERTY SOVERSION ${TDLib_VERSION}) -set_property(TARGET tdjson PROPERTY SOVERSION ${TDLib_VERSION}) +set_property(TARGET tdclient PROPERTY SOVERSION "${TDLib_VERSION}") +set_property(TARGET tdjson PROPERTY SOVERSION "${TDLib_VERSION}") diff --git a/SplitSource.php b/SplitSource.php index 6ff66c4e..16a89fa7 100644 --- a/SplitSource.php +++ b/SplitSource.php @@ -281,6 +281,7 @@ function split_file($file, $chunks, $undo) { 'secret_chats_manager[_(-][^.]|SecretChatsManager' => 'SecretChatsManager', 'stickers_manager[_(-][^.]|StickersManager' => 'StickersManager', '[>](td_db[(][)]|get_td_db_impl[(])|TdDb[^A-Za-z]' => 'TdDb', + 'TopDialogCategory|top_dialog_category_from_td_api' => 'TopDialogCategory', 'top_dialog_manager[_(-][^.]|TopDialogManager' => 'TopDialogManager', 'updates_manager[_(-][^.]|UpdatesManager|get_difference[)]' => 'UpdatesManager', 'WebPageId(Hash)?' => 'WebPageId', diff --git a/example/README.md b/example/README.md index 7bdbd7fe..1fdabe5a 100644 --- a/example/README.md +++ b/example/README.md @@ -91,7 +91,7 @@ You can also see [JTDLib](https://github.com/ErnyTech/JTDLib) for another exampl ## Using TDLib in Kotlin projects -TDLib can be used from the Kotlin/JVM programming language through same way as in [JAVA](#java). +TDLib can be used from the Kotlin/JVM programming language through same way as in [Java](#java). You can also use [ktd](https://github.com/whyoleg/ktd) library with kotlin specific bindings. diff --git a/example/web/tdweb/README.md b/example/web/tdweb/README.md index 4bec0da5..4d8d545c 100644 --- a/example/web/tdweb/README.md +++ b/example/web/tdweb/README.md @@ -3,7 +3,7 @@ [TDLib](https://github.com/tdlib/td) is a library for building Telegram clients. tdweb is a convenient wrapper for TDLib in a browser which controls TDLib instance creation, handles interaction with TDLib and manages a filesystem for persistent TDLib data. -For interaction with TDLib you need to create an instance of the class `TdClient`, providing a handler for incoming updates and other options if needed. +For interaction with TDLib, you need to create an instance of the class `TdClient`, providing a handler for incoming updates and other options if needed. Once this is done, you can send queries to the TDLib instance using the method `TdClient.send` which returns a Promise object representing the result of the query. See [Getting Started](https://core.telegram.org/tdlib/getting-started) for a description of basic TDLib concepts and a short introduction to TDLib usage. @@ -14,16 +14,16 @@ TDLib [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_func The JSON representation of TDLib API objects is straightforward: all API objects are represented as JSON objects with the same keys as the API object field names in the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme. Note that in the automatically generated C++ documentation all fields have an additional terminating underscore which shouldn't be used in the JSON interface. The object type name is stored in the special field '@type' which is optional in places where type is uniquely determined by the context. -Fields of Bool type are stored as Boolean, fields of int32, int53 and double types are stored as Number, fields of int64 and string types are stored as String, +Fields of Bool type are stored as Boolean, fields of int32, int53, and double types are stored as Number, fields of int64 and string types are stored as String, fields of bytes type are base64 encoded and then stored as String, fields of vector type are stored as Array. You can also add the field '@extra' to any query to TDLib and the response will contain the field '@extra' with exactly the same value. ## Installation -As usual, add npm tdweb package into you project: +As usual, add npm tdweb package into your project: ``` npm install tdweb ``` -All files will be installed into `node_modules/tdweb/dist/` folder. For now it is your responsibility to make +All files will be installed into `node_modules/tdweb/dist/` folder. For now, it is your responsibility to make those files loadable from your server. For example, [telegram-react](https://github.com/evgeny-nadymov/telegram-react) -manually copies this files into the `public` folder. If you know how to avoid this problem, please tell us. +manually copies these files into the `public` folder. If you know how to avoid this problem, please tell us. diff --git a/sqlite/CMakeLists.txt b/sqlite/CMakeLists.txt index 5db411ea..6b60b367 100644 --- a/sqlite/CMakeLists.txt +++ b/sqlite/CMakeLists.txt @@ -1,5 +1,9 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +if (NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") +endif() + if (NOT OPENSSL_FOUND) find_package(OpenSSL REQUIRED) find_package(ZLIB REQUIRED) @@ -43,8 +47,6 @@ elseif (MSVC) endif() install(TARGETS tdsqlite EXPORT TdTargets - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" ) diff --git a/td/generate/CMakeLists.txt b/td/generate/CMakeLists.txt index 0b07d616..a3f52b6c 100644 --- a/td/generate/CMakeLists.txt +++ b/td/generate/CMakeLists.txt @@ -1,29 +1,35 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +if (NOT DEFINED CMAKE_INSTALL_BINDIR) + set(CMAKE_INSTALL_BINDIR "bin") +endif() + file(MAKE_DIRECTORY auto/td/telegram) file(MAKE_DIRECTORY auto/td/mtproto) -set(TL_TD_AUTO_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/auto PARENT_SCOPE) +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 - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/mtproto/mtproto_api.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/mtproto/mtproto_api.h - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/mtproto/mtproto_api.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/td_api.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/td_api.h - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/td_api.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/telegram_api.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/telegram_api.h - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/telegram_api.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/secret_api.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/secret_api.h - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/secret_api.hpp + ${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/td_api.cpp + ${TD_AUTO_INCLUDE_DIR}/telegram/td_api.h + ${TD_AUTO_INCLUDE_DIR}/telegram/td_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_JSON_AUTO - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/td_api_json.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/td_api_json.h + ${TD_AUTO_INCLUDE_DIR}/telegram/td_api_json.cpp + ${TD_AUTO_INCLUDE_DIR}/telegram/td_api_json.h PARENT_SCOPE ) @@ -31,15 +37,15 @@ set(TL_TD_API_TLO ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tlo) set(TL_TD_API_TLO ${TL_TD_API_TLO} PARENT_SCOPE) set(TL_C_AUTO - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/td_tdc_api.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/td_tdc_api.h - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/td_tdc_api_inner.h + ${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 - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/TdDotNetApi.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/TdDotNetApi.h + ${TD_AUTO_INCLUDE_DIR}/telegram/TdDotNetApi.cpp + ${TD_AUTO_INCLUDE_DIR}/telegram/TdDotNetApi.h PARENT_SCOPE ) @@ -129,9 +135,9 @@ if (NOT CMAKE_CROSSCOMPILING) ) if (TD_ENABLE_JNI) - install(TARGETS td_generate_java_api RUNTIME DESTINATION bin) - install(FILES JavadocTlDocumentationGenerator.php TlDocumentationGenerator.php DESTINATION bin/td/generate) - install(FILES scheme/td_api.tlo scheme/td_api.tl DESTINATION bin/td/generate/scheme) + 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") endif() if (TD_ENABLE_DOTNET) diff --git a/td/mtproto/ProxySecret.cpp b/td/mtproto/ProxySecret.cpp index de4962e1..571cd8f7 100644 --- a/td/mtproto/ProxySecret.cpp +++ b/td/mtproto/ProxySecret.cpp @@ -12,7 +12,7 @@ namespace td { namespace mtproto { -Result ProxySecret::from_link(Slice encoded_secret) { +Result ProxySecret::from_link(Slice encoded_secret, bool truncate_if_needed) { auto r_decoded = hex_decode(encoded_secret); if (r_decoded.is_error()) { r_decoded = base64url_decode(encoded_secret); @@ -20,10 +20,17 @@ Result ProxySecret::from_link(Slice encoded_secret) { if (r_decoded.is_error()) { return Status::Error(400, "Wrong proxy secret"); } - return from_binary(r_decoded.ok()); + return from_binary(r_decoded.ok(), truncate_if_needed); } -Result ProxySecret::from_binary(Slice raw_unchecked_secret) { +Result ProxySecret::from_binary(Slice raw_unchecked_secret, bool truncate_if_needed) { + if (raw_unchecked_secret.size() > 17 + MAX_DOMAIN_LENGTH) { + if (truncate_if_needed) { + raw_unchecked_secret.truncate(17 + MAX_DOMAIN_LENGTH); + } else { + return Status::Error(400, "Too long secret"); + } + } if (raw_unchecked_secret.size() == 16 || (raw_unchecked_secret.size() == 17 && static_cast(raw_unchecked_secret[0]) == 0xdd) || (raw_unchecked_secret.size() >= 18 && static_cast(raw_unchecked_secret[0]) == 0xee)) { diff --git a/td/mtproto/ProxySecret.h b/td/mtproto/ProxySecret.h index c4aade6c..199d02a6 100644 --- a/td/mtproto/ProxySecret.h +++ b/td/mtproto/ProxySecret.h @@ -15,8 +15,12 @@ namespace mtproto { class ProxySecret { public: - static Result from_link(Slice encoded_secret); - static Result from_binary(Slice raw_unchecked_secret); + static constexpr size_t MAX_DOMAIN_LENGTH = 182; // must be small enough to not overflow TLS-hello length + + static Result from_link(Slice encoded_secret, bool truncate_if_needed = false); + + static Result from_binary(Slice raw_unchecked_secret, bool truncate_if_needed = false); + static ProxySecret from_raw(Slice raw_secret) { ProxySecret result; result.secret_ = raw_secret.str(); diff --git a/td/mtproto/TlsInit.cpp b/td/mtproto/TlsInit.cpp index 115512eb..75d419f1 100644 --- a/td/mtproto/TlsInit.cpp +++ b/td/mtproto/TlsInit.cpp @@ -6,6 +6,8 @@ // #include "td/mtproto/TlsInit.h" +#include "td/mtproto/ProxySecret.h" + #include "td/utils/as.h" #include "td/utils/BigNum.h" #include "td/utils/common.h" @@ -91,6 +93,33 @@ class TlsHello { static const TlsHello &get_default() { static TlsHello result = [] { TlsHello res; +#if TD_DARWIN + res.ops_ = { + Op::string("\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03"), + Op::zero(32), + Op::string("\x20"), + Op::random(32), + Op::string("\x00\x34\x13\x03\x13\x01\x13\x02\xc0\x2c\xc0\x2b\xc0\x24\xc0\x23\xc0\x0a\xc0\x09\xcc\xa9\xc0\x30" + "\xc0\x2f\xc0\x28\xc0\x27\xc0\x14\xc0\x13\xcc\xa8\x00\x9d\x00\x9c\x00\x3d\x00\x3c\x00\x35\x00\x2f" + "\xc0\x08\xc0\x12\x00\x0a\x01\x00\x01\x7f\xff\x01\x00\x01\x00\x00\x00"), + Op::begin_scope(), + Op::begin_scope(), + Op::string("\x00"), + Op::begin_scope(), + Op::domain(), + Op::end_scope(), + Op::end_scope(), + Op::end_scope(), + Op::string("\x00\x17\x00\x00\x00\x0d\x00\x18\x00\x16\x04\x03\x08\x04\x04\x01\x05\x03\x02\x03\x08\x05\x08\x05" + "\x05\x01\x08\x06\x06\x01\x02\x01\x00\x05\x00\x05\x01\x00\x00\x00\x00\x33\x74\x00\x00\x00\x12\x00" + "\x00\x00\x10\x00\x30\x00\x2e\x02\x68\x32\x05\x68\x32\x2d\x31\x36\x05\x68\x32\x2d\x31\x35\x05\x68" + "\x32\x2d\x31\x34\x08\x73\x70\x64\x79\x2f\x33\x2e\x31\x06\x73\x70\x64\x79\x2f\x33\x08\x68\x74\x74" + "\x70\x2f\x31\x2e\x31\x00\x0b\x00\x02\x01\x00\x00\x33\x00\x26\x00\x24\x00\x1d\x00\x20"), + Op::key(), + Op::string("\x00\x2d\x00\x02\x01\x01\x00\x2b\x00\x09\x08\x03\x04\x03\x03\x03\x02\x03\x01\x00\x0a\x00\x0a\x00" + "\x08\x00\x1d\x00\x17\x00\x18\x00\x19\x00\x15")}; + res.grease_size_ = 0; +#else res.ops_ = { Op::string("\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03"), Op::zero(32), @@ -125,6 +154,7 @@ class TlsHello { Op::grease(3), Op::string("\x00\x01\x00\x00\x15")}; res.grease_size_ = 7; +#endif return res; }(); return result; @@ -157,7 +187,7 @@ class TlsHelloContext { return grease_.size(); } Slice get_domain() const { - return domain_; + return Slice(domain_).substr(0, ProxySecret::MAX_DOMAIN_LENGTH); } private: @@ -225,7 +255,7 @@ class TlsHelloCalcLength { } Result finish() { - if (size_ > 515) { + if (size_ > 514) { on_error(Status::Error("Too long for zero padding")); } if (size_ < 11 + 32) { diff --git a/td/telegram/ConfigManager.cpp b/td/telegram/ConfigManager.cpp index 8649f2de..a3ef41c9 100644 --- a/td/telegram/ConfigManager.cpp +++ b/td/telegram/ConfigManager.cpp @@ -288,7 +288,7 @@ static ActorOwn<> get_simple_config_dns(Slice address, Slice host, Promise get_simple_config_google_dns(Promise promise, const ConfigShared *shared_config, bool is_test, int32 scheduler_id) { - return get_simple_config_dns("www.google.com/resolve", "dns.google.com", std::move(promise), shared_config, is_test, + return get_simple_config_dns("dns.google/resolve", "dns.google", std::move(promise), shared_config, is_test, scheduler_id); } diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 0029cd4c..e518bdfd 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -35,7 +35,6 @@ #include "td/telegram/StickersManager.h" #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" -#include "td/telegram/TopDialogManager.h" #include "td/telegram/UpdatesManager.h" #include "td/telegram/Version.h" @@ -7535,7 +7534,7 @@ void ContactsManager::on_load_user_full_from_database(UserId user_id, string val Dependencies dependencies; dependencies.user_ids.insert(user_id); - td_->messages_manager_->resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); if (user_full->need_phone_number_privacy_exception && is_user_contact(user_id)) { user_full->need_phone_number_privacy_exception = false; @@ -7705,7 +7704,7 @@ void ContactsManager::on_load_chat_full_from_database(ChatId chat_id, string val dependencies.user_ids.insert(participant.user_id); dependencies.user_ids.insert(participant.inviter_user_id); } - td_->messages_manager_->resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); for (auto &participant : chat_full->participants) { get_bot_info_force(participant.user_id); @@ -7778,10 +7777,10 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s Dependencies dependencies; dependencies.channel_ids.insert(channel_id); - td_->messages_manager_->add_dialog_dependencies(dependencies, DialogId(channel_full->linked_channel_id)); + MessagesManager::add_dialog_dependencies(dependencies, DialogId(channel_full->linked_channel_id)); dependencies.chat_ids.insert(channel_full->migrated_from_chat_id); dependencies.user_ids.insert(channel_full->bot_user_ids.begin(), channel_full->bot_user_ids.end()); - td_->messages_manager_->resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); for (auto &user_id : channel_full->bot_user_ids) { get_bot_info_force(user_id); @@ -7894,13 +7893,6 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo if (u->is_deleted) { td_->inline_queries_manager_->remove_recent_inline_bot(user_id, Promise<>()); - /* - DialogId dialog_id(user_id); - for (auto category : {TopDialogCategory::Correspondent, TopDialogCategory::BotPM, TopDialogCategory::BotInline}) { - send_closure(G()->top_dialog_manager(), &TopDialogManager::delete_dialog, category, dialog_id, - get_input_peer_user(user_id, AccessRights::Read)); - } - */ } LOG(DEBUG) << "Update " << user_id << ": need_save_to_database = " << u->need_save_to_database diff --git a/td/telegram/Dependencies.cpp b/td/telegram/Dependencies.cpp new file mode 100644 index 00000000..d4fc9466 --- /dev/null +++ b/td/telegram/Dependencies.cpp @@ -0,0 +1,52 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/Dependencies.h" + +#include "td/telegram/ContactsManager.h" +#include "td/telegram/MessagesManager.h" +#include "td/telegram/Td.h" +#include "td/telegram/WebPagesManager.h" + +#include "td/utils/logging.h" + +namespace td { + +void resolve_dependencies_force(Td *td, const Dependencies &dependencies) { + for (auto user_id : dependencies.user_ids) { + if (user_id.is_valid() && !td->contacts_manager_->have_user_force(user_id)) { + LOG(ERROR) << "Can't find " << user_id; + } + } + for (auto chat_id : dependencies.chat_ids) { + if (chat_id.is_valid() && !td->contacts_manager_->have_chat_force(chat_id)) { + LOG(ERROR) << "Can't find " << chat_id; + } + } + for (auto channel_id : dependencies.channel_ids) { + if (channel_id.is_valid() && !td->contacts_manager_->have_channel_force(channel_id)) { + LOG(ERROR) << "Can't find " << channel_id; + } + } + for (auto secret_chat_id : dependencies.secret_chat_ids) { + if (secret_chat_id.is_valid() && !td->contacts_manager_->have_secret_chat_force(secret_chat_id)) { + LOG(ERROR) << "Can't find " << secret_chat_id; + } + } + for (auto dialog_id : dependencies.dialog_ids) { + if (dialog_id.is_valid() && !td->messages_manager_->have_dialog_force(dialog_id)) { + LOG(ERROR) << "Can't find " << dialog_id; + td->messages_manager_->force_create_dialog(dialog_id, "resolve_dependencies_force"); + } + } + for (auto web_page_id : dependencies.web_page_ids) { + if (web_page_id.is_valid()) { + td->web_pages_manager_->have_web_page_force(web_page_id); + } + } +} + +} // namespace td diff --git a/td/telegram/Dependencies.h b/td/telegram/Dependencies.h index 64cc1adf..50760d31 100644 --- a/td/telegram/Dependencies.h +++ b/td/telegram/Dependencies.h @@ -17,6 +17,8 @@ namespace td { +class Td; + struct Dependencies { std::unordered_set user_ids; std::unordered_set chat_ids; @@ -26,4 +28,6 @@ struct Dependencies { std::unordered_set web_page_ids; }; +void resolve_dependencies_force(Td *td, const Dependencies &dependencies); + } // namespace td diff --git a/td/telegram/Document.cpp b/td/telegram/Document.cpp index df0a2ac3..341bc7d7 100644 --- a/td/telegram/Document.cpp +++ b/td/telegram/Document.cpp @@ -56,6 +56,14 @@ void Document::append_file_ids(const Td *td, vector &file_ids) const { } } +bool operator==(const Document &lhs, const Document &rhs) { + return lhs.type == rhs.type && lhs.file_id == rhs.file_id; +} + +bool operator!=(const Document &lhs, const Document &rhs) { + return !(lhs == rhs); +} + StringBuilder &operator<<(StringBuilder &string_builder, const Document::Type &document_type) { switch (document_type) { case Document::Type::Unknown: diff --git a/td/telegram/Document.h b/td/telegram/Document.h index ad09baa4..2cec9ad9 100644 --- a/td/telegram/Document.h +++ b/td/telegram/Document.h @@ -35,6 +35,10 @@ struct Document { void append_file_ids(const Td *td, vector &file_ids) const; }; +bool operator==(const Document &lhs, const Document &rhs); + +bool operator!=(const Document &lhs, const Document &rhs); + StringBuilder &operator<<(StringBuilder &string_builder, const Document::Type &document_type); StringBuilder &operator<<(StringBuilder &string_builder, const Document &document); diff --git a/td/telegram/Global.cpp b/td/telegram/Global.cpp index 9991f4fb..ea10f23e 100644 --- a/td/telegram/Global.cpp +++ b/td/telegram/Global.cpp @@ -110,7 +110,7 @@ Status Global::init(const TdParameters ¶meters, ActorId td, unique_ptr static void store(const MessageContent *content, StorerT &storer) { CHECK(content != nullptr); @@ -2395,57 +2307,6 @@ void delete_message_content_thumbnail(MessageContent *content, Td *td) { } } -bool is_allowed_media_group_content(MessageContentType content_type) { - switch (content_type) { - case MessageContentType::Photo: - case MessageContentType::Video: - case MessageContentType::ExpiredPhoto: - case MessageContentType::ExpiredVideo: - return true; - case MessageContentType::Animation: - case MessageContentType::Audio: - case MessageContentType::Contact: - case MessageContentType::Document: - case MessageContentType::Game: - case MessageContentType::Invoice: - case MessageContentType::LiveLocation: - case MessageContentType::Location: - case MessageContentType::Sticker: - case MessageContentType::Text: - case MessageContentType::Unsupported: - case MessageContentType::Venue: - case MessageContentType::VideoNote: - case MessageContentType::VoiceNote: - case MessageContentType::ChatCreate: - case MessageContentType::ChatChangeTitle: - case MessageContentType::ChatChangePhoto: - case MessageContentType::ChatDeletePhoto: - case MessageContentType::ChatDeleteHistory: - case MessageContentType::ChatAddUsers: - case MessageContentType::ChatJoinedByLink: - case MessageContentType::ChatDeleteUser: - case MessageContentType::ChatMigrateTo: - case MessageContentType::ChannelCreate: - case MessageContentType::ChannelMigrateFrom: - case MessageContentType::PinMessage: - case MessageContentType::GameScore: - case MessageContentType::ScreenshotTaken: - case MessageContentType::ChatSetTtl: - case MessageContentType::Call: - case MessageContentType::PaymentSuccessful: - case MessageContentType::ContactRegistered: - case MessageContentType::CustomServiceAction: - case MessageContentType::WebsiteConnected: - case MessageContentType::PassportDataSent: - case MessageContentType::PassportDataReceived: - case MessageContentType::Poll: - return false; - default: - UNREACHABLE(); - return false; - } -} - bool can_forward_message_content(const MessageContent *content) { auto content_type = content->get_type(); if (content_type == MessageContentType::Text) { @@ -2461,162 +2322,6 @@ bool can_forward_message_content(const MessageContent *content) { content_type != MessageContentType::ExpiredPhoto && content_type != MessageContentType::ExpiredVideo; } -bool is_secret_message_content(int32 ttl, MessageContentType content_type) { - if (ttl <= 0 || ttl > 60) { - return false; - } - switch (content_type) { - case MessageContentType::Animation: - case MessageContentType::Audio: - case MessageContentType::Photo: - case MessageContentType::Video: - case MessageContentType::VideoNote: - case MessageContentType::VoiceNote: - return true; - case MessageContentType::Contact: - case MessageContentType::Document: - case MessageContentType::Game: - case MessageContentType::Invoice: - case MessageContentType::LiveLocation: - case MessageContentType::Location: - case MessageContentType::Sticker: - case MessageContentType::Text: - case MessageContentType::Unsupported: - case MessageContentType::Venue: - case MessageContentType::ExpiredPhoto: - case MessageContentType::ExpiredVideo: - case MessageContentType::ChatCreate: - case MessageContentType::ChatChangeTitle: - case MessageContentType::ChatChangePhoto: - case MessageContentType::ChatDeletePhoto: - case MessageContentType::ChatDeleteHistory: - case MessageContentType::ChatAddUsers: - case MessageContentType::ChatJoinedByLink: - case MessageContentType::ChatDeleteUser: - case MessageContentType::ChatMigrateTo: - case MessageContentType::ChannelCreate: - case MessageContentType::ChannelMigrateFrom: - case MessageContentType::PinMessage: - case MessageContentType::GameScore: - case MessageContentType::ScreenshotTaken: - case MessageContentType::ChatSetTtl: - case MessageContentType::Call: - case MessageContentType::PaymentSuccessful: - case MessageContentType::ContactRegistered: - case MessageContentType::CustomServiceAction: - case MessageContentType::WebsiteConnected: - case MessageContentType::PassportDataSent: - case MessageContentType::PassportDataReceived: - case MessageContentType::Poll: - return false; - default: - UNREACHABLE(); - return false; - } -} - -bool is_service_message_content(MessageContentType content_type) { - switch (content_type) { - case MessageContentType::Animation: - case MessageContentType::Audio: - case MessageContentType::Contact: - case MessageContentType::Document: - case MessageContentType::Game: - case MessageContentType::Invoice: - case MessageContentType::LiveLocation: - case MessageContentType::Location: - case MessageContentType::Photo: - case MessageContentType::Sticker: - case MessageContentType::Text: - case MessageContentType::Unsupported: - case MessageContentType::Venue: - case MessageContentType::Video: - case MessageContentType::VideoNote: - case MessageContentType::VoiceNote: - case MessageContentType::ExpiredPhoto: - case MessageContentType::ExpiredVideo: - case MessageContentType::Poll: - return false; - case MessageContentType::ChatCreate: - case MessageContentType::ChatChangeTitle: - case MessageContentType::ChatChangePhoto: - case MessageContentType::ChatDeletePhoto: - case MessageContentType::ChatDeleteHistory: - case MessageContentType::ChatAddUsers: - case MessageContentType::ChatJoinedByLink: - case MessageContentType::ChatDeleteUser: - case MessageContentType::ChatMigrateTo: - case MessageContentType::ChannelCreate: - case MessageContentType::ChannelMigrateFrom: - case MessageContentType::PinMessage: - case MessageContentType::GameScore: - case MessageContentType::ScreenshotTaken: - case MessageContentType::ChatSetTtl: - case MessageContentType::Call: - case MessageContentType::PaymentSuccessful: - case MessageContentType::ContactRegistered: - case MessageContentType::CustomServiceAction: - case MessageContentType::WebsiteConnected: - case MessageContentType::PassportDataSent: - case MessageContentType::PassportDataReceived: - return true; - default: - UNREACHABLE(); - return false; - } -} - -bool can_have_message_content_caption(MessageContentType content_type) { - switch (content_type) { - case MessageContentType::Animation: - case MessageContentType::Audio: - case MessageContentType::Document: - case MessageContentType::Photo: - case MessageContentType::Video: - case MessageContentType::VoiceNote: - return true; - case MessageContentType::Contact: - case MessageContentType::Game: - case MessageContentType::Invoice: - case MessageContentType::LiveLocation: - case MessageContentType::Location: - case MessageContentType::Sticker: - case MessageContentType::Text: - case MessageContentType::Unsupported: - case MessageContentType::Venue: - case MessageContentType::VideoNote: - case MessageContentType::ChatCreate: - case MessageContentType::ChatChangeTitle: - case MessageContentType::ChatChangePhoto: - case MessageContentType::ChatDeletePhoto: - case MessageContentType::ChatDeleteHistory: - case MessageContentType::ChatAddUsers: - case MessageContentType::ChatJoinedByLink: - case MessageContentType::ChatDeleteUser: - case MessageContentType::ChatMigrateTo: - case MessageContentType::ChannelCreate: - case MessageContentType::ChannelMigrateFrom: - case MessageContentType::PinMessage: - case MessageContentType::GameScore: - case MessageContentType::ScreenshotTaken: - case MessageContentType::ChatSetTtl: - case MessageContentType::Call: - case MessageContentType::PaymentSuccessful: - case MessageContentType::ContactRegistered: - case MessageContentType::ExpiredPhoto: - case MessageContentType::ExpiredVideo: - case MessageContentType::CustomServiceAction: - case MessageContentType::WebsiteConnected: - case MessageContentType::PassportDataSent: - case MessageContentType::PassportDataReceived: - case MessageContentType::Poll: - return false; - default: - UNREACHABLE(); - return false; - } -} - bool update_opened_message_content(MessageContent *content) { switch (content->get_type()) { case MessageContentType::VideoNote: { @@ -2807,16 +2512,11 @@ bool get_message_content_poll_is_anonymous(const Td *td, const MessageContent *c } } -WebPageId get_message_content_web_page_id(const MessageContent *content) { - if (content->get_type() == MessageContentType::Text) { - return static_cast(content)->web_page_id; - } - return WebPageId(); -} - -void set_message_content_web_page_id(MessageContent *content, WebPageId web_page_id) { +void remove_message_content_web_page(MessageContent *content) { CHECK(content->get_type() == MessageContentType::Text); - static_cast(content)->web_page_id = web_page_id; + auto &web_page_id = static_cast(content)->web_page_id; + CHECK(web_page_id.is_valid()); + web_page_id = WebPageId(); } void set_message_content_poll_answer(Td *td, const MessageContent *content, FullMessageId full_message_id, @@ -3475,10 +3175,10 @@ bool merge_message_content_file_id(Td *td, MessageContent *message_content, File } void register_message_content(Td *td, const MessageContent *content, FullMessageId full_message_id) { - if (full_message_id.get_message_id().is_scheduled()) { - return; - } switch (content->get_type()) { + case MessageContentType::Text: + return td->web_pages_manager_->register_web_page(static_cast(content)->web_page_id, + full_message_id); case MessageContentType::Poll: return td->poll_manager_->register_poll(static_cast(content)->poll_id, full_message_id); default: @@ -3486,11 +3186,37 @@ void register_message_content(Td *td, const MessageContent *content, FullMessage } } -void unregister_message_content(Td *td, const MessageContent *content, FullMessageId full_message_id) { - if (full_message_id.get_message_id().is_scheduled()) { - return; +void reregister_message_content(Td *td, const MessageContent *old_content, const MessageContent *new_content, + FullMessageId full_message_id) { + auto old_content_type = old_content->get_type(); + auto new_content_type = new_content->get_type(); + if (old_content_type == new_content_type) { + switch (old_content_type) { + case MessageContentType::Text: + if (static_cast(old_content)->web_page_id == + static_cast(new_content)->web_page_id) { + return; + } + break; + case MessageContentType::Poll: + if (static_cast(old_content)->poll_id == + static_cast(new_content)->poll_id) { + return; + } + break; + default: + return; + } } + unregister_message_content(td, old_content, full_message_id); + register_message_content(td, new_content, full_message_id); +} + +void unregister_message_content(Td *td, const MessageContent *content, FullMessageId full_message_id) { switch (content->get_type()) { + case MessageContentType::Text: + return td->web_pages_manager_->unregister_web_page(static_cast(content)->web_page_id, + full_message_id); case MessageContentType::Poll: return td->poll_manager_->unregister_poll(static_cast(content)->poll_id, full_message_id); default: @@ -5163,4 +4889,39 @@ StickerSetId add_sticker_set(Td *td, tl_object_ptrstickers_manager_->add_sticker_set(std::move(input_sticker_set)); } +void on_dialog_used(TopDialogCategory category, DialogId dialog_id, int32 date) { + send_closure(G()->top_dialog_manager(), &TopDialogManager::on_dialog_used, category, dialog_id, date); +} + +void update_used_hashtags(Td *td, const MessageContent *content) { + const FormattedText *text = get_message_content_text(content); + if (text == nullptr || text->text.empty()) { + return; + } + + const unsigned char *ptr = Slice(text->text).ubegin(); + const unsigned char *end = Slice(text->text).uend(); + int32 utf16_pos = 0; + for (auto &entity : text->entities) { + if (entity.type != MessageEntity::Type::Hashtag) { + continue; + } + while (utf16_pos < entity.offset && ptr < end) { + utf16_pos += 1 + (ptr[0] >= 0xf0); + ptr = next_utf8_unsafe(ptr, nullptr, "update_used_hashtags"); + } + CHECK(utf16_pos == entity.offset); + auto from = ptr; + + while (utf16_pos < entity.offset + entity.length && ptr < end) { + utf16_pos += 1 + (ptr[0] >= 0xf0); + ptr = next_utf8_unsafe(ptr, nullptr, "update_used_hashtags 2"); + } + CHECK(utf16_pos == entity.offset + entity.length); + auto to = ptr; + + send_closure(td->hashtag_hints_, &HashtagHints::hashtag_used, Slice(from + 1, to).str()); + } +} + } // namespace td diff --git a/td/telegram/MessageContent.h b/td/telegram/MessageContent.h index 765ded13..87b40875 100644 --- a/td/telegram/MessageContent.h +++ b/td/telegram/MessageContent.h @@ -11,14 +11,17 @@ #include "td/telegram/files/FileId.h" #include "td/telegram/FullMessageId.h" #include "td/telegram/logevent/LogEvent.h" +#include "td/telegram/MessageContentType.h" #include "td/telegram/MessageEntity.h" #include "td/telegram/MessageId.h" #include "td/telegram/Photo.h" #include "td/telegram/ReplyMarkup.h" #include "td/telegram/secret_api.h" +#include "td/telegram/SecretInputMedia.h" #include "td/telegram/StickerSetId.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/TopDialogCategory.h" #include "td/telegram/UserId.h" #include "td/telegram/WebPageId.h" @@ -27,7 +30,8 @@ #include "td/utils/buffer.h" #include "td/utils/common.h" #include "td/utils/Status.h" -#include "td/utils/StringBuilder.h" + +#include namespace td { @@ -37,53 +41,6 @@ class Td; class MultiPromiseActor; -enum class MessageContentType : int32 { - None = -1, - Text, - Animation, - Audio, - Document, - Photo, - Sticker, - Video, - VoiceNote, - Contact, - Location, - Venue, - ChatCreate, - ChatChangeTitle, - ChatChangePhoto, - ChatDeletePhoto, - ChatDeleteHistory, - ChatAddUsers, - ChatJoinedByLink, - ChatDeleteUser, - ChatMigrateTo, - ChannelCreate, - ChannelMigrateFrom, - PinMessage, - Game, - GameScore, - ScreenshotTaken, - ChatSetTtl, - Unsupported, - Call, - Invoice, - PaymentSuccessful, - VideoNote, - ContactRegistered, - ExpiredPhoto, - ExpiredVideo, - LiveLocation, - CustomServiceAction, - WebsiteConnected, - PassportDataSent, - PassportDataReceived, - Poll -}; - -StringBuilder &operator<<(StringBuilder &string_builder, MessageContentType content_type); - // Do not forget to update merge_message_contents when one of the inheritors of this class changes class MessageContent { public: @@ -158,16 +115,8 @@ tl_object_ptr get_input_media(const MessageContent *co void delete_message_content_thumbnail(MessageContent *content, Td *td); -bool is_allowed_media_group_content(MessageContentType content_type); - bool can_forward_message_content(const MessageContent *content); -bool is_secret_message_content(int32 ttl, MessageContentType content_type); - -bool is_service_message_content(MessageContentType content_type); - -bool can_have_message_content_caption(MessageContentType content_type); - bool update_opened_message_content(MessageContent *content); int32 get_message_content_index_mask(const MessageContent *content, const Td *td, bool is_secret, bool is_outgoing); @@ -186,9 +135,7 @@ bool get_message_content_poll_is_closed(const Td *td, const MessageContent *cont bool get_message_content_poll_is_anonymous(const Td *td, const MessageContent *content); -WebPageId get_message_content_web_page_id(const MessageContent *content); - -void set_message_content_web_page_id(MessageContent *content, WebPageId web_page_id); +void remove_message_content_web_page(MessageContent *content); void set_message_content_poll_answer(Td *td, const MessageContent *content, FullMessageId full_message_id, vector &&option_ids, Promise &&promise); @@ -208,6 +155,9 @@ bool merge_message_content_file_id(Td *td, MessageContent *message_content, File void register_message_content(Td *td, const MessageContent *content, FullMessageId full_message_id); +void reregister_message_content(Td *td, const MessageContent *old_content, const MessageContent *new_content, + FullMessageId full_message_id); + void unregister_message_content(Td *td, const MessageContent *content, FullMessageId full_message_id); unique_ptr get_secret_message_content( @@ -264,4 +214,8 @@ void on_sent_message_content(Td *td, const MessageContent *content); StickerSetId add_sticker_set(Td *td, tl_object_ptr &&input_sticker_set); +void on_dialog_used(TopDialogCategory category, DialogId dialog_id, int32 date); + +void update_used_hashtags(Td *td, const MessageContent *content); + } // namespace td diff --git a/td/telegram/MessageContentType.cpp b/td/telegram/MessageContentType.cpp new file mode 100644 index 00000000..8d58addb --- /dev/null +++ b/td/telegram/MessageContentType.cpp @@ -0,0 +1,310 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/MessageContentType.h" + +namespace td { + +StringBuilder &operator<<(StringBuilder &string_builder, MessageContentType content_type) { + switch (content_type) { + case MessageContentType::None: + return string_builder << "None"; + case MessageContentType::Animation: + return string_builder << "Animation"; + case MessageContentType::Audio: + return string_builder << "Audio"; + case MessageContentType::Document: + return string_builder << "Document"; + case MessageContentType::ExpiredPhoto: + return string_builder << "ExpiredPhoto"; + case MessageContentType::Photo: + return string_builder << "Photo"; + case MessageContentType::ExpiredVideo: + return string_builder << "ExpiredVideo"; + case MessageContentType::Video: + return string_builder << "Video"; + case MessageContentType::VideoNote: + return string_builder << "VideoNote"; + case MessageContentType::VoiceNote: + return string_builder << "VoiceNote"; + case MessageContentType::Contact: + return string_builder << "Contact"; + case MessageContentType::LiveLocation: + return string_builder << "LiveLocation"; + case MessageContentType::Location: + return string_builder << "Location"; + case MessageContentType::Venue: + return string_builder << "Venue"; + case MessageContentType::Game: + return string_builder << "Game"; + case MessageContentType::Invoice: + return string_builder << "Invoice"; + case MessageContentType::Sticker: + return string_builder << "Sticker"; + case MessageContentType::Text: + return string_builder << "Text"; + case MessageContentType::Unsupported: + return string_builder << "Unsupported"; + case MessageContentType::ChatCreate: + return string_builder << "ChatCreate"; + case MessageContentType::ChatChangeTitle: + return string_builder << "ChatChangeTitle"; + case MessageContentType::ChatChangePhoto: + return string_builder << "ChatChangePhoto"; + case MessageContentType::ChatDeletePhoto: + return string_builder << "ChatDeletePhoto"; + case MessageContentType::ChatDeleteHistory: + return string_builder << "ChatDeleteHistory"; + case MessageContentType::ChatAddUsers: + return string_builder << "ChatAddUsers"; + case MessageContentType::ChatJoinedByLink: + return string_builder << "ChatJoinedByLink"; + case MessageContentType::ChatDeleteUser: + return string_builder << "ChatDeleteUser"; + case MessageContentType::ChatMigrateTo: + return string_builder << "ChatMigrateTo"; + case MessageContentType::ChannelCreate: + return string_builder << "ChannelCreate"; + case MessageContentType::ChannelMigrateFrom: + return string_builder << "ChannelMigrateFrom"; + case MessageContentType::PinMessage: + return string_builder << "PinMessage"; + case MessageContentType::GameScore: + return string_builder << "GameScore"; + case MessageContentType::ScreenshotTaken: + return string_builder << "ScreenshotTaken"; + case MessageContentType::ChatSetTtl: + return string_builder << "ChatSetTtl"; + case MessageContentType::Call: + return string_builder << "Call"; + case MessageContentType::PaymentSuccessful: + return string_builder << "PaymentSuccessful"; + case MessageContentType::ContactRegistered: + return string_builder << "ContactRegistered"; + case MessageContentType::CustomServiceAction: + return string_builder << "CustomServiceAction"; + case MessageContentType::WebsiteConnected: + return string_builder << "WebsiteConnected"; + case MessageContentType::PassportDataSent: + return string_builder << "PassportDataSent"; + case MessageContentType::PassportDataReceived: + return string_builder << "PassportDataReceived"; + case MessageContentType::Poll: + return string_builder << "Poll"; + default: + UNREACHABLE(); + return string_builder; + } +} + +bool is_allowed_media_group_content(MessageContentType content_type) { + switch (content_type) { + case MessageContentType::Photo: + case MessageContentType::Video: + case MessageContentType::ExpiredPhoto: + case MessageContentType::ExpiredVideo: + return true; + case MessageContentType::Animation: + case MessageContentType::Audio: + case MessageContentType::Contact: + case MessageContentType::Document: + case MessageContentType::Game: + case MessageContentType::Invoice: + case MessageContentType::LiveLocation: + case MessageContentType::Location: + case MessageContentType::Sticker: + case MessageContentType::Text: + case MessageContentType::Unsupported: + case MessageContentType::Venue: + case MessageContentType::VideoNote: + case MessageContentType::VoiceNote: + case MessageContentType::ChatCreate: + case MessageContentType::ChatChangeTitle: + case MessageContentType::ChatChangePhoto: + case MessageContentType::ChatDeletePhoto: + case MessageContentType::ChatDeleteHistory: + case MessageContentType::ChatAddUsers: + case MessageContentType::ChatJoinedByLink: + case MessageContentType::ChatDeleteUser: + case MessageContentType::ChatMigrateTo: + case MessageContentType::ChannelCreate: + case MessageContentType::ChannelMigrateFrom: + case MessageContentType::PinMessage: + case MessageContentType::GameScore: + case MessageContentType::ScreenshotTaken: + case MessageContentType::ChatSetTtl: + case MessageContentType::Call: + case MessageContentType::PaymentSuccessful: + case MessageContentType::ContactRegistered: + case MessageContentType::CustomServiceAction: + case MessageContentType::WebsiteConnected: + case MessageContentType::PassportDataSent: + case MessageContentType::PassportDataReceived: + case MessageContentType::Poll: + return false; + default: + UNREACHABLE(); + return false; + } +} + +bool is_secret_message_content(int32 ttl, MessageContentType content_type) { + if (ttl <= 0 || ttl > 60) { + return false; + } + switch (content_type) { + case MessageContentType::Animation: + case MessageContentType::Audio: + case MessageContentType::Photo: + case MessageContentType::Video: + case MessageContentType::VideoNote: + case MessageContentType::VoiceNote: + return true; + case MessageContentType::Contact: + case MessageContentType::Document: + case MessageContentType::Game: + case MessageContentType::Invoice: + case MessageContentType::LiveLocation: + case MessageContentType::Location: + case MessageContentType::Sticker: + case MessageContentType::Text: + case MessageContentType::Unsupported: + case MessageContentType::Venue: + case MessageContentType::ExpiredPhoto: + case MessageContentType::ExpiredVideo: + case MessageContentType::ChatCreate: + case MessageContentType::ChatChangeTitle: + case MessageContentType::ChatChangePhoto: + case MessageContentType::ChatDeletePhoto: + case MessageContentType::ChatDeleteHistory: + case MessageContentType::ChatAddUsers: + case MessageContentType::ChatJoinedByLink: + case MessageContentType::ChatDeleteUser: + case MessageContentType::ChatMigrateTo: + case MessageContentType::ChannelCreate: + case MessageContentType::ChannelMigrateFrom: + case MessageContentType::PinMessage: + case MessageContentType::GameScore: + case MessageContentType::ScreenshotTaken: + case MessageContentType::ChatSetTtl: + case MessageContentType::Call: + case MessageContentType::PaymentSuccessful: + case MessageContentType::ContactRegistered: + case MessageContentType::CustomServiceAction: + case MessageContentType::WebsiteConnected: + case MessageContentType::PassportDataSent: + case MessageContentType::PassportDataReceived: + case MessageContentType::Poll: + return false; + default: + UNREACHABLE(); + return false; + } +} + +bool is_service_message_content(MessageContentType content_type) { + switch (content_type) { + case MessageContentType::Animation: + case MessageContentType::Audio: + case MessageContentType::Contact: + case MessageContentType::Document: + case MessageContentType::Game: + case MessageContentType::Invoice: + case MessageContentType::LiveLocation: + case MessageContentType::Location: + case MessageContentType::Photo: + case MessageContentType::Sticker: + case MessageContentType::Text: + case MessageContentType::Unsupported: + case MessageContentType::Venue: + case MessageContentType::Video: + case MessageContentType::VideoNote: + case MessageContentType::VoiceNote: + case MessageContentType::ExpiredPhoto: + case MessageContentType::ExpiredVideo: + case MessageContentType::Poll: + return false; + case MessageContentType::ChatCreate: + case MessageContentType::ChatChangeTitle: + case MessageContentType::ChatChangePhoto: + case MessageContentType::ChatDeletePhoto: + case MessageContentType::ChatDeleteHistory: + case MessageContentType::ChatAddUsers: + case MessageContentType::ChatJoinedByLink: + case MessageContentType::ChatDeleteUser: + case MessageContentType::ChatMigrateTo: + case MessageContentType::ChannelCreate: + case MessageContentType::ChannelMigrateFrom: + case MessageContentType::PinMessage: + case MessageContentType::GameScore: + case MessageContentType::ScreenshotTaken: + case MessageContentType::ChatSetTtl: + case MessageContentType::Call: + case MessageContentType::PaymentSuccessful: + case MessageContentType::ContactRegistered: + case MessageContentType::CustomServiceAction: + case MessageContentType::WebsiteConnected: + case MessageContentType::PassportDataSent: + case MessageContentType::PassportDataReceived: + return true; + default: + UNREACHABLE(); + return false; + } +} + +bool can_have_message_content_caption(MessageContentType content_type) { + switch (content_type) { + case MessageContentType::Animation: + case MessageContentType::Audio: + case MessageContentType::Document: + case MessageContentType::Photo: + case MessageContentType::Video: + case MessageContentType::VoiceNote: + return true; + case MessageContentType::Contact: + case MessageContentType::Game: + case MessageContentType::Invoice: + case MessageContentType::LiveLocation: + case MessageContentType::Location: + case MessageContentType::Sticker: + case MessageContentType::Text: + case MessageContentType::Unsupported: + case MessageContentType::Venue: + case MessageContentType::VideoNote: + case MessageContentType::ChatCreate: + case MessageContentType::ChatChangeTitle: + case MessageContentType::ChatChangePhoto: + case MessageContentType::ChatDeletePhoto: + case MessageContentType::ChatDeleteHistory: + case MessageContentType::ChatAddUsers: + case MessageContentType::ChatJoinedByLink: + case MessageContentType::ChatDeleteUser: + case MessageContentType::ChatMigrateTo: + case MessageContentType::ChannelCreate: + case MessageContentType::ChannelMigrateFrom: + case MessageContentType::PinMessage: + case MessageContentType::GameScore: + case MessageContentType::ScreenshotTaken: + case MessageContentType::ChatSetTtl: + case MessageContentType::Call: + case MessageContentType::PaymentSuccessful: + case MessageContentType::ContactRegistered: + case MessageContentType::ExpiredPhoto: + case MessageContentType::ExpiredVideo: + case MessageContentType::CustomServiceAction: + case MessageContentType::WebsiteConnected: + case MessageContentType::PassportDataSent: + case MessageContentType::PassportDataReceived: + case MessageContentType::Poll: + return false; + default: + UNREACHABLE(); + return false; + } +} + +} // namespace td diff --git a/td/telegram/MessageContentType.h b/td/telegram/MessageContentType.h new file mode 100644 index 00000000..240b58b9 --- /dev/null +++ b/td/telegram/MessageContentType.h @@ -0,0 +1,69 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/utils/common.h" +#include "td/utils/StringBuilder.h" + +namespace td { + +enum class MessageContentType : int32 { + None = -1, + Text, + Animation, + Audio, + Document, + Photo, + Sticker, + Video, + VoiceNote, + Contact, + Location, + Venue, + ChatCreate, + ChatChangeTitle, + ChatChangePhoto, + ChatDeletePhoto, + ChatDeleteHistory, + ChatAddUsers, + ChatJoinedByLink, + ChatDeleteUser, + ChatMigrateTo, + ChannelCreate, + ChannelMigrateFrom, + PinMessage, + Game, + GameScore, + ScreenshotTaken, + ChatSetTtl, + Unsupported, + Call, + Invoice, + PaymentSuccessful, + VideoNote, + ContactRegistered, + ExpiredPhoto, + ExpiredVideo, + LiveLocation, + CustomServiceAction, + WebsiteConnected, + PassportDataSent, + PassportDataReceived, + Poll +}; + +StringBuilder &operator<<(StringBuilder &string_builder, MessageContentType content_type); + +bool is_allowed_media_group_content(MessageContentType content_type); + +bool is_secret_message_content(int32 ttl, MessageContentType content_type); + +bool is_service_message_content(MessageContentType content_type); + +bool can_have_message_content_caption(MessageContentType content_type); + +} // namespace td diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index db5ca5eb..2cbc9aad 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -20,7 +20,6 @@ #include "td/telegram/files/FileManager.h" #include "td/telegram/files/FileType.h" #include "td/telegram/Global.h" -#include "td/telegram/HashtagHints.h" #include "td/telegram/InlineQueriesManager.h" #include "td/telegram/InputMessageText.h" #include "td/telegram/Location.h" @@ -45,11 +44,10 @@ #include "td/telegram/SequenceDispatcher.h" #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" -#include "td/telegram/TopDialogManager.h" +#include "td/telegram/TopDialogCategory.h" #include "td/telegram/UpdatesManager.h" #include "td/telegram/Version.h" #include "td/telegram/WebPageId.h" -#include "td/telegram/WebPagesManager.h" #include "td/actor/PromiseFuture.h" #include "td/actor/SleepActor.h" @@ -5744,15 +5742,17 @@ void MessagesManager::on_update_some_live_location_viewed(Promise &&promis promise.set_value(Unit()); } -void MessagesManager::on_update_message_content(FullMessageId full_message_id) { +void MessagesManager::on_external_update_message_content(FullMessageId full_message_id) { const Dialog *d = get_dialog(full_message_id.get_dialog_id()); CHECK(d != nullptr); const Message *m = get_message(d, full_message_id.get_message_id()); CHECK(m != nullptr); auto live_location_date = m->is_failed_to_send ? 0 : m->date; send_update_message_content(full_message_id.get_dialog_id(), m->message_id, m->content.get(), live_location_date, - m->is_content_secret, "on_update_message_content"); - on_message_changed(d, m, true, "on_update_message_content"); + m->is_content_secret, "on_external_update_message_content"); + if (m->message_id == d->last_message_id) { + send_update_chat_last_message_impl(d, "on_external_update_message_content"); + } } bool MessagesManager::update_message_contains_unread_mention(Dialog *d, Message *m, bool contains_unread_mention, @@ -11870,59 +11870,37 @@ void MessagesManager::on_update_sent_text_message(int64 random_id, return; } - unregister_message_content(td_, m->content.get(), full_message_id); - bool need_update = false; bool is_content_changed = false; merge_message_contents(td_, m->content.get(), new_content.get(), need_message_changed_warning(m), dialog_id, false, is_content_changed, need_update); if (is_content_changed || need_update) { + reregister_message_content(td_, m->content.get(), new_content.get(), full_message_id); m->content = std::move(new_content); m->is_content_secret = is_secret_message_content(m->ttl, MessageContentType::Text); } - register_message_content(td_, m->content.get(), full_message_id); if (need_update) { send_update_message_content(dialog_id, m->message_id, m->content.get(), m->date, m->is_content_secret, "on_update_sent_text_message"); } } -void MessagesManager::on_update_message_web_page(FullMessageId full_message_id, bool have_web_page) { - waiting_for_web_page_messages_.erase(full_message_id); +void MessagesManager::delete_pending_message_web_page(FullMessageId full_message_id) { auto dialog_id = full_message_id.get_dialog_id(); Dialog *d = get_dialog(dialog_id); - if (d == nullptr) { - LOG(INFO) << "Can't find " << dialog_id; - // dialog can be not yet added - return; - } + CHECK(d != nullptr); Message *m = get_message(d, full_message_id.get_message_id()); - if (m == nullptr) { - // message can be already deleted - return; - } - CHECK(m->date > 0); + CHECK(m != nullptr); MessageContent *content = m->content.get(); - auto old_web_page_id = get_message_content_web_page_id(content); - if (!old_web_page_id.is_valid()) { - // webpage has already been received as empty - LOG_IF(ERROR, have_web_page) << "Receive earlier not received web page"; - return; - } - CHECK(content->get_type() == MessageContentType::Text); + unregister_message_content(td_, content, full_message_id); + remove_message_content_web_page(content); + register_message_content(td_, content, full_message_id); - if (!have_web_page) { - set_message_content_web_page_id(content, WebPageId()); - // don't need to send an update + // don't need to send an updateMessageContent, because the web page was pending - on_message_changed(d, m, true, "on_update_message_web_page"); - return; - } - - send_update_message_content(dialog_id, m->message_id, content, m->date, m->is_content_secret, - "on_update_message_web_page"); + on_message_changed(d, m, false, "delete_pending_message_web_page"); } void MessagesManager::on_get_dialogs(FolderId folder_id, vector> &&dialog_folders, @@ -12322,7 +12300,6 @@ bool MessagesManager::can_unload_message(const Dialog *d, const Message *m) cons CHECK(m->message_id.is_valid()); // don't want to unload messages from opened dialogs // don't want to unload messages to which there are replies in yet unsent messages - // don't want to unload messages with pending web pages // don't want to unload message with active reply markup // don't want to unload pinned message // don't want to unload last edited message, because server can send updateEditChannelMessage again @@ -12332,9 +12309,8 @@ bool MessagesManager::can_unload_message(const Dialog *d, const Message *m) cons return !d->is_opened && m->message_id != d->last_message_id && m->message_id != d->last_database_message_id && !m->message_id.is_yet_unsent() && active_live_location_full_message_ids_.count(full_message_id) == 0 && replied_by_yet_unsent_messages_.count(full_message_id) == 0 && m->edited_content == nullptr && - waiting_for_web_page_messages_.count(full_message_id) == 0 && d->suffix_load_queries_.empty() && - m->message_id != d->reply_markup_message_id && m->message_id != d->pinned_message_id && - m->message_id != d->last_edited_message_id; + d->suffix_load_queries_.empty() && m->message_id != d->reply_markup_message_id && + m->message_id != d->pinned_message_id && m->message_id != d->last_edited_message_id; } void MessagesManager::unload_message(Dialog *d, MessageId message_id) { @@ -12602,10 +12578,9 @@ unique_ptr MessagesManager::do_delete_message(Dialog * return nullptr; } - LOG_CHECK(!d->being_deleted_message_id.is_valid()) << d->being_deleted_message_id << " " << message_id << " " - << d->debug_being_deleted_message_id_source << " " << source; + LOG_CHECK(!d->being_deleted_message_id.is_valid()) + << d->being_deleted_message_id << " " << message_id << " " << source; d->being_deleted_message_id = message_id; - d->debug_being_deleted_message_id_source = source; if (is_debug_message_op_enabled()) { d->debug_message_op.emplace_back(Dialog::MessageOp::Delete, m->message_id, m->content->get_type(), false, @@ -12732,7 +12707,6 @@ unique_ptr MessagesManager::do_delete_message(Dialog * auto result = treap_delete_message(v); d->being_deleted_message_id = MessageId(); - d->debug_being_deleted_message_id_source = ""; if (!only_from_memory) { if (need_get_history && !td_->auth_manager_->is_bot() && have_input_peer(d->dialog_id, AccessRights::Read)) { @@ -12851,6 +12825,8 @@ unique_ptr MessagesManager::do_delete_scheduled_messag cancel_send_deleted_message(d->dialog_id, result.get(), is_permanently_deleted); + unregister_message_content(td_, result->content.get(), {d->dialog_id, message_id}); + return result; } @@ -12894,7 +12870,7 @@ void MessagesManager::load_dialogs(vector dialog_ids, Promise && add_dialog_dependencies(dependencies, dialog_id); } } - resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); for (auto dialog_id : dialog_ids) { if (dialog_id.is_valid()) { @@ -16296,7 +16272,7 @@ void MessagesManager::on_load_active_live_location_full_message_ids_from_databas on_load_active_live_location_messages_finished(); - if (!new_full_message_ids.empty()) { + if (!new_full_message_ids.empty() || old_full_message_ids.size() != active_live_location_full_message_ids_.size()) { save_active_live_locations(); } } @@ -16345,7 +16321,7 @@ void MessagesManager::add_active_live_location(FullMessageId full_message_id) { if (are_active_live_location_messages_loaded_) { save_active_live_locations(); - } else { + } else if (load_active_live_location_messages_queries_.empty()) { // load active live locations and save after that get_active_live_location_messages(Auto()); } @@ -17148,12 +17124,6 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId message->from_database = true; auto old_message = get_message(d, message->message_id); - if (old_message == nullptr) { - auto web_page_id = get_message_content_web_page_id(message->content.get()); - if (web_page_id.is_valid()) { - td_->web_pages_manager_->have_web_page_force(web_page_id); - } - } Message *m = old_message ? old_message : add_message_to_dialog(d, std::move(message), false, &need_update, &need_update_dialog_pos, "on_get_history_from_database"); @@ -17190,7 +17160,7 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId is_first = false; pos++; } - resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); if (!added_new_message && !only_local && dialog_id.get_type() != DialogType::SecretChat) { if (from_the_end) { @@ -17459,10 +17429,6 @@ void MessagesManager::on_get_scheduled_messages_from_database(DialogId dialog_id continue; } - auto web_page_id = get_message_content_web_page_id(message->content.get()); - if (web_page_id.is_valid()) { - td_->web_pages_manager_->have_web_page_force(web_page_id); - } bool need_update = false; Message *m = add_scheduled_message_to_dialog(d, std::move(message), false, &need_update, "on_get_scheduled_messages_from_database"); @@ -17471,7 +17437,7 @@ void MessagesManager::on_get_scheduled_messages_from_database(DialogId dialog_id added_message_ids.push_back(m->message_id); } } - resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); for (auto message_id : added_message_ids) { send_update_new_message(d, get_message(d, message_id)); @@ -18153,40 +18119,6 @@ void MessagesManager::add_dialog_dependencies(Dependencies &dependencies, Dialog } } -void MessagesManager::resolve_dependencies_force(const Dependencies &dependencies) { - for (auto user_id : dependencies.user_ids) { - if (user_id.is_valid() && !td_->contacts_manager_->have_user_force(user_id)) { - LOG(ERROR) << "Can't find " << user_id; - } - } - for (auto chat_id : dependencies.chat_ids) { - if (chat_id.is_valid() && !td_->contacts_manager_->have_chat_force(chat_id)) { - LOG(ERROR) << "Can't find " << chat_id; - } - } - for (auto channel_id : dependencies.channel_ids) { - if (channel_id.is_valid() && !td_->contacts_manager_->have_channel_force(channel_id)) { - LOG(ERROR) << "Can't find " << channel_id; - } - } - for (auto secret_chat_id : dependencies.secret_chat_ids) { - if (secret_chat_id.is_valid() && !td_->contacts_manager_->have_secret_chat_force(secret_chat_id)) { - LOG(ERROR) << "Can't find " << secret_chat_id; - } - } - for (auto dialog_id : dependencies.dialog_ids) { - if (dialog_id.is_valid() && !have_dialog_force(dialog_id)) { - LOG(ERROR) << "Can't find " << dialog_id; - force_create_dialog(dialog_id, "resolve_dependencies_force"); - } - } - for (auto web_page_id : dependencies.web_page_ids) { - if (web_page_id.is_valid()) { - td_->web_pages_manager_->have_web_page_force(web_page_id); - } - } -} - class MessagesManager::SendMessageLogEvent { public: DialogId dialog_id; @@ -25743,7 +25675,7 @@ MessagesManager::Message *MessagesManager::on_get_message_from_database(DialogId Dependencies dependencies; add_message_dependencies(dependencies, d->dialog_id, m.get()); - resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); m->have_previous = false; m->have_next = false; @@ -25876,7 +25808,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq if (message_id.is_server()) { if (d->being_added_message_id.is_valid()) { // if a too new message not from update has failed to preload before being_added_message_id was set, - // then it should fail to load event after it is set and last_new_message_id has changed + // then it should fail to load even after it is set and last_new_message_id has changed max_message_id = d->being_updated_last_new_message_id; } else { max_message_id = d->last_new_message_id; @@ -25944,13 +25876,6 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq return nullptr; } - auto web_page_id = get_message_content_web_page_id(message->content.get()); - if (web_page_id.is_valid() && !td_->web_pages_manager_->have_web_page(web_page_id)) { - waiting_for_web_page_messages_.emplace(dialog_id, message_id); - send_closure(G()->web_pages_manager(), &WebPagesManager::wait_for_pending_web_page, - FullMessageId{dialog_id, message_id}, web_page_id); - } - if (*need_update && message_id <= d->last_new_message_id) { *need_update = false; } @@ -26065,7 +25990,6 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq } MessageId added_pinned_message_id; // TODO remove MessageId preloaded_pinned_message_id; // TODO remove - const char *add_error_reason = ""; if (*need_update) { auto pinned_message_id = get_message_content_pinned_message_id(message->content.get()); added_pinned_message_id = pinned_message_id; @@ -26073,7 +25997,6 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq preloaded_pinned_message_id = pinned_message_id; LOG(INFO) << "Preloaded pinned " << pinned_message_id << " from database"; } - add_error_reason = debug_add_message_to_dialog_fail_reason_; if (d->pinned_message_notification_message_id.is_valid() && have_message_force({dialog_id, d->pinned_message_notification_message_id}, @@ -26085,19 +26008,13 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq // there must be no two recursive calls to add_message_to_dialog LOG_CHECK(!d->being_added_message_id.is_valid()) << d->dialog_id << " " << d->being_added_message_id << " " << message_id << " " << *need_update << " " - << d->debug_being_added_need_update << " " << d->pinned_message_notification_message_id << " " - << preloaded_pinned_message_id << " " << d->debug_preloaded_pinned_message_id << " " - << d->debug_added_pinned_message_id << " " << d->debug_add_message_to_dialog_fail_reason << " " << source; - LOG_CHECK(!d->being_deleted_message_id.is_valid()) << d->being_deleted_message_id << " " << message_id << " " - << d->debug_being_deleted_message_id_source << " " << source; + << d->pinned_message_notification_message_id << " " << preloaded_pinned_message_id << " " << source; + LOG_CHECK(!d->being_deleted_message_id.is_valid()) + << d->being_deleted_message_id << " " << message_id << " " << source; d->being_added_message_id = message_id; d->being_updated_last_new_message_id = d->last_new_message_id; d->being_updated_last_database_message_id = d->last_database_message_id; - d->debug_being_added_need_update = *need_update; - d->debug_preloaded_pinned_message_id = preloaded_pinned_message_id; - d->debug_added_pinned_message_id = added_pinned_message_id; - d->debug_add_message_to_dialog_fail_reason = add_error_reason; if (d->new_secret_chat_notification_id.is_valid()) { remove_new_secret_chat_notification(d, true); @@ -26523,13 +26440,6 @@ MessagesManager::Message *MessagesManager::add_scheduled_message_to_dialog(Dialo return nullptr; } - auto web_page_id = get_message_content_web_page_id(message->content.get()); - if (web_page_id.is_valid() && !td_->web_pages_manager_->have_web_page(web_page_id)) { - waiting_for_web_page_messages_.emplace(dialog_id, message_id); - send_closure(G()->web_pages_manager(), &WebPagesManager::wait_for_pending_web_page, - FullMessageId{dialog_id, message_id}, web_page_id); - } - { Message *m = message->from_database ? get_message(d, message_id) : get_message_force(d, message_id, "add_scheduled_message_to_dialog"); @@ -26572,6 +26482,8 @@ MessagesManager::Message *MessagesManager::add_scheduled_message_to_dialog(Dialo add_message_file_sources(dialog_id, m); + register_message_content(td_, m->content.get(), {dialog_id, m->message_id}); + if (from_update) { update_sent_message_contents(dialog_id, m); update_used_hashtags(dialog_id, m); @@ -26931,7 +26843,8 @@ bool MessagesManager::update_message(Dialog *d, Message *old_message, unique_ptr bool need_send_update = false; bool is_new_available = new_message->content->get_type() != MessageContentType::ChatDeleteHistory; bool replace_legacy = (old_message->legacy_layer != 0 && - (new_message->legacy_layer == 0 || old_message->legacy_layer < new_message->legacy_layer)); + (new_message->legacy_layer == 0 || old_message->legacy_layer < new_message->legacy_layer)) || + old_message->content->get_type() == MessageContentType::Unsupported; if (old_message->date != new_message->date) { if (new_message->date > 0) { LOG_IF(ERROR, !is_scheduled && !new_message->is_outgoing && dialog_id != get_my_dialog_id()) @@ -27181,7 +27094,7 @@ bool MessagesManager::update_message(Dialog *d, Message *old_message, unique_ptr // MessageGame and MessageInvoice reply markup can be generated server side // some forwards retain their reply markup if (content_type != MessageContentType::Game && content_type != MessageContentType::Invoice && - old_message->forward_info == nullptr) { + old_message->forward_info == nullptr && !replace_legacy) { LOG(ERROR) << message_id << " in " << dialog_id << " has received reply markup " << *new_message->reply_markup << ", message content type is " << old_message->content->get_type() << '/' << new_message->content->get_type(); @@ -27332,12 +27245,9 @@ bool MessagesManager::update_message_content(DialogId dialog_id, Message *old_me if (is_content_changed || need_update) { if (is_message_in_dialog) { - unregister_message_content(td_, old_content.get(), {dialog_id, old_message->message_id}); + reregister_message_content(td_, old_content.get(), new_content.get(), {dialog_id, old_message->message_id}); } old_content = std::move(new_content); - if (is_message_in_dialog) { - register_message_content(td_, old_content.get(), {dialog_id, old_message->message_id}); - } update_message_content_file_id_remote(old_content.get(), old_file_id); } else { update_message_content_file_id_remote(old_content.get(), get_message_content_any_file_id(new_content.get())); @@ -28383,7 +28293,7 @@ unique_ptr MessagesManager::parse_dialog(DialogId dialo if (d->draft_message != nullptr) { add_formatted_text_dependencies(dependencies, &d->draft_message->input_message_text.text); } - resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); return d; } @@ -29093,33 +29003,8 @@ void MessagesManager::update_used_hashtags(DialogId dialog_id, const Message *m) m->via_bot_user_id.is_valid() || m->hide_via_bot || m->forward_info != nullptr || m->had_forward_info) { return; } - const FormattedText *text = get_message_content_text(m->content.get()); - if (text == nullptr || text->text.empty()) { - return; - } - const unsigned char *ptr = Slice(text->text).ubegin(); - const unsigned char *end = Slice(text->text).uend(); - int32 utf16_pos = 0; - for (auto &entity : text->entities) { - if (entity.type != MessageEntity::Type::Hashtag) { - continue; - } - while (utf16_pos < entity.offset && ptr < end) { - utf16_pos += 1 + (ptr[0] >= 0xf0); - ptr = next_utf8_unsafe(ptr, nullptr, "update_used_hashtags"); - } - CHECK(utf16_pos == entity.offset); - auto from = ptr; - while (utf16_pos < entity.offset + entity.length && ptr < end) { - utf16_pos += 1 + (ptr[0] >= 0xf0); - ptr = next_utf8_unsafe(ptr, nullptr, "update_used_hashtags 2"); - } - CHECK(utf16_pos == entity.offset + entity.length); - auto to = ptr; - - send_closure(td_->hashtag_hints_, &HashtagHints::hashtag_used, Slice(from + 1, to).str()); - } + ::td::update_used_hashtags(td_, m->content.get()); } void MessagesManager::update_top_dialogs(DialogId dialog_id, const Message *m) { @@ -29133,8 +29018,7 @@ void MessagesManager::update_top_dialogs(DialogId dialog_id, const Message *m) { bool is_forward = m->forward_info != nullptr || m->had_forward_info; if (m->via_bot_user_id.is_valid() && !is_forward) { // forwarded game messages can't be distinguished from sent via bot game messages, so increase rating anyway - send_closure(G()->top_dialog_manager(), &TopDialogManager::on_dialog_used, TopDialogCategory::BotInline, - DialogId(m->via_bot_user_id), m->date); + on_dialog_used(TopDialogCategory::BotInline, DialogId(m->via_bot_user_id), m->date); } if (is_forward) { @@ -29142,7 +29026,7 @@ void MessagesManager::update_top_dialogs(DialogId dialog_id, const Message *m) { if (last_forward_date < m->date) { TopDialogCategory category = dialog_type == DialogType::User ? TopDialogCategory::ForwardUsers : TopDialogCategory::ForwardChats; - send_closure(G()->top_dialog_manager(), &TopDialogManager::on_dialog_used, category, dialog_id, m->date); + on_dialog_used(category, dialog_id, m->date); last_forward_date = m->date; } } @@ -29181,7 +29065,7 @@ void MessagesManager::update_top_dialogs(DialogId dialog_id, const Message *m) { UNREACHABLE(); } if (category != TopDialogCategory::Size) { - send_closure(G()->top_dialog_manager(), &TopDialogManager::on_dialog_used, category, dialog_id, m->date); + on_dialog_used(category, dialog_id, m->date); } } @@ -29271,7 +29155,7 @@ void MessagesManager::on_binlog_events(vector &&events) { Dependencies dependencies; add_dialog_dependencies(dependencies, dialog_id); add_message_dependencies(dependencies, dialog_id, m.get()); - resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); m->content = dup_message_content(td_, dialog_id, m->content.get(), MessageContentDupType::Send); @@ -29299,7 +29183,7 @@ void MessagesManager::on_binlog_events(vector &&events) { Dependencies dependencies; add_dialog_dependencies(dependencies, dialog_id); add_message_dependencies(dependencies, dialog_id, m.get()); - resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); auto bot_user_id = log_event.bot_user_id; if (!td_->contacts_manager_->have_user_force(bot_user_id)) { @@ -29336,7 +29220,7 @@ void MessagesManager::on_binlog_events(vector &&events) { Dependencies dependencies; add_dialog_dependencies(dependencies, dialog_id); add_message_dependencies(dependencies, dialog_id, m.get()); - resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); m->content = dup_message_content(td_, dialog_id, m->content.get(), MessageContentDupType::SendViaBot); @@ -29364,7 +29248,7 @@ void MessagesManager::on_binlog_events(vector &&events) { Dependencies dependencies; add_dialog_dependencies(dependencies, dialog_id); add_message_dependencies(dependencies, dialog_id, m.get()); - resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); auto result_message = continue_send_message(dialog_id, std::move(m), event.id_); if (result_message != nullptr) { @@ -29391,7 +29275,7 @@ void MessagesManager::on_binlog_events(vector &&events) { for (auto &m : messages) { add_message_dependencies(dependencies, to_dialog_id, m.get()); } - resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); Dialog *to_dialog = get_dialog_force(to_dialog_id); if (to_dialog == nullptr) { @@ -29819,7 +29703,7 @@ void MessagesManager::on_binlog_events(vector &&events) { auto dialog_id = log_event.dialog_id_; Dependencies dependencies; add_dialog_dependencies(dependencies, dialog_id); - resolve_dependencies_force(dependencies); + resolve_dependencies_force(td_, dependencies); get_dialog_force(dialog_id); // load it if exists diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 92d7cec6..53e4dfca 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -24,7 +24,7 @@ #include "td/telegram/FolderId.h" #include "td/telegram/FullMessageId.h" #include "td/telegram/Global.h" -#include "td/telegram/MessageContent.h" +#include "td/telegram/MessageContentType.h" #include "td/telegram/MessageEntity.h" #include "td/telegram/MessageId.h" #include "td/telegram/MessagesDb.h" @@ -73,11 +73,15 @@ namespace td { struct BinlogEvent; -class Td; +class DraftMessage; + +struct InputMessageContent; + +class MessageContent; class MultiSequenceDispatcher; -class DraftMessage; +class Td; class dummyUpdate : public telegram_api::Update { public: @@ -266,7 +270,7 @@ class MessagesManager : public Actor { void on_update_sent_text_message(int64 random_id, tl_object_ptr message_media, vector> &&entities); - void on_update_message_web_page(FullMessageId full_message_id, bool have_web_page); + void delete_pending_message_web_page(FullMessageId full_message_id); void on_get_dialogs(FolderId folder_id, vector> &&dialog_folders, int32 total_count, vector> &&messages, @@ -315,7 +319,7 @@ class MessagesManager : public Actor { void on_update_some_live_location_viewed(Promise &&promise); - void on_update_message_content(FullMessageId full_message_id); + void on_external_update_message_content(FullMessageId full_message_id); void on_read_channel_inbox(ChannelId channel_id, MessageId max_message_id, int32 server_unread_count, int32 pts, const char *source); @@ -824,8 +828,6 @@ class MessagesManager : public Actor { static void add_dialog_dependencies(Dependencies &dependencies, DialogId dialog_id); - void resolve_dependencies_force(const Dependencies &dependencies); - ActorOwn sequence_dispatcher_; private: @@ -1071,11 +1073,6 @@ class MessagesManager : public Actor { MessageId being_updated_last_new_message_id; MessageId being_updated_last_database_message_id; MessageId being_deleted_message_id; - const char *debug_being_deleted_message_id_source = ""; - bool debug_being_added_need_update = false; // TODO remove - MessageId debug_preloaded_pinned_message_id; // TODO remove - MessageId debug_added_pinned_message_id; // TODO remove - const char *debug_add_message_to_dialog_fail_reason = ""; NotificationGroupInfo message_notification_group; NotificationGroupInfo mention_notification_group; @@ -2626,8 +2623,6 @@ class MessagesManager : public Actor { std::unordered_map replied_by_yet_unsent_messages_; - std::unordered_set waiting_for_web_page_messages_; - struct ActiveDialogAction { UserId user_id; int32 action_id; diff --git a/td/telegram/NotificationManager.cpp b/td/telegram/NotificationManager.cpp index 6153b875..bc572f43 100644 --- a/td/telegram/NotificationManager.cpp +++ b/td/telegram/NotificationManager.cpp @@ -17,6 +17,7 @@ #include "td/telegram/DocumentsManager.h" #include "td/telegram/files/FileManager.h" #include "td/telegram/Global.h" +#include "td/telegram/logevent/LogEvent.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/misc.h" #include "td/telegram/net/ConnectionCreator.h" diff --git a/td/telegram/PollManager.cpp b/td/telegram/PollManager.cpp index 544e3d86..26792f5a 100644 --- a/td/telegram/PollManager.cpp +++ b/td/telegram/PollManager.cpp @@ -304,7 +304,7 @@ void PollManager::notify_on_poll_update(PollId poll_id) { } for (auto full_message_id : it->second) { - td_->messages_manager_->on_update_message_content(full_message_id); + td_->messages_manager_->on_external_update_message_content(full_message_id); } } @@ -572,7 +572,9 @@ PollId PollManager::create_poll(string &&question, vector &&options, boo void PollManager::register_poll(PollId poll_id, FullMessageId full_message_id) { CHECK(have_poll(poll_id)); - CHECK(!full_message_id.get_message_id().is_scheduled()); + if (full_message_id.get_message_id().is_scheduled()) { + return; + } if (!full_message_id.get_message_id().is_server()) { return; } @@ -586,7 +588,9 @@ void PollManager::register_poll(PollId poll_id, FullMessageId full_message_id) { void PollManager::unregister_poll(PollId poll_id, FullMessageId full_message_id) { CHECK(have_poll(poll_id)); - CHECK(!full_message_id.get_message_id().is_scheduled()); + if (full_message_id.get_message_id().is_scheduled()) { + return; + } if (!full_message_id.get_message_id().is_server()) { return; } @@ -1274,6 +1278,8 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptris_closed) { bool is_correct = (poll_result->flags_ & telegram_api::pollAnswerVoters::CORRECT_MASK) != 0; if (is_correct) { if (correct_option_id != -1) { @@ -1409,8 +1415,8 @@ void PollManager::on_binlog_events(vector &&events) { auto dialog_id = log_event.full_message_id_.get_dialog_id(); Dependencies dependencies; - td_->messages_manager_->add_dialog_dependencies(dependencies, dialog_id); - td_->messages_manager_->resolve_dependencies_force(dependencies); + MessagesManager::add_dialog_dependencies(dependencies, dialog_id); + resolve_dependencies_force(td_, dependencies); do_set_poll_answer(log_event.poll_id_, log_event.full_message_id_, std::move(log_event.options_), event.id_, Auto()); @@ -1428,8 +1434,8 @@ void PollManager::on_binlog_events(vector &&events) { auto dialog_id = log_event.full_message_id_.get_dialog_id(); Dependencies dependencies; - td_->messages_manager_->add_dialog_dependencies(dependencies, dialog_id); - td_->messages_manager_->resolve_dependencies_force(dependencies); + MessagesManager::add_dialog_dependencies(dependencies, dialog_id); + resolve_dependencies_force(td_, dependencies); do_stop_poll(log_event.poll_id_, log_event.full_message_id_, nullptr, event.id_, Auto()); break; diff --git a/td/telegram/PollManager.h b/td/telegram/PollManager.h index db2ac4f0..36ef5c06 100644 --- a/td/telegram/PollManager.h +++ b/td/telegram/PollManager.h @@ -18,11 +18,13 @@ #include "td/actor/PromiseFuture.h" #include "td/actor/Timeout.h" +#include "td/utils/buffer.h" #include "td/utils/common.h" #include "td/utils/Status.h" #include #include +#include namespace td { diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 97ce9ac4..843ac9f7 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -2022,7 +2022,8 @@ StickerSetId StickersManager::on_get_messages_sticker_set(StickerSetId sticker_s } } if (static_cast(s->sticker_ids.size()) != s->sticker_count) { - LOG(ERROR) << "Wrong sticker set size specified in " << set_id << " from " << source; + LOG(ERROR) << "Wrong sticker set size " << s->sticker_count << " instead of " << s->sticker_ids.size() + << " specified in " << set_id << " from " << source; s->sticker_count = static_cast(s->sticker_ids.size()); } diff --git a/td/telegram/StickersManager.hpp b/td/telegram/StickersManager.hpp index 2070a9c1..f56cf529 100644 --- a/td/telegram/StickersManager.hpp +++ b/td/telegram/StickersManager.hpp @@ -229,25 +229,25 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser sticker_set->is_masks = is_masks; sticker_set->is_animated = is_animated; - short_name_to_sticker_set_id_.emplace(clean_username(sticker_set->short_name), StickerSetId(sticker_set_id)); + short_name_to_sticker_set_id_.emplace(clean_username(sticker_set->short_name), sticker_set->id); on_update_sticker_set(sticker_set, is_installed, is_archived, false, true); } else { if (sticker_set->title != title) { - LOG(INFO) << "Title of " << sticker_set_id << " has changed"; + LOG(INFO) << "Title of " << sticker_set->id << " has changed"; } if (sticker_set->short_name != short_name) { - LOG(ERROR) << "Short name of " << sticker_set_id << " has changed from \"" << short_name << "\" to \"" + LOG(ERROR) << "Short name of " << sticker_set->id << " has changed from \"" << short_name << "\" to \"" << sticker_set->short_name << "\""; } if (sticker_set->sticker_count != sticker_count || sticker_set->hash != hash) { sticker_set->is_loaded = false; } if (sticker_set->is_animated != is_animated) { - LOG(ERROR) << "Is animated of " << sticker_set_id << " has changed from \"" << is_animated << "\" to \"" + LOG(ERROR) << "Is animated of " << sticker_set->id << " has changed from \"" << is_animated << "\" to \"" << sticker_set->is_animated << "\""; } if (sticker_set->is_masks != is_masks) { - LOG(ERROR) << "Is masks of " << sticker_set_id << " has changed from \"" << is_masks << "\" to \"" + LOG(ERROR) << "Is masks of " << sticker_set->id << " has changed from \"" << is_masks << "\" to \"" << sticker_set->is_masks << "\""; } } diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 19f5f167..eafec324 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -80,6 +80,7 @@ #include "td/telegram/StickersManager.h" #include "td/telegram/StorageManager.h" #include "td/telegram/TdDb.h" +#include "td/telegram/TopDialogCategory.h" #include "td/telegram/TopDialogManager.h" #include "td/telegram/UpdatesManager.h" #include "td/telegram/VideoNotesManager.h" @@ -4407,7 +4408,7 @@ Status Td::init(DbKey key) { // that RequestKey was already sent. // // 3. During replay of binlog some queries may be sent to other actors. They shouldn't process such events before all - // their binlog events are processed. So actor may receive some old queries. It must be in it's actual state in + // their binlog events are processed. So actor may receive some old queries. It must be in its actual state in // orded to handle them properly. // // -- Use send_closure_later, so actors don't even start process binlog events, before all binlog events are sent diff --git a/td/telegram/TopDialogCategory.h b/td/telegram/TopDialogCategory.h new file mode 100644 index 00000000..f7f08524 --- /dev/null +++ b/td/telegram/TopDialogCategory.h @@ -0,0 +1,48 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/td_api.h" + +#include "td/utils/common.h" + +namespace td { + +enum class TopDialogCategory : int32 { + Correspondent, + BotPM, + BotInline, + Group, + Channel, + Call, + ForwardUsers, + ForwardChats, + Size +}; + +inline TopDialogCategory top_dialog_category_from_td_api(const td_api::TopChatCategory &category) { + switch (category.get_id()) { + case td_api::topChatCategoryUsers::ID: + return TopDialogCategory::Correspondent; + case td_api::topChatCategoryBots::ID: + return TopDialogCategory::BotPM; + case td_api::topChatCategoryInlineBots::ID: + return TopDialogCategory::BotInline; + case td_api::topChatCategoryGroups::ID: + return TopDialogCategory::Group; + case td_api::topChatCategoryChannels::ID: + return TopDialogCategory::Channel; + case td_api::topChatCategoryCalls::ID: + return TopDialogCategory::Call; + case td_api::topChatCategoryForwardChats::ID: + return TopDialogCategory::ForwardUsers; + default: + UNREACHABLE(); + } +} + +} // namespace td diff --git a/td/telegram/TopDialogManager.h b/td/telegram/TopDialogManager.h index e861896e..de2602aa 100644 --- a/td/telegram/TopDialogManager.h +++ b/td/telegram/TopDialogManager.h @@ -9,11 +9,10 @@ #include "td/actor/actor.h" #include "td/actor/PromiseFuture.h" -#include "td/telegram/td_api.h" -#include "td/telegram/telegram_api.h" - #include "td/telegram/DialogId.h" #include "td/telegram/net/NetQuery.h" +#include "td/telegram/telegram_api.h" +#include "td/telegram/TopDialogCategory.h" #include "td/utils/common.h" #include "td/utils/Time.h" @@ -23,39 +22,6 @@ namespace td { -enum class TopDialogCategory : int32 { - Correspondent, - BotPM, - BotInline, - Group, - Channel, - Call, - ForwardUsers, - ForwardChats, - Size -}; - -inline TopDialogCategory top_dialog_category_from_td_api(const td_api::TopChatCategory &category) { - switch (category.get_id()) { - case td_api::topChatCategoryUsers::ID: - return TopDialogCategory::Correspondent; - case td_api::topChatCategoryBots::ID: - return TopDialogCategory::BotPM; - case td_api::topChatCategoryInlineBots::ID: - return TopDialogCategory::BotInline; - case td_api::topChatCategoryGroups::ID: - return TopDialogCategory::Group; - case td_api::topChatCategoryChannels::ID: - return TopDialogCategory::Channel; - case td_api::topChatCategoryCalls::ID: - return TopDialogCategory::Call; - case td_api::topChatCategoryForwardChats::ID: - return TopDialogCategory::ForwardUsers; - default: - UNREACHABLE(); - } -} - class TopDialogManager : public NetQueryCallback { public: explicit TopDialogManager(ActorShared<> parent) : parent_(std::move(parent)) { diff --git a/td/telegram/VideosManager.cpp b/td/telegram/VideosManager.cpp index 6de27ca7..a614cf04 100644 --- a/td/telegram/VideosManager.cpp +++ b/td/telegram/VideosManager.cpp @@ -10,7 +10,6 @@ #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" -#include "td/telegram/AuthManager.h" #include "td/telegram/files/FileManager.h" #include "td/telegram/Td.h" diff --git a/td/telegram/WebPagesManager.cpp b/td/telegram/WebPagesManager.cpp index ba2dd48a..30526c84 100644 --- a/td/telegram/WebPagesManager.cpp +++ b/td/telegram/WebPagesManager.cpp @@ -10,6 +10,7 @@ #include "td/telegram/AnimationsManager.h" #include "td/telegram/AudiosManager.h" +#include "td/telegram/AuthManager.h" #include "td/telegram/Document.h" #include "td/telegram/Document.hpp" #include "td/telegram/DocumentsManager.h" @@ -361,6 +362,16 @@ class WebPagesManager::WebPage { instant_view.is_v2 = true; } } + + friend bool operator==(const WebPage &lhs, const WebPage &rhs) { + return lhs.url == rhs.url && lhs.display_url == rhs.display_url && lhs.type == rhs.type && + lhs.site_name == rhs.site_name && lhs.title == rhs.title && lhs.description == rhs.description && + lhs.photo == rhs.photo && lhs.type == rhs.type && lhs.embed_url == rhs.embed_url && + lhs.embed_type == rhs.embed_type && lhs.embed_dimensions == rhs.embed_dimensions && + lhs.duration == rhs.duration && lhs.author == rhs.author && lhs.document == rhs.document && + lhs.documents == rhs.documents && lhs.instant_view.is_empty == rhs.instant_view.is_empty && + lhs.instant_view.is_v2 == rhs.instant_view.is_v2; + } }; WebPagesManager::WebPagesManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { @@ -402,20 +413,10 @@ WebPageId WebPagesManager::on_get_web_page(tl_object_ptr web_pages_.erase(web_page_id); } - update_messages_content(web_page_id, false); - if (!G()->parameters().use_message_db) { - // update_messages_content(web_page_id, false); - } else { + on_web_page_changed(web_page_id, false); + if (G()->parameters().use_message_db) { LOG(INFO) << "Delete " << web_page_id << " from database"; - G()->td_db()->get_sqlite_pmc()->erase(get_web_page_database_key(web_page_id), Auto() - /* - PromiseCreator::lambda([web_page_id](Result<> result) { - if (result.is_ok()) { - send_closure(G()->web_pages_manager(), &WebPagesManager::update_messages_content, web_page_id, false); - } - }) - */ - ); + G()->td_db()->get_sqlite_pmc()->erase(get_web_page_database_key(web_page_id), Auto()); G()->td_db()->get_sqlite_pmc()->erase(get_web_page_instant_view_database_key(web_page_id), Auto()); } @@ -518,7 +519,12 @@ void WebPagesManager::update_web_page(unique_ptr web_page, WebPageId we auto &page = web_pages_[web_page_id]; auto old_file_ids = get_web_page_file_ids(page.get()); WebPageInstantView old_instant_view; + bool is_changed = true; if (page != nullptr) { + if (*page == *web_page) { + is_changed = false; + } + old_instant_view = std::move(page->instant_view); web_page->logevent_id = page->logevent_id; } else { @@ -540,9 +546,9 @@ void WebPagesManager::update_web_page(unique_ptr web_page, WebPageId we on_get_web_page_by_url(page->url, web_page_id, from_database); - update_messages_content(web_page_id, true); + if (is_changed && !from_database) { + on_web_page_changed(web_page_id, true); - if (!from_database) { save_web_page(page.get(), web_page_id, from_binlog); } } @@ -626,15 +632,17 @@ bool WebPagesManager::need_use_old_instant_view(const WebPageInstantView &new_in } void WebPagesManager::on_get_web_page_by_url(const string &url, WebPageId web_page_id, bool from_database) { + auto &cached_web_page_id = url_to_web_page_id_[url]; if (!from_database && G()->parameters().use_message_db) { if (web_page_id.is_valid()) { - G()->td_db()->get_sqlite_pmc()->set(get_web_page_url_database_key(url), to_string(web_page_id.get()), Auto()); + if (cached_web_page_id != web_page_id) { //not already saved + G()->td_db()->get_sqlite_pmc()->set(get_web_page_url_database_key(url), to_string(web_page_id.get()), Auto()); + } } else { G()->td_db()->get_sqlite_pmc()->erase(get_web_page_url_database_key(url), Auto()); } } - auto &cached_web_page_id = url_to_web_page_id_[url]; if (cached_web_page_id.is_valid() && web_page_id.is_valid() && web_page_id != cached_web_page_id) { LOG(ERROR) << "Url \"" << url << "\" preview is changed from " << cached_web_page_id << " to " << web_page_id; } @@ -642,10 +650,37 @@ void WebPagesManager::on_get_web_page_by_url(const string &url, WebPageId web_pa cached_web_page_id = web_page_id; } -void WebPagesManager::wait_for_pending_web_page(FullMessageId full_message_id, WebPageId web_page_id) { - LOG(INFO) << "Waiting for " << web_page_id << " needed in " << full_message_id; - pending_web_pages_[web_page_id].emplace(full_message_id); - pending_web_pages_timeout_.add_timeout_in(web_page_id.get(), 1.0); +void WebPagesManager::register_web_page(WebPageId web_page_id, FullMessageId full_message_id) { + if (!web_page_id.is_valid()) { + return; + } + + LOG(INFO) << "Register " << web_page_id << " from " << full_message_id; + bool is_inserted = web_page_messages_[web_page_id].insert(full_message_id).second; + CHECK(is_inserted); + + if (!td_->auth_manager_->is_bot() && !have_web_page_force(web_page_id)) { + LOG(INFO) << "Waiting for " << web_page_id << " needed in " << full_message_id; + pending_web_pages_timeout_.add_timeout_in(web_page_id.get(), 1.0); + } +} + +void WebPagesManager::unregister_web_page(WebPageId web_page_id, FullMessageId full_message_id) { + if (!web_page_id.is_valid()) { + return; + } + + LOG(INFO) << "Unregister " << web_page_id << " from " << full_message_id; + auto &message_ids = web_page_messages_[web_page_id]; + auto is_deleted = message_ids.erase(full_message_id); + CHECK(is_deleted); + + if (message_ids.empty()) { + web_page_messages_.erase(web_page_id); + if (pending_get_web_pages_.count(web_page_id) == 0) { + pending_web_pages_timeout_.cancel_timeout(web_page_id.get()); + } + } } void WebPagesManager::on_get_web_page_preview_success(int64 request_id, const string &url, @@ -672,7 +707,6 @@ void WebPagesManager::on_get_web_page_preview_success(int64 request_id, const st if (web_page_id.is_valid() && !have_web_page(web_page_id)) { pending_get_web_pages_[web_page_id].emplace(request_id, std::make_pair(url, std::move(promise))); // TODO MultiPromise ? - pending_web_pages_timeout_.add_timeout_in(web_page_id.get(), 1.0); return; } @@ -1142,15 +1176,26 @@ tl_object_ptr WebPagesManager::get_web_page_instant_ web_page_instant_view->is_rtl, web_page_instant_view->is_full); } -void WebPagesManager::update_messages_content(WebPageId web_page_id, bool have_web_page) { - LOG(INFO) << "Update messages awaiting " << web_page_id; - auto it = pending_web_pages_.find(web_page_id); - if (it != pending_web_pages_.end()) { - auto full_message_ids = std::move(it->second); - pending_web_pages_.erase(it); +void WebPagesManager::on_web_page_changed(WebPageId web_page_id, bool have_web_page) { + LOG(INFO) << "Updated " << web_page_id; + auto it = web_page_messages_.find(web_page_id); + if (it != web_page_messages_.end()) { + vector full_message_ids; + for (auto full_message_id : it->second) { + full_message_ids.push_back(full_message_id); + } + CHECK(!full_message_ids.empty()); for (auto full_message_id : full_message_ids) { - send_closure_later(G()->messages_manager(), &MessagesManager::on_update_message_web_page, full_message_id, - have_web_page); + if (!have_web_page) { + td_->messages_manager_->delete_pending_message_web_page(full_message_id); + } else { + td_->messages_manager_->on_external_update_message_content(full_message_id); + } + } + if (have_web_page) { + CHECK(web_page_messages_[web_page_id].size() == full_message_ids.size()); + } else { + CHECK(web_page_messages_.count(web_page_id) == 0); } } auto get_it = pending_get_web_pages_.find(web_page_id); @@ -1187,9 +1232,13 @@ void WebPagesManager::on_pending_web_page_timeout_callback(void *web_pages_manag } void WebPagesManager::on_pending_web_page_timeout(WebPageId web_page_id) { + if (have_web_page(web_page_id)) { + return; + } + int32 count = 0; - auto it = pending_web_pages_.find(web_page_id); - if (it != pending_web_pages_.end()) { + auto it = web_page_messages_.find(web_page_id); + if (it != web_page_messages_.end()) { vector full_message_ids; for (auto full_message_id : it->second) { full_message_ids.push_back(full_message_id); @@ -1209,7 +1258,7 @@ void WebPagesManager::on_pending_web_page_timeout(WebPageId web_page_id) { } } if (count == 0) { - LOG(WARNING) << "Have no messages waiting for " << web_page_id; + LOG(WARNING) << "Have no messages and requests waiting for " << web_page_id; } } diff --git a/td/telegram/WebPagesManager.h b/td/telegram/WebPagesManager.h index 05d2680a..6ee613f2 100644 --- a/td/telegram/WebPagesManager.h +++ b/td/telegram/WebPagesManager.h @@ -13,7 +13,7 @@ #include "td/telegram/files/FileId.h" #include "td/telegram/files/FileSourceId.h" #include "td/telegram/FullMessageId.h" -#include "td/telegram/Photo.h" +#include "td/telegram/SecretInputMedia.h" #include "td/telegram/WebPageId.h" #include "td/actor/actor.h" @@ -47,7 +47,9 @@ class WebPagesManager : public Actor { void on_get_web_page_by_url(const string &url, WebPageId web_page_id, bool from_database); - void wait_for_pending_web_page(FullMessageId full_message_id, WebPageId web_page_id); + void register_web_page(WebPageId web_page_id, FullMessageId full_message_id); + + void unregister_web_page(WebPageId web_page_id, FullMessageId full_message_id); bool have_web_page(WebPageId web_page_id) const; @@ -111,7 +113,7 @@ class WebPagesManager : public Actor { static bool need_use_old_instant_view(const WebPageInstantView &new_instant_view, const WebPageInstantView &old_instant_view); - void update_messages_content(WebPageId web_page_id, bool have_web_page); + void on_web_page_changed(WebPageId web_page_id, bool have_web_page); const WebPage *get_web_page(WebPageId web_page_id) const; @@ -181,7 +183,8 @@ class WebPagesManager : public Actor { }; std::unordered_map load_web_page_instant_view_queries_; - std::unordered_map, WebPageIdHash> pending_web_pages_; + std::unordered_map, WebPageIdHash> web_page_messages_; + std::unordered_map>>, WebPageIdHash> pending_get_web_pages_; diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index c8fb0e1e..9a5e07d2 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -3522,7 +3522,8 @@ void FileManager::on_error_impl(FileNodePtr node, Query::Type type, bool was_act node->set_generate_location(nullptr); } - if (status.message() == "FILE_ID_INVALID" && FileView(node).may_reload_photo()) { + if ((status.message() == "FILE_ID_INVALID" || status.message() == "LOCATION_INVALID") && + FileView(node).may_reload_photo()) { node->need_reload_photo_ = true; run_download(node); return; diff --git a/td/telegram/net/Proxy.cpp b/td/telegram/net/Proxy.cpp index db68882f..b20c9478 100644 --- a/td/telegram/net/Proxy.cpp +++ b/td/telegram/net/Proxy.cpp @@ -17,6 +17,9 @@ Result Proxy::from_td_api(string server, int port, td_api::ProxyType *pro if (server.empty()) { return Status::Error(400, "Server name can't be empty"); } + if (server.size() > 255) { + return Status::Error(400, "Server name is too long"); + } if (port <= 0 || port > 65535) { return Status::Error(400, "Wrong port number"); } diff --git a/td/telegram/net/Proxy.h b/td/telegram/net/Proxy.h index a9dca8a4..947930c3 100644 --- a/td/telegram/net/Proxy.h +++ b/td/telegram/net/Proxy.h @@ -134,7 +134,7 @@ class Proxy { } else if (type_ == Proxy::Type::Mtproto) { parse(server_, parser); parse(port_, parser); - secret_ = mtproto::ProxySecret::from_link(parser.template fetch_string()).move_as_ok(); + secret_ = mtproto::ProxySecret::from_link(parser.template fetch_string(), true).move_as_ok(); } else { CHECK(type_ == Proxy::Type::None); } diff --git a/tdactor/CMakeLists.txt b/tdactor/CMakeLists.txt index 7583c1e5..58f0fb0a 100644 --- a/tdactor/CMakeLists.txt +++ b/tdactor/CMakeLists.txt @@ -1,5 +1,9 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +if (NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") +endif() + #SOURCE SETS set(TDACTOR_SOURCE td/actor/impl/ConcurrentScheduler.cpp @@ -50,8 +54,6 @@ if (NOT CMAKE_CROSSCOMPILING) endif() install(TARGETS tdactor EXPORT TdTargets - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" ) diff --git a/tddb/CMakeLists.txt b/tddb/CMakeLists.txt index 34a47c58..9a80b6cf 100644 --- a/tddb/CMakeLists.txt +++ b/tddb/CMakeLists.txt @@ -1,5 +1,9 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +if (NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") +endif() + #SOURCE SETS set(TDDB_SOURCE td/db/binlog/Binlog.cpp @@ -50,8 +54,6 @@ if (NOT CMAKE_CROSSCOMPILING) endif() install(TARGETS tddb EXPORT TdTargets - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" ) diff --git a/tddb/td/db/SqliteDb.cpp b/tddb/td/db/SqliteDb.cpp index f17956da..6e5de16c 100644 --- a/tddb/td/db/SqliteDb.cpp +++ b/tddb/td/db/SqliteDb.cpp @@ -159,8 +159,8 @@ Status SqliteDb::commit_transaction() { return Status::OK(); } -bool SqliteDb::is_encrypted() { - return true; +Status SqliteDb::check_encryption() { + return Status::OK(); } Result SqliteDb::open_with_key(CSlice path, const DbKey &db_key) { diff --git a/tddb/td/db/SqliteDb.h b/tddb/td/db/SqliteDb.h index 057a5e4a..9f7955bd 100644 --- a/tddb/td/db/SqliteDb.h +++ b/tddb/td/db/SqliteDb.h @@ -81,7 +81,7 @@ class SqliteDb { } std::shared_ptr raw_; - bool is_encrypted(); + Status check_encryption(); }; } // namespace td diff --git a/tdnet/CMakeLists.txt b/tdnet/CMakeLists.txt index bebbe9dd..ca7e33bf 100644 --- a/tdnet/CMakeLists.txt +++ b/tdnet/CMakeLists.txt @@ -1,5 +1,9 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +if (NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") +endif() + if (NOT OPENSSL_FOUND) find_package(OpenSSL REQUIRED) find_package(ZLIB REQUIRED) @@ -59,8 +63,6 @@ if (WIN32) endif() install(TARGETS tdnet EXPORT TdTargets - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" ) diff --git a/tdnet/td/net/GetHostByNameActor.cpp b/tdnet/td/net/GetHostByNameActor.cpp index 8f331c7a..5c949db9 100644 --- a/tdnet/td/net/GetHostByNameActor.cpp +++ b/tdnet/td/net/GetHostByNameActor.cpp @@ -53,8 +53,8 @@ class GoogleDnsResolver : public Actor { }); wget_ = create_actor( "GoogleDnsResolver", std::move(wget_promise), - PSTRING() << "https://www.google.com/resolve?name=" << url_encode(host_) << "&type=" << (prefer_ipv6_ ? 28 : 1), - std::vector>({{"Host", "dns.google.com"}}), timeout, ttl, prefer_ipv6_, + PSTRING() << "https://dns.google/resolve?name=" << url_encode(host_) << "&type=" << (prefer_ipv6_ ? 28 : 1), + std::vector>({{"Host", "dns.google"}}), timeout, ttl, prefer_ipv6_, SslStream::VerifyPeer::Off); } diff --git a/tdutils/CMakeLists.txt b/tdutils/CMakeLists.txt index d34b7f76..d57d93c8 100644 --- a/tdutils/CMakeLists.txt +++ b/tdutils/CMakeLists.txt @@ -1,5 +1,9 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +if (NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") +endif() + if (WIN32) if (WINGETOPT_FOUND) set(TD_HAVE_GETOPT 1) @@ -326,8 +330,6 @@ if (CMAKE_HOST_SYSTEM_NAME MATCHES "NetBSD") endif() install(TARGETS tdutils EXPORT TdTargets - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" )