From 03a624903e1d5a116d4342265f775139119e5fad Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 2 Apr 2024 03:52:34 +0300 Subject: [PATCH] Move relevant functions to UserManager. --- td/telegram/AccountManager.cpp | 16 +- td/telegram/AttachMenuManager.cpp | 39 +- td/telegram/AuthManager.cpp | 12 +- td/telegram/AutosaveManager.cpp | 3 +- td/telegram/BackgroundManager.cpp | 3 +- td/telegram/BoostManager.cpp | 15 +- td/telegram/BotCommand.cpp | 6 +- td/telegram/BotCommandScope.cpp | 5 +- td/telegram/BotInfoManager.cpp | 32 +- td/telegram/BotMenuButton.cpp | 6 +- td/telegram/BusinessConnectedBot.cpp | 4 +- td/telegram/BusinessConnectionManager.cpp | 19 +- td/telegram/BusinessManager.cpp | 19 +- td/telegram/BusinessRecipients.cpp | 8 +- td/telegram/CallActor.cpp | 6 +- td/telegram/CallbackQueriesManager.cpp | 19 +- td/telegram/CommonDialogManager.cpp | 9 +- td/telegram/ConfigManager.cpp | 6 +- td/telegram/ContactsManager.cpp | 7963 +------------------ td/telegram/ContactsManager.h | 905 +-- td/telegram/Dependencies.cpp | 5 +- td/telegram/DialogActionBar.cpp | 7 +- td/telegram/DialogActionManager.cpp | 11 +- td/telegram/DialogAdministrator.cpp | 8 +- td/telegram/DialogAdministrator.h | 5 +- td/telegram/DialogEventLog.cpp | 30 +- td/telegram/DialogFilter.cpp | 39 +- td/telegram/DialogFilterManager.cpp | 9 +- td/telegram/DialogInviteLink.cpp | 10 +- td/telegram/DialogInviteLink.h | 4 +- td/telegram/DialogInviteLinkManager.cpp | 64 +- td/telegram/DialogManager.cpp | 110 +- td/telegram/DialogParticipantFilter.cpp | 6 +- td/telegram/DialogParticipantManager.cpp | 119 +- td/telegram/DraftMessage.cpp | 5 +- td/telegram/FileReferenceManager.cpp | 7 +- td/telegram/FileReferenceManager.hpp | 5 +- td/telegram/ForumTopicManager.cpp | 5 +- td/telegram/Game.cpp | 8 +- td/telegram/Game.h | 4 +- td/telegram/GameManager.cpp | 14 +- td/telegram/GroupCallManager.cpp | 13 +- td/telegram/InlineQueriesManager.cpp | 41 +- td/telegram/LinkManager.cpp | 8 +- td/telegram/MessageContent.cpp | 49 +- td/telegram/MessageEntity.cpp | 57 +- td/telegram/MessageEntity.h | 21 +- td/telegram/MessageForwardInfo.cpp | 4 +- td/telegram/MessageImportManager.cpp | 3 +- td/telegram/MessageInputReplyTo.cpp | 6 +- td/telegram/MessageOrigin.cpp | 5 +- td/telegram/MessageReaction.cpp | 5 +- td/telegram/MessageReplyInfo.cpp | 3 +- td/telegram/MessageSender.cpp | 21 +- td/telegram/MessageViewer.cpp | 14 +- td/telegram/MessageViewer.h | 6 +- td/telegram/MessagesInfo.cpp | 3 +- td/telegram/MessagesManager.cpp | 423 +- td/telegram/NotificationManager.cpp | 13 +- td/telegram/NotificationSettingsManager.cpp | 5 +- td/telegram/OptionManager.cpp | 12 +- td/telegram/Payments.cpp | 16 +- td/telegram/PeopleNearbyManager.cpp | 5 +- td/telegram/PhoneNumberManager.cpp | 5 +- td/telegram/PollManager.cpp | 10 +- td/telegram/Premium.cpp | 13 +- td/telegram/PrivacyManager.cpp | 8 +- td/telegram/QuickReplyManager.cpp | 17 +- td/telegram/RecentDialogList.cpp | 7 +- td/telegram/RepliedMessageInfo.cpp | 4 +- td/telegram/ReplyMarkup.cpp | 30 +- td/telegram/ReplyMarkup.h | 10 +- td/telegram/RequestedDialogType.cpp | 5 +- td/telegram/SavedMessagesManager.cpp | 3 +- td/telegram/SecretChatsManager.cpp | 6 +- td/telegram/SecureManager.cpp | 6 +- td/telegram/SharedDialog.cpp | 4 +- td/telegram/SponsoredMessageManager.cpp | 15 +- td/telegram/StatisticsManager.cpp | 11 +- td/telegram/StickersManager.cpp | 24 +- td/telegram/StoryInteractionInfo.cpp | 6 +- td/telegram/StoryManager.cpp | 44 +- td/telegram/Support.cpp | 10 +- td/telegram/Td.cpp | 122 +- td/telegram/TopDialogManager.cpp | 9 +- td/telegram/TranslationManager.cpp | 14 +- td/telegram/UpdatesManager.cpp | 59 +- td/telegram/UserManager.cpp | 7943 ++++++++++++++++++ td/telegram/UserManager.h | 1083 +++ td/telegram/UserPrivacySettingRule.cpp | 17 +- td/telegram/WebPagesManager.cpp | 5 +- test/secret.cpp | 2 +- 92 files changed, 10021 insertions(+), 9774 deletions(-) diff --git a/td/telegram/AccountManager.cpp b/td/telegram/AccountManager.cpp index 7e8c7c5e9..fb6baede7 100644 --- a/td/telegram/AccountManager.cpp +++ b/td/telegram/AccountManager.cpp @@ -7,7 +7,6 @@ #include "td/telegram/AccountManager.h" #include "td/telegram/AuthManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DeviceTokenManager.h" #include "td/telegram/Global.h" #include "td/telegram/LinkManager.h" @@ -18,6 +17,7 @@ #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" #include "td/db/binlog/BinlogEvent.h" #include "td/db/binlog/BinlogHelper.h" @@ -461,7 +461,7 @@ class GetWebAuthorizationsQuery final : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetWebAuthorizationsQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetWebAuthorizationsQuery"); + td_->user_manager_->on_get_users(std::move(ptr->users_), "GetWebAuthorizationsQuery"); auto results = td_api::make_object(); results->websites_.reserve(ptr->authorizations_.size()); @@ -475,7 +475,7 @@ class GetWebAuthorizationsQuery final : public Td::ResultHandler { results->websites_.push_back(td_api::make_object( authorization->hash_, authorization->domain_, - td_->contacts_manager_->get_user_id_object(bot_user_id, "GetWebAuthorizationsQuery"), authorization->browser_, + td_->user_manager_->get_user_id_object(bot_user_id, "GetWebAuthorizationsQuery"), authorization->browser_, authorization->platform_, authorization->date_created_, authorization->date_active_, authorization->ip_, authorization->region_)); } @@ -591,9 +591,9 @@ class ImportContactTokenQuery final : public Td::ResultHandler { auto user = result_ptr.move_as_ok(); LOG(DEBUG) << "Receive result for ImportContactTokenQuery: " << to_string(user); - auto user_id = ContactsManager::get_user_id(user); - td_->contacts_manager_->on_get_user(std::move(user), "ImportContactTokenQuery"); - promise_.set_value(td_->contacts_manager_->get_user_object(user_id)); + auto user_id = UserManager::get_user_id(user); + td_->user_manager_->on_get_user(std::move(user), "ImportContactTokenQuery"); + promise_.set_value(td_->user_manager_->get_user_object(user_id)); } void on_error(Status status) final { @@ -1117,7 +1117,7 @@ void AccountManager::disconnect_all_websites(Promise &&promise) { } void AccountManager::get_user_link(Promise> &&promise) { - td_->contacts_manager_->get_me( + td_->user_manager_->get_me( PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)](Result &&result) mutable { if (result.is_error()) { promise.set_error(result.move_as_error()); @@ -1129,7 +1129,7 @@ void AccountManager::get_user_link(Promise> void AccountManager::get_user_link_impl(Promise> &&promise) { TRY_STATUS_PROMISE(promise, G()->close_status()); - auto username = td_->contacts_manager_->get_user_first_username(td_->contacts_manager_->get_my_id()); + auto username = td_->user_manager_->get_user_first_username(td_->user_manager_->get_my_id()); if (!username.empty()) { return promise.set_value( td_api::make_object(LinkManager::get_public_dialog_link(username, true), 0)); diff --git a/td/telegram/AttachMenuManager.cpp b/td/telegram/AttachMenuManager.cpp index 64c317ccd..0ca49137d 100644 --- a/td/telegram/AttachMenuManager.cpp +++ b/td/telegram/AttachMenuManager.cpp @@ -24,6 +24,7 @@ #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" #include "td/telegram/ThemeManager.h" +#include "td/telegram/UserManager.h" #include "td/telegram/WebApp.h" #include "td/utils/algorithm.h" @@ -222,7 +223,7 @@ class ProlongWebViewQuery final : public Td::ResultHandler { dialog_id_ = dialog_id; auto input_peer = td_->dialog_manager_->get_input_peer(dialog_id, AccessRights::Write); - auto r_input_user = td_->contacts_manager_->get_input_user(bot_user_id); + auto r_input_user = td_->user_manager_->get_input_user(bot_user_id); if (input_peer == nullptr || r_input_user.is_error()) { return; } @@ -275,7 +276,7 @@ class InvokeWebViewCustomMethodQuery final : public Td::ResultHandler { } void send(UserId bot_user_id, const string &method, const string ¶meters) { - auto r_input_user = td_->contacts_manager_->get_input_user(bot_user_id); + auto r_input_user = td_->user_manager_->get_input_user(bot_user_id); if (r_input_user.is_error()) { return on_error(r_input_user.move_as_error()); } @@ -770,8 +771,8 @@ void AttachMenuManager::schedule_ping_web_view() { void AttachMenuManager::get_web_app(UserId bot_user_id, const string &web_app_short_name, Promise> &&promise) { - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(bot_user_id)); - TRY_RESULT_PROMISE(promise, bot_data, td_->contacts_manager_->get_bot_data(bot_user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(bot_user_id)); + TRY_RESULT_PROMISE(promise, bot_data, td_->user_manager_->get_bot_data(bot_user_id)); auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), bot_user_id, web_app_short_name, promise = std::move(promise)]( Result> result) mutable { @@ -827,8 +828,8 @@ void AttachMenuManager::request_app_web_view(DialogId dialog_id, UserId bot_user dialog_id.get_type() == DialogType::SecretChat) { dialog_id = DialogId(bot_user_id); } - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(bot_user_id)); - TRY_RESULT_PROMISE(promise, bot_data, td_->contacts_manager_->get_bot_data(bot_user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(bot_user_id)); + TRY_RESULT_PROMISE(promise, bot_data, td_->user_manager_->get_bot_data(bot_user_id)); td_->create_handler(std::move(promise)) ->send(dialog_id, std::move(input_user), web_app_short_name, start_parameter, theme, platform, @@ -839,9 +840,9 @@ void AttachMenuManager::request_web_view(DialogId dialog_id, UserId bot_user_id, td_api::object_ptr &&reply_to, string &&url, td_api::object_ptr &&theme, string &&platform, Promise> &&promise) { - TRY_STATUS_PROMISE(promise, td_->contacts_manager_->get_bot_data(bot_user_id)); - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(bot_user_id)); - TRY_RESULT_PROMISE(promise, bot_data, td_->contacts_manager_->get_bot_data(bot_user_id)); + TRY_STATUS_PROMISE(promise, td_->user_manager_->get_bot_data(bot_user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(bot_user_id)); + TRY_RESULT_PROMISE(promise, bot_data, td_->user_manager_->get_bot_data(bot_user_id)); if (!td_->dialog_manager_->have_dialog_force(dialog_id, "request_web_view")) { return promise.set_error(Status::Error(400, "Chat not found")); @@ -917,7 +918,7 @@ void AttachMenuManager::invoke_web_view_custom_method( Result AttachMenuManager::get_attach_menu_bot( tl_object_ptr &&bot) { UserId user_id(bot->bot_id_); - if (!td_->contacts_manager_->have_user(user_id)) { + if (!td_->user_manager_->have_user(user_id)) { return Status::Error(PSLICE() << "Have no information about " << user_id); } @@ -1102,7 +1103,7 @@ void AttachMenuManager::on_reload_attach_menu_bots( CHECK(constructor_id == telegram_api::attachMenuBots::ID); auto attach_menu_bots = move_tl_object_as(attach_menu_bots_ptr); - td_->contacts_manager_->on_get_users(std::move(attach_menu_bots->users_), "on_reload_attach_menu_bots"); + td_->user_manager_->on_get_users(std::move(attach_menu_bots->users_), "on_reload_attach_menu_bots"); auto new_hash = attach_menu_bots->hash_; vector new_attach_menu_bots; @@ -1147,9 +1148,9 @@ void AttachMenuManager::remove_bot_from_attach_menu(UserId user_id) { void AttachMenuManager::get_attach_menu_bot(UserId user_id, Promise> &&promise) { - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); - TRY_RESULT_PROMISE(promise, bot_data, td_->contacts_manager_->get_bot_data(user_id)); + TRY_RESULT_PROMISE(promise, bot_data, td_->user_manager_->get_bot_data(user_id)); if (!bot_data.can_be_added_to_attach_menu) { return promise.set_error(Status::Error(400, "The bot can't be added to attachment menu")); } @@ -1168,7 +1169,7 @@ void AttachMenuManager::reload_attach_menu_bot(UserId user_id, Promise &&p return promise.set_error(Status::Error(400, "Can't reload attachment menu bot")); } - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); auto wrapped_promise = PromiseCreator::lambda( [promise = std::move(promise)](Result> result) mutable { @@ -1193,7 +1194,7 @@ void AttachMenuManager::on_get_attach_menu_bot( TRY_STATUS_PROMISE(promise, G()->close_status()); TRY_RESULT_PROMISE(promise, bot, std::move(result)); - td_->contacts_manager_->on_get_users(std::move(bot->users_), "on_get_attach_menu_bot"); + td_->user_manager_->on_get_users(std::move(bot->users_), "on_get_attach_menu_bot"); auto r_attach_menu_bot = get_attach_menu_bot(std::move(bot->bot_)); if (r_attach_menu_bot.is_error()) { @@ -1263,10 +1264,10 @@ void AttachMenuManager::toggle_bot_is_added_to_attach_menu(UserId user_id, bool Promise &&promise) { CHECK(is_active()); - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); if (is_added) { - TRY_RESULT_PROMISE(promise, bot_data, td_->contacts_manager_->get_bot_data(user_id)); + TRY_RESULT_PROMISE(promise, bot_data, td_->user_manager_->get_bot_data(user_id)); if (!bot_data.can_be_added_to_attach_menu) { return promise.set_error(Status::Error(400, "The bot can't be added to attachment menu")); } @@ -1304,8 +1305,8 @@ td_api::object_ptr AttachMenuManager::get_attachment_ }; return td_api::make_object( - td_->contacts_manager_->get_user_id_object(bot.user_id_, "get_attachment_menu_bot_object"), - bot.supports_self_dialog_, bot.supports_user_dialogs_, bot.supports_bot_dialogs_, bot.supports_group_dialogs_, + td_->user_manager_->get_user_id_object(bot.user_id_, "get_attachment_menu_bot_object"), bot.supports_self_dialog_, + bot.supports_user_dialogs_, bot.supports_bot_dialogs_, bot.supports_group_dialogs_, bot.supports_broadcast_dialogs_, bot.request_write_access_, bot.is_added_, bot.show_in_attach_menu_, bot.show_in_side_menu_, bot.side_menu_disclaimer_needed_, bot.name_, get_attach_menu_bot_color_object(bot.name_color_), get_file(bot.default_icon_file_id_), diff --git a/td/telegram/AuthManager.cpp b/td/telegram/AuthManager.cpp index 51456cad9..1ee1a848d 100644 --- a/td/telegram/AuthManager.cpp +++ b/td/telegram/AuthManager.cpp @@ -9,7 +9,6 @@ #include "td/telegram/AttachMenuManager.h" #include "td/telegram/AuthManager.hpp" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DialogFilterManager.h" #include "td/telegram/Global.h" #include "td/telegram/logevent/LogEvent.h" @@ -32,6 +31,7 @@ #include "td/telegram/ThemeManager.h" #include "td/telegram/TopDialogManager.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/telegram/Version.h" #include "td/utils/base64.h" @@ -287,7 +287,7 @@ AuthManager::AuthManager(int32 api_id, const string &api_hash, ActorShared<> par if (is_bot_str == "true") { is_bot_ = true; } - auto my_id = ContactsManager::load_my_id(); + auto my_id = UserManager::load_my_id(); if (my_id.is_valid()) { // just in case LOG(INFO) << "Logged in as " << my_id; @@ -295,8 +295,8 @@ AuthManager::AuthManager(int32 api_id, const string &api_hash, ActorShared<> par update_state(State::Ok); } else { LOG(ERROR) << "Restore unknown my_id"; - ContactsManager::send_get_me_query( - td_, PromiseCreator::lambda([this](Result result) { update_state(State::Ok); })); + UserManager::send_get_me_query(td_, + PromiseCreator::lambda([this](Result result) { update_state(State::Ok); })); } G()->net_query_dispatcher().check_authorization_is_ok(); } else if (auth_str == "logout") { @@ -1233,9 +1233,9 @@ void AuthManager::on_get_authorization(tl_object_ptrself_ = true; } } - td_->contacts_manager_->on_get_user(std::move(auth->user_), "on_get_authorization"); + td_->user_manager_->on_get_user(std::move(auth->user_), "on_get_authorization"); update_state(State::Ok); - if (!td_->contacts_manager_->get_my_id().is_valid()) { + if (!td_->user_manager_->get_my_id().is_valid()) { LOG(ERROR) << "Server didsn't send proper authorization"; on_current_query_error(Status::Error(500, "Server didn't send proper authorization")); log_out(0); diff --git a/td/telegram/AutosaveManager.cpp b/td/telegram/AutosaveManager.cpp index e9ed7c9bb..d18c88bb7 100644 --- a/td/telegram/AutosaveManager.cpp +++ b/td/telegram/AutosaveManager.cpp @@ -15,6 +15,7 @@ #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/db/SqliteKeyValueAsync.h" @@ -384,7 +385,7 @@ void AutosaveManager::on_get_autosave_settings( } auto settings = r_settings.move_as_ok(); - td_->contacts_manager_->on_get_users(std::move(settings->users_), "on_get_autosave_settings"); + td_->user_manager_->on_get_users(std::move(settings->users_), "on_get_autosave_settings"); td_->contacts_manager_->on_get_chats(std::move(settings->chats_), "on_get_autosave_settings"); DialogAutosaveSettings new_user_settings(settings->users_settings_.get()); diff --git a/td/telegram/BackgroundManager.cpp b/td/telegram/BackgroundManager.cpp index 6e956114a..1444ad189 100644 --- a/td/telegram/BackgroundManager.cpp +++ b/td/telegram/BackgroundManager.cpp @@ -25,6 +25,7 @@ #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/db/SqliteKeyValueAsync.h" @@ -785,7 +786,7 @@ Result BackgroundManager::get_background_dialog(DialogId dialog_id) { return dialog_id; } case DialogType::SecretChat: { - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + auto user_id = td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (!user_id.is_valid()) { return Status::Error(400, "Can't access the user"); } diff --git a/td/telegram/BoostManager.cpp b/td/telegram/BoostManager.cpp index 1b03a75c8..8f6954ac1 100644 --- a/td/telegram/BoostManager.cpp +++ b/td/telegram/BoostManager.cpp @@ -19,6 +19,7 @@ #include "td/telegram/telegram_api.h" #include "td/telegram/ThemeManager.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -41,7 +42,7 @@ static td_api::object_ptr get_chat_boost_object( giveaway_message_id = MessageId::min(); } return td_api::make_object( - td->contacts_manager_->get_user_id_object(user_id, "chatBoostSourceGiveaway"), boost->used_gift_slug_, + td->user_manager_->get_user_id_object(user_id, "chatBoostSourceGiveaway"), boost->used_gift_slug_, giveaway_message_id.get(), boost->unclaimed_); } if (boost->gift_) { @@ -50,7 +51,7 @@ static td_api::object_ptr get_chat_boost_object( return nullptr; } return td_api::make_object( - td->contacts_manager_->get_user_id_object(user_id, "chatBoostSourceGiftCode"), boost->used_gift_slug_); + td->user_manager_->get_user_id_object(user_id, "chatBoostSourceGiftCode"), boost->used_gift_slug_); } UserId user_id(boost->user_id_); @@ -58,7 +59,7 @@ static td_api::object_ptr get_chat_boost_object( return nullptr; } return td_api::make_object( - td->contacts_manager_->get_user_id_object(user_id, "chatBoostSourcePremium")); + td->user_manager_->get_user_id_object(user_id, "chatBoostSourcePremium")); }(); if (source == nullptr) { LOG(ERROR) << "Receive " << to_string(boost); @@ -70,7 +71,7 @@ static td_api::object_ptr get_chat_boost_object( static td_api::object_ptr get_chat_boost_slots_object( Td *td, telegram_api::object_ptr &&my_boosts) { - td->contacts_manager_->on_get_users(std::move(my_boosts->users_), "GetMyBoostsQuery"); + td->user_manager_->on_get_users(std::move(my_boosts->users_), "GetMyBoostsQuery"); td->contacts_manager_->on_get_chats(std::move(my_boosts->chats_), "GetMyBoostsQuery"); vector> slots; for (auto &my_boost : my_boosts->my_boosts_) { @@ -268,7 +269,7 @@ class GetBoostsListQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(DEBUG) << "Receive result for GetBoostsListQuery: " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetBoostsListQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetBoostsListQuery"); auto total_count = result->count_; vector> boosts; @@ -302,7 +303,7 @@ class GetUserBoostsQuery final : public Td::ResultHandler { dialog_id_ = dialog_id; auto input_peer = td_->dialog_manager_->get_input_peer(dialog_id_, AccessRights::Read); CHECK(input_peer != nullptr); - auto r_input_user = td_->contacts_manager_->get_input_user(user_id); + auto r_input_user = td_->user_manager_->get_input_user(user_id); CHECK(r_input_user.is_ok()); send_query(G()->net_query_creator().create( telegram_api::premium_getUserBoosts(std::move(input_peer), r_input_user.move_as_ok()))); @@ -316,7 +317,7 @@ class GetUserBoostsQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(DEBUG) << "Receive result for GetUserBoostsQuery: " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetUserBoostsQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetUserBoostsQuery"); auto total_count = result->count_; vector> boosts; diff --git a/td/telegram/BotCommand.cpp b/td/telegram/BotCommand.cpp index da8142577..3fe6bf062 100644 --- a/td/telegram/BotCommand.cpp +++ b/td/telegram/BotCommand.cpp @@ -7,11 +7,11 @@ #include "td/telegram/BotCommand.h" #include "td/telegram/BotCommandScope.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" #include "td/telegram/misc.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -100,7 +100,7 @@ class GetBotCommandsQuery final : public Td::ResultHandler { return on_error(result_ptr.move_as_error()); } - BotCommands commands(td_->contacts_manager_->get_my_id(), result_ptr.move_as_ok()); + BotCommands commands(td_->user_manager_->get_my_id(), result_ptr.move_as_ok()); promise_.set_value(commands.get_bot_commands_object(td_)); } @@ -137,7 +137,7 @@ BotCommands::BotCommands(UserId bot_user_id, vector BotCommands::get_bot_commands_object(Td *td) const { auto commands = transform(commands_, [](const auto &command) { return command.get_bot_command_object(); }); return td_api::make_object( - td->contacts_manager_->get_user_id_object(bot_user_id_, "get_bot_commands_object"), std::move(commands)); + td->user_manager_->get_user_id_object(bot_user_id_, "get_bot_commands_object"), std::move(commands)); } bool BotCommands::update_all_bot_commands(vector &all_bot_commands, BotCommands &&bot_commands) { diff --git a/td/telegram/BotCommandScope.cpp b/td/telegram/BotCommandScope.cpp index 1c9fc790f..50b40fe79 100644 --- a/td/telegram/BotCommandScope.cpp +++ b/td/telegram/BotCommandScope.cpp @@ -11,6 +11,7 @@ #include "td/telegram/ContactsManager.h" #include "td/telegram/DialogManager.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" namespace td { @@ -54,7 +55,7 @@ Result BotCommandScope::get_bot_command_scope(Td *td, type = Type::DialogParticipant; dialog_id = DialogId(scope->chat_id_); user_id = UserId(scope->user_id_); - TRY_STATUS(td->contacts_manager_->get_input_user(user_id)); + TRY_STATUS(td->user_manager_->get_input_user(user_id)); break; } default: @@ -94,7 +95,7 @@ telegram_api::object_ptr BotCommandScope::get_inp const Td *td) const { auto input_peer = dialog_id_.is_valid() ? td->dialog_manager_->get_input_peer(dialog_id_, AccessRights::Read) : nullptr; - auto r_input_user = td->contacts_manager_->get_input_user(user_id_); + auto r_input_user = td->user_manager_->get_input_user(user_id_); auto input_user = r_input_user.is_ok() ? r_input_user.move_as_ok() : nullptr; switch (type_) { case Type::Default: diff --git a/td/telegram/BotInfoManager.cpp b/td/telegram/BotInfoManager.cpp index 54393bd15..b9553a0bf 100644 --- a/td/telegram/BotInfoManager.cpp +++ b/td/telegram/BotInfoManager.cpp @@ -7,13 +7,13 @@ #include "td/telegram/BotInfoManager.h" #include "td/telegram/AuthManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" #include "td/telegram/misc.h" #include "td/telegram/net/NetQueryCreator.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -44,7 +44,7 @@ class SetBotGroupDefaultAdminRightsQuery final : public Td::ResultHandler { bool result = result_ptr.move_as_ok(); LOG_IF(WARNING, !result) << "Failed to set group default administrator rights"; - td_->contacts_manager_->invalidate_user_full(td_->contacts_manager_->get_my_id()); + td_->user_manager_->invalidate_user_full(td_->user_manager_->get_my_id()); promise_.set_value(Unit()); } @@ -52,7 +52,7 @@ class SetBotGroupDefaultAdminRightsQuery final : public Td::ResultHandler { if (status.message() == "RIGHTS_NOT_MODIFIED") { return promise_.set_value(Unit()); } - td_->contacts_manager_->invalidate_user_full(td_->contacts_manager_->get_my_id()); + td_->user_manager_->invalidate_user_full(td_->user_manager_->get_my_id()); promise_.set_error(std::move(status)); } }; @@ -77,7 +77,7 @@ class SetBotBroadcastDefaultAdminRightsQuery final : public Td::ResultHandler { bool result = result_ptr.move_as_ok(); LOG_IF(WARNING, !result) << "Failed to set channel default administrator rights"; - td_->contacts_manager_->invalidate_user_full(td_->contacts_manager_->get_my_id()); + td_->user_manager_->invalidate_user_full(td_->user_manager_->get_my_id()); promise_.set_value(Unit()); } @@ -85,7 +85,7 @@ class SetBotBroadcastDefaultAdminRightsQuery final : public Td::ResultHandler { if (status.message() == "RIGHTS_NOT_MODIFIED") { return promise_.set_value(Unit()); } - td_->contacts_manager_->invalidate_user_full(td_->contacts_manager_->get_my_id()); + td_->user_manager_->invalidate_user_full(td_->user_manager_->get_my_id()); promise_.set_error(std::move(status)); } }; @@ -98,7 +98,7 @@ class CanBotSendMessageQuery final : public Td::ResultHandler { } void send(UserId bot_user_id) { - auto r_input_user = td_->contacts_manager_->get_input_user(bot_user_id); + auto r_input_user = td_->user_manager_->get_input_user(bot_user_id); if (r_input_user.is_error()) { return on_error(r_input_user.move_as_error()); } @@ -132,7 +132,7 @@ class AllowBotSendMessageQuery final : public Td::ResultHandler { } void send(UserId bot_user_id) { - auto r_input_user = td_->contacts_manager_->get_input_user(bot_user_id); + auto r_input_user = td_->user_manager_->get_input_user(bot_user_id); if (r_input_user.is_error()) { return on_error(r_input_user.move_as_error()); } @@ -158,15 +158,15 @@ class AllowBotSendMessageQuery final : public Td::ResultHandler { static Result> get_bot_input_user(const Td *td, UserId bot_user_id) { if (td->auth_manager_->is_bot()) { - if (bot_user_id != UserId() && bot_user_id != td->contacts_manager_->get_my_id()) { + if (bot_user_id != UserId() && bot_user_id != td->user_manager_->get_my_id()) { return Status::Error(400, "Invalid bot user identifier specified"); } } else { - TRY_RESULT(bot_data, td->contacts_manager_->get_bot_data(bot_user_id)); + TRY_RESULT(bot_data, td->user_manager_->get_bot_data(bot_user_id)); if (!bot_data.can_be_edited) { return Status::Error(400, "The bot can't be edited"); } - return td->contacts_manager_->get_input_user(bot_user_id); + return td->user_manager_->get_input_user(bot_user_id); } return nullptr; } @@ -179,7 +179,7 @@ class SetBotInfoQuery final : public Td::ResultHandler { void invalidate_bot_info() { if (set_info_) { - td_->contacts_manager_->invalidate_user_full(bot_user_id_); + td_->user_manager_->invalidate_user_full(bot_user_id_); } } @@ -207,7 +207,7 @@ class SetBotInfoQuery final : public Td::ResultHandler { flags |= telegram_api::bots_setBotInfo::BOT_MASK; bot_user_id_ = bot_user_id; } else { - bot_user_id_ = td_->contacts_manager_->get_my_id(); + bot_user_id_ = td_->user_manager_->get_my_id(); } set_name_ = set_name; set_info_ = set_about || set_description; @@ -228,11 +228,11 @@ class SetBotInfoQuery final : public Td::ResultHandler { if (set_info_) { invalidate_bot_info(); if (!td_->auth_manager_->is_bot()) { - return td_->contacts_manager_->reload_user_full(bot_user_id_, std::move(promise_), "SetBotInfoQuery"); + return td_->user_manager_->reload_user_full(bot_user_id_, std::move(promise_), "SetBotInfoQuery"); } } if (set_name_) { - return td_->contacts_manager_->reload_user(bot_user_id_, std::move(promise_), "SetBotInfoQuery"); + return td_->user_manager_->reload_user(bot_user_id_, std::move(promise_), "SetBotInfoQuery"); } // invalidation is enough for bots if name wasn't changed promise_.set_value(Unit()); @@ -374,13 +374,13 @@ void BotInfoManager::timeout_expired() { void BotInfoManager::set_default_group_administrator_rights(AdministratorRights administrator_rights, Promise &&promise) { - td_->contacts_manager_->invalidate_user_full(td_->contacts_manager_->get_my_id()); + td_->user_manager_->invalidate_user_full(td_->user_manager_->get_my_id()); td_->create_handler(std::move(promise))->send(administrator_rights); } void BotInfoManager::set_default_channel_administrator_rights(AdministratorRights administrator_rights, Promise &&promise) { - td_->contacts_manager_->invalidate_user_full(td_->contacts_manager_->get_my_id()); + td_->user_manager_->invalidate_user_full(td_->user_manager_->get_my_id()); td_->create_handler(std::move(promise))->send(administrator_rights); } diff --git a/td/telegram/BotMenuButton.cpp b/td/telegram/BotMenuButton.cpp index 857fd5387..0f330debc 100644 --- a/td/telegram/BotMenuButton.cpp +++ b/td/telegram/BotMenuButton.cpp @@ -7,12 +7,12 @@ #include "td/telegram/BotMenuButton.h" #include "td/telegram/AuthManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" #include "td/telegram/LinkManager.h" #include "td/telegram/misc.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/buffer.h" #include "td/utils/logging.h" @@ -29,7 +29,7 @@ class SetBotMenuButtonQuery final : public Td::ResultHandler { } void send(UserId user_id, telegram_api::object_ptr input_bot_menu_button) { - auto input_user = user_id.is_valid() ? td_->contacts_manager_->get_input_user(user_id).move_as_ok() + auto input_user = user_id.is_valid() ? td_->user_manager_->get_input_user(user_id).move_as_ok() : make_tl_object(); send_query(G()->net_query_creator().create( telegram_api::bots_setBotMenuButton(std::move(input_user), std::move(input_bot_menu_button)))); @@ -61,7 +61,7 @@ class GetBotMenuButtonQuery final : public Td::ResultHandler { } void send(UserId user_id) { - auto input_user = user_id.is_valid() ? td_->contacts_manager_->get_input_user(user_id).move_as_ok() + auto input_user = user_id.is_valid() ? td_->user_manager_->get_input_user(user_id).move_as_ok() : make_tl_object(); send_query(G()->net_query_creator().create(telegram_api::bots_getBotMenuButton(std::move(input_user)))); } diff --git a/td/telegram/BusinessConnectedBot.cpp b/td/telegram/BusinessConnectedBot.cpp index 7578e5614..eabdf3c3d 100644 --- a/td/telegram/BusinessConnectedBot.cpp +++ b/td/telegram/BusinessConnectedBot.cpp @@ -6,8 +6,8 @@ // #include "td/telegram/BusinessConnectedBot.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" namespace td { @@ -30,7 +30,7 @@ BusinessConnectedBot::BusinessConnectedBot(td_api::object_ptr BusinessConnectedBot::get_business_connected_bot_object(Td *td) const { CHECK(is_valid()); return td_api::make_object( - td->contacts_manager_->get_user_id_object(user_id_, "businessConnectedBot"), + td->user_manager_->get_user_id_object(user_id_, "businessConnectedBot"), recipients_.get_business_recipients_object(td), can_reply_); } diff --git a/td/telegram/BusinessConnectionManager.cpp b/td/telegram/BusinessConnectionManager.cpp index 6ff53865a..fe1b74656 100644 --- a/td/telegram/BusinessConnectionManager.cpp +++ b/td/telegram/BusinessConnectionManager.cpp @@ -28,6 +28,7 @@ #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" #include "td/utils/buffer.h" #include "td/utils/format.h" @@ -98,7 +99,7 @@ struct BusinessConnectionManager::BusinessConnection { DialogId user_dialog_id(user_id_); td->dialog_manager_->force_create_dialog(user_dialog_id, "get_business_connection_object"); return td_api::make_object( - connection_id_.get(), td->contacts_manager_->get_user_id_object(user_id_, "businessConnection"), + connection_id_.get(), td->user_manager_->get_user_id_object(user_id_, "businessConnection"), td->dialog_manager_->get_chat_id_object(user_dialog_id, "businessConnection"), connection_date_, can_reply_, !is_disabled_); } @@ -155,7 +156,7 @@ class BusinessConnectionManager::SendBusinessMessageQuery final : public Td::Res const FormattedText *message_text = get_message_content_text(message_->content_.get()); CHECK(message_text != nullptr); - auto entities = get_input_message_entities(td_->contacts_manager_.get(), message_text, "SendBusinessMessageQuery"); + auto entities = get_input_message_entities(td_->user_manager_.get(), message_text, "SendBusinessMessageQuery"); if (!entities.empty()) { flags |= telegram_api::messages_sendMessage::ENTITIES_MASK; } @@ -169,7 +170,7 @@ class BusinessConnectionManager::SendBusinessMessageQuery final : public Td::Res telegram_api::messages_sendMessage( flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_peer), std::move(reply_to), message_text->text, - message_->random_id_, get_input_reply_markup(td_->contacts_manager_.get(), message_->reply_markup_), + message_->random_id_, get_input_reply_markup(td_->user_manager_.get(), message_->reply_markup_), std::move(entities), 0, nullptr, nullptr), td_->business_connection_manager_->get_business_connection_dc_id(message_->business_connection_id_), {{message_->dialog_id_}})); @@ -225,7 +226,7 @@ class BusinessConnectionManager::SendBusinessMediaQuery final : public Td::Resul } const FormattedText *message_text = get_message_content_text(message_->content_.get()); - auto entities = get_input_message_entities(td_->contacts_manager_.get(), message_text, "SendBusinessMediaQuery"); + auto entities = get_input_message_entities(td_->user_manager_.get(), message_text, "SendBusinessMediaQuery"); if (!entities.empty()) { flags |= telegram_api::messages_sendMedia::ENTITIES_MASK; } @@ -240,7 +241,7 @@ class BusinessConnectionManager::SendBusinessMediaQuery final : public Td::Resul false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_peer), std::move(reply_to), std::move(input_media), message_text == nullptr ? string() : message_text->text, message_->random_id_, - get_input_reply_markup(td_->contacts_manager_.get(), message_->reply_markup_), + get_input_reply_markup(td_->user_manager_.get(), message_->reply_markup_), std::move(entities), 0, nullptr, nullptr), td_->business_connection_manager_->get_business_connection_dc_id(message_->business_connection_id_), {{message_->dialog_id_}})); @@ -599,7 +600,7 @@ void BusinessConnectionManager::on_get_business_connection( } auto update = telegram_api::move_object_as(updates->updates_[0]); - td_->contacts_manager_->on_get_users(std::move(updates->users_), "on_get_business_connection"); + td_->user_manager_->on_get_users(std::move(updates->users_), "on_get_business_connection"); td_->contacts_manager_->on_get_chats(std::move(updates->chats_), "on_get_business_connection"); auto business_connection = make_unique(update->connection_); @@ -763,7 +764,7 @@ void BusinessConnectionManager::process_sent_business_message( } auto update = telegram_api::move_object_as(updates->updates_[0]); - td_->contacts_manager_->on_get_users(std::move(updates->users_), "SendBusinessMediaQuery"); + td_->user_manager_->on_get_users(std::move(updates->users_), "SendBusinessMediaQuery"); td_->contacts_manager_->on_get_chats(std::move(updates->chats_), "SendBusinessMediaQuery"); promise.set_value(td_->messages_manager_->get_business_message_object(std::move(update->message_), @@ -1067,7 +1068,7 @@ void BusinessConnectionManager::on_upload_message_album_media(int64 request_id, auto message = std::move(upload_result.message_); int32 flags = 0; const FormattedText *caption = get_message_content_text(message->content_.get()); - auto entities = get_input_message_entities(td_->contacts_manager_.get(), caption, "on_upload_message_album_media"); + auto entities = get_input_message_entities(td_->user_manager_.get(), caption, "on_upload_message_album_media"); if (!entities.empty()) { flags |= telegram_api::inputSingleMedia::ENTITIES_MASK; } @@ -1095,7 +1096,7 @@ void BusinessConnectionManager::process_sent_business_message_album( return promise.set_error(Status::Error(500, "Receive invalid business connection messages")); } } - td_->contacts_manager_->on_get_users(std::move(updates->users_), "process_sent_business_message_album"); + td_->user_manager_->on_get_users(std::move(updates->users_), "process_sent_business_message_album"); td_->contacts_manager_->on_get_chats(std::move(updates->chats_), "process_sent_business_message_album"); auto messages = td_api::make_object(); diff --git a/td/telegram/BusinessManager.cpp b/td/telegram/BusinessManager.cpp index 1c69c732e..c31f875a1 100644 --- a/td/telegram/BusinessManager.cpp +++ b/td/telegram/BusinessManager.cpp @@ -12,12 +12,12 @@ #include "td/telegram/BusinessIntro.h" #include "td/telegram/BusinessRecipients.h" #include "td/telegram/BusinessWorkHours.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DialogLocation.h" #include "td/telegram/Global.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/utils/buffer.h" #include "td/utils/logging.h" @@ -46,7 +46,7 @@ class GetConnectedBotsQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetConnectedBotsQuery: " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetConnectedBotsQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetConnectedBotsQuery"); if (result->connected_bots_.size() > 1u) { return on_error(Status::Error(500, "Receive invalid response")); } @@ -135,7 +135,7 @@ class UpdateBusinessLocationQuery final : public Td::ResultHandler { return on_error(result_ptr.move_as_error()); } - td_->contacts_manager_->on_update_user_location(td_->contacts_manager_->get_my_id(), std::move(location_)); + td_->user_manager_->on_update_user_location(td_->user_manager_->get_my_id(), std::move(location_)); promise_.set_value(Unit()); } @@ -169,7 +169,7 @@ class UpdateBusinessWorkHoursQuery final : public Td::ResultHandler { return on_error(result_ptr.move_as_error()); } - td_->contacts_manager_->on_update_user_work_hours(td_->contacts_manager_->get_my_id(), std::move(work_hours_)); + td_->user_manager_->on_update_user_work_hours(td_->user_manager_->get_my_id(), std::move(work_hours_)); promise_.set_value(Unit()); } @@ -204,8 +204,7 @@ class UpdateBusinessGreetingMessageQuery final : public Td::ResultHandler { return on_error(result_ptr.move_as_error()); } - td_->contacts_manager_->on_update_user_greeting_message(td_->contacts_manager_->get_my_id(), - std::move(greeting_message_)); + td_->user_manager_->on_update_user_greeting_message(td_->user_manager_->get_my_id(), std::move(greeting_message_)); promise_.set_value(Unit()); } @@ -240,7 +239,7 @@ class UpdateBusinessAwayMessageQuery final : public Td::ResultHandler { return on_error(result_ptr.move_as_error()); } - td_->contacts_manager_->on_update_user_away_message(td_->contacts_manager_->get_my_id(), std::move(away_message_)); + td_->user_manager_->on_update_user_away_message(td_->user_manager_->get_my_id(), std::move(away_message_)); promise_.set_value(Unit()); } @@ -275,7 +274,7 @@ class UpdateBusinessIntroQuery final : public Td::ResultHandler { return on_error(result_ptr.move_as_error()); } - td_->contacts_manager_->on_update_user_intro(td_->contacts_manager_->get_my_id(), std::move(intro_)); + td_->user_manager_->on_update_user_intro(td_->user_manager_->get_my_id(), std::move(intro_)); promise_.set_value(Unit()); } @@ -302,12 +301,12 @@ void BusinessManager::set_business_connected_bot(td_api::object_ptrcontacts_manager_->get_input_user(connected_bot.get_user_id())); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(connected_bot.get_user_id())); td_->create_handler(std::move(promise))->send(connected_bot, std::move(input_user)); } void BusinessManager::delete_business_connected_bot(UserId bot_user_id, Promise &&promise) { - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(bot_user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(bot_user_id)); td_->create_handler(std::move(promise))->send(std::move(input_user)); } diff --git a/td/telegram/BusinessRecipients.cpp b/td/telegram/BusinessRecipients.cpp index bb8bafb2e..dabc85098 100644 --- a/td/telegram/BusinessRecipients.cpp +++ b/td/telegram/BusinessRecipients.cpp @@ -6,11 +6,11 @@ // #include "td/telegram/BusinessRecipients.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Dependencies.h" #include "td/telegram/DialogId.h" #include "td/telegram/DialogManager.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" @@ -107,7 +107,7 @@ telegram_api::object_ptr BusinessRecipien } vector> input_users; for (auto user_id : user_ids_) { - auto r_input_user = td->contacts_manager_->get_input_user(user_id); + auto r_input_user = td->user_manager_->get_input_user(user_id); if (r_input_user.is_ok()) { input_users.push_back(r_input_user.move_as_ok()); } @@ -140,7 +140,7 @@ BusinessRecipients::get_input_business_bot_recipients(Td *td) const { } vector> input_users; for (auto user_id : user_ids_) { - auto r_input_user = td->contacts_manager_->get_input_user(user_id); + auto r_input_user = td->user_manager_->get_input_user(user_id); if (r_input_user.is_ok()) { input_users.push_back(r_input_user.move_as_ok()); } @@ -150,7 +150,7 @@ BusinessRecipients::get_input_business_bot_recipients(Td *td) const { } vector> excluded_input_users; for (auto user_id : excluded_user_ids_) { - auto r_input_user = td->contacts_manager_->get_input_user(user_id); + auto r_input_user = td->user_manager_->get_input_user(user_id); if (r_input_user.is_ok()) { excluded_input_users.push_back(r_input_user.move_as_ok()); } diff --git a/td/telegram/CallActor.cpp b/td/telegram/CallActor.cpp index 5c31437f8..e45fd5d16 100644 --- a/td/telegram/CallActor.cpp +++ b/td/telegram/CallActor.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/CallActor.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DhCache.h" #include "td/telegram/DialogId.h" #include "td/telegram/files/FileManager.h" @@ -19,6 +18,7 @@ #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/as.h" @@ -504,7 +504,7 @@ void CallActor::update_call(tl_object_ptr call) { void CallActor::update_call_inner(tl_object_ptr call) { LOG(INFO) << "Update call with " << to_string(call); - send_closure(G()->contacts_manager(), &ContactsManager::on_get_users, std::move(call->users_), "UpdatePhoneCall"); + send_closure(G()->user_manager(), &UserManager::on_get_users, std::move(call->users_), "UpdatePhoneCall"); update_call(std::move(call->phone_call_)); } @@ -921,7 +921,7 @@ void CallActor::flush_call_state() { call_state_need_flush_ = false; // TODO can't call const function - // send_closure(G()->contacts_manager(), &ContactsManager::get_user_id_object, user_id_, "flush_call_state"); + // send_closure(G()->user_manager(), &UserManager::get_user_id_object, user_id_, "flush_call_state"); send_closure(G()->td(), &Td::send_update, make_tl_object(make_tl_object( local_call_id_.get(), is_outgoing_ ? user_id_.get() : call_admin_user_id_.get(), is_outgoing_, diff --git a/td/telegram/CallbackQueriesManager.cpp b/td/telegram/CallbackQueriesManager.cpp index d8537665a..e62dfd746 100644 --- a/td/telegram/CallbackQueriesManager.cpp +++ b/td/telegram/CallbackQueriesManager.cpp @@ -8,7 +8,6 @@ #include "td/telegram/AccessRights.h" #include "td/telegram/AuthManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DialogManager.h" #include "td/telegram/Global.h" #include "td/telegram/InlineQueriesManager.h" @@ -17,6 +16,7 @@ #include "td/telegram/Td.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/actor/actor.h" @@ -174,7 +174,7 @@ void CallbackQueriesManager::on_new_query(int32 flags, int64 callback_query_id, LOG(ERROR) << "Receive new callback query from invalid " << sender_user_id << " in " << dialog_id; return; } - LOG_IF(ERROR, !td_->contacts_manager_->have_user(sender_user_id)) << "Receive unknown " << sender_user_id; + LOG_IF(ERROR, !td_->user_manager_->have_user(sender_user_id)) << "Receive unknown " << sender_user_id; if (!td_->auth_manager_->is_bot()) { LOG(ERROR) << "Receive new callback query"; return; @@ -191,12 +191,11 @@ void CallbackQueriesManager::on_new_query(int32 flags, int64 callback_query_id, } td_->dialog_manager_->force_create_dialog(dialog_id, "on_new_callback_query", true); - send_closure( - G()->td(), &Td::send_update, - td_api::make_object( - callback_query_id, td_->contacts_manager_->get_user_id_object(sender_user_id, "updateNewCallbackQuery"), - td_->dialog_manager_->get_chat_id_object(dialog_id, "updateNewCallbackQuery"), message_id.get(), - chat_instance, std::move(payload))); + send_closure(G()->td(), &Td::send_update, + td_api::make_object( + callback_query_id, td_->user_manager_->get_user_id_object(sender_user_id, "updateNewCallbackQuery"), + td_->dialog_manager_->get_chat_id_object(dialog_id, "updateNewCallbackQuery"), message_id.get(), + chat_instance, std::move(payload))); } void CallbackQueriesManager::on_new_inline_query( @@ -207,7 +206,7 @@ void CallbackQueriesManager::on_new_inline_query( LOG(ERROR) << "Receive new callback query from invalid " << sender_user_id; return; } - LOG_IF(ERROR, !td_->contacts_manager_->have_user(sender_user_id)) << "Receive unknown " << sender_user_id; + LOG_IF(ERROR, !td_->user_manager_->have_user(sender_user_id)) << "Receive unknown " << sender_user_id; if (!td_->auth_manager_->is_bot()) { LOG(ERROR) << "Receive new callback query"; return; @@ -221,7 +220,7 @@ void CallbackQueriesManager::on_new_inline_query( send_closure( G()->td(), &Td::send_update, make_tl_object( - callback_query_id, td_->contacts_manager_->get_user_id_object(sender_user_id, "updateNewInlineCallbackQuery"), + callback_query_id, td_->user_manager_->get_user_id_object(sender_user_id, "updateNewInlineCallbackQuery"), InlineQueriesManager::get_inline_message_id(std::move(inline_message_id)), chat_instance, std::move(payload))); } diff --git a/td/telegram/CommonDialogManager.cpp b/td/telegram/CommonDialogManager.cpp index 92d0a890a..d897c7caa 100644 --- a/td/telegram/CommonDialogManager.cpp +++ b/td/telegram/CommonDialogManager.cpp @@ -11,6 +11,7 @@ #include "td/telegram/Global.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -94,13 +95,13 @@ void CommonDialogManager::drop_common_dialogs_cache(UserId user_id) { std::pair> CommonDialogManager::get_common_dialogs(UserId user_id, DialogId offset_dialog_id, int32 limit, bool force, Promise &&promise) { - auto r_input_user = td_->contacts_manager_->get_input_user(user_id); + auto r_input_user = td_->user_manager_->get_input_user(user_id); if (r_input_user.is_error()) { promise.set_error(r_input_user.move_as_error()); return {}; } - if (user_id == td_->contacts_manager_->get_my_id()) { + if (user_id == td_->user_manager_->get_my_id()) { promise.set_error(Status::Error(400, "Can't get common chats with self")); return {}; } @@ -178,7 +179,7 @@ std::pair> CommonDialogManager::get_common_dialogs(UserI void CommonDialogManager::on_get_common_dialogs(UserId user_id, int64 offset_chat_id, vector> &&chats, int32 total_count) { CHECK(user_id.is_valid()); - td_->contacts_manager_->on_update_user_common_chat_count(user_id, total_count); + td_->user_manager_->on_update_user_common_chat_count(user_id, total_count); auto &common_dialogs = found_common_dialogs_[user_id]; if (common_dialogs.is_outdated && offset_chat_id == 0 && @@ -213,7 +214,7 @@ void CommonDialogManager::on_get_common_dialogs(UserId user_id, int64 offset_cha LOG(ERROR) << "Fix total count of common groups with " << user_id << " from " << total_count << " to " << result.size(); total_count = narrow_cast(result.size()); - td_->contacts_manager_->on_update_user_common_chat_count(user_id, total_count); + td_->user_manager_->on_update_user_common_chat_count(user_id, total_count); } result.emplace_back(); diff --git a/td/telegram/ConfigManager.cpp b/td/telegram/ConfigManager.cpp index 4fbaa41bc..d0e1e2957 100644 --- a/td/telegram/ConfigManager.cpp +++ b/td/telegram/ConfigManager.cpp @@ -8,7 +8,6 @@ #include "td/telegram/AuthManager.h" #include "td/telegram/ConnectionState.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" #include "td/telegram/JsonValue.h" #include "td/telegram/LinkManager.h" @@ -32,6 +31,7 @@ #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" #include "td/telegram/TranscriptionManager.h" +#include "td/telegram/UserManager.h" #include "td/mtproto/AuthData.h" #include "td/mtproto/AuthKey.h" @@ -1502,7 +1502,7 @@ void ConfigManager::process_app_config(tl_object_ptr &c int32 dialog_filter_update_period = 300; // bool archive_all_stories = false; int32 story_viewers_expire_period = 86400; - int64 stories_changelog_user_id = ContactsManager::get_service_notifications_user_id().get(); + int64 stories_changelog_user_id = UserManager::get_service_notifications_user_id().get(); int32 transcribe_audio_trial_weekly_number = 0; int32 transcribe_audio_trial_duration_max = 0; int32 transcribe_audio_trial_cooldown_until = 0; @@ -2173,7 +2173,7 @@ void ConfigManager::process_app_config(tl_object_ptr &c } else { options.set_option_empty("gift_premium_from_input_field"); } - if (stories_changelog_user_id != ContactsManager::get_service_notifications_user_id().get()) { + if (stories_changelog_user_id != UserManager::get_service_notifications_user_id().get()) { options.set_option_integer("stories_changelog_user_id", stories_changelog_user_id); } else { options.set_option_empty("stories_changelog_user_id"); diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index e5e7d64a0..a95fcf39e 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -6,19 +6,7 @@ // #include "td/telegram/ContactsManager.h" -#include "td/telegram/AnimationsManager.h" #include "td/telegram/AuthManager.h" -#include "td/telegram/Birthdate.hpp" -#include "td/telegram/BlockListId.h" -#include "td/telegram/BotMenuButton.h" -#include "td/telegram/BusinessAwayMessage.h" -#include "td/telegram/BusinessGreetingMessage.h" -#include "td/telegram/BusinessInfo.h" -#include "td/telegram/BusinessInfo.hpp" -#include "td/telegram/BusinessIntro.h" -#include "td/telegram/BusinessWorkHours.h" -#include "td/telegram/CommonDialogManager.h" -#include "td/telegram/ConfigManager.h" #include "td/telegram/Dependencies.h" #include "td/telegram/DialogAdministrator.h" #include "td/telegram/DialogInviteLink.h" @@ -26,17 +14,12 @@ #include "td/telegram/DialogLocation.h" #include "td/telegram/DialogManager.h" #include "td/telegram/DialogParticipantManager.h" -#include "td/telegram/Document.h" -#include "td/telegram/DocumentsManager.h" #include "td/telegram/FileReferenceManager.h" #include "td/telegram/files/FileManager.h" -#include "td/telegram/files/FileType.h" #include "td/telegram/FolderId.h" #include "td/telegram/Global.h" #include "td/telegram/GroupCallManager.h" -#include "td/telegram/InlineQueriesManager.h" #include "td/telegram/InputGroupCallId.h" -#include "td/telegram/LinkManager.h" #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/logevent/LogEventHelper.h" #include "td/telegram/MessageSender.h" @@ -45,20 +28,12 @@ #include "td/telegram/MinChannel.h" #include "td/telegram/misc.h" #include "td/telegram/net/NetQuery.h" -#include "td/telegram/NotificationManager.h" #include "td/telegram/OptionManager.h" #include "td/telegram/PeerColor.h" -#include "td/telegram/PeopleNearbyManager.h" #include "td/telegram/Photo.h" #include "td/telegram/Photo.hpp" #include "td/telegram/PhotoSize.h" -#include "td/telegram/PremiumGiftOption.hpp" -#include "td/telegram/ReactionListType.h" -#include "td/telegram/ReactionManager.h" -#include "td/telegram/SecretChatLayer.h" -#include "td/telegram/SecretChatsManager.h" #include "td/telegram/ServerMessageId.h" -#include "td/telegram/StickerPhotoSize.h" #include "td/telegram/StickersManager.h" #include "td/telegram/StoryManager.h" #include "td/telegram/SuggestedAction.h" @@ -67,13 +42,14 @@ #include "td/telegram/telegram_api.h" #include "td/telegram/ThemeManager.h" #include "td/telegram/UpdatesManager.h" -#include "td/telegram/Version.h" +#include "td/telegram/UserManager.h" #include "td/db/binlog/BinlogEvent.h" #include "td/db/binlog/BinlogHelper.h" #include "td/db/SqliteKeyValue.h" #include "td/db/SqliteKeyValueAsync.h" +#include "td/actor/MultiPromise.h" #include "td/actor/SleepActor.h" #include "td/utils/algorithm.h" @@ -81,7 +57,6 @@ #include "td/utils/format.h" #include "td/utils/logging.h" #include "td/utils/misc.h" -#include "td/utils/Random.h" #include "td/utils/ScopeGuard.h" #include "td/utils/Slice.h" #include "td/utils/SliceBuilder.h" @@ -90,1043 +65,11 @@ #include "td/utils/tl_helpers.h" #include "td/utils/utf8.h" -#include #include -#include -#include -#include #include namespace td { -class GetContactsQuery final : public Td::ResultHandler { - public: - void send(int64 hash) { - send_query(G()->net_query_creator().create(telegram_api::contacts_getContacts(hash))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for GetContactsQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_contacts(std::move(ptr)); - } - - void on_error(Status status) final { - td_->contacts_manager_->on_get_contacts_failed(std::move(status)); - } -}; - -class GetContactsBirthdaysQuery final : public Td::ResultHandler { - public: - void send() { - send_query(G()->net_query_creator().create(telegram_api::contacts_getBirthdays())); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for GetContactsBirthdaysQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_contact_birthdates(std::move(ptr)); - } - - void on_error(Status status) final { - td_->contacts_manager_->on_get_contact_birthdates(nullptr); - } -}; - -class GetContactsStatusesQuery final : public Td::ResultHandler { - public: - void send() { - send_query(G()->net_query_creator().create(telegram_api::contacts_getStatuses())); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - td_->contacts_manager_->on_get_contacts_statuses(result_ptr.move_as_ok()); - } - - void on_error(Status status) final { - if (!G()->is_expected_error(status)) { - LOG(ERROR) << "Receive error for GetContactsStatusesQuery: " << status; - } - } -}; - -class AddContactQuery final : public Td::ResultHandler { - Promise promise_; - UserId user_id_; - - public: - explicit AddContactQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(UserId user_id, tl_object_ptr &&input_user, const Contact &contact, - bool share_phone_number) { - user_id_ = user_id; - int32 flags = 0; - if (share_phone_number) { - flags |= telegram_api::contacts_addContact::ADD_PHONE_PRIVACY_EXCEPTION_MASK; - } - send_query(G()->net_query_creator().create( - telegram_api::contacts_addContact(flags, false /*ignored*/, std::move(input_user), contact.get_first_name(), - contact.get_last_name(), contact.get_phone_number()), - {{DialogId(user_id)}})); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for AddContactQuery: " << to_string(ptr); - td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - td_->contacts_manager_->reload_contacts(true); - td_->messages_manager_->reget_dialog_action_bar(DialogId(user_id_), "AddContactQuery"); - } -}; - -class EditCloseFriendsQuery final : public Td::ResultHandler { - Promise promise_; - vector user_ids_; - - public: - explicit EditCloseFriendsQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(vector user_ids) { - user_ids_ = std::move(user_ids); - send_query(G()->net_query_creator().create( - telegram_api::contacts_editCloseFriends(UserId::get_input_user_ids(user_ids_)))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - td_->contacts_manager_->on_set_close_friends(user_ids_, std::move(promise_)); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - -class ResolvePhoneQuery final : public Td::ResultHandler { - Promise promise_; - string phone_number_; - - public: - explicit ResolvePhoneQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(const string &phone_number) { - phone_number_ = phone_number; - send_query(G()->net_query_creator().create(telegram_api::contacts_resolvePhone(phone_number))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto ptr = result_ptr.move_as_ok(); - LOG(DEBUG) << "Receive result for ResolvePhoneQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "ResolvePhoneQuery"); - td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "ResolvePhoneQuery"); - - DialogId dialog_id(ptr->peer_); - if (dialog_id.get_type() != DialogType::User) { - LOG(ERROR) << "Receive " << dialog_id << " by " << phone_number_; - return on_error(Status::Error(500, "Receive invalid response")); - } - - td_->contacts_manager_->on_resolved_phone_number(phone_number_, dialog_id.get_user_id()); - - promise_.set_value(Unit()); - } - - void on_error(Status status) final { - if (status.message() == Slice("PHONE_NOT_OCCUPIED")) { - td_->contacts_manager_->on_resolved_phone_number(phone_number_, UserId()); - return promise_.set_value(Unit()); - } - promise_.set_error(std::move(status)); - } -}; - -class AcceptContactQuery final : public Td::ResultHandler { - Promise promise_; - UserId user_id_; - - public: - explicit AcceptContactQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(UserId user_id, tl_object_ptr &&input_user) { - user_id_ = user_id; - send_query(G()->net_query_creator().create(telegram_api::contacts_acceptContact(std::move(input_user)))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for AcceptContactQuery: " << to_string(ptr); - td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - td_->contacts_manager_->reload_contacts(true); - td_->messages_manager_->reget_dialog_action_bar(DialogId(user_id_), "AcceptContactQuery"); - } -}; - -class ImportContactsQuery final : public Td::ResultHandler { - int64 random_id_ = 0; - size_t sent_size_ = 0; - - public: - void send(vector> &&input_phone_contacts, int64 random_id) { - random_id_ = random_id; - sent_size_ = input_phone_contacts.size(); - send_query(G()->net_query_creator().create(telegram_api::contacts_importContacts(std::move(input_phone_contacts)))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for ImportContactsQuery: " << to_string(ptr); - if (sent_size_ == ptr->retry_contacts_.size()) { - return on_error(Status::Error(429, "Too Many Requests: retry after 3600")); - } - td_->contacts_manager_->on_imported_contacts(random_id_, std::move(ptr)); - } - - void on_error(Status status) final { - td_->contacts_manager_->on_imported_contacts(random_id_, std::move(status)); - } -}; - -class DeleteContactsQuery final : public Td::ResultHandler { - Promise promise_; - - public: - explicit DeleteContactsQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(vector> &&input_users) { - send_query(G()->net_query_creator().create(telegram_api::contacts_deleteContacts(std::move(input_users)))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for DeleteContactsQuery: " << to_string(ptr); - td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - td_->contacts_manager_->reload_contacts(true); - } -}; - -class DeleteContactsByPhoneNumberQuery final : public Td::ResultHandler { - Promise promise_; - vector user_ids_; - - public: - explicit DeleteContactsByPhoneNumberQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(vector &&user_phone_numbers, vector &&user_ids) { - if (user_phone_numbers.empty()) { - return promise_.set_value(Unit()); - } - user_ids_ = std::move(user_ids); - send_query(G()->net_query_creator().create(telegram_api::contacts_deleteByPhones(std::move(user_phone_numbers)))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - bool result = result_ptr.ok(); - if (!result) { - return on_error(Status::Error(500, "Some contacts can't be deleted")); - } - - td_->contacts_manager_->on_deleted_contacts(user_ids_); - promise_.set_value(Unit()); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - td_->contacts_manager_->reload_contacts(true); - } -}; - -class ResetContactsQuery final : public Td::ResultHandler { - Promise promise_; - - public: - explicit ResetContactsQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send() { - send_query(G()->net_query_creator().create(telegram_api::contacts_resetSaved())); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - bool result = result_ptr.ok(); - if (!result) { - LOG(ERROR) << "Failed to delete imported contacts"; - td_->contacts_manager_->reload_contacts(true); - } else { - td_->contacts_manager_->on_update_contacts_reset(); - } - - promise_.set_value(Unit()); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - td_->contacts_manager_->reload_contacts(true); - } -}; - -class UploadProfilePhotoQuery final : public Td::ResultHandler { - Promise promise_; - UserId user_id_; - FileId file_id_; - bool is_fallback_; - bool only_suggest_; - - public: - explicit UploadProfilePhotoQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(UserId user_id, FileId file_id, tl_object_ptr &&input_file, bool is_fallback, - bool only_suggest, bool is_animation, double main_frame_timestamp) { - CHECK(input_file != nullptr); - CHECK(file_id.is_valid()); - - user_id_ = user_id; - file_id_ = file_id; - is_fallback_ = is_fallback; - only_suggest_ = only_suggest; - - static_assert(static_cast(telegram_api::photos_uploadProfilePhoto::VIDEO_MASK) == - static_cast(telegram_api::photos_uploadContactProfilePhoto::VIDEO_MASK), - ""); - static_assert(static_cast(telegram_api::photos_uploadProfilePhoto::VIDEO_START_TS_MASK) == - static_cast(telegram_api::photos_uploadContactProfilePhoto::VIDEO_START_TS_MASK), - ""); - static_assert(static_cast(telegram_api::photos_uploadProfilePhoto::FILE_MASK) == - static_cast(telegram_api::photos_uploadContactProfilePhoto::FILE_MASK), - ""); - - int32 flags = 0; - tl_object_ptr photo_input_file; - tl_object_ptr video_input_file; - if (is_animation) { - flags |= telegram_api::photos_uploadProfilePhoto::VIDEO_MASK; - video_input_file = std::move(input_file); - - if (main_frame_timestamp != 0.0) { - flags |= telegram_api::photos_uploadProfilePhoto::VIDEO_START_TS_MASK; - } - } else { - flags |= telegram_api::photos_uploadProfilePhoto::FILE_MASK; - photo_input_file = std::move(input_file); - } - if (td_->contacts_manager_->is_user_bot(user_id)) { - auto r_input_user = td_->contacts_manager_->get_input_user(user_id); - if (r_input_user.is_error()) { - return on_error(r_input_user.move_as_error()); - } - flags |= telegram_api::photos_uploadProfilePhoto::BOT_MASK; - send_query(G()->net_query_creator().create( - telegram_api::photos_uploadProfilePhoto(flags, false /*ignored*/, r_input_user.move_as_ok(), - std::move(photo_input_file), std::move(video_input_file), - main_frame_timestamp, nullptr), - {{user_id}})); - } else if (user_id == td_->contacts_manager_->get_my_id()) { - if (is_fallback) { - flags |= telegram_api::photos_uploadProfilePhoto::FALLBACK_MASK; - } - send_query(G()->net_query_creator().create( - telegram_api::photos_uploadProfilePhoto(flags, false /*ignored*/, nullptr, std::move(photo_input_file), - std::move(video_input_file), main_frame_timestamp, nullptr), - {{"me"}})); - } else { - if (only_suggest) { - flags |= telegram_api::photos_uploadContactProfilePhoto::SUGGEST_MASK; - } else { - flags |= telegram_api::photos_uploadContactProfilePhoto::SAVE_MASK; - } - auto r_input_user = td_->contacts_manager_->get_input_user(user_id); - if (r_input_user.is_error()) { - return on_error(r_input_user.move_as_error()); - } - send_query(G()->net_query_creator().create( - telegram_api::photos_uploadContactProfilePhoto(flags, false /*ignored*/, false /*ignored*/, - r_input_user.move_as_ok(), std::move(photo_input_file), - std::move(video_input_file), main_frame_timestamp, nullptr), - {{user_id}})); - } - } - - void send(UserId user_id, unique_ptr sticker_photo_size, bool is_fallback, bool only_suggest) { - CHECK(sticker_photo_size != nullptr); - user_id_ = user_id; - file_id_ = FileId(); - is_fallback_ = is_fallback; - only_suggest_ = only_suggest; - - if (td_->contacts_manager_->is_user_bot(user_id)) { - auto r_input_user = td_->contacts_manager_->get_input_user(user_id); - if (r_input_user.is_error()) { - return on_error(r_input_user.move_as_error()); - } - int32 flags = telegram_api::photos_uploadProfilePhoto::VIDEO_EMOJI_MARKUP_MASK; - flags |= telegram_api::photos_uploadProfilePhoto::BOT_MASK; - send_query(G()->net_query_creator().create( - telegram_api::photos_uploadProfilePhoto(flags, false /*ignored*/, r_input_user.move_as_ok(), nullptr, nullptr, - 0.0, sticker_photo_size->get_input_video_size_object(td_)), - {{user_id}})); - } else if (user_id == td_->contacts_manager_->get_my_id()) { - int32 flags = telegram_api::photos_uploadProfilePhoto::VIDEO_EMOJI_MARKUP_MASK; - if (is_fallback) { - flags |= telegram_api::photos_uploadProfilePhoto::FALLBACK_MASK; - } - send_query(G()->net_query_creator().create( - telegram_api::photos_uploadProfilePhoto(flags, false /*ignored*/, nullptr, nullptr, nullptr, 0.0, - sticker_photo_size->get_input_video_size_object(td_)), - {{"me"}})); - } else { - int32 flags = telegram_api::photos_uploadContactProfilePhoto::VIDEO_EMOJI_MARKUP_MASK; - if (only_suggest) { - flags |= telegram_api::photos_uploadContactProfilePhoto::SUGGEST_MASK; - } else { - flags |= telegram_api::photos_uploadContactProfilePhoto::SAVE_MASK; - } - auto r_input_user = td_->contacts_manager_->get_input_user(user_id); - if (r_input_user.is_error()) { - return on_error(r_input_user.move_as_error()); - } - send_query(G()->net_query_creator().create( - telegram_api::photos_uploadContactProfilePhoto(flags, false /*ignored*/, false /*ignored*/, - r_input_user.move_as_ok(), nullptr, nullptr, 0.0, - sticker_photo_size->get_input_video_size_object(td_)), - {{user_id}})); - } - } - - void on_result(BufferSlice packet) final { - static_assert(std::is_same::value, - ""); - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - if (!only_suggest_) { - td_->contacts_manager_->on_set_profile_photo(user_id_, result_ptr.move_as_ok(), is_fallback_, 0, - std::move(promise_)); - } else { - promise_.set_value(Unit()); - } - - if (file_id_.is_valid()) { - td_->file_manager_->delete_partial_remote_location(file_id_); - } - } - - void on_error(Status status) final { - if (file_id_.is_valid()) { - td_->file_manager_->delete_partial_remote_location(file_id_); - } - promise_.set_error(std::move(status)); - } -}; - -class UpdateProfilePhotoQuery final : public Td::ResultHandler { - Promise promise_; - UserId user_id_; - FileId file_id_; - int64 old_photo_id_; - bool is_fallback_; - string file_reference_; - - public: - explicit UpdateProfilePhotoQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(UserId user_id, FileId file_id, int64 old_photo_id, bool is_fallback, - tl_object_ptr &&input_photo) { - CHECK(input_photo != nullptr); - user_id_ = user_id; - file_id_ = file_id; - old_photo_id_ = old_photo_id; - is_fallback_ = is_fallback; - file_reference_ = FileManager::extract_file_reference(input_photo); - int32 flags = 0; - if (is_fallback) { - flags |= telegram_api::photos_updateProfilePhoto::FALLBACK_MASK; - } - if (td_->contacts_manager_->is_user_bot(user_id)) { - auto r_input_user = td_->contacts_manager_->get_input_user(user_id); - if (r_input_user.is_error()) { - return on_error(r_input_user.move_as_error()); - } - flags |= telegram_api::photos_updateProfilePhoto::BOT_MASK; - send_query(G()->net_query_creator().create( - telegram_api::photos_updateProfilePhoto(flags, false /*ignored*/, r_input_user.move_as_ok(), - std::move(input_photo)), - {{user_id}})); - } else { - send_query(G()->net_query_creator().create( - telegram_api::photos_updateProfilePhoto(flags, false /*ignored*/, nullptr, std::move(input_photo)), - {{"me"}})); - } - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - td_->contacts_manager_->on_set_profile_photo(user_id_, result_ptr.move_as_ok(), is_fallback_, old_photo_id_, - std::move(promise_)); - } - - void on_error(Status status) final { - if (!td_->auth_manager_->is_bot() && FileReferenceManager::is_file_reference_error(status)) { - if (file_id_.is_valid()) { - VLOG(file_references) << "Receive " << status << " for " << file_id_; - td_->file_manager_->delete_file_reference(file_id_, file_reference_); - td_->file_reference_manager_->repair_file_reference( - file_id_, PromiseCreator::lambda([user_id = user_id_, file_id = file_id_, is_fallback = is_fallback_, - old_photo_id = old_photo_id_, - promise = std::move(promise_)](Result result) mutable { - if (result.is_error()) { - return promise.set_error(Status::Error(400, "Can't find the photo")); - } - - send_closure(G()->contacts_manager(), &ContactsManager::send_update_profile_photo_query, user_id, file_id, - old_photo_id, is_fallback, std::move(promise)); - })); - return; - } else { - LOG(ERROR) << "Receive file reference error, but file_id = " << file_id_; - } - } - - promise_.set_error(std::move(status)); - } -}; - -class DeleteContactProfilePhotoQuery final : public Td::ResultHandler { - Promise promise_; - UserId user_id_; - - public: - explicit DeleteContactProfilePhotoQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(UserId user_id, tl_object_ptr &&input_user) { - CHECK(input_user != nullptr); - user_id_ = user_id; - - int32 flags = 0; - flags |= telegram_api::photos_uploadContactProfilePhoto::SAVE_MASK; - send_query(G()->net_query_creator().create( - telegram_api::photos_uploadContactProfilePhoto(flags, false /*ignored*/, false /*ignored*/, - std::move(input_user), nullptr, nullptr, 0, nullptr), - {{user_id}})); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto ptr = result_ptr.move_as_ok(); - ptr->photo_ = nullptr; - td_->contacts_manager_->on_set_profile_photo(user_id_, std::move(ptr), false, 0, std::move(promise_)); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - -class DeleteProfilePhotoQuery final : public Td::ResultHandler { - Promise promise_; - int64 profile_photo_id_; - - public: - explicit DeleteProfilePhotoQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(int64 profile_photo_id) { - profile_photo_id_ = profile_photo_id; - vector> input_photo_ids; - input_photo_ids.push_back(make_tl_object(profile_photo_id, 0, BufferSlice())); - send_query(G()->net_query_creator().create(telegram_api::photos_deletePhotos(std::move(input_photo_ids)))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto result = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for DeleteProfilePhotoQuery: " << format::as_array(result); - if (result.size() != 1u) { - LOG(WARNING) << "Photo can't be deleted"; - return on_error(Status::Error(400, "Photo can't be deleted")); - } - - td_->contacts_manager_->on_delete_profile_photo(profile_photo_id_, std::move(promise_)); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - -class UpdateColorQuery final : public Td::ResultHandler { - Promise promise_; - bool for_profile_; - AccentColorId accent_color_id_; - CustomEmojiId background_custom_emoji_id_; - - public: - explicit UpdateColorQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(bool for_profile, AccentColorId accent_color_id, CustomEmojiId background_custom_emoji_id) { - for_profile_ = for_profile; - accent_color_id_ = accent_color_id; - background_custom_emoji_id_ = background_custom_emoji_id; - int32 flags = 0; - if (for_profile) { - flags |= telegram_api::account_updateColor::FOR_PROFILE_MASK; - } - if (accent_color_id.is_valid()) { - flags |= telegram_api::account_updateColor::COLOR_MASK; - } - if (background_custom_emoji_id.is_valid()) { - flags |= telegram_api::account_updateColor::BACKGROUND_EMOJI_ID_MASK; - } - send_query(G()->net_query_creator().create( - telegram_api::account_updateColor(flags, false /*ignored*/, accent_color_id.get(), - background_custom_emoji_id.get()), - {{"me"}})); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - LOG(DEBUG) << "Receive result for UpdateColorQuery: " << result_ptr.ok(); - td_->contacts_manager_->on_update_accent_color_success(for_profile_, accent_color_id_, background_custom_emoji_id_); - promise_.set_value(Unit()); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - -class UpdateProfileQuery final : public Td::ResultHandler { - Promise promise_; - int32 flags_; - string first_name_; - string last_name_; - string about_; - - public: - explicit UpdateProfileQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(int32 flags, const string &first_name, const string &last_name, const string &about) { - flags_ = flags; - first_name_ = first_name; - last_name_ = last_name; - about_ = about; - send_query(G()->net_query_creator().create(telegram_api::account_updateProfile(flags, first_name, last_name, about), - {{"me"}})); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - LOG(DEBUG) << "Receive result for UpdateProfileQuery: " << to_string(result_ptr.ok()); - td_->contacts_manager_->on_get_user(result_ptr.move_as_ok(), "UpdateProfileQuery"); - td_->contacts_manager_->on_update_profile_success(flags_, first_name_, last_name_, about_); - - promise_.set_value(Unit()); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - -class UpdateUsernameQuery final : public Td::ResultHandler { - Promise promise_; - - public: - explicit UpdateUsernameQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(const string &username) { - send_query(G()->net_query_creator().create(telegram_api::account_updateUsername(username), {{"me"}})); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - LOG(DEBUG) << "Receive result for UpdateUsernameQuery: " << to_string(result_ptr.ok()); - td_->contacts_manager_->on_get_user(result_ptr.move_as_ok(), "UpdateUsernameQuery"); - promise_.set_value(Unit()); - } - - void on_error(Status status) final { - if (status.message() == "USERNAME_NOT_MODIFIED" && !td_->auth_manager_->is_bot()) { - promise_.set_value(Unit()); - return; - } - promise_.set_error(std::move(status)); - } -}; - -class ToggleUsernameQuery final : public Td::ResultHandler { - Promise promise_; - string username_; - bool is_active_; - - public: - explicit ToggleUsernameQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(string &&username, bool is_active) { - username_ = std::move(username); - is_active_ = is_active; - send_query(G()->net_query_creator().create(telegram_api::account_toggleUsername(username_, is_active_), {{"me"}})); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - bool result = result_ptr.ok(); - LOG(DEBUG) << "Receive result for ToggleUsernameQuery: " << result; - td_->contacts_manager_->on_update_username_is_active(td_->contacts_manager_->get_my_id(), std::move(username_), - is_active_, std::move(promise_)); - } - - void on_error(Status status) final { - if (status.message() == "USERNAME_NOT_MODIFIED") { - td_->contacts_manager_->on_update_username_is_active(td_->contacts_manager_->get_my_id(), std::move(username_), - is_active_, std::move(promise_)); - return; - } - promise_.set_error(std::move(status)); - } -}; - -class ReorderUsernamesQuery final : public Td::ResultHandler { - Promise promise_; - vector usernames_; - - public: - explicit ReorderUsernamesQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(vector &&usernames) { - usernames_ = usernames; - send_query(G()->net_query_creator().create(telegram_api::account_reorderUsernames(std::move(usernames)), {{"me"}})); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - bool result = result_ptr.ok(); - LOG(DEBUG) << "Receive result for ReorderUsernamesQuery: " << result; - if (!result) { - return on_error(Status::Error(500, "Usernames weren't updated")); - } - - td_->contacts_manager_->on_update_active_usernames_order(td_->contacts_manager_->get_my_id(), std::move(usernames_), - std::move(promise_)); - } - - void on_error(Status status) final { - if (status.message() == "USERNAME_NOT_MODIFIED") { - td_->contacts_manager_->on_update_active_usernames_order(td_->contacts_manager_->get_my_id(), - std::move(usernames_), std::move(promise_)); - return; - } - promise_.set_error(std::move(status)); - } -}; - -class ToggleBotUsernameQuery final : public Td::ResultHandler { - Promise promise_; - UserId bot_user_id_; - string username_; - bool is_active_; - - public: - explicit ToggleBotUsernameQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(UserId bot_user_id, string &&username, bool is_active) { - bot_user_id_ = bot_user_id; - username_ = std::move(username); - is_active_ = is_active; - auto r_input_user = td_->contacts_manager_->get_input_user(bot_user_id_); - if (r_input_user.is_error()) { - return on_error(r_input_user.move_as_error()); - } - send_query(G()->net_query_creator().create( - telegram_api::bots_toggleUsername(r_input_user.move_as_ok(), username_, is_active_), {{bot_user_id_}})); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - bool result = result_ptr.ok(); - LOG(DEBUG) << "Receive result for ToggleBotUsernameQuery: " << result; - td_->contacts_manager_->on_update_username_is_active(bot_user_id_, std::move(username_), is_active_, - std::move(promise_)); - } - - void on_error(Status status) final { - if (status.message() == "USERNAME_NOT_MODIFIED") { - td_->contacts_manager_->on_update_username_is_active(bot_user_id_, std::move(username_), is_active_, - std::move(promise_)); - return; - } - promise_.set_error(std::move(status)); - } -}; - -class ReorderBotUsernamesQuery final : public Td::ResultHandler { - Promise promise_; - UserId bot_user_id_; - vector usernames_; - - public: - explicit ReorderBotUsernamesQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(UserId bot_user_id, vector &&usernames) { - bot_user_id_ = bot_user_id; - usernames_ = usernames; - auto r_input_user = td_->contacts_manager_->get_input_user(bot_user_id_); - if (r_input_user.is_error()) { - return on_error(r_input_user.move_as_error()); - } - send_query(G()->net_query_creator().create( - telegram_api::bots_reorderUsernames(r_input_user.move_as_ok(), std::move(usernames)), {{bot_user_id_}})); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - bool result = result_ptr.ok(); - LOG(DEBUG) << "Receive result for ReorderBotUsernamesQuery: " << result; - if (!result) { - return on_error(Status::Error(500, "Usernames weren't updated")); - } - - td_->contacts_manager_->on_update_active_usernames_order(bot_user_id_, std::move(usernames_), std::move(promise_)); - } - - void on_error(Status status) final { - if (status.message() == "USERNAME_NOT_MODIFIED") { - td_->contacts_manager_->on_update_active_usernames_order(bot_user_id_, std::move(usernames_), - std::move(promise_)); - return; - } - promise_.set_error(std::move(status)); - } -}; - -class UpdateBirthdayQuery final : public Td::ResultHandler { - Promise promise_; - - public: - explicit UpdateBirthdayQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(const Birthdate &birthdate) { - int32 flags = 0; - if (!birthdate.is_empty()) { - flags |= telegram_api::account_updateBirthday::BIRTHDAY_MASK; - } - send_query(G()->net_query_creator().create( - telegram_api::account_updateBirthday(flags, birthdate.get_input_birthday()), {{"me"}})); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - LOG(DEBUG) << "Receive result for UpdateBirthdayQuery: " << result_ptr.ok(); - if (result_ptr.ok()) { - promise_.set_value(Unit()); - } else { - promise_.set_error(Status::Error(400, "Failed to change birthdate")); - } - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - -class UpdatePersonalChannelQuery final : public Td::ResultHandler { - Promise promise_; - - public: - explicit UpdatePersonalChannelQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(ChannelId channel_id) { - telegram_api::object_ptr input_channel; - if (channel_id == ChannelId()) { - input_channel = telegram_api::make_object(); - } else { - input_channel = td_->contacts_manager_->get_input_channel(channel_id); - CHECK(input_channel != nullptr); - } - send_query(G()->net_query_creator().create(telegram_api::account_updatePersonalChannel(std::move(input_channel)), - {{"me"}})); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - LOG(DEBUG) << "Receive result for UpdatePersonalChannelQuery: " << result_ptr.ok(); - if (result_ptr.ok()) { - promise_.set_value(Unit()); - } else { - promise_.set_error(Status::Error(400, "Failed to change personal chat")); - } - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - -class UpdateEmojiStatusQuery final : public Td::ResultHandler { - Promise promise_; - - public: - explicit UpdateEmojiStatusQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(const EmojiStatus &emoji_status) { - send_query(G()->net_query_creator().create( - telegram_api::account_updateEmojiStatus(emoji_status.get_input_emoji_status()), {{"me"}})); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - LOG(DEBUG) << "Receive result for UpdateEmojiStatusQuery: " << result_ptr.ok(); - if (result_ptr.ok()) { - promise_.set_value(Unit()); - } else { - promise_.set_error(Status::Error(400, "Failed to change Premium badge")); - } - } - - void on_error(Status status) final { - get_recent_emoji_statuses(td_, Auto()); - promise_.set_error(std::move(status)); - } -}; - class CreateChatQuery final : public Td::ResultHandler { Promise> promise_; @@ -2426,7 +1369,7 @@ class GetInactiveChannelsQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetInactiveChannelsQuery: " << to_string(result); // don't need to use result->dates_, because chat.last_message.date is more reliable - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetInactiveChannelsQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetInactiveChannelsQuery"); td_->contacts_manager_->on_get_inactive_channels(std::move(result->chats_), std::move(promise_)); } @@ -2435,114 +1378,6 @@ class GetInactiveChannelsQuery final : public Td::ResultHandler { } }; -class GetUsersQuery final : public Td::ResultHandler { - Promise promise_; - - public: - explicit GetUsersQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(vector> &&input_users) { - send_query(G()->net_query_creator().create(telegram_api::users_getUsers(std::move(input_users)))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - td_->contacts_manager_->on_get_users(result_ptr.move_as_ok(), "GetUsersQuery"); - - promise_.set_value(Unit()); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - -class GetFullUserQuery final : public Td::ResultHandler { - Promise promise_; - - public: - explicit GetFullUserQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(tl_object_ptr &&input_user) { - send_query(G()->net_query_creator().create(telegram_api::users_getFullUser(std::move(input_user)))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto ptr = result_ptr.move_as_ok(); - LOG(DEBUG) << "Receive result for GetFullUserQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetFullUserQuery"); - td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetFullUserQuery"); - td_->contacts_manager_->on_get_user_full(std::move(ptr->full_user_)); - promise_.set_value(Unit()); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - -class GetUserPhotosQuery final : public Td::ResultHandler { - Promise promise_; - UserId user_id_; - int32 offset_; - int32 limit_; - - public: - explicit GetUserPhotosQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(UserId user_id, tl_object_ptr &&input_user, int32 offset, int32 limit, - int64 photo_id) { - user_id_ = user_id; - offset_ = offset; - limit_ = limit; - send_query(G()->net_query_creator().create( - telegram_api::photos_getUserPhotos(std::move(input_user), offset, photo_id, limit))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto ptr = result_ptr.move_as_ok(); - - LOG(INFO) << "Receive result for GetUserPhotosQuery: " << to_string(ptr); - int32 constructor_id = ptr->get_id(); - if (constructor_id == telegram_api::photos_photos::ID) { - auto photos = move_tl_object_as(ptr); - - td_->contacts_manager_->on_get_users(std::move(photos->users_), "GetUserPhotosQuery"); - auto photos_size = narrow_cast(photos->photos_.size()); - td_->contacts_manager_->on_get_user_photos(user_id_, offset_, limit_, photos_size, std::move(photos->photos_)); - } else { - CHECK(constructor_id == telegram_api::photos_photosSlice::ID); - auto photos = move_tl_object_as(ptr); - - td_->contacts_manager_->on_get_users(std::move(photos->users_), "GetUserPhotosQuery slice"); - td_->contacts_manager_->on_get_user_photos(user_id_, offset_, limit_, photos->count_, std::move(photos->photos_)); - } - - promise_.set_value(Unit()); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - class GetChatsQuery final : public Td::ResultHandler { Promise promise_; @@ -2604,7 +1439,7 @@ class GetFullChatQuery final : public Td::ResultHandler { } auto ptr = result_ptr.move_as_ok(); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetFullChatQuery"); + td_->user_manager_->on_get_users(std::move(ptr->users_), "GetFullChatQuery"); td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetFullChatQuery"); td_->contacts_manager_->on_get_chat_full(std::move(ptr->full_chat_), std::move(promise_)); } @@ -2690,7 +1525,7 @@ class GetFullChannelQuery final : public Td::ResultHandler { } auto ptr = result_ptr.move_as_ok(); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetFullChannelQuery"); + td_->user_manager_->on_get_users(std::move(ptr->users_), "GetFullChannelQuery"); td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetFullChannelQuery"); td_->contacts_manager_->on_get_chat_full(std::move(ptr->full_chat_), std::move(promise_)); } @@ -2702,122 +1537,7 @@ class GetFullChannelQuery final : public Td::ResultHandler { } }; -class GetSupportUserQuery final : public Td::ResultHandler { - Promise promise_; - - public: - explicit GetSupportUserQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send() { - send_query(G()->net_query_creator().create(telegram_api::help_getSupport())); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for GetSupportUserQuery: " << to_string(ptr); - - auto user_id = ContactsManager::get_user_id(ptr->user_); - td_->contacts_manager_->on_get_user(std::move(ptr->user_), "GetSupportUserQuery"); - - promise_.set_value(std::move(user_id)); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - -class GetIsPremiumRequiredToContactQuery final : public Td::ResultHandler { - Promise promise_; - vector user_ids_; - - public: - explicit GetIsPremiumRequiredToContactQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(vector &&user_ids, vector> &&input_users) { - user_ids_ = std::move(user_ids); - send_query( - G()->net_query_creator().create(telegram_api::users_getIsPremiumRequiredToContact(std::move(input_users)))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - td_->contacts_manager_->on_get_is_premium_required_to_contact_users(std::move(user_ids_), result_ptr.move_as_ok(), - std::move(promise_)); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - -class ContactsManager::UploadProfilePhotoCallback final : public FileManager::UploadCallback { - public: - void on_upload_ok(FileId file_id, tl_object_ptr input_file) final { - send_closure_later(G()->contacts_manager(), &ContactsManager::on_upload_profile_photo, file_id, - std::move(input_file)); - } - void on_upload_encrypted_ok(FileId file_id, tl_object_ptr input_file) final { - UNREACHABLE(); - } - void on_upload_secure_ok(FileId file_id, tl_object_ptr input_file) final { - UNREACHABLE(); - } - void on_upload_error(FileId file_id, Status error) final { - send_closure_later(G()->contacts_manager(), &ContactsManager::on_upload_profile_photo_error, file_id, - std::move(error)); - } -}; - ContactsManager::ContactsManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { - upload_profile_photo_callback_ = std::make_shared(); - - my_id_ = load_my_id(); - - if (G()->use_chat_info_database()) { - auto next_contacts_sync_date_string = G()->td_db()->get_binlog_pmc()->get("next_contacts_sync_date"); - if (!next_contacts_sync_date_string.empty()) { - next_contacts_sync_date_ = min(to_integer(next_contacts_sync_date_string), G()->unix_time() + 100000); - } - - auto saved_contact_count_string = G()->td_db()->get_binlog_pmc()->get("saved_contact_count"); - if (!saved_contact_count_string.empty()) { - saved_contact_count_ = to_integer(saved_contact_count_string); - } - } else if (!td_->auth_manager_->is_bot()) { - G()->td_db()->get_binlog_pmc()->erase("next_contacts_sync_date"); - G()->td_db()->get_binlog_pmc()->erase("saved_contact_count"); - } - if (G()->use_sqlite_pmc()) { - G()->td_db()->get_sqlite_pmc()->erase_by_prefix("us_bot_info", Auto()); - } - - if (!td_->auth_manager_->is_bot()) { - was_online_local_ = to_integer(G()->td_db()->get_binlog_pmc()->get("my_was_online_local")); - was_online_remote_ = to_integer(G()->td_db()->get_binlog_pmc()->get("my_was_online_remote")); - auto unix_time = G()->unix_time(); - if (was_online_local_ >= unix_time && !td_->is_online()) { - was_online_local_ = unix_time - 1; - } - } - - user_online_timeout_.set_callback(on_user_online_timeout_callback); - user_online_timeout_.set_callback_data(static_cast(this)); - - user_emoji_status_timeout_.set_callback(on_user_emoji_status_timeout_callback); - user_emoji_status_timeout_.set_callback_data(static_cast(this)); - channel_emoji_status_timeout_.set_callback(on_channel_emoji_status_timeout_callback); channel_emoji_status_timeout_.set_callback_data(static_cast(this)); @@ -2827,11 +1547,6 @@ ContactsManager::ContactsManager(Td *td, ActorShared<> parent) : td_(td), parent slow_mode_delay_timeout_.set_callback(on_slow_mode_delay_timeout_callback); slow_mode_delay_timeout_.set_callback_data(static_cast(this)); - get_user_queries_.set_merge_function([this](vector query_ids, Promise &&promise) { - TRY_STATUS_PROMISE(promise, G()->close_status()); - auto input_users = transform(query_ids, [this](int64 query_id) { return get_input_user_force(UserId(query_id)); }); - td_->create_handler(std::move(promise))->send(std::move(input_users)); - }); get_chat_queries_.set_merge_function([this](vector query_ids, Promise &&promise) { TRY_STATUS_PROMISE(promise, G()->close_status()); td_->create_handler(std::move(promise))->send(std::move(query_ids)); @@ -2845,105 +1560,24 @@ ContactsManager::ContactsManager(Td *td, ActorShared<> parent) : td_(td), parent } td_->create_handler(std::move(promise))->send(std::move(input_channel)); }); - get_is_premium_required_to_contact_queries_.set_merge_function( - [this](vector query_ids, Promise &&promise) { - TRY_STATUS_PROMISE(promise, G()->close_status()); - auto user_ids = UserId::get_user_ids(query_ids); - auto input_users = transform(user_ids, [this](UserId user_id) { return get_input_user_force(user_id); }); - td_->create_handler(std::move(promise)) - ->send(std::move(user_ids), std::move(input_users)); - }); } ContactsManager::~ContactsManager() { Scheduler::instance()->destroy_on_scheduler( - G()->get_gc_scheduler_id(), users_, users_full_, user_photos_, unknown_users_, pending_user_photos_, - user_profile_photo_file_source_ids_, my_photo_file_id_, user_full_file_source_ids_, chats_, chats_full_, - unknown_chats_, chat_full_file_source_ids_, min_channels_, channels_, channels_full_, unknown_channels_, - invalidated_channels_full_, channel_full_file_source_ids_, secret_chats_, unknown_secret_chats_, - secret_chats_with_user_); - Scheduler::instance()->destroy_on_scheduler( - G()->get_gc_scheduler_id(), loaded_from_database_users_, unavailable_user_fulls_, loaded_from_database_chats_, - unavailable_chat_fulls_, loaded_from_database_channels_, unavailable_channel_fulls_, - loaded_from_database_secret_chats_, resolved_phone_numbers_, all_imported_contacts_, linked_channel_ids_, - restricted_user_ids_, restricted_channel_ids_); + G()->get_gc_scheduler_id(), chats_, chats_full_, unknown_chats_, chat_full_file_source_ids_, min_channels_, + channels_, channels_full_, unknown_channels_, invalidated_channels_full_, channel_full_file_source_ids_); + Scheduler::instance()->destroy_on_scheduler(G()->get_gc_scheduler_id(), loaded_from_database_chats_, + unavailable_chat_fulls_, loaded_from_database_channels_, + unavailable_channel_fulls_, linked_channel_ids_, restricted_channel_ids_); } void ContactsManager::tear_down() { parent_.reset(); - LOG(DEBUG) << "Have " << users_.calc_size() << " users, " << chats_.calc_size() << " basic groups, " - << channels_.calc_size() << " supergroups and " << secret_chats_.calc_size() << " secret chats to free"; - LOG(DEBUG) << "Have " << users_full_.calc_size() << " full users, " << chats_full_.calc_size() - << " full basic groups and " << channels_full_.calc_size() << " full supergroups to free"; -} - -UserId ContactsManager::load_my_id() { - auto id_string = G()->td_db()->get_binlog_pmc()->get("my_id"); - if (!id_string.empty()) { - UserId my_id(to_integer(id_string)); - if (my_id.is_valid()) { - return my_id; - } - - my_id = UserId(to_integer(Slice(id_string).substr(5))); - if (my_id.is_valid()) { - G()->td_db()->get_binlog_pmc()->set("my_id", to_string(my_id.get())); - return my_id; - } - - LOG(ERROR) << "Wrong my ID = \"" << id_string << "\" stored in database"; - } - return UserId(); -} - -void ContactsManager::on_user_online_timeout_callback(void *contacts_manager_ptr, int64 user_id_long) { - if (G()->close_flag()) { - return; - } - - auto contacts_manager = static_cast(contacts_manager_ptr); - send_closure_later(contacts_manager->actor_id(contacts_manager), &ContactsManager::on_user_online_timeout, - UserId(user_id_long)); -} - -void ContactsManager::on_user_online_timeout(UserId user_id) { - if (G()->close_flag()) { - return; - } - - auto u = get_user(user_id); - CHECK(u != nullptr); - CHECK(u->is_update_user_sent); - - LOG(INFO) << "Update " << user_id << " online status to offline"; - send_closure(G()->td(), &Td::send_update, - td_api::make_object(user_id.get(), - get_user_status_object(user_id, u, G()->unix_time()))); - - td_->dialog_participant_manager_->update_user_online_member_count(user_id); -} - -void ContactsManager::on_user_emoji_status_timeout_callback(void *contacts_manager_ptr, int64 user_id_long) { - if (G()->close_flag()) { - return; - } - - auto contacts_manager = static_cast(contacts_manager_ptr); - send_closure_later(contacts_manager->actor_id(contacts_manager), &ContactsManager::on_user_emoji_status_timeout, - UserId(user_id_long)); -} - -void ContactsManager::on_user_emoji_status_timeout(UserId user_id) { - if (G()->close_flag()) { - return; - } - - auto u = get_user(user_id); - CHECK(u != nullptr); - CHECK(u->is_update_user_sent); - - update_user(u, user_id); + LOG(DEBUG) << "Have " << chats_.calc_size() << " basic groups and " << channels_.calc_size() + << " supergroups to free"; + LOG(DEBUG) << "Have " << chats_full_.calc_size() << " full basic groups and " << channels_full_.calc_size() + << " full supergroups to free"; } void ContactsManager::on_channel_emoji_status_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long) { @@ -3019,516 +1653,6 @@ void ContactsManager::on_slow_mode_delay_timeout(ChannelId channel_id) { on_update_channel_slow_mode_next_send_date(channel_id, 0); } -template -void ContactsManager::User::store(StorerT &storer) const { - using td::store; - bool has_last_name = !last_name.empty(); - bool legacy_has_username = false; - bool has_photo = photo.small_file_id.is_valid(); - bool has_language_code = !language_code.empty(); - bool have_access_hash = access_hash != -1; - bool has_cache_version = cache_version != 0; - bool has_is_contact = true; - bool has_restriction_reasons = !restriction_reasons.empty(); - bool has_emoji_status = !emoji_status.is_empty(); - bool has_usernames = !usernames.is_empty(); - bool has_flags2 = true; - bool has_max_active_story_id = max_active_story_id.is_valid(); - bool has_max_read_story_id = max_read_story_id.is_valid(); - bool has_max_active_story_id_next_reload_time = max_active_story_id_next_reload_time > Time::now(); - bool has_accent_color_id = accent_color_id.is_valid(); - bool has_background_custom_emoji_id = background_custom_emoji_id.is_valid(); - bool has_profile_accent_color_id = profile_accent_color_id.is_valid(); - bool has_profile_background_custom_emoji_id = profile_background_custom_emoji_id.is_valid(); - BEGIN_STORE_FLAGS(); - STORE_FLAG(is_received); - STORE_FLAG(is_verified); - STORE_FLAG(is_deleted); - STORE_FLAG(is_bot); - STORE_FLAG(can_join_groups); - STORE_FLAG(can_read_all_group_messages); - STORE_FLAG(is_inline_bot); - STORE_FLAG(need_location_bot); - STORE_FLAG(has_last_name); - STORE_FLAG(legacy_has_username); - STORE_FLAG(has_photo); - STORE_FLAG(false); // legacy is_restricted - STORE_FLAG(has_language_code); - STORE_FLAG(have_access_hash); - STORE_FLAG(is_support); - STORE_FLAG(is_min_access_hash); - STORE_FLAG(is_scam); - STORE_FLAG(has_cache_version); - STORE_FLAG(has_is_contact); - STORE_FLAG(is_contact); - STORE_FLAG(is_mutual_contact); - STORE_FLAG(has_restriction_reasons); - STORE_FLAG(need_apply_min_photo); - STORE_FLAG(is_fake); - STORE_FLAG(can_be_added_to_attach_menu); - STORE_FLAG(is_premium); - STORE_FLAG(attach_menu_enabled); - STORE_FLAG(has_emoji_status); - STORE_FLAG(has_usernames); - STORE_FLAG(can_be_edited_bot); - END_STORE_FLAGS(); - if (has_flags2) { - BEGIN_STORE_FLAGS(); - STORE_FLAG(is_close_friend); - STORE_FLAG(stories_hidden); - STORE_FLAG(false); - STORE_FLAG(has_max_active_story_id); - STORE_FLAG(has_max_read_story_id); - STORE_FLAG(has_max_active_story_id_next_reload_time); - STORE_FLAG(has_accent_color_id); - STORE_FLAG(has_background_custom_emoji_id); - STORE_FLAG(has_profile_accent_color_id); - STORE_FLAG(has_profile_background_custom_emoji_id); - STORE_FLAG(contact_require_premium); - STORE_FLAG(is_business_bot); - END_STORE_FLAGS(); - } - store(first_name, storer); - if (has_last_name) { - store(last_name, storer); - } - store(phone_number, storer); - if (have_access_hash) { - store(access_hash, storer); - } - if (has_photo) { - store(photo, storer); - } - store(was_online, storer); - if (has_restriction_reasons) { - store(restriction_reasons, storer); - } - if (is_inline_bot) { - store(inline_query_placeholder, storer); - } - if (is_bot) { - store(bot_info_version, storer); - } - if (has_language_code) { - store(language_code, storer); - } - if (has_cache_version) { - store(cache_version, storer); - } - if (has_emoji_status) { - store(emoji_status, storer); - } - if (has_usernames) { - store(usernames, storer); - } - if (has_max_active_story_id) { - store(max_active_story_id, storer); - } - if (has_max_read_story_id) { - store(max_read_story_id, storer); - } - if (has_max_active_story_id_next_reload_time) { - store_time(max_active_story_id_next_reload_time, storer); - } - if (has_accent_color_id) { - store(accent_color_id, storer); - } - if (has_background_custom_emoji_id) { - store(background_custom_emoji_id, storer); - } - if (has_profile_accent_color_id) { - store(profile_accent_color_id, storer); - } - if (has_profile_background_custom_emoji_id) { - store(profile_background_custom_emoji_id, storer); - } -} - -template -void ContactsManager::User::parse(ParserT &parser) { - using td::parse; - bool has_last_name; - bool legacy_has_username; - bool has_photo; - bool legacy_is_restricted; - bool has_language_code; - bool have_access_hash; - bool has_cache_version; - bool has_is_contact; - bool has_restriction_reasons; - bool has_emoji_status; - bool has_usernames; - bool has_flags2 = parser.version() >= static_cast(Version::AddUserFlags2); - bool legacy_has_stories = false; - bool has_max_active_story_id = false; - bool has_max_read_story_id = false; - bool has_max_active_story_id_next_reload_time = false; - bool has_accent_color_id = false; - bool has_background_custom_emoji_id = false; - bool has_profile_accent_color_id = false; - bool has_profile_background_custom_emoji_id = false; - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(is_received); - PARSE_FLAG(is_verified); - PARSE_FLAG(is_deleted); - PARSE_FLAG(is_bot); - PARSE_FLAG(can_join_groups); - PARSE_FLAG(can_read_all_group_messages); - PARSE_FLAG(is_inline_bot); - PARSE_FLAG(need_location_bot); - PARSE_FLAG(has_last_name); - PARSE_FLAG(legacy_has_username); - PARSE_FLAG(has_photo); - PARSE_FLAG(legacy_is_restricted); - PARSE_FLAG(has_language_code); - PARSE_FLAG(have_access_hash); - PARSE_FLAG(is_support); - PARSE_FLAG(is_min_access_hash); - PARSE_FLAG(is_scam); - PARSE_FLAG(has_cache_version); - PARSE_FLAG(has_is_contact); - PARSE_FLAG(is_contact); - PARSE_FLAG(is_mutual_contact); - PARSE_FLAG(has_restriction_reasons); - PARSE_FLAG(need_apply_min_photo); - PARSE_FLAG(is_fake); - PARSE_FLAG(can_be_added_to_attach_menu); - PARSE_FLAG(is_premium); - PARSE_FLAG(attach_menu_enabled); - PARSE_FLAG(has_emoji_status); - PARSE_FLAG(has_usernames); - PARSE_FLAG(can_be_edited_bot); - END_PARSE_FLAGS(); - if (has_flags2) { - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(is_close_friend); - PARSE_FLAG(stories_hidden); - PARSE_FLAG(legacy_has_stories); - PARSE_FLAG(has_max_active_story_id); - PARSE_FLAG(has_max_read_story_id); - PARSE_FLAG(has_max_active_story_id_next_reload_time); - PARSE_FLAG(has_accent_color_id); - PARSE_FLAG(has_background_custom_emoji_id); - PARSE_FLAG(has_profile_accent_color_id); - PARSE_FLAG(has_profile_background_custom_emoji_id); - PARSE_FLAG(contact_require_premium); - PARSE_FLAG(is_business_bot); - END_PARSE_FLAGS(); - } - parse(first_name, parser); - if (has_last_name) { - parse(last_name, parser); - } - if (legacy_has_username) { - CHECK(!has_usernames); - string username; - parse(username, parser); - usernames = Usernames(std::move(username), vector>()); - } - parse(phone_number, parser); - if (parser.version() < static_cast(Version::FixMinUsers)) { - have_access_hash = is_received; - } - if (have_access_hash) { - parse(access_hash, parser); - } else { - is_min_access_hash = true; - } - if (has_photo) { - parse(photo, parser); - } - if (!has_is_contact) { - // enum class LinkState : uint8 { Unknown, None, KnowsPhoneNumber, Contact }; - - uint32 link_state_inbound; - uint32 link_state_outbound; - parse(link_state_inbound, parser); - parse(link_state_outbound, parser); - - is_contact = link_state_outbound == 3; - is_mutual_contact = is_contact && link_state_inbound == 3; - is_close_friend = false; - } - parse(was_online, parser); - if (legacy_is_restricted) { - string restriction_reason; - parse(restriction_reason, parser); - restriction_reasons = get_restriction_reasons(restriction_reason); - } else if (has_restriction_reasons) { - parse(restriction_reasons, parser); - } - if (is_inline_bot) { - parse(inline_query_placeholder, parser); - } - if (is_bot) { - parse(bot_info_version, parser); - } - if (has_language_code) { - parse(language_code, parser); - } - if (has_cache_version) { - parse(cache_version, parser); - } - if (has_emoji_status) { - parse(emoji_status, parser); - } - if (has_usernames) { - CHECK(!legacy_has_username); - parse(usernames, parser); - } - if (has_max_active_story_id) { - parse(max_active_story_id, parser); - } - if (has_max_read_story_id) { - parse(max_read_story_id, parser); - } - if (has_max_active_story_id_next_reload_time) { - parse_time(max_active_story_id_next_reload_time, parser); - } - if (has_accent_color_id) { - parse(accent_color_id, parser); - } - if (has_background_custom_emoji_id) { - parse(background_custom_emoji_id, parser); - } - if (has_profile_accent_color_id) { - parse(profile_accent_color_id, parser); - } - if (has_profile_background_custom_emoji_id) { - parse(profile_background_custom_emoji_id, parser); - } - - if (!check_utf8(first_name)) { - LOG(ERROR) << "Have invalid first name \"" << first_name << '"'; - first_name.clear(); - cache_version = 0; - } - if (!check_utf8(last_name)) { - LOG(ERROR) << "Have invalid last name \"" << last_name << '"'; - last_name.clear(); - cache_version = 0; - } - - clean_phone_number(phone_number); - if (first_name.empty() && last_name.empty()) { - first_name = phone_number; - } - if (!is_contact && is_mutual_contact) { - LOG(ERROR) << "Have invalid flag is_mutual_contact"; - is_mutual_contact = false; - cache_version = 0; - } - if (!is_contact && is_close_friend) { - LOG(ERROR) << "Have invalid flag is_close_friend"; - is_close_friend = false; - cache_version = 0; - } -} - -template -void ContactsManager::UserFull::store(StorerT &storer) const { - using td::store; - bool has_about = !about.empty(); - bool has_photo = !photo.is_empty(); - bool has_description = !description.empty(); - bool has_commands = !commands.empty(); - bool has_private_forward_name = !private_forward_name.empty(); - bool has_group_administrator_rights = group_administrator_rights != AdministratorRights(); - bool has_broadcast_administrator_rights = broadcast_administrator_rights != AdministratorRights(); - bool has_menu_button = menu_button != nullptr; - bool has_description_photo = !description_photo.is_empty(); - bool has_description_animation = description_animation_file_id.is_valid(); - bool has_premium_gift_options = !premium_gift_options.empty(); - bool has_personal_photo = !personal_photo.is_empty(); - bool has_fallback_photo = !fallback_photo.is_empty(); - bool has_business_info = business_info != nullptr && !business_info->is_empty(); - bool has_birthdate = !birthdate.is_empty(); - bool has_personal_channel_id = personal_channel_id.is_valid(); - BEGIN_STORE_FLAGS(); - STORE_FLAG(has_about); - STORE_FLAG(is_blocked); - STORE_FLAG(can_be_called); - STORE_FLAG(has_private_calls); - STORE_FLAG(can_pin_messages); - STORE_FLAG(need_phone_number_privacy_exception); // 5 - STORE_FLAG(has_photo); - STORE_FLAG(supports_video_calls); - STORE_FLAG(has_description); - STORE_FLAG(has_commands); - STORE_FLAG(has_private_forward_name); // 10 - STORE_FLAG(has_group_administrator_rights); - STORE_FLAG(has_broadcast_administrator_rights); - STORE_FLAG(has_menu_button); - STORE_FLAG(has_description_photo); - STORE_FLAG(has_description_animation); // 15 - STORE_FLAG(has_premium_gift_options); - STORE_FLAG(voice_messages_forbidden); - STORE_FLAG(has_personal_photo); - STORE_FLAG(has_fallback_photo); - STORE_FLAG(has_pinned_stories); // 20 - STORE_FLAG(is_blocked_for_stories); - STORE_FLAG(wallpaper_overridden); - STORE_FLAG(read_dates_private); - STORE_FLAG(contact_require_premium); - STORE_FLAG(has_business_info); // 25 - STORE_FLAG(has_birthdate); - STORE_FLAG(has_personal_channel_id); - END_STORE_FLAGS(); - if (has_about) { - store(about, storer); - } - store(common_chat_count, storer); - store_time(expires_at, storer); - if (has_photo) { - store(photo, storer); - } - if (has_description) { - store(description, storer); - } - if (has_commands) { - store(commands, storer); - } - if (has_private_forward_name) { - store(private_forward_name, storer); - } - if (has_group_administrator_rights) { - store(group_administrator_rights, storer); - } - if (has_broadcast_administrator_rights) { - store(broadcast_administrator_rights, storer); - } - if (has_menu_button) { - store(menu_button, storer); - } - if (has_description_photo) { - store(description_photo, storer); - } - if (has_description_animation) { - storer.context()->td().get_actor_unsafe()->animations_manager_->store_animation(description_animation_file_id, - storer); - } - if (has_premium_gift_options) { - store(premium_gift_options, storer); - } - if (has_personal_photo) { - store(personal_photo, storer); - } - if (has_fallback_photo) { - store(fallback_photo, storer); - } - if (has_business_info) { - store(business_info, storer); - } - if (has_birthdate) { - store(birthdate, storer); - } - if (has_personal_channel_id) { - store(personal_channel_id, storer); - } -} - -template -void ContactsManager::UserFull::parse(ParserT &parser) { - using td::parse; - bool has_about; - bool has_photo; - bool has_description; - bool has_commands; - bool has_private_forward_name; - bool has_group_administrator_rights; - bool has_broadcast_administrator_rights; - bool has_menu_button; - bool has_description_photo; - bool has_description_animation; - bool has_premium_gift_options; - bool has_personal_photo; - bool has_fallback_photo; - bool has_business_info; - bool has_birthdate; - bool has_personal_channel_id; - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(has_about); - PARSE_FLAG(is_blocked); - PARSE_FLAG(can_be_called); - PARSE_FLAG(has_private_calls); - PARSE_FLAG(can_pin_messages); - PARSE_FLAG(need_phone_number_privacy_exception); - PARSE_FLAG(has_photo); - PARSE_FLAG(supports_video_calls); - PARSE_FLAG(has_description); - PARSE_FLAG(has_commands); - PARSE_FLAG(has_private_forward_name); - PARSE_FLAG(has_group_administrator_rights); - PARSE_FLAG(has_broadcast_administrator_rights); - PARSE_FLAG(has_menu_button); - PARSE_FLAG(has_description_photo); - PARSE_FLAG(has_description_animation); - PARSE_FLAG(has_premium_gift_options); - PARSE_FLAG(voice_messages_forbidden); - PARSE_FLAG(has_personal_photo); - PARSE_FLAG(has_fallback_photo); - PARSE_FLAG(has_pinned_stories); - PARSE_FLAG(is_blocked_for_stories); - PARSE_FLAG(wallpaper_overridden); - PARSE_FLAG(read_dates_private); - PARSE_FLAG(contact_require_premium); - PARSE_FLAG(has_business_info); - PARSE_FLAG(has_birthdate); - PARSE_FLAG(has_personal_channel_id); - END_PARSE_FLAGS(); - if (has_about) { - parse(about, parser); - } - parse(common_chat_count, parser); - parse_time(expires_at, parser); - if (has_photo) { - parse(photo, parser); - } - if (has_description) { - parse(description, parser); - } - if (has_commands) { - parse(commands, parser); - } - if (has_private_forward_name) { - parse(private_forward_name, parser); - } - if (has_group_administrator_rights) { - parse(group_administrator_rights, parser); - } - if (has_broadcast_administrator_rights) { - parse(broadcast_administrator_rights, parser); - } - if (has_menu_button) { - parse(menu_button, parser); - } - if (has_description_photo) { - parse(description_photo, parser); - } - if (has_description_animation) { - description_animation_file_id = - parser.context()->td().get_actor_unsafe()->animations_manager_->parse_animation(parser); - } - if (has_premium_gift_options) { - parse(premium_gift_options, parser); - } - if (has_personal_photo) { - parse(personal_photo, parser); - } - if (has_fallback_photo) { - parse(fallback_photo, parser); - } - if (has_business_info) { - parse(business_info, parser); - } - if (has_birthdate) { - parse(birthdate, parser); - } - if (has_personal_channel_id) { - parse(personal_channel_id, parser); - } -} - template void ContactsManager::Chat::store(StorerT &storer) const { using td::store; @@ -4289,99 +2413,6 @@ void ContactsManager::ChannelFull::parse(ParserT &parser) { } } -template -void ContactsManager::SecretChat::store(StorerT &storer) const { - using td::store; - bool has_layer = layer > static_cast(SecretChatLayer::Default); - bool has_initial_folder_id = initial_folder_id != FolderId(); - BEGIN_STORE_FLAGS(); - STORE_FLAG(is_outbound); - STORE_FLAG(has_layer); - STORE_FLAG(has_initial_folder_id); - END_STORE_FLAGS(); - - store(access_hash, storer); - store(user_id, storer); - store(state, storer); - store(ttl, storer); - store(date, storer); - store(key_hash, storer); - if (has_layer) { - store(layer, storer); - } - if (has_initial_folder_id) { - store(initial_folder_id, storer); - } -} - -template -void ContactsManager::SecretChat::parse(ParserT &parser) { - using td::parse; - bool has_layer; - bool has_initial_folder_id; - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(is_outbound); - PARSE_FLAG(has_layer); - PARSE_FLAG(has_initial_folder_id); - END_PARSE_FLAGS(); - - if (parser.version() >= static_cast(Version::AddAccessHashToSecretChat)) { - parse(access_hash, parser); - } - parse(user_id, parser); - parse(state, parser); - parse(ttl, parser); - parse(date, parser); - if (parser.version() >= static_cast(Version::AddKeyHashToSecretChat)) { - parse(key_hash, parser); - } - if (has_layer) { - parse(layer, parser); - } else { - layer = static_cast(SecretChatLayer::Default); - } - if (has_initial_folder_id) { - parse(initial_folder_id, parser); - } -} - -Result> ContactsManager::get_input_user(UserId user_id) const { - if (user_id == get_my_id()) { - return make_tl_object(); - } - - const User *u = get_user(user_id); - if (u == nullptr || u->access_hash == -1 || u->is_min_access_hash) { - if (td_->auth_manager_->is_bot() && user_id.is_valid()) { - return make_tl_object(user_id.get(), 0); - } - auto it = user_messages_.find(user_id); - if (it != user_messages_.end()) { - CHECK(!it->second.empty()); - auto message_full_id = *it->second.begin(); - return make_tl_object( - get_simple_input_peer(message_full_id.get_dialog_id()), - message_full_id.get_message_id().get_server_message_id().get(), user_id.get()); - } - if (u == nullptr) { - return Status::Error(400, "User not found"); - } else { - return Status::Error(400, "Have no access to the user"); - } - } - - return make_tl_object(user_id.get(), u->access_hash); -} - -telegram_api::object_ptr ContactsManager::get_input_user_force(UserId user_id) const { - auto r_input_user = get_input_user(user_id); - if (r_input_user.is_error()) { - CHECK(user_id.is_valid()); - return make_tl_object(user_id.get(), 0); - } - return r_input_user.move_as_ok(); -} - tl_object_ptr ContactsManager::get_input_channel(ChannelId channel_id) const { const Channel *c = get_channel(channel_id); if (c == nullptr) { @@ -4402,66 +2433,6 @@ tl_object_ptr ContactsManager::get_input_channel(Cha return make_tl_object(channel_id.get(), c->access_hash); } -bool ContactsManager::have_input_peer_user(UserId user_id, AccessRights access_rights) const { - if (user_id == get_my_id()) { - return true; - } - return have_input_peer_user(get_user(user_id), user_id, access_rights); -} - -bool ContactsManager::have_input_peer_user(const User *u, UserId user_id, AccessRights access_rights) const { - if (u == nullptr || u->access_hash == -1 || u->is_min_access_hash) { - if (u == nullptr) { - LOG(DEBUG) << "Have no user"; - } else { - LOG(DEBUG) << "Have user without access hash"; - } - if (td_->auth_manager_->is_bot() && user_id.is_valid()) { - return true; - } - if (user_messages_.count(user_id) != 0) { - return true; - } - return false; - } - if (access_rights == AccessRights::Know) { - return true; - } - if (access_rights == AccessRights::Read) { - return true; - } - if (u->is_deleted) { - LOG(DEBUG) << "Have a deleted user"; - return false; - } - return true; -} - -tl_object_ptr ContactsManager::get_input_peer_user(UserId user_id, - AccessRights access_rights) const { - if (user_id == get_my_id()) { - return make_tl_object(); - } - const User *u = get_user(user_id); - if (!have_input_peer_user(u, user_id, access_rights)) { - return nullptr; - } - if (u == nullptr || u->access_hash == -1 || u->is_min_access_hash) { - if (td_->auth_manager_->is_bot() && user_id.is_valid()) { - return make_tl_object(user_id.get(), 0); - } - auto it = user_messages_.find(user_id); - CHECK(it != user_messages_.end()); - CHECK(!it->second.empty()); - auto message_full_id = *it->second.begin(); - return make_tl_object( - get_simple_input_peer(message_full_id.get_dialog_id()), - message_full_id.get_message_id().get_server_message_id().get(), user_id.get()); - } - - return make_tl_object(user_id.get(), u->access_hash); -} - bool ContactsManager::have_input_peer_chat(ChatId chat_id, AccessRights access_rights) const { return have_input_peer_chat(get_chat(chat_id), access_rights); } @@ -4595,51 +2566,6 @@ bool ContactsManager::have_input_peer_channel(const Channel *c, ChannelId channe return false; } -bool ContactsManager::have_input_encrypted_peer(SecretChatId secret_chat_id, AccessRights access_rights) const { - return have_input_encrypted_peer(get_secret_chat(secret_chat_id), access_rights); -} - -bool ContactsManager::have_input_encrypted_peer(const SecretChat *secret_chat, AccessRights access_rights) { - if (secret_chat == nullptr) { - LOG(DEBUG) << "Have no secret chat"; - return false; - } - if (access_rights == AccessRights::Know) { - return true; - } - if (access_rights == AccessRights::Read) { - return true; - } - return secret_chat->state == SecretChatState::Active; -} - -tl_object_ptr ContactsManager::get_input_encrypted_chat( - SecretChatId secret_chat_id, AccessRights access_rights) const { - auto sc = get_secret_chat(secret_chat_id); - if (!have_input_encrypted_peer(sc, access_rights)) { - return nullptr; - } - - return make_tl_object(secret_chat_id.get(), sc->access_hash); -} - -void ContactsManager::apply_pending_user_photo(User *u, UserId user_id) { - if (u == nullptr || u->is_photo_inited) { - return; - } - - if (pending_user_photos_.count(user_id) > 0) { - do_update_user_photo(u, user_id, std::move(pending_user_photos_[user_id]), "apply_pending_user_photo"); - pending_user_photos_.erase(user_id); - update_user(u, user_id); - } -} - -bool ContactsManager::is_user_received_from_server(UserId user_id) const { - const auto *u = get_user(user_id); - return u != nullptr && u->is_received_from_server; -} - bool ContactsManager::is_chat_received_from_server(ChatId chat_id) const { const auto *c = get_chat(chat_id); return c != nullptr && c->is_received_from_server; @@ -4650,16 +2576,6 @@ bool ContactsManager::is_channel_received_from_server(ChannelId channel_id) cons return c != nullptr && c->is_received_from_server; } -const DialogPhoto *ContactsManager::get_user_dialog_photo(UserId user_id) { - auto u = get_user(user_id); - if (u == nullptr) { - return nullptr; - } - - apply_pending_user_photo(u, user_id); - return &u->photo; -} - const DialogPhoto *ContactsManager::get_chat_dialog_photo(ChatId chat_id) const { auto c = get_chat(chat_id); if (c == nullptr) { @@ -4680,23 +2596,6 @@ const DialogPhoto *ContactsManager::get_channel_dialog_photo(ChannelId channel_i return &c->photo; } -const DialogPhoto *ContactsManager::get_secret_chat_dialog_photo(SecretChatId secret_chat_id) { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return nullptr; - } - return get_user_dialog_photo(c->user_id); -} - -int32 ContactsManager::get_user_accent_color_id_object(UserId user_id) const { - auto u = get_user(user_id); - if (u == nullptr || !u->accent_color_id.is_valid()) { - return td_->theme_manager_->get_accent_color_id_object(AccentColorId(user_id)); - } - - return td_->theme_manager_->get_accent_color_id_object(u->accent_color_id, AccentColorId(user_id)); -} - int32 ContactsManager::get_chat_accent_color_id_object(ChatId chat_id) const { return td_->theme_manager_->get_accent_color_id_object(AccentColorId(chat_id)); } @@ -4722,23 +2621,6 @@ int32 ContactsManager::get_channel_accent_color_id_object(ChannelId channel_id) AccentColorId(channel_id)); } -int32 ContactsManager::get_secret_chat_accent_color_id_object(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return 5; - } - return get_user_accent_color_id_object(c->user_id); -} - -CustomEmojiId ContactsManager::get_user_background_custom_emoji_id(UserId user_id) const { - auto u = get_user(user_id); - if (u == nullptr) { - return CustomEmojiId(); - } - - return u->background_custom_emoji_id; -} - CustomEmojiId ContactsManager::get_chat_background_custom_emoji_id(ChatId chat_id) const { return CustomEmojiId(); } @@ -4752,23 +2634,6 @@ CustomEmojiId ContactsManager::get_channel_background_custom_emoji_id(ChannelId return c->background_custom_emoji_id; } -CustomEmojiId ContactsManager::get_secret_chat_background_custom_emoji_id(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return CustomEmojiId(); - } - return get_user_background_custom_emoji_id(c->user_id); -} - -int32 ContactsManager::get_user_profile_accent_color_id_object(UserId user_id) const { - auto u = get_user(user_id); - if (u == nullptr) { - return -1; - } - - return td_->theme_manager_->get_profile_accent_color_id_object(u->profile_accent_color_id); -} - int32 ContactsManager::get_chat_profile_accent_color_id_object(ChatId chat_id) const { return -1; } @@ -4781,23 +2646,6 @@ int32 ContactsManager::get_channel_profile_accent_color_id_object(ChannelId chan return td_->theme_manager_->get_profile_accent_color_id_object(c->profile_accent_color_id); } -int32 ContactsManager::get_secret_chat_profile_accent_color_id_object(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return -1; - } - return get_user_profile_accent_color_id_object(c->user_id); -} - -CustomEmojiId ContactsManager::get_user_profile_background_custom_emoji_id(UserId user_id) const { - auto u = get_user(user_id); - if (u == nullptr) { - return CustomEmojiId(); - } - - return u->profile_background_custom_emoji_id; -} - CustomEmojiId ContactsManager::get_chat_profile_background_custom_emoji_id(ChatId chat_id) const { return CustomEmojiId(); } @@ -4811,28 +2659,6 @@ CustomEmojiId ContactsManager::get_channel_profile_background_custom_emoji_id(Ch return c->profile_background_custom_emoji_id; } -CustomEmojiId ContactsManager::get_secret_chat_profile_background_custom_emoji_id(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return CustomEmojiId(); - } - return get_user_profile_background_custom_emoji_id(c->user_id); -} - -string ContactsManager::get_user_title(UserId user_id) const { - auto u = get_user(user_id); - if (u == nullptr) { - return string(); - } - if (u->last_name.empty()) { - return u->first_name; - } - if (u->first_name.empty()) { - return u->last_name; - } - return PSTRING() << u->first_name << ' ' << u->last_name; -} - string ContactsManager::get_chat_title(ChatId chat_id) const { auto c = get_chat(chat_id); if (c == nullptr) { @@ -4853,24 +2679,6 @@ string ContactsManager::get_channel_title(ChannelId channel_id) const { return c->title; } -string ContactsManager::get_secret_chat_title(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return string(); - } - return get_user_title(c->user_id); -} - -RestrictedRights ContactsManager::get_user_default_permissions(UserId user_id) const { - auto u = get_user(user_id); - if (u == nullptr || user_id == get_replies_bot_user_id()) { - return RestrictedRights(false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, u != nullptr, false, ChannelType::Unknown); - } - return RestrictedRights(true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, - true, false, ChannelType::Unknown); -} - RestrictedRights ContactsManager::get_chat_default_permissions(ChatId chat_id) const { auto c = get_chat(chat_id); if (c == nullptr) { @@ -4889,24 +2697,6 @@ RestrictedRights ContactsManager::get_channel_default_permissions(ChannelId chan return c->default_permissions; } -RestrictedRights ContactsManager::get_secret_chat_default_permissions(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return RestrictedRights(false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, ChannelType::Unknown); - } - return RestrictedRights(true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, - false, false, ChannelType::Unknown); -} - -td_api::object_ptr ContactsManager::get_user_emoji_status_object(UserId user_id) const { - auto u = get_user(user_id); - if (u == nullptr) { - return nullptr; - } - return u->last_sent_emoji_status.get_emoji_status_object(); -} - td_api::object_ptr ContactsManager::get_chat_emoji_status_object(ChatId chat_id) const { return nullptr; } @@ -4919,15 +2709,6 @@ td_api::object_ptr ContactsManager::get_channel_emoji_statu return c->last_sent_emoji_status.get_emoji_status_object(); } -td_api::object_ptr ContactsManager::get_secret_chat_emoji_status_object( - SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return nullptr; - } - return get_user_emoji_status_object(c->user_id); -} - bool ContactsManager::get_chat_has_protected_content(ChatId chat_id) const { auto c = get_chat(chat_id); if (c == nullptr) { @@ -4944,14 +2725,6 @@ bool ContactsManager::get_channel_has_protected_content(ChannelId channel_id) co return c->noforwards; } -bool ContactsManager::get_user_stories_hidden(UserId user_id) const { - auto u = get_user(user_id); - if (u == nullptr) { - return false; - } - return u->stories_hidden; -} - bool ContactsManager::get_channel_stories_hidden(ChannelId channel_id) const { auto c = get_channel(channel_id); if (c == nullptr) { @@ -4960,11 +2733,6 @@ bool ContactsManager::get_channel_stories_hidden(ChannelId channel_id) const { return c->stories_hidden; } -bool ContactsManager::can_poll_user_active_stories(UserId user_id) const { - const User *u = get_user(user_id); - return need_poll_user_active_stories(u, user_id) && Time::now() >= u->max_active_story_id_next_reload_time; -} - bool ContactsManager::can_poll_channel_active_stories(ChannelId channel_id) const { const Channel *c = get_channel(channel_id); return need_poll_channel_active_stories(c, channel_id) && Time::now() >= c->max_active_story_id_next_reload_time; @@ -4978,41 +2746,6 @@ bool ContactsManager::can_use_premium_custom_emoji_in_channel(ChannelId channel_ return channel_full == nullptr || channel_full->emoji_sticker_set_id.is_valid(); } -string ContactsManager::get_user_private_forward_name(UserId user_id) { - auto user_full = get_user_full_force(user_id, "get_user_private_forward_name"); - if (user_full != nullptr) { - return user_full->private_forward_name; - } - return string(); -} - -bool ContactsManager::get_user_voice_messages_forbidden(UserId user_id) const { - if (!is_user_premium(user_id)) { - return false; - } - auto user_full = get_user_full(user_id); - if (user_full != nullptr) { - return user_full->voice_messages_forbidden; - } - return false; -} - -bool ContactsManager::get_user_read_dates_private(UserId user_id) { - auto user_full = get_user_full_force(user_id, "get_user_read_dates_private"); - if (user_full != nullptr) { - return user_full->read_dates_private; - } - return false; -} - -string ContactsManager::get_user_about(UserId user_id) { - auto user_full = get_user_full_force(user_id, "get_user_about"); - if (user_full != nullptr) { - return user_full->about; - } - return string(); -} - string ContactsManager::get_chat_about(ChatId chat_id) { auto chat_full = get_chat_full_force(chat_id, "get_chat_about"); if (chat_full != nullptr) { @@ -5029,27 +2762,6 @@ string ContactsManager::get_channel_about(ChannelId channel_id) { return string(); } -string ContactsManager::get_secret_chat_about(SecretChatId secret_chat_id) { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return string(); - } - return get_user_about(c->user_id); -} - -string ContactsManager::get_user_search_text(UserId user_id) const { - auto u = get_user(user_id); - if (u == nullptr) { - return string(); - } - return get_user_search_text(u); -} - -string ContactsManager::get_user_search_text(const User *u) { - CHECK(u != nullptr); - return PSTRING() << u->first_name << ' ' << u->last_name << ' ' << implode(u->usernames.get_active_usernames()); -} - string ContactsManager::get_channel_search_text(ChannelId channel_id) const { auto c = get_channel(channel_id); if (c == nullptr) { @@ -5058,34 +2770,6 @@ string ContactsManager::get_channel_search_text(ChannelId channel_id) const { return PSTRING() << c->title << ' ' << implode(c->usernames.get_active_usernames()); } -int32 ContactsManager::get_secret_chat_date(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return 0; - } - return c->date; -} - -int32 ContactsManager::get_secret_chat_ttl(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return 0; - } - return c->ttl; -} - -string ContactsManager::get_user_first_username(UserId user_id) const { - if (!user_id.is_valid()) { - return string(); - } - - auto u = get_user(user_id); - if (u == nullptr) { - return string(); - } - return u->usernames.get_first_username(); -} - string ContactsManager::get_channel_first_username(ChannelId channel_id) const { auto c = get_channel(channel_id); if (c == nullptr) { @@ -5102,1469 +2786,10 @@ string ContactsManager::get_channel_editable_username(ChannelId channel_id) cons return c->usernames.get_editable_username(); } -bool ContactsManager::has_user_fragment_username(UserId user_id) const { - auto u = get_user(user_id); - if (u == nullptr) { - return false; - } - return u->usernames.get_active_usernames().size() > (u->usernames.has_editable_username() ? 1u : 0u); -} - -UserId ContactsManager::get_secret_chat_user_id(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return UserId(); - } - return c->user_id; -} - -bool ContactsManager::get_secret_chat_is_outbound(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return false; - } - return c->is_outbound; -} - -SecretChatState ContactsManager::get_secret_chat_state(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return SecretChatState::Unknown; - } - return c->state; -} - -int32 ContactsManager::get_secret_chat_layer(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return 0; - } - return c->layer; -} - -FolderId ContactsManager::get_secret_chat_initial_folder_id(SecretChatId secret_chat_id) const { - auto c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - return FolderId::main(); - } - return c->initial_folder_id; -} - -UserId ContactsManager::get_my_id() const { - LOG_IF(ERROR, !my_id_.is_valid()) << "Wrong or unknown my ID returned"; - return my_id_; -} - -void ContactsManager::set_my_id(UserId my_id) { - UserId my_old_id = my_id_; - if (my_old_id.is_valid() && my_old_id != my_id) { - LOG(ERROR) << "Already know that me is " << my_old_id << " but received userSelf with " << my_id; - return; - } - if (!my_id.is_valid()) { - LOG(ERROR) << "Receive invalid my ID " << my_id; - return; - } - if (my_old_id != my_id) { - my_id_ = my_id; - G()->td_db()->get_binlog_pmc()->set("my_id", to_string(my_id.get())); - td_->option_manager_->set_option_integer("my_id", my_id_.get()); - if (!td_->auth_manager_->is_bot()) { - G()->td_db()->get_binlog_pmc()->force_sync(Promise(), "set_my_id"); - } - } -} - -void ContactsManager::set_my_online_status(bool is_online, bool send_update, bool is_local) { - if (td_->auth_manager_->is_bot()) { - return; // just in case - } - - auto my_id = get_my_id(); - User *u = get_user_force(my_id, "set_my_online_status"); - if (u != nullptr) { - int32 new_online; - int32 unix_time = G()->unix_time(); - if (is_online) { - new_online = unix_time + 300; - } else { - new_online = unix_time - 1; - } - - auto old_was_online = get_user_was_online(u, my_id, unix_time); - if (is_local) { - LOG(INFO) << "Update my local online from " << my_was_online_local_ << " to " << new_online; - if (!is_online) { - new_online = min(new_online, u->was_online); - } - if (new_online != my_was_online_local_) { - my_was_online_local_ = new_online; - } - } else { - if (my_was_online_local_ != 0 || new_online != u->was_online) { - LOG(INFO) << "Update my online from " << u->was_online << " to " << new_online; - my_was_online_local_ = 0; - u->was_online = new_online; - u->need_save_to_database = true; - } - } - if (old_was_online != get_user_was_online(u, my_id, unix_time)) { - u->is_status_changed = true; - u->is_online_status_changed = true; - } - - if (was_online_local_ != new_online) { - was_online_local_ = new_online; - VLOG(notifications) << "Set was_online_local to " << was_online_local_; - G()->td_db()->get_binlog_pmc()->set("my_was_online_local", to_string(was_online_local_)); - } - - if (send_update) { - update_user(u, my_id); - } - } -} - -ContactsManager::MyOnlineStatusInfo ContactsManager::get_my_online_status() const { - MyOnlineStatusInfo status_info; - status_info.is_online_local = td_->is_online(); - status_info.is_online_remote = was_online_remote_ > G()->unix_time(); - status_info.was_online_local = was_online_local_; - status_info.was_online_remote = was_online_remote_; - - return status_info; -} - -UserId ContactsManager::get_service_notifications_user_id() { - return UserId(static_cast(777000)); -} - -UserId ContactsManager::add_service_notifications_user() { - auto user_id = get_service_notifications_user_id(); - if (!have_user_force(user_id, "add_service_notifications_user")) { - LOG(FATAL) << "Failed to load service notification user"; - } - return user_id; -} - -UserId ContactsManager::get_replies_bot_user_id() { - return UserId(static_cast(G()->is_test_dc() ? 708513 : 1271266957)); -} - -UserId ContactsManager::get_anonymous_bot_user_id() { - return UserId(static_cast(G()->is_test_dc() ? 552888 : 1087968824)); -} - -UserId ContactsManager::get_channel_bot_user_id() { - return UserId(static_cast(G()->is_test_dc() ? 936174 : 136817688)); -} - -UserId ContactsManager::get_anti_spam_bot_user_id() { - return UserId(static_cast(G()->is_test_dc() ? 2200583762ll : 5434988373ll)); -} - -UserId ContactsManager::add_anonymous_bot_user() { - auto user_id = get_anonymous_bot_user_id(); - if (!have_user_force(user_id, "add_anonymous_bot_user")) { - LOG(FATAL) << "Failed to load anonymous bot user"; - } - return user_id; -} - -UserId ContactsManager::add_channel_bot_user() { - auto user_id = get_channel_bot_user_id(); - if (!have_user_force(user_id, "add_channel_bot_user")) { - LOG(FATAL) << "Failed to load channel bot user"; - } - return user_id; -} - ChannelId ContactsManager::get_unsupported_channel_id() { return ChannelId(static_cast(G()->is_test_dc() ? 10304875 : 1535424647)); } -int32 ContactsManager::get_user_was_online(const User *u, UserId user_id, int32 unix_time) const { - if (u == nullptr || u->is_deleted) { - return 0; - } - - int32 was_online = u->was_online; - if (user_id == get_my_id()) { - if (my_was_online_local_ != 0) { - was_online = my_was_online_local_; - } - } else { - if (u->local_was_online > 0 && u->local_was_online > was_online && u->local_was_online > unix_time) { - was_online = u->local_was_online; - } - } - return was_online; -} - -void ContactsManager::can_send_message_to_user( - UserId user_id, bool force, Promise> &&promise) { - TRY_STATUS_PROMISE(promise, G()->close_status()); - if (user_id == get_my_id()) { - return promise.set_value(td_api::make_object()); - } - const auto *u = get_user(user_id); - if (!have_input_peer_user(u, user_id, AccessRights::Write)) { - return promise.set_value(td_api::make_object()); - } - CHECK(user_id.is_valid()); - if ((u != nullptr && (!u->contact_require_premium || u->is_mutual_contact)) || - td_->option_manager_->get_option_boolean("is_premium")) { - return promise.set_value(td_api::make_object()); - } - - auto user_full = get_user_full_force(user_id, "can_send_message_to_user"); - if (user_full != nullptr) { - if (!user_full->contact_require_premium) { - return promise.set_value(td_api::make_object()); - } - return promise.set_value(td_api::make_object()); - } - - auto it = user_full_contact_require_premium_.find(user_id); - if (it != user_full_contact_require_premium_.end()) { - if (!it->second) { - return promise.set_value(td_api::make_object()); - } - return promise.set_value(td_api::make_object()); - } - - if (force) { - return promise.set_value(td_api::make_object()); - } - - auto query_promise = PromiseCreator::lambda( - [actor_id = actor_id(this), user_id, promise = std::move(promise)](Result &&result) mutable { - if (result.is_error()) { - return promise.set_error(result.move_as_error()); - } - send_closure(actor_id, &ContactsManager::can_send_message_to_user, user_id, true, std::move(promise)); - }); - get_is_premium_required_to_contact_queries_.add_query(user_id.get(), std::move(query_promise), - "can_send_message_to_user"); -} - -void ContactsManager::on_get_is_premium_required_to_contact_users(vector &&user_ids, - vector &&is_premium_required, - Promise &&promise) { - if (user_ids.size() != is_premium_required.size()) { - LOG(ERROR) << "Receive " << is_premium_required.size() << " flags instead of " << user_ids.size(); - return promise.set_error(Status::Error(500, "Receive invalid response")); - } - for (size_t i = 0; i < user_ids.size(); i++) { - auto user_id = user_ids[i]; - CHECK(user_id.is_valid()); - if (get_user_full(user_id) == nullptr) { - user_full_contact_require_premium_[user_id] = is_premium_required[i]; - } - } - promise.set_value(Unit()); -} - -void ContactsManager::allow_send_message_to_user(UserId user_id) { - if (get_user_full(user_id) == nullptr) { - CHECK(user_id.is_valid()); - user_full_contact_require_premium_[user_id] = true; - } -} - -void ContactsManager::load_contacts(Promise &&promise) { - if (td_->auth_manager_->is_bot()) { - are_contacts_loaded_ = true; - saved_contact_count_ = 0; - } - if (are_contacts_loaded_ && saved_contact_count_ != -1) { - LOG(INFO) << "Contacts are already loaded"; - promise.set_value(Unit()); - return; - } - load_contacts_queries_.push_back(std::move(promise)); - if (load_contacts_queries_.size() == 1u) { - if (G()->use_chat_info_database() && next_contacts_sync_date_ > 0 && saved_contact_count_ != -1) { - LOG(INFO) << "Load contacts from database"; - G()->td_db()->get_sqlite_pmc()->get( - "user_contacts", PromiseCreator::lambda([](string value) { - send_closure(G()->contacts_manager(), &ContactsManager::on_load_contacts_from_database, std::move(value)); - })); - } else { - LOG(INFO) << "Load contacts from server"; - reload_contacts(true); - } - } else { - LOG(INFO) << "Load contacts request has already been sent"; - } -} - -int64 ContactsManager::get_contacts_hash() { - if (!are_contacts_loaded_) { - return 0; - } - - vector user_ids = contacts_hints_.search_empty(100000).second; - CHECK(std::is_sorted(user_ids.begin(), user_ids.end())); - auto my_id = get_my_id(); - const User *u = get_user_force(my_id, "get_contacts_hash"); - if (u != nullptr && u->is_contact) { - user_ids.insert(std::upper_bound(user_ids.begin(), user_ids.end(), my_id.get()), my_id.get()); - } - - vector numbers; - numbers.reserve(user_ids.size() + 1); - numbers.push_back(saved_contact_count_); - for (auto user_id : user_ids) { - numbers.push_back(user_id); - } - return get_vector_hash(numbers); -} - -void ContactsManager::reload_contacts(bool force) { - if (!G()->close_flag() && !td_->auth_manager_->is_bot() && - next_contacts_sync_date_ != std::numeric_limits::max() && - (next_contacts_sync_date_ < G()->unix_time() || force)) { - next_contacts_sync_date_ = std::numeric_limits::max(); - td_->create_handler()->send(get_contacts_hash()); - } -} - -void ContactsManager::add_contact(Contact contact, bool share_phone_number, Promise &&promise) { - TRY_STATUS_PROMISE(promise, G()->close_status()); - - if (!are_contacts_loaded_) { - load_contacts(PromiseCreator::lambda([actor_id = actor_id(this), contact = std::move(contact), share_phone_number, - promise = std::move(promise)](Result &&) mutable { - send_closure(actor_id, &ContactsManager::add_contact, std::move(contact), share_phone_number, std::move(promise)); - })); - return; - } - - LOG(INFO) << "Add " << contact << " with share_phone_number = " << share_phone_number; - - auto user_id = contact.get_user_id(); - TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); - - td_->create_handler(std::move(promise)) - ->send(user_id, std::move(input_user), contact, share_phone_number); -} - -std::pair, vector> ContactsManager::import_contacts(const vector &contacts, - int64 &random_id, Promise &&promise) { - if (!are_contacts_loaded_) { - load_contacts(std::move(promise)); - return {}; - } - - LOG(INFO) << "Asked to import " << contacts.size() << " contacts with random_id = " << random_id; - if (random_id != 0) { - // request has already been sent before - auto it = imported_contacts_.find(random_id); - CHECK(it != imported_contacts_.end()); - auto result = std::move(it->second); - imported_contacts_.erase(it); - - promise.set_value(Unit()); - return result; - } - - do { - random_id = Random::secure_int64(); - } while (random_id == 0 || random_id == 1 || imported_contacts_.count(random_id) > 0); - imported_contacts_[random_id]; // reserve place for result - - do_import_contacts(contacts, random_id, std::move(promise)); - return {}; -} - -void ContactsManager::do_import_contacts(vector contacts, int64 random_id, Promise &&promise) { - size_t size = contacts.size(); - if (size == 0) { - on_import_contacts_finished(random_id, {}, {}); - return promise.set_value(Unit()); - } - - vector> input_phone_contacts; - input_phone_contacts.reserve(size); - for (size_t i = 0; i < size; i++) { - input_phone_contacts.push_back(contacts[i].get_input_phone_contact(static_cast(i))); - } - - auto task = make_unique(); - task->promise_ = std::move(promise); - task->input_contacts_ = std::move(contacts); - task->imported_user_ids_.resize(size); - task->unimported_contact_invites_.resize(size); - - bool is_added = import_contact_tasks_.emplace(random_id, std::move(task)).second; - CHECK(is_added); - - td_->create_handler()->send(std::move(input_phone_contacts), random_id); -} - -void ContactsManager::on_imported_contacts(int64 random_id, - Result> result) { - auto it = import_contact_tasks_.find(random_id); - CHECK(it != import_contact_tasks_.end()); - CHECK(it->second != nullptr); - - auto task = it->second.get(); - if (result.is_error()) { - auto promise = std::move(task->promise_); - import_contact_tasks_.erase(it); - return promise.set_error(result.move_as_error()); - } - - auto imported_contacts = result.move_as_ok(); - on_get_users(std::move(imported_contacts->users_), "on_imported_contacts"); - - for (auto &imported_contact : imported_contacts->imported_) { - int64 client_id = imported_contact->client_id_; - if (client_id < 0 || client_id >= static_cast(task->imported_user_ids_.size())) { - LOG(ERROR) << "Wrong client_id " << client_id << " returned"; - continue; - } - - task->imported_user_ids_[static_cast(client_id)] = UserId(imported_contact->user_id_); - } - for (auto &popular_contact : imported_contacts->popular_invites_) { - int64 client_id = popular_contact->client_id_; - if (client_id < 0 || client_id >= static_cast(task->unimported_contact_invites_.size())) { - LOG(ERROR) << "Wrong client_id " << client_id << " returned"; - continue; - } - if (popular_contact->importers_ < 0) { - LOG(ERROR) << "Wrong number of importers " << popular_contact->importers_ << " returned"; - continue; - } - - task->unimported_contact_invites_[static_cast(client_id)] = popular_contact->importers_; - } - - if (!imported_contacts->retry_contacts_.empty()) { - auto total_size = static_cast(task->input_contacts_.size()); - vector> input_phone_contacts; - input_phone_contacts.reserve(imported_contacts->retry_contacts_.size()); - for (auto &client_id : imported_contacts->retry_contacts_) { - if (client_id < 0 || client_id >= total_size) { - LOG(ERROR) << "Wrong client_id " << client_id << " returned"; - continue; - } - auto i = static_cast(client_id); - input_phone_contacts.push_back(task->input_contacts_[i].get_input_phone_contact(client_id)); - } - td_->create_handler()->send(std::move(input_phone_contacts), random_id); - return; - } - - auto promise = std::move(task->promise_); - on_import_contacts_finished(random_id, std::move(task->imported_user_ids_), - std::move(task->unimported_contact_invites_)); - import_contact_tasks_.erase(it); - promise.set_value(Unit()); -} - -void ContactsManager::remove_contacts(const vector &user_ids, Promise &&promise) { - LOG(INFO) << "Delete contacts: " << format::as_array(user_ids); - if (!are_contacts_loaded_) { - load_contacts(std::move(promise)); - return; - } - - vector to_delete_user_ids; - vector> input_users; - for (auto &user_id : user_ids) { - const User *u = get_user(user_id); - if (u != nullptr && u->is_contact) { - auto r_input_user = get_input_user(user_id); - if (r_input_user.is_ok()) { - to_delete_user_ids.push_back(user_id); - input_users.push_back(r_input_user.move_as_ok()); - } - } - } - - if (input_users.empty()) { - return promise.set_value(Unit()); - } - - td_->create_handler(std::move(promise))->send(std::move(input_users)); -} - -void ContactsManager::remove_contacts_by_phone_number(vector user_phone_numbers, vector user_ids, - Promise &&promise) { - LOG(INFO) << "Delete contacts by phone number: " << format::as_array(user_phone_numbers); - if (!are_contacts_loaded_) { - load_contacts(std::move(promise)); - return; - } - - td_->create_handler(std::move(promise)) - ->send(std::move(user_phone_numbers), std::move(user_ids)); -} - -int32 ContactsManager::get_imported_contact_count(Promise &&promise) { - LOG(INFO) << "Get imported contact count"; - - if (!are_contacts_loaded_ || saved_contact_count_ == -1) { - load_contacts(std::move(promise)); - return 0; - } - reload_contacts(false); - - promise.set_value(Unit()); - return saved_contact_count_; -} - -void ContactsManager::load_imported_contacts(Promise &&promise) { - if (td_->auth_manager_->is_bot()) { - are_imported_contacts_loaded_ = true; - } - if (are_imported_contacts_loaded_) { - LOG(INFO) << "Imported contacts are already loaded"; - promise.set_value(Unit()); - return; - } - load_imported_contacts_queries_.push_back(std::move(promise)); - if (load_imported_contacts_queries_.size() == 1u) { - if (G()->use_chat_info_database()) { - LOG(INFO) << "Load imported contacts from database"; - G()->td_db()->get_sqlite_pmc()->get( - "user_imported_contacts", PromiseCreator::lambda([](string value) { - send_closure_later(G()->contacts_manager(), &ContactsManager::on_load_imported_contacts_from_database, - std::move(value)); - })); - } else { - LOG(INFO) << "Have no previously imported contacts"; - send_closure_later(G()->contacts_manager(), &ContactsManager::on_load_imported_contacts_from_database, string()); - } - } else { - LOG(INFO) << "Load imported contacts request has already been sent"; - } -} - -void ContactsManager::on_load_imported_contacts_from_database(string value) { - if (G()->close_flag()) { - return; - } - - CHECK(!are_imported_contacts_loaded_); - if (need_clear_imported_contacts_) { - need_clear_imported_contacts_ = false; - value.clear(); - } - if (value.empty()) { - CHECK(all_imported_contacts_.empty()); - } else { - if (log_event_parse(all_imported_contacts_, value).is_error()) { - LOG(ERROR) << "Failed to load all imported contacts from database"; - all_imported_contacts_.clear(); - } else { - LOG(INFO) << "Successfully loaded " << all_imported_contacts_.size() << " imported contacts from database"; - } - } - - load_imported_contact_users_multipromise_.add_promise( - PromiseCreator::lambda([actor_id = actor_id(this)](Result result) { - if (result.is_ok()) { - send_closure_later(actor_id, &ContactsManager::on_load_imported_contacts_finished); - } - })); - - auto lock_promise = load_imported_contact_users_multipromise_.get_promise(); - - for (const auto &contact : all_imported_contacts_) { - auto user_id = contact.get_user_id(); - if (user_id.is_valid()) { - get_user(user_id, 3, load_imported_contact_users_multipromise_.get_promise()); - } - } - - lock_promise.set_value(Unit()); -} - -void ContactsManager::on_load_imported_contacts_finished() { - LOG(INFO) << "Finished to load " << all_imported_contacts_.size() << " imported contacts"; - - for (const auto &contact : all_imported_contacts_) { - get_user_id_object(contact.get_user_id(), "on_load_imported_contacts_finished"); // to ensure updateUser - } - - if (need_clear_imported_contacts_) { - need_clear_imported_contacts_ = false; - all_imported_contacts_.clear(); - } - are_imported_contacts_loaded_ = true; - set_promises(load_imported_contacts_queries_); -} - -std::pair, vector> ContactsManager::change_imported_contacts(vector &contacts, - int64 &random_id, - Promise &&promise) { - if (!are_contacts_loaded_) { - load_contacts(std::move(promise)); - return {}; - } - if (!are_imported_contacts_loaded_) { - load_imported_contacts(std::move(promise)); - return {}; - } - - LOG(INFO) << "Asked to change imported contacts to a list of " << contacts.size() - << " contacts with random_id = " << random_id; - if (random_id != 0) { - // request has already been sent before - if (need_clear_imported_contacts_) { - need_clear_imported_contacts_ = false; - all_imported_contacts_.clear(); - if (G()->use_chat_info_database()) { - G()->td_db()->get_sqlite_pmc()->erase("user_imported_contacts", Auto()); - } - reload_contacts(true); - } - - CHECK(are_imported_contacts_changing_); - are_imported_contacts_changing_ = false; - - auto unimported_contact_invites = std::move(unimported_contact_invites_); - unimported_contact_invites_.clear(); - - auto imported_contact_user_ids = std::move(imported_contact_user_ids_); - imported_contact_user_ids_.clear(); - - promise.set_value(Unit()); - return {std::move(imported_contact_user_ids), std::move(unimported_contact_invites)}; - } - - if (are_imported_contacts_changing_) { - promise.set_error(Status::Error(400, "ChangeImportedContacts can be called only once at the same time")); - return {}; - } - - vector new_contacts_unique_id(contacts.size()); - vector unique_new_contacts; - unique_new_contacts.reserve(contacts.size()); - std::unordered_map different_new_contacts; - std::unordered_set> different_new_phone_numbers; - size_t unique_size = 0; - for (size_t i = 0; i < contacts.size(); i++) { - auto it_success = different_new_contacts.emplace(std::move(contacts[i]), unique_size); - new_contacts_unique_id[i] = it_success.first->second; - if (it_success.second) { - unique_new_contacts.push_back(it_success.first->first); - different_new_phone_numbers.insert(unique_new_contacts.back().get_phone_number()); - unique_size++; - } - } - - vector to_delete; - vector to_delete_user_ids; - for (auto &old_contact : all_imported_contacts_) { - auto user_id = old_contact.get_user_id(); - auto it = different_new_contacts.find(old_contact); - if (it == different_new_contacts.end()) { - auto phone_number = old_contact.get_phone_number(); - if (different_new_phone_numbers.count(phone_number) == 0) { - to_delete.push_back(std::move(phone_number)); - if (user_id.is_valid()) { - to_delete_user_ids.push_back(user_id); - } - } - } else { - unique_new_contacts[it->second].set_user_id(user_id); - different_new_contacts.erase(it); - } - } - std::pair, vector> to_add; - for (auto &new_contact : different_new_contacts) { - to_add.first.push_back(new_contact.second); - to_add.second.push_back(new_contact.first); - } - - if (to_add.first.empty() && to_delete.empty()) { - for (size_t i = 0; i < contacts.size(); i++) { - auto unique_id = new_contacts_unique_id[i]; - contacts[i].set_user_id(unique_new_contacts[unique_id].get_user_id()); - } - - promise.set_value(Unit()); - return {transform(contacts, [&](const Contact &contact) { return contact.get_user_id(); }), - vector(contacts.size())}; - } - - are_imported_contacts_changing_ = true; - random_id = 1; - - remove_contacts_by_phone_number( - std::move(to_delete), std::move(to_delete_user_ids), - PromiseCreator::lambda([new_contacts = std::move(unique_new_contacts), - new_contacts_unique_id = std::move(new_contacts_unique_id), to_add = std::move(to_add), - promise = std::move(promise)](Result<> result) mutable { - if (result.is_ok()) { - send_closure_later(G()->contacts_manager(), &ContactsManager::on_clear_imported_contacts, - std::move(new_contacts), std::move(new_contacts_unique_id), std::move(to_add), - std::move(promise)); - } else { - promise.set_error(result.move_as_error()); - } - })); - return {}; -} - -void ContactsManager::on_clear_imported_contacts(vector &&contacts, vector contacts_unique_id, - std::pair, vector> &&to_add, - Promise &&promise) { - LOG(INFO) << "Add " << to_add.first.size() << " contacts"; - next_all_imported_contacts_ = std::move(contacts); - imported_contacts_unique_id_ = std::move(contacts_unique_id); - imported_contacts_pos_ = std::move(to_add.first); - - do_import_contacts(std::move(to_add.second), 1, std::move(promise)); -} - -void ContactsManager::clear_imported_contacts(Promise &&promise) { - LOG(INFO) << "Delete imported contacts"; - - if (saved_contact_count_ == 0) { - promise.set_value(Unit()); - return; - } - - td_->create_handler(std::move(promise))->send(); -} - -void ContactsManager::on_update_contacts_reset() { - /* - UserId my_id = get_my_id(); - users_.foreach([&](const UserId &user_id, unique_ptr &user) { - User *u = user.get(); - if (u->is_contact) { - LOG(INFO) << "Drop contact with " << user_id; - if (user_id != my_id) { - CHECK(contacts_hints_.has_key(user_id.get())); - } - on_update_user_is_contact(u, user_id, false, false, false); - CHECK(u->is_is_contact_changed); - u->cache_version = 0; - u->is_repaired = false; - update_user(u, user_id); - CHECK(!u->is_contact); - if (user_id != my_id) { - CHECK(!contacts_hints_.has_key(user_id.get())); - } - } - }); - */ - - saved_contact_count_ = 0; - if (G()->use_chat_info_database()) { - G()->td_db()->get_binlog_pmc()->set("saved_contact_count", "0"); - G()->td_db()->get_sqlite_pmc()->erase("user_imported_contacts", Auto()); - } - if (!are_imported_contacts_loaded_) { - if (load_imported_contacts_queries_.empty()) { - CHECK(all_imported_contacts_.empty()); - LOG(INFO) << "Imported contacts were never loaded, just clear them"; - } else { - LOG(INFO) << "Imported contacts are being loaded, clear them after they will be loaded"; - need_clear_imported_contacts_ = true; - } - } else { - if (!are_imported_contacts_changing_) { - LOG(INFO) << "Imported contacts were loaded, but aren't changing now, just clear them"; - all_imported_contacts_.clear(); - } else { - LOG(INFO) << "Imported contacts are changing now, clear them after they will be changed"; - need_clear_imported_contacts_ = true; - } - } - reload_contacts(true); -} - -std::pair> ContactsManager::search_contacts(const string &query, int32 limit, - Promise &&promise) { - LOG(INFO) << "Search contacts with query = \"" << query << "\" and limit = " << limit; - - if (limit < 0) { - promise.set_error(Status::Error(400, "Limit must be non-negative")); - return {}; - } - - if (!are_contacts_loaded_) { - load_contacts(std::move(promise)); - return {}; - } - reload_contacts(false); - - std::pair> result; - if (query.empty()) { - result = contacts_hints_.search_empty(limit); - } else { - result = contacts_hints_.search(query, limit); - } - - vector user_ids; - user_ids.reserve(result.second.size()); - for (auto key : result.second) { - user_ids.emplace_back(key); - } - - promise.set_value(Unit()); - return {narrow_cast(result.first), std::move(user_ids)}; -} - -void ContactsManager::reload_contact_birthdates(bool force) { - if (!G()->close_flag() && !td_->auth_manager_->is_bot() && !contact_birthdates_.is_being_synced_ && - (contact_birthdates_.next_sync_time_ < Time::now() || force)) { - contact_birthdates_.is_being_synced_ = true; - td_->create_handler()->send(); - } -} - -void ContactsManager::on_get_contact_birthdates( - telegram_api::object_ptr &&birthdays) { - CHECK(contact_birthdates_.is_being_synced_); - contact_birthdates_.is_being_synced_ = false; - if (birthdays == nullptr) { - contact_birthdates_.next_sync_time_ = Time::now() + Random::fast(120, 180); - return; - } - contact_birthdates_.next_sync_time_ = Time::now() + Random::fast(86400 / 4, 86400 / 3); - - on_get_users(std::move(birthdays->users_), "on_get_contact_birthdates"); - vector> users; - for (auto &contact : birthdays->contacts_) { - UserId user_id(contact->contact_id_); - if (is_user_contact(user_id)) { - Birthdate birthdate(std::move(contact->birthday_)); - UserFull *user_full = get_user_full_force(user_id, "on_get_contact_birthdates"); - if (user_full != nullptr && user_full->birthdate != birthdate) { - user_full->birthdate = birthdate; - user_full->is_changed = true; - update_user_full(user_full, user_id, "on_get_contact_birthdates"); - } - if (!birthdate.is_empty()) { - users.emplace_back(user_id, birthdate); - } - } - } - if (contact_birthdates_.users_ != users) { - contact_birthdates_.users_ = std::move(users); - send_closure(G()->td(), &Td::send_update, get_update_contact_close_birthdays()); - } - // there is no need to save them between restarts -} - -vector ContactsManager::get_close_friends(Promise &&promise) { - if (!are_contacts_loaded_) { - load_contacts(std::move(promise)); - return {}; - } - reload_contacts(false); - - auto result = contacts_hints_.search_empty(10000); - - vector user_ids; - for (auto key : result.second) { - UserId user_id(key); - const User *u = get_user(user_id); - if (u != nullptr && u->is_close_friend) { - user_ids.push_back(user_id); - } - } - - promise.set_value(Unit()); - return user_ids; -} - -void ContactsManager::set_close_friends(vector user_ids, Promise &&promise) { - for (auto &user_id : user_ids) { - if (!have_user(user_id)) { - return promise.set_error(Status::Error(400, "User not found")); - } - } - - td_->create_handler(std::move(promise))->send(std::move(user_ids)); -} - -void ContactsManager::on_set_close_friends(const vector &user_ids, Promise &&promise) { - FlatHashSet close_friend_user_ids; - for (auto &user_id : user_ids) { - CHECK(user_id.is_valid()); - close_friend_user_ids.insert(user_id); - } - users_.foreach([&](const UserId &user_id, unique_ptr &user) { - User *u = user.get(); - if (u->is_contact && u->is_close_friend != (close_friend_user_ids.count(user_id) > 0)) { - on_update_user_is_contact(u, user_id, u->is_contact, u->is_mutual_contact, !u->is_close_friend); - update_user(u, user_id); - } - }); - promise.set_value(Unit()); -} - -UserId ContactsManager::search_user_by_phone_number(string phone_number, Promise &&promise) { - clean_phone_number(phone_number); - if (phone_number.empty()) { - promise.set_error(Status::Error(200, "Phone number is invalid")); - return UserId(); - } - - auto it = resolved_phone_numbers_.find(phone_number); - if (it != resolved_phone_numbers_.end()) { - promise.set_value(Unit()); - return it->second; - } - - td_->create_handler(std::move(promise))->send(phone_number); - return UserId(); -} - -void ContactsManager::on_resolved_phone_number(const string &phone_number, UserId user_id) { - if (!user_id.is_valid()) { - resolved_phone_numbers_.emplace(phone_number, UserId()); // negative cache - return; - } - - auto it = resolved_phone_numbers_.find(phone_number); - if (it != resolved_phone_numbers_.end()) { - if (it->second != user_id) { - LOG(WARNING) << "Resolve phone number \"" << phone_number << "\" to " << user_id << ", but have it in " - << it->second; - it->second = user_id; - } - return; - } - - auto *u = get_user(user_id); - if (u == nullptr) { - LOG(ERROR) << "Resolve phone number \"" << phone_number << "\" to unknown " << user_id; - } else if (!u->phone_number.empty()) { - LOG(ERROR) << "Resolve phone number \"" << phone_number << "\" to " << user_id << " with phone number " - << u->phone_number; - } else { - // the user's phone number can be hidden by privacy settings, despite the user can be found by the phone number - } - resolved_phone_numbers_[phone_number] = user_id; // always update cached value -} - -void ContactsManager::share_phone_number(UserId user_id, Promise &&promise) { - TRY_STATUS_PROMISE(promise, G()->close_status()); - - if (!are_contacts_loaded_) { - load_contacts(PromiseCreator::lambda( - [actor_id = actor_id(this), user_id, promise = std::move(promise)](Result &&) mutable { - send_closure(actor_id, &ContactsManager::share_phone_number, user_id, std::move(promise)); - })); - return; - } - - LOG(INFO) << "Share phone number with " << user_id; - TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); - - td_->messages_manager_->hide_dialog_action_bar(DialogId(user_id)); - - td_->create_handler(std::move(promise))->send(user_id, std::move(input_user)); -} - -void ContactsManager::on_update_bot_menu_button(UserId bot_user_id, - tl_object_ptr &&bot_menu_button) { - if (!bot_user_id.is_valid()) { - LOG(ERROR) << "Receive updateBotMenuButton about invalid " << bot_user_id; - return; - } - if (!have_user_force(bot_user_id, "on_update_bot_menu_button") || !is_user_bot(bot_user_id)) { - return; - } - if (td_->auth_manager_->is_bot()) { - return; - } - - auto user_full = get_user_full_force(bot_user_id, "on_update_bot_menu_button"); - if (user_full != nullptr) { - on_update_user_full_menu_button(user_full, bot_user_id, std::move(bot_menu_button)); - update_user_full(user_full, bot_user_id, "on_update_bot_menu_button"); - } -} - -FileId ContactsManager::get_profile_photo_file_id(int64 photo_id) const { - auto it = my_photo_file_id_.find(photo_id); - if (it == my_photo_file_id_.end()) { - return FileId(); - } - return it->second; -} - -void ContactsManager::set_bot_profile_photo(UserId bot_user_id, - const td_api::object_ptr &input_photo, - Promise &&promise) { - if (td_->auth_manager_->is_bot()) { - if (bot_user_id != UserId() && bot_user_id != get_my_id()) { - return promise.set_error(Status::Error(400, "Invalid bot user identifier specified")); - } - bot_user_id = get_my_id(); - } else { - TRY_RESULT_PROMISE(promise, bot_data, get_bot_data(bot_user_id)); - if (!bot_data.can_be_edited) { - return promise.set_error(Status::Error(400, "The bot can't be edited")); - } - } - if (input_photo == nullptr) { - td_->create_handler(std::move(promise)) - ->send(bot_user_id, FileId(), 0, false, make_tl_object()); - return; - } - set_profile_photo_impl(bot_user_id, input_photo, false, false, std::move(promise)); -} - -void ContactsManager::set_profile_photo(const td_api::object_ptr &input_photo, bool is_fallback, - Promise &&promise) { - set_profile_photo_impl(get_my_id(), input_photo, is_fallback, false, std::move(promise)); -} - -void ContactsManager::set_profile_photo_impl(UserId user_id, - const td_api::object_ptr &input_photo, - bool is_fallback, bool only_suggest, Promise &&promise) { - if (input_photo == nullptr) { - return promise.set_error(Status::Error(400, "New profile photo must be non-empty")); - } - - const td_api::object_ptr *input_file = nullptr; - double main_frame_timestamp = 0.0; - bool is_animation = false; - switch (input_photo->get_id()) { - case td_api::inputChatPhotoPrevious::ID: { - if (user_id != get_my_id() || td_->auth_manager_->is_bot()) { - return promise.set_error(Status::Error(400, "Can't use inputChatPhotoPrevious")); - } - auto photo = static_cast(input_photo.get()); - auto photo_id = photo->chat_photo_id_; - auto *u = get_user(user_id); - if (u != nullptr && u->photo.id > 0 && photo_id == u->photo.id) { - // it is possible that u->photo.is_fallback != is_fallback, so we need to set the photo anyway - // return promise.set_value(Unit()); - } - - auto file_id = get_profile_photo_file_id(photo_id); - if (!file_id.is_valid()) { - return promise.set_error(Status::Error(400, "Unknown profile photo ID specified")); - } - return send_update_profile_photo_query(user_id, - td_->file_manager_->dup_file_id(file_id, "set_profile_photo_impl"), - photo_id, is_fallback, std::move(promise)); - } - case td_api::inputChatPhotoStatic::ID: { - auto photo = static_cast(input_photo.get()); - input_file = &photo->photo_; - break; - } - case td_api::inputChatPhotoAnimation::ID: { - auto photo = static_cast(input_photo.get()); - input_file = &photo->animation_; - main_frame_timestamp = photo->main_frame_timestamp_; - is_animation = true; - break; - } - case td_api::inputChatPhotoSticker::ID: { - auto photo = static_cast(input_photo.get()); - TRY_RESULT_PROMISE(promise, sticker_photo_size, StickerPhotoSize::get_sticker_photo_size(td_, photo->sticker_)); - - td_->create_handler(std::move(promise)) - ->send(user_id, std::move(sticker_photo_size), is_fallback, only_suggest); - return; - } - default: - UNREACHABLE(); - break; - } - - const double MAX_ANIMATION_DURATION = 10.0; - if (main_frame_timestamp < 0.0 || main_frame_timestamp > MAX_ANIMATION_DURATION) { - return promise.set_error(Status::Error(400, "Wrong main frame timestamp specified")); - } - - auto file_type = is_animation ? FileType::Animation : FileType::Photo; - TRY_RESULT_PROMISE(promise, file_id, - td_->file_manager_->get_input_file_id(file_type, *input_file, DialogId(user_id), false, false)); - CHECK(file_id.is_valid()); - - upload_profile_photo(user_id, td_->file_manager_->dup_file_id(file_id, "set_profile_photo_impl"), is_fallback, - only_suggest, is_animation, main_frame_timestamp, std::move(promise)); -} - -void ContactsManager::set_user_profile_photo(UserId user_id, - const td_api::object_ptr &input_photo, - bool only_suggest, Promise &&promise) { - TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); - if (!only_suggest && !is_user_contact(user_id)) { - return promise.set_error(Status::Error(400, "User isn't a contact")); - } - if (user_id == get_my_id()) { - return promise.set_error(Status::Error(400, "Can't set personal or suggest photo to self")); - } - if (is_user_bot(user_id)) { - return promise.set_error(Status::Error(400, "Can't set personal or suggest photo to bots")); - } - if (input_photo == nullptr) { - td_->create_handler(std::move(promise))->send(user_id, std::move(input_user)); - return; - } - - set_profile_photo_impl(user_id, input_photo, false, only_suggest, std::move(promise)); -} - -void ContactsManager::send_update_profile_photo_query(UserId user_id, FileId file_id, int64 old_photo_id, - bool is_fallback, Promise &&promise) { - FileView file_view = td_->file_manager_->get_file_view(file_id); - td_->create_handler(std::move(promise)) - ->send(user_id, file_id, old_photo_id, is_fallback, file_view.main_remote_location().as_input_photo()); -} - -void ContactsManager::upload_profile_photo(UserId user_id, FileId file_id, bool is_fallback, bool only_suggest, - bool is_animation, double main_frame_timestamp, Promise &&promise, - int reupload_count, vector bad_parts) { - CHECK(file_id.is_valid()); - bool is_inserted = - uploaded_profile_photos_ - .emplace(file_id, UploadedProfilePhoto{user_id, is_fallback, only_suggest, main_frame_timestamp, is_animation, - reupload_count, std::move(promise)}) - .second; - CHECK(is_inserted); - LOG(INFO) << "Ask to upload " << (is_animation ? "animated" : "static") << " profile photo " << file_id - << " for user " << user_id << " with bad parts " << bad_parts; - // TODO use force_reupload if reupload_count >= 1, replace reupload_count with is_reupload - td_->file_manager_->resume_upload(file_id, std::move(bad_parts), upload_profile_photo_callback_, 32, 0); -} - -void ContactsManager::delete_profile_photo(int64 profile_photo_id, bool is_recursive, Promise &&promise) { - TRY_STATUS_PROMISE(promise, G()->close_status()); - const UserFull *user_full = get_user_full_force(get_my_id(), "delete_profile_photo"); - if (user_full == nullptr) { - // must load UserFull first, because fallback photo can't be deleted via DeleteProfilePhotoQuery - if (is_recursive) { - return promise.set_error(Status::Error(500, "Failed to load UserFullInfo")); - } - auto reload_promise = PromiseCreator::lambda( - [actor_id = actor_id(this), profile_photo_id, promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - return promise.set_error(result.move_as_error()); - } - send_closure(actor_id, &ContactsManager::delete_profile_photo, profile_photo_id, true, std::move(promise)); - }); - reload_user_full(get_my_id(), std::move(reload_promise), "delete_profile_photo"); - return; - } - if (user_full->photo.id.get() == profile_photo_id || user_full->fallback_photo.id.get() == profile_photo_id) { - td_->create_handler(std::move(promise)) - ->send(get_my_id(), FileId(), profile_photo_id, user_full->fallback_photo.id.get() == profile_photo_id, - make_tl_object()); - return; - } - - td_->create_handler(std::move(promise))->send(profile_photo_id); -} - -void ContactsManager::set_accent_color(AccentColorId accent_color_id, CustomEmojiId background_custom_emoji_id, - Promise &&promise) { - if (!accent_color_id.is_valid()) { - return promise.set_error(Status::Error(400, "Invalid accent color identifier specified")); - } - if (accent_color_id == AccentColorId(get_my_id())) { - accent_color_id = AccentColorId(); - } - - td_->create_handler(std::move(promise))->send(false, accent_color_id, background_custom_emoji_id); -} - -void ContactsManager::set_profile_accent_color(AccentColorId accent_color_id, CustomEmojiId background_custom_emoji_id, - Promise &&promise) { - td_->create_handler(std::move(promise))->send(true, accent_color_id, background_custom_emoji_id); -} - -void ContactsManager::set_name(const string &first_name, const string &last_name, Promise &&promise) { - auto new_first_name = clean_name(first_name, MAX_NAME_LENGTH); - auto new_last_name = clean_name(last_name, MAX_NAME_LENGTH); - if (new_first_name.empty()) { - return promise.set_error(Status::Error(400, "First name must be non-empty")); - } - - const User *u = get_user(get_my_id()); - int32 flags = 0; - // TODO we can already send request for changing first_name and last_name and wanting to set initial values - // TODO need to be rewritten using invoke after and cancelling previous request - if (u == nullptr || u->first_name != new_first_name) { - flags |= ACCOUNT_UPDATE_FIRST_NAME; - } - if (u == nullptr || u->last_name != new_last_name) { - flags |= ACCOUNT_UPDATE_LAST_NAME; - } - if (flags == 0) { - return promise.set_value(Unit()); - } - - td_->create_handler(std::move(promise))->send(flags, new_first_name, new_last_name, ""); -} - -void ContactsManager::set_bio(const string &bio, Promise &&promise) { - auto max_bio_length = static_cast(td_->option_manager_->get_option_integer("bio_length_max")); - auto new_bio = strip_empty_characters(bio, max_bio_length); - for (auto &c : new_bio) { - if (c == '\n') { - c = ' '; - } - } - - const UserFull *user_full = get_user_full(get_my_id()); - int32 flags = 0; - // TODO we can already send request for changing bio and wanting to set initial values - // TODO need to be rewritten using invoke after and cancelling previous request - if (user_full == nullptr || user_full->about != new_bio) { - flags |= ACCOUNT_UPDATE_ABOUT; - } - if (flags == 0) { - return promise.set_value(Unit()); - } - - td_->create_handler(std::move(promise))->send(flags, "", "", new_bio); -} - -void ContactsManager::on_update_accent_color_success(bool for_profile, AccentColorId accent_color_id, - CustomEmojiId background_custom_emoji_id) { - auto user_id = get_my_id(); - User *u = get_user_force(user_id, "on_update_accent_color_success"); - if (u == nullptr) { - return; - } - if (for_profile) { - on_update_user_profile_accent_color_id(u, user_id, accent_color_id); - on_update_user_profile_background_custom_emoji_id(u, user_id, background_custom_emoji_id); - } else { - on_update_user_accent_color_id(u, user_id, accent_color_id); - on_update_user_background_custom_emoji_id(u, user_id, background_custom_emoji_id); - } - update_user(u, user_id); -} - -void ContactsManager::on_update_profile_success(int32 flags, const string &first_name, const string &last_name, - const string &about) { - CHECK(flags != 0); - - auto my_user_id = get_my_id(); - const User *u = get_user(my_user_id); - if (u == nullptr) { - LOG(ERROR) << "Doesn't receive info about me during update profile"; - return; - } - LOG_IF(ERROR, (flags & ACCOUNT_UPDATE_FIRST_NAME) != 0 && u->first_name != first_name) - << "Wrong first name \"" << u->first_name << "\", expected \"" << first_name << '"'; - LOG_IF(ERROR, (flags & ACCOUNT_UPDATE_LAST_NAME) != 0 && u->last_name != last_name) - << "Wrong last name \"" << u->last_name << "\", expected \"" << last_name << '"'; - - if ((flags & ACCOUNT_UPDATE_ABOUT) != 0) { - UserFull *user_full = get_user_full_force(my_user_id, "on_update_profile_success"); - if (user_full != nullptr) { - user_full->about = about; - user_full->is_changed = true; - update_user_full(user_full, my_user_id, "on_update_profile_success"); - td_->group_call_manager_->on_update_dialog_about(DialogId(my_user_id), user_full->about, true); - } - } -} - -void ContactsManager::set_username(const string &username, Promise &&promise) { - if (!username.empty() && !is_allowed_username(username)) { - return promise.set_error(Status::Error(400, "Username is invalid")); - } - td_->create_handler(std::move(promise))->send(username); -} - -void ContactsManager::toggle_username_is_active(string &&username, bool is_active, Promise &&promise) { - get_me(PromiseCreator::lambda([actor_id = actor_id(this), username = std::move(username), is_active, - promise = std::move(promise)](Result &&result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - send_closure(actor_id, &ContactsManager::toggle_username_is_active_impl, std::move(username), is_active, - std::move(promise)); - } - })); -} - -void ContactsManager::toggle_username_is_active_impl(string &&username, bool is_active, Promise &&promise) { - TRY_STATUS_PROMISE(promise, G()->close_status()); - const User *u = get_user(get_my_id()); - CHECK(u != nullptr); - if (!u->usernames.can_toggle(username)) { - return promise.set_error(Status::Error(400, "Wrong username specified")); - } - td_->create_handler(std::move(promise))->send(std::move(username), is_active); -} - -void ContactsManager::reorder_usernames(vector &&usernames, Promise &&promise) { - get_me(PromiseCreator::lambda([actor_id = actor_id(this), usernames = std::move(usernames), - promise = std::move(promise)](Result &&result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - send_closure(actor_id, &ContactsManager::reorder_usernames_impl, std::move(usernames), std::move(promise)); - } - })); -} - -void ContactsManager::reorder_usernames_impl(vector &&usernames, Promise &&promise) { - TRY_STATUS_PROMISE(promise, G()->close_status()); - const User *u = get_user(get_my_id()); - CHECK(u != nullptr); - if (!u->usernames.can_reorder_to(usernames)) { - return promise.set_error(Status::Error(400, "Invalid username order specified")); - } - if (usernames.size() <= 1) { - return promise.set_value(Unit()); - } - td_->create_handler(std::move(promise))->send(std::move(usernames)); -} - -void ContactsManager::on_update_username_is_active(UserId user_id, string &&username, bool is_active, - Promise &&promise) { - User *u = get_user(user_id); - CHECK(u != nullptr); - if (!u->usernames.can_toggle(username)) { - return reload_user(user_id, std::move(promise), "on_update_username_is_active"); - } - on_update_user_usernames(u, user_id, u->usernames.toggle(username, is_active)); - update_user(u, user_id); - promise.set_value(Unit()); -} - -void ContactsManager::on_update_active_usernames_order(UserId user_id, vector &&usernames, - Promise &&promise) { - User *u = get_user(user_id); - CHECK(u != nullptr); - if (!u->usernames.can_reorder_to(usernames)) { - return reload_user(user_id, std::move(promise), "on_update_active_usernames_order"); - } - on_update_user_usernames(u, user_id, u->usernames.reorder_to(std::move(usernames))); - update_user(u, user_id); - promise.set_value(Unit()); -} - -void ContactsManager::toggle_bot_username_is_active(UserId bot_user_id, string &&username, bool is_active, - Promise &&promise) { - TRY_RESULT_PROMISE(promise, bot_data, get_bot_data(bot_user_id)); - if (!bot_data.can_be_edited) { - return promise.set_error(Status::Error(400, "The bot can't be edited")); - } - const User *u = get_user(bot_user_id); - CHECK(u != nullptr); - if (!u->usernames.can_toggle(username)) { - return promise.set_error(Status::Error(400, "Wrong username specified")); - } - td_->create_handler(std::move(promise))->send(bot_user_id, std::move(username), is_active); -} - -void ContactsManager::reorder_bot_usernames(UserId bot_user_id, vector &&usernames, Promise &&promise) { - TRY_RESULT_PROMISE(promise, bot_data, get_bot_data(bot_user_id)); - if (!bot_data.can_be_edited) { - return promise.set_error(Status::Error(400, "The bot can't be edited")); - } - const User *u = get_user(bot_user_id); - CHECK(u != nullptr); - if (!u->usernames.can_reorder_to(usernames)) { - return promise.set_error(Status::Error(400, "Invalid username order specified")); - } - if (usernames.size() <= 1) { - return promise.set_value(Unit()); - } - td_->create_handler(std::move(promise))->send(bot_user_id, std::move(usernames)); -} - -void ContactsManager::set_birthdate(Birthdate &&birthdate, Promise &&promise) { - dismiss_suggested_action(SuggestedAction{SuggestedAction::Type::BirthdaySetup}, Promise()); - auto query_promise = PromiseCreator::lambda( - [actor_id = actor_id(this), birthdate, promise = std::move(promise)](Result result) mutable { - if (result.is_ok()) { - send_closure(actor_id, &ContactsManager::on_set_birthdate, birthdate, std::move(promise)); - } else { - promise.set_error(result.move_as_error()); - } - }); - td_->create_handler(std::move(query_promise))->send(birthdate); -} - -void ContactsManager::on_set_birthdate(Birthdate birthdate, Promise &&promise) { - auto my_user_id = get_my_id(); - UserFull *user_full = get_user_full_force(my_user_id, "on_set_birthdate"); - if (user_full != nullptr && user_full->birthdate != birthdate) { - user_full->birthdate = std::move(birthdate); - user_full->is_changed = true; - update_user_full(user_full, my_user_id, "on_set_birthdate"); - } - promise.set_value(Unit()); -} - -void ContactsManager::set_personal_channel(DialogId dialog_id, Promise &&promise) { - ChannelId channel_id; - if (dialog_id != DialogId() && !td_->dialog_manager_->have_dialog_force(dialog_id, "set_personal_channel")) { - return promise.set_error(Status::Error(400, "Chat not found")); - } - if (dialog_id != DialogId()) { - if (dialog_id.get_type() != DialogType::Channel) { - return promise.set_error(Status::Error(400, "Chat can't be set as a personal chat")); - } - channel_id = dialog_id.get_channel_id(); - if (!is_suitable_created_public_channel(PublicDialogType::ForPersonalDialog, get_channel(channel_id))) { - return promise.set_error(Status::Error(400, "Chat can't be set as a personal chat")); - } - } - auto query_promise = PromiseCreator::lambda( - [actor_id = actor_id(this), channel_id, promise = std::move(promise)](Result result) mutable { - if (result.is_ok()) { - send_closure(actor_id, &ContactsManager::on_set_personal_channel, channel_id, std::move(promise)); - } else { - promise.set_error(result.move_as_error()); - } - }); - td_->create_handler(std::move(query_promise))->send(channel_id); -} - -void ContactsManager::on_set_personal_channel(ChannelId channel_id, Promise &&promise) { - auto my_user_id = get_my_id(); - UserFull *user_full = get_user_full_force(my_user_id, "on_set_personal_channel"); - if (user_full != nullptr && user_full->personal_channel_id != channel_id) { - user_full->personal_channel_id = channel_id; - user_full->is_changed = true; - update_user_full(user_full, my_user_id, "on_set_personal_channel"); - } - promise.set_value(Unit()); -} - -void ContactsManager::set_emoji_status(const EmojiStatus &emoji_status, Promise &&promise) { - if (!td_->option_manager_->get_option_boolean("is_premium")) { - return promise.set_error(Status::Error(400, "The method is available only to Telegram Premium users")); - } - add_recent_emoji_status(td_, emoji_status); - auto query_promise = PromiseCreator::lambda( - [actor_id = actor_id(this), emoji_status, promise = std::move(promise)](Result result) mutable { - if (result.is_ok()) { - send_closure(actor_id, &ContactsManager::on_set_emoji_status, emoji_status, std::move(promise)); - } else { - promise.set_error(result.move_as_error()); - } - }); - td_->create_handler(std::move(query_promise))->send(emoji_status); -} - -void ContactsManager::on_set_emoji_status(EmojiStatus emoji_status, Promise &&promise) { - auto user_id = get_my_id(); - User *u = get_user(user_id); - if (u != nullptr) { - on_update_user_emoji_status(u, user_id, emoji_status); - update_user(u, user_id); - } - promise.set_value(Unit()); -} - void ContactsManager::set_chat_description(ChatId chat_id, const string &description, Promise &&promise) { auto new_description = strip_empty_characters(description, MAX_DESCRIPTION_LENGTH); auto c = get_chat(chat_id); @@ -7248,7 +3473,7 @@ void ContactsManager::report_channel_spam(ChannelId channel_id, const vectormessages_manager_->get_dialog_message_sender({DialogId(channel_id), message_id}); CHECK(sender_dialog_id.get_type() != DialogType::SecretChat); - if (sender_dialog_id.is_valid() && sender_dialog_id != DialogId(get_my_id()) && + if (sender_dialog_id.is_valid() && sender_dialog_id != td_->dialog_manager_->get_my_dialog_id() && td_->dialog_manager_->have_input_peer(sender_dialog_id, AccessRights::Know)) { server_message_ids[sender_dialog_id].push_back(message_id); } @@ -7615,26 +3840,6 @@ void ContactsManager::remove_inactive_channel(ChannelId channel_id) { } } -void ContactsManager::register_message_users(MessageFullId message_full_id, vector user_ids) { - auto dialog_id = message_full_id.get_dialog_id(); - CHECK(dialog_id.get_type() == DialogType::Channel); - if (!have_channel(dialog_id.get_channel_id())) { - return; - } - for (auto user_id : user_ids) { - CHECK(user_id.is_valid()); - const User *u = get_user(user_id); - if (u == nullptr || u->access_hash == -1 || u->is_min_access_hash) { - auto &user_messages = user_messages_[user_id]; - auto need_update = user_messages.empty(); - user_messages.insert(message_full_id); - if (need_update) { - send_closure(G()->td(), &Td::send_update, get_update_user_object(user_id, u)); - } - } - } -} - void ContactsManager::register_message_channels(MessageFullId message_full_id, vector channel_ids) { auto dialog_id = message_full_id.get_dialog_id(); CHECK(dialog_id.get_type() == DialogType::Channel); @@ -7652,27 +3857,6 @@ void ContactsManager::register_message_channels(MessageFullId message_full_id, v } } -void ContactsManager::unregister_message_users(MessageFullId message_full_id, vector user_ids) { - if (user_messages_.empty()) { - // fast path - return; - } - for (auto user_id : user_ids) { - auto it = user_messages_.find(user_id); - if (it != user_messages_.end()) { - it->second.erase(message_full_id); - if (it->second.empty()) { - user_messages_.erase(it); - - const User *u = get_user(user_id); - if (u == nullptr || u->access_hash == -1 || u->is_min_access_hash) { - send_closure(G()->td(), &Td::send_update, get_update_user_object(user_id, u)); - } - } - } - } -} - void ContactsManager::unregister_message_channels(MessageFullId message_full_id, vector channel_ids) { if (channel_messages_.empty()) { // fast path @@ -7689,284 +3873,6 @@ void ContactsManager::unregister_message_channels(MessageFullId message_full_id, } } -void ContactsManager::on_import_contacts_finished(int64 random_id, vector imported_contact_user_ids, - vector unimported_contact_invites) { - LOG(INFO) << "Contacts import with random_id " << random_id - << " has finished: " << format::as_array(imported_contact_user_ids); - if (random_id == 1) { - // import from change_imported_contacts - all_imported_contacts_ = std::move(next_all_imported_contacts_); - next_all_imported_contacts_.clear(); - - auto result_size = imported_contacts_unique_id_.size(); - auto unique_size = all_imported_contacts_.size(); - auto add_size = imported_contacts_pos_.size(); - - imported_contact_user_ids_.resize(result_size); - unimported_contact_invites_.resize(result_size); - - CHECK(imported_contact_user_ids.size() == add_size); - CHECK(unimported_contact_invites.size() == add_size); - CHECK(imported_contacts_unique_id_.size() == result_size); - - std::unordered_map> unique_id_to_unimported_contact_invites; - for (size_t i = 0; i < add_size; i++) { - auto unique_id = imported_contacts_pos_[i]; - get_user_id_object(imported_contact_user_ids[i], "on_import_contacts_finished"); // to ensure updateUser - all_imported_contacts_[unique_id].set_user_id(imported_contact_user_ids[i]); - unique_id_to_unimported_contact_invites[narrow_cast(unique_id)] = unimported_contact_invites[i]; - } - - if (G()->use_chat_info_database()) { - G()->td_db()->get_binlog()->force_sync( - PromiseCreator::lambda( - [log_event = log_event_store(all_imported_contacts_).as_slice().str()](Result<> result) mutable { - if (result.is_ok()) { - LOG(INFO) << "Save imported contacts to database"; - G()->td_db()->get_sqlite_pmc()->set("user_imported_contacts", std::move(log_event), Auto()); - } - }), - "on_import_contacts_finished"); - } - - for (size_t i = 0; i < result_size; i++) { - auto unique_id = imported_contacts_unique_id_[i]; - CHECK(unique_id < unique_size); - imported_contact_user_ids_[i] = all_imported_contacts_[unique_id].get_user_id(); - auto it = unique_id_to_unimported_contact_invites.find(narrow_cast(unique_id)); - if (it == unique_id_to_unimported_contact_invites.end()) { - unimported_contact_invites_[i] = 0; - } else { - unimported_contact_invites_[i] = it->second; - } - } - return; - } - - auto it = imported_contacts_.find(random_id); - CHECK(it != imported_contacts_.end()); - CHECK(it->second.first.empty()); - CHECK(it->second.second.empty()); - imported_contacts_[random_id] = {std::move(imported_contact_user_ids), std::move(unimported_contact_invites)}; -} - -void ContactsManager::on_deleted_contacts(const vector &deleted_contact_user_ids) { - LOG(INFO) << "Contacts deletion has finished for " << deleted_contact_user_ids; - - for (auto user_id : deleted_contact_user_ids) { - auto u = get_user(user_id); - CHECK(u != nullptr); - if (!u->is_contact) { - continue; - } - - LOG(INFO) << "Drop contact with " << user_id; - on_update_user_is_contact(u, user_id, false, false, false); - CHECK(u->is_is_contact_changed); - u->cache_version = 0; - u->is_repaired = false; - update_user(u, user_id); - CHECK(!u->is_contact); - CHECK(!contacts_hints_.has_key(user_id.get())); - } -} - -void ContactsManager::save_next_contacts_sync_date() { - if (G()->close_flag()) { - return; - } - if (!G()->use_chat_info_database()) { - return; - } - G()->td_db()->get_binlog_pmc()->set("next_contacts_sync_date", to_string(next_contacts_sync_date_)); -} - -void ContactsManager::on_get_contacts(tl_object_ptr &&new_contacts) { - next_contacts_sync_date_ = G()->unix_time() + Random::fast(70000, 100000); - - CHECK(new_contacts != nullptr); - if (new_contacts->get_id() == telegram_api::contacts_contactsNotModified::ID) { - if (saved_contact_count_ == -1) { - saved_contact_count_ = 0; - } - on_get_contacts_finished(contacts_hints_.size()); - td_->create_handler()->send(); - return; - } - - auto contacts = move_tl_object_as(new_contacts); - FlatHashSet contact_user_ids; - for (auto &user : contacts->users_) { - auto user_id = get_user_id(user); - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - continue; - } - contact_user_ids.insert(user_id); - } - on_get_users(std::move(contacts->users_), "on_get_contacts"); - - UserId my_id = get_my_id(); - users_.foreach([&](const UserId &user_id, unique_ptr &user) { - User *u = user.get(); - bool should_be_contact = contact_user_ids.count(user_id) == 1; - if (u->is_contact != should_be_contact) { - if (u->is_contact) { - LOG(INFO) << "Drop contact with " << user_id; - if (user_id != my_id) { - LOG_CHECK(contacts_hints_.has_key(user_id.get())) - << my_id << " " << user_id << " " << to_string(get_user_object(user_id, u)); - } - on_update_user_is_contact(u, user_id, false, false, false); - CHECK(u->is_is_contact_changed); - u->cache_version = 0; - u->is_repaired = false; - update_user(u, user_id); - CHECK(!u->is_contact); - if (user_id != my_id) { - CHECK(!contacts_hints_.has_key(user_id.get())); - } - } else { - LOG(ERROR) << "Receive non-contact " << user_id << " in the list of contacts"; - } - } - }); - - saved_contact_count_ = contacts->saved_count_; - on_get_contacts_finished(std::numeric_limits::max()); -} - -void ContactsManager::save_contacts_to_database() { - if (!G()->use_chat_info_database() || !are_contacts_loaded_) { - return; - } - - LOG(INFO) << "Schedule save contacts to database"; - vector user_ids = - transform(contacts_hints_.search_empty(100000).second, [](int64 key) { return UserId(key); }); - - G()->td_db()->get_binlog_pmc()->set("saved_contact_count", to_string(saved_contact_count_)); - G()->td_db()->get_binlog()->force_sync( - PromiseCreator::lambda([user_ids = std::move(user_ids)](Result<> result) { - if (result.is_ok()) { - LOG(INFO) << "Saved contacts to database"; - G()->td_db()->get_sqlite_pmc()->set( - "user_contacts", log_event_store(user_ids).as_slice().str(), PromiseCreator::lambda([](Result<> result) { - if (result.is_ok()) { - send_closure(G()->contacts_manager(), &ContactsManager::save_next_contacts_sync_date); - } - })); - } - }), - "save_contacts_to_database"); -} - -void ContactsManager::on_get_contacts_failed(Status error) { - CHECK(error.is_error()); - next_contacts_sync_date_ = G()->unix_time() + Random::fast(5, 10); - fail_promises(load_contacts_queries_, std::move(error)); -} - -void ContactsManager::on_load_contacts_from_database(string value) { - if (G()->close_flag()) { - return; - } - if (value.empty()) { - reload_contacts(true); - return; - } - - vector user_ids; - if (log_event_parse(user_ids, value).is_error()) { - LOG(ERROR) << "Failed to load contacts from database"; - reload_contacts(true); - return; - } - - if (log_event_get_version(value) < static_cast(Version::AddUserFlags2)) { - next_contacts_sync_date_ = 0; - save_next_contacts_sync_date(); - reload_contacts(true); - } - - LOG(INFO) << "Successfully loaded " << user_ids.size() << " contacts from database"; - - load_contact_users_multipromise_.add_promise(PromiseCreator::lambda( - [actor_id = actor_id(this), expected_contact_count = user_ids.size()](Result result) { - if (result.is_ok()) { - send_closure(actor_id, &ContactsManager::on_get_contacts_finished, expected_contact_count); - } else { - LOG(INFO) << "Failed to load contact users from database: " << result.error(); - send_closure(actor_id, &ContactsManager::reload_contacts, true); - } - })); - - auto lock_promise = load_contact_users_multipromise_.get_promise(); - - for (auto user_id : user_ids) { - get_user(user_id, 3, load_contact_users_multipromise_.get_promise()); - } - - lock_promise.set_value(Unit()); -} - -void ContactsManager::on_get_contacts_finished(size_t expected_contact_count) { - LOG(INFO) << "Finished to get " << contacts_hints_.size() << " contacts out of expected " << expected_contact_count; - are_contacts_loaded_ = true; - set_promises(load_contacts_queries_); - if (expected_contact_count != contacts_hints_.size()) { - save_contacts_to_database(); - } -} - -void ContactsManager::on_get_contacts_statuses(vector> &&statuses) { - auto my_user_id = get_my_id(); - for (auto &status : statuses) { - UserId user_id(status->user_id_); - if (user_id != my_user_id) { - on_update_user_online(user_id, std::move(status->status_)); - } - } - save_next_contacts_sync_date(); -} - -void ContactsManager::on_update_online_status_privacy() { - td_->create_handler()->send(); -} - -void ContactsManager::on_update_phone_number_privacy() { - // all UserFull.need_phone_number_privacy_exception can be outdated now, - // so mark all of them as expired - users_full_.foreach([&](const UserId &user_id, unique_ptr &user_full) { user_full->expires_at = 0.0; }); -} - -void ContactsManager::invalidate_user_full(UserId user_id) { - auto user_full = get_user_full_force(user_id, "invalidate_user_full"); - if (user_full != nullptr) { - td_->dialog_manager_->on_dialog_info_full_invalidated(DialogId(user_id)); - - if (!user_full->is_expired()) { - user_full->expires_at = 0.0; - user_full->need_save_to_database = true; - - update_user_full(user_full, user_id, "invalidate_user_full"); - } - } -} - -UserId ContactsManager::get_user_id(const tl_object_ptr &user) { - CHECK(user != nullptr); - switch (user->get_id()) { - case telegram_api::userEmpty::ID: - return UserId(static_cast(user.get())->id_); - case telegram_api::user::ID: - return UserId(static_cast(user.get())->id_); - default: - UNREACHABLE(); - return UserId(); - } -} - ChatId ContactsManager::get_chat_id(const tl_object_ptr &chat) { CHECK(chat != nullptr); switch (chat->get_id()) { @@ -8001,614 +3907,6 @@ DialogId ContactsManager::get_dialog_id(const tl_object_ptr return DialogId(get_chat_id(chat)); } -void ContactsManager::on_get_user(tl_object_ptr &&user_ptr, const char *source) { - LOG(DEBUG) << "Receive from " << source << ' ' << to_string(user_ptr); - int32 constructor_id = user_ptr->get_id(); - if (constructor_id == telegram_api::userEmpty::ID) { - auto user = move_tl_object_as(user_ptr); - UserId user_id(user->id_); - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id << " from " << source; - return; - } - LOG(INFO) << "Receive empty " << user_id << " from " << source; - - User *u = get_user_force(user_id, source); - if (u == nullptr && Slice(source) != Slice("GetUsersQuery")) { - // userEmpty should be received only through getUsers for nonexistent users - LOG(ERROR) << "Have no information about " << user_id << ", but received userEmpty from " << source; - } - return; - } - - CHECK(constructor_id == telegram_api::user::ID); - auto user = move_tl_object_as(user_ptr); - UserId user_id(user->id_); - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - int32 flags = user->flags_; - int32 flags2 = user->flags2_; - LOG(INFO) << "Receive " << user_id << " with flags " << flags << ' ' << flags2 << " from " << source; - - // the True fields aren't set for manually created telegram_api::user objects, therefore the flags must be used - bool is_bot = (flags & USER_FLAG_IS_BOT) != 0; - if (flags & USER_FLAG_IS_ME) { - set_my_id(user_id); - if (!is_bot) { - td_->option_manager_->set_option_string("my_phone_number", user->phone_); - } - } - - bool have_access_hash = (flags & USER_FLAG_HAS_ACCESS_HASH) != 0; - bool is_received = (flags & USER_FLAG_IS_INACCESSIBLE) == 0; - bool is_contact = (flags & USER_FLAG_IS_CONTACT) != 0; - - User *u = get_user(user_id); - if (u == nullptr) { - if (!is_received) { - // we must preload received inaccessible users from database in order to not save - // the min-user to the database and to not override access_hash and other data - u = get_user_force(user_id, "on_get_user 2"); - if (u == nullptr) { - LOG(INFO) << "Receive inaccessible " << user_id; - u = add_user(user_id); - } - } else if (is_contact && !are_contacts_loaded_) { - // preload contact users from database to know that is_contact didn't changed - // and the list of contacts doesn't need to be saved to the database - u = get_user_force(user_id, "on_get_user 3"); - if (u == nullptr) { - LOG(INFO) << "Receive contact " << user_id << " for the first time"; - u = add_user(user_id); - } - } else { - u = add_user(user_id); - } - CHECK(u != nullptr); - } - - if (have_access_hash) { // access_hash must be updated before photo - auto access_hash = user->access_hash_; - bool is_min_access_hash = !is_received && !((flags & USER_FLAG_HAS_PHONE_NUMBER) != 0 && user->phone_.empty()); - if (u->access_hash != access_hash && (!is_min_access_hash || u->is_min_access_hash || u->access_hash == -1)) { - LOG(DEBUG) << "Access hash has changed for " << user_id << " from " << u->access_hash << "/" - << u->is_min_access_hash << " to " << access_hash << "/" << is_min_access_hash; - u->access_hash = access_hash; - u->is_min_access_hash = is_min_access_hash; - u->need_save_to_database = true; - } - } - - bool is_verified = (flags & USER_FLAG_IS_VERIFIED) != 0; - bool is_premium = (flags & USER_FLAG_IS_PREMIUM) != 0; - bool is_support = (flags & USER_FLAG_IS_SUPPORT) != 0; - bool is_deleted = (flags & USER_FLAG_IS_DELETED) != 0; - bool can_join_groups = (flags & USER_FLAG_IS_PRIVATE_BOT) == 0; - bool can_read_all_group_messages = (flags & USER_FLAG_IS_BOT_WITH_PRIVACY_DISABLED) != 0; - bool can_be_added_to_attach_menu = (flags & USER_FLAG_IS_ATTACH_MENU_BOT) != 0; - bool attach_menu_enabled = (flags & USER_FLAG_ATTACH_MENU_ENABLED) != 0; - bool is_scam = (flags & USER_FLAG_IS_SCAM) != 0; - bool can_be_edited_bot = (flags2 & USER_FLAG_CAN_BE_EDITED_BOT) != 0; - bool is_inline_bot = (flags & USER_FLAG_IS_INLINE_BOT) != 0; - bool is_business_bot = user->bot_business_; - string inline_query_placeholder = std::move(user->bot_inline_placeholder_); - bool need_location_bot = (flags & USER_FLAG_NEED_LOCATION_BOT) != 0; - bool has_bot_info_version = (flags & USER_FLAG_HAS_BOT_INFO_VERSION) != 0; - bool need_apply_min_photo = (flags & USER_FLAG_NEED_APPLY_MIN_PHOTO) != 0; - bool is_fake = (flags & USER_FLAG_IS_FAKE) != 0; - bool stories_available = user->stories_max_id_ > 0; - bool stories_unavailable = user->stories_unavailable_; - bool stories_hidden = user->stories_hidden_; - bool contact_require_premium = user->contact_require_premium_; - - if (!is_bot && (!can_join_groups || can_read_all_group_messages || can_be_added_to_attach_menu || can_be_edited_bot || - is_inline_bot || is_business_bot)) { - LOG(ERROR) << "Receive not bot " << user_id << " with bot properties from " << source; - can_join_groups = true; - can_read_all_group_messages = false; - can_be_added_to_attach_menu = false; - can_be_edited_bot = false; - is_inline_bot = false; - is_business_bot = false; - } - if (need_location_bot && !is_inline_bot) { - LOG(ERROR) << "Receive not inline bot " << user_id << " which needs user location from " << source; - need_location_bot = false; - } - - if (is_deleted) { - // just in case - is_verified = false; - is_premium = false; - is_support = false; - is_bot = false; - can_join_groups = false; - can_read_all_group_messages = false; - can_be_added_to_attach_menu = false; - can_be_edited_bot = false; - is_inline_bot = false; - is_business_bot = false; - inline_query_placeholder = string(); - need_location_bot = false; - has_bot_info_version = false; - need_apply_min_photo = false; - } - - LOG_IF(ERROR, has_bot_info_version && !is_bot) - << "Receive not bot " << user_id << " which has bot info version from " << source; - - int32 bot_info_version = has_bot_info_version ? user->bot_info_version_ : -1; - if (is_verified != u->is_verified || is_support != u->is_support || is_bot != u->is_bot || - can_join_groups != u->can_join_groups || can_read_all_group_messages != u->can_read_all_group_messages || - is_scam != u->is_scam || is_fake != u->is_fake || is_inline_bot != u->is_inline_bot || - is_business_bot != u->is_business_bot || inline_query_placeholder != u->inline_query_placeholder || - need_location_bot != u->need_location_bot || can_be_added_to_attach_menu != u->can_be_added_to_attach_menu) { - if (is_bot != u->is_bot) { - LOG_IF(ERROR, !is_deleted && !u->is_deleted && u->is_received) - << "User.is_bot has changed for " << user_id << "/" << u->usernames << " from " << source << " from " - << u->is_bot << " to " << is_bot; - u->is_full_info_changed = true; - } - u->is_verified = is_verified; - u->is_support = is_support; - u->is_bot = is_bot; - u->can_join_groups = can_join_groups; - u->can_read_all_group_messages = can_read_all_group_messages; - u->is_scam = is_scam; - u->is_fake = is_fake; - u->is_inline_bot = is_inline_bot; - u->is_business_bot = is_business_bot; - u->inline_query_placeholder = std::move(inline_query_placeholder); - u->need_location_bot = need_location_bot; - u->can_be_added_to_attach_menu = can_be_added_to_attach_menu; - - LOG(DEBUG) << "Info has changed for " << user_id; - u->is_changed = true; - } - if (u->contact_require_premium != contact_require_premium) { - u->contact_require_premium = contact_require_premium; - u->is_changed = true; - user_full_contact_require_premium_.erase(user_id); - } - if (is_received && attach_menu_enabled != u->attach_menu_enabled) { - u->attach_menu_enabled = attach_menu_enabled; - u->is_changed = true; - } - if (is_premium != u->is_premium) { - u->is_premium = is_premium; - u->is_is_premium_changed = true; - u->is_changed = true; - u->is_full_info_changed = true; - } - if (is_received && can_be_edited_bot != u->can_be_edited_bot) { - u->can_be_edited_bot = can_be_edited_bot; - u->is_changed = true; - u->is_full_info_changed = true; - } - - if (u->bot_info_version != bot_info_version) { - u->bot_info_version = bot_info_version; - LOG(DEBUG) << "Bot info version has changed for " << user_id; - u->need_save_to_database = true; - } - if (is_received && u->need_apply_min_photo != need_apply_min_photo) { - LOG(DEBUG) << "Need apply min photo has changed for " << user_id; - u->need_apply_min_photo = need_apply_min_photo; - u->need_save_to_database = true; - } - - if (is_received && !u->is_received) { - u->is_received = true; - - LOG(DEBUG) << "Receive " << user_id; - u->is_changed = true; - } - - if (is_deleted != u->is_deleted) { - u->is_deleted = is_deleted; - - LOG(DEBUG) << "User.is_deleted has changed for " << user_id << " to " << u->is_deleted; - u->is_is_deleted_changed = true; - u->is_changed = true; - } - - bool has_language_code = (flags & USER_FLAG_HAS_LANGUAGE_CODE) != 0; - LOG_IF(ERROR, has_language_code && !td_->auth_manager_->is_bot()) - << "Receive language code for " << user_id << " from " << source; - if (u->language_code != user->lang_code_ && !user->lang_code_.empty()) { - u->language_code = user->lang_code_; - - LOG(DEBUG) << "Language code has changed for " << user_id << " to " << u->language_code; - u->is_changed = true; - } - - bool is_me_regular_user = !td_->auth_manager_->is_bot(); - if (is_received || u->need_apply_min_photo || !u->is_received) { - on_update_user_photo(u, user_id, std::move(user->photo_), source); - } - if (is_me_regular_user) { - if (is_received || !u->is_received) { - on_update_user_phone_number(u, user_id, std::move(user->phone_)); - } - if (is_received || !u->is_received || u->was_online == 0) { - on_update_user_online(u, user_id, std::move(user->status_)); - } - if (is_received) { - auto is_mutual_contact = (flags & USER_FLAG_IS_MUTUAL_CONTACT) != 0; - auto is_close_friend = (flags2 & USER_FLAG_IS_CLOSE_FRIEND) != 0; - on_update_user_is_contact(u, user_id, is_contact, is_mutual_contact, is_close_friend); - } - } - - if (is_received || !u->is_received) { - on_update_user_name(u, user_id, std::move(user->first_name_), std::move(user->last_name_)); - on_update_user_usernames(u, user_id, Usernames{std::move(user->username_), std::move(user->usernames_)}); - } - on_update_user_emoji_status(u, user_id, EmojiStatus(std::move(user->emoji_status_))); - PeerColor peer_color(user->color_); - on_update_user_accent_color_id(u, user_id, peer_color.accent_color_id_); - on_update_user_background_custom_emoji_id(u, user_id, peer_color.background_custom_emoji_id_); - PeerColor profile_peer_color(user->profile_color_); - on_update_user_profile_accent_color_id(u, user_id, profile_peer_color.accent_color_id_); - on_update_user_profile_background_custom_emoji_id(u, user_id, profile_peer_color.background_custom_emoji_id_); - if (is_me_regular_user) { - if (is_received) { - on_update_user_stories_hidden(u, user_id, stories_hidden); - } - if (stories_available || stories_unavailable) { - // update at the end, because it calls need_poll_user_active_stories - on_update_user_story_ids_impl(u, user_id, StoryId(user->stories_max_id_), StoryId()); - } - auto restriction_reasons = get_restriction_reasons(std::move(user->restriction_reason_)); - if (restriction_reasons != u->restriction_reasons) { - u->restriction_reasons = std::move(restriction_reasons); - u->is_changed = true; - } - } - - if (u->cache_version != User::CACHE_VERSION && u->is_received) { - u->cache_version = User::CACHE_VERSION; - u->need_save_to_database = true; - } - u->is_received_from_server = true; - update_user(u, user_id); -} - -class ContactsManager::UserLogEvent { - public: - UserId user_id; - const User *u_in = nullptr; - unique_ptr u_out; - - UserLogEvent() = default; - - UserLogEvent(UserId user_id, const User *u) : user_id(user_id), u_in(u) { - } - - template - void store(StorerT &storer) const { - td::store(user_id, storer); - td::store(*u_in, storer); - } - - template - void parse(ParserT &parser) { - td::parse(user_id, parser); - td::parse(u_out, parser); - } -}; - -void ContactsManager::save_user(User *u, UserId user_id, bool from_binlog) { - if (!G()->use_chat_info_database()) { - return; - } - CHECK(u != nullptr); - if (!u->is_saved || !u->is_status_saved) { // TODO more effective handling of !u->is_status_saved - if (!from_binlog) { - auto log_event = UserLogEvent(user_id, u); - auto storer = get_log_event_storer(log_event); - if (u->log_event_id == 0) { - u->log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::Users, storer); - } else { - binlog_rewrite(G()->td_db()->get_binlog(), u->log_event_id, LogEvent::HandlerType::Users, storer); - } - } - - save_user_to_database(u, user_id); - } -} - -void ContactsManager::on_binlog_user_event(BinlogEvent &&event) { - if (!G()->use_chat_info_database()) { - binlog_erase(G()->td_db()->get_binlog(), event.id_); - return; - } - - UserLogEvent log_event; - if (log_event_parse(log_event, event.get_data()).is_error()) { - LOG(ERROR) << "Failed to load a user from binlog"; - binlog_erase(G()->td_db()->get_binlog(), event.id_); - return; - } - - auto user_id = log_event.user_id; - if (have_min_user(user_id) || !user_id.is_valid()) { - LOG(ERROR) << "Skip adding already added " << user_id; - binlog_erase(G()->td_db()->get_binlog(), event.id_); - return; - } - - LOG(INFO) << "Add " << user_id << " from binlog"; - users_.set(user_id, std::move(log_event.u_out)); - - User *u = get_user(user_id); - CHECK(u != nullptr); - u->log_event_id = event.id_; - - update_user(u, user_id, true, false); -} - -string ContactsManager::get_user_database_key(UserId user_id) { - return PSTRING() << "us" << user_id.get(); -} - -string ContactsManager::get_user_database_value(const User *u) { - return log_event_store(*u).as_slice().str(); -} - -void ContactsManager::save_user_to_database(User *u, UserId user_id) { - CHECK(u != nullptr); - if (u->is_being_saved) { - return; - } - if (loaded_from_database_users_.count(user_id)) { - save_user_to_database_impl(u, user_id, get_user_database_value(u)); - return; - } - if (load_user_from_database_queries_.count(user_id) != 0) { - return; - } - - load_user_from_database_impl(user_id, Auto()); -} - -void ContactsManager::save_user_to_database_impl(User *u, UserId user_id, string value) { - CHECK(u != nullptr); - CHECK(load_user_from_database_queries_.count(user_id) == 0); - CHECK(!u->is_being_saved); - u->is_being_saved = true; - u->is_saved = true; - u->is_status_saved = true; - LOG(INFO) << "Trying to save to database " << user_id; - G()->td_db()->get_sqlite_pmc()->set( - get_user_database_key(user_id), std::move(value), PromiseCreator::lambda([user_id](Result<> result) { - send_closure(G()->contacts_manager(), &ContactsManager::on_save_user_to_database, user_id, result.is_ok()); - })); -} - -void ContactsManager::on_save_user_to_database(UserId user_id, bool success) { - if (G()->close_flag()) { - return; - } - - User *u = get_user(user_id); - CHECK(u != nullptr); - LOG_CHECK(u->is_being_saved) << success << ' ' << user_id << ' ' << u->is_saved << ' ' << u->is_status_saved << ' ' - << load_user_from_database_queries_.count(user_id) << ' ' << u->is_received << ' ' - << u->is_deleted << ' ' << u->is_bot << ' ' << u->need_save_to_database << ' ' - << u->is_changed << ' ' << u->is_status_changed << ' ' << u->is_name_changed << ' ' - << u->is_username_changed << ' ' << u->is_photo_changed << ' ' - << u->is_is_contact_changed << ' ' << u->is_is_deleted_changed << ' ' - << u->is_stories_hidden_changed << ' ' << u->log_event_id; - CHECK(load_user_from_database_queries_.count(user_id) == 0); - u->is_being_saved = false; - - if (!success) { - LOG(ERROR) << "Failed to save " << user_id << " to database"; - u->is_saved = false; - u->is_status_saved = false; - } else { - LOG(INFO) << "Successfully saved " << user_id << " to database"; - } - if (u->is_saved && u->is_status_saved) { - if (u->log_event_id != 0) { - binlog_erase(G()->td_db()->get_binlog(), u->log_event_id); - u->log_event_id = 0; - } - } else { - save_user(u, user_id, u->log_event_id != 0); - } -} - -void ContactsManager::load_user_from_database(User *u, UserId user_id, Promise promise) { - if (loaded_from_database_users_.count(user_id)) { - promise.set_value(Unit()); - return; - } - - CHECK(u == nullptr || !u->is_being_saved); - load_user_from_database_impl(user_id, std::move(promise)); -} - -void ContactsManager::load_user_from_database_impl(UserId user_id, Promise promise) { - LOG(INFO) << "Load " << user_id << " from database"; - auto &load_user_queries = load_user_from_database_queries_[user_id]; - load_user_queries.push_back(std::move(promise)); - if (load_user_queries.size() == 1u) { - G()->td_db()->get_sqlite_pmc()->get(get_user_database_key(user_id), PromiseCreator::lambda([user_id](string value) { - send_closure(G()->contacts_manager(), - &ContactsManager::on_load_user_from_database, user_id, - std::move(value), false); - })); - } -} - -void ContactsManager::on_load_user_from_database(UserId user_id, string value, bool force) { - if (G()->close_flag() && !force) { - // the user is in Binlog and will be saved after restart - return; - } - - CHECK(user_id.is_valid()); - if (!loaded_from_database_users_.insert(user_id).second) { - return; - } - - auto it = load_user_from_database_queries_.find(user_id); - vector> promises; - if (it != load_user_from_database_queries_.end()) { - promises = std::move(it->second); - CHECK(!promises.empty()); - load_user_from_database_queries_.erase(it); - } - - LOG(INFO) << "Successfully loaded " << user_id << " of size " << value.size() << " from database"; - // G()->td_db()->get_sqlite_pmc()->erase(get_user_database_key(user_id), Auto()); - // return; - - User *u = get_user(user_id); - if (u == nullptr) { - if (!value.empty()) { - u = add_user(user_id); - - if (log_event_parse(*u, value).is_error()) { - LOG(ERROR) << "Failed to load " << user_id << " from database"; - users_.erase(user_id); - } else { - u->is_saved = true; - u->is_status_saved = true; - update_user(u, user_id, true, true); - } - } - } else { - CHECK(!u->is_saved); // user can't be saved before load completes - CHECK(!u->is_being_saved); - auto new_value = get_user_database_value(u); - if (value != new_value) { - save_user_to_database_impl(u, user_id, std::move(new_value)); - } else if (u->log_event_id != 0) { - binlog_erase(G()->td_db()->get_binlog(), u->log_event_id); - u->log_event_id = 0; - } - } - - set_promises(promises); -} - -bool ContactsManager::have_user_force(UserId user_id, const char *source) { - return get_user_force(user_id, source) != nullptr; -} - -ContactsManager::User *ContactsManager::get_user_force(UserId user_id, const char *source) { - auto u = get_user_force_impl(user_id, source); - if ((u == nullptr || !u->is_received) && - (user_id == get_service_notifications_user_id() || user_id == get_replies_bot_user_id() || - user_id == get_anonymous_bot_user_id() || user_id == get_channel_bot_user_id() || - user_id == get_anti_spam_bot_user_id())) { - int32 flags = USER_FLAG_HAS_ACCESS_HASH | USER_FLAG_HAS_FIRST_NAME | USER_FLAG_NEED_APPLY_MIN_PHOTO; - int64 profile_photo_id = 0; - int32 profile_photo_dc_id = 1; - string first_name; - string last_name; - string username; - string phone_number; - int32 bot_info_version = 0; - - if (user_id == get_service_notifications_user_id()) { - flags |= USER_FLAG_HAS_PHONE_NUMBER | USER_FLAG_IS_VERIFIED | USER_FLAG_IS_SUPPORT; - first_name = "Telegram"; - if (G()->is_test_dc()) { - flags |= USER_FLAG_HAS_LAST_NAME; - last_name = "Notifications"; - } - phone_number = "42777"; - profile_photo_id = 3337190045231023; - } else if (user_id == get_replies_bot_user_id()) { - flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT; - if (!G()->is_test_dc()) { - flags |= USER_FLAG_IS_PRIVATE_BOT; - } - first_name = "Replies"; - username = "replies"; - bot_info_version = G()->is_test_dc() ? 1 : 3; - } else if (user_id == get_anonymous_bot_user_id()) { - flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT; - if (!G()->is_test_dc()) { - flags |= USER_FLAG_IS_PRIVATE_BOT; - } - first_name = "Group"; - username = G()->is_test_dc() ? "izgroupbot" : "GroupAnonymousBot"; - bot_info_version = G()->is_test_dc() ? 1 : 3; - profile_photo_id = 5159307831025969322; - } else if (user_id == get_channel_bot_user_id()) { - flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT; - if (!G()->is_test_dc()) { - flags |= USER_FLAG_IS_PRIVATE_BOT; - } - first_name = G()->is_test_dc() ? "Channels" : "Channel"; - username = G()->is_test_dc() ? "channelsbot" : "Channel_Bot"; - bot_info_version = G()->is_test_dc() ? 1 : 4; - profile_photo_id = 587627495930570665; - } else if (user_id == get_service_notifications_user_id()) { - flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT; - if (G()->is_test_dc()) { - first_name = "antispambot"; - username = "tantispambot"; - } else { - flags |= USER_FLAG_IS_VERIFIED; - first_name = "Telegram Anti-Spam"; - username = "tgsantispambot"; - profile_photo_id = 5170408289966598902; - } - } - - telegram_api::object_ptr profile_photo; - if (!G()->is_test_dc() && profile_photo_id != 0) { - profile_photo = telegram_api::make_object(0, false, false, profile_photo_id, - BufferSlice(), profile_photo_dc_id); - } - - auto user = telegram_api::make_object( - flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, - false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, - false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, - false /*ignored*/, false /*ignored*/, false /*ignored*/, 0, false /*ignored*/, false /*ignored*/, - false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, user_id.get(), 1, first_name, - string(), username, phone_number, std::move(profile_photo), nullptr, bot_info_version, Auto(), string(), - string(), nullptr, vector>(), 0, nullptr, nullptr); - on_get_user(std::move(user), "get_user_force"); - u = get_user(user_id); - CHECK(u != nullptr && u->is_received); - - reload_user(user_id, Promise(), "get_user_force"); - } - return u; -} - -ContactsManager::User *ContactsManager::get_user_force_impl(UserId user_id, const char *source) { - if (!user_id.is_valid()) { - return nullptr; - } - - User *u = get_user(user_id); - if (u != nullptr) { - return u; - } - if (!G()->use_chat_info_database()) { - return nullptr; - } - if (loaded_from_database_users_.count(user_id)) { - return nullptr; - } - - LOG(INFO) << "Trying to load " << user_id << " from database from " << source; - on_load_user_from_database(user_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_user_database_key(user_id)), true); - return get_user(user_id); -} - class ContactsManager::ChatLogEvent { public: ChatId chat_id; @@ -9118,356 +4416,6 @@ ContactsManager::Channel *ContactsManager::get_channel_force(ChannelId channel_i return get_channel(channel_id); } -class ContactsManager::SecretChatLogEvent { - public: - SecretChatId secret_chat_id; - const SecretChat *c_in = nullptr; - unique_ptr c_out; - - SecretChatLogEvent() = default; - - SecretChatLogEvent(SecretChatId secret_chat_id, const SecretChat *c) : secret_chat_id(secret_chat_id), c_in(c) { - } - - template - void store(StorerT &storer) const { - td::store(secret_chat_id, storer); - td::store(*c_in, storer); - } - - template - void parse(ParserT &parser) { - td::parse(secret_chat_id, parser); - td::parse(c_out, parser); - } -}; - -void ContactsManager::save_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog) { - if (!G()->use_chat_info_database()) { - return; - } - CHECK(c != nullptr); - if (!c->is_saved) { - if (!from_binlog) { - auto log_event = SecretChatLogEvent(secret_chat_id, c); - auto storer = get_log_event_storer(log_event); - if (c->log_event_id == 0) { - c->log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::SecretChatInfos, storer); - } else { - binlog_rewrite(G()->td_db()->get_binlog(), c->log_event_id, LogEvent::HandlerType::SecretChatInfos, storer); - } - } - - save_secret_chat_to_database(c, secret_chat_id); - return; - } -} - -void ContactsManager::on_binlog_secret_chat_event(BinlogEvent &&event) { - if (!G()->use_chat_info_database()) { - binlog_erase(G()->td_db()->get_binlog(), event.id_); - return; - } - - SecretChatLogEvent log_event; - if (log_event_parse(log_event, event.get_data()).is_error()) { - LOG(ERROR) << "Failed to load a secret chat from binlog"; - binlog_erase(G()->td_db()->get_binlog(), event.id_); - return; - } - - auto secret_chat_id = log_event.secret_chat_id; - if (have_secret_chat(secret_chat_id) || !secret_chat_id.is_valid()) { - LOG(ERROR) << "Skip adding already added " << secret_chat_id; - binlog_erase(G()->td_db()->get_binlog(), event.id_); - return; - } - - LOG(INFO) << "Add " << secret_chat_id << " from binlog"; - secret_chats_.set(secret_chat_id, std::move(log_event.c_out)); - - SecretChat *c = get_secret_chat(secret_chat_id); - CHECK(c != nullptr); - c->log_event_id = event.id_; - - update_secret_chat(c, secret_chat_id, true, false); -} - -string ContactsManager::get_secret_chat_database_key(SecretChatId secret_chat_id) { - return PSTRING() << "sc" << secret_chat_id.get(); -} - -string ContactsManager::get_secret_chat_database_value(const SecretChat *c) { - return log_event_store(*c).as_slice().str(); -} - -void ContactsManager::save_secret_chat_to_database(SecretChat *c, SecretChatId secret_chat_id) { - CHECK(c != nullptr); - if (c->is_being_saved) { - return; - } - if (loaded_from_database_secret_chats_.count(secret_chat_id)) { - save_secret_chat_to_database_impl(c, secret_chat_id, get_secret_chat_database_value(c)); - return; - } - if (load_secret_chat_from_database_queries_.count(secret_chat_id) != 0) { - return; - } - - load_secret_chat_from_database_impl(secret_chat_id, Auto()); -} - -void ContactsManager::save_secret_chat_to_database_impl(SecretChat *c, SecretChatId secret_chat_id, string value) { - CHECK(c != nullptr); - CHECK(load_secret_chat_from_database_queries_.count(secret_chat_id) == 0); - CHECK(!c->is_being_saved); - c->is_being_saved = true; - c->is_saved = true; - LOG(INFO) << "Trying to save to database " << secret_chat_id; - G()->td_db()->get_sqlite_pmc()->set(get_secret_chat_database_key(secret_chat_id), std::move(value), - PromiseCreator::lambda([secret_chat_id](Result<> result) { - send_closure(G()->contacts_manager(), - &ContactsManager::on_save_secret_chat_to_database, secret_chat_id, - result.is_ok()); - })); -} - -void ContactsManager::on_save_secret_chat_to_database(SecretChatId secret_chat_id, bool success) { - if (G()->close_flag()) { - return; - } - - SecretChat *c = get_secret_chat(secret_chat_id); - CHECK(c != nullptr); - CHECK(c->is_being_saved); - CHECK(load_secret_chat_from_database_queries_.count(secret_chat_id) == 0); - c->is_being_saved = false; - - if (!success) { - LOG(ERROR) << "Failed to save " << secret_chat_id << " to database"; - c->is_saved = false; - } else { - LOG(INFO) << "Successfully saved " << secret_chat_id << " to database"; - } - if (c->is_saved) { - if (c->log_event_id != 0) { - binlog_erase(G()->td_db()->get_binlog(), c->log_event_id); - c->log_event_id = 0; - } - } else { - save_secret_chat(c, secret_chat_id, c->log_event_id != 0); - } -} - -void ContactsManager::load_secret_chat_from_database(SecretChat *c, SecretChatId secret_chat_id, - Promise promise) { - if (loaded_from_database_secret_chats_.count(secret_chat_id)) { - promise.set_value(Unit()); - return; - } - - CHECK(c == nullptr || !c->is_being_saved); - load_secret_chat_from_database_impl(secret_chat_id, std::move(promise)); -} - -void ContactsManager::load_secret_chat_from_database_impl(SecretChatId secret_chat_id, Promise promise) { - LOG(INFO) << "Load " << secret_chat_id << " from database"; - auto &load_secret_chat_queries = load_secret_chat_from_database_queries_[secret_chat_id]; - load_secret_chat_queries.push_back(std::move(promise)); - if (load_secret_chat_queries.size() == 1u) { - G()->td_db()->get_sqlite_pmc()->get( - get_secret_chat_database_key(secret_chat_id), PromiseCreator::lambda([secret_chat_id](string value) { - send_closure(G()->contacts_manager(), &ContactsManager::on_load_secret_chat_from_database, secret_chat_id, - std::move(value), false); - })); - } -} - -void ContactsManager::on_load_secret_chat_from_database(SecretChatId secret_chat_id, string value, bool force) { - if (G()->close_flag() && !force) { - // the secret chat is in Binlog and will be saved after restart - return; - } - - CHECK(secret_chat_id.is_valid()); - if (!loaded_from_database_secret_chats_.insert(secret_chat_id).second) { - return; - } - - auto it = load_secret_chat_from_database_queries_.find(secret_chat_id); - vector> promises; - if (it != load_secret_chat_from_database_queries_.end()) { - promises = std::move(it->second); - CHECK(!promises.empty()); - load_secret_chat_from_database_queries_.erase(it); - } - - LOG(INFO) << "Successfully loaded " << secret_chat_id << " of size " << value.size() << " from database"; - // G()->td_db()->get_sqlite_pmc()->erase(get_secret_chat_database_key(secret_chat_id), Auto()); - // return; - - SecretChat *c = get_secret_chat(secret_chat_id); - if (c == nullptr) { - if (!value.empty()) { - c = add_secret_chat(secret_chat_id); - - if (log_event_parse(*c, value).is_error()) { - LOG(ERROR) << "Failed to load " << secret_chat_id << " from database"; - secret_chats_.erase(secret_chat_id); - } else { - c->is_saved = true; - update_secret_chat(c, secret_chat_id, true, true); - } - } - } else { - CHECK(!c->is_saved); // secret chat can't be saved before load completes - CHECK(!c->is_being_saved); - auto new_value = get_secret_chat_database_value(c); - if (value != new_value) { - save_secret_chat_to_database_impl(c, secret_chat_id, std::move(new_value)); - } else if (c->log_event_id != 0) { - binlog_erase(G()->td_db()->get_binlog(), c->log_event_id); - c->log_event_id = 0; - } - } - - // TODO load users asynchronously - if (c != nullptr && !have_user_force(c->user_id, "on_load_secret_chat_from_database")) { - LOG(ERROR) << "Can't find " << c->user_id << " from " << secret_chat_id; - } - - set_promises(promises); -} - -bool ContactsManager::have_secret_chat_force(SecretChatId secret_chat_id, const char *source) { - return get_secret_chat_force(secret_chat_id, source) != nullptr; -} - -ContactsManager::SecretChat *ContactsManager::get_secret_chat_force(SecretChatId secret_chat_id, const char *source) { - if (!secret_chat_id.is_valid()) { - return nullptr; - } - - SecretChat *c = get_secret_chat(secret_chat_id); - if (c != nullptr) { - if (!have_user_force(c->user_id, source)) { - LOG(ERROR) << "Can't find " << c->user_id << " from " << secret_chat_id << " from " << source; - } - return c; - } - if (!G()->use_chat_info_database()) { - return nullptr; - } - if (loaded_from_database_secret_chats_.count(secret_chat_id)) { - return nullptr; - } - - LOG(INFO) << "Trying to load " << secret_chat_id << " from database from " << source; - on_load_secret_chat_from_database( - secret_chat_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_secret_chat_database_key(secret_chat_id)), true); - return get_secret_chat(secret_chat_id); -} - -void ContactsManager::save_user_full(const UserFull *user_full, UserId user_id) { - if (!G()->use_chat_info_database()) { - return; - } - - LOG(INFO) << "Trying to save to database full " << user_id; - CHECK(user_full != nullptr); - G()->td_db()->get_sqlite_pmc()->set(get_user_full_database_key(user_id), get_user_full_database_value(user_full), - Auto()); -} - -string ContactsManager::get_user_full_database_key(UserId user_id) { - return PSTRING() << "usf" << user_id.get(); -} - -string ContactsManager::get_user_full_database_value(const UserFull *user_full) { - return log_event_store(*user_full).as_slice().str(); -} - -void ContactsManager::on_load_user_full_from_database(UserId user_id, string value) { - LOG(INFO) << "Successfully loaded full " << user_id << " of size " << value.size() << " from database"; - // G()->td_db()->get_sqlite_pmc()->erase(get_user_full_database_key(user_id), Auto()); - // return; - - if (get_user_full(user_id) != nullptr || value.empty()) { - return; - } - - UserFull *user_full = add_user_full(user_id); - auto status = log_event_parse(*user_full, value); - if (status.is_error()) { - // can't happen unless database is broken - LOG(ERROR) << "Repair broken full " << user_id << ' ' << format::as_hex_dump<4>(Slice(value)); - - // just clean all known data about the user and pretend that there was nothing in the database - users_full_.erase(user_id); - G()->td_db()->get_sqlite_pmc()->erase(get_user_full_database_key(user_id), Auto()); - return; - } - - Dependencies dependencies; - dependencies.add(user_id); - if (user_full->business_info != nullptr) { - user_full->business_info->add_dependencies(dependencies); - } - dependencies.add(user_full->personal_channel_id); - if (!dependencies.resolve_force(td_, "on_load_user_full_from_database")) { - users_full_.erase(user_id); - G()->td_db()->get_sqlite_pmc()->erase(get_user_full_database_key(user_id), Auto()); - return; - } - - if (user_full->need_phone_number_privacy_exception && is_user_contact(user_id)) { - user_full->need_phone_number_privacy_exception = false; - } - - User *u = get_user(user_id); - CHECK(u != nullptr); - drop_user_full_photos(user_full, user_id, u->photo.id, "on_load_user_full_from_database"); - if (!user_full->photo.is_empty()) { - register_user_photo(u, user_id, user_full->photo); - } - if (user_id == get_my_id() && !user_full->fallback_photo.is_empty()) { - register_suggested_profile_photo(user_full->fallback_photo); - } - - td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, false); - - user_full->is_update_user_full_sent = true; - update_user_full(user_full, user_id, "on_load_user_full_from_database", true); - - if (is_user_deleted(u)) { - drop_user_full(user_id); - } else if (user_full->expires_at == 0.0) { - reload_user_full(user_id, Auto(), "on_load_user_full_from_database"); - } -} - -ContactsManager::UserFull *ContactsManager::get_user_full_force(UserId user_id, const char *source) { - if (!have_user_force(user_id, source)) { - return nullptr; - } - - UserFull *user_full = get_user_full(user_id); - if (user_full != nullptr) { - return user_full; - } - if (!G()->use_chat_info_database()) { - return nullptr; - } - if (!unavailable_user_fulls_.insert(user_id).second) { - return nullptr; - } - - LOG(INFO) << "Trying to load full " << user_id << " from database from " << source; - on_load_user_full_from_database(user_id, - G()->td_db()->get_sqlite_sync_pmc()->get(get_user_full_database_key(user_id))); - return get_user_full(user_id); -} - void ContactsManager::save_chat_full(const ChatFull *chat_full, ChatId chat_id) { if (!G()->use_chat_info_database()) { return; @@ -9720,218 +4668,6 @@ ContactsManager::ChannelFull *ContactsManager::get_channel_full_force(ChannelId return get_channel_full(channel_id, only_local, source); } -void ContactsManager::for_each_secret_chat_with_user(UserId user_id, const std::function &f) { - auto it = secret_chats_with_user_.find(user_id); - if (it != secret_chats_with_user_.end()) { - for (auto secret_chat_id : it->second) { - f(secret_chat_id); - } - } -} - -void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, bool from_database) { - CHECK(u != nullptr); - - if (u->is_being_updated) { - LOG(ERROR) << "Detected recursive update of " << user_id; - } - u->is_being_updated = true; - SCOPE_EXIT { - u->is_being_updated = false; - }; - - if (user_id == get_my_id()) { - if (td_->option_manager_->get_option_boolean("is_premium") != u->is_premium) { - td_->option_manager_->set_option_boolean("is_premium", u->is_premium); - send_closure(td_->config_manager_, &ConfigManager::request_config, true); - if (!td_->auth_manager_->is_bot()) { - td_->reaction_manager_->reload_reaction_list(ReactionListType::Top, "update_user is_premium"); - td_->messages_manager_->update_is_translatable(u->is_premium); - } - } - } - if (u->is_name_changed || u->is_username_changed || u->is_is_contact_changed) { - update_contacts_hints(u, user_id, from_database); - u->is_username_changed = false; - } - if (u->is_is_contact_changed) { - td_->messages_manager_->on_dialog_user_is_contact_updated(DialogId(user_id), u->is_contact); - send_closure_later(td_->story_manager_actor_, &StoryManager::on_dialog_active_stories_order_updated, - DialogId(user_id), "is_contact"); - if (is_user_contact(u, user_id, false)) { - auto user_full = get_user_full(user_id); - if (user_full != nullptr && user_full->need_phone_number_privacy_exception) { - on_update_user_full_need_phone_number_privacy_exception(user_full, user_id, false); - update_user_full(user_full, user_id, "update_user"); - } - } - u->is_is_contact_changed = false; - } - if (u->is_is_mutual_contact_changed) { - if (!from_database && u->is_update_user_sent) { - send_closure_later(td_->story_manager_actor_, &StoryManager::reload_dialog_expiring_stories, DialogId(user_id)); - } - u->is_is_mutual_contact_changed = false; - } - if (u->is_is_deleted_changed) { - td_->messages_manager_->on_dialog_user_is_deleted_updated(DialogId(user_id), u->is_deleted); - if (u->is_deleted) { - auto user_full = get_user_full(user_id); // must not load user_full from database before sending updateUser - if (user_full != nullptr) { - u->is_full_info_changed = false; - drop_user_full(user_id); - } - } - u->is_is_deleted_changed = false; - } - if (u->is_is_premium_changed) { - send_closure_later(td_->story_manager_actor_, &StoryManager::on_dialog_active_stories_order_updated, - DialogId(user_id), "is_premium"); - u->is_is_premium_changed = false; - } - if (u->is_name_changed) { - auto messages_manager = td_->messages_manager_.get(); - messages_manager->on_dialog_title_updated(DialogId(user_id)); - for_each_secret_chat_with_user(user_id, [messages_manager](SecretChatId secret_chat_id) { - messages_manager->on_dialog_title_updated(DialogId(secret_chat_id)); - }); - u->is_name_changed = false; - } - if (u->is_photo_changed) { - auto messages_manager = td_->messages_manager_.get(); - messages_manager->on_dialog_photo_updated(DialogId(user_id)); - for_each_secret_chat_with_user(user_id, [messages_manager](SecretChatId secret_chat_id) { - messages_manager->on_dialog_photo_updated(DialogId(secret_chat_id)); - }); - u->is_photo_changed = false; - } - if (u->is_accent_color_changed) { - auto messages_manager = td_->messages_manager_.get(); - messages_manager->on_dialog_accent_colors_updated(DialogId(user_id)); - for_each_secret_chat_with_user(user_id, [messages_manager](SecretChatId secret_chat_id) { - messages_manager->on_dialog_accent_colors_updated(DialogId(secret_chat_id)); - }); - u->is_accent_color_changed = false; - } - if (u->is_phone_number_changed) { - if (!u->phone_number.empty() && !td_->auth_manager_->is_bot()) { - resolved_phone_numbers_[u->phone_number] = user_id; - } - u->is_phone_number_changed = false; - } - auto unix_time = G()->unix_time(); - if (u->is_status_changed && user_id != get_my_id()) { - auto left_time = get_user_was_online(u, user_id, unix_time) - G()->server_time(); - if (left_time >= 0 && left_time < 30 * 86400) { - left_time += 2.0; // to guarantee expiration - LOG(DEBUG) << "Set online timeout for " << user_id << " in " << left_time << " seconds"; - user_online_timeout_.set_timeout_in(user_id.get(), left_time); - } else { - LOG(DEBUG) << "Cancel online timeout for " << user_id; - user_online_timeout_.cancel_timeout(user_id.get()); - } - } - if (u->is_stories_hidden_changed) { - send_closure_later(td_->story_manager_actor_, &StoryManager::on_dialog_active_stories_order_updated, - DialogId(user_id), "stories_hidden"); - u->is_stories_hidden_changed = false; - } - if (!td_->auth_manager_->is_bot()) { - if (u->restriction_reasons.empty()) { - restricted_user_ids_.erase(user_id); - } else { - restricted_user_ids_.insert(user_id); - } - } - - auto effective_emoji_status = u->emoji_status.get_effective_emoji_status(u->is_premium, unix_time); - if (effective_emoji_status != u->last_sent_emoji_status) { - if (!u->last_sent_emoji_status.is_empty()) { - user_emoji_status_timeout_.cancel_timeout(user_id.get()); - } - u->last_sent_emoji_status = effective_emoji_status; - if (!u->last_sent_emoji_status.is_empty()) { - auto until_date = u->last_sent_emoji_status.get_until_date(); - auto left_time = until_date - unix_time; - if (left_time >= 0 && left_time < 30 * 86400) { - user_emoji_status_timeout_.set_timeout_in(user_id.get(), left_time); - } - } - u->is_changed = true; - - auto messages_manager = td_->messages_manager_.get(); - messages_manager->on_dialog_emoji_status_updated(DialogId(user_id)); - for_each_secret_chat_with_user(user_id, [messages_manager](SecretChatId secret_chat_id) { - messages_manager->on_dialog_emoji_status_updated(DialogId(secret_chat_id)); - }); - u->is_emoji_status_changed = false; - } else if (u->is_emoji_status_changed) { - LOG(DEBUG) << "Emoji status for " << user_id << " has changed"; - u->need_save_to_database = true; - u->is_emoji_status_changed = false; - } - - if (u->is_deleted) { - td_->inline_queries_manager_->remove_recent_inline_bot(user_id, Promise<>()); - } - if (from_binlog || from_database) { - td_->dialog_manager_->on_dialog_usernames_received(DialogId(user_id), u->usernames, true); - } - - LOG(DEBUG) << "Update " << user_id << ": need_save_to_database = " << u->need_save_to_database - << ", is_changed = " << u->is_changed << ", is_status_changed = " << u->is_status_changed - << ", from_binlog = " << from_binlog << ", from_database = " << from_database; - u->need_save_to_database |= u->is_changed; - if (u->need_save_to_database) { - if (!from_database) { - u->is_saved = false; - } - u->need_save_to_database = false; - } - if (u->is_changed) { - send_closure(G()->td(), &Td::send_update, get_update_user_object(user_id, u)); - u->is_changed = false; - u->is_status_changed = false; - u->is_update_user_sent = true; - } - if (u->is_status_changed) { - if (!from_database) { - u->is_status_saved = false; - } - CHECK(u->is_update_user_sent); - send_closure( - G()->td(), &Td::send_update, - make_tl_object(user_id.get(), get_user_status_object(user_id, u, unix_time))); - u->is_status_changed = false; - } - if (u->is_online_status_changed) { - td_->dialog_participant_manager_->update_user_online_member_count(user_id); - u->is_online_status_changed = false; - } - - if (!from_database) { - save_user(u, user_id, from_binlog); - } - - if (u->cache_version != User::CACHE_VERSION && !u->is_repaired && - have_input_peer_user(u, user_id, AccessRights::Read) && !G()->close_flag()) { - u->is_repaired = true; - - LOG(INFO) << "Repairing cache of " << user_id; - reload_user(user_id, Promise(), "update_user"); - } - - if (u->is_full_info_changed) { - u->is_full_info_changed = false; - auto user_full = get_user_full(user_id); - if (user_full != nullptr) { - user_full->need_send_update = true; - update_user_full(user_full, user_id, "update_user is_full_info_changed"); - reload_user_full(user_id, Promise(), "update_user"); - } - } -} - void ContactsManager::update_chat(Chat *c, ChatId chat_id, bool from_binlog, bool from_database) { CHECK(c != nullptr); @@ -10225,134 +4961,6 @@ void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from } } -void ContactsManager::update_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog, - bool from_database) { - CHECK(c != nullptr); - - if (c->is_being_updated) { - LOG(ERROR) << "Detected recursive update of " << secret_chat_id; - } - c->is_being_updated = true; - SCOPE_EXIT { - c->is_being_updated = false; - }; - - LOG(DEBUG) << "Update " << secret_chat_id << ": need_save_to_database = " << c->need_save_to_database - << ", is_changed = " << c->is_changed; - c->need_save_to_database |= c->is_changed; - if (c->need_save_to_database) { - if (!from_database) { - c->is_saved = false; - } - c->need_save_to_database = false; - - DialogId dialog_id(secret_chat_id); - send_closure_later(G()->messages_manager(), &MessagesManager::force_create_dialog, dialog_id, "update secret chat", - true, true); - if (c->is_state_changed) { - send_closure_later(G()->messages_manager(), &MessagesManager::on_update_secret_chat_state, secret_chat_id, - c->state); - c->is_state_changed = false; - } - if (c->is_ttl_changed) { - send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_message_ttl, - DialogId(secret_chat_id), MessageTtl(c->ttl)); - c->is_ttl_changed = false; - } - } - if (c->is_changed) { - send_closure(G()->td(), &Td::send_update, get_update_secret_chat_object(secret_chat_id, c)); - c->is_changed = false; - } - - if (!from_database) { - save_secret_chat(c, secret_chat_id, from_binlog); - } -} - -void ContactsManager::update_user_full(UserFull *user_full, UserId user_id, const char *source, bool from_database) { - CHECK(user_full != nullptr); - - if (user_full->is_being_updated) { - LOG(ERROR) << "Detected recursive update of full " << user_id << " from " << source; - } - user_full->is_being_updated = true; - SCOPE_EXIT { - user_full->is_being_updated = false; - }; - - unavailable_user_fulls_.erase(user_id); // don't needed anymore - if (user_full->is_common_chat_count_changed) { - td_->common_dialog_manager_->drop_common_dialogs_cache(user_id); - user_full->is_common_chat_count_changed = false; - } - if (true) { - vector file_ids; - if (!user_full->personal_photo.is_empty()) { - append(file_ids, photo_get_file_ids(user_full->personal_photo)); - } - if (!user_full->fallback_photo.is_empty()) { - append(file_ids, photo_get_file_ids(user_full->fallback_photo)); - } - if (!user_full->description_photo.is_empty()) { - append(file_ids, photo_get_file_ids(user_full->description_photo)); - } - if (user_full->description_animation_file_id.is_valid()) { - file_ids.push_back(user_full->description_animation_file_id); - } - if (user_full->business_info != nullptr) { - append(file_ids, user_full->business_info->get_file_ids(td_)); - } - if (user_full->registered_file_ids != file_ids) { - auto &file_source_id = user_full->file_source_id; - if (!file_source_id.is_valid()) { - file_source_id = user_full_file_source_ids_.get(user_id); - if (file_source_id.is_valid()) { - VLOG(file_references) << "Move " << file_source_id << " inside of " << user_id; - user_full_file_source_ids_.erase(user_id); - } else { - VLOG(file_references) << "Need to create new file source for full " << user_id; - file_source_id = td_->file_reference_manager_->create_user_full_file_source(user_id); - } - } - - td_->file_manager_->change_files_source(file_source_id, user_full->registered_file_ids, file_ids); - user_full->registered_file_ids = std::move(file_ids); - } - } - - user_full->need_send_update |= user_full->is_changed; - user_full->need_save_to_database |= user_full->is_changed; - user_full->is_changed = false; - if (user_full->need_send_update || user_full->need_save_to_database) { - LOG(INFO) << "Update full " << user_id << " from " << source; - } - if (user_full->need_send_update) { - { - auto u = get_user(user_id); - CHECK(u == nullptr || u->is_update_user_sent); - } - if (!user_full->is_update_user_full_sent) { - LOG(ERROR) << "Send partial updateUserFullInfo for " << user_id << " from " << source; - user_full->is_update_user_full_sent = true; - } - send_closure(G()->td(), &Td::send_update, - make_tl_object(get_user_id_object(user_id, "updateUserFullInfo"), - get_user_full_info_object(user_id, user_full))); - user_full->need_send_update = false; - - if (user_id == get_my_id() && !user_full->birthdate.is_empty() && !td_->auth_manager_->is_bot()) { - dismiss_suggested_action(SuggestedAction{SuggestedAction::Type::BirthdaySetup}, Promise()); - } - } - if (user_full->need_save_to_database) { - if (!from_database) { - save_user_full(user_full, user_id); - } - user_full->need_save_to_database = false; - } -} - void ContactsManager::update_chat_full(ChatFull *chat_full, ChatId chat_id, const char *source, bool from_database) { CHECK(chat_full != nullptr); @@ -10382,7 +4990,7 @@ void ContactsManager::update_chat_full(ChatFull *chat_full, ChatId chat_id, cons } if (participant.dialog_id_.get_type() == DialogType::User) { auto user_id = participant.dialog_id_.get_user_id(); - if (is_user_bot(user_id)) { + if (td_->user_manager_->is_user_bot(user_id)) { bot_user_ids.push_back(user_id); } } @@ -10490,313 +5098,6 @@ void ContactsManager::update_channel_full(ChannelFull *channel_full, ChannelId c } } -void ContactsManager::on_get_users(vector> &&users, const char *source) { - for (auto &user : users) { - on_get_user(std::move(user), source); - } -} - -void ContactsManager::on_get_user_full(tl_object_ptr &&user) { - LOG(INFO) << "Receive " << to_string(user); - - UserId user_id(user->id_); - User *u = get_user(user_id); - if (u == nullptr) { - LOG(ERROR) << "Failed to find " << user_id; - return; - } - - apply_pending_user_photo(u, user_id); - - td_->messages_manager_->on_update_dialog_notify_settings(DialogId(user_id), std::move(user->notify_settings_), - "on_get_user_full"); - - td_->messages_manager_->on_update_dialog_background(DialogId(user_id), std::move(user->wallpaper_)); - - td_->messages_manager_->on_update_dialog_theme_name(DialogId(user_id), std::move(user->theme_emoticon_)); - - td_->messages_manager_->on_update_dialog_last_pinned_message_id(DialogId(user_id), - MessageId(ServerMessageId(user->pinned_msg_id_))); - - td_->messages_manager_->on_update_dialog_folder_id(DialogId(user_id), FolderId(user->folder_id_)); - - td_->messages_manager_->on_update_dialog_has_scheduled_server_messages(DialogId(user_id), user->has_scheduled_); - - td_->messages_manager_->on_update_dialog_message_ttl(DialogId(user_id), MessageTtl(user->ttl_period_)); - - td_->messages_manager_->on_update_dialog_is_blocked(DialogId(user_id), user->blocked_, - user->blocked_my_stories_from_); - - td_->messages_manager_->on_update_dialog_is_translatable(DialogId(user_id), !user->translations_disabled_); - - send_closure_later(td_->story_manager_actor_, &StoryManager::on_get_dialog_stories, DialogId(user_id), - std::move(user->stories_), Promise()); - - UserFull *user_full = add_user_full(user_id); - user_full->expires_at = Time::now() + USER_FULL_EXPIRE_TIME; - - on_update_user_full_is_blocked(user_full, user_id, user->blocked_, user->blocked_my_stories_from_); - on_update_user_full_common_chat_count(user_full, user_id, user->common_chats_count_); - on_update_user_full_location(user_full, user_id, DialogLocation(td_, std::move(user->business_location_))); - on_update_user_full_work_hours(user_full, user_id, BusinessWorkHours(std::move(user->business_work_hours_))); - on_update_user_full_away_message(user_full, user_id, BusinessAwayMessage(std::move(user->business_away_message_))); - on_update_user_full_greeting_message(user_full, user_id, - BusinessGreetingMessage(std::move(user->business_greeting_message_))); - on_update_user_full_intro(user_full, user_id, BusinessIntro(td_, std::move(user->business_intro_))); - on_update_user_full_need_phone_number_privacy_exception(user_full, user_id, - user->settings_->need_contacts_exception_); - on_update_user_full_wallpaper_overridden(user_full, user_id, user->wallpaper_overridden_); - - bool can_pin_messages = user->can_pin_message_; - bool can_be_called = user->phone_calls_available_ && !user->phone_calls_private_; - bool supports_video_calls = user->video_calls_available_ && !user->phone_calls_private_; - bool has_private_calls = user->phone_calls_private_; - bool voice_messages_forbidden = u->is_premium ? user->voice_messages_forbidden_ : false; - auto premium_gift_options = get_premium_gift_options(std::move(user->premium_gifts_)); - AdministratorRights group_administrator_rights(user->bot_group_admin_rights_, ChannelType::Megagroup); - AdministratorRights broadcast_administrator_rights(user->bot_broadcast_admin_rights_, ChannelType::Broadcast); - bool has_pinned_stories = user->stories_pinned_available_; - auto birthdate = Birthdate(std::move(user->birthday_)); - auto personal_channel_id = ChannelId(user->personal_channel_id_); - if (user_full->can_be_called != can_be_called || user_full->supports_video_calls != supports_video_calls || - user_full->has_private_calls != has_private_calls || - user_full->group_administrator_rights != group_administrator_rights || - user_full->broadcast_administrator_rights != broadcast_administrator_rights || - user_full->premium_gift_options != premium_gift_options || - user_full->voice_messages_forbidden != voice_messages_forbidden || - user_full->can_pin_messages != can_pin_messages || user_full->has_pinned_stories != has_pinned_stories) { - user_full->can_be_called = can_be_called; - user_full->supports_video_calls = supports_video_calls; - user_full->has_private_calls = has_private_calls; - user_full->group_administrator_rights = group_administrator_rights; - user_full->broadcast_administrator_rights = broadcast_administrator_rights; - user_full->premium_gift_options = std::move(premium_gift_options); - user_full->voice_messages_forbidden = voice_messages_forbidden; - user_full->can_pin_messages = can_pin_messages; - user_full->has_pinned_stories = has_pinned_stories; - - user_full->is_changed = true; - } - if (user_full->birthdate != birthdate) { - user_full->birthdate = birthdate; - user_full->is_changed = true; - - if (u->is_contact) { - reload_contact_birthdates(true); - } - } - - if (user_full->private_forward_name != user->private_forward_name_) { - if (user_full->private_forward_name.empty() != user->private_forward_name_.empty()) { - user_full->is_changed = true; - } - user_full->private_forward_name = std::move(user->private_forward_name_); - user_full->need_save_to_database = true; - } - if (user_full->read_dates_private != user->read_dates_private_ || - user_full->contact_require_premium != user->contact_require_premium_) { - user_full->read_dates_private = user->read_dates_private_; - user_full->contact_require_premium = user->contact_require_premium_; - user_full->need_save_to_database = true; - } - if (user_full->about != user->about_) { - user_full->about = std::move(user->about_); - user_full->is_changed = true; - td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, true); - } - string description; - Photo description_photo; - FileId description_animation_file_id; - if (user->bot_info_ != nullptr && !td_->auth_manager_->is_bot()) { - description = std::move(user->bot_info_->description_); - description_photo = get_photo(td_, std::move(user->bot_info_->description_photo_), DialogId(user_id)); - auto document = std::move(user->bot_info_->description_document_); - if (document != nullptr) { - int32 document_id = document->get_id(); - if (document_id == telegram_api::document::ID) { - auto parsed_document = td_->documents_manager_->on_get_document( - move_tl_object_as(document), DialogId(user_id)); - if (parsed_document.type == Document::Type::Animation) { - description_animation_file_id = parsed_document.file_id; - } else { - LOG(ERROR) << "Receive non-animation document in bot description"; - } - } - } - - on_update_user_full_commands(user_full, user_id, std::move(user->bot_info_->commands_)); - on_update_user_full_menu_button(user_full, user_id, std::move(user->bot_info_->menu_button_)); - } - if (user_full->description != description) { - user_full->description = std::move(description); - user_full->is_changed = true; - } - if (user_full->description_photo != description_photo || - user_full->description_animation_file_id != description_animation_file_id) { - user_full->description_photo = std::move(description_photo); - user_full->description_animation_file_id = description_animation_file_id; - user_full->is_changed = true; - } - if (personal_channel_id != ChannelId() && !personal_channel_id.is_valid()) { - LOG(ERROR) << "Receive personal " << personal_channel_id; - personal_channel_id = ChannelId(); - } - if (user_full->personal_channel_id != personal_channel_id) { - user_full->personal_channel_id = personal_channel_id; - user_full->is_changed = true; - } - if (user_full->personal_channel_id != ChannelId()) { - auto personal_message_id = MessageId(ServerMessageId(user->personal_channel_message_)); - td_->messages_manager_->get_channel_difference_if_needed(DialogId(user_full->personal_channel_id), - personal_message_id, "on_get_user_full personal chat"); - } - - auto photo = get_photo(td_, std::move(user->profile_photo_), DialogId(user_id)); - auto personal_photo = get_photo(td_, std::move(user->personal_photo_), DialogId(user_id)); - auto fallback_photo = get_photo(td_, std::move(user->fallback_photo_), DialogId(user_id)); - // do_update_user_photo should be a no-op if server sent consistent data - const Photo *photo_ptr = nullptr; - bool is_personal = false; - if (!personal_photo.is_empty()) { - photo_ptr = &personal_photo; - is_personal = true; - } else if (!photo.is_empty()) { - photo_ptr = &photo; - } else { - photo_ptr = &fallback_photo; - } - bool is_photo_empty = photo_ptr->is_empty(); - do_update_user_photo(u, user_id, - as_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, *photo_ptr, is_personal), - false, "on_get_user_full"); - if (photo != user_full->photo) { - user_full->photo = std::move(photo); - user_full->is_changed = true; - } - if (personal_photo != user_full->personal_photo) { - user_full->personal_photo = std::move(personal_photo); - user_full->is_changed = true; - } - if (fallback_photo != user_full->fallback_photo) { - user_full->fallback_photo = std::move(fallback_photo); - user_full->is_changed = true; - } - if (!user_full->photo.is_empty()) { - register_user_photo(u, user_id, user_full->photo); - } - if (user_id == get_my_id() && !user_full->fallback_photo.is_empty()) { - register_suggested_profile_photo(user_full->fallback_photo); - } - if (is_photo_empty) { - drop_user_photos(user_id, true, "on_get_user_full"); - } - - // User must be updated before UserFull - if (u->is_changed) { - LOG(ERROR) << "Receive inconsistent chatPhoto and chatPhotoInfo for " << user_id; - update_user(u, user_id); - } - - user_full->is_update_user_full_sent = true; - update_user_full(user_full, user_id, "on_get_user_full"); - - // update peer settings after UserFull is created and updated to not update twice need_phone_number_privacy_exception - td_->messages_manager_->on_get_peer_settings(DialogId(user_id), std::move(user->settings_)); -} - -ContactsManager::UserPhotos *ContactsManager::add_user_photos(UserId user_id) { - CHECK(user_id.is_valid()); - auto &user_photos_ptr = user_photos_[user_id]; - if (user_photos_ptr == nullptr) { - user_photos_ptr = make_unique(); - } - return user_photos_ptr.get(); -} - -void ContactsManager::on_get_user_photos(UserId user_id, int32 offset, int32 limit, int32 total_count, - vector> photos) { - auto photo_count = narrow_cast(photos.size()); - int32 min_total_count = (offset >= 0 && photo_count > 0 ? offset : 0) + photo_count; - if (total_count < min_total_count) { - LOG(ERROR) << "Receive wrong photos total_count " << total_count << " for user " << user_id << ": receive " - << photo_count << " photos with offset " << offset; - total_count = min_total_count; - } - LOG_IF(ERROR, limit < photo_count) << "Requested not more than " << limit << " photos, but " << photo_count - << " received"; - - User *u = get_user(user_id); - if (u == nullptr) { - LOG(ERROR) << "Can't find " << user_id; - return; - } - - if (offset == -1) { - // from reload_user_profile_photo - CHECK(limit == 1); - for (auto &photo_ptr : photos) { - if (photo_ptr->get_id() == telegram_api::photo::ID) { - auto server_photo = telegram_api::move_object_as(photo_ptr); - if (server_photo->id_ == u->photo.id) { - auto profile_photo = convert_photo_to_profile_photo(server_photo, u->photo.is_personal); - if (profile_photo) { - LOG_IF(ERROR, u->access_hash == -1) << "Receive profile photo of " << user_id << " without access hash"; - get_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, std::move(profile_photo)); - } else { - LOG(ERROR) << "Failed to get profile photo from " << to_string(server_photo); - } - } - - auto photo = get_photo(td_, std::move(server_photo), DialogId(user_id)); - register_user_photo(u, user_id, photo); - } - } - return; - } - - LOG(INFO) << "Receive " << photo_count << " photos of " << user_id << " out of " << total_count << " with offset " - << offset << " and limit " << limit; - UserPhotos *user_photos = add_user_photos(user_id); - user_photos->count = total_count; - CHECK(!user_photos->pending_requests.empty()); - - if (user_photos->offset == -1) { - user_photos->offset = 0; - CHECK(user_photos->photos.empty()); - } - - if (offset != narrow_cast(user_photos->photos.size()) + user_photos->offset) { - LOG(INFO) << "Inappropriate offset to append " << user_id << " profile photos to cache: offset = " << offset - << ", current_offset = " << user_photos->offset << ", photo_count = " << user_photos->photos.size(); - user_photos->photos.clear(); - user_photos->offset = offset; - } - - for (auto &photo : photos) { - auto user_photo = get_photo(td_, std::move(photo), DialogId(user_id)); - if (user_photo.is_empty()) { - LOG(ERROR) << "Receive empty profile photo in getUserPhotos request for " << user_id << " with offset " << offset - << " and limit " << limit << ". Receive " << photo_count << " photos out of " << total_count - << " photos"; - user_photos->count--; - CHECK(user_photos->count >= 0); - continue; - } - - user_photos->photos.push_back(std::move(user_photo)); - register_user_photo(u, user_id, user_photos->photos.back()); - } - if (user_photos->offset > user_photos->count) { - user_photos->offset = user_photos->count; - user_photos->photos.clear(); - } - - auto known_photo_count = narrow_cast(user_photos->photos.size()); - if (user_photos->offset + known_photo_count > user_photos->count) { - user_photos->photos.resize(user_photos->count - user_photos->offset); - } -} - void ContactsManager::on_get_chat(tl_object_ptr &&chat, const char *source) { LOG(DEBUG) << "Receive from " << source << ' ' << to_string(chat); switch (chat->get_id()) { @@ -10837,47 +5138,6 @@ void ContactsManager::on_get_chats(vector> &&c } } -vector ContactsManager::get_bot_commands(vector> &&bot_infos, - const vector *participants) { - vector result; - if (td_->auth_manager_->is_bot()) { - return result; - } - for (auto &bot_info : bot_infos) { - if (bot_info->commands_.empty()) { - continue; - } - - auto user_id = UserId(bot_info->user_id_); - const User *u = get_user_force(user_id, "get_bot_commands"); - if (u == nullptr) { - LOG(ERROR) << "Receive unknown " << user_id; - continue; - } - if (!is_user_bot(u)) { - if (!is_user_deleted(u)) { - LOG(ERROR) << "Receive non-bot " << user_id; - } - continue; - } - if (participants != nullptr) { - bool is_participant = false; - for (auto &participant : *participants) { - if (participant.dialog_id_ == DialogId(user_id)) { - is_participant = true; - break; - } - } - if (!is_participant) { - LOG(ERROR) << "Skip commands of non-member bot " << user_id; - continue; - } - } - result.emplace_back(user_id, std::move(bot_info->commands_)); - } - return result; -} - void ContactsManager::on_get_chat_full(tl_object_ptr &&chat_full_ptr, Promise &&promise) { LOG(INFO) << "Receive " << to_string(chat_full_ptr); if (chat_full_ptr->get_id() == telegram_api::chatFull::ID) { @@ -10956,7 +5216,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c td_->messages_manager_->on_update_dialog_pending_join_requests(DialogId(chat_id), chat->requests_pending_, std::move(chat->recent_requesters_)); - auto bot_commands = get_bot_commands(std::move(chat->bot_info_), &chat_full->participants); + auto bot_commands = td_->user_manager_->get_bot_commands(std::move(chat->bot_info_), &chat_full->participants); if (chat_full->bot_commands != bot_commands) { chat_full->bot_commands = std::move(bot_commands); chat_full->is_changed = true; @@ -11185,7 +5445,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c vector bot_user_ids; for (const auto &bot_info : channel->bot_info_) { UserId user_id(bot_info->user_id_); - if (!is_user_bot(user_id)) { + if (!td_->user_manager_->is_user_bot(user_id)) { continue; } @@ -11193,7 +5453,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c } on_update_channel_full_bot_user_ids(channel_full, channel_id, std::move(bot_user_ids)); - auto bot_commands = get_bot_commands(std::move(channel->bot_info_), nullptr); + auto bot_commands = td_->user_manager_->get_bot_commands(std::move(channel->bot_info_), nullptr); if (channel_full->bot_commands != bot_commands) { channel_full->bot_commands = std::move(bot_commands); channel_full->is_changed = true; @@ -11277,1181 +5537,12 @@ void ContactsManager::on_get_channel_full_failed(ChannelId channel_id) { } } -void ContactsManager::on_update_user_name(UserId user_id, string &&first_name, string &&last_name, - Usernames &&usernames) { - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - User *u = get_user_force(user_id, "on_update_user_name"); - if (u != nullptr) { - on_update_user_name(u, user_id, std::move(first_name), std::move(last_name)); - on_update_user_usernames(u, user_id, std::move(usernames)); - update_user(u, user_id); - } else { - LOG(INFO) << "Ignore update user name about unknown " << user_id; - } -} - -void ContactsManager::on_update_user_name(User *u, UserId user_id, string &&first_name, string &&last_name) { - if (first_name.empty() && last_name.empty()) { - first_name = u->phone_number; - } - if (u->first_name != first_name || u->last_name != last_name) { - u->first_name = std::move(first_name); - u->last_name = std::move(last_name); - u->is_name_changed = true; - LOG(DEBUG) << "Name has changed for " << user_id; - u->is_changed = true; - } -} - -void ContactsManager::on_update_user_usernames(User *u, UserId user_id, Usernames &&usernames) { - if (u->usernames != usernames) { - td_->dialog_manager_->on_dialog_usernames_updated(DialogId(user_id), u->usernames, usernames); - td_->messages_manager_->on_dialog_usernames_updated(DialogId(user_id), u->usernames, usernames); - if (u->can_be_edited_bot && u->usernames.get_editable_username() != usernames.get_editable_username()) { - u->is_full_info_changed = true; - } - u->usernames = std::move(usernames); - u->is_username_changed = true; - LOG(DEBUG) << "Usernames have changed for " << user_id; - u->is_changed = true; - } else if (u->is_bot || !td_->auth_manager_->is_bot()) { - td_->dialog_manager_->on_dialog_usernames_received(DialogId(user_id), usernames, false); - } -} - -void ContactsManager::on_update_user_phone_number(UserId user_id, string &&phone_number) { - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - User *u = get_user_force(user_id, "on_update_user_phone_number"); - if (u != nullptr) { - on_update_user_phone_number(u, user_id, std::move(phone_number)); - update_user(u, user_id); - } else { - LOG(INFO) << "Ignore update user phone number about unknown " << user_id; - } -} - -void ContactsManager::on_update_user_phone_number(User *u, UserId user_id, string &&phone_number) { - if (td_->auth_manager_->is_bot()) { - return; - } - - clean_phone_number(phone_number); - if (u->phone_number != phone_number) { - if (!u->phone_number.empty()) { - auto it = resolved_phone_numbers_.find(u->phone_number); - if (it != resolved_phone_numbers_.end() && it->second == user_id) { - resolved_phone_numbers_.erase(it); - } - } - - u->phone_number = std::move(phone_number); - u->is_phone_number_changed = true; - LOG(DEBUG) << "Phone number has changed for " << user_id; - u->is_changed = true; - } -} - -void ContactsManager::on_update_user_photo(User *u, UserId user_id, - tl_object_ptr &&photo, const char *source) { - if (td_->auth_manager_->is_bot() && !G()->use_chat_info_database()) { - if (!u->is_photo_inited) { - auto new_photo_id = get_profile_photo_id(photo); - auto &old_photo = pending_user_photos_[user_id]; - if (new_photo_id == get_profile_photo_id(old_photo)) { - return; - } - if (photo != nullptr && photo->get_id() == telegram_api::userProfilePhoto::ID) { - auto *profile_photo = static_cast(photo.get()); - if ((profile_photo->flags_ & telegram_api::userProfilePhoto::STRIPPED_THUMB_MASK) != 0) { - profile_photo->flags_ -= telegram_api::userProfilePhoto::STRIPPED_THUMB_MASK; - profile_photo->stripped_thumb_ = BufferSlice(); - } - } - - old_photo = std::move(photo); - - drop_user_photos(user_id, new_photo_id == 0, "on_update_user_photo"); - auto user_full = get_user_full(user_id); // must not load UserFull - if (user_full != nullptr && new_photo_id != get_user_full_profile_photo_id(user_full)) { - // we didn't sent updateUser yet, so we must not sent updateUserFull with new_photo_id yet - drop_user_full_photos(user_full, user_id, 0, "on_update_user_photo"); - } - return; - } - if (u->is_received) { - auto new_photo_id = get_profile_photo_id(photo); - if (new_photo_id == u->photo.id) { - return; - } - } - } - - do_update_user_photo(u, user_id, std::move(photo), source); -} - -void ContactsManager::do_update_user_photo(User *u, UserId user_id, - tl_object_ptr &&photo, const char *source) { - ProfilePhoto new_photo = get_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, std::move(photo)); - if (td_->auth_manager_->is_bot()) { - new_photo.minithumbnail.clear(); - } - do_update_user_photo(u, user_id, std::move(new_photo), true, source); -} - -void ContactsManager::do_update_user_photo(User *u, UserId user_id, ProfilePhoto &&new_photo, - bool invalidate_photo_cache, const char *source) { - u->is_photo_inited = true; - if (need_update_profile_photo(u->photo, new_photo)) { - LOG_IF(ERROR, u->access_hash == -1 && new_photo.small_file_id.is_valid()) - << "Update profile photo of " << user_id << " without access hash from " << source; - u->photo = new_photo; - u->is_photo_changed = true; - LOG(DEBUG) << "Photo has changed for " << user_id << " to " << u->photo - << ", invalidate_photo_cache = " << invalidate_photo_cache << " from " << source; - u->is_changed = true; - - if (invalidate_photo_cache) { - drop_user_photos(user_id, u->photo.id == 0, source); - } - auto user_full = get_user_full(user_id); // must not load UserFull - if (user_full != nullptr && u->photo.id != get_user_full_profile_photo_id(user_full)) { - // we didn't sent updateUser yet, so we must not sent updateUserFull with u->photo.id yet - drop_user_full_photos(user_full, user_id, 0, "do_update_user_photo"); - } - } else if (need_update_dialog_photo_minithumbnail(u->photo.minithumbnail, new_photo.minithumbnail)) { - LOG(DEBUG) << "Photo minithumbnail has changed for " << user_id << " from " << source; - u->photo.minithumbnail = std::move(new_photo.minithumbnail); - u->is_photo_changed = true; - u->is_changed = true; - } -} - -void ContactsManager::register_suggested_profile_photo(const Photo &photo) { - auto photo_file_ids = photo_get_file_ids(photo); - if (photo.is_empty() || photo_file_ids.empty()) { - return; - } - auto first_file_id = photo_file_ids[0]; - auto file_type = td_->file_manager_->get_file_view(first_file_id).get_type(); - if (file_type == FileType::ProfilePhoto) { - return; - } - CHECK(file_type == FileType::Photo); - auto photo_id = photo.id.get(); - if (photo_id != 0) { - my_photo_file_id_[photo_id] = first_file_id; - } -} - -void ContactsManager::register_user_photo(User *u, UserId user_id, const Photo &photo) { - auto photo_file_ids = photo_get_file_ids(photo); - if (photo.is_empty() || photo_file_ids.empty()) { - return; - } - auto first_file_id = photo_file_ids[0]; - auto file_type = td_->file_manager_->get_file_view(first_file_id).get_type(); - if (file_type == FileType::ProfilePhoto) { - return; - } - CHECK(file_type == FileType::Photo); - CHECK(u != nullptr); - auto photo_id = photo.id.get(); - if (photo_id != 0 && u->photo_ids.emplace(photo_id).second) { - VLOG(file_references) << "Register photo " << photo_id << " of " << user_id; - if (user_id == get_my_id()) { - my_photo_file_id_[photo_id] = first_file_id; - } - auto file_source_id = user_profile_photo_file_source_ids_.get(std::make_pair(user_id, photo_id)); - if (file_source_id.is_valid()) { - VLOG(file_references) << "Move " << file_source_id << " inside of " << user_id; - user_profile_photo_file_source_ids_.erase(std::make_pair(user_id, photo_id)); - } else { - VLOG(file_references) << "Need to create new file source for photo " << photo_id << " of " << user_id; - file_source_id = td_->file_reference_manager_->create_user_photo_file_source(user_id, photo_id); - } - for (auto &file_id : photo_file_ids) { - td_->file_manager_->add_file_source(file_id, file_source_id); - } - } -} - -void ContactsManager::on_update_user_accent_color_id(User *u, UserId user_id, AccentColorId accent_color_id) { - if (accent_color_id == AccentColorId(user_id) || !accent_color_id.is_valid()) { - accent_color_id = AccentColorId(); - } - if (u->accent_color_id != accent_color_id) { - u->accent_color_id = accent_color_id; - u->is_accent_color_changed = true; - u->is_changed = true; - } -} - -void ContactsManager::on_update_user_background_custom_emoji_id(User *u, UserId user_id, - CustomEmojiId background_custom_emoji_id) { - if (u->background_custom_emoji_id != background_custom_emoji_id) { - u->background_custom_emoji_id = background_custom_emoji_id; - u->is_accent_color_changed = true; - u->is_changed = true; - } -} - -void ContactsManager::on_update_user_profile_accent_color_id(User *u, UserId user_id, AccentColorId accent_color_id) { - if (!accent_color_id.is_valid()) { - accent_color_id = AccentColorId(); - } - if (u->profile_accent_color_id != accent_color_id) { - u->profile_accent_color_id = accent_color_id; - u->is_accent_color_changed = true; - u->is_changed = true; - } -} - -void ContactsManager::on_update_user_profile_background_custom_emoji_id(User *u, UserId user_id, - CustomEmojiId background_custom_emoji_id) { - if (u->profile_background_custom_emoji_id != background_custom_emoji_id) { - u->profile_background_custom_emoji_id = background_custom_emoji_id; - u->is_accent_color_changed = true; - u->is_changed = true; - } -} - -void ContactsManager::on_update_user_emoji_status(UserId user_id, - tl_object_ptr &&emoji_status) { - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - User *u = get_user_force(user_id, "on_update_user_emoji_status"); - if (u != nullptr) { - on_update_user_emoji_status(u, user_id, EmojiStatus(std::move(emoji_status))); - update_user(u, user_id); - } else { - LOG(INFO) << "Ignore update user emoji status about unknown " << user_id; - } -} - -void ContactsManager::on_update_user_emoji_status(User *u, UserId user_id, EmojiStatus emoji_status) { - if (u->emoji_status != emoji_status) { - LOG(DEBUG) << "Change emoji status of " << user_id << " from " << u->emoji_status << " to " << emoji_status; - u->emoji_status = std::move(emoji_status); - u->is_emoji_status_changed = true; - // effective emoji status might not be changed; checked in update_user - // u->is_changed = true; - } -} - -void ContactsManager::on_update_user_story_ids(UserId user_id, StoryId max_active_story_id, StoryId max_read_story_id) { - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - User *u = get_user_force(user_id, "on_update_user_story_ids"); - if (u != nullptr) { - on_update_user_story_ids_impl(u, user_id, max_active_story_id, max_read_story_id); - update_user(u, user_id); - } else { - LOG(INFO) << "Ignore update user story identifiers about unknown " << user_id; - } -} - -void ContactsManager::on_update_user_story_ids_impl(User *u, UserId user_id, StoryId max_active_story_id, - StoryId max_read_story_id) { - if (td_->auth_manager_->is_bot()) { - return; - } - if (max_active_story_id != StoryId() && !max_active_story_id.is_server()) { - LOG(ERROR) << "Receive max active " << max_active_story_id << " for " << user_id; - return; - } - if (max_read_story_id != StoryId() && !max_read_story_id.is_server()) { - LOG(ERROR) << "Receive max read " << max_read_story_id << " for " << user_id; - return; - } - - auto has_unread_stories = get_user_has_unread_stories(u); - if (u->max_active_story_id != max_active_story_id) { - LOG(DEBUG) << "Change last active story of " << user_id << " from " << u->max_active_story_id << " to " - << max_active_story_id; - u->max_active_story_id = max_active_story_id; - u->need_save_to_database = true; - } - if (need_poll_user_active_stories(u, user_id)) { - auto max_active_story_id_next_reload_time = Time::now() + MAX_ACTIVE_STORY_ID_RELOAD_TIME; - if (max_active_story_id_next_reload_time > - u->max_active_story_id_next_reload_time + MAX_ACTIVE_STORY_ID_RELOAD_TIME / 5) { - LOG(DEBUG) << "Change max_active_story_id_next_reload_time of " << user_id; - u->max_active_story_id_next_reload_time = max_active_story_id_next_reload_time; - u->need_save_to_database = true; - } - } - if (!max_active_story_id.is_valid()) { - CHECK(max_read_story_id == StoryId()); - if (u->max_read_story_id != StoryId()) { - LOG(DEBUG) << "Drop last read " << u->max_read_story_id << " of " << user_id; - u->max_read_story_id = StoryId(); - u->need_save_to_database = true; - } - } else if (max_read_story_id.get() > u->max_read_story_id.get()) { - LOG(DEBUG) << "Change last read story of " << user_id << " from " << u->max_read_story_id << " to " - << max_read_story_id; - u->max_read_story_id = max_read_story_id; - u->need_save_to_database = true; - } - if (has_unread_stories != get_user_has_unread_stories(u)) { - LOG(DEBUG) << "Change has_unread_stories of " << user_id << " to " << !has_unread_stories; - u->is_changed = true; - } -} - -void ContactsManager::on_update_user_max_read_story_id(UserId user_id, StoryId max_read_story_id) { - CHECK(user_id.is_valid()); - - User *u = get_user(user_id); - if (u != nullptr) { - on_update_user_max_read_story_id(u, user_id, max_read_story_id); - update_user(u, user_id); - } -} - -void ContactsManager::on_update_user_max_read_story_id(User *u, UserId user_id, StoryId max_read_story_id) { - if (td_->auth_manager_->is_bot() || !u->is_received) { - return; - } - - auto has_unread_stories = get_user_has_unread_stories(u); - if (max_read_story_id.get() > u->max_read_story_id.get()) { - LOG(DEBUG) << "Change last read story of " << user_id << " from " << u->max_read_story_id << " to " - << max_read_story_id; - u->max_read_story_id = max_read_story_id; - u->need_save_to_database = true; - } - if (has_unread_stories != get_user_has_unread_stories(u)) { - LOG(DEBUG) << "Change has_unread_stories of " << user_id << " to " << !has_unread_stories; - u->is_changed = true; - } -} - -void ContactsManager::on_update_user_stories_hidden(UserId user_id, bool stories_hidden) { - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - User *u = get_user_force(user_id, "on_update_user_stories_hidden"); - if (u != nullptr) { - on_update_user_stories_hidden(u, user_id, stories_hidden); - update_user(u, user_id); - } else { - LOG(INFO) << "Ignore update user stories are archived about unknown " << user_id; - } -} - -void ContactsManager::on_update_user_stories_hidden(User *u, UserId user_id, bool stories_hidden) { - if (td_->auth_manager_->is_bot()) { - return; - } - - if (u->stories_hidden != stories_hidden) { - LOG(DEBUG) << "Change stories are archived of " << user_id << " to " << stories_hidden; - u->stories_hidden = stories_hidden; - u->is_stories_hidden_changed = true; - u->need_save_to_database = true; - } -} - -void ContactsManager::on_update_user_is_contact(User *u, UserId user_id, bool is_contact, bool is_mutual_contact, - bool is_close_friend) { - if (td_->auth_manager_->is_bot()) { - return; - } - - UserId my_id = get_my_id(); - if (user_id == my_id) { - is_mutual_contact = is_contact; - is_close_friend = false; - } - if (!is_contact && (is_mutual_contact || is_close_friend)) { - LOG(ERROR) << "Receive is_mutual_contact = " << is_mutual_contact << ", and is_close_friend = " << is_close_friend - << " for non-contact " << user_id; - is_mutual_contact = false; - is_close_friend = false; - } - - if (u->is_contact != is_contact || u->is_mutual_contact != is_mutual_contact || - u->is_close_friend != is_close_friend) { - LOG(DEBUG) << "Update " << user_id << " is_contact from (" << u->is_contact << ", " << u->is_mutual_contact << ", " - << u->is_close_friend << ") to (" << is_contact << ", " << is_mutual_contact << ", " << is_close_friend - << ")"; - if (u->is_contact != is_contact) { - u->is_contact = is_contact; - u->is_is_contact_changed = true; - - reload_contact_birthdates(true); - } - if (u->is_mutual_contact != is_mutual_contact) { - u->is_mutual_contact = is_mutual_contact; - u->is_is_mutual_contact_changed = true; - } - u->is_close_friend = is_close_friend; - u->is_changed = true; - } -} - -void ContactsManager::on_update_user_online(UserId user_id, tl_object_ptr &&status) { - if (td_->auth_manager_->is_bot()) { - return; - } - - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - User *u = get_user_force(user_id, "on_update_user_online"); - if (u != nullptr) { - if (u->is_bot) { - LOG(ERROR) << "Receive updateUserStatus about bot " << user_id; - return; - } - on_update_user_online(u, user_id, std::move(status)); - update_user(u, user_id); - - if (user_id == get_my_id() && - was_online_remote_ != u->was_online) { // only update was_online_remote_ from updateUserStatus - was_online_remote_ = u->was_online; - VLOG(notifications) << "Set was_online_remote to " << was_online_remote_; - G()->td_db()->get_binlog_pmc()->set("my_was_online_remote", to_string(was_online_remote_)); - } - } else { - LOG(INFO) << "Ignore update user online about unknown " << user_id; - } -} - -void ContactsManager::on_update_user_online(User *u, UserId user_id, tl_object_ptr &&status) { - if (td_->auth_manager_->is_bot()) { - return; - } - - int32 id = status == nullptr ? telegram_api::userStatusEmpty::ID : status->get_id(); - int32 new_online; - bool is_offline = false; - if (id == telegram_api::userStatusOnline::ID) { - int32 now = G()->unix_time(); - - auto st = move_tl_object_as(status); - new_online = st->expires_; - LOG_IF(ERROR, new_online < now - 86400) - << "Receive userStatusOnline expired more than one day in past " << new_online; - } else if (id == telegram_api::userStatusOffline::ID) { - int32 now = G()->unix_time(); - - auto st = move_tl_object_as(status); - new_online = st->was_online_; - if (new_online >= now) { - LOG_IF(ERROR, new_online > now + 10) - << "Receive userStatusOffline but was online points to future time " << new_online << ", now is " << now; - new_online = now - 1; - } - is_offline = true; - } else if (id == telegram_api::userStatusRecently::ID) { - auto st = telegram_api::move_object_as(status); - new_online = st->by_me_ ? -4 : -1; - } else if (id == telegram_api::userStatusLastWeek::ID) { - auto st = telegram_api::move_object_as(status); - new_online = st->by_me_ ? -5 : -2; - } else if (id == telegram_api::userStatusLastMonth::ID) { - auto st = telegram_api::move_object_as(status); - new_online = st->by_me_ ? -6 : -3; - } else { - CHECK(id == telegram_api::userStatusEmpty::ID); - new_online = 0; - } - - if (new_online != u->was_online && !(new_online < 0 && user_id == get_my_id())) { - LOG(DEBUG) << "Update " << user_id << " online from " << u->was_online << " to " << new_online; - auto unix_time = G()->unix_time(); - bool old_is_online = u->was_online > unix_time; - bool new_is_online = new_online > unix_time; - u->was_online = new_online; - u->is_status_changed = true; - if (u->was_online > 0) { - u->local_was_online = 0; - } - - if (user_id == get_my_id()) { - if (my_was_online_local_ != 0 || old_is_online != new_is_online) { - my_was_online_local_ = 0; - u->is_online_status_changed = true; - } - if (is_offline) { - td_->on_online_updated(false, false); - } - } else if (old_is_online != new_is_online) { - u->is_online_status_changed = true; - } - } -} - -void ContactsManager::on_update_user_local_was_online(UserId user_id, int32 local_was_online) { - CHECK(user_id.is_valid()); - if (td_->auth_manager_->is_bot()) { - return; - } - - User *u = get_user_force(user_id, "on_update_user_local_was_online"); - if (u == nullptr) { - return; - } - - on_update_user_local_was_online(u, user_id, local_was_online); - update_user(u, user_id); -} - -void ContactsManager::on_update_user_local_was_online(User *u, UserId user_id, int32 local_was_online) { - CHECK(u != nullptr); - if (u->is_deleted || u->is_bot || u->is_support || user_id == get_my_id()) { - return; - } - int32 unix_time = G()->unix_time(); - if (u->was_online > unix_time) { - // if user is currently online, ignore local online - return; - } - - // bring users online for 30 seconds - local_was_online += 30; - if (local_was_online < unix_time + 2 || local_was_online <= u->local_was_online || - local_was_online <= u->was_online) { - return; - } - - LOG(DEBUG) << "Update " << user_id << " local online from " << u->local_was_online << " to " << local_was_online; - bool old_is_online = u->local_was_online > unix_time; - u->local_was_online = local_was_online; - u->is_status_changed = true; - - if (!old_is_online) { - u->is_online_status_changed = true; - } -} - -void ContactsManager::on_update_user_is_blocked(UserId user_id, bool is_blocked, bool is_blocked_for_stories) { - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - UserFull *user_full = get_user_full_force(user_id, "on_update_user_is_blocked"); - if (user_full == nullptr) { - return; - } - on_update_user_full_is_blocked(user_full, user_id, is_blocked, is_blocked_for_stories); - update_user_full(user_full, user_id, "on_update_user_is_blocked"); -} - -void ContactsManager::on_update_user_full_is_blocked(UserFull *user_full, UserId user_id, bool is_blocked, - bool is_blocked_for_stories) { - CHECK(user_full != nullptr); - if (user_full->is_blocked != is_blocked || user_full->is_blocked_for_stories != is_blocked_for_stories) { - LOG(INFO) << "Receive update user full is blocked with " << user_id << " and is_blocked = " << is_blocked << '/' - << is_blocked_for_stories; - user_full->is_blocked = is_blocked; - user_full->is_blocked_for_stories = is_blocked_for_stories; - user_full->is_changed = true; - } -} - -void ContactsManager::on_update_user_has_pinned_stories(UserId user_id, bool has_pinned_stories) { - if (td_->auth_manager_->is_bot()) { - return; - } - - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - UserFull *user_full = get_user_full_force(user_id, "on_update_user_has_pinned_stories"); - if (user_full == nullptr || user_full->has_pinned_stories == has_pinned_stories) { - return; - } - user_full->has_pinned_stories = has_pinned_stories; - user_full->is_changed = true; - update_user_full(user_full, user_id, "on_update_user_has_pinned_stories"); -} - -void ContactsManager::on_update_user_common_chat_count(UserId user_id, int32 common_chat_count) { - LOG(INFO) << "Receive " << common_chat_count << " common chat count with " << user_id; - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - UserFull *user_full = get_user_full_force(user_id, "on_update_user_common_chat_count"); - if (user_full == nullptr) { - return; - } - on_update_user_full_common_chat_count(user_full, user_id, common_chat_count); - update_user_full(user_full, user_id, "on_update_user_common_chat_count"); -} - -void ContactsManager::on_update_user_full_common_chat_count(UserFull *user_full, UserId user_id, - int32 common_chat_count) { - CHECK(user_full != nullptr); - if (common_chat_count < 0) { - LOG(ERROR) << "Receive " << common_chat_count << " as common group count with " << user_id; - common_chat_count = 0; - } - if (user_full->common_chat_count != common_chat_count) { - user_full->common_chat_count = common_chat_count; - user_full->is_common_chat_count_changed = true; - user_full->is_changed = true; - } -} - -void ContactsManager::on_update_user_location(UserId user_id, DialogLocation &&location) { - LOG(INFO) << "Receive " << location << " for " << user_id; - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - UserFull *user_full = get_user_full_force(user_id, "on_update_user_location"); - if (user_full == nullptr) { - return; - } - on_update_user_full_location(user_full, user_id, std::move(location)); - update_user_full(user_full, user_id, "on_update_user_location"); -} - -void ContactsManager::on_update_user_full_location(UserFull *user_full, UserId user_id, DialogLocation &&location) { - CHECK(user_full != nullptr); - if (BusinessInfo::set_location(user_full->business_info, std::move(location))) { - user_full->is_changed = true; - } -} - -void ContactsManager::on_update_user_work_hours(UserId user_id, BusinessWorkHours &&work_hours) { - LOG(INFO) << "Receive " << work_hours << " for " << user_id; - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - UserFull *user_full = get_user_full_force(user_id, "on_update_user_work_hours"); - if (user_full == nullptr) { - return; - } - on_update_user_full_work_hours(user_full, user_id, std::move(work_hours)); - update_user_full(user_full, user_id, "on_update_user_work_hours"); -} - -void ContactsManager::on_update_user_full_work_hours(UserFull *user_full, UserId user_id, - BusinessWorkHours &&work_hours) { - CHECK(user_full != nullptr); - if (BusinessInfo::set_work_hours(user_full->business_info, std::move(work_hours))) { - user_full->is_changed = true; - } -} - -void ContactsManager::on_update_user_away_message(UserId user_id, BusinessAwayMessage &&away_message) { - LOG(INFO) << "Receive " << away_message << " for " << user_id; - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - UserFull *user_full = get_user_full_force(user_id, "on_update_user_away_message"); - if (user_full == nullptr) { - return; - } - on_update_user_full_away_message(user_full, user_id, std::move(away_message)); - update_user_full(user_full, user_id, "on_update_user_away_message"); -} - -void ContactsManager::on_update_user_full_away_message(UserFull *user_full, UserId user_id, - BusinessAwayMessage &&away_message) const { - CHECK(user_full != nullptr); - if (away_message.is_valid() && user_id != get_my_id()) { - LOG(ERROR) << "Receive " << away_message << " for " << user_id; - return; - } - if (BusinessInfo::set_away_message(user_full->business_info, std::move(away_message))) { - user_full->is_changed = true; - } -} - -void ContactsManager::on_update_user_greeting_message(UserId user_id, BusinessGreetingMessage &&greeting_message) { - LOG(INFO) << "Receive " << greeting_message << " for " << user_id; - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - UserFull *user_full = get_user_full_force(user_id, "on_update_user_greeting_message"); - if (user_full == nullptr) { - return; - } - on_update_user_full_greeting_message(user_full, user_id, std::move(greeting_message)); - update_user_full(user_full, user_id, "on_update_user_greeting_message"); -} - -void ContactsManager::on_update_user_full_greeting_message(UserFull *user_full, UserId user_id, - BusinessGreetingMessage &&greeting_message) const { - CHECK(user_full != nullptr); - if (greeting_message.is_valid() && user_id != get_my_id()) { - LOG(ERROR) << "Receive " << greeting_message << " for " << user_id; - return; - } - if (BusinessInfo::set_greeting_message(user_full->business_info, std::move(greeting_message))) { - user_full->is_changed = true; - } -} - -void ContactsManager::on_update_user_intro(UserId user_id, BusinessIntro &&intro) { - LOG(INFO) << "Receive " << intro << " for " << user_id; - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - UserFull *user_full = get_user_full_force(user_id, "on_update_user_intro"); - if (user_full == nullptr) { - return; - } - on_update_user_full_intro(user_full, user_id, std::move(intro)); - update_user_full(user_full, user_id, "on_update_user_intro"); -} - -void ContactsManager::on_update_user_full_intro(UserFull *user_full, UserId user_id, BusinessIntro &&intro) { - CHECK(user_full != nullptr); - if (BusinessInfo::set_intro(user_full->business_info, std::move(intro))) { - user_full->is_changed = true; - } -} - -void ContactsManager::on_update_user_commands( - UserId user_id, vector> &&bot_commands) { - UserFull *user_full = get_user_full_force(user_id, "on_update_user_commands"); - if (user_full != nullptr) { - on_update_user_full_commands(user_full, user_id, std::move(bot_commands)); - update_user_full(user_full, user_id, "on_update_user_commands"); - } -} - -void ContactsManager::on_update_user_full_commands(UserFull *user_full, UserId user_id, - vector> &&bot_commands) { - CHECK(user_full != nullptr); - auto commands = transform(std::move(bot_commands), [](tl_object_ptr &&bot_command) { - return BotCommand(std::move(bot_command)); - }); - if (user_full->commands != commands) { - user_full->commands = std::move(commands); - user_full->is_changed = true; - } -} - -void ContactsManager::on_update_user_full_menu_button(UserFull *user_full, UserId user_id, - tl_object_ptr &&bot_menu_button) { - CHECK(user_full != nullptr); - auto new_button = get_bot_menu_button(std::move(bot_menu_button)); - bool is_changed; - if (user_full->menu_button == nullptr) { - is_changed = (new_button != nullptr); - } else { - is_changed = (new_button == nullptr || *user_full->menu_button != *new_button); - } - if (is_changed) { - user_full->menu_button = std::move(new_button); - user_full->is_changed = true; - } -} - -void ContactsManager::on_update_user_need_phone_number_privacy_exception(UserId user_id, - bool need_phone_number_privacy_exception) { - LOG(INFO) << "Receive " << need_phone_number_privacy_exception << " need phone number privacy exception with " - << user_id; - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - UserFull *user_full = get_user_full_force(user_id, "on_update_user_need_phone_number_privacy_exception"); - if (user_full == nullptr) { - return; - } - on_update_user_full_need_phone_number_privacy_exception(user_full, user_id, need_phone_number_privacy_exception); - update_user_full(user_full, user_id, "on_update_user_need_phone_number_privacy_exception"); -} - -void ContactsManager::on_update_user_full_need_phone_number_privacy_exception( - UserFull *user_full, UserId user_id, bool need_phone_number_privacy_exception) const { - CHECK(user_full != nullptr); - if (need_phone_number_privacy_exception) { - const User *u = get_user(user_id); - if (u == nullptr || u->is_contact || user_id == get_my_id()) { - need_phone_number_privacy_exception = false; - } - } - if (user_full->need_phone_number_privacy_exception != need_phone_number_privacy_exception) { - user_full->need_phone_number_privacy_exception = need_phone_number_privacy_exception; - user_full->is_changed = true; - } -} - -void ContactsManager::on_update_user_wallpaper_overridden(UserId user_id, bool wallpaper_overridden) { - LOG(INFO) << "Receive " << wallpaper_overridden << " set chat background for " << user_id; - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - return; - } - - UserFull *user_full = get_user_full_force(user_id, "on_update_user_wallpaper_overridden"); - if (user_full == nullptr) { - return; - } - on_update_user_full_wallpaper_overridden(user_full, user_id, wallpaper_overridden); - update_user_full(user_full, user_id, "on_update_user_wallpaper_overridden"); -} - -void ContactsManager::on_update_user_full_wallpaper_overridden(UserFull *user_full, UserId user_id, - bool wallpaper_overridden) const { - CHECK(user_full != nullptr); - if (user_full->wallpaper_overridden != wallpaper_overridden) { - user_full->wallpaper_overridden = wallpaper_overridden; - user_full->is_changed = true; - } -} - void ContactsManager::on_ignored_restriction_reasons_changed() { - restricted_user_ids_.foreach([&](const UserId &user_id) { - send_closure(G()->td(), &Td::send_update, get_update_user_object(user_id, get_user(user_id))); - }); restricted_channel_ids_.foreach([&](const ChannelId &channel_id) { send_closure(G()->td(), &Td::send_update, get_update_supergroup_object(channel_id, get_channel(channel_id))); }); } -void ContactsManager::on_set_profile_photo(UserId user_id, tl_object_ptr &&photo, - bool is_fallback, int64 old_photo_id, Promise &&promise) { - LOG(INFO) << "Changed profile photo to " << to_string(photo); - - bool is_bot = is_user_bot(user_id); - bool is_my = (user_id == get_my_id()); - if (is_my && !is_fallback) { - delete_my_profile_photo_from_cache(old_photo_id); - } - bool have_user = false; - for (const auto &user : photo->users_) { - if (get_user_id(user) == user_id) { - have_user = true; - } - } - on_get_users(std::move(photo->users_), "on_set_profile_photo"); - if (!is_bot) { - add_set_profile_photo_to_cache(user_id, get_photo(td_, std::move(photo->photo_), DialogId(user_id)), is_fallback); - } - if (have_user) { - promise.set_value(Unit()); - } else { - reload_user(user_id, std::move(promise), "on_set_profile_photo"); - } -} - -void ContactsManager::on_delete_profile_photo(int64 profile_photo_id, Promise promise) { - bool need_reget_user = delete_my_profile_photo_from_cache(profile_photo_id); - if (need_reget_user && !G()->close_flag()) { - return reload_user(get_my_id(), std::move(promise), "on_delete_profile_photo"); - } - - promise.set_value(Unit()); -} - -int64 ContactsManager::get_user_full_profile_photo_id(const UserFull *user_full) { - if (!user_full->personal_photo.is_empty()) { - return user_full->personal_photo.id.get(); - } - if (!user_full->photo.is_empty()) { - return user_full->photo.id.get(); - } - return user_full->fallback_photo.id.get(); -} - -void ContactsManager::add_set_profile_photo_to_cache(UserId user_id, Photo &&photo, bool is_fallback) { - // we have subsequence of user photos in user_photos_ - // ProfilePhoto in User and Photo in UserFull - - User *u = get_user_force(user_id, "add_set_profile_photo_to_cache"); - if (u == nullptr) { - return; - } - - LOG(INFO) << "Add profile photo " << photo.id.get() << " to cache"; - - bool is_me = user_id == get_my_id(); - - // update photo list - auto user_photos = user_photos_.get_pointer(user_id); - if (is_me && !is_fallback && user_photos != nullptr && user_photos->count != -1 && !photo.is_empty()) { - if (user_photos->offset == 0) { - if (user_photos->photos.empty() || user_photos->photos[0].id.get() != photo.id.get()) { - user_photos->photos.insert(user_photos->photos.begin(), photo); - user_photos->count++; - register_user_photo(u, user_id, user_photos->photos[0]); - } - } else { - user_photos->count++; - user_photos->offset++; - } - } - - // update ProfilePhoto in User - if ((!is_fallback || u->photo.id == 0) && !photo.is_empty()) { - do_update_user_photo(u, user_id, as_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, photo, !is_me), - false, "add_set_profile_photo_to_cache"); - update_user(u, user_id); - } - - // update Photo in UserFull - auto user_full = get_user_full_force(user_id, "add_set_profile_photo_to_cache"); - if (user_full != nullptr) { - Photo *current_photo = nullptr; - // don't update the changed photo if other photos aren't known to avoid having only some photos known - bool need_apply = get_user_full_profile_photo_id(user_full) > 0; - if (!is_me) { - current_photo = &user_full->personal_photo; - if (photo.is_empty()) { - // always can apply empty personal photo - need_apply = true; - } - } else if (!is_fallback) { - current_photo = &user_full->photo; - if (photo.is_empty()) { - // never can apply empty photo - need_apply = false; - } - } else { - current_photo = &user_full->fallback_photo; - if (photo.is_empty()) { - // always can apply empty fallback photo - need_apply = true; - } - } - if (*current_photo != photo && need_apply) { - LOG(INFO) << "Update full photo of " << user_id << " to " << photo; - *current_photo = photo; - user_full->is_changed = true; - if (is_me && !photo.is_empty()) { - if (!is_fallback) { - register_user_photo(u, user_id, photo); - } else { - register_suggested_profile_photo(photo); - } - } - drop_user_full_photos(user_full, user_id, u->photo.id, "add_set_profile_photo_to_cache"); // just in case - } - if (user_full->expires_at > 0.0) { - user_full->expires_at = 0.0; - user_full->need_save_to_database = true; - } - update_user_full(user_full, user_id, "add_set_profile_photo_to_cache"); - reload_user_full(user_id, Auto(), "add_set_profile_photo_to_cache"); - } -} - -bool ContactsManager::delete_my_profile_photo_from_cache(int64 profile_photo_id) { - if (profile_photo_id == 0 || profile_photo_id == -2) { - return false; - } - - // we have subsequence of user photos in user_photos_ - // ProfilePhoto in User and Photo in UserFull - - LOG(INFO) << "Delete profile photo " << profile_photo_id << " from cache"; - - auto user_id = get_my_id(); - User *u = get_user_force(user_id, "delete_my_profile_photo_from_cache"); - bool is_main_photo_deleted = u != nullptr && u->photo.id == profile_photo_id; - - // update photo list - auto user_photos = user_photos_.get_pointer(user_id); - if (user_photos != nullptr && user_photos->count > 0) { - auto old_size = user_photos->photos.size(); - if (td::remove_if(user_photos->photos, - [profile_photo_id](const auto &photo) { return photo.id.get() == profile_photo_id; })) { - auto removed_photos = old_size - user_photos->photos.size(); - CHECK(removed_photos > 0); - LOG_IF(ERROR, removed_photos != 1) << "Had " << removed_photos << " photos with ID " << profile_photo_id; - user_photos->count -= narrow_cast(removed_photos); - // offset was not changed - CHECK(user_photos->count >= 0); - } else { - // failed to find photo to remove from cache - // don't know how to adjust user_photos->offset, so drop photos cache - LOG(INFO) << "Drop photos of " << user_id; - user_photos->photos.clear(); - user_photos->count = -1; - user_photos->offset = -1; - } - } - bool have_new_photo = - user_photos != nullptr && user_photos->count != -1 && user_photos->offset == 0 && !user_photos->photos.empty(); - - auto user_full = get_user_full_force(user_id, "delete_my_profile_photo_from_cache"); - - // update ProfilePhoto in User - bool need_reget_user = false; - if (is_main_photo_deleted) { - if (have_new_photo) { - do_update_user_photo( - u, user_id, - as_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, user_photos->photos[0], false), false, - "delete_my_profile_photo_from_cache"); - } else { - do_update_user_photo(u, user_id, ProfilePhoto(), false, "delete_my_profile_photo_from_cache 2"); - need_reget_user = user_photos == nullptr || user_photos->count != 0; - } - update_user(u, user_id); - - // update Photo in UserFull - if (user_full != nullptr) { - if (user_full->fallback_photo.id.get() == profile_photo_id) { - LOG(INFO) << "Drop full public photo of " << user_id; - user_full->photo = Photo(); - user_full->is_changed = true; - } else if (have_new_photo) { - if (user_full->photo.id.get() == profile_photo_id && user_photos->photos[0] != user_full->photo) { - LOG(INFO) << "Update full photo of " << user_id << " to " << user_photos->photos[0]; - user_full->photo = user_photos->photos[0]; - user_full->is_changed = true; - } - } else { - // repair UserFull photo - if (!user_full->photo.is_empty()) { - user_full->photo = Photo(); - user_full->is_changed = true; - } - if (!user_full->fallback_photo.is_empty()) { - user_full->fallback_photo = Photo(); - user_full->is_changed = true; - } - } - if (user_full->expires_at > 0.0) { - user_full->expires_at = 0.0; - user_full->need_save_to_database = true; - } - reload_user_full(user_id, Auto(), "delete_my_profile_photo_from_cache"); - update_user_full(user_full, user_id, "delete_my_profile_photo_from_cache"); - } - } - - return need_reget_user; -} - -void ContactsManager::drop_user_full_photos(UserFull *user_full, UserId user_id, int64 expected_photo_id, - const char *source) { - if (user_full == nullptr) { - return; - } - LOG(INFO) << "Expect full photo " << expected_photo_id << " from " << source; - for (auto photo_ptr : {&user_full->personal_photo, &user_full->photo, &user_full->fallback_photo}) { - if (photo_ptr->is_empty()) { - continue; - } - if (expected_photo_id == 0) { - // if profile photo is empty, we must drop the full photo - *photo_ptr = Photo(); - user_full->is_changed = true; - } else if (expected_photo_id != photo_ptr->id.get()) { - LOG(INFO) << "Drop full photo " << photo_ptr->id.get(); - // if full profile photo is unknown, we must drop the full photo - *photo_ptr = Photo(); - user_full->is_changed = true; - } else { - // nothing to drop - break; - } - } - if (expected_photo_id != get_user_full_profile_photo_id(user_full)) { - user_full->expires_at = 0.0; - } - if (user_full->is_update_user_full_sent) { - update_user_full(user_full, user_id, "drop_user_full_photos"); - } -} - -void ContactsManager::drop_user_photos(UserId user_id, bool is_empty, const char *source) { - LOG(INFO) << "Drop user photos to " << (is_empty ? "empty" : "unknown") << " from " << source; - auto user_photos = user_photos_.get_pointer(user_id); - if (user_photos != nullptr) { - int32 new_count = is_empty ? 0 : -1; - if (user_photos->count == new_count) { - CHECK(user_photos->photos.empty()); - CHECK(user_photos->offset == user_photos->count); - } else { - LOG(INFO) << "Drop photos of " << user_id << " to " << (is_empty ? "empty" : "unknown") << " from " << source; - user_photos->photos.clear(); - user_photos->count = new_count; - user_photos->offset = user_photos->count; - } - } -} - -void ContactsManager::drop_user_full(UserId user_id) { - auto user_full = get_user_full_force(user_id, "drop_user_full"); - - drop_user_photos(user_id, false, "drop_user_full"); - - if (user_full == nullptr) { - return; - } - - user_full->expires_at = 0.0; - - user_full->photo = Photo(); - user_full->personal_photo = Photo(); - user_full->fallback_photo = Photo(); - // user_full->is_blocked = false; - // user_full->is_blocked_for_stories = false; - user_full->can_be_called = false; - user_full->supports_video_calls = false; - user_full->has_private_calls = false; - user_full->need_phone_number_privacy_exception = false; - user_full->wallpaper_overridden = false; - user_full->about = string(); - user_full->description = string(); - user_full->description_photo = Photo(); - user_full->description_animation_file_id = FileId(); - user_full->menu_button = nullptr; - user_full->commands.clear(); - user_full->common_chat_count = 0; - user_full->personal_channel_id = ChannelId(); - user_full->business_info = nullptr; - user_full->private_forward_name.clear(); - user_full->group_administrator_rights = {}; - user_full->broadcast_administrator_rights = {}; - user_full->premium_gift_options.clear(); - user_full->voice_messages_forbidden = false; - user_full->has_pinned_stories = false; - user_full->read_dates_private = false; - user_full->contact_require_premium = false; - user_full->birthdate = {}; - user_full->is_changed = true; - - update_user_full(user_full, user_id, "drop_user_full"); - td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, true); -} - void ContactsManager::update_chat_online_member_count(ChatId chat_id, bool is_from_server) { auto chat_full = get_chat_full(chat_id); if (chat_full != nullptr) { @@ -12518,7 +5609,7 @@ void ContactsManager::on_get_chat_participants(tl_object_ptrdialog_manager_->have_dialog_info(dialog_participant.dialog_id_)) << "Have no information about " << dialog_participant.dialog_id_ << " as a member of " << chat_id; - LOG_IF(ERROR, !have_user(dialog_participant.inviter_user_id_)) + LOG_IF(ERROR, !td_->user_manager_->have_user(dialog_participant.inviter_user_id_)) << "Have no information about " << dialog_participant.inviter_user_id_ << " as a member of " << chat_id; if (dialog_participant.joined_date_ < c->date) { LOG_IF(ERROR, dialog_participant.joined_date_ < c->date - 30 && c->date >= 1486000000) @@ -12582,7 +5673,7 @@ tl_object_ptr ContactsManager::get_chat_member_object(const const char *source) const { return td_api::make_object( get_message_sender_object(td_, dialog_participant.dialog_id_, source), - get_user_id_object(dialog_participant.inviter_user_id_, "chatMember.inviter_user_id"), + td_->user_manager_->get_user_id_object(dialog_participant.inviter_user_id_, "chatMember.inviter_user_id"), dialog_participant.joined_date_, dialog_participant.status_.get_chat_member_status_object()); } @@ -12650,14 +5741,6 @@ bool ContactsManager::on_get_channel_error(ChannelId channel_id, const Status &s return false; } -bool ContactsManager::is_user_contact(UserId user_id, bool is_mutual) const { - return is_user_contact(get_user(user_id), user_id, is_mutual); -} - -bool ContactsManager::is_user_contact(const User *u, UserId user_id, bool is_mutual) const { - return u != nullptr && (is_mutual ? u->is_mutual_contact : u->is_contact) && user_id != get_my_id(); -} - bool ContactsManager::speculative_add_count(int32 &count, int32 delta_count, int32 min_count) { auto new_count = count + delta_count; if (new_count < min_count) { @@ -12683,7 +5766,8 @@ void ContactsManager::speculative_add_channel_participants(ChannelId channel_id, } delta_participant_count++; - if (channel_full != nullptr && is_user_bot(user_id) && !td::contains(channel_full->bot_user_ids, user_id)) { + if (channel_full != nullptr && td_->user_manager_->is_user_bot(user_id) && + !td::contains(channel_full->bot_user_ids, user_id)) { channel_full->bot_user_ids.push_back(user_id); channel_full->need_save_to_database = true; reload_channel_full(channel_id, Promise(), "speculative_add_channel_participants"); @@ -12712,7 +5796,7 @@ void ContactsManager::speculative_delete_channel_participant(ChannelId channel_i td_->dialog_participant_manager_->delete_cached_channel_participant(channel_id, deleted_user_id); - if (is_user_bot(deleted_user_id)) { + if (td_->user_manager_->is_user_bot(deleted_user_id)) { auto channel_full = get_channel_full_force(channel_id, true, "speculative_delete_channel_participant"); if (channel_full != nullptr && td::remove(channel_full->bot_user_ids, deleted_user_id)) { channel_full->need_save_to_database = true; @@ -12797,7 +5881,7 @@ void ContactsManager::speculative_add_channel_user(ChannelId channel_id, UserId channel_full->speculative_version++; } - if (new_status.is_member() != old_status.is_member() && is_user_bot(user_id)) { + if (new_status.is_member() != old_status.is_member() && td_->user_manager_->is_user_bot(user_id)) { if (new_status.is_member()) { if (!td::contains(channel_full->bot_user_ids, user_id)) { channel_full->bot_user_ids.push_back(user_id); @@ -13114,11 +6198,6 @@ bool ContactsManager::update_permanent_invite_link(DialogInviteLink &invite_link return false; } -bool ContactsManager::need_poll_user_active_stories(const User *u, UserId user_id) const { - return u != nullptr && user_id != get_my_id() && !is_user_contact(u, user_id, false) && !is_user_bot(u) && - !is_user_support(u) && !is_user_deleted(u) && u->was_online != 0; -} - void ContactsManager::repair_chat_participants(ChatId chat_id) { send_get_chat_full_query(chat_id, Auto(), "repair_chat_participants"); } @@ -13129,11 +6208,11 @@ void ContactsManager::on_update_chat_add_user(ChatId chat_id, UserId inviter_use LOG(ERROR) << "Receive invalid " << chat_id; return; } - if (!have_user(user_id)) { + if (!td_->user_manager_->have_user(user_id)) { LOG(ERROR) << "Can't find " << user_id; return; } - if (!have_user(inviter_user_id)) { + if (!td_->user_manager_->have_user(inviter_user_id)) { LOG(ERROR) << "Can't find " << inviter_user_id; return; } @@ -13199,7 +6278,7 @@ void ContactsManager::on_update_chat_edit_administrator(ChatId chat_id, UserId u LOG(ERROR) << "Receive invalid " << chat_id; return; } - if (!have_user(user_id)) { + if (!td_->user_manager_->have_user(user_id)) { LOG(ERROR) << "Can't find " << user_id; return; } @@ -13237,7 +6316,7 @@ void ContactsManager::on_update_chat_edit_administrator(ChatId chat_id, UserId u c->version = version; c->need_save_to_database = true; - if (user_id == get_my_id() && !c->status.is_creator()) { + if (user_id == td_->user_manager_->get_my_id() && !c->status.is_creator()) { // if chat with version was already received, then the update is already processed // so we need to call on_update_chat_status only if version > c->version on_update_chat_status(c, chat_id, status); @@ -13268,7 +6347,7 @@ void ContactsManager::on_update_chat_delete_user(ChatId chat_id, UserId user_id, LOG(ERROR) << "Receive invalid " << chat_id; return; } - if (!have_user(user_id)) { + if (!td_->user_manager_->have_user(user_id)) { LOG(ERROR) << "Can't find " << user_id; return; } @@ -13286,7 +6365,7 @@ void ContactsManager::on_update_chat_delete_user(ChatId chat_id, UserId user_id, repair_chat_participants(chat_id); return; } - if (user_id == get_my_id()) { + if (user_id == td_->user_manager_->get_my_id()) { LOG_IF(WARNING, c->status.is_member()) << "User was removed from " << chat_id << " but it is not left the group. Possible if updates comes out of order"; return; @@ -14265,480 +7344,6 @@ void ContactsManager::on_update_channel_default_permissions(ChannelId channel_id } } -void ContactsManager::update_contacts_hints(const User *u, UserId user_id, bool from_database) { - bool is_contact = is_user_contact(u, user_id, false); - if (td_->auth_manager_->is_bot()) { - LOG_IF(ERROR, is_contact) << "Bot has " << user_id << " in the contacts list"; - return; - } - - int64 key = user_id.get(); - string old_value = contacts_hints_.key_to_string(key); - string new_value = is_contact ? get_user_search_text(u) : string(); - - if (new_value != old_value) { - if (is_contact) { - contacts_hints_.add(key, new_value); - } else { - contacts_hints_.remove(key); - } - } - - if (G()->use_chat_info_database()) { - // update contacts database - if (!are_contacts_loaded_) { - if (!from_database && load_contacts_queries_.empty() && is_contact && u->is_is_contact_changed) { - search_contacts("", std::numeric_limits::max(), Auto()); - } - } else { - if (old_value.empty() == is_contact) { - save_contacts_to_database(); - } - } - } -} - -bool ContactsManager::have_user(UserId user_id) const { - auto u = get_user(user_id); - return u != nullptr && u->is_received; -} - -bool ContactsManager::have_min_user(UserId user_id) const { - return users_.count(user_id) > 0; -} - -bool ContactsManager::is_user_premium(UserId user_id) const { - return is_user_premium(get_user(user_id)); -} - -bool ContactsManager::is_user_premium(const User *u) { - return u != nullptr && u->is_premium; -} - -bool ContactsManager::is_user_deleted(UserId user_id) const { - return is_user_deleted(get_user(user_id)); -} - -bool ContactsManager::is_user_deleted(const User *u) { - return u == nullptr || u->is_deleted; -} - -bool ContactsManager::is_user_support(UserId user_id) const { - return is_user_support(get_user(user_id)); -} - -bool ContactsManager::is_user_support(const User *u) { - return u != nullptr && !u->is_deleted && u->is_support; -} - -bool ContactsManager::is_user_bot(UserId user_id) const { - return is_user_bot(get_user(user_id)); -} - -bool ContactsManager::is_user_bot(const User *u) { - return u != nullptr && !u->is_deleted && u->is_bot; -} - -Result ContactsManager::get_bot_data(UserId user_id) const { - auto u = get_user(user_id); - if (u == nullptr) { - return Status::Error(400, "Bot not found"); - } - if (!u->is_bot) { - return Status::Error(400, "User is not a bot"); - } - if (u->is_deleted) { - return Status::Error(400, "Bot is deleted"); - } - if (!u->is_received) { - return Status::Error(400, "Bot is inaccessible"); - } - - BotData bot_data; - bot_data.username = u->usernames.get_first_username(); - bot_data.can_be_edited = u->can_be_edited_bot; - bot_data.can_join_groups = u->can_join_groups; - bot_data.can_read_all_group_messages = u->can_read_all_group_messages; - bot_data.is_inline = u->is_inline_bot; - bot_data.is_business = u->is_business_bot; - bot_data.need_location = u->need_location_bot; - bot_data.can_be_added_to_attach_menu = u->can_be_added_to_attach_menu; - return bot_data; -} - -bool ContactsManager::is_user_online(UserId user_id, int32 tolerance, int32 unix_time) const { - if (unix_time <= 0) { - unix_time = G()->unix_time(); - } - int32 was_online = get_user_was_online(get_user(user_id), user_id, unix_time); - return was_online > unix_time - tolerance; -} - -int32 ContactsManager::get_user_was_online(UserId user_id, int32 unix_time) const { - if (unix_time <= 0) { - unix_time = G()->unix_time(); - } - return get_user_was_online(get_user(user_id), user_id, unix_time); -} - -bool ContactsManager::is_user_status_exact(UserId user_id) const { - auto u = get_user(user_id); - return u != nullptr && !u->is_deleted && !u->is_bot && u->was_online > 0; -} - -bool ContactsManager::can_report_user(UserId user_id) const { - auto u = get_user(user_id); - return u != nullptr && !u->is_deleted && !u->is_support && - (u->is_bot || td_->people_nearby_manager_->is_user_nearby(user_id)); -} - -const ContactsManager::User *ContactsManager::get_user(UserId user_id) const { - return users_.get_pointer(user_id); -} - -ContactsManager::User *ContactsManager::get_user(UserId user_id) { - return users_.get_pointer(user_id); -} - -void ContactsManager::send_get_me_query(Td *td, Promise &&promise) { - vector> users; - users.push_back(make_tl_object()); - td->create_handler(std::move(promise))->send(std::move(users)); -} - -UserId ContactsManager::get_me(Promise &&promise) { - auto my_id = get_my_id(); - if (!have_user_force(my_id, "get_me")) { - get_user_queries_.add_query(my_id.get(), std::move(promise), "get_me"); - return UserId(); - } - - promise.set_value(Unit()); - return my_id; -} - -bool ContactsManager::get_user(UserId user_id, int left_tries, Promise &&promise) { - if (!user_id.is_valid()) { - promise.set_error(Status::Error(400, "Invalid user identifier")); - return false; - } - - if (user_id == get_service_notifications_user_id() || user_id == get_replies_bot_user_id() || - user_id == get_anonymous_bot_user_id() || user_id == get_channel_bot_user_id() || - user_id == get_anti_spam_bot_user_id()) { - get_user_force(user_id, "get_user"); - } - - if (td_->auth_manager_->is_bot() ? !have_user(user_id) : !have_min_user(user_id)) { - if (left_tries > 2 && G()->use_chat_info_database()) { - send_closure_later(actor_id(this), &ContactsManager::load_user_from_database, nullptr, user_id, - std::move(promise)); - return false; - } - auto r_input_user = get_input_user(user_id); - if (left_tries == 1 || r_input_user.is_error()) { - if (r_input_user.is_error()) { - promise.set_error(r_input_user.move_as_error()); - } else { - promise.set_error(Status::Error(400, "User not found")); - } - return false; - } - - get_user_queries_.add_query(user_id.get(), std::move(promise), "get_user"); - return false; - } - - promise.set_value(Unit()); - return true; -} - -ContactsManager::User *ContactsManager::add_user(UserId user_id) { - CHECK(user_id.is_valid()); - auto &user_ptr = users_[user_id]; - if (user_ptr == nullptr) { - user_ptr = make_unique(); - } - return user_ptr.get(); -} - -const ContactsManager::UserFull *ContactsManager::get_user_full(UserId user_id) const { - return users_full_.get_pointer(user_id); -} - -ContactsManager::UserFull *ContactsManager::get_user_full(UserId user_id) { - return users_full_.get_pointer(user_id); -} - -ContactsManager::UserFull *ContactsManager::add_user_full(UserId user_id) { - CHECK(user_id.is_valid()); - auto &user_full_ptr = users_full_[user_id]; - if (user_full_ptr == nullptr) { - user_full_ptr = make_unique(); - user_full_contact_require_premium_.erase(user_id); - } - return user_full_ptr.get(); -} - -void ContactsManager::reload_user(UserId user_id, Promise &&promise, const char *source) { - if (!user_id.is_valid()) { - return promise.set_error(Status::Error(400, "Invalid user identifier")); - } - - have_user_force(user_id, source); - - TRY_STATUS_PROMISE(promise, get_input_user(user_id)); - - get_user_queries_.add_query(user_id.get(), std::move(promise), source); -} - -void ContactsManager::load_user_full(UserId user_id, bool force, Promise &&promise, const char *source) { - auto u = get_user(user_id); - if (u == nullptr) { - return promise.set_error(Status::Error(400, "User not found")); - } - - auto user_full = get_user_full_force(user_id, source); - if (user_full == nullptr) { - TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); - return send_get_user_full_query(user_id, std::move(input_user), std::move(promise), source); - } - if (user_full->is_expired()) { - auto input_user = get_input_user_force(user_id); - if (td_->auth_manager_->is_bot() && !force) { - return send_get_user_full_query(user_id, std::move(input_user), std::move(promise), "load expired user_full"); - } - - send_get_user_full_query(user_id, std::move(input_user), Auto(), "load expired user_full"); - } - - td_->story_manager_->on_view_dialog_active_stories({DialogId(user_id)}); - promise.set_value(Unit()); -} - -void ContactsManager::reload_user_full(UserId user_id, Promise &&promise, const char *source) { - TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); - send_get_user_full_query(user_id, std::move(input_user), std::move(promise), source); -} - -void ContactsManager::send_get_user_full_query(UserId user_id, tl_object_ptr &&input_user, - Promise &&promise, const char *source) { - LOG(INFO) << "Get full " << user_id << " from " << source; - if (!user_id.is_valid()) { - return promise.set_error(Status::Error(500, "Invalid user_id")); - } - auto send_query = - PromiseCreator::lambda([td = td_, input_user = std::move(input_user)](Result> &&promise) mutable { - if (promise.is_ok() && !G()->close_flag()) { - td->create_handler(promise.move_as_ok())->send(std::move(input_user)); - } - }); - get_user_full_queries_.add_query(user_id.get(), std::move(send_query), std::move(promise)); -} - -void ContactsManager::get_user_profile_photos(UserId user_id, int32 offset, int32 limit, - Promise> &&promise) { - if (offset < 0) { - return promise.set_error(Status::Error(400, "Parameter offset must be non-negative")); - } - if (limit <= 0) { - return promise.set_error(Status::Error(400, "Parameter limit must be positive")); - } - if (limit > MAX_GET_PROFILE_PHOTOS) { - limit = MAX_GET_PROFILE_PHOTOS; - } - - TRY_STATUS_PROMISE(promise, get_input_user(user_id)); - - auto *u = get_user(user_id); - if (u == nullptr) { - return promise.set_error(Status::Error(400, "User not found")); - } - - apply_pending_user_photo(u, user_id); - - auto user_photos = add_user_photos(user_id); - if (user_photos->count != -1) { // know photo count - CHECK(user_photos->offset != -1); - LOG(INFO) << "Have " << user_photos->count << " cached user profile photos at offset " << user_photos->offset; - vector> photo_objects; - - if (offset >= user_photos->count) { - // offset if too big - return promise.set_value(td_api::make_object(user_photos->count, std::move(photo_objects))); - } - - if (limit > user_photos->count - offset) { - limit = user_photos->count - offset; - } - - int32 cache_begin = user_photos->offset; - int32 cache_end = cache_begin + narrow_cast(user_photos->photos.size()); - if (cache_begin <= offset && offset + limit <= cache_end) { - // answer query from cache - for (int i = 0; i < limit; i++) { - photo_objects.push_back( - get_chat_photo_object(td_->file_manager_.get(), user_photos->photos[i + offset - cache_begin])); - } - return promise.set_value(td_api::make_object(user_photos->count, std::move(photo_objects))); - } - } - - PendingGetPhotoRequest pending_request; - pending_request.offset = offset; - pending_request.limit = limit; - pending_request.promise = std::move(promise); - user_photos->pending_requests.push_back(std::move(pending_request)); - if (user_photos->pending_requests.size() != 1u) { - return; - } - - send_get_user_photos_query(user_id, user_photos); -} - -void ContactsManager::send_get_user_photos_query(UserId user_id, const UserPhotos *user_photos) { - CHECK(!user_photos->pending_requests.empty()); - auto offset = user_photos->pending_requests[0].offset; - auto limit = user_photos->pending_requests[0].limit; - - if (user_photos->count != -1 && offset >= user_photos->offset) { - int32 cache_end = user_photos->offset + narrow_cast(user_photos->photos.size()); - if (offset < cache_end) { - // adjust offset to the end of cache - CHECK(offset + limit > cache_end); // otherwise the request has already been answered - limit = offset + limit - cache_end; - offset = cache_end; - } - } - - auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), user_id](Result &&result) { - send_closure(actor_id, &ContactsManager::on_get_user_profile_photos, user_id, std::move(result)); - }); - - td_->create_handler(std::move(query_promise)) - ->send(user_id, get_input_user_force(user_id), offset, max(limit, MAX_GET_PROFILE_PHOTOS / 5), 0); -} - -void ContactsManager::on_get_user_profile_photos(UserId user_id, Result &&result) { - G()->ignore_result_if_closing(result); - auto user_photos = add_user_photos(user_id); - auto pending_requests = std::move(user_photos->pending_requests); - CHECK(!pending_requests.empty()); - if (result.is_error()) { - for (auto &request : pending_requests) { - request.promise.set_error(result.error().clone()); - } - return; - } - if (user_photos->count == -1) { - CHECK(have_user(user_id)); - // received result has just been dropped; resend request - if (++pending_requests[0].retry_count >= 3) { - pending_requests[0].promise.set_error(Status::Error(500, "Failed to return profile photos")); - pending_requests.erase(pending_requests.begin()); - if (pending_requests.empty()) { - return; - } - } - user_photos->pending_requests = std::move(pending_requests); - return send_get_user_photos_query(user_id, user_photos); - } - - CHECK(user_photos->offset != -1); - LOG(INFO) << "Have " << user_photos->count << " cached user profile photos at offset " << user_photos->offset; - vector left_requests; - for (size_t request_index = 0; request_index < pending_requests.size(); request_index++) { - auto &request = pending_requests[request_index]; - vector> photo_objects; - - if (request.offset >= user_photos->count) { - // offset if too big - request.promise.set_value(td_api::make_object(user_photos->count, std::move(photo_objects))); - continue; - } - - if (request.limit > user_photos->count - request.offset) { - request.limit = user_photos->count - request.offset; - } - - int32 cache_begin = user_photos->offset; - int32 cache_end = cache_begin + narrow_cast(user_photos->photos.size()); - if (cache_begin <= request.offset && request.offset + request.limit <= cache_end) { - // answer query from cache - for (int i = 0; i < request.limit; i++) { - photo_objects.push_back( - get_chat_photo_object(td_->file_manager_.get(), user_photos->photos[i + request.offset - cache_begin])); - } - request.promise.set_value(td_api::make_object(user_photos->count, std::move(photo_objects))); - continue; - } - - if (request_index == 0 && ++request.retry_count >= 3) { - request.promise.set_error(Status::Error(500, "Failed to get profile photos")); - continue; - } - - left_requests.push_back(std::move(request)); - } - - if (!left_requests.empty()) { - bool need_send = user_photos->pending_requests.empty(); - append(user_photos->pending_requests, std::move(left_requests)); - if (need_send) { - send_get_user_photos_query(user_id, user_photos); - } - } -} - -void ContactsManager::reload_user_profile_photo(UserId user_id, int64 photo_id, Promise &&promise) { - get_user_force(user_id, "reload_user_profile_photo"); - TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); - - // this request will be needed only to download the photo, - // so there is no reason to combine different requests for a photo into one request - td_->create_handler(std::move(promise))->send(user_id, std::move(input_user), -1, 1, photo_id); -} - -FileSourceId ContactsManager::get_user_profile_photo_file_source_id(UserId user_id, int64 photo_id) { - if (!user_id.is_valid()) { - return FileSourceId(); - } - - auto u = get_user(user_id); - if (u != nullptr && u->photo_ids.count(photo_id) != 0) { - VLOG(file_references) << "Don't need to create file source for photo " << photo_id << " of " << user_id; - // photo was already added, source ID was registered and shouldn't be needed - return FileSourceId(); - } - - auto &source_id = user_profile_photo_file_source_ids_[std::make_pair(user_id, photo_id)]; - if (!source_id.is_valid()) { - source_id = td_->file_reference_manager_->create_user_photo_file_source(user_id, photo_id); - } - VLOG(file_references) << "Return " << source_id << " for photo " << photo_id << " of " << user_id; - return source_id; -} - -FileSourceId ContactsManager::get_user_full_file_source_id(UserId user_id) { - if (!user_id.is_valid()) { - return FileSourceId(); - } - - auto user_full = get_user_full(user_id); - if (user_full != nullptr) { - VLOG(file_references) << "Don't need to create file source for full " << user_id; - // user full was already added, source ID was registered and shouldn't be needed - return user_full->is_update_user_full_sent ? FileSourceId() : user_full->file_source_id; - } - - auto &source_id = user_full_file_source_ids_[user_id]; - if (!source_id.is_valid()) { - source_id = td_->file_reference_manager_->create_user_full_file_source(user_id); - } - VLOG(file_references) << "Return " << source_id << " for full " << user_id; - return source_id; -} - FileSourceId ContactsManager::get_chat_full_file_source_id(ChatId chat_id) { if (!chat_id.is_valid()) { return FileSourceId(); @@ -14788,7 +7393,7 @@ void ContactsManager::create_new_chat(const vector &user_ids, const stri vector> input_users; for (auto user_id : user_ids) { - auto r_input_user = get_input_user(user_id); + auto r_input_user = td_->user_manager_->get_input_user(user_id); if (r_input_user.is_error()) { return promise.set_error(r_input_user.move_as_error()); } @@ -15431,129 +8036,6 @@ void ContactsManager::send_get_channel_full_query(ChannelFull *channel_full, Cha get_chat_full_queries_.add_query(DialogId(channel_id).get(), std::move(send_query), std::move(promise)); } -void ContactsManager::create_new_secret_chat(UserId user_id, Promise> &&promise) { - TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); - if (input_user->get_id() != telegram_api::inputUser::ID) { - return promise.set_error(Status::Error(400, "Can't create secret chat with the user")); - } - auto user = static_cast(input_user.get()); - - send_closure( - G()->secret_chats_manager(), &SecretChatsManager::create_chat, UserId(user->user_id_), user->access_hash_, - PromiseCreator::lambda([actor_id = actor_id(this), - promise = std::move(promise)](Result r_secret_chat_id) mutable { - if (r_secret_chat_id.is_error()) { - return promise.set_error(r_secret_chat_id.move_as_error()); - } - send_closure(actor_id, &ContactsManager::on_create_new_secret_chat, r_secret_chat_id.ok(), std::move(promise)); - })); -} - -void ContactsManager::on_create_new_secret_chat(SecretChatId secret_chat_id, - Promise> &&promise) { - TRY_STATUS_PROMISE(promise, G()->close_status()); - CHECK(secret_chat_id.is_valid()); - DialogId dialog_id(secret_chat_id); - td_->dialog_manager_->force_create_dialog(dialog_id, "on_create_new_secret_chat"); - promise.set_value(td_->messages_manager_->get_chat_object(dialog_id, "on_create_new_secret_chat")); -} - -bool ContactsManager::have_secret_chat(SecretChatId secret_chat_id) const { - return secret_chats_.count(secret_chat_id) > 0; -} - -ContactsManager::SecretChat *ContactsManager::add_secret_chat(SecretChatId secret_chat_id) { - CHECK(secret_chat_id.is_valid()); - auto &secret_chat_ptr = secret_chats_[secret_chat_id]; - if (secret_chat_ptr == nullptr) { - secret_chat_ptr = make_unique(); - } - return secret_chat_ptr.get(); -} - -const ContactsManager::SecretChat *ContactsManager::get_secret_chat(SecretChatId secret_chat_id) const { - return secret_chats_.get_pointer(secret_chat_id); -} - -ContactsManager::SecretChat *ContactsManager::get_secret_chat(SecretChatId secret_chat_id) { - return secret_chats_.get_pointer(secret_chat_id); -} - -bool ContactsManager::get_secret_chat(SecretChatId secret_chat_id, bool force, Promise &&promise) { - if (!secret_chat_id.is_valid()) { - promise.set_error(Status::Error(400, "Invalid secret chat identifier")); - return false; - } - - if (!have_secret_chat(secret_chat_id)) { - if (!force && G()->use_chat_info_database()) { - send_closure_later(actor_id(this), &ContactsManager::load_secret_chat_from_database, nullptr, secret_chat_id, - std::move(promise)); - return false; - } - - promise.set_error(Status::Error(400, "Secret chat not found")); - return false; - } - - promise.set_value(Unit()); - return true; -} - -void ContactsManager::on_update_secret_chat(SecretChatId secret_chat_id, int64 access_hash, UserId user_id, - SecretChatState state, bool is_outbound, int32 ttl, int32 date, - string key_hash, int32 layer, FolderId initial_folder_id) { - LOG(INFO) << "Update " << secret_chat_id << " with " << user_id << " and access_hash " << access_hash; - auto *secret_chat = add_secret_chat(secret_chat_id); - if (access_hash != secret_chat->access_hash) { - secret_chat->access_hash = access_hash; - secret_chat->need_save_to_database = true; - } - if (user_id.is_valid() && user_id != secret_chat->user_id) { - if (secret_chat->user_id.is_valid()) { - LOG(ERROR) << "Secret chat user has changed from " << secret_chat->user_id << " to " << user_id; - auto &old_secret_chat_ids = secret_chats_with_user_[secret_chat->user_id]; - td::remove(old_secret_chat_ids, secret_chat_id); - } - secret_chat->user_id = user_id; - secret_chats_with_user_[secret_chat->user_id].push_back(secret_chat_id); - secret_chat->is_changed = true; - } - if (state != SecretChatState::Unknown && state != secret_chat->state) { - secret_chat->state = state; - secret_chat->is_changed = true; - secret_chat->is_state_changed = true; - } - if (is_outbound != secret_chat->is_outbound) { - secret_chat->is_outbound = is_outbound; - secret_chat->is_changed = true; - } - - if (ttl != -1 && ttl != secret_chat->ttl) { - secret_chat->ttl = ttl; - secret_chat->need_save_to_database = true; - secret_chat->is_ttl_changed = true; - } - if (date != 0 && date != secret_chat->date) { - secret_chat->date = date; - secret_chat->need_save_to_database = true; - } - if (!key_hash.empty() && key_hash != secret_chat->key_hash) { - secret_chat->key_hash = std::move(key_hash); - secret_chat->is_changed = true; - } - if (layer != 0 && layer != secret_chat->layer) { - secret_chat->layer = layer; - secret_chat->is_changed = true; - } - if (initial_folder_id != FolderId() && initial_folder_id != secret_chat->initial_folder_id) { - secret_chat->initial_folder_id = initial_folder_id; - secret_chat->is_changed = true; - } - - update_secret_chat(secret_chat, secret_chat_id); -} - void ContactsManager::get_chat_participant(ChatId chat_id, UserId user_id, Promise &&promise) { LOG(INFO) << "Trying to get " << user_id << " as member of " << chat_id; @@ -16183,264 +8665,6 @@ void ContactsManager::on_get_channel_forbidden(telegram_api::channelForbidden &c } } -void ContactsManager::on_upload_profile_photo(FileId file_id, tl_object_ptr input_file) { - auto it = uploaded_profile_photos_.find(file_id); - CHECK(it != uploaded_profile_photos_.end()); - - UserId user_id = it->second.user_id; - bool is_fallback = it->second.is_fallback; - bool only_suggest = it->second.only_suggest; - double main_frame_timestamp = it->second.main_frame_timestamp; - bool is_animation = it->second.is_animation; - int32 reupload_count = it->second.reupload_count; - auto promise = std::move(it->second.promise); - - uploaded_profile_photos_.erase(it); - - LOG(INFO) << "Uploaded " << (is_animation ? "animated" : "static") << " profile photo " << file_id << " for " - << user_id << " with reupload_count = " << reupload_count; - FileView file_view = td_->file_manager_->get_file_view(file_id); - if (file_view.has_remote_location() && input_file == nullptr) { - if (file_view.main_remote_location().is_web()) { - return promise.set_error(Status::Error(400, "Can't use web photo as profile photo")); - } - if (reupload_count == 3) { // upload, ForceReupload repair file reference, reupload - return promise.set_error(Status::Error(400, "Failed to reupload the file")); - } - - // delete file reference and forcely reupload the file - if (is_animation) { - CHECK(file_view.get_type() == FileType::Animation); - LOG_CHECK(file_view.main_remote_location().is_common()) << file_view.main_remote_location(); - } else { - CHECK(file_view.get_type() == FileType::Photo); - LOG_CHECK(file_view.main_remote_location().is_photo()) << file_view.main_remote_location(); - } - auto file_reference = - is_animation ? FileManager::extract_file_reference(file_view.main_remote_location().as_input_document()) - : FileManager::extract_file_reference(file_view.main_remote_location().as_input_photo()); - td_->file_manager_->delete_file_reference(file_id, file_reference); - upload_profile_photo(user_id, file_id, is_fallback, only_suggest, is_animation, main_frame_timestamp, - std::move(promise), reupload_count + 1, {-1}); - return; - } - CHECK(input_file != nullptr); - - td_->create_handler(std::move(promise)) - ->send(user_id, file_id, std::move(input_file), is_fallback, only_suggest, is_animation, main_frame_timestamp); -} - -void ContactsManager::on_upload_profile_photo_error(FileId file_id, Status status) { - LOG(INFO) << "File " << file_id << " has upload error " << status; - CHECK(status.is_error()); - - auto it = uploaded_profile_photos_.find(file_id); - CHECK(it != uploaded_profile_photos_.end()); - - auto promise = std::move(it->second.promise); - - uploaded_profile_photos_.erase(it); - - promise.set_error(std::move(status)); // TODO check that status has valid error code -} - -td_api::object_ptr ContactsManager::get_user_status_object(UserId user_id, const User *u, - int32 unix_time) const { - if (u->is_bot) { - return make_tl_object(std::numeric_limits::max()); - } - - int32 was_online = get_user_was_online(u, user_id, unix_time); - switch (was_online) { - case -6: - case -3: - return make_tl_object(was_online == -6); - case -5: - case -2: - return make_tl_object(was_online == -5); - case -4: - case -1: - return make_tl_object(was_online == -4); - case 0: - return make_tl_object(); - default: { - int32 time = G()->unix_time(); - if (was_online > time) { - return make_tl_object(was_online); - } else { - return make_tl_object(was_online); - } - } - } -} - -bool ContactsManager::get_user_has_unread_stories(const User *u) { - CHECK(u != nullptr); - return u->max_active_story_id.get() > u->max_read_story_id.get(); -} - -td_api::object_ptr ContactsManager::get_update_contact_close_birthdays() const { - return td_api::make_object( - transform(contact_birthdates_.users_, [this](const std::pair &user) { - return td_api::make_object(get_user_id_object(user.first, "closeBirthdayUser"), - user.second.get_birthdate_object()); - })); -} - -td_api::object_ptr ContactsManager::get_update_user_object(UserId user_id, const User *u) const { - if (u == nullptr) { - return get_update_unknown_user_object(user_id); - } - return td_api::make_object(get_user_object(user_id, u)); -} - -td_api::object_ptr ContactsManager::get_update_unknown_user_object(UserId user_id) const { - auto have_access = user_id == get_my_id() || user_messages_.count(user_id) != 0; - return td_api::make_object(td_api::make_object( - user_id.get(), "", "", nullptr, "", td_api::make_object(), nullptr, - td_->theme_manager_->get_accent_color_id_object(AccentColorId(user_id)), 0, -1, 0, nullptr, false, false, false, - false, false, false, "", false, false, false, false, false, have_access, - td_api::make_object(), "", false)); -} - -int64 ContactsManager::get_user_id_object(UserId user_id, const char *source) const { - if (user_id.is_valid() && get_user(user_id) == nullptr && unknown_users_.count(user_id) == 0) { - LOG(ERROR) << "Have no information about " << user_id << " from " << source; - unknown_users_.insert(user_id); - send_closure(G()->td(), &Td::send_update, get_update_unknown_user_object(user_id)); - } - return user_id.get(); -} - -tl_object_ptr ContactsManager::get_user_object(UserId user_id) const { - return get_user_object(user_id, get_user(user_id)); -} - -tl_object_ptr ContactsManager::get_user_object(UserId user_id, const User *u) const { - if (u == nullptr) { - return nullptr; - } - tl_object_ptr type; - if (u->is_deleted) { - type = make_tl_object(); - } else if (u->is_bot) { - type = make_tl_object(u->can_be_edited_bot, u->can_join_groups, u->can_read_all_group_messages, - u->is_inline_bot, u->inline_query_placeholder, u->need_location_bot, - u->is_business_bot, u->can_be_added_to_attach_menu); - } else { - type = make_tl_object(); - } - - auto emoji_status = u->last_sent_emoji_status.get_emoji_status_object(); - auto have_access = user_id == get_my_id() || have_input_peer_user(u, user_id, AccessRights::Know); - auto accent_color_id = u->accent_color_id.is_valid() ? u->accent_color_id : AccentColorId(user_id); - auto restricts_new_chats = u->contact_require_premium && !u->is_mutual_contact; - return td_api::make_object( - user_id.get(), u->first_name, u->last_name, u->usernames.get_usernames_object(), u->phone_number, - get_user_status_object(user_id, u, G()->unix_time()), - get_profile_photo_object(td_->file_manager_.get(), u->photo), - td_->theme_manager_->get_accent_color_id_object(accent_color_id, AccentColorId(user_id)), - u->background_custom_emoji_id.get(), - td_->theme_manager_->get_profile_accent_color_id_object(u->profile_accent_color_id), - u->profile_background_custom_emoji_id.get(), std::move(emoji_status), u->is_contact, u->is_mutual_contact, - u->is_close_friend, u->is_verified, u->is_premium, u->is_support, - get_restriction_reason_description(u->restriction_reasons), u->is_scam, u->is_fake, - u->max_active_story_id.is_valid(), get_user_has_unread_stories(u), restricts_new_chats, have_access, - std::move(type), u->language_code, u->attach_menu_enabled); -} - -vector ContactsManager::get_user_ids_object(const vector &user_ids, const char *source) const { - return transform(user_ids, [this, source](UserId user_id) { return get_user_id_object(user_id, source); }); -} - -tl_object_ptr ContactsManager::get_users_object(int32 total_count, - const vector &user_ids) const { - if (total_count == -1) { - total_count = narrow_cast(user_ids.size()); - } - return td_api::make_object(total_count, get_user_ids_object(user_ids, "get_users_object")); -} - -tl_object_ptr ContactsManager::get_user_full_info_object(UserId user_id) const { - return get_user_full_info_object(user_id, get_user_full(user_id)); -} - -tl_object_ptr ContactsManager::get_user_full_info_object(UserId user_id, - const UserFull *user_full) const { - CHECK(user_full != nullptr); - td_api::object_ptr bot_info; - const User *u = get_user(user_id); - bool is_bot = is_user_bot(u); - bool is_premium = is_user_premium(u); - td_api::object_ptr bio_object; - if (is_bot) { - auto menu_button = get_bot_menu_button_object(td_, user_full->menu_button.get()); - auto commands = - transform(user_full->commands, [](const auto &command) { return command.get_bot_command_object(); }); - bot_info = td_api::make_object( - user_full->about, user_full->description, - get_photo_object(td_->file_manager_.get(), user_full->description_photo), - td_->animations_manager_->get_animation_object(user_full->description_animation_file_id), - std::move(menu_button), std::move(commands), - user_full->group_administrator_rights == AdministratorRights() - ? nullptr - : user_full->group_administrator_rights.get_chat_administrator_rights_object(), - user_full->broadcast_administrator_rights == AdministratorRights() - ? nullptr - : user_full->broadcast_administrator_rights.get_chat_administrator_rights_object(), - nullptr, nullptr, nullptr, nullptr); - if (u != nullptr && u->can_be_edited_bot && u->usernames.has_editable_username()) { - auto bot_username = u->usernames.get_editable_username(); - bot_info->edit_commands_link_ = td_api::make_object( - "botfather", PSTRING() << bot_username << "-commands", true); - bot_info->edit_description_link_ = td_api::make_object( - "botfather", PSTRING() << bot_username << "-intro", true); - bot_info->edit_description_media_link_ = td_api::make_object( - "botfather", PSTRING() << bot_username << "-intropic", true); - bot_info->edit_settings_link_ = - td_api::make_object("botfather", bot_username, true); - } - } else { - FormattedText bio; - bio.text = user_full->about; - bio.entities = find_entities(bio.text, true, true); - if (!is_premium) { - td::remove_if(bio.entities, [&](const MessageEntity &entity) { - if (entity.type == MessageEntity::Type::EmailAddress) { - return true; - } - if (entity.type == MessageEntity::Type::Url && - !LinkManager::is_internal_link(utf8_utf16_substr(bio.text, entity.offset, entity.length))) { - return true; - } - return false; - }); - } - bio_object = get_formatted_text_object(bio, true, 0); - } - auto voice_messages_forbidden = is_premium ? user_full->voice_messages_forbidden : false; - auto block_list_id = BlockListId(user_full->is_blocked, user_full->is_blocked_for_stories); - auto business_info = is_premium && user_full->business_info != nullptr - ? user_full->business_info->get_business_info_object(td_) - : nullptr; - int64 personal_chat_id = 0; - if (user_full->personal_channel_id.is_valid()) { - DialogId dialog_id(user_full->personal_channel_id); - td_->dialog_manager_->force_create_dialog(dialog_id, "get_user_full_info_object", true); - personal_chat_id = td_->dialog_manager_->get_chat_id_object(dialog_id, "get_user_full_info_object"); - } - return td_api::make_object( - get_chat_photo_object(td_->file_manager_.get(), user_full->personal_photo), - get_chat_photo_object(td_->file_manager_.get(), user_full->photo), - get_chat_photo_object(td_->file_manager_.get(), user_full->fallback_photo), block_list_id.get_block_list_object(), - user_full->can_be_called, user_full->supports_video_calls, user_full->has_private_calls, - !user_full->private_forward_name.empty(), voice_messages_forbidden, user_full->has_pinned_stories, - user_full->need_phone_number_privacy_exception, user_full->wallpaper_overridden, std::move(bio_object), - user_full->birthdate.get_birthdate_object(), personal_chat_id, - get_premium_payment_options_object(user_full->premium_gift_options), user_full->common_chat_count, - std::move(business_info), std::move(bot_info)); -} - td_api::object_ptr ContactsManager::get_update_basic_group_object(ChatId chat_id, const Chat *c) { if (c == nullptr) { @@ -16498,9 +8722,9 @@ tl_object_ptr ContactsManager::get_basic_group_full_ }); return make_tl_object( get_chat_photo_object(td_->file_manager_.get(), chat_full->photo), chat_full->description, - get_user_id_object(chat_full->creator_user_id, "basicGroupFullInfo"), std::move(members), + td_->user_manager_->get_user_id_object(chat_full->creator_user_id, "basicGroupFullInfo"), std::move(members), can_hide_chat_participants(chat_id).is_ok(), can_toggle_chat_aggressive_anti_spam(chat_id).is_ok(), - chat_full->invite_link.get_chat_invite_link_object(this), std::move(bot_commands)); + chat_full->invite_link.get_chat_invite_link_object(td_->user_manager_.get()), std::move(bot_commands)); } td_api::object_ptr ContactsManager::get_update_supergroup_object(ChannelId channel_id, @@ -16588,108 +8812,12 @@ tl_object_ptr ContactsManager::get_supergroup_full_i channel_full->has_aggressive_anti_spam_enabled, channel_full->has_pinned_stories, channel_full->boost_count, channel_full->unrestrict_boost_count, channel_full->sticker_set_id.get(), channel_full->emoji_sticker_set_id.get(), channel_full->location.get_chat_location_object(), - channel_full->invite_link.get_chat_invite_link_object(this), std::move(bot_commands), + channel_full->invite_link.get_chat_invite_link_object(td_->user_manager_.get()), std::move(bot_commands), get_basic_group_id_object(channel_full->migrated_from_chat_id, "get_supergroup_full_info_object"), channel_full->migrated_from_max_message_id.get()); } -tl_object_ptr ContactsManager::get_secret_chat_state_object(SecretChatState state) { - switch (state) { - case SecretChatState::Waiting: - return make_tl_object(); - case SecretChatState::Active: - return make_tl_object(); - case SecretChatState::Closed: - case SecretChatState::Unknown: - return make_tl_object(); - default: - UNREACHABLE(); - return nullptr; - } -} - -td_api::object_ptr ContactsManager::get_update_secret_chat_object( - SecretChatId secret_chat_id, const SecretChat *secret_chat) { - if (secret_chat == nullptr) { - return get_update_unknown_secret_chat_object(secret_chat_id); - } - return td_api::make_object(get_secret_chat_object(secret_chat_id, secret_chat)); -} - -td_api::object_ptr ContactsManager::get_update_unknown_secret_chat_object( - SecretChatId secret_chat_id) { - return td_api::make_object(td_api::make_object( - secret_chat_id.get(), 0, get_secret_chat_state_object(SecretChatState::Unknown), false, string(), 0)); -} - -int32 ContactsManager::get_secret_chat_id_object(SecretChatId secret_chat_id, const char *source) const { - if (secret_chat_id.is_valid() && get_secret_chat(secret_chat_id) == nullptr && - unknown_secret_chats_.count(secret_chat_id) == 0) { - LOG(ERROR) << "Have no information about " << secret_chat_id << " from " << source; - unknown_secret_chats_.insert(secret_chat_id); - send_closure(G()->td(), &Td::send_update, get_update_unknown_secret_chat_object(secret_chat_id)); - } - return secret_chat_id.get(); -} - -tl_object_ptr ContactsManager::get_secret_chat_object(SecretChatId secret_chat_id) { - return get_secret_chat_object(secret_chat_id, get_secret_chat(secret_chat_id)); -} - -tl_object_ptr ContactsManager::get_secret_chat_object(SecretChatId secret_chat_id, - const SecretChat *secret_chat) { - if (secret_chat == nullptr) { - return nullptr; - } - get_user_force(secret_chat->user_id, "get_secret_chat_object"); - return get_secret_chat_object_const(secret_chat_id, secret_chat); -} - -tl_object_ptr ContactsManager::get_secret_chat_object_const(SecretChatId secret_chat_id, - const SecretChat *secret_chat) const { - return td_api::make_object(secret_chat_id.get(), - get_user_id_object(secret_chat->user_id, "secretChat"), - get_secret_chat_state_object(secret_chat->state), - secret_chat->is_outbound, secret_chat->key_hash, secret_chat->layer); -} - -void ContactsManager::get_support_user(Promise> &&promise) { - if (support_user_id_.is_valid()) { - return promise.set_value(get_user_object(support_user_id_)); - } - - auto query_promise = PromiseCreator::lambda( - [actor_id = actor_id(this), promise = std::move(promise)](Result &&result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - send_closure(actor_id, &ContactsManager::on_get_support_user, result.move_as_ok(), std::move(promise)); - } - }); - td_->create_handler(std::move(query_promise))->send(); -} - -void ContactsManager::on_get_support_user(UserId user_id, Promise> &&promise) { - TRY_STATUS_PROMISE(promise, G()->close_status()); - - const User *u = get_user(user_id); - if (u == nullptr) { - return promise.set_error(Status::Error(500, "Can't find support user")); - } - if (!u->is_support) { - LOG(ERROR) << "Receive non-support " << user_id << ", but expected a support user"; - } - - support_user_id_ = user_id; - promise.set_value(get_user_object(user_id, u)); -} - void ContactsManager::get_current_state(vector> &updates) const { - for (auto user_id : unknown_users_) { - if (!have_min_user(user_id)) { - updates.push_back(get_update_unknown_user_object(user_id)); - } - } for (auto chat_id : unknown_chats_) { if (!have_chat(chat_id)) { updates.push_back(get_update_unknown_basic_group_object(chat_id)); @@ -16700,15 +8828,7 @@ void ContactsManager::get_current_state(vector &user) { - updates.push_back(get_update_user_object(user_id, user.get())); - }); channels_.foreach([&](const ChannelId &channel_id, const unique_ptr &channel) { updates.push_back(get_update_supergroup_object(channel_id, channel.get())); }); @@ -16716,16 +8836,7 @@ void ContactsManager::get_current_state(vector &chat) { updates.push_back(td_api::make_object(get_basic_group_object_const(chat_id, chat.get()))); }); - // secret chat objects contain user_id, so they must be sent after users - secret_chats_.foreach([&](const SecretChatId &secret_chat_id, const unique_ptr &secret_chat) { - updates.push_back( - td_api::make_object(get_secret_chat_object_const(secret_chat_id, secret_chat.get()))); - }); - users_full_.foreach([&](const UserId &user_id, const unique_ptr &user_full) { - updates.push_back(td_api::make_object( - user_id.get(), get_user_full_info_object(user_id, user_full.get()))); - }); channels_full_.foreach([&](const ChannelId &channel_id, const unique_ptr &channel_full) { updates.push_back(td_api::make_object( channel_id.get(), get_supergroup_full_info_object(channel_id, channel_full.get()))); @@ -16734,10 +8845,6 @@ void ContactsManager::get_current_state(vector( chat_id.get(), get_basic_group_full_info_object(chat_id, chat_full.get()))); }); - - if (!contact_birthdates_.users_.empty()) { - updates.push_back(get_update_contact_close_birthdays()); - } } } // namespace td diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 6d27bb57d..a7f6e75ba 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -8,13 +8,10 @@ #include "td/telegram/AccentColorId.h" #include "td/telegram/AccessRights.h" -#include "td/telegram/Birthdate.h" #include "td/telegram/BotCommand.h" -#include "td/telegram/BotMenuButton.h" #include "td/telegram/ChannelId.h" #include "td/telegram/ChannelType.h" #include "td/telegram/ChatId.h" -#include "td/telegram/Contact.h" #include "td/telegram/CustomEmojiId.h" #include "td/telegram/DialogId.h" #include "td/telegram/DialogInviteLink.h" @@ -23,18 +20,15 @@ #include "td/telegram/EmojiStatus.h" #include "td/telegram/files/FileId.h" #include "td/telegram/files/FileSourceId.h" -#include "td/telegram/FolderId.h" #include "td/telegram/MessageFullId.h" #include "td/telegram/MessageId.h" #include "td/telegram/MessageTtl.h" #include "td/telegram/net/DcId.h" #include "td/telegram/Photo.h" -#include "td/telegram/PremiumGiftOption.h" #include "td/telegram/PublicDialogType.h" #include "td/telegram/QueryCombiner.h" #include "td/telegram/QueryMerger.h" #include "td/telegram/RestrictionReason.h" -#include "td/telegram/SecretChatId.h" #include "td/telegram/StickerSetId.h" #include "td/telegram/StoryId.h" #include "td/telegram/td_api.h" @@ -43,14 +37,11 @@ #include "td/telegram/Usernames.h" #include "td/actor/actor.h" -#include "td/actor/MultiPromise.h" #include "td/actor/MultiTimeout.h" #include "td/utils/common.h" #include "td/utils/FlatHashMap.h" #include "td/utils/FlatHashSet.h" -#include "td/utils/HashTableUtils.h" -#include "td/utils/Hints.h" #include "td/utils/Promise.h" #include "td/utils/Status.h" #include "td/utils/StringBuilder.h" @@ -58,18 +49,11 @@ #include "td/utils/WaitFreeHashMap.h" #include "td/utils/WaitFreeHashSet.h" -#include -#include #include namespace td { struct BinlogEvent; -class BusinessAwayMessage; -class BusinessGreetingMessage; -class BusinessInfo; -class BusinessIntro; -class BusinessWorkHours; struct MinChannel; class Td; @@ -82,160 +66,71 @@ class ContactsManager final : public Actor { ContactsManager &operator=(ContactsManager &&) = delete; ~ContactsManager() final; - static UserId load_my_id(); - - static UserId get_user_id(const tl_object_ptr &user); static ChatId get_chat_id(const tl_object_ptr &chat); static ChannelId get_channel_id(const tl_object_ptr &chat); static DialogId get_dialog_id(const tl_object_ptr &chat); vector get_channel_ids(vector> &&chats, const char *source); - Result> get_input_user(UserId user_id) const; - - tl_object_ptr get_input_user_force(UserId user_id) const; - // TODO get_input_chat ??? tl_object_ptr get_input_channel(ChannelId channel_id) const; - tl_object_ptr get_input_peer_user(UserId user_id, AccessRights access_rights) const; - bool have_input_peer_user(UserId user_id, AccessRights access_rights) const; - tl_object_ptr get_input_peer_chat(ChatId chat_id, AccessRights access_rights) const; bool have_input_peer_chat(ChatId chat_id, AccessRights access_rights) const; + tl_object_ptr get_simple_input_peer(DialogId dialog_id) const; tl_object_ptr get_input_peer_channel(ChannelId channel_id, AccessRights access_rights) const; bool have_input_peer_channel(ChannelId channel_id, AccessRights access_rights) const; - tl_object_ptr get_input_encrypted_chat(SecretChatId secret_chat_id, - AccessRights access_rights) const; - bool have_input_encrypted_peer(SecretChatId secret_chat_id, AccessRights access_rights) const; - - bool is_user_received_from_server(UserId user_id) const; bool is_chat_received_from_server(ChatId chat_id) const; bool is_channel_received_from_server(ChannelId channel_id) const; - const DialogPhoto *get_user_dialog_photo(UserId user_id); const DialogPhoto *get_chat_dialog_photo(ChatId chat_id) const; const DialogPhoto *get_channel_dialog_photo(ChannelId channel_id) const; - const DialogPhoto *get_secret_chat_dialog_photo(SecretChatId secret_chat_id); AccentColorId get_channel_accent_color_id(ChannelId channel_id) const; - int32 get_user_accent_color_id_object(UserId user_id) const; int32 get_chat_accent_color_id_object(ChatId chat_id) const; int32 get_channel_accent_color_id_object(ChannelId channel_id) const; - int32 get_secret_chat_accent_color_id_object(SecretChatId secret_chat_id) const; - CustomEmojiId get_user_background_custom_emoji_id(UserId user_id) const; CustomEmojiId get_chat_background_custom_emoji_id(ChatId chat_id) const; CustomEmojiId get_channel_background_custom_emoji_id(ChannelId channel_id) const; - CustomEmojiId get_secret_chat_background_custom_emoji_id(SecretChatId secret_chat_id) const; - int32 get_user_profile_accent_color_id_object(UserId user_id) const; int32 get_chat_profile_accent_color_id_object(ChatId chat_id) const; int32 get_channel_profile_accent_color_id_object(ChannelId channel_id) const; - int32 get_secret_chat_profile_accent_color_id_object(SecretChatId secret_chat_id) const; - CustomEmojiId get_user_profile_background_custom_emoji_id(UserId user_id) const; CustomEmojiId get_chat_profile_background_custom_emoji_id(ChatId chat_id) const; CustomEmojiId get_channel_profile_background_custom_emoji_id(ChannelId channel_id) const; - CustomEmojiId get_secret_chat_profile_background_custom_emoji_id(SecretChatId secret_chat_id) const; - string get_user_title(UserId user_id) const; string get_chat_title(ChatId chat_id) const; string get_channel_title(ChannelId channel_id) const; - string get_secret_chat_title(SecretChatId secret_chat_id) const; - RestrictedRights get_user_default_permissions(UserId user_id) const; RestrictedRights get_chat_default_permissions(ChatId chat_id) const; RestrictedRights get_channel_default_permissions(ChannelId channel_id) const; - RestrictedRights get_secret_chat_default_permissions(SecretChatId secret_chat_id) const; - td_api::object_ptr get_user_emoji_status_object(UserId user_id) const; td_api::object_ptr get_chat_emoji_status_object(ChatId chat_id) const; td_api::object_ptr get_channel_emoji_status_object(ChannelId channel_id) const; - td_api::object_ptr get_secret_chat_emoji_status_object(SecretChatId secret_chat_id) const; - string get_user_about(UserId user_id); string get_chat_about(ChatId chat_id); string get_channel_about(ChannelId channel_id); - string get_secret_chat_about(SecretChatId secret_chat_id); bool get_chat_has_protected_content(ChatId chat_id) const; bool get_channel_has_protected_content(ChannelId channel_id) const; - bool get_user_stories_hidden(UserId user_id) const; bool get_channel_stories_hidden(ChannelId channel_id) const; - bool can_poll_user_active_stories(UserId user_id) const; bool can_poll_channel_active_stories(ChannelId channel_id) const; bool can_use_premium_custom_emoji_in_channel(ChannelId channel_id) const; - string get_user_private_forward_name(UserId user_id); - - bool get_user_voice_messages_forbidden(UserId user_id) const; - - bool get_user_read_dates_private(UserId user_id); - - string get_user_search_text(UserId user_id) const; - string get_channel_search_text(ChannelId channel_id) const; - void for_each_secret_chat_with_user(UserId user_id, const std::function &f); - - string get_user_first_username(UserId user_id) const; string get_channel_first_username(ChannelId channel_id) const; string get_channel_editable_username(ChannelId channel_id) const; - bool has_user_fragment_username(UserId user_id) const; - - int32 get_secret_chat_date(SecretChatId secret_chat_id) const; - int32 get_secret_chat_ttl(SecretChatId secret_chat_id) const; - UserId get_secret_chat_user_id(SecretChatId secret_chat_id) const; - bool get_secret_chat_is_outbound(SecretChatId secret_chat_id) const; - SecretChatState get_secret_chat_state(SecretChatId secret_chat_id) const; - int32 get_secret_chat_layer(SecretChatId secret_chat_id) const; - FolderId get_secret_chat_initial_folder_id(SecretChatId secret_chat_id) const; - - void can_send_message_to_user(UserId user_id, bool force, - Promise> &&promise); - - void allow_send_message_to_user(UserId user_id); - - void on_imported_contacts(int64 random_id, Result> result); - - void on_deleted_contacts(const vector &deleted_contact_user_ids); - - void on_get_contacts(tl_object_ptr &&new_contacts); - - void on_get_contacts_failed(Status error); - - void on_get_contact_birthdates(telegram_api::object_ptr &&birthdays); - - void on_get_contacts_statuses(vector> &&statuses); - - void reload_contacts(bool force); - - void reload_contact_birthdates(bool force); - - void on_get_user(tl_object_ptr &&user, const char *source); - void on_get_users(vector> &&users, const char *source); - - void on_get_is_premium_required_to_contact_users(vector &&user_ids, vector &&is_premium_required, - Promise &&promise); - - void on_binlog_user_event(BinlogEvent &&event); void on_binlog_chat_event(BinlogEvent &&event); void on_binlog_channel_event(BinlogEvent &&event); - void on_binlog_secret_chat_event(BinlogEvent &&event); - - void on_get_user_full(tl_object_ptr &&user); - - void on_get_user_photos(UserId user_id, int32 offset, int32 limit, int32 total_count, - vector> photos); void on_get_chat(tl_object_ptr &&chat, const char *source); void on_get_chats(vector> &&chats, const char *source); @@ -244,37 +139,6 @@ class ContactsManager final : public Actor { void on_get_chat_full_failed(ChatId chat_id); void on_get_channel_full_failed(ChannelId channel_id); - void on_update_profile_success(int32 flags, const string &first_name, const string &last_name, const string &about); - void on_update_accent_color_success(bool for_profile, AccentColorId accent_color_id, - CustomEmojiId background_custom_emoji_id); - - void on_update_user_name(UserId user_id, string &&first_name, string &&last_name, Usernames &&usernames); - void on_update_user_phone_number(UserId user_id, string &&phone_number); - void on_update_user_emoji_status(UserId user_id, tl_object_ptr &&emoji_status); - void on_update_user_story_ids(UserId user_id, StoryId max_active_story_id, StoryId max_read_story_id); - void on_update_user_max_read_story_id(UserId user_id, StoryId max_read_story_id); - void on_update_user_stories_hidden(UserId user_id, bool stories_hidden); - void on_update_user_online(UserId user_id, tl_object_ptr &&status); - void on_update_user_local_was_online(UserId user_id, int32 local_was_online); - // use on_update_dialog_is_blocked instead - void on_update_user_is_blocked(UserId user_id, bool is_blocked, bool is_blocked_for_stories); - void on_update_user_has_pinned_stories(UserId user_id, bool has_pinned_stories); - void on_update_user_common_chat_count(UserId user_id, int32 common_chat_count); - void on_update_user_location(UserId user_id, DialogLocation &&location); - void on_update_user_work_hours(UserId user_id, BusinessWorkHours &&work_hours); - void on_update_user_away_message(UserId user_id, BusinessAwayMessage &&away_message); - void on_update_user_greeting_message(UserId user_id, BusinessGreetingMessage &&greeting_message); - void on_update_user_intro(UserId user_id, BusinessIntro &&intro); - void on_update_user_need_phone_number_privacy_exception(UserId user_id, bool need_phone_number_privacy_exception); - void on_update_user_wallpaper_overridden(UserId user_id, bool wallpaper_overridden); - void on_update_user_commands(UserId user_id, - vector> &&bot_commands); - - void on_set_profile_photo(UserId user_id, tl_object_ptr &&photo, bool is_fallback, - int64 old_photo_id, Promise &&promise); - - void on_delete_profile_photo(int64 profile_photo_id, Promise promise); - void on_ignored_restriction_reasons_changed(); void on_get_chat_participants(tl_object_ptr &&participants, bool from_update); @@ -313,8 +177,6 @@ class ContactsManager final : public Actor { void on_update_channel_bot_commands(ChannelId channel_id, BotCommands &&bot_commands); void on_update_channel_permanent_invite_link(ChannelId channel_id, const DialogInviteLink &invite_link); - void on_update_bot_menu_button(UserId bot_user_id, tl_object_ptr &&bot_menu_button); - void speculative_add_channel_participants(ChannelId channel_id, const vector &added_user_ids, UserId inviter_user_id, int32 date, bool by_me); @@ -332,53 +194,16 @@ class ContactsManager final : public Actor { void remove_inactive_channel(ChannelId channel_id); - void register_message_users(MessageFullId message_full_id, vector user_ids); - void register_message_channels(MessageFullId message_full_id, vector channel_ids); - void unregister_message_users(MessageFullId message_full_id, vector user_ids); - void unregister_message_channels(MessageFullId message_full_id, vector channel_ids); - UserId get_my_id() const; - - void set_my_online_status(bool is_online, bool send_update, bool is_local); - - struct MyOnlineStatusInfo { - bool is_online_local = false; - bool is_online_remote = false; - int32 was_online_local = 0; - int32 was_online_remote = 0; - }; - - MyOnlineStatusInfo get_my_online_status() const; - - static UserId get_service_notifications_user_id(); - - UserId add_service_notifications_user(); - - static UserId get_replies_bot_user_id(); - - static UserId get_anonymous_bot_user_id(); - - static UserId get_channel_bot_user_id(); - - static UserId get_anti_spam_bot_user_id(); - - UserId add_anonymous_bot_user(); - - UserId add_channel_bot_user(); - static ChannelId get_unsupported_channel_id(); void update_chat_online_member_count(ChatId chat_id, bool is_from_server); void on_update_channel_bot_user_ids(ChannelId channel_id, vector &&bot_user_ids); - void on_update_username_is_active(UserId user_id, string &&username, bool is_active, Promise &&promise); - - void on_update_active_usernames_order(UserId user_id, vector &&usernames, Promise &&promise); - void on_update_channel_username_is_active(ChannelId channel_id, string &&username, bool is_active, Promise &&promise); @@ -387,89 +212,6 @@ class ContactsManager final : public Actor { void on_update_channel_active_usernames_order(ChannelId channel_id, vector &&usernames, Promise &&promise); - void on_update_online_status_privacy(); - - void on_update_phone_number_privacy(); - - void invalidate_user_full(UserId user_id); - - void add_contact(Contact contact, bool share_phone_number, Promise &&promise); - - std::pair, vector> import_contacts(const vector &contacts, int64 &random_id, - Promise &&promise); - - std::pair> search_contacts(const string &query, int32 limit, Promise &&promise); - - void remove_contacts(const vector &user_ids, Promise &&promise); - - void remove_contacts_by_phone_number(vector user_phone_numbers, vector user_ids, - Promise &&promise); - - int32 get_imported_contact_count(Promise &&promise); - - std::pair, vector> change_imported_contacts(vector &contacts, int64 &random_id, - Promise &&promise); - - void clear_imported_contacts(Promise &&promise); - - void on_update_contacts_reset(); - - vector get_close_friends(Promise &&promise); - - void set_close_friends(vector user_ids, Promise &&promise); - - void on_set_close_friends(const vector &user_ids, Promise &&promise); - - UserId search_user_by_phone_number(string phone_number, Promise &&promise); - - void on_resolved_phone_number(const string &phone_number, UserId user_id); - - void share_phone_number(UserId user_id, Promise &&promise); - - void register_suggested_profile_photo(const Photo &photo); - - FileId get_profile_photo_file_id(int64 photo_id) const; - - void set_bot_profile_photo(UserId bot_user_id, const td_api::object_ptr &input_photo, - Promise &&promise); - - void set_profile_photo(const td_api::object_ptr &input_photo, bool is_fallback, - Promise &&promise); - - void set_user_profile_photo(UserId user_id, const td_api::object_ptr &input_photo, - bool only_suggest, Promise &&promise); - - void send_update_profile_photo_query(UserId user_id, FileId file_id, int64 old_photo_id, bool is_fallback, - Promise &&promise); - - void delete_profile_photo(int64 profile_photo_id, bool is_recursive, Promise &&promise); - - void set_accent_color(AccentColorId accent_color_id, CustomEmojiId background_custom_emoji_id, - Promise &&promise); - - void set_profile_accent_color(AccentColorId accent_color_id, CustomEmojiId background_custom_emoji_id, - Promise &&promise); - - void set_name(const string &first_name, const string &last_name, Promise &&promise); - - void set_bio(const string &bio, Promise &&promise); - - void set_username(const string &username, Promise &&promise); - - void toggle_username_is_active(string &&username, bool is_active, Promise &&promise); - - void reorder_usernames(vector &&usernames, Promise &&promise); - - void toggle_bot_username_is_active(UserId bot_user_id, string &&username, bool is_active, Promise &&promise); - - void reorder_bot_usernames(UserId bot_user_id, vector &&usernames, Promise &&promise); - - void set_birthdate(Birthdate &&birthdate, Promise &&promise); - - void set_personal_channel(DialogId dialog_id, Promise &&promise); - - void set_emoji_status(const EmojiStatus &emoji_status, Promise &&promise); - void set_chat_description(ChatId chat_id, const string &description, Promise &&promise); void set_channel_username(ChannelId channel_id, const string &username, Promise &&promise); @@ -549,53 +291,6 @@ class ContactsManager final : public Actor { vector get_inactive_channels(Promise &&promise); - bool is_user_contact(UserId user_id, bool is_mutual = false) const; - - bool is_user_premium(UserId user_id) const; - - bool is_user_deleted(UserId user_id) const; - - bool is_user_support(UserId user_id) const; - - bool is_user_bot(UserId user_id) const; - - struct BotData { - string username; - bool can_be_edited; - bool can_join_groups; - bool can_read_all_group_messages; - bool is_inline; - bool is_business; - bool need_location; - bool can_be_added_to_attach_menu; - }; - Result get_bot_data(UserId user_id) const TD_WARN_UNUSED_RESULT; - - bool is_user_online(UserId user_id, int32 tolerance = 0, int32 unix_time = 0) const; - - int32 get_user_was_online(UserId user_id, int32 unix_time = 0) const; - - bool is_user_status_exact(UserId user_id) const; - - bool can_report_user(UserId user_id) const; - - bool have_user(UserId user_id) const; - bool have_min_user(UserId user_id) const; - bool have_user_force(UserId user_id, const char *source); - - static void send_get_me_query(Td *td, Promise &&promise); - UserId get_me(Promise &&promise); - bool get_user(UserId user_id, int left_tries, Promise &&promise); - void reload_user(UserId user_id, Promise &&promise, const char *source); - void load_user_full(UserId user_id, bool force, Promise &&promise, const char *source); - FileSourceId get_user_full_file_source_id(UserId user_id); - void reload_user_full(UserId user_id, Promise &&promise, const char *source); - - void get_user_profile_photos(UserId user_id, int32 offset, int32 limit, - Promise> &&promise); - void reload_user_profile_photo(UserId user_id, int64 photo_id, Promise &&promise); - FileSourceId get_user_profile_photo_file_source_id(UserId user_id, int64 photo_id); - void create_new_chat(const vector &user_ids, const string &title, MessageTtl message_ttl, Promise> &&promise); @@ -635,13 +330,6 @@ class ContactsManager final : public Actor { bool is_channel_public(ChannelId channel_id) const; - void create_new_secret_chat(UserId user_id, Promise> &&promise); - - bool have_secret_chat(SecretChatId secret_chat_id) const; - bool have_secret_chat_force(SecretChatId secret_chat_id, const char *source); - bool get_secret_chat(SecretChatId secret_chat_id, bool force, Promise &&promise); - bool get_secret_chat_full(SecretChatId secret_chat_id, Promise &&promise); - ChannelType get_channel_type(ChannelId channel_id) const; bool is_broadcast_channel(ChannelId channel_id) const; bool is_megagroup_channel(ChannelId channel_id) const; @@ -667,16 +355,6 @@ class ContactsManager final : public Actor { void speculative_add_channel_user(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &new_status, const DialogParticipantStatus &old_status); - int64 get_user_id_object(UserId user_id, const char *source) const; - - tl_object_ptr get_user_object(UserId user_id) const; - - vector get_user_ids_object(const vector &user_ids, const char *source) const; - - tl_object_ptr get_users_object(int32 total_count, const vector &user_ids) const; - - tl_object_ptr get_user_full_info_object(UserId user_id) const; - int64 get_basic_group_id_object(ChatId chat_id, const char *source) const; tl_object_ptr get_basic_group_object(ChatId chat_id); @@ -689,181 +367,14 @@ class ContactsManager final : public Actor { tl_object_ptr get_supergroup_full_info_object(ChannelId channel_id) const; - int32 get_secret_chat_id_object(SecretChatId secret_chat_id, const char *source) const; - - tl_object_ptr get_secret_chat_object(SecretChatId secret_chat_id); - - void on_update_secret_chat(SecretChatId secret_chat_id, int64 access_hash, UserId user_id, SecretChatState state, - bool is_outbound, int32 ttl, int32 date, string key_hash, int32 layer, - FolderId initial_folder_id); - tl_object_ptr get_chat_member_object(const DialogParticipant &dialog_participant, const char *source) const; - void get_support_user(Promise> &&promise); - void repair_chat_participants(ChatId chat_id); void get_current_state(vector> &updates) const; private: - struct User { - string first_name; - string last_name; - Usernames usernames; - string phone_number; - int64 access_hash = -1; - EmojiStatus emoji_status; - EmojiStatus last_sent_emoji_status; - - ProfilePhoto photo; - - vector restriction_reasons; - string inline_query_placeholder; - int32 bot_info_version = -1; - - AccentColorId accent_color_id; - CustomEmojiId background_custom_emoji_id; - AccentColorId profile_accent_color_id; - CustomEmojiId profile_background_custom_emoji_id; - - int32 was_online = 0; - int32 local_was_online = 0; - - double max_active_story_id_next_reload_time = 0.0; - StoryId max_active_story_id; - StoryId max_read_story_id; - - string language_code; - - FlatHashSet photo_ids; - - static constexpr uint32 CACHE_VERSION = 4; - uint32 cache_version = 0; - - bool is_min_access_hash = true; - bool is_received = false; - bool is_verified = false; - bool is_premium = false; - bool is_support = false; - bool is_deleted = true; - bool is_bot = true; - bool can_join_groups = true; - bool can_read_all_group_messages = true; - bool can_be_edited_bot = false; - bool is_inline_bot = false; - bool is_business_bot = false; - bool need_location_bot = false; - bool is_scam = false; - bool is_fake = false; - bool is_contact = false; - bool is_mutual_contact = false; - bool is_close_friend = false; - bool need_apply_min_photo = false; - bool can_be_added_to_attach_menu = false; - bool attach_menu_enabled = false; - bool stories_hidden = false; - bool contact_require_premium = false; - - bool is_photo_inited = false; - - bool is_repaired = false; // whether cached value is rechecked - - bool is_name_changed = true; - bool is_username_changed = true; - bool is_photo_changed = true; - bool is_accent_color_changed = true; - bool is_phone_number_changed = true; - bool is_emoji_status_changed = true; - bool is_is_contact_changed = true; - bool is_is_mutual_contact_changed = true; - bool is_is_deleted_changed = true; - bool is_is_premium_changed = true; - bool is_stories_hidden_changed = true; - bool is_full_info_changed = false; - bool is_being_updated = false; - bool is_changed = true; // have new changes that need to be sent to the client and database - bool need_save_to_database = true; // have new changes that need only to be saved to the database - bool is_status_changed = true; - bool is_online_status_changed = true; // whether online/offline has changed - bool is_update_user_sent = false; - - bool is_saved = false; // is current user version being saved/is saved to the database - bool is_being_saved = false; // is current user being saved to the database - bool is_status_saved = false; // is current user status being saved/is saved to the database - - bool is_received_from_server = false; // true, if the user was received from the server and not the database - - uint64 log_event_id = 0; - - template - void store(StorerT &storer) const; - - template - void parse(ParserT &parser); - }; - - // do not forget to update drop_user_full and on_get_user_full - struct UserFull { - Photo photo; - Photo fallback_photo; - Photo personal_photo; - - string about; - string private_forward_name; - string description; - Photo description_photo; - FileId description_animation_file_id; - vector registered_file_ids; - FileSourceId file_source_id; - - vector premium_gift_options; - - unique_ptr menu_button; - vector commands; - AdministratorRights group_administrator_rights; - AdministratorRights broadcast_administrator_rights; - - int32 common_chat_count = 0; - Birthdate birthdate; - - ChannelId personal_channel_id; - - unique_ptr business_info; - - bool is_blocked = false; - bool is_blocked_for_stories = false; - bool can_be_called = false; - bool supports_video_calls = false; - bool has_private_calls = false; - bool can_pin_messages = true; - bool need_phone_number_privacy_exception = false; - bool wallpaper_overridden = false; - bool voice_messages_forbidden = false; - bool has_pinned_stories = false; - bool read_dates_private = false; - bool contact_require_premium = false; - - bool is_common_chat_count_changed = true; - bool is_being_updated = false; - bool is_changed = true; // have new changes that need to be sent to the client and database - bool need_send_update = true; // have new changes that need only to be sent to the client - bool need_save_to_database = true; // have new changes that need only to be saved to the database - bool is_update_user_full_sent = false; - - double expires_at = 0.0; - - bool is_expired() const { - return expires_at < Time::now(); - } - - template - void store(StorerT &storer) const; - - template - void parse(ParserT &parser); - }; - struct Chat { string title; DialogPhoto photo; @@ -1088,98 +599,14 @@ class ContactsManager final : public Actor { template void parse(ParserT &parser); }; - - struct SecretChat { - int64 access_hash = 0; - UserId user_id; - SecretChatState state = SecretChatState::Unknown; - string key_hash; - int32 ttl = 0; - int32 date = 0; - int32 layer = 0; - FolderId initial_folder_id; - - bool is_outbound = false; - - bool is_ttl_changed = true; - bool is_state_changed = true; - bool is_being_updated = false; - bool is_changed = true; // have new changes that need to be sent to the client and database - bool need_save_to_database = true; // have new changes that need only to be saved to the database - - bool is_saved = false; // is current secret chat version being saved/is saved to the database - bool is_being_saved = false; // is current secret chat being saved to the database - - uint64 log_event_id = 0; - - template - void store(StorerT &storer) const; - - template - void parse(ParserT &parser); - }; - - struct PendingGetPhotoRequest { - int32 offset = 0; - int32 limit = 0; - int32 retry_count = 0; - Promise> promise; - }; - - struct UserPhotos { - vector photos; - int32 count = -1; - int32 offset = -1; - - vector pending_requests; - }; - - class UserLogEvent; class ChatLogEvent; class ChannelLogEvent; - class SecretChatLogEvent; - static constexpr int32 MAX_GET_PROFILE_PHOTOS = 100; // server side limit - static constexpr size_t MAX_NAME_LENGTH = 64; // server side limit for first/last name static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for chat title static constexpr size_t MAX_DESCRIPTION_LENGTH = 255; // server side limit for chat/channel description static constexpr int32 MAX_ACTIVE_STORY_ID_RELOAD_TIME = 3600; // some reasonable limit - // the True fields aren't set for manually created telegram_api::user objects, therefore the flags must be used - static constexpr int32 USER_FLAG_HAS_ACCESS_HASH = 1 << 0; - static constexpr int32 USER_FLAG_HAS_FIRST_NAME = 1 << 1; - static constexpr int32 USER_FLAG_HAS_LAST_NAME = 1 << 2; - static constexpr int32 USER_FLAG_HAS_USERNAME = 1 << 3; - static constexpr int32 USER_FLAG_HAS_PHONE_NUMBER = 1 << 4; - static constexpr int32 USER_FLAG_HAS_PHOTO = 1 << 5; - static constexpr int32 USER_FLAG_HAS_STATUS = 1 << 6; - static constexpr int32 USER_FLAG_HAS_BOT_INFO_VERSION = 1 << 14; - static constexpr int32 USER_FLAG_IS_ME = 1 << 10; - static constexpr int32 USER_FLAG_IS_CONTACT = 1 << 11; - static constexpr int32 USER_FLAG_IS_MUTUAL_CONTACT = 1 << 12; - static constexpr int32 USER_FLAG_IS_DELETED = 1 << 13; - static constexpr int32 USER_FLAG_IS_BOT = 1 << 14; - static constexpr int32 USER_FLAG_IS_BOT_WITH_PRIVACY_DISABLED = 1 << 15; - static constexpr int32 USER_FLAG_IS_PRIVATE_BOT = 1 << 16; - static constexpr int32 USER_FLAG_IS_VERIFIED = 1 << 17; - static constexpr int32 USER_FLAG_IS_RESTRICTED = 1 << 18; - static constexpr int32 USER_FLAG_IS_INLINE_BOT = 1 << 19; - static constexpr int32 USER_FLAG_IS_INACCESSIBLE = 1 << 20; - static constexpr int32 USER_FLAG_NEED_LOCATION_BOT = 1 << 21; - static constexpr int32 USER_FLAG_HAS_LANGUAGE_CODE = 1 << 22; - static constexpr int32 USER_FLAG_IS_SUPPORT = 1 << 23; - static constexpr int32 USER_FLAG_IS_SCAM = 1 << 24; - static constexpr int32 USER_FLAG_NEED_APPLY_MIN_PHOTO = 1 << 25; - static constexpr int32 USER_FLAG_IS_FAKE = 1 << 26; - static constexpr int32 USER_FLAG_IS_ATTACH_MENU_BOT = 1 << 27; - static constexpr int32 USER_FLAG_IS_PREMIUM = 1 << 28; - static constexpr int32 USER_FLAG_ATTACH_MENU_ENABLED = 1 << 29; - static constexpr int32 USER_FLAG_HAS_EMOJI_STATUS = 1 << 30; - static constexpr int32 USER_FLAG_HAS_USERNAMES = 1 << 0; - static constexpr int32 USER_FLAG_CAN_BE_EDITED_BOT = 1 << 1; - static constexpr int32 USER_FLAG_IS_CLOSE_FRIEND = 1 << 2; - static constexpr int32 CHAT_FLAG_USER_IS_CREATOR = 1 << 0; static constexpr int32 CHAT_FLAG_USER_HAS_LEFT = 1 << 2; // static constexpr int32 CHAT_FLAG_ADMINISTRATORS_ENABLED = 1 << 3; @@ -1219,36 +646,12 @@ class ContactsManager final : public Actor { static constexpr int32 CHANNEL_FLAG_IS_FORUM = 1 << 30; static constexpr int32 CHANNEL_FLAG_HAS_USERNAMES = 1 << 0; - static constexpr int32 USER_FULL_EXPIRE_TIME = 60; static constexpr int32 CHANNEL_FULL_EXPIRE_TIME = 60; - static constexpr int32 ACCOUNT_UPDATE_FIRST_NAME = 1 << 0; - static constexpr int32 ACCOUNT_UPDATE_LAST_NAME = 1 << 1; - static constexpr int32 ACCOUNT_UPDATE_ABOUT = 1 << 2; - - bool have_input_peer_user(const User *u, UserId user_id, AccessRights access_rights) const; static bool have_input_peer_chat(const Chat *c, AccessRights access_rights); + bool have_input_peer_channel(const Channel *c, ChannelId channel_id, AccessRights access_rights, bool from_linked = false) const; - static bool have_input_encrypted_peer(const SecretChat *secret_chat, AccessRights access_rights); - - tl_object_ptr get_simple_input_peer(DialogId dialog_id) const; - - const User *get_user(UserId user_id) const; - User *get_user(UserId user_id); - User *get_user_force(UserId user_id, const char *source); - User *get_user_force_impl(UserId user_id, const char *source); - - User *add_user(UserId user_id); - - const UserFull *get_user_full(UserId user_id) const; - UserFull *get_user_full(UserId user_id); - UserFull *get_user_full_force(UserId user_id, const char *source); - - UserFull *add_user_full(UserId user_id); - - void send_get_user_full_query(UserId user_id, tl_object_ptr &&input_user, - Promise &&promise, const char *source); const Chat *get_chat(ChatId chat_id) const; Chat *get_chat(ChatId chat_id); @@ -1280,16 +683,6 @@ class ContactsManager final : public Actor { void send_get_channel_full_query(ChannelFull *channel_full, ChannelId channel_id, Promise &&promise, const char *source); - void on_create_new_secret_chat(SecretChatId secret_chat_id, Promise> &&promise); - - const SecretChat *get_secret_chat(SecretChatId secret_chat_id) const; - SecretChat *get_secret_chat(SecretChatId secret_chat_id); - SecretChat *get_secret_chat_force(SecretChatId secret_chat_id, const char *source); - - SecretChat *add_secret_chat(SecretChatId secret_chat_id); - - static string get_user_search_text(const User *u); - static DialogParticipantStatus get_chat_status(const Chat *c); DialogParticipantStatus get_chat_permissions(const Chat *c) const; @@ -1302,78 +695,6 @@ class ContactsManager final : public Actor { static bool get_channel_join_to_send(const Channel *c); static bool get_channel_join_request(const Channel *c); - void set_my_id(UserId my_id); - - void on_set_birthdate(Birthdate birthdate, Promise &&promise); - - void on_set_personal_channel(ChannelId channel_id, Promise &&promise); - - void on_set_emoji_status(EmojiStatus emoji_status, Promise &&promise); - - void on_update_user_name(User *u, UserId user_id, string &&first_name, string &&last_name); - void on_update_user_usernames(User *u, UserId user_id, Usernames &&usernames); - void on_update_user_phone_number(User *u, UserId user_id, string &&phone_number); - void on_update_user_photo(User *u, UserId user_id, tl_object_ptr &&photo, - const char *source); - void on_update_user_accent_color_id(User *u, UserId user_id, AccentColorId accent_color_id); - void on_update_user_background_custom_emoji_id(User *u, UserId user_id, CustomEmojiId background_custom_emoji_id); - void on_update_user_profile_accent_color_id(User *u, UserId user_id, AccentColorId accent_color_id); - void on_update_user_profile_background_custom_emoji_id(User *u, UserId user_id, - CustomEmojiId background_custom_emoji_id); - void on_update_user_emoji_status(User *u, UserId user_id, EmojiStatus emoji_status); - void on_update_user_story_ids_impl(User *u, UserId user_id, StoryId max_active_story_id, StoryId max_read_story_id); - void on_update_user_max_read_story_id(User *u, UserId user_id, StoryId max_read_story_id); - void on_update_user_stories_hidden(User *u, UserId user_id, bool stories_hidden); - void on_update_user_is_contact(User *u, UserId user_id, bool is_contact, bool is_mutual_contact, - bool is_close_friend); - void on_update_user_online(User *u, UserId user_id, tl_object_ptr &&status); - void on_update_user_local_was_online(User *u, UserId user_id, int32 local_was_online); - - void do_update_user_photo(User *u, UserId user_id, tl_object_ptr &&photo, - const char *source); - void do_update_user_photo(User *u, UserId user_id, ProfilePhoto &&new_photo, bool invalidate_photo_cache, - const char *source); - void apply_pending_user_photo(User *u, UserId user_id); - - void set_profile_photo_impl(UserId user_id, const td_api::object_ptr &input_photo, - bool is_fallback, bool only_suggest, Promise &&promise); - - void upload_profile_photo(UserId user_id, FileId file_id, bool is_fallback, bool only_suggest, bool is_animation, - double main_frame_timestamp, Promise &&promise, int reupload_count = 0, - vector bad_parts = {}); - - void on_upload_profile_photo(FileId file_id, tl_object_ptr input_file); - void on_upload_profile_photo_error(FileId file_id, Status status); - - void register_user_photo(User *u, UserId user_id, const Photo &photo); - - static void on_update_user_full_is_blocked(UserFull *user_full, UserId user_id, bool is_blocked, - bool is_blocked_for_stories); - static void on_update_user_full_common_chat_count(UserFull *user_full, UserId user_id, int32 common_chat_count); - static void on_update_user_full_location(UserFull *user_full, UserId user_id, DialogLocation &&location); - static void on_update_user_full_work_hours(UserFull *user_full, UserId user_id, BusinessWorkHours &&work_hours); - void on_update_user_full_away_message(UserFull *user_full, UserId user_id, BusinessAwayMessage &&away_message) const; - void on_update_user_full_greeting_message(UserFull *user_full, UserId user_id, - BusinessGreetingMessage &&greeting_message) const; - static void on_update_user_full_intro(UserFull *user_full, UserId user_id, BusinessIntro &&intro); - static void on_update_user_full_commands(UserFull *user_full, UserId user_id, - vector> &&bot_commands); - static void on_update_user_full_menu_button(UserFull *user_full, UserId user_id, - tl_object_ptr &&bot_menu_button); - void on_update_user_full_need_phone_number_privacy_exception(UserFull *user_full, UserId user_id, - bool need_phone_number_privacy_exception) const; - void on_update_user_full_wallpaper_overridden(UserFull *user_full, UserId user_id, bool wallpaper_overridden) const; - - UserPhotos *add_user_photos(UserId user_id); - void send_get_user_photos_query(UserId user_id, const UserPhotos *user_photos); - void on_get_user_profile_photos(UserId user_id, Result &&result); - int64 get_user_full_profile_photo_id(const UserFull *user_full); - void add_set_profile_photo_to_cache(UserId user_id, Photo &&photo, bool is_fallback); - bool delete_my_profile_photo_from_cache(int64 profile_photo_id); - void drop_user_full_photos(UserFull *user_full, UserId user_id, int64 expected_photo_id, const char *source); - void drop_user_photos(UserId user_id, bool is_empty, const char *source); - void drop_user_full(UserId user_id); - void on_update_chat_status(Chat *c, ChatId chat_id, DialogParticipantStatus status); static void on_update_chat_default_permissions(Chat *c, ChatId chat_id, RestrictedRights default_permissions, int32 version); @@ -1429,10 +750,6 @@ class ContactsManager final : public Actor { static void on_update_channel_full_bot_user_ids(ChannelFull *channel_full, ChannelId channel_id, vector &&bot_user_ids); - void toggle_username_is_active_impl(string &&username, bool is_active, Promise &&promise); - - void reorder_usernames_impl(vector &&usernames, Promise &&promise); - void on_channel_status_changed(Channel *c, ChannelId channel_id, const DialogParticipantStatus &old_status, const DialogParticipantStatus &new_status); void on_channel_usernames_changed(const Channel *c, ChannelId channel_id, const Usernames &old_usernames, @@ -1457,16 +774,6 @@ class ContactsManager final : public Actor { void on_get_channel(telegram_api::channel &channel, const char *source); void on_get_channel_forbidden(telegram_api::channelForbidden &channel, const char *source); - void save_user(User *u, UserId user_id, bool from_binlog); - static string get_user_database_key(UserId user_id); - static string get_user_database_value(const User *u); - void save_user_to_database(User *u, UserId user_id); - void save_user_to_database_impl(User *u, UserId user_id, string value); - void on_save_user_to_database(UserId user_id, bool success); - void load_user_from_database(User *u, UserId user_id, Promise promise); - void load_user_from_database_impl(UserId user_id, Promise promise); - void on_load_user_from_database(UserId user_id, string value, bool force); - void save_chat(Chat *c, ChatId chat_id, bool from_binlog); static string get_chat_database_key(ChatId chat_id); static string get_chat_database_value(const Chat *c); @@ -1487,21 +794,6 @@ class ContactsManager final : public Actor { void load_channel_from_database_impl(ChannelId channel_id, Promise promise); void on_load_channel_from_database(ChannelId channel_id, string value, bool force); - void save_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog); - static string get_secret_chat_database_key(SecretChatId secret_chat_id); - static string get_secret_chat_database_value(const SecretChat *c); - void save_secret_chat_to_database(SecretChat *c, SecretChatId secret_chat_id); - void save_secret_chat_to_database_impl(SecretChat *c, SecretChatId secret_chat_id, string value); - void on_save_secret_chat_to_database(SecretChatId secret_chat_id, bool success); - void load_secret_chat_from_database(SecretChat *c, SecretChatId secret_chat_id, Promise promise); - void load_secret_chat_from_database_impl(SecretChatId secret_chat_id, Promise promise); - void on_load_secret_chat_from_database(SecretChatId secret_chat_id, string value, bool force); - - static void save_user_full(const UserFull *user_full, UserId user_id); - static string get_user_full_database_key(UserId user_id); - static string get_user_full_database_value(const UserFull *user_full); - void on_load_user_full_from_database(UserId user_id, string value); - static void save_chat_full(const ChatFull *chat_full, ChatId chat_id); static string get_chat_full_database_key(ChatId chat_id); static string get_chat_full_database_value(const ChatFull *chat_full); @@ -1512,59 +804,15 @@ class ContactsManager final : public Actor { static string get_channel_full_database_value(const ChannelFull *channel_full); void on_load_channel_full_from_database(ChannelId channel_id, string value, const char *source); - void update_user(User *u, UserId user_id, bool from_binlog = false, bool from_database = false); void update_chat(Chat *c, ChatId chat_id, bool from_binlog = false, bool from_database = false); void update_channel(Channel *c, ChannelId channel_id, bool from_binlog = false, bool from_database = false); - void update_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog = false, - bool from_database = false); - void update_user_full(UserFull *user_full, UserId user_id, const char *source, bool from_database = false); void update_chat_full(ChatFull *chat_full, ChatId chat_id, const char *source, bool from_database = false); void update_channel_full(ChannelFull *channel_full, ChannelId channel_id, const char *source, bool from_database = false); bool is_chat_full_outdated(const ChatFull *chat_full, const Chat *c, ChatId chat_id, bool only_participants) const; - bool is_user_contact(const User *u, UserId user_id, bool is_mutual) const; - - static bool is_user_premium(const User *u); - - static bool is_user_deleted(const User *u); - - static bool is_user_support(const User *u); - - static bool is_user_bot(const User *u); - - int32 get_user_was_online(const User *u, UserId user_id, int32 unix_time) const; - - int64 get_contacts_hash(); - - void update_contacts_hints(const User *u, UserId user_id, bool from_database); - - void save_next_contacts_sync_date(); - - void save_contacts_to_database(); - - void load_contacts(Promise &&promise); - - void on_load_contacts_from_database(string value); - - void on_get_contacts_finished(size_t expected_contact_count); - - void do_import_contacts(vector contacts, int64 random_id, Promise &&promise); - - void on_import_contacts_finished(int64 random_id, vector imported_contact_user_ids, - vector unimported_contact_invites); - - void load_imported_contacts(Promise &&promise); - - void on_load_imported_contacts_from_database(string value); - - void on_load_imported_contacts_finished(); - - void on_clear_imported_contacts(vector &&contacts, vector contacts_unique_id, - std::pair, vector> &&to_add, Promise &&promise); - static bool is_channel_public(const Channel *c); static bool is_suitable_created_public_channel(PublicDialogType type, const Channel *c); @@ -1582,29 +830,10 @@ class ContactsManager final : public Actor { bool update_permanent_invite_link(DialogInviteLink &invite_link, DialogInviteLink new_invite_link); - vector get_bot_commands(vector> &&bot_infos, - const vector *participants); - static const DialogParticipant *get_chat_full_participant(const ChatFull *chat_full, DialogId dialog_id); void finish_get_chat_participant(ChatId chat_id, UserId user_id, Promise &&promise); - bool need_poll_user_active_stories(const User *u, UserId user_id) const; - - static bool get_user_has_unread_stories(const User *u); - - td_api::object_ptr get_update_contact_close_birthdays() const; - - td_api::object_ptr get_update_user_object(UserId user_id, const User *u) const; - - td_api::object_ptr get_update_unknown_user_object(UserId user_id) const; - - td_api::object_ptr get_user_status_object(UserId user_id, const User *u, int32 unix_time) const; - - tl_object_ptr get_user_object(UserId user_id, const User *u) const; - - tl_object_ptr get_user_full_info_object(UserId user_id, const UserFull *user_full) const; - td_api::object_ptr get_update_basic_group_object(ChatId chat_id, const Chat *c); static td_api::object_ptr get_update_unknown_basic_group_object(ChatId chat_id); @@ -1638,19 +867,6 @@ class ContactsManager final : public Actor { tl_object_ptr get_supergroup_full_info_object(ChannelId channel_id, const ChannelFull *channel_full) const; - static tl_object_ptr get_secret_chat_state_object(SecretChatState state); - - td_api::object_ptr get_update_secret_chat_object(SecretChatId secret_chat_id, - const SecretChat *secret_chat); - - static td_api::object_ptr get_update_unknown_secret_chat_object( - SecretChatId secret_chat_id); - - tl_object_ptr get_secret_chat_object(SecretChatId secret_chat_id, const SecretChat *secret_chat); - - tl_object_ptr get_secret_chat_object_const(SecretChatId secret_chat_id, - const SecretChat *secret_chat) const; - vector get_dialog_ids(vector> &&chats, const char *source); void on_create_inactive_channels(vector &&channel_ids, Promise &&promise); @@ -1659,22 +875,12 @@ class ContactsManager final : public Actor { void get_channel_statistics_dc_id_impl(ChannelId channel_id, bool for_full_statistics, Promise &&promise); - void on_get_support_user(UserId user_id, Promise> &&promise); - - static void on_user_online_timeout_callback(void *contacts_manager_ptr, int64 user_id_long); - - static void on_user_emoji_status_timeout_callback(void *contacts_manager_ptr, int64 user_id_long); - static void on_channel_emoji_status_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long); static void on_channel_unban_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long); static void on_slow_mode_delay_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long); - void on_user_online_timeout(UserId user_id); - - void on_user_emoji_status_timeout(UserId user_id); - void on_channel_emoji_status_timeout(ChannelId channel_id); void on_channel_unban_timeout(ChannelId channel_id); @@ -1685,23 +891,6 @@ class ContactsManager final : public Actor { Td *td_; ActorShared<> parent_; - UserId my_id_; - UserId support_user_id_; - int32 my_was_online_local_ = 0; - - WaitFreeHashMap, UserIdHash> users_; - WaitFreeHashMap, UserIdHash> users_full_; - WaitFreeHashMap, UserIdHash> user_photos_; - mutable FlatHashSet unknown_users_; - WaitFreeHashMap, UserIdHash> pending_user_photos_; - struct UserIdPhotoIdHash { - uint32 operator()(const std::pair &pair) const { - return combine_hashes(UserIdHash()(pair.first), Hash()(pair.second)); - } - }; - WaitFreeHashMap, FileSourceId, UserIdPhotoIdHash> user_profile_photo_file_source_ids_; - FlatHashMap my_photo_file_id_; - WaitFreeHashMap user_full_file_source_ids_; WaitFreeHashMap, ChatIdHash> chats_; WaitFreeHashMap, ChatIdHash> chats_full_; @@ -1715,11 +904,6 @@ class ContactsManager final : public Actor { WaitFreeHashSet invalidated_channels_full_; WaitFreeHashMap channel_full_file_source_ids_; - WaitFreeHashMap, SecretChatIdHash> secret_chats_; - mutable FlatHashSet unknown_secret_chats_; - - FlatHashMap, UserIdHash> secret_chats_with_user_; - bool created_public_channels_inited_[3] = {false, false, false}; vector created_public_channels_[3]; vector>> get_created_public_channels_queries_[3]; @@ -1730,10 +914,6 @@ class ContactsManager final : public Actor { bool inactive_channel_ids_inited_ = false; vector inactive_channel_ids_; - FlatHashMap>, UserIdHash> load_user_from_database_queries_; - FlatHashSet loaded_from_database_users_; - FlatHashSet unavailable_user_fulls_; - FlatHashMap>, ChatIdHash> load_chat_from_database_queries_; FlatHashSet loaded_from_database_chats_; FlatHashSet unavailable_chat_fulls_; @@ -1742,98 +922,17 @@ class ContactsManager final : public Actor { FlatHashSet loaded_from_database_channels_; FlatHashSet unavailable_channel_fulls_; - FlatHashMap>, SecretChatIdHash> load_secret_chat_from_database_queries_; - FlatHashSet loaded_from_database_secret_chats_; - - QueryMerger get_user_queries_{"GetUserMerger", 3, 50}; QueryMerger get_chat_queries_{"GetChatMerger", 3, 50}; QueryMerger get_channel_queries_{"GetChannelMerger", 100, 1}; // can't merge getChannel queries without access hash - QueryMerger get_is_premium_required_to_contact_queries_{"GetIsPremiumRequiredToContactMerger", 3, 100}; - - QueryCombiner get_user_full_queries_{"GetUserFullCombiner", 2.0}; QueryCombiner get_chat_full_queries_{"GetChatFullCombiner", 2.0}; - class UploadProfilePhotoCallback; - std::shared_ptr upload_profile_photo_callback_; - - struct UploadedProfilePhoto { - UserId user_id; - bool is_fallback; - bool only_suggest; - double main_frame_timestamp; - bool is_animation; - int reupload_count; - Promise promise; - - UploadedProfilePhoto(UserId user_id, bool is_fallback, bool only_suggest, double main_frame_timestamp, - bool is_animation, int32 reupload_count, Promise promise) - : user_id(user_id) - , is_fallback(is_fallback) - , only_suggest(only_suggest) - , main_frame_timestamp(main_frame_timestamp) - , is_animation(is_animation) - , reupload_count(reupload_count) - , promise(std::move(promise)) { - } - }; - FlatHashMap uploaded_profile_photos_; - - struct ImportContactsTask { - Promise promise_; - vector input_contacts_; - vector imported_user_ids_; - vector unimported_contact_invites_; - }; - FlatHashMap> import_contact_tasks_; - - FlatHashMap, vector>> imported_contacts_; - - FlatHashMap resolved_phone_numbers_; - - FlatHashMap, UserIdHash> user_messages_; FlatHashMap, ChannelIdHash> channel_messages_; - bool are_contacts_loaded_ = false; - int32 next_contacts_sync_date_ = 0; - Hints contacts_hints_; // search contacts by first name, last name and usernames - vector> load_contacts_queries_; - MultiPromiseActor load_contact_users_multipromise_{"LoadContactUsersMultiPromiseActor"}; - int32 saved_contact_count_ = -1; - - int32 was_online_local_ = 0; - int32 was_online_remote_ = 0; - - bool are_imported_contacts_loaded_ = false; - vector> load_imported_contacts_queries_; - MultiPromiseActor load_imported_contact_users_multipromise_{"LoadImportedContactUsersMultiPromiseActor"}; - vector all_imported_contacts_; - bool are_imported_contacts_changing_ = false; - bool need_clear_imported_contacts_ = false; - - FlatHashMap user_full_contact_require_premium_; - WaitFreeHashMap linked_channel_ids_; - WaitFreeHashSet restricted_user_ids_; WaitFreeHashSet restricted_channel_ids_; - struct ContactBirthdates { - vector> users_; - double next_sync_time_ = 0.0; - bool is_being_synced_ = false; - }; - ContactBirthdates contact_birthdates_; - - vector next_all_imported_contacts_; - vector imported_contacts_unique_id_; - vector imported_contacts_pos_; - - vector imported_contact_user_ids_; // result of change_imported_contacts - vector unimported_contact_invites_; // result of change_imported_contacts - - MultiTimeout user_online_timeout_{"UserOnlineTimeout"}; - MultiTimeout user_emoji_status_timeout_{"UserEmojiStatusTimeout"}; MultiTimeout channel_emoji_status_timeout_{"ChannelEmojiStatusTimeout"}; MultiTimeout channel_unban_timeout_{"ChannelUnbanTimeout"}; MultiTimeout slow_mode_delay_timeout_{"SlowModeDelayTimeout"}; diff --git a/td/telegram/Dependencies.cpp b/td/telegram/Dependencies.cpp index b352d8938..714361cfd 100644 --- a/td/telegram/Dependencies.cpp +++ b/td/telegram/Dependencies.cpp @@ -10,6 +10,7 @@ #include "td/telegram/DialogManager.h" #include "td/telegram/StoryManager.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" #include "td/telegram/WebPagesManager.h" #include "td/utils/common.h" @@ -92,7 +93,7 @@ void Dependencies::add_message_sender_dependencies(DialogId dialog_id) { bool Dependencies::resolve_force(Td *td, const char *source, bool ignore_errors) const { bool success = true; for (auto user_id : user_ids) { - if (!td->contacts_manager_->have_user_force(user_id, source)) { + if (!td->user_manager_->have_user_force(user_id, source)) { if (!ignore_errors) { LOG(ERROR) << "Can't find " << user_id << " from " << source; } @@ -120,7 +121,7 @@ bool Dependencies::resolve_force(Td *td, const char *source, bool ignore_errors) } } for (auto secret_chat_id : secret_chat_ids) { - if (!td->contacts_manager_->have_secret_chat_force(secret_chat_id, source)) { + if (!td->user_manager_->have_secret_chat_force(secret_chat_id, source)) { if (!ignore_errors) { LOG(ERROR) << "Can't find " << secret_chat_id << " from " << source; } diff --git a/td/telegram/DialogActionBar.cpp b/td/telegram/DialogActionBar.cpp index f2b746f54..8f3cef1ed 100644 --- a/td/telegram/DialogActionBar.cpp +++ b/td/telegram/DialogActionBar.cpp @@ -8,6 +8,7 @@ #include "td/telegram/ContactsManager.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" #include "td/utils/logging.h" @@ -113,9 +114,9 @@ void DialogActionBar::fix(Td *td, DialogId dialog_id, bool is_dialog_blocked, Fo } if (dialog_type == DialogType::User) { auto user_id = dialog_id.get_user_id(); - bool is_me = user_id == td->contacts_manager_->get_my_id(); - bool is_deleted = td->contacts_manager_->is_user_deleted(user_id); - bool is_contact = td->contacts_manager_->is_user_contact(user_id); + bool is_me = user_id == td->user_manager_->get_my_id(); + bool is_deleted = td->user_manager_->is_user_deleted(user_id); + bool is_contact = td->user_manager_->is_user_contact(user_id); if (is_me || is_dialog_blocked) { can_report_spam_ = false; can_unarchive_ = false; diff --git a/td/telegram/DialogActionManager.cpp b/td/telegram/DialogActionManager.cpp index c0e7022f4..18d6329e5 100644 --- a/td/telegram/DialogActionManager.cpp +++ b/td/telegram/DialogActionManager.cpp @@ -9,7 +9,6 @@ #include "td/telegram/AccessRights.h" #include "td/telegram/AuthManager.h" #include "td/telegram/BusinessConnectionManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DialogManager.h" #include "td/telegram/Global.h" #include "td/telegram/MessageSender.h" @@ -21,6 +20,7 @@ #include "td/telegram/Td.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/buffer.h" #include "td/utils/emoji.h" @@ -180,7 +180,7 @@ void DialogActionManager::on_dialog_action(DialogId dialog_id, MessageId top_thr } if (typing_dialog_type == DialogType::User) { - if (!td_->contacts_manager_->have_min_user(typing_dialog_id.get_user_id())) { + if (!td_->user_manager_->have_min_user(typing_dialog_id.get_user_id())) { LOG(DEBUG) << "Ignore " << action << " of unknown " << typing_dialog_id.get_user_id(); return; } @@ -198,13 +198,13 @@ void DialogActionManager::on_dialog_action(DialogId dialog_id, MessageId top_thr bool is_canceled = action == DialogAction(); if ((!is_canceled || message_content_type != MessageContentType::None) && typing_dialog_type == DialogType::User) { - td_->contacts_manager_->on_update_user_local_was_online(typing_dialog_id.get_user_id(), date); + td_->user_manager_->on_update_user_local_was_online(typing_dialog_id.get_user_id(), date); } if (dialog_type == DialogType::User || dialog_type == DialogType::SecretChat) { CHECK(typing_dialog_type == DialogType::User); auto user_id = typing_dialog_id.get_user_id(); - if (!td_->contacts_manager_->is_user_bot(user_id) && !td_->contacts_manager_->is_user_status_exact(user_id) && + if (!td_->user_manager_->is_user_bot(user_id) && !td_->user_manager_->is_user_status_exact(user_id) && !td_->messages_manager_->is_dialog_opened(dialog_id) && !is_canceled) { return; } @@ -225,8 +225,7 @@ void DialogActionManager::on_dialog_action(DialogId dialog_id, MessageId top_thr return; } - if (!(typing_dialog_type == DialogType::User && - td_->contacts_manager_->is_user_bot(typing_dialog_id.get_user_id())) && + if (!(typing_dialog_type == DialogType::User && td_->user_manager_->is_user_bot(typing_dialog_id.get_user_id())) && !it->action.is_canceled_by_message_of_type(message_content_type)) { return; } diff --git a/td/telegram/DialogAdministrator.cpp b/td/telegram/DialogAdministrator.cpp index db2d25930..ed044cc0d 100644 --- a/td/telegram/DialogAdministrator.cpp +++ b/td/telegram/DialogAdministrator.cpp @@ -6,16 +6,16 @@ // #include "td/telegram/DialogAdministrator.h" -#include "td/telegram/ContactsManager.h" +#include "td/telegram/UserManager.h" namespace td { td_api::object_ptr DialogAdministrator::get_chat_administrator_object( - const ContactsManager *contacts_manager) const { - CHECK(contacts_manager != nullptr); + const UserManager *user_manager) const { + CHECK(user_manager != nullptr); CHECK(user_id_.is_valid()); return td_api::make_object( - contacts_manager->get_user_id_object(user_id_, "get_chat_administrator_object"), rank_, is_creator_); + user_manager->get_user_id_object(user_id_, "get_chat_administrator_object"), rank_, is_creator_); } StringBuilder &operator<<(StringBuilder &string_builder, const DialogAdministrator &administrator) { diff --git a/td/telegram/DialogAdministrator.h b/td/telegram/DialogAdministrator.h index bae43ca97..a9e0f6b48 100644 --- a/td/telegram/DialogAdministrator.h +++ b/td/telegram/DialogAdministrator.h @@ -15,7 +15,7 @@ namespace td { -class ContactsManager; +class UserManager; class DialogAdministrator { UserId user_id_; @@ -31,8 +31,7 @@ class DialogAdministrator { : user_id_(user_id), rank_(rank), is_creator_(is_creator) { } - td_api::object_ptr get_chat_administrator_object( - const ContactsManager *contacts_manager) const; + td_api::object_ptr get_chat_administrator_object(const UserManager *user_manager) const; UserId get_user_id() const { return user_id_; diff --git a/td/telegram/DialogEventLog.cpp b/td/telegram/DialogEventLog.cpp index 34ea302d2..ae162fcc9 100644 --- a/td/telegram/DialogEventLog.cpp +++ b/td/telegram/DialogEventLog.cpp @@ -30,6 +30,7 @@ #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" #include "td/telegram/ThemeManager.h" +#include "td/telegram/UserManager.h" #include "td/utils/buffer.h" #include "td/utils/logging.h" @@ -54,7 +55,7 @@ static td_api::object_ptr get_chat_event_action_object( return nullptr; } return td_api::make_object( - invite_link.get_chat_invite_link_object(td->contacts_manager_.get()), action->via_chatlist_); + invite_link.get_chat_invite_link_object(td->user_manager_.get()), action->via_chatlist_); } case telegram_api::channelAdminLogEventActionParticipantJoinByRequest::ID: { auto action = move_tl_object_as(action_ptr); @@ -65,8 +66,8 @@ static td_api::object_ptr get_chat_event_action_object( return nullptr; } return td_api::make_object( - td->contacts_manager_->get_user_id_object(approver_user_id, "chatEventMemberJoinedByRequest"), - invite_link.get_chat_invite_link_object(td->contacts_manager_.get())); + td->user_manager_->get_user_id_object(approver_user_id, "chatEventMemberJoinedByRequest"), + invite_link.get_chat_invite_link_object(td->user_manager_.get())); } case telegram_api::channelAdminLogEventActionParticipantLeave::ID: return td_api::make_object(); @@ -79,8 +80,7 @@ static td_api::object_ptr get_chat_event_action_object( return nullptr; } return td_api::make_object( - td->contacts_manager_->get_user_id_object(dialog_participant.dialog_id_.get_user_id(), - "chatEventMemberInvited"), + td->user_manager_->get_user_id_object(dialog_participant.dialog_id_.get_user_id(), "chatEventMemberInvited"), dialog_participant.status_.get_chat_member_status_object()); } case telegram_api::channelAdminLogEventActionParticipantToggleBan::ID: { @@ -116,8 +116,8 @@ static td_api::object_ptr get_chat_event_action_object( return nullptr; } return td_api::make_object( - td->contacts_manager_->get_user_id_object(old_dialog_participant.dialog_id_.get_user_id(), - "chatEventMemberPromoted"), + td->user_manager_->get_user_id_object(old_dialog_participant.dialog_id_.get_user_id(), + "chatEventMemberPromoted"), old_dialog_participant.status_.get_chat_member_status_object(), new_dialog_participant.status_.get_chat_member_status_object()); } @@ -281,8 +281,8 @@ static td_api::object_ptr get_chat_event_action_object( return nullptr; } return td_api::make_object( - old_invite_link.get_chat_invite_link_object(td->contacts_manager_.get()), - new_invite_link.get_chat_invite_link_object(td->contacts_manager_.get())); + old_invite_link.get_chat_invite_link_object(td->user_manager_.get()), + new_invite_link.get_chat_invite_link_object(td->user_manager_.get())); } case telegram_api::channelAdminLogEventActionExportedInviteRevoke::ID: { auto action = move_tl_object_as(action_ptr); @@ -292,7 +292,7 @@ static td_api::object_ptr get_chat_event_action_object( return nullptr; } return td_api::make_object( - invite_link.get_chat_invite_link_object(td->contacts_manager_.get())); + invite_link.get_chat_invite_link_object(td->user_manager_.get())); } case telegram_api::channelAdminLogEventActionExportedInviteDelete::ID: { auto action = move_tl_object_as(action_ptr); @@ -302,7 +302,7 @@ static td_api::object_ptr get_chat_event_action_object( return nullptr; } return td_api::make_object( - invite_link.get_chat_invite_link_object(td->contacts_manager_.get())); + invite_link.get_chat_invite_link_object(td->user_manager_.get())); } case telegram_api::channelAdminLogEventActionStartGroupCall::ID: { auto action = move_tl_object_as(action_ptr); @@ -513,7 +513,7 @@ class GetChannelAdminLogQuery final : public Td::ResultHandler { auto events = result_ptr.move_as_ok(); LOG(INFO) << "Receive in " << channel_id_ << ' ' << to_string(events); - td_->contacts_manager_->on_get_users(std::move(events->users_), "on_get_event_log"); + td_->user_manager_->on_get_users(std::move(events->users_), "on_get_event_log"); td_->contacts_manager_->on_get_chats(std::move(events->chats_), "on_get_event_log"); auto anti_spam_user_id = UserId(G()->get_option_integer("anti_spam_bot_user_id")); @@ -530,7 +530,7 @@ class GetChannelAdminLogQuery final : public Td::ResultHandler { LOG(ERROR) << "Receive invalid " << user_id; continue; } - LOG_IF(ERROR, !td_->contacts_manager_->have_user(user_id)) << "Receive unknown " << user_id; + LOG_IF(ERROR, !td_->user_manager_->have_user(user_id)) << "Receive unknown " << user_id; DialogId actor_dialog_id; auto action = get_chat_event_action_object(td_, channel_id_, std::move(event->action_), actor_dialog_id); @@ -541,7 +541,7 @@ class GetChannelAdminLogQuery final : public Td::ResultHandler { action->get_id() == td_api::chatEventMessageDeleted::ID) { static_cast(action.get())->can_report_anti_spam_false_positive_ = true; } - if (user_id == ContactsManager::get_channel_bot_user_id() && actor_dialog_id.is_valid() && + if (user_id == UserManager::get_channel_bot_user_id() && actor_dialog_id.is_valid() && actor_dialog_id.get_type() != DialogType::User) { user_id = UserId(); } else { @@ -641,7 +641,7 @@ void get_dialog_event_log(Td *td, DialogId dialog_id, const string &query, int64 vector> input_users; for (auto user_id : user_ids) { - TRY_RESULT_PROMISE(promise, input_user, td->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td->user_manager_->get_input_user(user_id)); input_users.push_back(std::move(input_user)); } diff --git a/td/telegram/DialogFilter.cpp b/td/telegram/DialogFilter.cpp index abfaab184..929a9d703 100644 --- a/td/telegram/DialogFilter.cpp +++ b/td/telegram/DialogFilter.cpp @@ -13,6 +13,7 @@ #include "td/telegram/MessagesManager.h" #include "td/telegram/misc.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/emoji.h" @@ -692,20 +693,18 @@ void DialogFilter::sort_input_dialog_ids(const Td *td, const char *source) { excluded_dialog_ids_.clear(); } - auto sort_input_dialog_ids = [contacts_manager = - td->contacts_manager_.get()](vector &input_dialog_ids) { - std::sort(input_dialog_ids.begin(), input_dialog_ids.end(), - [contacts_manager](InputDialogId lhs, InputDialogId rhs) { - auto get_order = [contacts_manager](InputDialogId input_dialog_id) { - auto dialog_id = input_dialog_id.get_dialog_id(); - if (dialog_id.get_type() != DialogType::SecretChat) { - return dialog_id.get() * 10; - } - auto user_id = contacts_manager->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); - return DialogId(user_id).get() * 10 + 1; - }; - return get_order(lhs) < get_order(rhs); - }); + auto sort_input_dialog_ids = [user_manager = td->user_manager_.get()](vector &input_dialog_ids) { + std::sort(input_dialog_ids.begin(), input_dialog_ids.end(), [user_manager](InputDialogId lhs, InputDialogId rhs) { + auto get_order = [user_manager](InputDialogId input_dialog_id) { + auto dialog_id = input_dialog_id.get_dialog_id(); + if (dialog_id.get_type() != DialogType::SecretChat) { + return dialog_id.get() * 10; + } + auto user_id = user_manager->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + return DialogId(user_id).get() * 10 + 1; + }; + return get_order(lhs) < get_order(rhs); + }); }; sort_input_dialog_ids(excluded_dialog_ids_); @@ -773,7 +772,7 @@ bool DialogFilter::need_dialog(const Td *td, const DialogFilterDialogInfo &dialo return false; } if (dialog_id.get_type() == DialogType::SecretChat) { - auto user_id = td->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + auto user_id = td->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (user_id.is_valid()) { auto user_dialog_id = DialogId(user_id); if (is_dialog_included(user_dialog_id)) { @@ -798,10 +797,10 @@ bool DialogFilter::need_dialog(const Td *td, const DialogFilterDialogInfo &dialo switch (dialog_id.get_type()) { case DialogType::User: { auto user_id = dialog_id.get_user_id(); - if (td->contacts_manager_->is_user_bot(user_id)) { + if (td->user_manager_->is_user_bot(user_id)) { return include_bots_; } - if (user_id == td->contacts_manager_->get_my_id() || td->contacts_manager_->is_user_contact(user_id)) { + if (user_id == td->user_manager_->get_my_id() || td->user_manager_->is_user_contact(user_id)) { return include_contacts_; } return include_non_contacts_; @@ -812,11 +811,11 @@ bool DialogFilter::need_dialog(const Td *td, const DialogFilterDialogInfo &dialo return td->contacts_manager_->is_broadcast_channel(dialog_id.get_channel_id()) ? include_channels_ : include_groups_; case DialogType::SecretChat: { - auto user_id = td->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); - if (td->contacts_manager_->is_user_bot(user_id)) { + auto user_id = td->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + if (td->user_manager_->is_user_bot(user_id)) { return include_bots_; } - if (td->contacts_manager_->is_user_contact(user_id)) { + if (td->user_manager_->is_user_contact(user_id)) { return include_contacts_; } return include_non_contacts_; diff --git a/td/telegram/DialogFilterManager.cpp b/td/telegram/DialogFilterManager.cpp index a2a2309a3..244fa53ae 100644 --- a/td/telegram/DialogFilterManager.cpp +++ b/td/telegram/DialogFilterManager.cpp @@ -23,6 +23,7 @@ #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/telegram/Version.h" #include "td/actor/MultiPromise.h" @@ -207,7 +208,7 @@ class GetExportedChatlistInvitesQuery final : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetExportedChatlistInvitesQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetExportedChatlistInvitesQuery"); + td_->user_manager_->on_get_users(std::move(ptr->users_), "GetExportedChatlistInvitesQuery"); td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetExportedChatlistInvitesQuery"); auto result = td_api::make_object(); for (auto &invite : ptr->invites_) { @@ -424,7 +425,7 @@ class GetChatlistUpdatesQuery final : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetChatlistUpdatesQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetChatlistUpdatesQuery"); + td_->user_manager_->on_get_users(std::move(ptr->users_), "GetChatlistUpdatesQuery"); td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetChatlistUpdatesQuery"); auto missing_dialog_ids = td_->dialog_manager_->get_peers_dialog_ids(std::move(ptr->missing_peers_), true); promise_.set_value(td_->dialog_manager_->get_chats_object(-1, missing_dialog_ids, "GetChatlistUpdatesQuery")); @@ -517,7 +518,7 @@ class GetDialogsQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetDialogsQuery: " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetDialogsQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetDialogsQuery"); td_->contacts_manager_->on_get_chats(std::move(result->chats_), "GetDialogsQuery"); td_->messages_manager_->on_get_dialogs(FolderId(), std::move(result->dialogs_), -1, std::move(result->messages_), std::move(promise_)); @@ -2130,7 +2131,7 @@ void DialogFilterManager::on_get_chatlist_invite( break; } - td_->contacts_manager_->on_get_users(std::move(users), "on_get_chatlist_invite"); + td_->user_manager_->on_get_users(std::move(users), "on_get_chatlist_invite"); td_->contacts_manager_->on_get_chats(std::move(chats), "on_get_chatlist_invite"); auto missing_dialog_ids = td_->dialog_manager_->get_peers_dialog_ids(std::move(missing_peers), true); diff --git a/td/telegram/DialogInviteLink.cpp b/td/telegram/DialogInviteLink.cpp index 14770410b..f0e0b21b0 100644 --- a/td/telegram/DialogInviteLink.cpp +++ b/td/telegram/DialogInviteLink.cpp @@ -6,8 +6,8 @@ // #include "td/telegram/DialogInviteLink.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/LinkManager.h" +#include "td/telegram/UserManager.h" #include "td/utils/logging.h" #include "td/utils/misc.h" @@ -99,15 +99,15 @@ bool DialogInviteLink::is_valid_invite_link(Slice invite_link, bool allow_trunca } td_api::object_ptr DialogInviteLink::get_chat_invite_link_object( - const ContactsManager *contacts_manager) const { - CHECK(contacts_manager != nullptr); + const UserManager *user_manager) const { + CHECK(user_manager != nullptr); if (!is_valid()) { return nullptr; } return td_api::make_object( - invite_link_, title_, contacts_manager->get_user_id_object(creator_user_id_, "get_chat_invite_link_object"), - date_, edit_date_, expire_date_, usage_limit_, usage_count_, request_count_, creates_join_request_, is_permanent_, + invite_link_, title_, user_manager->get_user_id_object(creator_user_id_, "get_chat_invite_link_object"), date_, + edit_date_, expire_date_, usage_limit_, usage_count_, request_count_, creates_join_request_, is_permanent_, is_revoked_); } diff --git a/td/telegram/DialogInviteLink.h b/td/telegram/DialogInviteLink.h index 7aa220164..04e304c30 100644 --- a/td/telegram/DialogInviteLink.h +++ b/td/telegram/DialogInviteLink.h @@ -17,7 +17,7 @@ namespace td { -class ContactsManager; +class UserManager; class DialogInviteLink { string invite_link_; @@ -45,7 +45,7 @@ class DialogInviteLink { static bool is_valid_invite_link(Slice invite_link, bool allow_truncated = false); - td_api::object_ptr get_chat_invite_link_object(const ContactsManager *contacts_manager) const; + td_api::object_ptr get_chat_invite_link_object(const UserManager *user_manager) const; bool is_valid() const { return !invite_link_.empty() && creator_user_id_.is_valid() && date_ > 0; diff --git a/td/telegram/DialogInviteLinkManager.cpp b/td/telegram/DialogInviteLinkManager.cpp index 5c16e440e..1ae378a68 100644 --- a/td/telegram/DialogInviteLinkManager.cpp +++ b/td/telegram/DialogInviteLinkManager.cpp @@ -19,6 +19,7 @@ #include "td/telegram/telegram_api.h" #include "td/telegram/ThemeManager.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/utils/buffer.h" #include "td/utils/logging.h" @@ -151,13 +152,13 @@ class ExportChatInviteQuery final : public Td::ResultHandler { if (!invite_link.is_valid()) { return on_error(Status::Error(500, "Receive invalid invite link")); } - if (invite_link.get_creator_user_id() != td_->contacts_manager_->get_my_id()) { + if (invite_link.get_creator_user_id() != td_->user_manager_->get_my_id()) { return on_error(Status::Error(500, "Receive invalid invite link creator")); } if (invite_link.is_permanent()) { td_->dialog_invite_link_manager_->on_get_permanent_dialog_invite_link(dialog_id_, invite_link); } - promise_.set_value(invite_link.get_chat_invite_link_object(td_->contacts_manager_.get())); + promise_.set_value(invite_link.get_chat_invite_link_object(td_->user_manager_.get())); } void on_error(Status status) final { @@ -207,13 +208,13 @@ class EditChatInviteLinkQuery final : public Td::ResultHandler { auto invite = move_tl_object_as(result); - td_->contacts_manager_->on_get_users(std::move(invite->users_), "EditChatInviteLinkQuery"); + td_->user_manager_->on_get_users(std::move(invite->users_), "EditChatInviteLinkQuery"); DialogInviteLink invite_link(std::move(invite->invite_), false, "EditChatInviteLinkQuery"); if (!invite_link.is_valid()) { return on_error(Status::Error(500, "Receive invalid invite link")); } - promise_.set_value(invite_link.get_chat_invite_link_object(td_->contacts_manager_.get())); + promise_.set_value(invite_link.get_chat_invite_link_object(td_->user_manager_.get())); } void on_error(Status status) final { @@ -256,14 +257,14 @@ class GetExportedChatInviteQuery final : public Td::ResultHandler { auto result = move_tl_object_as(result_ptr.ok_ref()); LOG(INFO) << "Receive result for GetExportedChatInviteQuery: " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetExportedChatInviteQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetExportedChatInviteQuery"); DialogInviteLink invite_link(std::move(result->invite_), false, "GetExportedChatInviteQuery"); if (!invite_link.is_valid()) { LOG(ERROR) << "Receive invalid invite link in " << dialog_id_; return on_error(Status::Error(500, "Receive invalid invite link")); } - promise_.set_value(invite_link.get_chat_invite_link_object(td_->contacts_manager_.get())); + promise_.set_value(invite_link.get_chat_invite_link_object(td_->user_manager_.get())); } void on_error(Status status) final { @@ -311,7 +312,7 @@ class GetExportedChatInvitesQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetExportedChatInvitesQuery: " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetExportedChatInvitesQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetExportedChatInvitesQuery"); int32 total_count = result->count_; if (total_count < static_cast(result->invites_.size())) { @@ -326,7 +327,7 @@ class GetExportedChatInvitesQuery final : public Td::ResultHandler { total_count--; continue; } - invite_links.push_back(invite_link.get_chat_invite_link_object(td_->contacts_manager_.get())); + invite_links.push_back(invite_link.get_chat_invite_link_object(td_->user_manager_.get())); } promise_.set_value(td_api::make_object(total_count, std::move(invite_links))); } @@ -365,7 +366,7 @@ class GetChatAdminWithInvitesQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetChatAdminWithInvitesQuery: " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetChatAdminWithInvitesQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetChatAdminWithInvitesQuery"); vector> invite_link_counts; for (auto &admin : result->admins_) { @@ -375,7 +376,7 @@ class GetChatAdminWithInvitesQuery final : public Td::ResultHandler { continue; } invite_link_counts.push_back(td_api::make_object( - td_->contacts_manager_->get_user_id_object(user_id, "chatInviteLinkCount"), admin->invites_count_, + td_->user_manager_->get_user_id_object(user_id, "chatInviteLinkCount"), admin->invites_count_, admin->revoked_invites_count_)); } promise_.set_value(td_api::make_object(std::move(invite_link_counts))); @@ -403,7 +404,7 @@ class GetChatInviteImportersQuery final : public Td::ResultHandler { return on_error(Status::Error(400, "Can't access the chat")); } - auto r_input_user = td_->contacts_manager_->get_input_user(offset_user_id); + auto r_input_user = td_->user_manager_->get_input_user(offset_user_id); if (r_input_user.is_error()) { r_input_user = make_tl_object(); } @@ -423,7 +424,7 @@ class GetChatInviteImportersQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetChatInviteImportersQuery: " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetChatInviteImportersQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetChatInviteImportersQuery"); int32 total_count = result->count_; if (total_count < static_cast(result->importers_.size())) { @@ -441,9 +442,8 @@ class GetChatInviteImportersQuery final : public Td::ResultHandler { continue; } invite_link_members.push_back(td_api::make_object( - td_->contacts_manager_->get_user_id_object(user_id, "chatInviteLinkMember"), importer->date_, - importer->via_chatlist_, - td_->contacts_manager_->get_user_id_object(approver_user_id, "chatInviteLinkMember"))); + td_->user_manager_->get_user_id_object(user_id, "chatInviteLinkMember"), importer->date_, + importer->via_chatlist_, td_->user_manager_->get_user_id_object(approver_user_id, "chatInviteLinkMember"))); } promise_.set_value(td_api::make_object(total_count, std::move(invite_link_members))); } @@ -489,19 +489,19 @@ class RevokeChatInviteLinkQuery final : public Td::ResultHandler { case telegram_api::messages_exportedChatInvite::ID: { auto invite = move_tl_object_as(result); - td_->contacts_manager_->on_get_users(std::move(invite->users_), "RevokeChatInviteLinkQuery"); + td_->user_manager_->on_get_users(std::move(invite->users_), "RevokeChatInviteLinkQuery"); DialogInviteLink invite_link(std::move(invite->invite_), false, "RevokeChatInviteLinkQuery"); if (!invite_link.is_valid()) { return on_error(Status::Error(500, "Receive invalid invite link")); } - links.push_back(invite_link.get_chat_invite_link_object(td_->contacts_manager_.get())); + links.push_back(invite_link.get_chat_invite_link_object(td_->user_manager_.get())); break; } case telegram_api::messages_exportedChatInviteReplaced::ID: { auto invite = move_tl_object_as(result); - td_->contacts_manager_->on_get_users(std::move(invite->users_), "RevokeChatInviteLinkQuery replaced"); + td_->user_manager_->on_get_users(std::move(invite->users_), "RevokeChatInviteLinkQuery replaced"); DialogInviteLink invite_link(std::move(invite->invite_), false, "RevokeChatInviteLinkQuery replaced"); DialogInviteLink new_invite_link(std::move(invite->new_invite_), false, @@ -509,12 +509,12 @@ class RevokeChatInviteLinkQuery final : public Td::ResultHandler { if (!invite_link.is_valid() || !new_invite_link.is_valid()) { return on_error(Status::Error(500, "Receive invalid invite link")); } - if (new_invite_link.get_creator_user_id() == td_->contacts_manager_->get_my_id() && + if (new_invite_link.get_creator_user_id() == td_->user_manager_->get_my_id() && new_invite_link.is_permanent()) { td_->dialog_invite_link_manager_->on_get_permanent_dialog_invite_link(dialog_id_, new_invite_link); } - links.push_back(invite_link.get_chat_invite_link_object(td_->contacts_manager_.get())); - links.push_back(new_invite_link.get_chat_invite_link_object(td_->contacts_manager_.get())); + links.push_back(invite_link.get_chat_invite_link_object(td_->user_manager_.get())); + links.push_back(new_invite_link.get_chat_invite_link_object(td_->user_manager_.get())); break; } default: @@ -727,13 +727,13 @@ void DialogInviteLinkManager::on_get_dialog_invite_link_info( auto chat_invite = telegram_api::move_object_as(chat_invite_ptr); vector participant_user_ids; for (auto &user : chat_invite->participants_) { - auto user_id = ContactsManager::get_user_id(user); + auto user_id = UserManager::get_user_id(user); if (!user_id.is_valid()) { LOG(ERROR) << "Receive invalid " << user_id; continue; } - td_->contacts_manager_->on_get_user(std::move(user), "chatInvite"); + td_->user_manager_->on_get_user(std::move(user), "chatInvite"); participant_user_ids.push_back(user_id); } @@ -850,8 +850,8 @@ td_api::object_ptr DialogInviteLinkManager::get_chat accent_color_id_object = td_->theme_manager_->get_accent_color_id_object(invite_link_info->accent_color_id); description = invite_link_info->description; participant_count = invite_link_info->participant_count; - member_user_ids = td_->contacts_manager_->get_user_ids_object(invite_link_info->participant_user_ids, - "get_chat_invite_link_info_object"); + member_user_ids = td_->user_manager_->get_user_ids_object(invite_link_info->participant_user_ids, + "get_chat_invite_link_info_object"); creates_join_request = invite_link_info->creates_join_request; is_public = invite_link_info->is_public; is_verified = invite_link_info->is_verified; @@ -978,9 +978,9 @@ void DialogInviteLinkManager::on_get_permanent_dialog_invite_link(DialogId dialo void DialogInviteLinkManager::export_dialog_invite_link(DialogId dialog_id, string title, int32 expire_date, int32 usage_limit, bool creates_join_request, bool is_permanent, Promise> &&promise) { - td_->contacts_manager_->get_me(PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, title = std::move(title), - expire_date, usage_limit, creates_join_request, is_permanent, - promise = std::move(promise)](Result &&result) mutable { + td_->user_manager_->get_me(PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, title = std::move(title), + expire_date, usage_limit, creates_join_request, is_permanent, + promise = std::move(promise)](Result &&result) mutable { if (result.is_error()) { promise.set_error(result.move_as_error()); } else { @@ -1045,8 +1045,8 @@ void DialogInviteLinkManager::get_dialog_invite_links(DialogId dialog_id, UserId int32 offset_date, const string &offset_invite_link, int32 limit, Promise> &&promise) { TRY_STATUS_PROMISE(promise, - can_manage_dialog_invite_links(dialog_id, creator_user_id != td_->contacts_manager_->get_my_id())); - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(creator_user_id)); + can_manage_dialog_invite_links(dialog_id, creator_user_id != td_->user_manager_->get_my_id())); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(creator_user_id)); if (limit <= 0) { return promise.set_error(Status::Error(400, "Parameter limit must be positive")); @@ -1105,8 +1105,8 @@ void DialogInviteLinkManager::delete_revoked_dialog_invite_link(DialogId dialog_ void DialogInviteLinkManager::delete_all_revoked_dialog_invite_links(DialogId dialog_id, UserId creator_user_id, Promise &&promise) { TRY_STATUS_PROMISE(promise, - can_manage_dialog_invite_links(dialog_id, creator_user_id != td_->contacts_manager_->get_my_id())); - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(creator_user_id)); + can_manage_dialog_invite_links(dialog_id, creator_user_id != td_->user_manager_->get_my_id())); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(creator_user_id)); td_->create_handler(std::move(promise)) ->send(dialog_id, std::move(input_user)); diff --git a/td/telegram/DialogManager.cpp b/td/telegram/DialogManager.cpp index 3e7ea21c9..09cc8ec9a 100644 --- a/td/telegram/DialogManager.cpp +++ b/td/telegram/DialogManager.cpp @@ -27,6 +27,7 @@ #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" #include "td/telegram/Usernames.h" #include "td/utils/algorithm.h" @@ -123,7 +124,7 @@ class ResolveUsernameQuery final : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(DEBUG) << "Receive result for ResolveUsernameQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "ResolveUsernameQuery"); + td_->user_manager_->on_get_users(std::move(ptr->users_), "ResolveUsernameQuery"); td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "ResolveUsernameQuery"); promise_.set_value(DialogId(ptr->peer_)); @@ -552,7 +553,7 @@ void DialogManager::tear_down() { } DialogId DialogManager::get_my_dialog_id() const { - return DialogId(td_->contacts_manager_->get_my_id()); + return DialogId(td_->user_manager_->get_my_id()); } InputDialogId DialogManager::get_input_dialog_id(DialogId dialog_id) const { @@ -569,7 +570,7 @@ tl_object_ptr DialogManager::get_input_peer(DialogId di AccessRights access_rights) const { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->get_input_peer_user(dialog_id.get_user_id(), access_rights); + return td_->user_manager_->get_input_peer_user(dialog_id.get_user_id(), access_rights); case DialogType::Chat: return td_->contacts_manager_->get_input_peer_chat(dialog_id.get_chat_id(), access_rights); case DialogType::Channel: @@ -658,7 +659,7 @@ tl_object_ptr DialogManager::get_input_encrypt switch (dialog_id.get_type()) { case DialogType::SecretChat: { SecretChatId secret_chat_id = dialog_id.get_secret_chat_id(); - return td_->contacts_manager_->get_input_encrypted_chat(secret_chat_id, access_rights); + return td_->user_manager_->get_input_encrypted_chat(secret_chat_id, access_rights); } case DialogType::User: case DialogType::Chat: @@ -674,7 +675,7 @@ bool DialogManager::have_input_peer(DialogId dialog_id, AccessRights access_righ switch (dialog_id.get_type()) { case DialogType::User: { UserId user_id = dialog_id.get_user_id(); - return td_->contacts_manager_->have_input_peer_user(user_id, access_rights); + return td_->user_manager_->have_input_peer_user(user_id, access_rights); } case DialogType::Chat: { ChatId chat_id = dialog_id.get_chat_id(); @@ -686,7 +687,7 @@ bool DialogManager::have_input_peer(DialogId dialog_id, AccessRights access_righ } case DialogType::SecretChat: { SecretChatId secret_chat_id = dialog_id.get_secret_chat_id(); - return td_->contacts_manager_->have_input_encrypted_peer(secret_chat_id, access_rights); + return td_->user_manager_->have_input_encrypted_peer(secret_chat_id, access_rights); } case DialogType::None: return false; @@ -723,7 +724,7 @@ bool DialogManager::have_dialog_info(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: { UserId user_id = dialog_id.get_user_id(); - return td_->contacts_manager_->have_user(user_id); + return td_->user_manager_->have_user(user_id); } case DialogType::Chat: { ChatId chat_id = dialog_id.get_chat_id(); @@ -735,7 +736,7 @@ bool DialogManager::have_dialog_info(DialogId dialog_id) const { } case DialogType::SecretChat: { SecretChatId secret_chat_id = dialog_id.get_secret_chat_id(); - return td_->contacts_manager_->have_secret_chat(secret_chat_id); + return td_->user_manager_->have_secret_chat(secret_chat_id); } case DialogType::None: default: @@ -746,7 +747,7 @@ bool DialogManager::have_dialog_info(DialogId dialog_id) const { bool DialogManager::is_dialog_info_received_from_server(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->is_user_received_from_server(dialog_id.get_user_id()); + return td_->user_manager_->is_user_received_from_server(dialog_id.get_user_id()); case DialogType::Chat: return td_->contacts_manager_->is_chat_received_from_server(dialog_id.get_chat_id()); case DialogType::Channel: @@ -760,7 +761,7 @@ bool DialogManager::have_dialog_info_force(DialogId dialog_id, const char *sourc switch (dialog_id.get_type()) { case DialogType::User: { UserId user_id = dialog_id.get_user_id(); - return td_->contacts_manager_->have_user_force(user_id, source); + return td_->user_manager_->have_user_force(user_id, source); } case DialogType::Chat: { ChatId chat_id = dialog_id.get_chat_id(); @@ -772,7 +773,7 @@ bool DialogManager::have_dialog_info_force(DialogId dialog_id, const char *sourc } case DialogType::SecretChat: { SecretChatId secret_chat_id = dialog_id.get_secret_chat_id(); - return td_->contacts_manager_->have_secret_chat_force(secret_chat_id, source); + return td_->user_manager_->have_secret_chat_force(secret_chat_id, source); } case DialogType::None: default: @@ -783,7 +784,7 @@ bool DialogManager::have_dialog_info_force(DialogId dialog_id, const char *sourc void DialogManager::reload_dialog_info(DialogId dialog_id, Promise &&promise) { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->reload_user(dialog_id.get_user_id(), std::move(promise), "reload_dialog_info"); + return td_->user_manager_->reload_user(dialog_id.get_user_id(), std::move(promise), "reload_dialog_info"); case DialogType::Chat: return td_->contacts_manager_->reload_chat(dialog_id.get_chat_id(), std::move(promise), "reload_dialog_info"); case DialogType::Channel: @@ -797,7 +798,7 @@ void DialogManager::reload_dialog_info(DialogId dialog_id, Promise &&promi void DialogManager::get_dialog_info_full(DialogId dialog_id, Promise &&promise, const char *source) { switch (dialog_id.get_type()) { case DialogType::User: - send_closure_later(td_->contacts_manager_actor_, &ContactsManager::load_user_full, dialog_id.get_user_id(), false, + send_closure_later(td_->user_manager_actor_, &UserManager::load_user_full, dialog_id.get_user_id(), false, std::move(promise), source); return; case DialogType::Chat: @@ -825,7 +826,7 @@ void DialogManager::reload_dialog_info_full(DialogId dialog_id, const char *sour LOG(INFO) << "Reload full info about " << dialog_id << " from " << source; switch (dialog_id.get_type()) { case DialogType::User: - send_closure_later(td_->contacts_manager_actor_, &ContactsManager::reload_user_full, dialog_id.get_user_id(), + send_closure_later(td_->user_manager_actor_, &UserManager::reload_user_full, dialog_id.get_user_id(), Promise(), source); return; case DialogType::Chat: @@ -876,7 +877,7 @@ td_api::object_ptr DialogManager::get_chat_type_object(DialogI switch (dialog_id.get_type()) { case DialogType::User: return td_api::make_object( - td_->contacts_manager_->get_user_id_object(dialog_id.get_user_id(), source)); + td_->user_manager_->get_user_id_object(dialog_id.get_user_id(), source)); case DialogType::Chat: return td_api::make_object( td_->contacts_manager_->get_basic_group_id_object(dialog_id.get_chat_id(), source)); @@ -888,10 +889,10 @@ td_api::object_ptr DialogManager::get_chat_type_object(DialogI } case DialogType::SecretChat: { auto secret_chat_id = dialog_id.get_secret_chat_id(); - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id); + auto user_id = td_->user_manager_->get_secret_chat_user_id(secret_chat_id); return td_api::make_object( - td_->contacts_manager_->get_secret_chat_id_object(secret_chat_id, source), - td_->contacts_manager_->get_user_id_object(user_id, source)); + td_->user_manager_->get_secret_chat_id_object(secret_chat_id, source), + td_->user_manager_->get_user_id_object(user_id, source)); } case DialogType::None: default: @@ -1066,13 +1067,13 @@ void DialogManager::delete_dialog(DialogId dialog_id, Promise &&promise) { string DialogManager::get_dialog_title(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->get_user_title(dialog_id.get_user_id()); + return td_->user_manager_->get_user_title(dialog_id.get_user_id()); case DialogType::Chat: return td_->contacts_manager_->get_chat_title(dialog_id.get_chat_id()); case DialogType::Channel: return td_->contacts_manager_->get_channel_title(dialog_id.get_channel_id()); case DialogType::SecretChat: - return td_->contacts_manager_->get_secret_chat_title(dialog_id.get_secret_chat_id()); + return td_->user_manager_->get_secret_chat_title(dialog_id.get_secret_chat_id()); case DialogType::None: default: UNREACHABLE(); @@ -1083,13 +1084,13 @@ string DialogManager::get_dialog_title(DialogId dialog_id) const { const DialogPhoto *DialogManager::get_dialog_photo(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->get_user_dialog_photo(dialog_id.get_user_id()); + return td_->user_manager_->get_user_dialog_photo(dialog_id.get_user_id()); case DialogType::Chat: return td_->contacts_manager_->get_chat_dialog_photo(dialog_id.get_chat_id()); case DialogType::Channel: return td_->contacts_manager_->get_channel_dialog_photo(dialog_id.get_channel_id()); case DialogType::SecretChat: - return td_->contacts_manager_->get_secret_chat_dialog_photo(dialog_id.get_secret_chat_id()); + return td_->user_manager_->get_secret_chat_dialog_photo(dialog_id.get_secret_chat_id()); case DialogType::None: default: UNREACHABLE(); @@ -1100,13 +1101,13 @@ const DialogPhoto *DialogManager::get_dialog_photo(DialogId dialog_id) const { int32 DialogManager::get_dialog_accent_color_id_object(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->get_user_accent_color_id_object(dialog_id.get_user_id()); + return td_->user_manager_->get_user_accent_color_id_object(dialog_id.get_user_id()); case DialogType::Chat: return td_->contacts_manager_->get_chat_accent_color_id_object(dialog_id.get_chat_id()); case DialogType::Channel: return td_->contacts_manager_->get_channel_accent_color_id_object(dialog_id.get_channel_id()); case DialogType::SecretChat: - return td_->contacts_manager_->get_secret_chat_accent_color_id_object(dialog_id.get_secret_chat_id()); + return td_->user_manager_->get_secret_chat_accent_color_id_object(dialog_id.get_secret_chat_id()); case DialogType::None: default: UNREACHABLE(); @@ -1117,13 +1118,13 @@ int32 DialogManager::get_dialog_accent_color_id_object(DialogId dialog_id) const CustomEmojiId DialogManager::get_dialog_background_custom_emoji_id(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->get_user_background_custom_emoji_id(dialog_id.get_user_id()); + return td_->user_manager_->get_user_background_custom_emoji_id(dialog_id.get_user_id()); case DialogType::Chat: return td_->contacts_manager_->get_chat_background_custom_emoji_id(dialog_id.get_chat_id()); case DialogType::Channel: return td_->contacts_manager_->get_channel_background_custom_emoji_id(dialog_id.get_channel_id()); case DialogType::SecretChat: - return td_->contacts_manager_->get_secret_chat_background_custom_emoji_id(dialog_id.get_secret_chat_id()); + return td_->user_manager_->get_secret_chat_background_custom_emoji_id(dialog_id.get_secret_chat_id()); case DialogType::None: default: UNREACHABLE(); @@ -1134,13 +1135,13 @@ CustomEmojiId DialogManager::get_dialog_background_custom_emoji_id(DialogId dial int32 DialogManager::get_dialog_profile_accent_color_id_object(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->get_user_profile_accent_color_id_object(dialog_id.get_user_id()); + return td_->user_manager_->get_user_profile_accent_color_id_object(dialog_id.get_user_id()); case DialogType::Chat: return td_->contacts_manager_->get_chat_profile_accent_color_id_object(dialog_id.get_chat_id()); case DialogType::Channel: return td_->contacts_manager_->get_channel_profile_accent_color_id_object(dialog_id.get_channel_id()); case DialogType::SecretChat: - return td_->contacts_manager_->get_secret_chat_profile_accent_color_id_object(dialog_id.get_secret_chat_id()); + return td_->user_manager_->get_secret_chat_profile_accent_color_id_object(dialog_id.get_secret_chat_id()); case DialogType::None: default: UNREACHABLE(); @@ -1151,13 +1152,13 @@ int32 DialogManager::get_dialog_profile_accent_color_id_object(DialogId dialog_i CustomEmojiId DialogManager::get_dialog_profile_background_custom_emoji_id(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->get_user_profile_background_custom_emoji_id(dialog_id.get_user_id()); + return td_->user_manager_->get_user_profile_background_custom_emoji_id(dialog_id.get_user_id()); case DialogType::Chat: return td_->contacts_manager_->get_chat_profile_background_custom_emoji_id(dialog_id.get_chat_id()); case DialogType::Channel: return td_->contacts_manager_->get_channel_profile_background_custom_emoji_id(dialog_id.get_channel_id()); case DialogType::SecretChat: - return td_->contacts_manager_->get_secret_chat_profile_background_custom_emoji_id(dialog_id.get_secret_chat_id()); + return td_->user_manager_->get_secret_chat_profile_background_custom_emoji_id(dialog_id.get_secret_chat_id()); case DialogType::None: default: UNREACHABLE(); @@ -1168,13 +1169,13 @@ CustomEmojiId DialogManager::get_dialog_profile_background_custom_emoji_id(Dialo RestrictedRights DialogManager::get_dialog_default_permissions(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->get_user_default_permissions(dialog_id.get_user_id()); + return td_->user_manager_->get_user_default_permissions(dialog_id.get_user_id()); case DialogType::Chat: return td_->contacts_manager_->get_chat_default_permissions(dialog_id.get_chat_id()); case DialogType::Channel: return td_->contacts_manager_->get_channel_default_permissions(dialog_id.get_channel_id()); case DialogType::SecretChat: - return td_->contacts_manager_->get_secret_chat_default_permissions(dialog_id.get_secret_chat_id()); + return td_->user_manager_->get_secret_chat_default_permissions(dialog_id.get_secret_chat_id()); case DialogType::None: default: UNREACHABLE(); @@ -1186,13 +1187,13 @@ RestrictedRights DialogManager::get_dialog_default_permissions(DialogId dialog_i td_api::object_ptr DialogManager::get_dialog_emoji_status_object(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->get_user_emoji_status_object(dialog_id.get_user_id()); + return td_->user_manager_->get_user_emoji_status_object(dialog_id.get_user_id()); case DialogType::Chat: return td_->contacts_manager_->get_chat_emoji_status_object(dialog_id.get_chat_id()); case DialogType::Channel: return td_->contacts_manager_->get_channel_emoji_status_object(dialog_id.get_channel_id()); case DialogType::SecretChat: - return td_->contacts_manager_->get_secret_chat_emoji_status_object(dialog_id.get_secret_chat_id()); + return td_->user_manager_->get_secret_chat_emoji_status_object(dialog_id.get_secret_chat_id()); case DialogType::None: default: UNREACHABLE(); @@ -1203,13 +1204,13 @@ td_api::object_ptr DialogManager::get_dialog_emoji_status_o string DialogManager::get_dialog_about(DialogId dialog_id) { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->get_user_about(dialog_id.get_user_id()); + return td_->user_manager_->get_user_about(dialog_id.get_user_id()); case DialogType::Chat: return td_->contacts_manager_->get_chat_about(dialog_id.get_chat_id()); case DialogType::Channel: return td_->contacts_manager_->get_channel_about(dialog_id.get_channel_id()); case DialogType::SecretChat: - return td_->contacts_manager_->get_secret_chat_about(dialog_id.get_secret_chat_id()); + return td_->user_manager_->get_secret_chat_about(dialog_id.get_secret_chat_id()); case DialogType::None: default: UNREACHABLE(); @@ -1220,14 +1221,14 @@ string DialogManager::get_dialog_about(DialogId dialog_id) { string DialogManager::get_dialog_search_text(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->get_user_search_text(dialog_id.get_user_id()); + return td_->user_manager_->get_user_search_text(dialog_id.get_user_id()); case DialogType::Chat: return td_->contacts_manager_->get_chat_title(dialog_id.get_chat_id()); case DialogType::Channel: return td_->contacts_manager_->get_channel_search_text(dialog_id.get_channel_id()); case DialogType::SecretChat: - return td_->contacts_manager_->get_user_search_text( - td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id())); + return td_->user_manager_->get_user_search_text( + td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id())); case DialogType::None: default: UNREACHABLE(); @@ -1261,20 +1262,20 @@ bool DialogManager::is_dialog_action_unneeded(DialogId dialog_id) const { if (dialog_type == DialogType::User || dialog_type == DialogType::SecretChat) { UserId user_id = dialog_type == DialogType::User ? dialog_id.get_user_id() - : td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); - if (td_->contacts_manager_->is_user_deleted(user_id)) { + : td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + if (td_->user_manager_->is_user_deleted(user_id)) { return true; } - if (td_->contacts_manager_->is_user_bot(user_id) && !td_->contacts_manager_->is_user_support(user_id)) { + if (td_->user_manager_->is_user_bot(user_id) && !td_->user_manager_->is_user_support(user_id)) { return true; } - if (user_id == td_->contacts_manager_->get_my_id()) { + if (user_id == td_->user_manager_->get_my_id()) { return true; } if (!td_->auth_manager_->is_bot()) { - if (td_->contacts_manager_->is_user_status_exact(user_id)) { - if (!td_->contacts_manager_->is_user_online(user_id, 30)) { + if (td_->user_manager_->is_user_status_exact(user_id)) { + if (!td_->user_manager_->is_user_online(user_id, 30)) { return true; } } else { @@ -1369,7 +1370,7 @@ void DialogManager::set_dialog_photo(DialogId dialog_id, const td_api::object_pt switch (input_photo->get_id()) { case td_api::inputChatPhotoPrevious::ID: { auto photo = static_cast(input_photo.get()); - auto file_id = td_->contacts_manager_->get_profile_photo_file_id(photo->chat_photo_id_); + auto file_id = td_->user_manager_->get_profile_photo_file_id(photo->chat_photo_id_); if (!file_id.is_valid()) { return promise.set_error(Status::Error(400, "Unknown profile photo ID specified")); } @@ -1545,8 +1546,7 @@ void DialogManager::set_dialog_accent_color(DialogId dialog_id, AccentColorId ac switch (dialog_id.get_type()) { case DialogType::User: if (dialog_id == get_my_dialog_id()) { - return td_->contacts_manager_->set_accent_color(accent_color_id, background_custom_emoji_id, - std::move(promise)); + return td_->user_manager_->set_accent_color(accent_color_id, background_custom_emoji_id, std::move(promise)); } break; case DialogType::Chat: @@ -1573,8 +1573,8 @@ void DialogManager::set_dialog_profile_accent_color(DialogId dialog_id, AccentCo switch (dialog_id.get_type()) { case DialogType::User: if (dialog_id == get_my_dialog_id()) { - return td_->contacts_manager_->set_profile_accent_color(profile_accent_color_id, - profile_background_custom_emoji_id, std::move(promise)); + return td_->user_manager_->set_profile_accent_color(profile_accent_color_id, profile_background_custom_emoji_id, + std::move(promise)); } break; case DialogType::Chat: @@ -1655,7 +1655,7 @@ void DialogManager::set_dialog_emoji_status(DialogId dialog_id, const EmojiStatu switch (dialog_id.get_type()) { case DialogType::User: if (dialog_id == get_my_dialog_id()) { - return td_->contacts_manager_->set_emoji_status(emoji_status, std::move(promise)); + return td_->user_manager_->set_emoji_status(emoji_status, std::move(promise)); } break; case DialogType::Chat: @@ -1757,7 +1757,7 @@ bool DialogManager::can_report_dialog(DialogId dialog_id) const { // doesn't include possibility of report from action bar switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->can_report_user(dialog_id.get_user_id()); + return td_->user_manager_->can_report_user(dialog_id.get_user_id()); case DialogType::Chat: return false; case DialogType::Channel: @@ -1914,8 +1914,8 @@ void DialogManager::on_update_dialog_bot_commands( LOG(ERROR) << "Receive updateBotCommands about invalid " << bot_user_id; return; } - if (!td_->contacts_manager_->have_user_force(bot_user_id, "on_update_dialog_bot_commands") || - !td_->contacts_manager_->is_user_bot(bot_user_id)) { + if (!td_->user_manager_->have_user_force(bot_user_id, "on_update_dialog_bot_commands") || + !td_->user_manager_->is_user_bot(bot_user_id)) { return; } if (td_->auth_manager_->is_bot()) { @@ -1928,7 +1928,7 @@ void DialogManager::on_update_dialog_bot_commands( LOG(ERROR) << "Receive commands of " << bot_user_id << " in " << dialog_id; return; } - return td_->contacts_manager_->on_update_user_commands(bot_user_id, std::move(bot_commands)); + return td_->user_manager_->on_update_user_commands(bot_user_id, std::move(bot_commands)); case DialogType::Chat: return td_->contacts_manager_->on_update_chat_bot_commands(dialog_id.get_chat_id(), BotCommands(bot_user_id, std::move(bot_commands))); diff --git a/td/telegram/DialogParticipantFilter.cpp b/td/telegram/DialogParticipantFilter.cpp index 3dd63424e..32f6581c5 100644 --- a/td/telegram/DialogParticipantFilter.cpp +++ b/td/telegram/DialogParticipantFilter.cpp @@ -6,10 +6,10 @@ // #include "td/telegram/DialogParticipantFilter.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DialogId.h" #include "td/telegram/DialogParticipant.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" namespace td { @@ -119,7 +119,7 @@ bool DialogParticipantFilter::is_dialog_participant_suitable(const Td *td, const switch (type_) { case Type::Contacts: return participant.dialog_id_.get_type() == DialogType::User && - td->contacts_manager_->is_user_contact(participant.dialog_id_.get_user_id()); + td->user_manager_->is_user_contact(participant.dialog_id_.get_user_id()); case Type::Administrators: return participant.status_.is_administrator(); case Type::Members: @@ -132,7 +132,7 @@ bool DialogParticipantFilter::is_dialog_participant_suitable(const Td *td, const return true; case Type::Bots: return participant.dialog_id_.get_type() == DialogType::User && - td->contacts_manager_->is_user_bot(participant.dialog_id_.get_user_id()); + td->user_manager_->is_user_bot(participant.dialog_id_.get_user_id()); default: UNREACHABLE(); return false; diff --git a/td/telegram/DialogParticipantManager.cpp b/td/telegram/DialogParticipantManager.cpp index 9130dc001..267e9d5d7 100644 --- a/td/telegram/DialogParticipantManager.cpp +++ b/td/telegram/DialogParticipantManager.cpp @@ -23,6 +23,7 @@ #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/db/SqliteKeyValueAsync.h" @@ -99,7 +100,7 @@ class GetChatJoinRequestsQuery final : public Td::ResultHandler { return on_error(Status::Error(400, "Can't access the chat")); } - auto r_input_user = td_->contacts_manager_->get_input_user(offset_user_id); + auto r_input_user = td_->user_manager_->get_input_user(offset_user_id); if (r_input_user.is_error()) { r_input_user = make_tl_object(); } @@ -125,7 +126,7 @@ class GetChatJoinRequestsQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetChatJoinRequestsQuery: " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetChatJoinRequestsQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetChatJoinRequestsQuery"); int32 total_count = result->count_; if (total_count < static_cast(result->importers_.size())) { @@ -146,7 +147,7 @@ class GetChatJoinRequestsQuery final : public Td::ResultHandler { recent_requesters.push_back(user_id.get()); } join_requests.push_back(td_api::make_object( - td_->contacts_manager_->get_user_id_object(user_id, "chatJoinRequest"), request->date_, request->about_)); + td_->user_manager_->get_user_id_object(user_id, "chatJoinRequest"), request->date_, request->about_)); } if (is_full_list_) { td_->messages_manager_->on_update_dialog_pending_join_requests(dialog_id_, total_count, @@ -176,7 +177,7 @@ class HideChatJoinRequestQuery final : public Td::ResultHandler { return on_error(Status::Error(400, "Can't access the chat")); } - TRY_RESULT_PROMISE(promise_, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise_, input_user, td_->user_manager_->get_input_user(user_id)); int32 flags = 0; if (approve) { @@ -279,7 +280,7 @@ class GetChannelAdministratorsQuery final : public Td::ResultHandler { switch (participants_ptr->get_id()) { case telegram_api::channels_channelParticipants::ID: { auto participants = telegram_api::move_object_as(participants_ptr); - td_->contacts_manager_->on_get_users(std::move(participants->users_), "GetChannelAdministratorsQuery"); + td_->user_manager_->on_get_users(std::move(participants->users_), "GetChannelAdministratorsQuery"); td_->contacts_manager_->on_get_chats(std::move(participants->chats_), "GetChannelAdministratorsQuery"); auto channel_type = td_->contacts_manager_->get_channel_type(channel_id_); @@ -350,7 +351,7 @@ class GetChannelParticipantQuery final : public Td::ResultHandler { auto participant = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetChannelParticipantQuery: " << to_string(participant); - td_->contacts_manager_->on_get_users(std::move(participant->users_), "GetChannelParticipantQuery"); + td_->user_manager_->on_get_users(std::move(participant->users_), "GetChannelParticipantQuery"); td_->contacts_manager_->on_get_chats(std::move(participant->chats_), "GetChannelParticipantQuery"); DialogParticipant result(std::move(participant->participant_), td_->contacts_manager_->get_channel_type(channel_id_)); @@ -744,7 +745,7 @@ class CanEditChannelCreatorQuery final : public Td::ResultHandler { } void send() { - auto r_input_user = td_->contacts_manager_->get_input_user(td_->contacts_manager_->get_my_id()); + auto r_input_user = td_->user_manager_->get_input_user(td_->user_manager_->get_my_id()); CHECK(r_input_user.is_ok()); send_query(G()->net_query_creator().create(telegram_api::channels_editCreator( telegram_api::make_object(), r_input_user.move_as_ok(), @@ -784,7 +785,7 @@ class EditChannelCreatorQuery final : public Td::ResultHandler { if (input_channel == nullptr) { return promise_.set_error(Status::Error(400, "Have no access to the chat")); } - TRY_RESULT_PROMISE(promise_, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise_, input_user, td_->user_manager_->get_input_user(user_id)); send_query(G()->net_query_creator().create( telegram_api::channels_editCreator(std::move(input_channel), std::move(input_user), std::move(input_check_password)), @@ -1059,8 +1060,8 @@ void DialogParticipantManager::update_dialog_online_member_count(const vectorcontacts_manager_->is_user_deleted(user_id) && !td_->contacts_manager_->is_user_bot(user_id)) { - if (td_->contacts_manager_->is_user_online(user_id, 0, unix_time)) { + if (!td_->user_manager_->is_user_deleted(user_id) && !td_->user_manager_->is_user_bot(user_id)) { + if (td_->user_manager_->is_user_online(user_id, 0, unix_time)) { online_member_count++; } if (is_from_server) { @@ -1183,7 +1184,7 @@ void DialogParticipantManager::speculative_update_dialog_administrators(DialogId td_api::object_ptr DialogParticipantManager::get_chat_administrators_object( const vector &dialog_administrators) { auto administrator_objects = transform(dialog_administrators, [this](const DialogAdministrator &administrator) { - return administrator.get_chat_administrator_object(td_->contacts_manager_.get()); + return administrator.get_chat_administrator_object(td_->user_manager_.get()); }); return td_api::make_object(std::move(administrator_objects)); } @@ -1259,7 +1260,7 @@ void DialogParticipantManager::on_load_dialog_administrators_from_database( auto lock_promise = load_users_multipromise.get_promise(); for (auto &administrator : administrators) { - td_->contacts_manager_->get_user(administrator.get_user_id(), 3, load_users_multipromise.get_promise()); + td_->user_manager_->get_user(administrator.get_user_id(), 3, load_users_multipromise.get_promise()); } lock_promise.set_value(Unit()); @@ -1377,25 +1378,24 @@ void DialogParticipantManager::send_update_chat_member(DialogId dialog_id, UserI send_closure(G()->td(), &Td::send_update, td_api::make_object( td_->dialog_manager_->get_chat_id_object(dialog_id, "updateChatMember"), - td_->contacts_manager_->get_user_id_object(agent_user_id, "updateChatMember"), date, - invite_link.get_chat_invite_link_object(td_->contacts_manager_.get()), via_dialog_filter_invite_link, + td_->user_manager_->get_user_id_object(agent_user_id, "updateChatMember"), date, + invite_link.get_chat_invite_link_object(td_->user_manager_.get()), via_dialog_filter_invite_link, td_->contacts_manager_->get_chat_member_object(old_dialog_participant, "updateChatMember old"), td_->contacts_manager_->get_chat_member_object(new_dialog_participant, "updateChatMember new"))); } void DialogParticipantManager::on_update_bot_stopped(UserId user_id, int32 date, bool is_stopped, bool force) { CHECK(td_->auth_manager_->is_bot()); - if (date <= 0 || !td_->contacts_manager_->have_user_force(user_id, "on_update_bot_stopped")) { + if (date <= 0 || !td_->user_manager_->have_user_force(user_id, "on_update_bot_stopped")) { LOG(ERROR) << "Receive invalid updateBotStopped by " << user_id << " at " << date; return; } - auto my_user_id = td_->contacts_manager_->get_my_id(); - if (!td_->contacts_manager_->have_user_force(my_user_id, "on_update_bot_stopped 2")) { + auto my_user_id = td_->user_manager_->get_my_id(); + if (!td_->user_manager_->have_user_force(my_user_id, "on_update_bot_stopped 2")) { if (!force) { - td_->contacts_manager_->get_me( - PromiseCreator::lambda([actor_id = actor_id(this), user_id, date, is_stopped](Unit) { - send_closure(actor_id, &DialogParticipantManager::on_update_bot_stopped, user_id, date, is_stopped, true); - })); + td_->user_manager_->get_me(PromiseCreator::lambda([actor_id = actor_id(this), user_id, date, is_stopped](Unit) { + send_closure(actor_id, &DialogParticipantManager::on_update_bot_stopped, user_id, date, is_stopped, true); + })); return; } LOG(ERROR) << "Have no self-user to process updateBotStopped"; @@ -1449,7 +1449,7 @@ void DialogParticipantManager::on_update_chat_participant( LOG(ERROR) << "Receive wrong updateChatParticipant: " << old_dialog_participant << " -> " << new_dialog_participant; return; } - if (new_dialog_participant.dialog_id_ == DialogId(td_->contacts_manager_->get_my_id()) && + if (new_dialog_participant.dialog_id_ == DialogId(td_->user_manager_->get_my_id()) && new_dialog_participant.status_ != chat_status && false) { LOG(ERROR) << "Have status " << chat_status << " after receiving updateChatParticipant in " << chat_id << " by " << user_id << " at " << date << " from " << old_dialog_participant << " to " << new_dialog_participant; @@ -1495,7 +1495,7 @@ void DialogParticipantManager::on_update_channel_participant( << new_dialog_participant; return; } - if (new_dialog_participant.status_.is_administrator() && user_id == td_->contacts_manager_->get_my_id() && + if (new_dialog_participant.status_.is_administrator() && user_id == td_->user_manager_->get_my_id() && !new_dialog_participant.status_.can_be_edited()) { LOG(ERROR) << "Fix wrong can_be_edited in " << new_dialog_participant << " from " << channel_id << " changed from " << old_dialog_participant; @@ -1524,7 +1524,7 @@ void DialogParticipantManager::on_update_channel_participant( void DialogParticipantManager::on_update_chat_invite_requester(DialogId dialog_id, UserId user_id, string about, int32 date, DialogInviteLink invite_link) { CHECK(td_->auth_manager_->is_bot()); - if (date <= 0 || !td_->contacts_manager_->have_user_force(user_id, "on_update_chat_invite_requester") || + if (date <= 0 || !td_->user_manager_->have_user_force(user_id, "on_update_chat_invite_requester") || !td_->dialog_manager_->have_dialog_info_force(dialog_id, "on_update_chat_invite_requester")) { LOG(ERROR) << "Receive invalid updateBotChatInviteRequester by " << user_id << " in " << dialog_id << " at " << date; @@ -1538,9 +1538,9 @@ void DialogParticipantManager::on_update_chat_invite_requester(DialogId dialog_i td_api::make_object( td_->dialog_manager_->get_chat_id_object(dialog_id, "updateNewChatJoinRequest"), td_api::make_object( - td_->contacts_manager_->get_user_id_object(user_id, "updateNewChatJoinRequest"), date, about), + td_->user_manager_->get_user_id_object(user_id, "updateNewChatJoinRequest"), date, about), td_->dialog_manager_->get_chat_id_object(user_dialog_id, "updateNewChatJoinRequest 2"), - invite_link.get_chat_invite_link_object(td_->contacts_manager_.get()))); + invite_link.get_chat_invite_link_object(td_->user_manager_.get()))); } void DialogParticipantManager::get_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id, @@ -1560,7 +1560,7 @@ void DialogParticipantManager::finish_get_dialog_participant( auto participant_dialog_id = dialog_participant.dialog_id_; bool is_user = participant_dialog_id.get_type() == DialogType::User; - if ((is_user && !td_->contacts_manager_->have_user(participant_dialog_id.get_user_id())) || + if ((is_user && !td_->user_manager_->have_user(participant_dialog_id.get_user_id())) || (!is_user && !td_->messages_manager_->have_dialog(participant_dialog_id))) { return promise.set_error(Status::Error(400, "Member not found")); } @@ -1578,7 +1578,7 @@ void DialogParticipantManager::do_get_dialog_participant(DialogId dialog_id, Dia switch (dialog_id.get_type()) { case DialogType::User: { - auto my_user_id = td_->contacts_manager_->get_my_id(); + auto my_user_id = td_->user_manager_->get_my_id(); auto peer_user_id = dialog_id.get_user_id(); if (participant_dialog_id == DialogId(my_user_id)) { return promise.set_value(DialogParticipant::private_member(my_user_id, peer_user_id)); @@ -1598,8 +1598,8 @@ void DialogParticipantManager::do_get_dialog_participant(DialogId dialog_id, Dia case DialogType::Channel: return get_channel_participant(dialog_id.get_channel_id(), participant_dialog_id, std::move(promise)); case DialogType::SecretChat: { - auto my_user_id = td_->contacts_manager_->get_my_id(); - auto peer_user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + auto my_user_id = td_->user_manager_->get_my_id(); + auto peer_user_id = td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (participant_dialog_id == DialogId(my_user_id)) { return promise.set_value(DialogParticipant::private_member(my_user_id, peer_user_id)); } @@ -1675,8 +1675,7 @@ std::pair> DialogParticipantManager::search_among_dialog hints.add(dialog_id.get(), td_->dialog_manager_->get_dialog_search_text(dialog_id)); } if (dialog_id.get_type() == DialogType::User) { - hints.set_rating(dialog_id.get(), - -td_->contacts_manager_->get_user_was_online(dialog_id.get_user_id(), unix_time)); + hints.set_rating(dialog_id.get(), -td_->user_manager_->get_user_was_online(dialog_id.get_user_id(), unix_time)); } } @@ -1687,7 +1686,7 @@ std::pair> DialogParticipantManager::search_among_dialog DialogParticipants DialogParticipantManager::search_private_chat_participants(UserId peer_user_id, const string &query, int32 limit, DialogParticipantFilter filter) const { - auto my_user_id = td_->contacts_manager_->get_my_id(); + auto my_user_id = td_->user_manager_->get_my_id(); vector dialog_ids; if (filter.is_dialog_participant_suitable(td_, DialogParticipant::private_member(my_user_id, peer_user_id))) { dialog_ids.push_back(DialogId(my_user_id)); @@ -1798,7 +1797,7 @@ void DialogParticipantManager::on_get_channel_participants( Promise &&promise) { TRY_STATUS_PROMISE(promise, G()->close_status()); - td_->contacts_manager_->on_get_users(std::move(channel_participants->users_), "on_get_channel_participants"); + td_->user_manager_->on_get_users(std::move(channel_participants->users_), "on_get_channel_participants"); td_->contacts_manager_->on_get_chats(std::move(channel_participants->chats_), "on_get_channel_participants"); int32 total_count = channel_participants->count_; auto participants = std::move(channel_participants->participants_); @@ -1819,15 +1818,15 @@ void DialogParticipantManager::on_get_channel_participants( if (participant.dialog_id_.get_type() == DialogType::User) { participant_user_id = participant.dialog_id_.get_user_id(); } - if (!participant.is_valid() || (filter.is_bots() && !td_->contacts_manager_->is_user_bot(participant_user_id)) || + if (!participant.is_valid() || (filter.is_bots() && !td_->user_manager_->is_user_bot(participant_user_id)) || (filter.is_administrators() && !participant.status_.is_administrator()) || ((filter.is_recent() || filter.is_contacts() || filter.is_search()) && !participant.status_.is_member()) || - (filter.is_contacts() && !td_->contacts_manager_->is_user_contact(participant_user_id)) || + (filter.is_contacts() && !td_->user_manager_->is_user_contact(participant_user_id)) || (filter.is_restricted() && !participant.status_.is_restricted()) || (filter.is_banned() && !participant.status_.is_banned())) { bool skip_error = ((filter.is_administrators() || filter.is_bots()) && - td_->contacts_manager_->is_user_deleted(participant_user_id)) || - (filter.is_contacts() && participant_user_id == td_->contacts_manager_->get_my_id()); + td_->user_manager_->is_user_deleted(participant_user_id)) || + (filter.is_contacts() && participant_user_id == td_->user_manager_->get_my_id()); if (!skip_error) { LOG(ERROR) << "Receive " << participant << ", while searching for " << filter << " in " << channel_id << " with offset " << offset << " and limit " << limit << ": " << oneline(debug_participant); @@ -1868,7 +1867,7 @@ void DialogParticipantManager::on_get_channel_participants( administrators.emplace_back(participant_user_id, participant.status_.get_rank(), participant.status_.is_creator()); } - if (is_full_recent && td_->contacts_manager_->is_user_bot(participant_user_id)) { + if (is_full_recent && td_->user_manager_->is_user_bot(participant_user_id)) { bot_user_ids.push_back(participant_user_id); } } @@ -1971,7 +1970,7 @@ void DialogParticipantManager::search_dialog_participants(DialogId dialog_id, co } } case DialogType::SecretChat: { - auto peer_user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + auto peer_user_id = td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); return promise.set_value(search_private_chat_participants(peer_user_id, query, limit, filter)); } case DialogType::None: @@ -2098,7 +2097,7 @@ void DialogParticipantManager::leave_dialog(DialogId dialog_id, Promise && case DialogType::User: return promise.set_error(Status::Error(400, "Can't leave private chats")); case DialogType::Chat: - return delete_chat_participant(dialog_id.get_chat_id(), td_->contacts_manager_->get_my_id(), false, + return delete_chat_participant(dialog_id.get_chat_id(), td_->user_manager_->get_my_id(), false, std::move(promise)); case DialogType::Channel: { auto channel_id = dialog_id.get_channel_id(); @@ -2128,7 +2127,7 @@ void DialogParticipantManager::add_chat_participant(ChatId chat_id, UserId user_ return promise.set_error(Status::Error(400, "Can't forward negative number of messages")); } auto permissions = td_->contacts_manager_->get_chat_permissions(chat_id); - if (user_id != td_->contacts_manager_->get_my_id()) { + if (user_id != td_->user_manager_->get_my_id()) { if (!permissions.can_invite_users()) { return promise.set_error(Status::Error(400, "Not enough rights to invite members to the group chat")); } @@ -2137,7 +2136,7 @@ void DialogParticipantManager::add_chat_participant(ChatId chat_id, UserId user_ } // TODO upper bound on forward_limit - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); // TODO invoke after td_->create_handler(std::move(promise)) @@ -2191,7 +2190,7 @@ void DialogParticipantManager::set_chat_participant_status(ChatId chat_id, UserI return promise.set_error(Status::Error(400, "Need owner rights in the group chat")); } - if (user_id == td_->contacts_manager_->get_my_id()) { + if (user_id == td_->user_manager_->get_my_id()) { return promise.set_error(Status::Error(400, "Can't promote or demote self")); } @@ -2216,7 +2215,7 @@ void DialogParticipantManager::set_chat_participant_status(ChatId chat_id, UserI void DialogParticipantManager::send_edit_chat_admin_query(ChatId chat_id, UserId user_id, bool is_administrator, Promise &&promise) { TRY_STATUS_PROMISE(promise, G()->close_status()); - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); td_->create_handler(std::move(promise)) ->send(chat_id, user_id, std::move(input_user), is_administrator); @@ -2231,7 +2230,7 @@ void DialogParticipantManager::delete_chat_participant(ChatId chat_id, UserId us return promise.set_error(Status::Error(400, "Chat is deactivated")); } - auto my_id = td_->contacts_manager_->get_my_id(); + auto my_id = td_->user_manager_->get_my_id(); auto permissions = td_->contacts_manager_->get_chat_permissions(chat_id); if (permissions.is_left()) { if (user_id == my_id) { @@ -2268,7 +2267,7 @@ void DialogParticipantManager::delete_chat_participant(ChatId chat_id, UserId us } } */ - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); // TODO invoke after td_->create_handler(std::move(promise))->send(chat_id, std::move(input_user), revoke_messages); @@ -2284,9 +2283,9 @@ void DialogParticipantManager::add_channel_participant(ChannelId channel_id, Use if (!td_->contacts_manager_->have_channel(channel_id)) { return promise.set_error(Status::Error(400, "Chat info not found")); } - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); - if (user_id == td_->contacts_manager_->get_my_id()) { + if (user_id == td_->user_manager_->get_my_id()) { // join the channel auto my_status = td_->contacts_manager_->get_channel_status(channel_id); if (my_status.is_banned()) { @@ -2354,9 +2353,9 @@ void DialogParticipantManager::add_channel_participants(ChannelId channel_id, co vector> input_users; for (auto user_id : user_ids) { - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); - if (user_id == td_->contacts_manager_->get_my_id()) { + if (user_id == td_->user_manager_->get_my_id()) { // can't invite self continue; } @@ -2436,13 +2435,13 @@ void DialogParticipantManager::set_channel_participant_status_impl(ChannelId cha if (!new_status.is_creator()) { return promise.set_error(Status::Error(400, "Can't remove chat owner")); } - auto user_id = td_->contacts_manager_->get_my_id(); + auto user_id = td_->user_manager_->get_my_id(); if (participant_dialog_id != DialogId(user_id)) { return promise.set_error(Status::Error(400, "Not enough rights to edit chat owner rights")); } if (new_status.is_member() == old_status.is_member()) { // change rank and is_anonymous - auto r_input_user = td_->contacts_manager_->get_input_user(user_id); + auto r_input_user = td_->user_manager_->get_input_user(user_id); CHECK(r_input_user.is_ok()); td_->create_handler(std::move(promise)) ->send(channel_id, user_id, r_input_user.move_as_ok(), new_status); @@ -2507,7 +2506,7 @@ void DialogParticipantManager::promote_channel_participant(ChannelId channel_id, const DialogParticipantStatus &old_status, Promise &&promise) { LOG(INFO) << "Promote " << user_id << " in " << channel_id << " from " << old_status << " to " << new_status; - if (user_id == td_->contacts_manager_->get_my_id()) { + if (user_id == td_->user_manager_->get_my_id()) { if (new_status.is_administrator()) { return promise.set_error(Status::Error(400, "Can't promote self")); } @@ -2522,7 +2521,7 @@ void DialogParticipantManager::promote_channel_participant(ChannelId channel_id, CHECK(!new_status.is_creator()); } - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); speculative_add_channel_user(channel_id, user_id, new_status, old_status); td_->create_handler(std::move(promise)) @@ -2681,7 +2680,7 @@ void DialogParticipantManager::send_update_add_chat_members_privacy_forbidden(Di send_closure(G()->td(), &Td::send_update, td_api::make_object( td_->dialog_manager_->get_chat_id_object(dialog_id, "updateAddChatMembersPrivacyForbidden"), - td_->contacts_manager_->get_user_ids_object(user_ids, source))); + td_->user_manager_->get_user_ids_object(user_ids, source))); } void DialogParticipantManager::on_channel_participant_cache_timeout_callback(void *dialog_participant_manager_ptr, @@ -2863,7 +2862,7 @@ void DialogParticipantManager::update_cached_channel_participant_status(ChannelI } } if (!is_found && status.is_member()) { - participants.emplace_back(DialogId(user_id), td_->contacts_manager_->get_my_id(), G()->unix_time(), status); + participants.emplace_back(DialogId(user_id), td_->user_manager_->get_my_id(), G()->unix_time(), status); update_channel_online_member_count(channel_id, false); } } @@ -2925,13 +2924,13 @@ void DialogParticipantManager::transfer_dialog_ownership(DialogId dialog_id, Use if (!td_->dialog_manager_->have_dialog_force(dialog_id, "transfer_dialog_ownership")) { return promise.set_error(Status::Error(400, "Chat not found")); } - if (!td_->contacts_manager_->have_user_force(user_id, "transfer_dialog_ownership")) { + if (!td_->user_manager_->have_user_force(user_id, "transfer_dialog_ownership")) { return promise.set_error(Status::Error(400, "User not found")); } - if (td_->contacts_manager_->is_user_bot(user_id)) { + if (td_->user_manager_->is_user_bot(user_id)) { return promise.set_error(Status::Error(400, "User is a bot")); } - if (td_->contacts_manager_->is_user_deleted(user_id)) { + if (td_->user_manager_->is_user_deleted(user_id)) { return promise.set_error(Status::Error(400, "User is deleted")); } if (password.empty()) { diff --git a/td/telegram/DraftMessage.cpp b/td/telegram/DraftMessage.cpp index 91eda7e92..7e1447dc7 100644 --- a/td/telegram/DraftMessage.cpp +++ b/td/telegram/DraftMessage.cpp @@ -57,7 +57,7 @@ class SaveDraftMessageQuery final : public Td::ResultHandler { flags |= telegram_api::messages_saveDraft::INVERT_MEDIA_MASK; } input_message_entities = get_input_message_entities( - td_->contacts_manager_.get(), draft_message->input_message_text_.text.entities, "SaveDraftMessageQuery"); + td_->user_manager_.get(), draft_message->input_message_text_.text.entities, "SaveDraftMessageQuery"); if (!input_message_entities.empty()) { flags |= telegram_api::messages_saveDraft::ENTITIES_MASK; } @@ -409,8 +409,7 @@ DraftMessage::DraftMessage(Td *td, telegram_api::object_ptrdate_; message_input_reply_to_ = MessageInputReplyTo(td, std::move(draft_message->reply_to_)); - auto entities = - get_message_entities(td->contacts_manager_.get(), std::move(draft_message->entities_), "draftMessage"); + auto entities = get_message_entities(td->user_manager_.get(), std::move(draft_message->entities_), "draftMessage"); auto status = fix_formatted_text(draft_message->message_, entities, true, true, true, true, true); if (status.is_error()) { LOG(ERROR) << "Receive error " << status << " while parsing draft " << draft_message->message_; diff --git a/td/telegram/FileReferenceManager.cpp b/td/telegram/FileReferenceManager.cpp index 9d8cb156d..529a1d25d 100644 --- a/td/telegram/FileReferenceManager.cpp +++ b/td/telegram/FileReferenceManager.cpp @@ -21,6 +21,7 @@ #include "td/telegram/StickersManager.h" #include "td/telegram/StoryManager.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" #include "td/telegram/WebPageId.h" #include "td/telegram/WebPagesManager.h" @@ -324,7 +325,7 @@ void FileReferenceManager::send_query(Destination dest, FileSourceId file_source std::move(promise), "FileSourceMessage", nullptr); }, [&](const FileSourceUserPhoto &source) { - send_closure_later(G()->contacts_manager(), &ContactsManager::reload_user_profile_photo, source.user_id, + send_closure_later(G()->user_manager(), &UserManager::reload_user_profile_photo, source.user_id, source.photo_id, std::move(promise)); }, [&](const FileSourceChatPhoto &source) { @@ -376,8 +377,8 @@ void FileReferenceManager::send_query(Destination dest, FileSourceId file_source std::move(promise)); }, [&](const FileSourceUserFull &source) { - send_closure_later(G()->contacts_manager(), &ContactsManager::reload_user_full, source.user_id, - std::move(promise), "FileSourceUserFull"); + send_closure_later(G()->user_manager(), &UserManager::reload_user_full, source.user_id, std::move(promise), + "FileSourceUserFull"); }, [&](const FileSourceAttachMenuBot &source) { send_closure_later(G()->attach_menu_manager(), &AttachMenuManager::reload_attach_menu_bot, source.user_id, diff --git a/td/telegram/FileReferenceManager.hpp b/td/telegram/FileReferenceManager.hpp index cef314f1e..4a539f004 100644 --- a/td/telegram/FileReferenceManager.hpp +++ b/td/telegram/FileReferenceManager.hpp @@ -24,6 +24,7 @@ #include "td/telegram/StoryManager.h" #include "td/telegram/Td.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" #include "td/telegram/WebPagesManager.h" #include "td/utils/common.h" @@ -82,7 +83,7 @@ FileSourceId FileReferenceManager::parse_file_source(Td *td, ParserT &parser) { int64 photo_id; td::parse(user_id, parser); td::parse(photo_id, parser); - return td->contacts_manager_->get_user_profile_photo_file_source_id(user_id, photo_id); + return td->user_manager_->get_user_profile_photo_file_source_id(user_id, photo_id); } case 2: { ChatId chat_id; @@ -134,7 +135,7 @@ FileSourceId FileReferenceManager::parse_file_source(Td *td, ParserT &parser) { case 14: { UserId user_id; td::parse(user_id, parser); - return td->contacts_manager_->get_user_full_file_source_id(user_id); + return td->user_manager_->get_user_full_file_source_id(user_id); } case 15: { UserId user_id; diff --git a/td/telegram/ForumTopicManager.cpp b/td/telegram/ForumTopicManager.cpp index 878a9a1c0..a64e71236 100644 --- a/td/telegram/ForumTopicManager.cpp +++ b/td/telegram/ForumTopicManager.cpp @@ -29,6 +29,7 @@ #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -316,7 +317,7 @@ class GetForumTopicQuery final : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetForumTopicQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetForumTopicQuery"); + td_->user_manager_->on_get_users(std::move(ptr->users_), "GetForumTopicQuery"); td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetForumTopicQuery"); if (ptr->topics_.size() != 1u) { @@ -386,7 +387,7 @@ class GetForumTopicsQuery final : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetForumTopicsQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetForumTopicsQuery"); + td_->user_manager_->on_get_users(std::move(ptr->users_), "GetForumTopicsQuery"); td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetForumTopicsQuery"); MessagesInfo messages_info; diff --git a/td/telegram/Game.cpp b/td/telegram/Game.cpp index c275b54c8..9150a992d 100644 --- a/td/telegram/Game.cpp +++ b/td/telegram/Game.cpp @@ -7,13 +7,13 @@ #include "td/telegram/Game.h" #include "td/telegram/AnimationsManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Document.h" #include "td/telegram/DocumentsManager.h" #include "td/telegram/misc.h" #include "td/telegram/Photo.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/common.h" #include "td/utils/logging.h" @@ -91,7 +91,7 @@ bool Game::has_input_media() const { } tl_object_ptr Game::get_input_media_game(const Td *td) const { - auto input_user = td->contacts_manager_->get_input_user_force(bot_user_id_); + auto input_user = td->user_manager_->get_input_user_force(bot_user_id_); return make_tl_object( make_tl_object(std::move(input_user), short_name_)); } @@ -113,14 +113,14 @@ StringBuilder &operator<<(StringBuilder &string_builder, const Game &game) { << ", photo = " << game.photo_ << ", animation_file_id = " << game.animation_file_id_ << "]"; } -Result process_input_message_game(const ContactsManager *contacts_manager, +Result process_input_message_game(const UserManager *user_manager, tl_object_ptr &&input_message_content) { CHECK(input_message_content != nullptr); CHECK(input_message_content->get_id() == td_api::inputMessageGame::ID); auto input_message_game = move_tl_object_as(input_message_content); UserId bot_user_id(input_message_game->bot_user_id_); - TRY_STATUS(contacts_manager->get_input_user(bot_user_id)); + TRY_STATUS(user_manager->get_input_user(bot_user_id)); if (!clean_input_string(input_message_game->game_short_name_)) { return Status::Error(400, "Game short name must be encoded in UTF-8"); diff --git a/td/telegram/Game.h b/td/telegram/Game.h index f728b2337..4178981eb 100644 --- a/td/telegram/Game.h +++ b/td/telegram/Game.h @@ -20,7 +20,7 @@ namespace td { -class ContactsManager; +class UserManager; class Td; class Game { @@ -79,7 +79,7 @@ bool operator!=(const Game &lhs, const Game &rhs); StringBuilder &operator<<(StringBuilder &string_builder, const Game &game); -Result process_input_message_game(const ContactsManager *contacts_manager, +Result process_input_message_game(const UserManager *user_manager, tl_object_ptr &&input_message_content) TD_WARN_UNUSED_RESULT; diff --git a/td/telegram/GameManager.cpp b/td/telegram/GameManager.cpp index bbbff97f4..f7ba167f0 100644 --- a/td/telegram/GameManager.cpp +++ b/td/telegram/GameManager.cpp @@ -9,7 +9,6 @@ #include "td/telegram/AccessRights.h" #include "td/telegram/AuthManager.h" #include "td/telegram/ChainId.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DialogId.h" #include "td/telegram/DialogManager.h" #include "td/telegram/Global.h" @@ -21,6 +20,7 @@ #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/utils/buffer.h" #include "td/utils/logging.h" @@ -212,7 +212,7 @@ void GameManager::set_game_score(MessageFullId message_full_id, bool edit_messag return promise.set_error(Status::Error(400, "Can't access the chat")); } - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); if (!td_->messages_manager_->can_set_game_score(message_full_id)) { return promise.set_error(Status::Error(400, "Game score can't be set")); @@ -243,7 +243,7 @@ void GameManager::set_inline_game_score(const string &inline_message_id, bool ed return promise.set_error(Status::Error(400, "Invalid inline message identifier specified")); } - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); td_->create_handler(std::move(promise)) ->send(std::move(input_bot_inline_message_id), edit_message, std::move(input_user), score, force); @@ -266,7 +266,7 @@ void GameManager::get_game_high_scores(MessageFullId message_full_id, UserId use return promise.set_error(Status::Error(400, "Wrong message identifier specified")); } - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); td_->create_handler(std::move(promise))->send(dialog_id, message_id, std::move(input_user)); } @@ -280,7 +280,7 @@ void GameManager::get_inline_game_high_scores(const string &inline_message_id, U return promise.set_error(Status::Error(400, "Invalid inline message identifier specified")); } - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); td_->create_handler(std::move(promise)) ->send(std::move(input_bot_inline_message_id), std::move(input_user)); @@ -288,7 +288,7 @@ void GameManager::get_inline_game_high_scores(const string &inline_message_id, U td_api::object_ptr GameManager::get_game_high_scores_object( telegram_api::object_ptr &&high_scores) { - td_->contacts_manager_->on_get_users(std::move(high_scores->users_), "get_game_high_scores_object"); + td_->user_manager_->on_get_users(std::move(high_scores->users_), "get_game_high_scores_object"); auto result = td_api::make_object(); for (const auto &high_score : high_scores->scores_) { @@ -300,7 +300,7 @@ td_api::object_ptr GameManager::get_game_high_scores_obj continue; } result->scores_.push_back(make_tl_object( - position, td_->contacts_manager_->get_user_id_object(user_id, "get_game_high_scores_object"), score)); + position, td_->user_manager_->get_user_id_object(user_id, "get_game_high_scores_object"), score)); } return result; } diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index cf5b93dc8..3dabc1889 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -24,6 +24,7 @@ #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -141,7 +142,7 @@ class GetGroupCallJoinAsQuery final : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetGroupCallJoinAsQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetGroupCallJoinAsQuery"); + td_->user_manager_->on_get_users(std::move(ptr->users_), "GetGroupCallJoinAsQuery"); td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetGroupCallJoinAsQuery"); promise_.set_value(convert_message_senders_object(td_, ptr->peers_)); @@ -1460,7 +1461,7 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i load_group_call_queries_.erase(it); if (result.is_ok()) { - td_->contacts_manager_->on_get_users(std::move(result.ok_ref()->users_), "finish_get_group_call"); + td_->user_manager_->on_get_users(std::move(result.ok_ref()->users_), "finish_get_group_call"); td_->contacts_manager_->on_get_chats(std::move(result.ok_ref()->chats_), "finish_get_group_call"); if (update_group_call(result.ok()->call_, DialogId()) != input_group_call_id) { @@ -1605,7 +1606,7 @@ void GroupCallManager::on_get_group_call_participants( LOG(INFO) << "Receive group call participants: " << to_string(participants); CHECK(participants != nullptr); - td_->contacts_manager_->on_get_users(std::move(participants->users_), "on_get_group_call_participants"); + td_->user_manager_->on_get_users(std::move(participants->users_), "on_get_group_call_participants"); td_->contacts_manager_->on_get_chats(std::move(participants->chats_), "on_get_group_call_participants"); if (!need_group_call_participants(input_group_call_id)) { @@ -2642,7 +2643,7 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di if (as_dialog_id != my_dialog_id) { return promise.set_error(Status::Error(400, "Can't join voice chat as another user")); } - if (!td_->contacts_manager_->have_user_force(as_dialog_id.get_user_id(), "join_group_call")) { + if (!td_->user_manager_->have_user_force(as_dialog_id.get_user_id(), "join_group_call")) { have_as_dialog_id = false; } } else { @@ -3520,9 +3521,9 @@ void GroupCallManager::invite_group_call_participants(GroupCallId group_call_id, TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); vector> input_users; - auto my_user_id = td_->contacts_manager_->get_my_id(); + auto my_user_id = td_->user_manager_->get_my_id(); for (auto user_id : user_ids) { - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); if (user_id == my_user_id) { // can't invite self diff --git a/td/telegram/InlineQueriesManager.cpp b/td/telegram/InlineQueriesManager.cpp index a385c10b7..987b5e975 100644 --- a/td/telegram/InlineQueriesManager.cpp +++ b/td/telegram/InlineQueriesManager.cpp @@ -39,6 +39,7 @@ #include "td/telegram/telegram_api.h" #include "td/telegram/ThemeManager.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/telegram/Venue.h" #include "td/telegram/VideosManager.h" #include "td/telegram/VoiceNotesManager.h" @@ -372,14 +373,14 @@ Result> InlineQueriesManager: return Status::Error(400, "Inline message must be non-empty"); } TRY_RESULT(reply_markup, get_reply_markup(std::move(reply_markup_ptr), true, true, false, true)); - auto input_reply_markup = get_input_reply_markup(td_->contacts_manager_.get(), reply_markup); + auto input_reply_markup = get_input_reply_markup(td_->user_manager_.get(), reply_markup); auto constructor_id = input_message_content->get_id(); if (constructor_id == td_api::inputMessageText::ID) { TRY_RESULT(input_message_text, process_input_message_text(td_, td_->dialog_manager_->get_my_dialog_id(), std::move(input_message_content), true)); - auto entities = get_input_message_entities(td_->contacts_manager_.get(), input_message_text.text.entities, - "get_inline_message"); + auto entities = + get_input_message_entities(td_->user_manager_.get(), input_message_text.text.entities, "get_inline_message"); if (!input_message_text.web_page_url.empty()) { int32 flags = 0; if (input_reply_markup != nullptr) { @@ -458,7 +459,7 @@ Result> InlineQueriesManager: if (input_reply_markup != nullptr) { flags |= telegram_api::inputBotInlineMessageMediaAuto::REPLY_MARKUP_MASK; } - auto entities = get_input_message_entities(td_->contacts_manager_.get(), caption.entities, "get_inline_message"); + auto entities = get_input_message_entities(td_->user_manager_.get(), caption.entities, "get_inline_message"); if (!entities.empty()) { flags |= telegram_api::inputBotInlineMessageMediaAuto::ENTITIES_MASK; } @@ -581,8 +582,8 @@ void InlineQueriesManager::answer_inline_query( void InlineQueriesManager::get_simple_web_view_url(UserId bot_user_id, string &&url, const td_api::object_ptr &theme, string &&platform, Promise &&promise) { - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(bot_user_id)); - TRY_RESULT_PROMISE(promise, bot_data, td_->contacts_manager_->get_bot_data(bot_user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(bot_user_id)); + TRY_RESULT_PROMISE(promise, bot_data, td_->user_manager_->get_bot_data(bot_user_id)); td_->create_handler(std::move(promise)) ->send(std::move(input_user), std::move(url), theme, std::move(platform)); @@ -590,14 +591,14 @@ void InlineQueriesManager::get_simple_web_view_url(UserId bot_user_id, string && void InlineQueriesManager::send_web_view_data(UserId bot_user_id, string &&button_text, string &&data, Promise &&promise) const { - TRY_RESULT_PROMISE(promise, bot_data, td_->contacts_manager_->get_bot_data(bot_user_id)); + TRY_RESULT_PROMISE(promise, bot_data, td_->user_manager_->get_bot_data(bot_user_id)); int64 random_id; do { random_id = Random::secure_int64(); } while (random_id == 0); - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(bot_user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(bot_user_id)); td_->create_handler(std::move(promise)) ->send(std::move(input_user), random_id, button_text, data); @@ -776,7 +777,7 @@ Result> InlineQueriesManager:: return r_reply_markup.move_as_error(); } - auto input_reply_markup = get_input_reply_markup(td_->contacts_manager_.get(), r_reply_markup.ok()); + auto input_reply_markup = get_input_reply_markup(td_->user_manager_.get(), r_reply_markup.ok()); int32 flags = 0; if (input_reply_markup != nullptr) { flags |= telegram_api::inputBotInlineMessageGame::REPLY_MARKUP_MASK; @@ -1022,7 +1023,7 @@ uint64 InlineQueriesManager::send_inline_query(UserId bot_user_id, DialogId dial return 0; } - auto r_bot_data = td_->contacts_manager_->get_bot_data(bot_user_id); + auto r_bot_data = td_->user_manager_->get_bot_data(bot_user_id); if (r_bot_data.is_error()) { promise.set_error(r_bot_data.move_as_error()); return 0; @@ -1104,7 +1105,7 @@ void InlineQueriesManager::loop() { auto now = Time::now(); if (now >= next_inline_query_time_) { LOG(INFO) << "Send inline query " << pending_inline_query_->query_hash; - auto r_bot_input_user = td_->contacts_manager_->get_input_user(pending_inline_query_->bot_user_id); + auto r_bot_input_user = td_->user_manager_->get_input_user(pending_inline_query_->bot_user_id); if (r_bot_input_user.is_ok()) { if (!sent_query_.empty()) { LOG(INFO) << "Cancel inline query request"; @@ -1582,7 +1583,7 @@ void InlineQueriesManager::on_get_inline_query_results(DialogId dialog_id, UserI } LOG(INFO) << to_string(results); - td_->contacts_manager_->on_get_users(std::move(results->users_), "on_get_inline_query_results"); + td_->user_manager_->on_get_users(std::move(results->users_), "on_get_inline_query_results"); auto dialog_type = dialog_id.get_type(); bool allow_invoice = dialog_type != DialogType::SecretChat; @@ -2060,7 +2061,7 @@ void InlineQueriesManager::save_recently_used_bots() { value += ','; value_ids += ','; } - value += td_->contacts_manager_->get_user_first_username(bot_user_id); + value += td_->user_manager_->get_user_first_username(bot_user_id); value_ids += to_string(bot_user_id.get()); } G()->td_db()->get_binlog_pmc()->set("recently_used_inline_bot_usernames", value); @@ -2092,7 +2093,7 @@ bool InlineQueriesManager::load_recently_used_bots(Promise &promise) { for (auto it = bot_ids.rbegin(); it != bot_ids.rend(); ++it) { UserId user_id(to_integer(*it)); - if (td_->contacts_manager_->have_user(user_id)) { + if (td_->user_manager_->have_user(user_id)) { update_bot_usage(user_id); } else { LOG(ERROR) << "Can't find " << user_id; @@ -2120,7 +2121,7 @@ bool InlineQueriesManager::load_recently_used_bots(Promise &promise) { } else { for (auto &bot_id : bot_ids) { UserId user_id(to_integer(bot_id)); - td_->contacts_manager_->get_user(user_id, 3, resolve_recent_inline_bots_multipromise_.get_promise()); + td_->user_manager_->get_user(user_id, 3, resolve_recent_inline_bots_multipromise_.get_promise()); } } lock.set_value(Unit()); @@ -2152,7 +2153,7 @@ void InlineQueriesManager::on_new_query(int64 query_id, UserId sender_user_id, L switch (peer_type->get_id()) { case telegram_api::inlineQueryPeerTypeSameBotPM::ID: return td_api::make_object( - td_->contacts_manager_->get_user_id_object(sender_user_id, "inlineQueryPeerTypeSameBotPM")); + td_->user_manager_->get_user_id_object(sender_user_id, "inlineQueryPeerTypeSameBotPM")); case telegram_api::inlineQueryPeerTypeBotPM::ID: case telegram_api::inlineQueryPeerTypePM::ID: return td_api::make_object(0); @@ -2169,7 +2170,7 @@ void InlineQueriesManager::on_new_query(int64 query_id, UserId sender_user_id, L }(); send_closure(G()->td(), &Td::send_update, make_tl_object( - query_id, td_->contacts_manager_->get_user_id_object(sender_user_id, "updateNewInlineQuery"), + query_id, td_->user_manager_->get_user_id_object(sender_user_id, "updateNewInlineQuery"), user_location.get_location_object(), std::move(chat_type), query, offset)); } @@ -2180,14 +2181,14 @@ void InlineQueriesManager::on_chosen_result( LOG(ERROR) << "Receive chosen inline query result from invalid " << user_id; return; } - LOG_IF(ERROR, !td_->contacts_manager_->have_user(user_id)) << "Receive unknown " << user_id; + LOG_IF(ERROR, !td_->user_manager_->have_user(user_id)) << "Receive unknown " << user_id; if (!td_->auth_manager_->is_bot()) { LOG(ERROR) << "Receive chosen inline query result"; return; } send_closure(G()->td(), &Td::send_update, make_tl_object( - td_->contacts_manager_->get_user_id_object(user_id, "updateNewChosenInlineResult"), + td_->user_manager_->get_user_id_object(user_id, "updateNewChosenInlineResult"), user_location.get_location_object(), query, result_id, get_inline_message_id(std::move(input_bot_inline_message_id)))); } @@ -2199,7 +2200,7 @@ bool InlineQueriesManager::update_bot_usage(UserId bot_user_id) { if (!recently_used_bot_user_ids_.empty() && recently_used_bot_user_ids_[0] == bot_user_id) { return false; } - auto r_bot_data = td_->contacts_manager_->get_bot_data(bot_user_id); + auto r_bot_data = td_->user_manager_->get_bot_data(bot_user_id); if (r_bot_data.is_error()) { return false; } diff --git a/td/telegram/LinkManager.cpp b/td/telegram/LinkManager.cpp index bfaa9d40a..a603eb9bb 100644 --- a/td/telegram/LinkManager.cpp +++ b/td/telegram/LinkManager.cpp @@ -11,7 +11,6 @@ #include "td/telegram/ChannelId.h" #include "td/telegram/ChannelType.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DialogId.h" #include "td/telegram/DialogManager.h" #include "td/telegram/DialogParticipant.h" @@ -27,6 +26,7 @@ #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" #include "td/mtproto/ProxySecret.h" @@ -877,13 +877,13 @@ class RequestUrlAuthQuery final : public Td::ResultHandler { switch (result->get_id()) { case telegram_api::urlAuthResultRequest::ID: { auto request = telegram_api::move_object_as(result); - UserId bot_user_id = ContactsManager::get_user_id(request->bot_); + UserId bot_user_id = UserManager::get_user_id(request->bot_); if (!bot_user_id.is_valid()) { return on_error(Status::Error(500, "Receive invalid bot_user_id")); } - td_->contacts_manager_->on_get_user(std::move(request->bot_), "RequestUrlAuthQuery"); + td_->user_manager_->on_get_user(std::move(request->bot_), "RequestUrlAuthQuery"); promise_.set_value(td_api::make_object( - url_, request->domain_, td_->contacts_manager_->get_user_id_object(bot_user_id, "RequestUrlAuthQuery"), + url_, request->domain_, td_->user_manager_->get_user_id_object(bot_user_id, "RequestUrlAuthQuery"), request->request_write_access_)); break; } diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index f4d354f72..22183edd7 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -84,6 +84,7 @@ #include "td/telegram/TopDialogManager.h" #include "td/telegram/TranscriptionManager.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" #include "td/telegram/Venue.h" #include "td/telegram/Version.h" #include "td/telegram/VideoNotesManager.h" @@ -2470,8 +2471,8 @@ InlineMessageContent create_inline_message_content(Td *td, FileId file_id, switch (bot_inline_message->get_id()) { case telegram_api::botInlineMessageText::ID: { auto inline_message = move_tl_object_as(bot_inline_message); - auto entities = get_message_entities(td->contacts_manager_.get(), std::move(inline_message->entities_), - "botInlineMessageText"); + auto entities = + get_message_entities(td->user_manager_.get(), std::move(inline_message->entities_), "botInlineMessageText"); auto status = fix_formatted_text(inline_message->message_, entities, false, true, true, false, false); if (status.is_error()) { LOG(ERROR) << "Receive error " << status << " while parsing botInlineMessageText " << inline_message->message_; @@ -2496,7 +2497,7 @@ InlineMessageContent create_inline_message_content(Td *td, FileId file_id, if (inline_message->manual_) { web_page_url = std::move(inline_message->url_); } - auto entities = get_message_entities(td->contacts_manager_.get(), std::move(inline_message->entities_), + auto entities = get_message_entities(td->user_manager_.get(), std::move(inline_message->entities_), "botInlineMessageMediaWebPage"); auto status = fix_formatted_text(inline_message->message_, entities, !web_page_url.empty(), true, true, false, false); @@ -2554,7 +2555,7 @@ InlineMessageContent create_inline_message_content(Td *td, FileId file_id, case telegram_api::botInlineMessageMediaAuto::ID: { auto inline_message = move_tl_object_as(bot_inline_message); auto caption = - get_message_text(td->contacts_manager_.get(), inline_message->message_, std::move(inline_message->entities_), + get_message_text(td->user_manager_.get(), inline_message->message_, std::move(inline_message->entities_), true, false, 0, false, "create_inline_message_content"); if (allowed_media_content_id == td_api::inputMessageAnimation::ID) { result.message_content = make_unique(file_id, std::move(caption), false); @@ -2791,9 +2792,9 @@ static Result create_input_message_content( break; } case td_api::inputMessageGame::ID: { - TRY_RESULT(game, process_input_message_game(td->contacts_manager_.get(), std::move(input_message_content))); + TRY_RESULT(game, process_input_message_game(td->user_manager_.get(), std::move(input_message_content))); via_bot_user_id = game.get_bot_user_id(); - if (via_bot_user_id == td->contacts_manager_->get_my_id()) { + if (via_bot_user_id == td->user_manager_->get_my_id()) { via_bot_user_id = UserId(); } @@ -3586,18 +3587,18 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten } switch (dialog_type) { case DialogType::User: - return td->contacts_manager_->get_user_default_permissions(dialog_id.get_user_id()); + return td->user_manager_->get_user_default_permissions(dialog_id.get_user_id()); case DialogType::Chat: return td->contacts_manager_->get_chat_permissions(dialog_id.get_chat_id()).get_effective_restricted_rights(); case DialogType::Channel: return td->contacts_manager_->get_channel_permissions(dialog_id.get_channel_id()) .get_effective_restricted_rights(); case DialogType::SecretChat: - return td->contacts_manager_->get_secret_chat_default_permissions(dialog_id.get_secret_chat_id()); + return td->user_manager_->get_secret_chat_default_permissions(dialog_id.get_secret_chat_id()); case DialogType::None: default: UNREACHABLE(); - return td->contacts_manager_->get_user_default_permissions(UserId()); + return td->user_manager_->get_user_default_permissions(UserId()); } }(); @@ -3692,7 +3693,7 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten return Status::Error(400, "Non-anonymous polls can't be sent to channel chats"); } if (dialog_type == DialogType::User && !is_forward && !td->auth_manager_->is_bot() && - !td->contacts_manager_->is_user_bot(dialog_id.get_user_id())) { + !td->user_manager_->is_user_bot(dialog_id.get_user_id())) { return Status::Error(400, "Polls can't be sent to the private chat"); } if (dialog_type == DialogType::SecretChat) { @@ -3735,7 +3736,7 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten return Status::Error(400, "Not enough rights to send video notes to the chat"); } if (dialog_type == DialogType::User && - td->contacts_manager_->get_user_voice_messages_forbidden(dialog_id.get_user_id())) { + td->user_manager_->get_user_voice_messages_forbidden(dialog_id.get_user_id())) { return Status::Error(400, "User restricted receiving of voice messages"); } break; @@ -3744,7 +3745,7 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten return Status::Error(400, "Not enough rights to send voice notes to the chat"); } if (dialog_type == DialogType::User && - td->contacts_manager_->get_user_voice_messages_forbidden(dialog_id.get_user_id())) { + td->user_manager_->get_user_voice_messages_forbidden(dialog_id.get_user_id())) { return Status::Error(400, "User restricted receiving of video messages"); } break; @@ -5397,7 +5398,7 @@ void register_message_content(Td *td, const MessageContent *content, MessageFull return td->stickers_manager_->register_premium_gift(static_cast(content)->months, message_full_id, source); case MessageContentType::SuggestProfilePhoto: - return td->contacts_manager_->register_suggested_profile_photo( + return td->user_manager_->register_suggested_profile_photo( static_cast(content)->photo); case MessageContentType::Story: return td->story_manager_->register_story(static_cast(content)->story_full_id, @@ -6052,8 +6053,8 @@ unique_ptr get_message_content(Td *td, FormattedText message, case telegram_api::messageMediaContact::ID: { auto media = move_tl_object_as(media_ptr); if (media->user_id_ != 0) { - td->contacts_manager_->get_user_id_object(UserId(media->user_id_), - "MessageMediaContact"); // to ensure updateUser + td->user_manager_->get_user_id_object(UserId(media->user_id_), + "MessageMediaContact"); // to ensure updateUser } return make_unique(Contact(std::move(media->phone_number_), std::move(media->first_name_), std::move(media->last_name_), std::move(media->vcard_), @@ -7052,7 +7053,7 @@ tl_object_ptr get_message_content_object(const MessageCo case MessageContentType::ChatCreate: { const auto *m = static_cast(content); return make_tl_object( - m->title, td->contacts_manager_->get_user_ids_object(m->participant_user_ids, "MessageChatCreate")); + m->title, td->user_manager_->get_user_ids_object(m->participant_user_ids, "MessageChatCreate")); } case MessageContentType::ChatChangeTitle: { const auto *m = static_cast(content); @@ -7074,7 +7075,7 @@ tl_object_ptr get_message_content_object(const MessageCo case MessageContentType::ChatAddUsers: { const auto *m = static_cast(content); return make_tl_object( - td->contacts_manager_->get_user_ids_object(m->user_ids, "MessageChatAddUsers")); + td->user_manager_->get_user_ids_object(m->user_ids, "MessageChatAddUsers")); } case MessageContentType::ChatJoinedByLink: { const MessageChatJoinedByLink *m = static_cast(content); @@ -7086,7 +7087,7 @@ tl_object_ptr get_message_content_object(const MessageCo case MessageContentType::ChatDeleteUser: { const auto *m = static_cast(content); return make_tl_object( - td->contacts_manager_->get_user_id_object(m->user_id, "MessageChatDeleteMember")); + td->user_manager_->get_user_id_object(m->user_id, "MessageChatDeleteMember")); } case MessageContentType::ChatMigrateTo: { const auto *m = static_cast(content); @@ -7116,7 +7117,7 @@ tl_object_ptr get_message_content_object(const MessageCo case MessageContentType::ChatSetTtl: { const auto *m = static_cast(content); return make_tl_object( - m->ttl, td->contacts_manager_->get_user_id_object(m->from_user_id, "MessageChatSetTtl")); + m->ttl, td->user_manager_->get_user_id_object(m->from_user_id, "MessageChatSetTtl")); } case MessageContentType::Call: { const auto *m = static_cast(content); @@ -7200,7 +7201,7 @@ tl_object_ptr get_message_content_object(const MessageCo const auto *m = static_cast(content); return make_tl_object( td->group_call_manager_->get_group_call_id(m->input_group_call_id, DialogId()).get(), - td->contacts_manager_->get_user_ids_object(m->user_ids, "MessageInviteToGroupCall")); + td->user_manager_->get_user_ids_object(m->user_ids, "MessageInviteToGroupCall")); } case MessageContentType::ChatSetTheme: { const auto *m = static_cast(content); @@ -7219,9 +7220,9 @@ tl_object_ptr get_message_content_object(const MessageCo int64 gifter_user_id = 0; if (dialog_id.get_type() == DialogType::User) { auto user_id = dialog_id.get_user_id(); - if (user_id != ContactsManager::get_service_notifications_user_id() && - !td->contacts_manager_->is_user_bot(user_id) && !td->contacts_manager_->is_user_support(user_id)) { - gifter_user_id = td->contacts_manager_->get_user_id_object(user_id, "MessageGiftPremium"); + if (user_id != UserManager::get_service_notifications_user_id() && !td->user_manager_->is_user_bot(user_id) && + !td->user_manager_->is_user_support(user_id)) { + gifter_user_id = td->user_manager_->get_user_id_object(user_id, "MessageGiftPremium"); } } return make_tl_object( @@ -7309,7 +7310,7 @@ tl_object_ptr get_message_content_object(const MessageCo td->dialog_manager_->get_chat_id_object(DialogId(m->boosted_channel_id), "messagePremiumGiveawayWinners"), m->giveaway_message_id.get(), m->additional_dialog_count, m->winners_selection_date, m->only_new_subscribers, m->was_refunded, m->month_count, m->prize_description, m->winner_count, - td->contacts_manager_->get_user_ids_object(m->winner_user_ids, "messagePremiumGiveawayWinners"), + td->user_manager_->get_user_ids_object(m->winner_user_ids, "messagePremiumGiveawayWinners"), m->unclaimed_count); } case MessageContentType::ExpiredVideoNote: diff --git a/td/telegram/MessageEntity.cpp b/td/telegram/MessageEntity.cpp index a62b46ba9..41e07ed4c 100644 --- a/td/telegram/MessageEntity.cpp +++ b/td/telegram/MessageEntity.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/MessageEntity.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Dependencies.h" #include "td/telegram/DialogManager.h" #include "td/telegram/LinkManager.h" @@ -15,6 +14,7 @@ #include "td/telegram/SecretChatLayer.h" #include "td/telegram/StickersManager.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" #include "td/actor/MultiPromise.h" @@ -162,7 +162,7 @@ tl_object_ptr MessageEntity::get_text_entity_type_object case MessageEntity::Type::TextUrl: return make_tl_object(argument); case MessageEntity::Type::MentionName: - // can't use contacts_manager, because can be called from a static request + // can't use user_manager, because can be called from a static request return make_tl_object(user_id.get()); case MessageEntity::Type::Cashtag: return make_tl_object(); @@ -3540,7 +3540,7 @@ vector> get_input_secret_message_entiti return result; } -Result> get_message_entities(const ContactsManager *contacts_manager, +Result> get_message_entities(const UserManager *user_manager, vector> &&input_entities, bool allow_all) { vector entities; @@ -3613,8 +3613,8 @@ Result> get_message_entities(const ContactsManager *contac } auto user_id = LinkManager::get_link_user_id(entity->url_); if (user_id.is_valid()) { - if (contacts_manager != nullptr) { - TRY_STATUS(contacts_manager->get_input_user(user_id)); + if (user_manager != nullptr) { + TRY_STATUS(user_manager->get_input_user(user_id)); } entities.emplace_back(offset, length, user_id); break; @@ -3629,8 +3629,8 @@ Result> get_message_entities(const ContactsManager *contac case td_api::textEntityTypeMentionName::ID: { auto entity = static_cast(input_entity->type_.get()); UserId user_id(entity->user_id_); - if (contacts_manager != nullptr) { - TRY_STATUS(contacts_manager->get_input_user(user_id)); + if (user_manager != nullptr) { + TRY_STATUS(user_manager->get_input_user(user_id)); } entities.emplace_back(offset, length, user_id); break; @@ -3666,7 +3666,7 @@ Result> get_message_entities(const ContactsManager *contac return std::move(entities); } -vector get_message_entities(const ContactsManager *contacts_manager, +vector get_message_entities(const UserManager *user_manager, vector> &&server_entities, const char *source) { vector entities; @@ -3777,11 +3777,11 @@ vector get_message_entities(const ContactsManager *contacts_manag LOG(ERROR) << "Receive invalid " << user_id << " in MentionName from " << source; continue; } - if (contacts_manager == nullptr) { + if (user_manager == nullptr) { LOG(ERROR) << "Receive unknown " << user_id << " in MentionName from " << source; continue; } - auto r_input_user = contacts_manager->get_input_user(user_id); + auto r_input_user = user_manager->get_input_user(user_id); if (r_input_user.is_error()) { LOG(ERROR) << "Receive wrong " << user_id << ": " << r_input_user.error() << " from " << source; continue; @@ -3942,18 +3942,19 @@ vector get_message_entities(Td *td, vector get_input_text_with_entities( - const ContactsManager *contacts_manager, const FormattedText &text, const char *source) { +telegram_api::object_ptr get_input_text_with_entities(const UserManager *user_manager, + const FormattedText &text, + const char *source) { return telegram_api::make_object( - text.text, get_input_message_entities(contacts_manager, text.entities, source)); + text.text, get_input_message_entities(user_manager, text.entities, source)); } -FormattedText get_formatted_text(const ContactsManager *contacts_manager, +FormattedText get_formatted_text(const UserManager *user_manager, telegram_api::object_ptr text_with_entities, bool allow_empty, bool skip_new_entities, bool skip_bot_commands, bool skip_media_timestamps, bool skip_trim, const char *source) { CHECK(text_with_entities != nullptr); - auto entities = get_message_entities(contacts_manager, std::move(text_with_entities->entities_), source); + auto entities = get_message_entities(user_manager, std::move(text_with_entities->entities_), source); auto status = fix_formatted_text(text_with_entities->text_, entities, allow_empty, skip_new_entities, skip_bot_commands, skip_media_timestamps, skip_trim); if (status.is_error()) { @@ -4442,11 +4443,11 @@ Status fix_formatted_text(string &text, vector &entities, bool al return Status::OK(); } -FormattedText get_message_text(const ContactsManager *contacts_manager, string message_text, +FormattedText get_message_text(const UserManager *user_manager, string message_text, vector> &&server_entities, bool skip_new_entities, bool skip_media_timestamps, int32 send_date, bool from_album, const char *source) { - auto entities = get_message_entities(contacts_manager, std::move(server_entities), source); + auto entities = get_message_entities(user_manager, std::move(server_entities), source); auto debug_message_text = message_text; auto debug_entities = entities; auto status = fix_formatted_text(message_text, entities, true, skip_new_entities, true, skip_media_timestamps, false); @@ -4528,8 +4529,8 @@ Result get_formatted_text(const Td *td, DialogId dialog_id, return Status::Error(400, "Text must be non-empty"); } - TRY_RESULT(entities, get_message_entities(td->contacts_manager_.get(), std::move(text->entities_))); - auto need_skip_bot_commands = need_always_skip_bot_commands(td->contacts_manager_.get(), dialog_id, is_bot); + TRY_RESULT(entities, get_message_entities(td->user_manager_.get(), std::move(text->entities_))); + auto need_skip_bot_commands = need_always_skip_bot_commands(td->user_manager_.get(), dialog_id, is_bot); bool parse_markdown = td->option_manager_->get_option_boolean("always_parse_markdown"); bool skip_new_entities = is_bot && td->option_manager_->get_option_integer("session_count") > 1; TRY_STATUS(fix_formatted_text(text->text_, entities, allow_empty, skip_new_entities || parse_markdown, @@ -4581,7 +4582,7 @@ bool has_bot_commands(const FormattedText *text) { return false; } -bool need_always_skip_bot_commands(const ContactsManager *contacts_manager, DialogId dialog_id, bool is_bot) { +bool need_always_skip_bot_commands(const UserManager *user_manager, DialogId dialog_id, bool is_bot) { if (!dialog_id.is_valid()) { return true; } @@ -4592,11 +4593,11 @@ bool need_always_skip_bot_commands(const ContactsManager *contacts_manager, Dial switch (dialog_id.get_type()) { case DialogType::User: { auto user_id = dialog_id.get_user_id(); - return user_id == ContactsManager::get_replies_bot_user_id() || !contacts_manager->is_user_bot(user_id); + return user_id == UserManager::get_replies_bot_user_id() || !user_manager->is_user_bot(user_id); } case DialogType::SecretChat: { - auto user_id = contacts_manager->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); - return !user_id.is_valid() || !contacts_manager->is_user_bot(user_id); + auto user_id = user_manager->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + return !user_id.is_valid() || !user_manager->is_user_bot(user_id); } case DialogType::Chat: case DialogType::Channel: @@ -4608,7 +4609,7 @@ bool need_always_skip_bot_commands(const ContactsManager *contacts_manager, Dial } } -vector> get_input_message_entities(const ContactsManager *contacts_manager, +vector> get_input_message_entities(const UserManager *user_manager, const vector &entities, const char *source) { vector> result; @@ -4650,7 +4651,7 @@ vector> get_input_message_entities(co make_tl_object(entity.offset, entity.length, entity.argument)); break; case MessageEntity::Type::MentionName: { - auto input_user = contacts_manager->get_input_user_force(entity.user_id); + auto input_user = user_manager->get_input_user_force(entity.user_id); result.push_back(make_tl_object(entity.offset, entity.length, std::move(input_user))); break; @@ -4690,11 +4691,11 @@ vector> get_input_message_entities(co return result; } -vector> get_input_message_entities(const ContactsManager *contacts_manager, +vector> get_input_message_entities(const UserManager *user_manager, const FormattedText *text, const char *source) { if (text != nullptr && !text->entities.empty()) { - return get_input_message_entities(contacts_manager, text->entities, source); + return get_input_message_entities(user_manager, text->entities, source); } return {}; } @@ -4712,7 +4713,7 @@ void remove_unallowed_entities(const Td *td, FormattedText &text, DialogId dialo } if (dialog_id.get_type() == DialogType::SecretChat) { - auto layer = td->contacts_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); + auto layer = td->user_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); td::remove_if(text.entities, [layer](const MessageEntity &entity) { if (layer < static_cast(SecretChatLayer::NewEntities) && (entity.type == MessageEntity::Type::Underline || entity.type == MessageEntity::Type::Strikethrough || diff --git a/td/telegram/MessageEntity.h b/td/telegram/MessageEntity.h index c5ab5b2d5..be03885f6 100644 --- a/td/telegram/MessageEntity.h +++ b/td/telegram/MessageEntity.h @@ -24,10 +24,10 @@ namespace td { -class ContactsManager; class Dependencies; class MultiPromiseActor; class Td; +class UserManager; class MessageEntity { public: @@ -155,7 +155,7 @@ inline bool operator!=(const FormattedText &lhs, const FormattedText &rhs) { const FlatHashSet &get_valid_short_usernames(); -Result> get_message_entities(const ContactsManager *contacts_manager, +Result> get_message_entities(const UserManager *user_manager, vector> &&input_entities, bool allow_all = false); @@ -201,28 +201,29 @@ FormattedText get_markdown_v3(FormattedText text); Result> parse_html(string &str); -vector> get_input_message_entities(const ContactsManager *contacts_manager, +vector> get_input_message_entities(const UserManager *user_manager, const vector &entities, const char *source); -vector> get_input_message_entities(const ContactsManager *contacts_manager, +vector> get_input_message_entities(const UserManager *user_manager, const FormattedText *text, const char *source); vector> get_input_secret_message_entities( const vector &entities, int32 layer); -vector get_message_entities(const ContactsManager *contacts_manager, +vector get_message_entities(const UserManager *user_manager, vector> &&server_entities, const char *source); vector get_message_entities(Td *td, vector> &&secret_entities, bool is_premium, MultiPromiseActor &load_data_multipromise); -telegram_api::object_ptr get_input_text_with_entities( - const ContactsManager *contacts_manager, const FormattedText &text, const char *source); +telegram_api::object_ptr get_input_text_with_entities(const UserManager *user_manager, + const FormattedText &text, + const char *source); -FormattedText get_formatted_text(const ContactsManager *contacts_manager, +FormattedText get_formatted_text(const UserManager *user_manager, telegram_api::object_ptr text_with_entities, bool allow_empty, bool skip_new_entities, bool skip_bot_commands, bool skip_media_timestamps, bool skip_trim, const char *source); @@ -232,7 +233,7 @@ Status fix_formatted_text(string &text, vector &entities, bool al bool skip_bot_commands, bool skip_media_timestamps, bool skip_trim, int32 *ltrim_count = nullptr) TD_WARN_UNUSED_RESULT; -FormattedText get_message_text(const ContactsManager *contacts_manager, string message_text, +FormattedText get_message_text(const UserManager *user_manager, string message_text, vector> &&server_entities, bool skip_new_entities, bool skip_media_timestamps, int32 send_date, bool from_album, const char *source); @@ -253,6 +254,6 @@ bool has_media_timestamps(const FormattedText *text, int32 min_media_timestamp, bool has_bot_commands(const FormattedText *text); -bool need_always_skip_bot_commands(const ContactsManager *contacts_manager, DialogId dialog_id, bool is_bot); +bool need_always_skip_bot_commands(const UserManager *user_manager, DialogId dialog_id, bool is_bot); } // namespace td diff --git a/td/telegram/MessageForwardInfo.cpp b/td/telegram/MessageForwardInfo.cpp index 9c36cd1f3..4e81a45c7 100644 --- a/td/telegram/MessageForwardInfo.cpp +++ b/td/telegram/MessageForwardInfo.cpp @@ -6,13 +6,13 @@ // #include "td/telegram/MessageForwardInfo.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Dependencies.h" #include "td/telegram/DialogManager.h" #include "td/telegram/MessageSender.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/ServerMessageId.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" #include "td/utils/logging.h" #include "td/utils/misc.h" @@ -33,7 +33,7 @@ void LastForwardedMessageInfo::validate() { void LastForwardedMessageInfo::hide_sender_if_needed(Td *td) { if (sender_name_.empty() && sender_dialog_id_.get_type() == DialogType::User) { - auto private_forward_name = td->contacts_manager_->get_user_private_forward_name(sender_dialog_id_.get_user_id()); + auto private_forward_name = td->user_manager_->get_user_private_forward_name(sender_dialog_id_.get_user_id()); if (!private_forward_name.empty()) { dialog_id_ = DialogId(); message_id_ = MessageId(); diff --git a/td/telegram/MessageImportManager.cpp b/td/telegram/MessageImportManager.cpp index 5ba528efd..44e9b0102 100644 --- a/td/telegram/MessageImportManager.cpp +++ b/td/telegram/MessageImportManager.cpp @@ -16,6 +16,7 @@ #include "td/telegram/MessageContent.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/buffer.h" #include "td/utils/logging.h" @@ -295,7 +296,7 @@ Status MessageImportManager::can_import_messages(DialogId dialog_id) { switch (dialog_id.get_type()) { case DialogType::User: - if (!td_->contacts_manager_->is_user_contact(dialog_id.get_user_id(), true)) { + if (!td_->user_manager_->is_user_contact(dialog_id.get_user_id(), true)) { return Status::Error(400, "User must be a mutual contact"); } break; diff --git a/td/telegram/MessageInputReplyTo.cpp b/td/telegram/MessageInputReplyTo.cpp index a3173024e..625df4255 100644 --- a/td/telegram/MessageInputReplyTo.cpp +++ b/td/telegram/MessageInputReplyTo.cpp @@ -57,8 +57,8 @@ MessageInputReplyTo::MessageInputReplyTo(Td *td, dialog_id_ = dialog_id; if (!reply_to->quote_text_.empty()) { - auto entities = get_message_entities(td->contacts_manager_.get(), std::move(reply_to->quote_entities_), - "inputReplyToMessage"); + auto entities = + get_message_entities(td->user_manager_.get(), std::move(reply_to->quote_entities_), "inputReplyToMessage"); auto status = fix_formatted_text(reply_to->quote_text_, entities, true, true, true, true, false); if (status.is_error()) { if (!clean_input_string(reply_to->quote_text_)) { @@ -120,7 +120,7 @@ telegram_api::object_ptr MessageInputReplyTo::get_in if (!quote_.text.empty()) { flags |= telegram_api::inputReplyToMessage::QUOTE_TEXT_MASK; } - auto quote_entities = get_input_message_entities(td->contacts_manager_.get(), quote_.entities, "get_input_reply_to"); + auto quote_entities = get_input_message_entities(td->user_manager_.get(), quote_.entities, "get_input_reply_to"); if (!quote_entities.empty()) { flags |= telegram_api::inputReplyToMessage::QUOTE_ENTITIES_MASK; } diff --git a/td/telegram/MessageOrigin.cpp b/td/telegram/MessageOrigin.cpp index 9e747063e..463162e54 100644 --- a/td/telegram/MessageOrigin.cpp +++ b/td/telegram/MessageOrigin.cpp @@ -13,6 +13,7 @@ #include "td/telegram/Global.h" #include "td/telegram/ServerMessageId.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" #include "td/utils/logging.h" #include "td/utils/misc.h" @@ -94,7 +95,7 @@ td_api::object_ptr MessageOrigin::get_message_origin_obje sender_name_.empty() ? author_signature_ : sender_name_); } return td_api::make_object( - td->contacts_manager_->get_user_id_object(sender_user_id_, "messageOriginUser")); + td->user_manager_->get_user_id_object(sender_user_id_, "messageOriginUser")); } bool MessageOrigin::is_sender_hidden() const { @@ -121,7 +122,7 @@ DialogId MessageOrigin::get_sender() const { void MessageOrigin::hide_sender_if_needed(Td *td) { if (!is_sender_hidden() && !message_id_.is_valid() && !sender_dialog_id_.is_valid()) { - auto private_forward_name = td->contacts_manager_->get_user_private_forward_name(sender_user_id_); + auto private_forward_name = td->user_manager_->get_user_private_forward_name(sender_user_id_); if (!private_forward_name.empty()) { sender_user_id_ = UserId(); sender_name_ = std::move(private_forward_name); diff --git a/td/telegram/MessageReaction.cpp b/td/telegram/MessageReaction.cpp index 75442e864..4b84e8bd2 100644 --- a/td/telegram/MessageReaction.cpp +++ b/td/telegram/MessageReaction.cpp @@ -17,6 +17,7 @@ #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/actor/actor.h" #include "td/actor/SleepActor.h" @@ -198,7 +199,7 @@ class GetMessageReactionsListQuery final : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetMessageReactionsListQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetMessageReactionsListQuery"); + td_->user_manager_->on_get_users(std::move(ptr->users_), "GetMessageReactionsListQuery"); td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetMessageReactionsListQuery"); int32 total_count = ptr->count_; @@ -516,7 +517,7 @@ unique_ptr MessageReactions::get_message_reactions( auto dialog_type = dialog_id.get_type(); if (dialog_type == DialogType::User) { auto user_id = dialog_id.get_user_id(); - if (!td->contacts_manager_->have_min_user(user_id)) { + if (!td->user_manager_->have_min_user(user_id)) { LOG(ERROR) << "Receive unknown " << user_id; continue; } diff --git a/td/telegram/MessageReplyInfo.cpp b/td/telegram/MessageReplyInfo.cpp index 984d79b06..071f44d86 100644 --- a/td/telegram/MessageReplyInfo.cpp +++ b/td/telegram/MessageReplyInfo.cpp @@ -11,6 +11,7 @@ #include "td/telegram/MessageSender.h" #include "td/telegram/ServerMessageId.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/logging.h" @@ -59,7 +60,7 @@ MessageReplyInfo::MessageReplyInfo(Td *td, tl_object_ptrcontacts_manager_->have_min_user(replier_user_id)) { + if (!td->user_manager_->have_min_user(replier_user_id)) { LOG(ERROR) << "Receive unknown replied " << replier_user_id; continue; } diff --git a/td/telegram/MessageSender.cpp b/td/telegram/MessageSender.cpp index a174d3191..3dbbf8820 100644 --- a/td/telegram/MessageSender.cpp +++ b/td/telegram/MessageSender.cpp @@ -11,6 +11,7 @@ #include "td/telegram/DialogManager.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/logging.h" @@ -27,9 +28,9 @@ td_api::object_ptr get_message_sender_object_const(Td *td if (!user_id.is_valid()) { // can happen only if the server sends a message with wrong sender LOG(ERROR) << "Receive message with wrong sender " << user_id << '/' << dialog_id << " from " << source; - user_id = td->contacts_manager_->add_service_notifications_user(); + user_id = td->user_manager_->add_service_notifications_user(); } - return td_api::make_object(td->contacts_manager_->get_user_id_object(user_id, source)); + return td_api::make_object(td->user_manager_->get_user_id_object(user_id, source)); } td_api::object_ptr get_message_sender_object_const(Td *td, DialogId dialog_id, @@ -46,9 +47,9 @@ td_api::object_ptr get_message_sender_object(Td *td, User td->dialog_manager_->force_create_dialog(dialog_id, source, true); } if (!user_id.is_valid() && td->auth_manager_->is_bot()) { - td->contacts_manager_->add_anonymous_bot_user(); - td->contacts_manager_->add_channel_bot_user(); - td->contacts_manager_->add_service_notifications_user(); + td->user_manager_->add_anonymous_bot_user(); + td->user_manager_->add_channel_bot_user(); + td->user_manager_->add_service_notifications_user(); } return get_message_sender_object_const(td, user_id, dialog_id, source); } @@ -65,8 +66,8 @@ td_api::object_ptr get_min_message_sender_object(Td *td, auto dialog_type = dialog_id.get_type(); if (dialog_type == DialogType::User) { auto user_id = dialog_id.get_user_id(); - if (td->contacts_manager_->have_min_user(user_id)) { - return td_api::make_object(td->contacts_manager_->get_user_id_object(user_id, source)); + if (td->user_manager_->have_min_user(user_id)) { + return td_api::make_object(td->user_manager_->get_user_id_object(user_id, source)); } } else { if (!td->messages_manager_->have_dialog(dialog_id) && @@ -95,7 +96,7 @@ vector get_message_sender_dialog_ids(Td *td, continue; } if (dialog_id.get_type() == DialogType::User) { - if (!td->contacts_manager_->have_user(dialog_id.get_user_id())) { + if (!td->user_manager_->have_user(dialog_id.get_user_id())) { LOG(ERROR) << "Receive unknown " << dialog_id.get_user_id(); continue; } @@ -140,7 +141,7 @@ Result get_message_sender_dialog_id(Td *td, } return Status::Error(400, "Invalid user identifier specified"); } - bool know_user = td->contacts_manager_->have_user_force(user_id, "get_message_sender_dialog_id"); + bool know_user = td->user_manager_->have_user_force(user_id, "get_message_sender_dialog_id"); if (check_access && !know_user) { return Status::Error(400, "Unknown user identifier specified"); } @@ -156,7 +157,7 @@ Result get_message_sender_dialog_id(Td *td, } bool know_dialog = dialog_id.get_type() == DialogType::User - ? td->contacts_manager_->have_user_force(dialog_id.get_user_id(), "get_message_sender_dialog_id 2") + ? td->user_manager_->have_user_force(dialog_id.get_user_id(), "get_message_sender_dialog_id 2") : td->dialog_manager_->have_dialog_force(dialog_id, "get_message_sender_dialog_id"); if (check_access && !know_dialog) { return Status::Error(400, "Unknown chat identifier specified"); diff --git a/td/telegram/MessageViewer.cpp b/td/telegram/MessageViewer.cpp index e8d46b7cd..1cb011950 100644 --- a/td/telegram/MessageViewer.cpp +++ b/td/telegram/MessageViewer.cpp @@ -6,7 +6,7 @@ // #include "td/telegram/MessageViewer.h" -#include "td/telegram/ContactsManager.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/logging.h" @@ -17,10 +17,9 @@ MessageViewer::MessageViewer(telegram_api::object_ptruser_id_), read_date->date_) { } -td_api::object_ptr MessageViewer::get_message_viewer_object( - ContactsManager *contacts_manager) const { +td_api::object_ptr MessageViewer::get_message_viewer_object(UserManager *user_manager) const { return td_api::make_object( - contacts_manager->get_user_id_object(user_id_, "get_message_viewer_object"), date_); + user_manager->get_user_id_object(user_id_, "get_message_viewer_object"), date_); } StringBuilder &operator<<(StringBuilder &string_builder, const MessageViewer &viewer) { @@ -42,11 +41,10 @@ vector MessageViewers::get_user_ids() const { return transform(message_viewers_, [](auto &viewer) { return viewer.get_user_id(); }); } -td_api::object_ptr MessageViewers::get_message_viewers_object( - ContactsManager *contacts_manager) const { +td_api::object_ptr MessageViewers::get_message_viewers_object(UserManager *user_manager) const { return td_api::make_object( - transform(message_viewers_, [contacts_manager](const MessageViewer &message_viewer) { - return message_viewer.get_message_viewer_object(contacts_manager); + transform(message_viewers_, [user_manager](const MessageViewer &message_viewer) { + return message_viewer.get_message_viewer_object(user_manager); })); } diff --git a/td/telegram/MessageViewer.h b/td/telegram/MessageViewer.h index b09aafbe6..f3ddaffb1 100644 --- a/td/telegram/MessageViewer.h +++ b/td/telegram/MessageViewer.h @@ -15,7 +15,7 @@ namespace td { -class ContactsManager; +class UserManager; class MessageViewer { UserId user_id_; @@ -37,7 +37,7 @@ class MessageViewer { return user_id_ == UserId() && date_ == 0; } - td_api::object_ptr get_message_viewer_object(ContactsManager *contacts_manager) const; + td_api::object_ptr get_message_viewer_object(UserManager *user_manager) const; }; StringBuilder &operator<<(StringBuilder &string_builder, const MessageViewer &viewer); @@ -54,7 +54,7 @@ class MessageViewers { vector get_user_ids() const; - td_api::object_ptr get_message_viewers_object(ContactsManager *contacts_manager) const; + td_api::object_ptr get_message_viewers_object(UserManager *user_manager) const; }; StringBuilder &operator<<(StringBuilder &string_builder, const MessageViewers &viewers); diff --git a/td/telegram/MessagesInfo.cpp b/td/telegram/MessagesInfo.cpp index 2e4b45b56..23023a8cc 100644 --- a/td/telegram/MessagesInfo.cpp +++ b/td/telegram/MessagesInfo.cpp @@ -10,6 +10,7 @@ #include "td/telegram/ForumTopicManager.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/logging.h" #include "td/utils/misc.h" @@ -67,7 +68,7 @@ MessagesInfo get_messages_info(Td *td, DialogId dialog_id, break; } - td->contacts_manager_->on_get_users(std::move(users), source); + td->user_manager_->on_get_users(std::move(users), source); td->contacts_manager_->on_get_chats(std::move(chats), source); td->forum_topic_manager_->on_get_forum_topic_infos(dialog_id, std::move(topics), source); diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index f9d610028..9a4f9ec5c 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -84,6 +84,7 @@ #include "td/telegram/TopDialogManager.h" #include "td/telegram/TranslationManager.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/telegram/Usernames.h" #include "td/telegram/Version.h" #include "td/telegram/WebPageId.h" @@ -136,7 +137,7 @@ class GetDialogQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetDialogQuery: " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetDialogQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetDialogQuery"); td_->contacts_manager_->on_get_chats(std::move(result->chats_), "GetDialogQuery"); td_->messages_manager_->on_get_dialogs(FolderId(), std::move(result->dialogs_), -1, std::move(result->messages_), PromiseCreator::lambda([actor_id = td_->messages_manager_actor_.get(), @@ -179,7 +180,7 @@ class GetPinnedDialogsQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(INFO) << "Receive pinned chats in " << folder_id_ << ": " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetPinnedDialogsQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetPinnedDialogsQuery"); td_->contacts_manager_->on_get_chats(std::move(result->chats_), "GetPinnedDialogsQuery"); td_->messages_manager_->on_get_dialogs(folder_id_, std::move(result->dialogs_), -2, std::move(result->messages_), std::move(promise_)); @@ -652,7 +653,7 @@ class GetDialogListQuery final : public Td::ResultHandler { switch (ptr->get_id()) { case telegram_api::messages_dialogs::ID: { auto dialogs = move_tl_object_as(ptr); - td_->contacts_manager_->on_get_users(std::move(dialogs->users_), "GetDialogListQuery"); + td_->user_manager_->on_get_users(std::move(dialogs->users_), "GetDialogListQuery"); td_->contacts_manager_->on_get_chats(std::move(dialogs->chats_), "GetDialogListQuery"); td_->messages_manager_->on_get_dialogs(folder_id_, std::move(dialogs->dialogs_), narrow_cast(dialogs->dialogs_.size()), @@ -661,7 +662,7 @@ class GetDialogListQuery final : public Td::ResultHandler { } case telegram_api::messages_dialogsSlice::ID: { auto dialogs = move_tl_object_as(ptr); - td_->contacts_manager_->on_get_users(std::move(dialogs->users_), "GetDialogListQuery slice"); + td_->user_manager_->on_get_users(std::move(dialogs->users_), "GetDialogListQuery slice"); td_->contacts_manager_->on_get_chats(std::move(dialogs->chats_), "GetDialogListQuery slice"); td_->messages_manager_->on_get_dialogs(folder_id_, std::move(dialogs->dialogs_), max(dialogs->count_, 0), std::move(dialogs->messages_), std::move(promise_)); @@ -698,7 +699,7 @@ class SearchPublicDialogsQuery final : public Td::ResultHandler { auto dialogs = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for SearchPublicDialogsQuery: " << to_string(dialogs); - td_->contacts_manager_->on_get_users(std::move(dialogs->users_), "SearchPublicDialogsQuery"); + td_->user_manager_->on_get_users(std::move(dialogs->users_), "SearchPublicDialogsQuery"); td_->contacts_manager_->on_get_chats(std::move(dialogs->chats_), "SearchPublicDialogsQuery"); td_->messages_manager_->on_get_public_dialogs_search_result(query_, std::move(dialogs->my_results_), std::move(dialogs->results_)); @@ -751,7 +752,7 @@ class GetBlockedDialogsQuery final : public Td::ResultHandler { case telegram_api::contacts_blocked::ID: { auto blocked_peers = move_tl_object_as(ptr); - td_->contacts_manager_->on_get_users(std::move(blocked_peers->users_), "GetBlockedDialogsQuery"); + td_->user_manager_->on_get_users(std::move(blocked_peers->users_), "GetBlockedDialogsQuery"); td_->contacts_manager_->on_get_chats(std::move(blocked_peers->chats_), "GetBlockedDialogsQuery"); td_->messages_manager_->on_get_blocked_dialogs(offset_, limit_, narrow_cast(blocked_peers->blocked_.size()), @@ -761,7 +762,7 @@ class GetBlockedDialogsQuery final : public Td::ResultHandler { case telegram_api::contacts_blockedSlice::ID: { auto blocked_peers = move_tl_object_as(ptr); - td_->contacts_manager_->on_get_users(std::move(blocked_peers->users_), "GetBlockedDialogsQuery slice"); + td_->user_manager_->on_get_users(std::move(blocked_peers->users_), "GetBlockedDialogsQuery slice"); td_->contacts_manager_->on_get_chats(std::move(blocked_peers->chats_), "GetBlockedDialogsQuery slice"); td_->messages_manager_->on_get_blocked_dialogs(offset_, limit_, blocked_peers->count_, std::move(blocked_peers->blocked_), std::move(promise_)); @@ -1216,7 +1217,7 @@ class GetMessagesViewsQuery final : public Td::ResultHandler { if (message_ids_.size() != interaction_infos.size()) { return on_error(Status::Error(500, "Wrong number of message views returned")); } - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetMessagesViewsQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetMessagesViewsQuery"); td_->contacts_manager_->on_get_chats(std::move(result->chats_), "GetMessagesViewsQuery"); for (size_t i = 0; i < message_ids_.size(); i++) { MessageFullId message_full_id{dialog_id_, message_ids_[i]}; @@ -1649,7 +1650,7 @@ class GetSearchResultCalendarQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetSearchResultCalendarQuery: " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "GetSearchResultCalendarQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "GetSearchResultCalendarQuery"); td_->contacts_manager_->on_get_chats(std::move(result->chats_), "GetSearchResultCalendarQuery"); // unused: inexact:flags.0?true min_date:int min_msg_id:int offset_id_offset:flags.1?int @@ -3851,7 +3852,7 @@ class GetPeerSettingsQuery final : public Td::ResultHandler { } auto ptr = result_ptr.move_as_ok(); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetPeerSettingsQuery"); + td_->user_manager_->on_get_users(std::move(ptr->users_), "GetPeerSettingsQuery"); td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetPeerSettingsQuery"); td_->messages_manager_->on_get_peer_settings(dialog_id_, std::move(ptr->settings_)); } @@ -3939,7 +3940,7 @@ class ReportEncryptedSpamQuery final : public Td::ResultHandler { LOG(INFO) << "Receive error for report encrypted spam: " << status; td_->dialog_manager_->on_get_dialog_error(dialog_id_, status, "ReportEncryptedSpamQuery"); td_->messages_manager_->reget_dialog_action_bar( - DialogId(td_->contacts_manager_->get_secret_chat_user_id(dialog_id_.get_secret_chat_id())), + DialogId(td_->user_manager_->get_secret_chat_user_id(dialog_id_.get_secret_chat_id())), "ReportEncryptedSpamQuery"); promise_.set_error(std::move(status)); } @@ -5773,7 +5774,7 @@ void MessagesManager::skip_old_pending_pts_update(tl_object_ptrcontacts_manager_->add_service_notifications_user(); + UserId service_notifications_user_id = td_->user_manager_->add_service_notifications_user(); DialogId service_notifications_dialog_id(service_notifications_user_id); force_create_dialog(service_notifications_dialog_id, "get_service_notifications_dialog"); return get_dialog(service_notifications_dialog_id); @@ -5782,7 +5783,7 @@ MessagesManager::Dialog *MessagesManager::get_service_notifications_dialog() { void MessagesManager::extract_authentication_codes(DialogId dialog_id, const Message *m, vector &authentication_codes) { CHECK(m != nullptr); - if (dialog_id != DialogId(ContactsManager::get_service_notifications_user_id()) || !m->message_id.is_valid() || + if (dialog_id != DialogId(UserManager::get_service_notifications_user_id()) || !m->message_id.is_valid() || !m->message_id.is_server() || m->content->get_type() != MessageContentType::Text || m->is_outgoing) { return; } @@ -5867,8 +5868,8 @@ void MessagesManager::on_update_service_notification(tl_object_ptrauth_manager_->is_authorized(); bool is_user = is_authorized && !td_->auth_manager_->is_bot(); - auto contacts_manager = is_authorized ? td_->contacts_manager_.get() : nullptr; - auto message_text = get_message_text(contacts_manager, std::move(update->message_), std::move(update->entities_), + auto user_manager = is_authorized ? td_->user_manager_.get() : nullptr; + auto message_text = get_message_text(user_manager, std::move(update->message_), std::move(update->entities_), skip_new_entities, !is_user, date, false, "on_update_service_notification"); DialogId owner_dialog_id = is_user ? get_service_notifications_dialog()->dialog_id : DialogId(); MessageSelfDestructType ttl; @@ -6358,7 +6359,7 @@ td_api::object_ptr MessagesManager::get_message_ UserId my_user_id; UserId peer_user_id; if (dialog_id.get_type() == DialogType::User) { - my_user_id = td_->contacts_manager_->get_my_id(); + my_user_id = td_->user_manager_->get_my_id(); peer_user_id = dialog_id.get_user_id(); } reactions = m->reactions->get_message_reactions_object(td_, my_user_id, peer_user_id); @@ -7748,7 +7749,7 @@ void MessagesManager::reget_dialog_action_bar(DialogId dialog_id, const char *so LOG(INFO) << "Reget action bar in " << dialog_id << " from " << source; switch (dialog_id.get_type()) { case DialogType::User: - td_->contacts_manager_->reload_user_full(dialog_id.get_user_id(), Auto(), source); + td_->user_manager_->reload_user_full(dialog_id.get_user_id(), Auto(), source); return; case DialogType::Chat: case DialogType::Channel: @@ -7816,7 +7817,7 @@ void MessagesManager::remove_dialog_action_bar(DialogId dialog_id, Promise } if (dialog_id.get_type() == DialogType::SecretChat) { - dialog_id = DialogId(td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id())); + dialog_id = DialogId(td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id())); d = get_dialog_force(dialog_id, "remove_dialog_action_bar 2"); if (d == nullptr) { return promise.set_error(Status::Error(400, "Chat with the user not found")); @@ -7919,7 +7920,7 @@ void MessagesManager::toggle_dialog_report_spam_state_on_server(DialogId dialog_ if (is_spam_dialog) { return td_->create_handler(std::move(promise))->send(dialog_id); } else { - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + auto user_id = td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (!user_id.is_valid()) { return promise.set_error(Status::Error(400, "Peer user not found")); } @@ -7941,8 +7942,8 @@ void MessagesManager::on_get_peer_settings(DialogId dialog_id, } if (dialog_id.get_type() == DialogType::User && !ignore_privacy_exception) { - td_->contacts_manager_->on_update_user_need_phone_number_privacy_exception(dialog_id.get_user_id(), - peer_settings->need_contacts_exception_); + td_->user_manager_->on_update_user_need_phone_number_privacy_exception(dialog_id.get_user_id(), + peer_settings->need_contacts_exception_); } Dialog *d = get_dialog_force(dialog_id, "on_get_peer_settings"); @@ -8185,7 +8186,7 @@ void MessagesManager::do_send_secret_media(DialogId dialog_id, Message *m, FileI LOG(INFO) << "Do send secret media file " << file_id << " with thumbnail " << thumbnail_file_id << ", have_input_file = " << have_input_file; - auto layer = td_->contacts_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); + auto layer = td_->user_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); on_secret_message_media_uploaded( dialog_id, m, get_secret_input_media(m->content.get(), td_, std::move(input_encrypted_file), std::move(thumbnail), layer), @@ -9720,7 +9721,7 @@ bool MessagesManager::can_revoke_message(DialogId dialog_id, const Message *m) c return true; // any server message that can be deleted will be deleted for all participants case DialogType::SecretChat: // all non-service messages will be deleted for everyone if secret chat is active - return td_->contacts_manager_->get_secret_chat_state(dialog_id.get_secret_chat_id()) == SecretChatState::Active && + return td_->user_manager_->get_secret_chat_state(dialog_id.get_secret_chat_id()) == SecretChatState::Active && !is_service_message_content(content_type); case DialogType::None: default: @@ -10033,8 +10034,8 @@ MessagesManager::CanDeleteDialog MessagesManager::can_delete_dialog(const Dialog switch (d->dialog_id.get_type()) { case DialogType::User: if (d->dialog_id == td_->dialog_manager_->get_my_dialog_id() || - td_->contacts_manager_->is_user_deleted(d->dialog_id.get_user_id()) || - td_->contacts_manager_->is_user_bot(d->dialog_id.get_user_id())) { + td_->user_manager_->is_user_deleted(d->dialog_id.get_user_id()) || + td_->user_manager_->is_user_bot(d->dialog_id.get_user_id())) { return {true, false}; } return {true, td_->option_manager_->get_option_boolean("revoke_pm_inbox", true)}; @@ -10051,7 +10052,7 @@ MessagesManager::CanDeleteDialog MessagesManager::can_delete_dialog(const Dialog td_->contacts_manager_->get_channel_can_be_deleted(channel_id)}; } case DialogType::SecretChat: - if (td_->contacts_manager_->get_secret_chat_state(d->dialog_id.get_secret_chat_id()) == SecretChatState::Closed) { + if (td_->user_manager_->get_secret_chat_state(d->dialog_id.get_secret_chat_id()) == SecretChatState::Closed) { // in a closed secret chats there is no way to delete messages for both users return {true, false}; } @@ -12710,9 +12711,9 @@ void MessagesManager::read_secret_chat_outbox(SecretChatId secret_chat_id, int32 } if (read_date > 0) { - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id); + auto user_id = td_->user_manager_->get_secret_chat_user_id(secret_chat_id); if (user_id.is_valid()) { - td_->contacts_manager_->on_update_user_local_was_online(user_id, read_date); + td_->user_manager_->on_update_user_local_was_online(user_id, read_date); } } @@ -12862,7 +12863,7 @@ void MessagesManager::on_get_secret_message(SecretChatId secret_chat_id, UserId message_info.content = get_secret_message_content( td_, std::move(message->message_), std::move(file), std::move(message->media_), std::move(message->entities_), message_info.dialog_id, pending_secret_message->load_data_multipromise, - td_->contacts_manager_->is_user_premium(user_id)); + td_->user_manager_->is_user_premium(user_id)); add_secret_message(std::move(pending_secret_message), std::move(lock_promise)); } @@ -12874,7 +12875,7 @@ void MessagesManager::on_resolve_secret_chat_message_via_bot_username(const stri auto dialog_id = td_->dialog_manager_->get_resolved_dialog_by_username(via_bot_username); if (dialog_id.is_valid() && dialog_id.get_type() == DialogType::User) { auto user_id = dialog_id.get_user_id(); - auto r_bot_data = td_->contacts_manager_->get_bot_data(user_id); + auto r_bot_data = td_->user_manager_->get_bot_data(user_id); if (r_bot_data.is_ok() && r_bot_data.ok().is_inline) { message_info_ptr->via_bot_user_id = user_id; } @@ -13009,7 +13010,7 @@ void MessagesManager::finish_add_secret_message(unique_ptr << " received earlier with " << message_id << " and random_id " << random_id; } } else { - if (!td_->contacts_manager_->is_user_premium(pending_secret_message->message_info.sender_user_id)) { + if (!td_->user_manager_->is_user_premium(pending_secret_message->message_info.sender_user_id)) { auto message_text = get_message_content_text_mutable(pending_secret_message->message_info.content.get()); if (message_text != nullptr) { remove_premium_custom_emoji_entities(td_, message_text->entities, true); @@ -13111,8 +13112,8 @@ MessagesManager::MessageInfo MessagesManager::parse_telegram_api_message( << message_info.sender_dialog_id << " from " << source; message_info.content = get_message_content( td, - get_message_text(td->contacts_manager_.get(), std::move(message->message_), std::move(message->entities_), - true, td->auth_manager_->is_bot(), + get_message_text(td->user_manager_.get(), std::move(message->message_), std::move(message->entities_), true, + td->auth_manager_->is_bot(), message_info.forward_header ? message_info.forward_header->date_ : message_info.date, message_info.media_album_id != 0, new_source.c_str()), std::move(message->media_), message_info.dialog_id, message_info.date, is_content_read, @@ -13195,10 +13196,10 @@ std::pair> MessagesManager::creat } if (!td->dialog_manager_->is_broadcast_channel(dialog_id) && td->auth_manager_->is_bot()) { if (dialog_id == sender_dialog_id) { - td->contacts_manager_->add_anonymous_bot_user(); + td->user_manager_->add_anonymous_bot_user(); } else { - td->contacts_manager_->add_service_notifications_user(); - td->contacts_manager_->add_channel_bot_user(); + td->user_manager_->add_service_notifications_user(); + td->user_manager_->add_channel_bot_user(); } } } @@ -13224,7 +13225,7 @@ std::pair> MessagesManager::creat is_channel_post = false; } - UserId my_id = td->contacts_manager_->get_my_id(); + UserId my_id = td->user_manager_->get_my_id(); DialogId my_dialog_id = DialogId(my_id); if (dialog_id == my_dialog_id && (sender_user_id != my_id || sender_dialog_id.is_valid())) { LOG(ERROR) << "Receive " << sender_user_id << "/" << sender_dialog_id << " as a sender of " << message_id @@ -14234,7 +14235,7 @@ void MessagesManager::on_update_sent_text_message(int64 random_id, const FormattedText *old_message_text = get_message_content_text(m->content.get()); CHECK(old_message_text != nullptr); FormattedText new_message_text = get_message_text( - td_->contacts_manager_.get(), old_message_text->text, std::move(entities), true, td_->auth_manager_->is_bot(), + td_->user_manager_.get(), old_message_text->text, std::move(entities), true, td_->auth_manager_->is_bot(), get_message_original_date(m), m->media_album_id != 0, "on_update_sent_text_message"); auto new_content = get_message_content(td_, std::move(new_message_text), std::move(message_media), dialog_id, m->date, true /*likely ignored*/, UserId() /*likely ignored*/, nullptr /*ignored*/, @@ -15254,7 +15255,7 @@ void MessagesManager::on_message_deleted(Dialog *d, Message *m, bool is_permanen break; case DialogType::Channel: if (m->message_id.is_server() && !td_->auth_manager_->is_bot()) { - td_->contacts_manager_->unregister_message_users({d->dialog_id, m->message_id}, get_message_user_ids(m)); + td_->user_manager_->unregister_message_users({d->dialog_id, m->message_id}, get_message_user_ids(m)); td_->contacts_manager_->unregister_message_channels({d->dialog_id, m->message_id}, get_message_channel_ids(m)); } break; @@ -15404,7 +15405,7 @@ bool MessagesManager::load_dialog(DialogId dialog_id, int left_tries, Promisecontacts_manager_->get_user(user_id, left_tries, std::move(promise)); + auto have_user = td_->user_manager_->get_user(user_id, left_tries, std::move(promise)); if (!have_user) { return false; } @@ -16045,7 +16046,7 @@ vector MessagesManager::search_public_dialogs(const string &query, Pro auto d = get_dialog(dialog_id); if (d == nullptr || d->order != DEFAULT_ORDER || (dialog_id.get_type() == DialogType::User && - td_->contacts_manager_->is_user_contact(dialog_id.get_user_id()))) { + td_->user_manager_->is_user_contact(dialog_id.get_user_id()))) { continue; } @@ -16181,7 +16182,7 @@ vector MessagesManager::search_dialogs_on_server(const string &query, void MessagesManager::block_message_sender_from_replies(MessageId message_id, bool need_delete_message, bool need_delete_all_messages, bool report_spam, Promise &&promise) { - auto dialog_id = DialogId(ContactsManager::get_replies_bot_user_id()); + auto dialog_id = DialogId(UserManager::get_replies_bot_user_id()); Dialog *d = get_dialog_force(dialog_id, "block_message_sender_from_replies"); if (d == nullptr) { return promise.set_error(Status::Error(400, "Chat not found")); @@ -16542,7 +16543,7 @@ void MessagesManager::process_discussion_message( Promise promise) { LOG(INFO) << "Receive discussion message for " << message_id << " in " << dialog_id << " with expected " << expected_message_id << " in " << expected_dialog_id << ": " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "process_discussion_message"); + td_->user_manager_->on_get_users(std::move(result->users_), "process_discussion_message"); td_->contacts_manager_->on_get_chats(std::move(result->chats_), "process_discussion_message"); for (auto &message : result->messages_) { @@ -16741,10 +16742,10 @@ Status MessagesManager::can_get_message_read_date(DialogId dialog_id, const Mess return Status::Error(400, "Can't access the chat"); } auto user_id = dialog_id.get_user_id(); - if (td_->contacts_manager_->is_user_bot(user_id)) { + if (td_->user_manager_->is_user_bot(user_id)) { return Status::Error(400, "The user is a bot"); } - if (td_->contacts_manager_->is_user_support(user_id)) { + if (td_->user_manager_->is_user_support(user_id)) { return Status::Error(400, "The user is a Telegram support account"); } @@ -16780,7 +16781,7 @@ void MessagesManager::get_message_read_date(MessageFullId message_full_id, if (d->last_read_outbox_message_id < m->message_id) { return promise.set_value(td_api::make_object()); } - if (td_->contacts_manager_->get_user_read_dates_private(dialog_id.get_user_id())) { + if (td_->user_manager_->get_user_read_dates_private(dialog_id.get_user_id())) { return promise.set_value(td_api::make_object()); } @@ -16894,7 +16895,7 @@ void MessagesManager::on_get_message_viewers(DialogId dialog_id, MessageViewers if (!is_recursive) { bool need_participant_list = false; for (auto user_id : message_viewers.get_user_ids()) { - if (!td_->contacts_manager_->have_user_force(user_id, "on_get_message_viewers")) { + if (!td_->user_manager_->have_user_force(user_id, "on_get_message_viewers")) { need_participant_list = true; } } @@ -16922,7 +16923,7 @@ void MessagesManager::on_get_message_viewers(DialogId dialog_id, MessageViewers } } } - promise.set_value(message_viewers.get_message_viewers_object(td_->contacts_manager_.get())); + promise.set_value(message_viewers.get_message_viewers_object(td_->user_manager_.get())); } void MessagesManager::translate_message_text(MessageFullId message_full_id, const string &to_language_code, @@ -17147,7 +17148,7 @@ MessagesManager::ReportDialogFromActionBar MessagesManager::report_dialog_from_a ReportDialogFromActionBar result; Dialog *d = nullptr; if (dialog_id.get_type() == DialogType::SecretChat) { - auto user_dialog_id = DialogId(td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id())); + auto user_dialog_id = DialogId(td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id())); d = get_dialog_force(user_dialog_id, "report_dialog_from_action_bar"); if (d == nullptr) { promise.set_error(Status::Error(400, "Chat with the user not found")); @@ -18204,8 +18205,8 @@ Status MessagesManager::set_message_sender_block_list(const td_api::object_ptrcontacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); - if (!user_id.is_valid() || !td_->contacts_manager_->have_user_force(user_id, "set_message_sender_block_list")) { + auto user_id = td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + if (!user_id.is_valid() || !td_->user_manager_->have_user_force(user_id, "set_message_sender_block_list")) { return Status::Error(400, "The secret chat can't be blocked"); } dialog_id = DialogId(user_id); @@ -18227,7 +18228,7 @@ Status MessagesManager::set_message_sender_block_list(const td_api::object_ptrcontacts_manager_->on_update_user_is_blocked(dialog_id.get_user_id(), is_blocked, is_blocked_for_stories); + td_->user_manager_->on_update_user_is_blocked(dialog_id.get_user_id(), is_blocked, is_blocked_for_stories); } toggle_dialog_is_blocked_on_server(dialog_id, is_blocked, is_blocked_for_stories, 0); @@ -18489,8 +18490,7 @@ Status MessagesManager::view_messages(DialogId dialog_id, vector mess bool need_mark_download_as_viewed = is_dialog_history || source == MessageSource::HistoryPreview || source == MessageSource::Search || source == MessageSource::Other; bool need_invalidate_authentication_code = - dialog_id == DialogId(ContactsManager::get_service_notifications_user_id()) && - source == MessageSource::Screenshot; + dialog_id == DialogId(UserManager::get_service_notifications_user_id()) && source == MessageSource::Screenshot; auto dialog_type = dialog_id.get_type(); bool need_screenshot_notification = source == MessageSource::Screenshot && (dialog_type == DialogType::User || dialog_type == DialogType::SecretChat) && @@ -19084,9 +19084,9 @@ void MessagesManager::open_dialog(Dialog *d) { } case DialogType::SecretChat: { // to repair dialog action bar - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + auto user_id = td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (user_id.is_valid()) { - td_->contacts_manager_->reload_user_full(user_id, Promise(), "open_dialog"); + td_->user_manager_->reload_user_full(user_id, Promise(), "open_dialog"); } break; } @@ -19209,7 +19209,7 @@ td_api::object_ptr MessagesManager::get_chat_action_bar_o CHECK(d != nullptr); auto dialog_type = d->dialog_id.get_type(); if (dialog_type == DialogType::SecretChat) { - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id()); + auto user_id = td_->user_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id()); if (!user_id.is_valid()) { return nullptr; } @@ -19229,7 +19229,7 @@ td_api::object_ptr MessagesManager::get_chat_action_bar_o td_api::object_ptr MessagesManager::get_chat_background_object(const Dialog *d) const { CHECK(d != nullptr); if (d->dialog_id.get_type() == DialogType::SecretChat) { - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id()); + auto user_id = td_->user_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id()); if (!user_id.is_valid()) { return nullptr; } @@ -19244,7 +19244,7 @@ td_api::object_ptr MessagesManager::get_chat_background_ string MessagesManager::get_dialog_theme_name(const Dialog *d) const { CHECK(d != nullptr); if (d->dialog_id.get_type() == DialogType::SecretChat) { - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id()); + auto user_id = td_->user_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id()); if (!user_id.is_valid()) { return string(); } @@ -19262,8 +19262,8 @@ td_api::object_ptr MessagesManager::get_chat_join_ return nullptr; } return td_api::make_object( - d->pending_join_request_count, td_->contacts_manager_->get_user_ids_object(d->pending_join_request_user_ids, - "get_chat_join_requests_info_object")); + d->pending_join_request_count, + td_->user_manager_->get_user_ids_object(d->pending_join_request_user_ids, "get_chat_join_requests_info_object")); } td_api::object_ptr MessagesManager::get_video_chat_object(const Dialog *d) const { @@ -20715,7 +20715,7 @@ void MessagesManager::on_message_live_location_viewed(Dialog *d, const Message * if (m->is_outgoing || !m->message_id.is_server() || m->via_bot_user_id.is_valid() || m->via_business_bot_user_id.is_valid() || !m->sender_user_id.is_valid() || - td_->contacts_manager_->is_user_bot(m->sender_user_id) || m->forward_info != nullptr) { + td_->user_manager_->is_user_bot(m->sender_user_id) || m->forward_info != nullptr) { return; } @@ -22674,10 +22674,10 @@ td_api::object_ptr MessagesManager::get_dialog_event_log_messag auto import_info = m->forward_info == nullptr ? nullptr : m->forward_info->get_message_import_info_object(); auto interaction_info = get_message_interaction_info_object(dialog_id, m); auto can_be_saved = can_save_message(dialog_id, m); - auto via_bot_user_id = td_->contacts_manager_->get_user_id_object( - m->via_bot_user_id, "get_dialog_event_log_message_object via_bot_user_id"); + auto via_bot_user_id = + td_->user_manager_->get_user_id_object(m->via_bot_user_id, "get_dialog_event_log_message_object via_bot_user_id"); auto edit_date = m->hide_edit_date ? 0 : m->edit_date; - auto reply_markup = get_reply_markup_object(td_->contacts_manager_.get(), m->reply_markup); + auto reply_markup = get_reply_markup_object(td_->user_manager_.get(), m->reply_markup); auto content = get_message_content_object(m->content.get(), td_, dialog_id, 0, false, true, get_message_own_max_media_timestamp(m), m->invert_media, m->disable_web_page_preview); @@ -22729,9 +22729,9 @@ td_api::object_ptr MessagesManager::get_business_message_messag m->forward_info == nullptr ? nullptr : m->forward_info->get_message_forward_info_object(td_, false); auto import_info = m->forward_info == nullptr ? nullptr : m->forward_info->get_message_import_info_object(); auto can_be_saved = can_save_message(dialog_id, m); - auto via_bot_user_id = td_->contacts_manager_->get_user_id_object( - m->via_bot_user_id, "get_business_message_message_object via_bot_user_id"); - auto via_business_bot_user_id = td_->contacts_manager_->get_user_id_object( + auto via_bot_user_id = + td_->user_manager_->get_user_id_object(m->via_bot_user_id, "get_business_message_message_object via_bot_user_id"); + auto via_business_bot_user_id = td_->user_manager_->get_user_id_object( m->via_business_bot_user_id, "get_business_message_message_object via_business_bot_user_id"); auto reply_to = [&]() -> td_api::object_ptr { if (!m->replied_message_info.is_empty()) { @@ -22745,7 +22745,7 @@ td_api::object_ptr MessagesManager::get_business_message_messag } return nullptr; }(); - auto reply_markup = get_reply_markup_object(td_->contacts_manager_.get(), m->reply_markup); + auto reply_markup = get_reply_markup_object(td_->user_manager_.get(), m->reply_markup); auto content = get_message_message_content_object(dialog_id, m); auto self_destruct_type = m->ttl.get_message_self_destruct_type_object(); @@ -22836,9 +22836,9 @@ td_api::object_ptr MessagesManager::get_message_object(DialogId auto can_get_media_timestamp_links = can_get_media_timestamp_link(dialog_id, m).is_ok(); auto can_report_reactions = can_report_message_reactions(dialog_id, m); auto via_bot_user_id = - td_->contacts_manager_->get_user_id_object(m->via_bot_user_id, "get_message_object via_bot_user_id"); - auto via_business_bot_user_id = td_->contacts_manager_->get_user_id_object( - m->via_business_bot_user_id, "get_message_object via_business_bot_user_id"); + td_->user_manager_->get_user_id_object(m->via_bot_user_id, "get_message_object via_bot_user_id"); + auto via_business_bot_user_id = td_->user_manager_->get_user_id_object(m->via_business_bot_user_id, + "get_message_object via_business_bot_user_id"); auto reply_to = [&]() -> td_api::object_ptr { if (!m->replied_message_info.is_empty()) { if (!is_bot && m->is_topic_message && @@ -22858,7 +22858,7 @@ td_api::object_ptr MessagesManager::get_message_object(DialogId auto date = is_scheduled ? 0 : m->date; auto edit_date = m->hide_edit_date ? 0 : m->edit_date; auto has_timestamped_media = reply_to == nullptr || m->max_own_media_timestamp >= 0; - auto reply_markup = get_reply_markup_object(td_->contacts_manager_.get(), m->reply_markup); + auto reply_markup = get_reply_markup_object(td_->user_manager_.get(), m->reply_markup); auto content = get_message_message_content_object(dialog_id, m); auto self_destruct_type = m->ttl.get_message_self_destruct_type_object(); @@ -22955,7 +22955,7 @@ unique_ptr MessagesManager::create_message_to_send( DialogId dialog_id = d->dialog_id; auto dialog_type = dialog_id.get_type(); - auto my_id = td_->contacts_manager_->get_my_id(); + auto my_id = td_->user_manager_->get_my_id(); int64 reply_to_random_id = 0; bool is_topic_message = false; @@ -22994,7 +22994,7 @@ unique_ptr MessagesManager::create_message_to_send( if (is_channel_post) { // sender of the post can be hidden if (!is_scheduled && td_->contacts_manager_->get_channel_sign_messages(dialog_id.get_channel_id())) { - m->author_signature = td_->contacts_manager_->get_user_title(my_id); + m->author_signature = td_->user_manager_->get_user_title(my_id); } m->sender_dialog_id = dialog_id; } else { @@ -23087,8 +23087,7 @@ unique_ptr MessagesManager::create_message_to_send( if (is_service_message_content(m->content->get_type())) { m->ttl = {}; } else { - m->ttl = - MessageSelfDestructType(td_->contacts_manager_->get_secret_chat_ttl(dialog_id.get_secret_chat_id()), false); + m->ttl = MessageSelfDestructType(td_->user_manager_->get_secret_chat_ttl(dialog_id.get_secret_chat_id()), false); } m->is_content_secret = m->ttl.is_secret_message_content(m->content->get_type()); } @@ -23412,11 +23411,10 @@ bool MessagesManager::is_message_auto_read(DialogId dialog_id, bool is_outgoing) switch (dialog_id.get_type()) { case DialogType::User: { auto user_id = dialog_id.get_user_id(); - if (user_id == td_->contacts_manager_->get_my_id()) { + if (user_id == td_->user_manager_->get_my_id()) { return true; } - if (is_outgoing && td_->contacts_manager_->is_user_bot(user_id) && - !td_->contacts_manager_->is_user_support(user_id)) { + if (is_outgoing && td_->user_manager_->is_user_bot(user_id) && !td_->user_manager_->is_user_support(user_id)) { return true; } return false; @@ -24003,7 +24001,7 @@ void MessagesManager::do_send_message(DialogId dialog_id, const Message *m, vect LOG(DEBUG) << "Need to send file " << file_id << " with thumbnail " << thumbnail_file_id; if (is_secret) { CHECK(!is_edit); - auto layer = td_->contacts_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); + auto layer = td_->user_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); auto secret_input_media = get_secret_input_media(content, td_, nullptr, BufferSlice(), layer); if (secret_input_media.empty()) { LOG(INFO) << "Ask to upload encrypted file " << file_id; @@ -24059,7 +24057,7 @@ void MessagesManager::on_message_media_uploaded(DialogId dialog_id, const Messag auto message_id = m->message_id; if (message_id.is_any_server()) { const FormattedText *caption = get_message_content_caption(m->edited_content.get()); - auto input_reply_markup = get_input_reply_markup(td_->contacts_manager_.get(), m->edited_reply_markup); + auto input_reply_markup = get_input_reply_markup(td_->user_manager_.get(), m->edited_reply_markup); bool was_uploaded = FileManager::extract_was_uploaded(input_media); bool was_thumbnail_uploaded = FileManager::extract_was_thumbnail_uploaded(input_media); @@ -24075,35 +24073,35 @@ void MessagesManager::on_message_media_uploaded(DialogId dialog_id, const Messag }); td_->create_handler(std::move(promise)) ->send(1 << 11, dialog_id, message_id, caption == nullptr ? "" : caption->text, - get_input_message_entities(td_->contacts_manager_.get(), caption, "edit_message_media"), + get_input_message_entities(td_->user_manager_.get(), caption, "edit_message_media"), std::move(input_media), m->edited_invert_media, std::move(input_reply_markup), schedule_date); return; } if (m->media_album_id == 0) { - send_closure_later( - actor_id(this), &MessagesManager::on_media_message_ready_to_send, dialog_id, message_id, - PromiseCreator::lambda([this, dialog_id, input_media = std::move(input_media), file_id, - thumbnail_file_id](Result result) mutable { - if (G()->close_flag() || result.is_error()) { - return; - } + send_closure_later(actor_id(this), &MessagesManager::on_media_message_ready_to_send, dialog_id, message_id, + PromiseCreator::lambda([this, dialog_id, input_media = std::move(input_media), file_id, + thumbnail_file_id](Result result) mutable { + if (G()->close_flag() || result.is_error()) { + return; + } - auto m = result.move_as_ok(); - CHECK(m != nullptr); - CHECK(input_media != nullptr); + auto m = result.move_as_ok(); + CHECK(m != nullptr); + CHECK(input_media != nullptr); - const FormattedText *caption = get_message_content_caption(m->content.get()); - LOG(INFO) << "Send media from " << m->message_id << " in " << dialog_id; - int64 random_id = begin_send_message(dialog_id, m); - td_->create_handler()->send( - file_id, thumbnail_file_id, get_message_flags(m), dialog_id, get_send_message_as_input_peer(m), - *get_message_input_reply_to(m), m->initial_top_thread_message_id, get_message_schedule_date(m), - get_input_reply_markup(td_->contacts_manager_.get(), m->reply_markup), - get_input_message_entities(td_->contacts_manager_.get(), caption, "on_message_media_uploaded"), - caption == nullptr ? "" : caption->text, std::move(input_media), m->content->get_type(), m->is_copy, - random_id, &m->send_query_ref); - })); + const FormattedText *caption = get_message_content_caption(m->content.get()); + LOG(INFO) << "Send media from " << m->message_id << " in " << dialog_id; + int64 random_id = begin_send_message(dialog_id, m); + td_->create_handler()->send( + file_id, thumbnail_file_id, get_message_flags(m), dialog_id, + get_send_message_as_input_peer(m), *get_message_input_reply_to(m), + m->initial_top_thread_message_id, get_message_schedule_date(m), + get_input_reply_markup(td_->user_manager_.get(), m->reply_markup), + get_input_message_entities(td_->user_manager_.get(), caption, "on_message_media_uploaded"), + caption == nullptr ? "" : caption->text, std::move(input_media), m->content->get_type(), + m->is_copy, random_id, &m->send_query_ref); + })); } else { switch (input_media->get_id()) { case telegram_api::inputMediaUploadedDocument::ID: @@ -24186,7 +24184,7 @@ void MessagesManager::send_secret_message(DialogId dialog_id, const Message *m, auto text = get_message_content_text(m->content.get()); vector> entities; if (text != nullptr && !text->entities.empty()) { - auto layer = td_->contacts_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); + auto layer = td_->user_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); entities = get_input_secret_message_entities(text->entities, layer); } @@ -24216,8 +24214,8 @@ void MessagesManager::send_secret_message(DialogId dialog_id, const Message *m, make_tl_object( flags, false /*ignored*/, random_id, m->ttl.get_input_ttl(), m->content->get_type() == MessageContentType::Text ? text->text : string(), std::move(media.decrypted_media_), - std::move(entities), td_->contacts_manager_->get_user_first_username(m->via_bot_user_id), - m->reply_to_random_id, -m->media_album_id), + std::move(entities), td_->user_manager_->get_user_first_username(m->via_bot_user_id), m->reply_to_random_id, + -m->media_album_id), std::move(media.input_file_), Promise()); } @@ -24444,7 +24442,7 @@ void MessagesManager::do_send_message_group(int64 media_album_id) { << file_view.has_active_download_remote_location() << " " << file_view.is_encrypted() << " " << is_web << " " << file_view.has_url() << " " << to_string(get_message_message_content_object(dialog_id, m)); } - auto entities = get_input_message_entities(td_->contacts_manager_.get(), caption, "do_send_message_group"); + auto entities = get_input_message_entities(td_->user_manager_.get(), caption, "do_send_message_group"); int32 input_single_media_flags = 0; if (!entities.empty()) { input_single_media_flags |= telegram_api::inputSingleMedia::ENTITIES_MASK; @@ -24502,7 +24500,7 @@ void MessagesManager::on_text_message_ready_to_send(DialogId dialog_id, MessageI if (dialog_id.get_type() == DialogType::SecretChat) { CHECK(!message_id.is_scheduled()); - auto layer = td_->contacts_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); + auto layer = td_->user_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); send_secret_message(dialog_id, m, get_secret_input_media(content, td_, nullptr, BufferSlice(), layer)); } else { const FormattedText *message_text = get_message_content_text(content); @@ -24513,15 +24511,15 @@ void MessagesManager::on_text_message_ready_to_send(DialogId dialog_id, MessageI td_->create_handler()->send( get_message_flags(m), dialog_id, get_send_message_as_input_peer(m), *get_message_input_reply_to(m), m->initial_top_thread_message_id, get_message_schedule_date(m), - get_input_reply_markup(td_->contacts_manager_.get(), m->reply_markup), - get_input_message_entities(td_->contacts_manager_.get(), message_text, "on_text_message_ready_to_send"), + get_input_reply_markup(td_->user_manager_.get(), m->reply_markup), + get_input_message_entities(td_->user_manager_.get(), message_text, "on_text_message_ready_to_send"), message_text->text, m->is_copy, random_id, &m->send_query_ref); } else { td_->create_handler()->send( FileId(), FileId(), get_message_flags(m), dialog_id, get_send_message_as_input_peer(m), *get_message_input_reply_to(m), m->initial_top_thread_message_id, get_message_schedule_date(m), - get_input_reply_markup(td_->contacts_manager_.get(), m->reply_markup), - get_input_message_entities(td_->contacts_manager_.get(), message_text, "on_text_message_ready_to_send"), + get_input_reply_markup(td_->user_manager_.get(), m->reply_markup), + get_input_message_entities(td_->user_manager_.get(), message_text, "on_text_message_ready_to_send"), message_text->text, std::move(input_media), MessageContentType::Text, m->is_copy, random_id, &m->send_query_ref); } @@ -24603,7 +24601,7 @@ Result MessagesManager::send_bot_start_message(UserId bot_user_id, Di const string ¶meter) { CHECK(!td_->auth_manager_->is_bot()); - TRY_RESULT(bot_data, td_->contacts_manager_->get_bot_data(bot_user_id)); + TRY_RESULT(bot_data, td_->user_manager_->get_bot_data(bot_user_id)); Dialog *d = get_dialog_force(dialog_id, "send_bot_start_message"); if (d == nullptr) { @@ -24756,7 +24754,7 @@ void MessagesManager::do_send_bot_start_message(UserId bot_user_id, DialogId dia if (input_peer == nullptr) { return on_send_message_fail(random_id, Status::Error(400, "Chat is not accessible")); } - auto r_bot_input_user = td_->contacts_manager_->get_input_user(bot_user_id); + auto r_bot_input_user = td_->user_manager_->get_input_user(bot_user_id); if (r_bot_input_user.is_error()) { return on_send_message_fail(random_id, r_bot_input_user.move_as_error()); } @@ -24944,7 +24942,7 @@ bool MessagesManager::can_edit_message(DialogId dialog_id, const Message *m, boo return false; } - auto my_id = td_->contacts_manager_->get_my_id(); + auto my_id = td_->user_manager_->get_my_id(); bool is_inline_message = m->via_bot_user_id.is_valid(); if (is_inline_message && (m->via_bot_user_id != my_id || m->message_id.is_scheduled())) { return false; @@ -25083,7 +25081,7 @@ bool MessagesManager::is_deleted_secret_chat(const Dialog *d) const { return false; } - auto state = td_->contacts_manager_->get_secret_chat_state(d->dialog_id.get_secret_chat_id()); + auto state = td_->user_manager_->get_secret_chat_state(d->dialog_id.get_secret_chat_id()); if (state != SecretChatState::Closed) { return false; } @@ -25174,18 +25172,18 @@ void MessagesManager::edit_message_text(MessageFullId message_full_id, if (r_new_reply_markup.is_error()) { return promise.set_error(r_new_reply_markup.move_as_error()); } - auto input_reply_markup = get_input_reply_markup(td_->contacts_manager_.get(), r_new_reply_markup.ok()); + auto input_reply_markup = get_input_reply_markup(td_->user_manager_.get(), r_new_reply_markup.ok()); int32 flags = 0; if (input_message_text.disable_web_page_preview) { flags |= SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW; } td_->create_handler(std::move(promise)) - ->send(flags, dialog_id, m->message_id, input_message_text.text.text, - get_input_message_entities(td_->contacts_manager_.get(), input_message_text.text.entities, - "edit_message_text"), - input_message_text.get_input_media_web_page(), input_message_text.show_above_text, - std::move(input_reply_markup), get_message_schedule_date(m)); + ->send( + flags, dialog_id, m->message_id, input_message_text.text.text, + get_input_message_entities(td_->user_manager_.get(), input_message_text.text.entities, "edit_message_text"), + input_message_text.get_input_media_web_page(), input_message_text.show_above_text, + std::move(input_reply_markup), get_message_schedule_date(m)); } void MessagesManager::edit_message_live_location(MessageFullId message_full_id, @@ -25230,7 +25228,7 @@ void MessagesManager::edit_message_live_location(MessageFullId message_full_id, if (r_new_reply_markup.is_error()) { return promise.set_error(r_new_reply_markup.move_as_error()); } - auto input_reply_markup = get_input_reply_markup(td_->contacts_manager_.get(), r_new_reply_markup.ok()); + auto input_reply_markup = get_input_reply_markup(td_->user_manager_.get(), r_new_reply_markup.ok()); int32 flags = 0; if (location.empty()) { @@ -25475,12 +25473,12 @@ void MessagesManager::edit_message_caption(MessageFullId message_full_id, if (r_new_reply_markup.is_error()) { return promise.set_error(r_new_reply_markup.move_as_error()); } - auto input_reply_markup = get_input_reply_markup(td_->contacts_manager_.get(), r_new_reply_markup.ok()); + auto input_reply_markup = get_input_reply_markup(td_->user_manager_.get(), r_new_reply_markup.ok()); td_->create_handler(std::move(promise)) ->send(1 << 11, dialog_id, m->message_id, caption.text, - get_input_message_entities(td_->contacts_manager_.get(), caption.entities, "edit_message_caption"), - nullptr, m->invert_media, std::move(input_reply_markup), get_message_schedule_date(m)); + get_input_message_entities(td_->user_manager_.get(), caption.entities, "edit_message_caption"), nullptr, + m->invert_media, std::move(input_reply_markup), get_message_schedule_date(m)); } void MessagesManager::edit_message_reply_markup(MessageFullId message_full_id, @@ -25512,7 +25510,7 @@ void MessagesManager::edit_message_reply_markup(MessageFullId message_full_id, if (r_new_reply_markup.is_error()) { return promise.set_error(r_new_reply_markup.move_as_error()); } - auto input_reply_markup = get_input_reply_markup(td_->contacts_manager_.get(), r_new_reply_markup.ok()); + auto input_reply_markup = get_input_reply_markup(td_->user_manager_.get(), r_new_reply_markup.ok()); td_->create_handler(std::move(promise)) ->send(0, dialog_id, m->message_id, string(), vector>(), nullptr, false, std::move(input_reply_markup), get_message_schedule_date(m)); @@ -25555,10 +25553,10 @@ void MessagesManager::edit_inline_message_text(const string &inline_message_id, } td_->create_handler(std::move(promise)) ->send(flags, std::move(input_bot_inline_message_id), input_message_text.text.text, - get_input_message_entities(td_->contacts_manager_.get(), input_message_text.text.entities, + get_input_message_entities(td_->user_manager_.get(), input_message_text.text.entities, "edit_inline_message_text"), input_message_text.get_input_media_web_page(), input_message_text.show_above_text, - get_input_reply_markup(td_->contacts_manager_.get(), r_new_reply_markup.ok())); + get_input_reply_markup(td_->user_manager_.get(), r_new_reply_markup.ok())); } void MessagesManager::edit_inline_message_live_location(const string &inline_message_id, @@ -25594,8 +25592,7 @@ void MessagesManager::edit_inline_message_live_location(const string &inline_mes flags, false /*ignored*/, location.get_input_geo_point(), heading, 0, proximity_alert_radius); td_->create_handler(std::move(promise)) ->send(0, std::move(input_bot_inline_message_id), "", vector>(), - std::move(input_media), false, - get_input_reply_markup(td_->contacts_manager_.get(), r_new_reply_markup.ok())); + std::move(input_media), false, get_input_reply_markup(td_->user_manager_.get(), r_new_reply_markup.ok())); } void MessagesManager::edit_inline_message_media(const string &inline_message_id, @@ -25643,9 +25640,9 @@ void MessagesManager::edit_inline_message_media(const string &inline_message_id, const FormattedText *caption = get_message_content_caption(content.content.get()); td_->create_handler(std::move(promise)) ->send(1 << 11, std::move(input_bot_inline_message_id), caption == nullptr ? "" : caption->text, - get_input_message_entities(td_->contacts_manager_.get(), caption, "edit_inline_message_media"), + get_input_message_entities(td_->user_manager_.get(), caption, "edit_inline_message_media"), std::move(input_media), content.invert_media, - get_input_reply_markup(td_->contacts_manager_.get(), r_new_reply_markup.ok())); + get_input_reply_markup(td_->user_manager_.get(), r_new_reply_markup.ok())); } void MessagesManager::edit_inline_message_caption(const string &inline_message_id, @@ -25673,8 +25670,8 @@ void MessagesManager::edit_inline_message_caption(const string &inline_message_i td_->create_handler(std::move(promise)) ->send(1 << 11, std::move(input_bot_inline_message_id), caption.text, - get_input_message_entities(td_->contacts_manager_.get(), caption.entities, "edit_inline_message_caption"), - nullptr, false, get_input_reply_markup(td_->contacts_manager_.get(), r_new_reply_markup.ok())); + get_input_message_entities(td_->user_manager_.get(), caption.entities, "edit_inline_message_caption"), + nullptr, false, get_input_reply_markup(td_->user_manager_.get(), r_new_reply_markup.ok())); } void MessagesManager::edit_inline_message_reply_markup(const string &inline_message_id, @@ -25694,7 +25691,7 @@ void MessagesManager::edit_inline_message_reply_markup(const string &inline_mess td_->create_handler(std::move(promise)) ->send(0, std::move(input_bot_inline_message_id), string(), vector>(), - nullptr, false, get_input_reply_markup(td_->contacts_manager_.get(), r_new_reply_markup.ok())); + nullptr, false, get_input_reply_markup(td_->user_manager_.get(), r_new_reply_markup.ok())); } void MessagesManager::edit_message_scheduling_state( @@ -25747,7 +25744,7 @@ bool MessagesManager::is_discussion_message(DialogId dialog_id, const Message *m return false; } if (m->sender_user_id.is_valid()) { - if (!td_->auth_manager_->is_bot() || m->sender_user_id != ContactsManager::get_service_notifications_user_id()) { + if (!td_->auth_manager_->is_bot() || m->sender_user_id != UserManager::get_service_notifications_user_id()) { return false; } } @@ -26079,7 +26076,7 @@ bool MessagesManager::can_set_game_score(DialogId dialog_id, const Message *m) c return false; } auto is_inline_message = m->via_bot_user_id.is_valid(); - if (is_inline_message && m->via_bot_user_id != td_->contacts_manager_->get_my_id()) { + if (is_inline_message && m->via_bot_user_id != td_->user_manager_->get_my_id()) { return false; } @@ -26273,8 +26270,8 @@ MessageOrigin MessagesManager::get_forwarded_message_origin(DialogId dialog_id, origin = m->forward_info->get_origin(); } else if (m->is_channel_post) { if (td_->dialog_manager_->is_broadcast_channel(dialog_id)) { - auto author_signature = m->sender_user_id.is_valid() ? td_->contacts_manager_->get_user_title(m->sender_user_id) - : m->author_signature; + auto author_signature = + m->sender_user_id.is_valid() ? td_->user_manager_->get_user_title(m->sender_user_id) : m->author_signature; origin = MessageOrigin{UserId(), dialog_id, m->message_id, std::move(author_signature), string()}; } else { LOG(ERROR) << "Don't know how to forward a channel post not from a channel"; @@ -26348,7 +26345,7 @@ void MessagesManager::fix_forwarded_message(Message *m, DialogId to_dialog_id, c // if there is no via_bot_user_id, then the original message was sent by the game owner m->via_bot_user_id = forwarded_message->sender_user_id; } - if (m->via_bot_user_id == td_->contacts_manager_->get_my_id()) { + if (m->via_bot_user_id == td_->user_manager_->get_my_id()) { // if via_bot_user_id is the current bot user, then there should be m->via_bot_user_id = UserId(); } @@ -26686,7 +26683,7 @@ Result> MessagesManager::forward_messages( bool is_secret = to_dialog_id.get_type() == DialogType::SecretChat; bool is_copy = !is_secret; bool need_invalidate_authentication_code = - from_dialog_id == DialogId(ContactsManager::get_service_notifications_user_id()) && !td_->auth_manager_->is_bot(); + from_dialog_id == DialogId(UserManager::get_service_notifications_user_id()) && !td_->auth_manager_->is_bot(); vector authentication_codes; for (const auto &copied_message : copied_messages) { if (forwarded_message_id_to_new_message_id.count(copied_message.original_reply_to_message_id) > 0) { @@ -27080,7 +27077,7 @@ void MessagesManager::share_dialogs_with_bot(MessageFullId message_full_id, int3 if (!expect_user) { return promise.set_error(Status::Error(400, "Wrong chat type")); } - if (!td_->contacts_manager_->have_user(shared_dialog_id.get_user_id())) { + if (!td_->user_manager_->have_user(shared_dialog_id.get_user_id())) { return promise.set_error(Status::Error(400, "Shared user not found")); } } @@ -27147,13 +27144,13 @@ Result MessagesManager::add_local_message( } auto dialog_type = dialog_id.get_type(); - auto my_id = td_->contacts_manager_->get_my_id(); + auto my_id = td_->user_manager_->get_my_id(); if (sender_user_id != my_id) { if (dialog_type == DialogType::User && DialogId(sender_user_id) != dialog_id) { return Status::Error(400, "Wrong sender user"); } if (dialog_type == DialogType::SecretChat) { - auto peer_user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + auto peer_user_id = td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (!peer_user_id.is_valid() || sender_user_id != peer_user_id) { return Status::Error(400, "Wrong sender user"); } @@ -27170,7 +27167,7 @@ Result MessagesManager::add_local_message( if (is_channel_post) { // sender of the post can be hidden if (td_->contacts_manager_->get_channel_sign_messages(dialog_id.get_channel_id())) { - m->author_signature = td_->contacts_manager_->get_user_title(sender_user_id); + m->author_signature = td_->user_manager_->get_user_title(sender_user_id); } m->sender_dialog_id = sender_dialog_id; } else { @@ -27206,8 +27203,7 @@ Result MessagesManager::add_local_message( m->clear_draft = message_content.clear_draft; if (dialog_type == DialogType::SecretChat) { if (!is_service_message_content(m->content->get_type())) { - m->ttl = - MessageSelfDestructType(td_->contacts_manager_->get_secret_chat_ttl(dialog_id.get_secret_chat_id()), false); + m->ttl = MessageSelfDestructType(td_->user_manager_->get_secret_chat_ttl(dialog_id.get_secret_chat_id()), false); } } else if (message_content.ttl.is_valid()) { m->ttl = message_content.ttl; @@ -27548,7 +27544,7 @@ NotificationGroupFromDatabase MessagesManager::get_message_notification_group_fo CHECK(d->dialog_id.get_type() == DialogType::SecretChat); result.type = NotificationGroupType::SecretChat; result.notifications.emplace_back(d->notification_info->new_secret_chat_notification_id_, - td_->contacts_manager_->get_secret_chat_date(d->dialog_id.get_secret_chat_id()), + td_->user_manager_->get_secret_chat_date(d->dialog_id.get_secret_chat_id()), false, create_new_secret_chat_notification()); } else { result.type = from_mentions ? NotificationGroupType::Mentions : NotificationGroupType::Messages; @@ -27868,7 +27864,7 @@ void MessagesManager::get_message_notifications_from_database(DialogId dialog_id CHECK(dialog_id.get_type() == DialogType::SecretChat); vector notifications; if (!from_mentions && d->notification_info->new_secret_chat_notification_id_.get() < from_notification_id.get()) { - auto date = td_->contacts_manager_->get_secret_chat_date(dialog_id.get_secret_chat_id()); + auto date = td_->user_manager_->get_secret_chat_date(dialog_id.get_secret_chat_id()); if (date <= 0) { remove_new_secret_chat_notification(d, true); } else { @@ -28258,7 +28254,7 @@ bool MessagesManager::is_dialog_message_notification_disabled(DialogId dialog_id } break; case DialogType::SecretChat: - if (td_->contacts_manager_->get_secret_chat_state(dialog_id.get_secret_chat_id()) == SecretChatState::Closed) { + if (td_->user_manager_->get_secret_chat_state(dialog_id.get_secret_chat_id()) == SecretChatState::Closed) { return true; } break; @@ -28437,7 +28433,7 @@ bool MessagesManager::add_new_message_notification(Dialog *d, Message *m, bool f VLOG(notifications) << "Create " << m->notification_id << " with " << m->message_id << " in " << group_info.get_group_id() << '/' << d->dialog_id; int32 min_delay_ms = 0; - if (need_delay_message_content_notification(m->content.get(), td_->contacts_manager_->get_my_id())) { + if (need_delay_message_content_notification(m->content.get(), td_->user_manager_->get_my_id())) { min_delay_ms = 3000; // 3 seconds } else if (td_->is_online() && d->open_count > 0) { min_delay_ms = 1000; // 1 second @@ -28623,7 +28619,7 @@ void MessagesManager::send_update_message_edited(DialogId dialog_id, const Messa send_closure(G()->td(), &Td::send_update, td_api::make_object( get_chat_id_object(dialog_id, "updateMessageEdited"), m->message_id.get(), edit_date, - get_reply_markup_object(td_->contacts_manager_.get(), m->reply_markup))); + get_reply_markup_object(td_->user_manager_.get(), m->reply_markup))); } void MessagesManager::send_update_message_interaction_info(DialogId dialog_id, const Message *m) const { @@ -28973,7 +28969,7 @@ void MessagesManager::send_update_secret_chats_with_user_action_bar(const Dialog return; } - td_->contacts_manager_->for_each_secret_chat_with_user( + td_->user_manager_->for_each_secret_chat_with_user( d->dialog_id.get_user_id(), [this, user_d = d](SecretChatId secret_chat_id) { DialogId dialog_id(secret_chat_id); auto secret_chat_d = get_dialog(dialog_id); // must not create the dialog @@ -29021,7 +29017,7 @@ void MessagesManager::send_update_secret_chats_with_user_background(const Dialog return; } - td_->contacts_manager_->for_each_secret_chat_with_user( + td_->user_manager_->for_each_secret_chat_with_user( d->dialog_id.get_user_id(), [this, user_d = d](SecretChatId secret_chat_id) { DialogId dialog_id(secret_chat_id); auto secret_chat_d = get_dialog(dialog_id); // must not create the dialog @@ -29058,7 +29054,7 @@ void MessagesManager::send_update_secret_chats_with_user_theme(const Dialog *d) return; } - td_->contacts_manager_->for_each_secret_chat_with_user( + td_->user_manager_->for_each_secret_chat_with_user( d->dialog_id.get_user_id(), [this, user_d = d](SecretChatId secret_chat_id) { DialogId dialog_id(secret_chat_id); auto secret_chat_d = get_dialog(dialog_id); // must not create the dialog @@ -30188,7 +30184,7 @@ void MessagesManager::on_update_dialog_is_blocked(DialogId dialog_id, bool is_bl return; } if (dialog_id.get_type() == DialogType::User) { - td_->contacts_manager_->on_update_user_is_blocked(dialog_id.get_user_id(), is_blocked, is_blocked_for_stories); + td_->user_manager_->on_update_user_is_blocked(dialog_id.get_user_id(), is_blocked, is_blocked_for_stories); } auto d = get_dialog_force(dialog_id, "on_update_dialog_is_blocked"); @@ -30227,7 +30223,7 @@ void MessagesManager::set_dialog_is_blocked(Dialog *d, bool is_blocked, bool is_ block_list_id.get_block_list_object())); if (d->dialog_id.get_type() == DialogType::User) { - td_->contacts_manager_->on_update_user_is_blocked(d->dialog_id.get_user_id(), is_blocked, is_blocked_for_stories); + td_->user_manager_->on_update_user_is_blocked(d->dialog_id.get_user_id(), is_blocked, is_blocked_for_stories); if (d->know_action_bar) { if (is_blocked) { @@ -30240,7 +30236,7 @@ void MessagesManager::set_dialog_is_blocked(Dialog *d, bool is_blocked, bool is_ } } - td_->contacts_manager_->for_each_secret_chat_with_user( + td_->user_manager_->for_each_secret_chat_with_user( d->dialog_id.get_user_id(), [this, is_blocked, is_blocked_for_stories](SecretChatId secret_chat_id) { DialogId dialog_id(secret_chat_id); auto d = get_dialog(dialog_id); // must not create the dialog @@ -30617,7 +30613,7 @@ void MessagesManager::do_set_dialog_folder_id(Dialog *d, FolderId folder_id) { d->folder_id = folder_id; if (d->dialog_id.get_type() == DialogType::SecretChat) { // need to change action bar only for the secret chat and keep unarchive for the main chat - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id()); + auto user_id = td_->user_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id()); if (d->is_update_new_chat_sent && user_id.is_valid()) { const Dialog *user_d = get_dialog(DialogId(user_id)); if (user_d != nullptr && user_d->action_bar != nullptr && user_d->action_bar->can_unarchive()) { @@ -30722,8 +30718,8 @@ void MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id(Dial if (default_join_as_dialog_id.is_valid()) { if (default_join_as_dialog_id.get_type() != DialogType::User) { force_create_dialog(default_join_as_dialog_id, "on_update_dialog_default_join_group_call_as_dialog_id"); - } else if (!td_->contacts_manager_->have_user_force(default_join_as_dialog_id.get_user_id(), - "on_update_dialog_default_join_group_call_as_dialog_id") || + } else if (!td_->user_manager_->have_user_force(default_join_as_dialog_id.get_user_id(), + "on_update_dialog_default_join_group_call_as_dialog_id") || default_join_as_dialog_id != td_->dialog_manager_->get_my_dialog_id()) { default_join_as_dialog_id = DialogId(); } @@ -30763,8 +30759,8 @@ void MessagesManager::on_update_dialog_default_send_message_as_dialog_id(DialogI if (default_send_as_dialog_id.is_valid()) { if (default_send_as_dialog_id.get_type() != DialogType::User) { force_create_dialog(default_send_as_dialog_id, "on_update_dialog_default_send_message_as_dialog_id"); - } else if (!td_->contacts_manager_->have_user_force(default_send_as_dialog_id.get_user_id(), - "on_update_dialog_default_send_message_as_dialog_id") || + } else if (!td_->user_manager_->have_user_force(default_send_as_dialog_id.get_user_id(), + "on_update_dialog_default_send_message_as_dialog_id") || default_send_as_dialog_id != td_->dialog_manager_->get_my_dialog_id()) { default_send_as_dialog_id = DialogId(); } @@ -31000,7 +30996,7 @@ void MessagesManager::on_dialog_user_is_contact_updated(DialogId dialog_id, bool if (td_->dialog_filter_manager_->have_dialog_filters() && d->order != DEFAULT_ORDER) { update_dialog_lists(d, get_dialog_positions(d), true, false, "on_dialog_user_is_contact_updated"); - td_->contacts_manager_->for_each_secret_chat_with_user( + td_->user_manager_->for_each_secret_chat_with_user( d->dialog_id.get_user_id(), [this](SecretChatId secret_chat_id) { DialogId dialog_id(secret_chat_id); auto d = get_dialog(dialog_id); // must not create the dialog @@ -31028,26 +31024,24 @@ void MessagesManager::on_dialog_user_is_deleted_updated(DialogId dialog_id, bool if (td_->dialog_filter_manager_->have_dialog_filters() && d->order != DEFAULT_ORDER) { update_dialog_lists(d, get_dialog_positions(d), true, false, "on_dialog_user_is_deleted_updated"); - td_->contacts_manager_->for_each_secret_chat_with_user( - dialog_id.get_user_id(), [this](SecretChatId secret_chat_id) { - DialogId dialog_id(secret_chat_id); - auto d = get_dialog(dialog_id); // must not create the dialog - if (d != nullptr && d->is_update_new_chat_sent && d->order != DEFAULT_ORDER) { - update_dialog_lists(d, get_dialog_positions(d), true, false, "on_dialog_user_is_deleted_updated"); - } - }); + td_->user_manager_->for_each_secret_chat_with_user(dialog_id.get_user_id(), [this](SecretChatId secret_chat_id) { + DialogId dialog_id(secret_chat_id); + auto d = get_dialog(dialog_id); // must not create the dialog + if (d != nullptr && d->is_update_new_chat_sent && d->order != DEFAULT_ORDER) { + update_dialog_lists(d, get_dialog_positions(d), true, false, "on_dialog_user_is_deleted_updated"); + } + }); } if (is_deleted && d->has_bots) { set_dialog_has_bots(d, false); - td_->contacts_manager_->for_each_secret_chat_with_user( - dialog_id.get_user_id(), [this](SecretChatId secret_chat_id) { - DialogId dialog_id(secret_chat_id); - auto d = get_dialog(dialog_id); // must not create the dialog - if (d != nullptr && d->is_update_new_chat_sent && d->has_bots) { - set_dialog_has_bots(d, false); - } - }); + td_->user_manager_->for_each_secret_chat_with_user(dialog_id.get_user_id(), [this](SecretChatId secret_chat_id) { + DialogId dialog_id(secret_chat_id); + auto d = get_dialog(dialog_id); // must not create the dialog + if (d != nullptr && d->is_update_new_chat_sent && d->has_bots) { + set_dialog_has_bots(d, false); + } + }); } } } @@ -31595,7 +31589,7 @@ vector MessagesManager::get_dialog_lists_to_add_dialog(DialogId di } if (dialog_id != td_->dialog_manager_->get_my_dialog_id() && - dialog_id != DialogId(ContactsManager::get_service_notifications_user_id())) { + dialog_id != DialogId(UserManager::get_service_notifications_user_id())) { result.push_back( DialogListId(get_dialog(dialog_id)->folder_id == FolderId::archive() ? FolderId::main() : FolderId::archive())); } @@ -31637,9 +31631,8 @@ void MessagesManager::add_dialog_to_list(DialogId dialog_id, DialogListId dialog return promise.set_value(Unit()); } - if (folder_id == FolderId::archive() && - (dialog_id == td_->dialog_manager_->get_my_dialog_id() || - dialog_id == DialogId(ContactsManager::get_service_notifications_user_id()))) { + if (folder_id == FolderId::archive() && (dialog_id == td_->dialog_manager_->get_my_dialog_id() || + dialog_id == DialogId(UserManager::get_service_notifications_user_id()))) { return promise.set_error(Status::Error(400, "Chat can't be archived")); } @@ -31773,7 +31766,7 @@ void MessagesManager::set_dialog_message_ttl(DialogId dialog_id, int32 ttl, Prom switch (dialog_id.get_type()) { case DialogType::User: if (dialog_id == td_->dialog_manager_->get_my_dialog_id() || - dialog_id == DialogId(ContactsManager::get_service_notifications_user_id())) { + dialog_id == DialogId(UserManager::get_service_notifications_user_id())) { return promise.set_error(Status::Error(400, "Message auto-delete time in the chat can't be changed")); } break; @@ -31838,7 +31831,7 @@ void MessagesManager::set_dialog_theme(DialogId dialog_id, const string &theme_n case DialogType::Channel: return promise.set_error(Status::Error(400, "Can't change theme in the chat")); case DialogType::SecretChat: { - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + auto user_id = td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (!user_id.is_valid()) { return promise.set_error(Status::Error(400, "Can't access the user")); } @@ -32200,7 +32193,7 @@ void MessagesManager::fix_new_message(const Dialog *d, Message *m, bool from_dat } auto dialog_type = dialog_id.get_type(); - if (m->sender_user_id == ContactsManager::get_anonymous_bot_user_id() && !m->sender_dialog_id.is_valid() && + if (m->sender_user_id == UserManager::get_anonymous_bot_user_id() && !m->sender_dialog_id.is_valid() && dialog_type == DialogType::Channel && !td_->dialog_manager_->is_broadcast_channel(dialog_id)) { m->sender_user_id = UserId(); m->sender_dialog_id = dialog_id; @@ -32905,18 +32898,18 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq dialog_id != td_->dialog_manager_->get_my_dialog_id()) { switch (dialog_type) { case DialogType::User: - td_->contacts_manager_->invalidate_user_full(dialog_id.get_user_id()); - td_->contacts_manager_->reload_user_full(dialog_id.get_user_id(), Promise(), "add_message_to_dialog"); + td_->user_manager_->invalidate_user_full(dialog_id.get_user_id()); + td_->user_manager_->reload_user_full(dialog_id.get_user_id(), Promise(), "add_message_to_dialog"); break; case DialogType::Chat: case DialogType::Channel: // nothing to do break; case DialogType::SecretChat: { - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + auto user_id = td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (user_id.is_valid()) { - td_->contacts_manager_->invalidate_user_full(user_id); - td_->contacts_manager_->reload_user_full(user_id, Promise(), "add_message_to_dialog"); + td_->user_manager_->invalidate_user_full(user_id); + td_->user_manager_->reload_user_full(user_id, Promise(), "add_message_to_dialog"); } break; } @@ -32944,7 +32937,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq } if (!td_->auth_manager_->is_bot() && dialog_type == DialogType::User && !m->is_outgoing) { - td_->contacts_manager_->allow_send_message_to_user(dialog_id.get_user_id()); + td_->user_manager_->allow_send_message_to_user(dialog_id.get_user_id()); } switch (dialog_type) { @@ -32956,7 +32949,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq break; case DialogType::Channel: if (m->message_id.is_server() && !td_->auth_manager_->is_bot()) { - td_->contacts_manager_->register_message_users({dialog_id, m->message_id}, get_message_user_ids(m)); + td_->user_manager_->register_message_users({dialog_id, m->message_id}, get_message_user_ids(m)); td_->contacts_manager_->register_message_channels({dialog_id, m->message_id}, get_message_channel_ids(m)); } break; @@ -34251,13 +34244,13 @@ void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source update_dialog_pos(d, source); if (dialog_id.get_type() == DialogType::SecretChat && !d->notification_settings.is_synchronized && - td_->contacts_manager_->get_secret_chat_state(dialog_id.get_secret_chat_id()) != SecretChatState::Closed) { + td_->user_manager_->get_secret_chat_state(dialog_id.get_secret_chat_id()) != SecretChatState::Closed) { // secret chat is being created // let's copy notification settings from main chat if available VLOG(notifications) << "Create new secret " << dialog_id << " from " << source; auto secret_chat_id = dialog_id.get_secret_chat_id(); { - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id); + auto user_id = td_->user_manager_->get_secret_chat_user_id(secret_chat_id); Dialog *user_d = get_dialog_force(DialogId(user_id), source); if (user_d != nullptr && user_d->notification_settings.is_synchronized) { VLOG(notifications) << "Copy notification settings from " << user_d->dialog_id << " to " << dialog_id; @@ -34277,7 +34270,7 @@ void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source } if (G()->use_message_database() && !td_->auth_manager_->is_bot() && - !td_->contacts_manager_->get_secret_chat_is_outbound(secret_chat_id)) { + !td_->user_manager_->get_secret_chat_is_outbound(secret_chat_id)) { auto notification_info = add_dialog_notification_info(d); auto notification_group_id = get_dialog_notification_group_id(dialog_id, notification_info->message_notification_group_); @@ -34289,7 +34282,7 @@ void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source notification_info->new_secret_chat_notification_id_ = get_next_notification_id(notification_info, notification_group_id, MessageId()); if (notification_info->new_secret_chat_notification_id_.is_valid()) { - auto date = td_->contacts_manager_->get_secret_chat_date(secret_chat_id); + auto date = td_->user_manager_->get_secret_chat_date(secret_chat_id); set_dialog_last_notification_checked(dialog_id, notification_info->message_notification_group_, date, notification_info->new_secret_chat_notification_id_, "add_new_secret_chat"); @@ -34368,8 +34361,8 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&di d->last_read_inbox_message_id = d->last_new_message_id; d->last_read_outbox_message_id = d->last_new_message_id; } - d->has_bots = dialog_id.get_user_id() != ContactsManager::get_replies_bot_user_id() && - td_->contacts_manager_->is_user_bot(dialog_id.get_user_id()); + d->has_bots = dialog_id.get_user_id() != UserManager::get_replies_bot_user_id() && + td_->user_manager_->is_user_bot(dialog_id.get_user_id()); d->is_has_bots_inited = true; d->is_available_reactions_inited = true; d->is_view_as_messages_inited = true; @@ -34421,13 +34414,13 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&di d->is_is_blocked_for_stories_inited = true; d->is_view_as_messages_inited = true; if (!d->is_folder_id_inited && !td_->auth_manager_->is_bot()) { - do_set_dialog_folder_id( - d, td_->contacts_manager_->get_secret_chat_initial_folder_id(dialog_id.get_secret_chat_id())); + do_set_dialog_folder_id(d, + td_->user_manager_->get_secret_chat_initial_folder_id(dialog_id.get_secret_chat_id())); } - d->message_ttl = MessageTtl(td_->contacts_manager_->get_secret_chat_ttl(dialog_id.get_secret_chat_id())); + d->message_ttl = MessageTtl(td_->user_manager_->get_secret_chat_ttl(dialog_id.get_secret_chat_id())); d->is_message_ttl_inited = true; - d->has_bots = td_->contacts_manager_->is_user_bot( - td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id())); + d->has_bots = + td_->user_manager_->is_user_bot(td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id())); d->is_has_bots_inited = true; d->is_available_reactions_inited = true; d->has_loaded_scheduled_messages_from_database = true; @@ -34563,7 +34556,7 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&draft auto dialog_type = dialog_id.get_type(); if (!td_->auth_manager_->is_bot() && dialog_type == DialogType::SecretChat) { - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + auto user_id = td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (user_id.is_valid()) { force_create_dialog(DialogId(user_id), "add chat with user to load/store action_bar and is_blocked"); @@ -35186,7 +35179,7 @@ void MessagesManager::update_dialog_pos(Dialog *d, const char *source, bool need break; } case DialogType::SecretChat: { - auto date = td_->contacts_manager_->get_secret_chat_date(d->dialog_id.get_secret_chat_id()); + auto date = td_->user_manager_->get_secret_chat_date(d->dialog_id.get_secret_chat_id()); if (date != 0 && !is_deleted_secret_chat(d)) { LOG(INFO) << "Creation at " << date << " found"; int64 creation_order = get_dialog_order(MessageId(), date); @@ -36516,7 +36509,7 @@ void MessagesManager::on_get_channel_difference(DialogId dialog_id, int32 reques case telegram_api::updates_channelDifference::ID: { auto difference = static_cast(difference_ptr.get()); have_new_messages = !difference->new_messages_.empty(); - td_->contacts_manager_->on_get_users(std::move(difference->users_), "updates.channelDifference"); + td_->user_manager_->on_get_users(std::move(difference->users_), "updates.channelDifference"); td_->contacts_manager_->on_get_chats(std::move(difference->chats_), "updates.channelDifference"); for (const auto &message : difference->new_messages_) { if (is_invalid_poll_message(message.get())) { @@ -36531,7 +36524,7 @@ void MessagesManager::on_get_channel_difference(DialogId dialog_id, int32 reques case telegram_api::updates_channelDifferenceTooLong::ID: { auto difference = static_cast(difference_ptr.get()); have_new_messages = difference->dialog_->get_id() == telegram_api::dialog::ID && !difference->messages_.empty(); - td_->contacts_manager_->on_get_users(std::move(difference->users_), "updates.channelDifferenceTooLong"); + td_->user_manager_->on_get_users(std::move(difference->users_), "updates.channelDifferenceTooLong"); td_->contacts_manager_->on_get_chats(std::move(difference->chats_), "updates.channelDifferenceTooLong"); break; } @@ -36879,7 +36872,7 @@ void MessagesManager::speculatively_update_channel_participants(DialogId dialog_ } auto channel_id = dialog_id.get_channel_id(); - UserId my_user_id(td_->contacts_manager_->get_my_id()); + UserId my_user_id(td_->user_manager_->get_my_id()); bool by_me = m->sender_user_id == my_user_id; switch (m->content->get_type()) { case MessageContentType::ChatAddUsers: @@ -36949,7 +36942,7 @@ void MessagesManager::update_top_dialogs(DialogId dialog_id, const Message *m) { TopDialogCategory category = TopDialogCategory::Size; switch (dialog_type) { case DialogType::User: { - if (td_->contacts_manager_->is_user_bot(dialog_id.get_user_id())) { + if (td_->user_manager_->is_user_bot(dialog_id.get_user_id())) { category = TopDialogCategory::BotPM; } else { category = TopDialogCategory::Correspondent; @@ -37032,7 +37025,7 @@ void MessagesManager::update_has_outgoing_messages(DialogId dialog_id, const Mes case DialogType::Channel: break; case DialogType::SecretChat: { - auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); + auto user_id = td_->user_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (user_id.is_valid()) { d = get_dialog_force(DialogId(user_id), "update_has_outgoing_messages"); } @@ -38256,7 +38249,7 @@ void MessagesManager::on_get_sponsored_dialog(tl_object_ptr vector> chats) { CHECK(peer != nullptr); - td_->contacts_manager_->on_get_users(std::move(users), "on_get_sponsored_dialog"); + td_->user_manager_->on_get_users(std::move(users), "on_get_sponsored_dialog"); td_->contacts_manager_->on_get_chats(std::move(chats), "on_get_sponsored_dialog"); set_sponsored_dialog(DialogId(peer), std::move(source)); diff --git a/td/telegram/NotificationManager.cpp b/td/telegram/NotificationManager.cpp index ff436f0ad..ee4a315db 100644 --- a/td/telegram/NotificationManager.cpp +++ b/td/telegram/NotificationManager.cpp @@ -9,7 +9,6 @@ #include "td/telegram/AuthManager.h" #include "td/telegram/ChannelId.h" #include "td/telegram/ChatId.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DeviceTokenManager.h" #include "td/telegram/DialogManager.h" #include "td/telegram/Document.h" @@ -33,6 +32,7 @@ #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/mtproto/AuthKey.h" #include "td/mtproto/mtproto_api.h" @@ -846,7 +846,7 @@ int32 NotificationManager::get_notification_delay_ms(DialogId dialog_id, const P auto server_time = G()->server_time(); auto delay_ms = [&] { - auto online_info = td_->contacts_manager_->get_my_online_status(); + auto online_info = td_->user_manager_->get_my_online_status(); if (!online_info.is_online_local && online_info.is_online_remote) { // If we are offline, but online from some other client, then delay notification // for 'notification_cloud_delay' seconds. @@ -3083,7 +3083,7 @@ void NotificationManager::add_push_notification_user( false /*ignored*/, false /*ignored*/, sender_user_id.get(), sender_access_hash, user_name, string(), string(), string(), std::move(sender_photo), nullptr, 0, Auto(), string(), string(), nullptr, vector>(), 0, nullptr, nullptr); - td_->contacts_manager_->on_get_user(std::move(user), "add_push_notification_user"); + td_->user_manager_->on_get_user(std::move(user), "add_push_notification_user"); } Status NotificationManager::parse_push_notification_attach(DialogId dialog_id, string &loc_key, JsonObject &custom, @@ -3573,7 +3573,7 @@ Status NotificationManager::process_push_notification_payload(string payload, bo } if (sender_user_id.is_valid() && - !td_->contacts_manager_->have_user_force(sender_user_id, "process_push_notification_payload")) { + !td_->user_manager_->have_user_force(sender_user_id, "process_push_notification_payload")) { int64 sender_access_hash = -1; telegram_api::object_ptr sender_photo; TRY_RESULT(mtpeer, custom.extract_optional_field("mtpeer", JsonValue::Type::Object)); @@ -3847,7 +3847,7 @@ void NotificationManager::add_message_push_notification(DialogId dialog_id, Mess } if (sender_user_id.is_valid() && - !td_->contacts_manager_->have_user_force(sender_user_id, "add_message_push_notification")) { + !td_->user_manager_->have_user_force(sender_user_id, "add_message_push_notification")) { add_push_notification_user(sender_user_id, -1, sender_name, nullptr); } @@ -3875,8 +3875,7 @@ void NotificationManager::add_message_push_notification(DialogId dialog_id, Mess auto group_id = info.group_id; CHECK(group_id.is_valid()); - bool is_outgoing = - sender_user_id.is_valid() ? td_->contacts_manager_->get_my_id() == sender_user_id : is_from_scheduled; + bool is_outgoing = sender_user_id.is_valid() ? td_->user_manager_->get_my_id() == sender_user_id : is_from_scheduled; if (log_event_id != 0) { VLOG(notifications) << "Register temporary " << notification_id << " with log event " << log_event_id; NotificationObjectFullId object_full_id(dialog_id, message_id); diff --git a/td/telegram/NotificationSettingsManager.cpp b/td/telegram/NotificationSettingsManager.cpp index ef1d526ec..c70bc4f07 100644 --- a/td/telegram/NotificationSettingsManager.cpp +++ b/td/telegram/NotificationSettingsManager.cpp @@ -31,6 +31,7 @@ #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/telegram/VoiceNotesManager.h" #include "td/db/binlog/BinlogEvent.h" @@ -271,7 +272,7 @@ class GetNotifySettingsExceptionsQuery final : public Td::ResultHandler { break; } } - td_->contacts_manager_->on_get_users(std::move(users), "GetNotifySettingsExceptionsQuery"); + td_->user_manager_->on_get_users(std::move(users), "GetNotifySettingsExceptionsQuery"); td_->contacts_manager_->on_get_chats(std::move(chats), "GetNotifySettingsExceptionsQuery"); for (auto &dialog_id : dialog_ids) { td_->dialog_manager_->force_create_dialog(dialog_id, "GetNotifySettingsExceptionsQuery"); @@ -326,7 +327,7 @@ class GetStoryNotifySettingsExceptionsQuery final : public Td::ResultHandler { break; } } - td_->contacts_manager_->on_get_users(std::move(users), "GetStoryNotifySettingsExceptionsQuery"); + td_->user_manager_->on_get_users(std::move(users), "GetStoryNotifySettingsExceptionsQuery"); td_->contacts_manager_->on_get_chats(std::move(chats), "GetStoryNotifySettingsExceptionsQuery"); for (auto &dialog_id : dialog_ids) { td_->dialog_manager_->force_create_dialog(dialog_id, "GetStoryNotifySettingsExceptionsQuery"); diff --git a/td/telegram/OptionManager.cpp b/td/telegram/OptionManager.cpp index eae8a1a0c..77c84c59c 100644 --- a/td/telegram/OptionManager.cpp +++ b/td/telegram/OptionManager.cpp @@ -31,6 +31,7 @@ #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" #include "td/telegram/TopDialogManager.h" +#include "td/telegram/UserManager.h" #include "td/db/KeyValueSyncInterface.h" #include "td/db/TsSeqKeyValue.h" @@ -98,11 +99,11 @@ OptionManager::OptionManager(Td *td) } }; set_default_integer_option("telegram_service_notifications_chat_id", - DialogId(ContactsManager::get_service_notifications_user_id()).get()); - set_default_integer_option("replies_bot_chat_id", DialogId(ContactsManager::get_replies_bot_user_id()).get()); - set_default_integer_option("group_anonymous_bot_user_id", ContactsManager::get_anonymous_bot_user_id().get()); - set_default_integer_option("channel_bot_user_id", ContactsManager::get_channel_bot_user_id().get()); - set_default_integer_option("anti_spam_bot_user_id", ContactsManager::get_anti_spam_bot_user_id().get()); + DialogId(UserManager::get_service_notifications_user_id()).get()); + set_default_integer_option("replies_bot_chat_id", DialogId(UserManager::get_replies_bot_user_id()).get()); + set_default_integer_option("group_anonymous_bot_user_id", UserManager::get_anonymous_bot_user_id().get()); + set_default_integer_option("channel_bot_user_id", UserManager::get_channel_bot_user_id().get()); + set_default_integer_option("anti_spam_bot_user_id", UserManager::get_anti_spam_bot_user_id().get()); set_default_integer_option("message_caption_length_max", 1024); set_default_integer_option("message_reply_quote_length_max", 1024); set_default_integer_option("story_caption_length_max", 200); @@ -524,6 +525,7 @@ void OptionManager::on_option_updated(Slice name) { case 'i': if (name == "ignored_restriction_reasons") { send_closure(td_->contacts_manager_actor_, &ContactsManager::on_ignored_restriction_reasons_changed); + send_closure(td_->user_manager_actor_, &UserManager::on_ignored_restriction_reasons_changed); } if (name == "is_emulator") { if (G()->mtproto_header().set_is_emulator(get_option_boolean(name))) { diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index ffd0185e0..9e1833bdb 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -7,7 +7,6 @@ #include "td/telegram/Payments.h" #include "td/telegram/AccessRights.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DialogId.h" #include "td/telegram/DialogManager.h" #include "td/telegram/GiveawayParameters.h" @@ -26,6 +25,7 @@ #include "td/telegram/ThemeManager.h" #include "td/telegram/UpdatesManager.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -82,7 +82,7 @@ Result get_input_invoice_info(Td *td, td_api::object_ptr(invoice->purpose_.get()); vector> input_users; for (auto user_id : p->user_ids_) { - TRY_RESULT(input_user, td->contacts_manager_->get_input_user(UserId(user_id))); + TRY_RESULT(input_user, td->user_manager_->get_input_user(UserId(user_id))); input_users.push_back(std::move(input_user)); } if (p->amount_ <= 0 || !check_currency_amount(p->amount_)) { @@ -433,7 +433,7 @@ class GetPaymentFormQuery final : public Td::ResultHandler { auto payment_form = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetPaymentFormQuery: " << to_string(payment_form); - td_->contacts_manager_->on_get_users(std::move(payment_form->users_), "GetPaymentFormQuery"); + td_->user_manager_->on_get_users(std::move(payment_form->users_), "GetPaymentFormQuery"); UserId payments_provider_user_id(payment_form->provider_id_); if (!payments_provider_user_id.is_valid()) { @@ -459,8 +459,8 @@ class GetPaymentFormQuery final : public Td::ResultHandler { }); promise_.set_value(make_tl_object( payment_form->form_id_, convert_invoice(std::move(payment_form->invoice_)), - td_->contacts_manager_->get_user_id_object(seller_bot_user_id, "paymentForm seller"), - td_->contacts_manager_->get_user_id_object(payments_provider_user_id, "paymentForm provider"), + td_->user_manager_->get_user_id_object(seller_bot_user_id, "paymentForm seller"), + td_->user_manager_->get_user_id_object(payments_provider_user_id, "paymentForm provider"), std::move(payment_provider), std::move(additional_payment_options), convert_order_info(std::move(payment_form->saved_info_)), convert_saved_credentials(std::move(payment_form->saved_credentials_)), can_save_credentials, need_password, @@ -613,7 +613,7 @@ class GetPaymentReceiptQuery final : public Td::ResultHandler { auto payment_receipt = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetPaymentReceiptQuery: " << to_string(payment_receipt); - td_->contacts_manager_->on_get_users(std::move(payment_receipt->users_), "GetPaymentReceiptQuery"); + td_->user_manager_->on_get_users(std::move(payment_receipt->users_), "GetPaymentReceiptQuery"); UserId payments_provider_user_id(payment_receipt->provider_id_); if (!payments_provider_user_id.is_valid()) { @@ -634,8 +634,8 @@ class GetPaymentReceiptQuery final : public Td::ResultHandler { promise_.set_value(make_tl_object( payment_receipt->title_, get_product_description_object(payment_receipt->description_), get_photo_object(td_->file_manager_.get(), photo), payment_receipt->date_, - td_->contacts_manager_->get_user_id_object(seller_bot_user_id, "paymentReceipt seller"), - td_->contacts_manager_->get_user_id_object(payments_provider_user_id, "paymentReceipt provider"), + td_->user_manager_->get_user_id_object(seller_bot_user_id, "paymentReceipt seller"), + td_->user_manager_->get_user_id_object(payments_provider_user_id, "paymentReceipt provider"), convert_invoice(std::move(payment_receipt->invoice_)), convert_order_info(std::move(payment_receipt->info_)), convert_shipping_option(std::move(payment_receipt->shipping_)), std::move(payment_receipt->credentials_title_), payment_receipt->tip_amount_)); diff --git a/td/telegram/PeopleNearbyManager.cpp b/td/telegram/PeopleNearbyManager.cpp index 300755da2..65defa871 100644 --- a/td/telegram/PeopleNearbyManager.cpp +++ b/td/telegram/PeopleNearbyManager.cpp @@ -14,6 +14,7 @@ #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -165,7 +166,7 @@ void PeopleNearbyManager::on_get_dialogs_nearby(Result(updates_ptr); LOG(INFO) << "Receive chats nearby in " << to_string(update); - td_->contacts_manager_->on_get_users(std::move(update->users_), "on_get_dialogs_nearby"); + td_->user_manager_->on_get_users(std::move(update->users_), "on_get_dialogs_nearby"); td_->contacts_manager_->on_get_chats(std::move(update->chats_), "on_get_dialogs_nearby"); for (auto &dialog_nearby : users_nearby_) { @@ -364,7 +365,7 @@ int32 PeopleNearbyManager::on_update_peer_located(vectorcontacts_manager_->have_user(user_id)) { + if (!td_->user_manager_->have_user(user_id)) { LOG(ERROR) << "Can't find " << user_id; continue; } diff --git a/td/telegram/PhoneNumberManager.cpp b/td/telegram/PhoneNumberManager.cpp index f8d9ce597..2648705d3 100644 --- a/td/telegram/PhoneNumberManager.cpp +++ b/td/telegram/PhoneNumberManager.cpp @@ -7,13 +7,13 @@ #include "td/telegram/PhoneNumberManager.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/SuggestedAction.h" #include "td/telegram/Td.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/logging.h" @@ -168,8 +168,7 @@ void PhoneNumberManager::process_check_code_result(Resultcontacts_manager(), &ContactsManager::on_get_user, result.move_as_ok(), - "process_check_code_result"); + send_closure(G()->user_manager(), &UserManager::on_get_user, result.move_as_ok(), "process_check_code_result"); state_ = State::Ok; on_current_query_ok(); } diff --git a/td/telegram/PollManager.cpp b/td/telegram/PollManager.cpp index 3571086d9..4b0852ffa 100644 --- a/td/telegram/PollManager.cpp +++ b/td/telegram/PollManager.cpp @@ -26,6 +26,7 @@ #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/db/binlog/BinlogEvent.h" #include "td/db/binlog/BinlogHelper.h" @@ -197,7 +198,7 @@ class StopPollQuery final : public Td::ResultHandler { } int32 flags = telegram_api::messages_editMessage::MEDIA_MASK; - auto input_reply_markup = get_input_reply_markup(td_->contacts_manager_.get(), reply_markup); + auto input_reply_markup = get_input_reply_markup(td_->user_manager_.get(), reply_markup); if (input_reply_markup != nullptr) { flags |= telegram_api::messages_editMessage::REPLY_MARKUP_MASK; } @@ -1187,7 +1188,7 @@ void PollManager::on_get_poll_voters(PollId poll_id, int32 option_id, string off } auto vote_list = result.move_as_ok(); - td_->contacts_manager_->on_get_users(std::move(vote_list->users_), "on_get_poll_voters"); + td_->user_manager_->on_get_users(std::move(vote_list->users_), "on_get_poll_voters"); td_->contacts_manager_->on_get_chats(std::move(vote_list->chats_), "on_get_poll_voters"); voters.next_offset_ = std::move(vote_list->next_offset_); @@ -1551,7 +1552,7 @@ tl_object_ptr PollManager::get_input_media(PollId poll 0, poll_flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, poll->question_, transform(poll->options_, get_input_poll_option), poll->open_period_, poll->close_date_), std::move(correct_answers), poll->explanation_.text, - get_input_message_entities(td_->contacts_manager_.get(), poll->explanation_.entities, "get_input_media_poll")); + get_input_message_entities(td_->user_manager_.get(), poll->explanation_.entities, "get_input_media_poll")); } vector PollManager::get_poll_options( @@ -1811,8 +1812,7 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptrcontacts_manager_.get(), std::move(poll_results->solution_entities_), source); + auto entities = get_message_entities(td_->user_manager_.get(), std::move(poll_results->solution_entities_), source); auto status = fix_formatted_text(poll_results->solution_, entities, true, true, true, true, false); if (status.is_error()) { if (!clean_input_string(poll_results->solution_)) { diff --git a/td/telegram/Premium.cpp b/td/telegram/Premium.cpp index 9d3c1328b..8c1668f11 100644 --- a/td/telegram/Premium.cpp +++ b/td/telegram/Premium.cpp @@ -29,6 +29,7 @@ #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -198,7 +199,7 @@ static Result> get_input_s case td_api::storePaymentPurposeGiftedPremium::ID: { auto p = static_cast(purpose.get()); UserId user_id(p->user_id_); - TRY_RESULT(input_user, td->contacts_manager_->get_input_user(user_id)); + TRY_RESULT(input_user, td->user_manager_->get_input_user(user_id)); if (p->amount_ <= 0 || !check_currency_amount(p->amount_)) { return Status::Error(400, "Invalid amount of the currency specified"); } @@ -209,7 +210,7 @@ static Result> get_input_s auto p = static_cast(purpose.get()); vector> input_users; for (auto user_id : p->user_ids_) { - TRY_RESULT(input_user, td->contacts_manager_->get_input_user(UserId(user_id))); + TRY_RESULT(input_user, td->user_manager_->get_input_user(UserId(user_id))); input_users.push_back(std::move(input_user)); } if (p->amount_ <= 0 || !check_currency_amount(p->amount_)) { @@ -259,9 +260,9 @@ class GetPremiumPromoQuery final : public Td::ResultHandler { auto promo = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetPremiumPromoQuery: " << to_string(promo); - td_->contacts_manager_->on_get_users(std::move(promo->users_), "GetPremiumPromoQuery"); + td_->user_manager_->on_get_users(std::move(promo->users_), "GetPremiumPromoQuery"); - auto state = get_message_text(td_->contacts_manager_.get(), std::move(promo->status_text_), + auto state = get_message_text(td_->user_manager_.get(), std::move(promo->status_text_), std::move(promo->status_entities_), true, true, 0, false, "GetPremiumPromoQuery"); if (promo->video_sections_.size() != promo->videos_.size()) { @@ -391,7 +392,7 @@ class CheckGiftCodeQuery final : public Td::ResultHandler { auto result = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for CheckGiftCodeQuery: " << to_string(result); - td_->contacts_manager_->on_get_users(std::move(result->users_), "CheckGiftCodeQuery"); + td_->user_manager_->on_get_users(std::move(result->users_), "CheckGiftCodeQuery"); td_->contacts_manager_->on_get_chats(std::move(result->chats_), "CheckGiftCodeQuery"); if (result->date_ <= 0 || result->months_ <= 0 || result->used_date_ < 0) { @@ -429,7 +430,7 @@ class CheckGiftCodeQuery final : public Td::ResultHandler { creator_dialog_id == DialogId() ? nullptr : get_message_sender_object(td_, creator_dialog_id, "premiumGiftCodeInfo"), result->date_, result->via_giveaway_, message_id.get(), result->months_, - td_->contacts_manager_->get_user_id_object(user_id, "premiumGiftCodeInfo"), result->used_date_)); + td_->user_manager_->get_user_id_object(user_id, "premiumGiftCodeInfo"), result->used_date_)); } void on_error(Status status) final { diff --git a/td/telegram/PrivacyManager.cpp b/td/telegram/PrivacyManager.cpp index 0da2084eb..2466f7a45 100644 --- a/td/telegram/PrivacyManager.cpp +++ b/td/telegram/PrivacyManager.cpp @@ -6,13 +6,13 @@ // #include "td/telegram/PrivacyManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" #include "td/telegram/net/NetQueryCreator.h" #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -211,7 +211,7 @@ void PrivacyManager::do_update_privacy(UserPrivacySetting user_privacy_setting, if (!G()->close_flag() && (from_update || was_synchronized)) { switch (user_privacy_setting.type()) { case UserPrivacySetting::Type::UserStatus: { - send_closure_later(G()->contacts_manager(), &ContactsManager::on_update_online_status_privacy); + send_closure_later(G()->user_manager(), &UserManager::on_update_online_status_privacy); auto old_restricted = info.rules_.get_restricted_user_ids(); auto new_restricted = privacy_rules.get_restricted_user_ids(); @@ -223,14 +223,14 @@ void PrivacyManager::do_update_privacy(UserPrivacySetting user_privacy_setting, new_restricted.end(), std::back_inserter(unrestricted), [](UserId lhs, UserId rhs) { return lhs.get() < rhs.get(); }); for (auto &user_id : unrestricted) { - send_closure_later(G()->contacts_manager(), &ContactsManager::reload_user, user_id, Promise(), + send_closure_later(G()->user_manager(), &UserManager::reload_user, user_id, Promise(), "do_update_privacy"); } } break; } case UserPrivacySetting::Type::UserPhoneNumber: - send_closure_later(G()->contacts_manager(), &ContactsManager::on_update_phone_number_privacy); + send_closure_later(G()->user_manager(), &UserManager::on_update_phone_number_privacy); break; default: break; diff --git a/td/telegram/QuickReplyManager.cpp b/td/telegram/QuickReplyManager.cpp index 1607e4d1f..6778ca775 100644 --- a/td/telegram/QuickReplyManager.cpp +++ b/td/telegram/QuickReplyManager.cpp @@ -29,6 +29,7 @@ #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/telegram/Version.h" #include "td/utils/algorithm.h" @@ -535,8 +536,8 @@ unique_ptr QuickReplyManager::create_messa bool disable_web_page_preview = false; auto content = get_message_content( td_, - get_message_text(td_->contacts_manager_.get(), std::move(message->message_), std::move(message->entities_), - true, td_->auth_manager_->is_bot(), 0, media_album_id != 0, source), + get_message_text(td_->user_manager_.get(), std::move(message->message_), std::move(message->entities_), true, + td_->auth_manager_->is_bot(), 0, media_album_id != 0, source), std::move(message->media_), my_dialog_id, message->date_, true, via_bot_user_id, &ttl, &disable_web_page_preview, source); @@ -662,9 +663,9 @@ td_api::object_ptr QuickReplyManager::get_quick_reply auto can_be_edited = can_edit_quick_reply_message(m); return td_api::make_object( m->message_id.get(), get_message_sending_state_object(m), can_be_edited, m->reply_to_message_id.get(), - td_->contacts_manager_->get_user_id_object(m->via_bot_user_id, "via_bot_user_id"), m->media_album_id, + td_->user_manager_->get_user_id_object(m->via_bot_user_id, "via_bot_user_id"), m->media_album_id, get_quick_reply_message_message_content_object(m), - get_reply_markup_object(td_->contacts_manager_.get(), m->reply_markup)); + get_reply_markup_object(td_->user_manager_.get(), m->reply_markup)); } int32 QuickReplyManager::get_shortcut_message_count(const Shortcut *s) { @@ -727,7 +728,7 @@ void QuickReplyManager::on_reload_quick_reply_shortcuts( break; case telegram_api::messages_quickReplies::ID: { auto shortcuts = telegram_api::move_object_as(shortcuts_ptr); - td_->contacts_manager_->on_get_users(std::move(shortcuts->users_), "messages.quickReplies"); + td_->user_manager_->on_get_users(std::move(shortcuts->users_), "messages.quickReplies"); td_->contacts_manager_->on_get_chats(std::move(shortcuts->chats_), "messages.quickReplies"); FlatHashMap, MessageIdHash> message_id_to_message; @@ -1239,7 +1240,7 @@ void QuickReplyManager::on_reload_quick_reply_messages( break; case telegram_api::messages_messages::ID: { auto messages = telegram_api::move_object_as(messages_ptr); - td_->contacts_manager_->on_get_users(std::move(messages->users_), "on_reload_quick_reply_messages"); + td_->user_manager_->on_get_users(std::move(messages->users_), "on_reload_quick_reply_messages"); td_->contacts_manager_->on_get_chats(std::move(messages->chats_), "on_reload_quick_reply_messages"); vector> quick_reply_messages; @@ -1366,7 +1367,7 @@ void QuickReplyManager::on_reload_quick_reply_message( return promise.set_error(Status::Error(400, "Receive wrong response")); case telegram_api::messages_messages::ID: { auto messages = telegram_api::move_object_as(messages_ptr); - td_->contacts_manager_->on_get_users(std::move(messages->users_), "on_reload_quick_reply_message"); + td_->user_manager_->on_get_users(std::move(messages->users_), "on_reload_quick_reply_message"); td_->contacts_manager_->on_get_chats(std::move(messages->chats_), "on_reload_quick_reply_message"); if (messages->messages_.size() > 1u) { @@ -1413,7 +1414,7 @@ Result> QuickReplyManager::g if (!td_->dialog_manager_->have_input_peer(dialog_id, AccessRights::Write)) { return Status::Error(400, "Have no write access to the chat"); } - if (dialog_id.get_type() != DialogType::User || td_->contacts_manager_->is_user_bot(dialog_id.get_user_id())) { + if (dialog_id.get_type() != DialogType::User || td_->user_manager_->is_user_bot(dialog_id.get_user_id())) { return Status::Error(400, "Can't use quick replies in the chat"); } diff --git a/td/telegram/RecentDialogList.cpp b/td/telegram/RecentDialogList.cpp index f37a76795..2892b9dea 100644 --- a/td/telegram/RecentDialogList.cpp +++ b/td/telegram/RecentDialogList.cpp @@ -16,6 +16,7 @@ #include "td/telegram/Td.h" #include "td/telegram/td_api.h" #include "td/telegram/TdDb.h" +#include "td/telegram/UserManager.h" #include "td/actor/MultiPromise.h" @@ -49,8 +50,8 @@ void RecentDialogList::save_dialogs() const { string username; switch (dialog_id.get_type()) { case DialogType::User: - if (!td_->contacts_manager_->is_user_contact(dialog_id.get_user_id())) { - username = td_->contacts_manager_->get_user_first_username(dialog_id.get_user_id()); + if (!td_->user_manager_->is_user_contact(dialog_id.get_user_id())) { + username = td_->user_manager_->get_user_first_username(dialog_id.get_user_id()); } break; case DialogType::Chat: @@ -116,7 +117,7 @@ void RecentDialogList::load_dialogs(Promise &&promise) { PromiseCreator::lambda([promise = mpas.get_promise()](td_api::object_ptr &&chats) mutable { promise.set_value(Unit()); })); - td_->contacts_manager_->search_contacts("", 1, mpas.get_promise()); + td_->user_manager_->search_contacts("", 1, mpas.get_promise()); } } diff --git a/td/telegram/RepliedMessageInfo.cpp b/td/telegram/RepliedMessageInfo.cpp index 1ab21e00b..52e111787 100644 --- a/td/telegram/RepliedMessageInfo.cpp +++ b/td/telegram/RepliedMessageInfo.cpp @@ -117,8 +117,8 @@ RepliedMessageInfo::RepliedMessageInfo(Td *td, tl_object_ptrquote_text_.empty()) { is_quote_manual_ = reply_header->quote_; - auto entities = get_message_entities(td->contacts_manager_.get(), std::move(reply_header->quote_entities_), - "RepliedMessageInfo"); + auto entities = + get_message_entities(td->user_manager_.get(), std::move(reply_header->quote_entities_), "RepliedMessageInfo"); auto status = fix_formatted_text(reply_header->quote_text_, entities, true, true, true, true, false); if (status.is_error()) { if (!clean_input_string(reply_header->quote_text_)) { diff --git a/td/telegram/ReplyMarkup.cpp b/td/telegram/ReplyMarkup.cpp index b2e61c376..d56c18852 100644 --- a/td/telegram/ReplyMarkup.cpp +++ b/td/telegram/ReplyMarkup.cpp @@ -6,13 +6,13 @@ // #include "td/telegram/ReplyMarkup.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Dependencies.h" #include "td/telegram/Global.h" #include "td/telegram/LinkManager.h" #include "td/telegram/misc.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -903,7 +903,7 @@ static tl_object_ptr get_input_keyboard_button(con } static tl_object_ptr get_input_keyboard_button( - ContactsManager *contacts_manager, const InlineKeyboardButton &keyboard_button) { + UserManager *user_manager, const InlineKeyboardButton &keyboard_button) { switch (keyboard_button.type) { case InlineKeyboardButton::Type::Url: return make_tl_object(keyboard_button.text, keyboard_button.data); @@ -952,7 +952,7 @@ static tl_object_ptr get_input_keyboard_button( if (!keyboard_button.forward_text.empty()) { flags |= telegram_api::inputKeyboardButtonUrlAuth::FWD_TEXT_MASK; } - auto r_input_user = contacts_manager->get_input_user(UserId(bot_user_id)); + auto r_input_user = user_manager->get_input_user(UserId(bot_user_id)); if (r_input_user.is_error()) { LOG(ERROR) << "Failed to get InputUser for " << bot_user_id << ": " << r_input_user.error(); return make_tl_object(keyboard_button.text, keyboard_button.data); @@ -965,7 +965,7 @@ static tl_object_ptr get_input_keyboard_button( UNREACHABLE(); break; case InlineKeyboardButton::Type::User: { - auto r_input_user = contacts_manager->get_input_user(keyboard_button.user_id); + auto r_input_user = user_manager->get_input_user(keyboard_button.user_id); if (r_input_user.is_error()) { LOG(ERROR) << "Failed to get InputUser for " << keyboard_button.user_id << ": " << r_input_user.error(); r_input_user = make_tl_object(); @@ -981,7 +981,7 @@ static tl_object_ptr get_input_keyboard_button( } } -tl_object_ptr ReplyMarkup::get_input_reply_markup(ContactsManager *contacts_manager) const { +tl_object_ptr ReplyMarkup::get_input_reply_markup(UserManager *user_manager) const { LOG(DEBUG) << "Send " << *this; switch (type) { case ReplyMarkup::Type::InlineKeyboard: { @@ -991,7 +991,7 @@ tl_object_ptr ReplyMarkup::get_input_reply_markup(Con vector> buttons; buttons.reserve(row.size()); for (auto &button : row) { - buttons.push_back(get_input_keyboard_button(contacts_manager, button)); + buttons.push_back(get_input_keyboard_button(user_manager, button)); } rows.push_back(make_tl_object(std::move(buttons))); } @@ -1067,7 +1067,7 @@ static tl_object_ptr get_keyboard_button_object(const Ke } static tl_object_ptr get_inline_keyboard_button_object( - ContactsManager *contacts_manager, const InlineKeyboardButton &keyboard_button) { + UserManager *user_manager, const InlineKeyboardButton &keyboard_button) { tl_object_ptr type; switch (keyboard_button.type) { case InlineKeyboardButton::Type::Url: @@ -1106,9 +1106,9 @@ static tl_object_ptr get_inline_keyboard_button_ob type = make_tl_object(keyboard_button.data); break; case InlineKeyboardButton::Type::User: { - bool need_user = contacts_manager != nullptr && !contacts_manager->is_user_bot(contacts_manager->get_my_id()); + bool need_user = user_manager != nullptr && !user_manager->is_user_bot(user_manager->get_my_id()); auto user_id = - need_user ? contacts_manager->get_user_id_object(keyboard_button.user_id, "get_inline_keyboard_button_object") + need_user ? user_manager->get_user_id_object(keyboard_button.user_id, "get_inline_keyboard_button_object") : keyboard_button.user_id.get(); type = make_tl_object(user_id); break; @@ -1123,7 +1123,7 @@ static tl_object_ptr get_inline_keyboard_button_ob return make_tl_object(keyboard_button.text, std::move(type)); } -tl_object_ptr ReplyMarkup::get_reply_markup_object(ContactsManager *contacts_manager) const { +tl_object_ptr ReplyMarkup::get_reply_markup_object(UserManager *user_manager) const { switch (type) { case ReplyMarkup::Type::InlineKeyboard: { vector>> rows; @@ -1132,7 +1132,7 @@ tl_object_ptr ReplyMarkup::get_reply_markup_object(Contacts vector> buttons; buttons.reserve(row.size()); for (auto &button : row) { - buttons.push_back(get_inline_keyboard_button_object(contacts_manager, button)); + buttons.push_back(get_inline_keyboard_button_object(user_manager, button)); } rows.push_back(std::move(buttons)); } @@ -1186,22 +1186,22 @@ Status ReplyMarkup::check_shared_dialog_count(int32 button_id, size_t count) con return Status::Error(400, "Button not found"); } -tl_object_ptr get_input_reply_markup(ContactsManager *contacts_manager, +tl_object_ptr get_input_reply_markup(UserManager *user_manager, const unique_ptr &reply_markup) { if (reply_markup == nullptr) { return nullptr; } - return reply_markup->get_input_reply_markup(contacts_manager); + return reply_markup->get_input_reply_markup(user_manager); } -tl_object_ptr get_reply_markup_object(ContactsManager *contacts_manager, +tl_object_ptr get_reply_markup_object(UserManager *user_manager, const unique_ptr &reply_markup) { if (reply_markup == nullptr) { return nullptr; } - return reply_markup->get_reply_markup_object(contacts_manager); + return reply_markup->get_reply_markup_object(user_manager); } void add_reply_markup_dependencies(Dependencies &dependencies, const ReplyMarkup *reply_markup) { diff --git a/td/telegram/ReplyMarkup.h b/td/telegram/ReplyMarkup.h index 415d9c50c..5f4ad3d71 100644 --- a/td/telegram/ReplyMarkup.h +++ b/td/telegram/ReplyMarkup.h @@ -18,8 +18,8 @@ namespace td { -class ContactsManager; class Dependencies; +class UserManager; struct KeyboardButton { // append only @@ -86,9 +86,9 @@ struct ReplyMarkup { StringBuilder &print(StringBuilder &string_builder) const; - tl_object_ptr get_input_reply_markup(ContactsManager *contacts_manager) const; + tl_object_ptr get_input_reply_markup(UserManager *user_manager) const; - tl_object_ptr get_reply_markup_object(ContactsManager *contacts_manager) const; + tl_object_ptr get_reply_markup_object(UserManager *user_manager) const; Status check_shared_dialog(Td *td, int32 button_id, DialogId dialog_id) const; @@ -112,10 +112,10 @@ Result> get_reply_markup(td_api::object_ptr dup_reply_markup(const unique_ptr &reply_markup); -tl_object_ptr get_input_reply_markup(ContactsManager *contacts_manager, +tl_object_ptr get_input_reply_markup(UserManager *user_manager, const unique_ptr &reply_markup); -tl_object_ptr get_reply_markup_object(ContactsManager *contacts_manager, +tl_object_ptr get_reply_markup_object(UserManager *user_manager, const unique_ptr &reply_markup); void add_reply_markup_dependencies(Dependencies &dependencies, const ReplyMarkup *reply_markup); diff --git a/td/telegram/RequestedDialogType.cpp b/td/telegram/RequestedDialogType.cpp index e512ce784..c8ba841d0 100644 --- a/td/telegram/RequestedDialogType.cpp +++ b/td/telegram/RequestedDialogType.cpp @@ -9,6 +9,7 @@ #include "td/telegram/ChannelType.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" namespace td { @@ -207,10 +208,10 @@ Status RequestedDialogType::check_shared_dialog(Td *td, DialogId dialog_id) cons return Status::Error(400, "Wrong chat type"); } auto user_id = dialog_id.get_user_id(); - if (restrict_is_bot_ && td->contacts_manager_->is_user_bot(user_id) != is_bot_) { + if (restrict_is_bot_ && td->user_manager_->is_user_bot(user_id) != is_bot_) { return Status::Error(400, "Wrong is_bot value"); } - if (restrict_is_premium_ && td->contacts_manager_->is_user_premium(user_id) != is_premium_) { + if (restrict_is_premium_ && td->user_manager_->is_user_premium(user_id) != is_premium_) { return Status::Error(400, "Wrong is_premium value"); } break; diff --git a/td/telegram/SavedMessagesManager.cpp b/td/telegram/SavedMessagesManager.cpp index eba0299d8..8bd4e4f0f 100644 --- a/td/telegram/SavedMessagesManager.cpp +++ b/td/telegram/SavedMessagesManager.cpp @@ -18,6 +18,7 @@ #include "td/telegram/ServerMessageId.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -584,7 +585,7 @@ void SavedMessagesManager::on_get_saved_messages_topics( default: UNREACHABLE(); } - td_->contacts_manager_->on_get_users(std::move(users), "on_get_saved_messages_topics"); + td_->user_manager_->on_get_users(std::move(users), "on_get_saved_messages_topics"); td_->contacts_manager_->on_get_chats(std::move(chats), "on_get_saved_messages_topics"); FlatHashMap, MessageIdHash> message_id_to_message; diff --git a/td/telegram/SecretChatsManager.cpp b/td/telegram/SecretChatsManager.cpp index aa525421a..966ce39b6 100644 --- a/td/telegram/SecretChatsManager.cpp +++ b/td/telegram/SecretChatsManager.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/SecretChatsManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DhCache.h" #include "td/telegram/EncryptedFile.h" #include "td/telegram/FolderId.h" @@ -20,6 +19,7 @@ #include "td/telegram/StateManager.h" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/mtproto/DhCallback.h" @@ -366,8 +366,8 @@ unique_ptr SecretChatsManager::make_secret_chat_contex void on_update_secret_chat(int64 access_hash, UserId user_id, SecretChatState state, bool is_outbound, int32 ttl, int32 date, string key_hash, int32 layer, FolderId initial_folder_id) final { - send_closure(G()->contacts_manager(), &ContactsManager::on_update_secret_chat, secret_chat_id_, access_hash, - user_id, state, is_outbound, ttl, date, key_hash, layer, initial_folder_id); + send_closure(G()->user_manager(), &UserManager::on_update_secret_chat, secret_chat_id_, access_hash, user_id, + state, is_outbound, ttl, date, key_hash, layer, initial_folder_id); } void on_inbound_message(UserId user_id, MessageId message_id, int32 date, unique_ptr file, diff --git a/td/telegram/SecureManager.cpp b/td/telegram/SecureManager.cpp index 36c0b345a..b1b0c768a 100644 --- a/td/telegram/SecureManager.cpp +++ b/td/telegram/SecureManager.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/SecureManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DialogId.h" #include "td/telegram/files/FileId.h" #include "td/telegram/files/FileManager.h" @@ -17,6 +16,7 @@ #include "td/telegram/PasswordManager.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -987,8 +987,8 @@ void SecureManager::on_get_passport_authorization_form( auto authorization_form = r_authorization_form.move_as_ok(); LOG(INFO) << "Receive " << to_string(authorization_form); - G()->td().get_actor_unsafe()->contacts_manager_->on_get_users(std::move(authorization_form->users_), - "on_get_passport_authorization_form"); + G()->td().get_actor_unsafe()->user_manager_->on_get_users(std::move(authorization_form->users_), + "on_get_passport_authorization_form"); vector> required_types; std::map all_types; diff --git a/td/telegram/SharedDialog.cpp b/td/telegram/SharedDialog.cpp index f55126bf0..edcfb44f8 100644 --- a/td/telegram/SharedDialog.cpp +++ b/td/telegram/SharedDialog.cpp @@ -9,10 +9,10 @@ #include "td/telegram/AuthManager.h" #include "td/telegram/ChannelId.h" #include "td/telegram/ChatId.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DialogManager.h" #include "td/telegram/Td.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" namespace td { @@ -52,7 +52,7 @@ td_api::object_ptr SharedDialog::get_shared_user_object(Td * CHECK(is_user()); auto user_id = td->auth_manager_->is_bot() ? dialog_id_.get_user_id().get() - : td->contacts_manager_->get_user_id_object(dialog_id_.get_user_id(), "sharedUser"); + : td->user_manager_->get_user_id_object(dialog_id_.get_user_id(), "sharedUser"); return td_api::make_object(user_id, first_name_, last_name_, username_, get_photo_object(td->file_manager_.get(), photo_)); } diff --git a/td/telegram/SponsoredMessageManager.cpp b/td/telegram/SponsoredMessageManager.cpp index 6b91d5ced..dba23f726 100644 --- a/td/telegram/SponsoredMessageManager.cpp +++ b/td/telegram/SponsoredMessageManager.cpp @@ -22,6 +22,7 @@ #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" #include "td/telegram/WebApp.h" #include "td/utils/algorithm.h" @@ -285,11 +286,11 @@ td_api::object_ptr SponsoredMessageManager::get_message_ switch (sponsored_message.sponsor_dialog_id.get_type()) { case DialogType::User: { auto user_id = sponsored_message.sponsor_dialog_id.get_user_id(); - if (!td_->contacts_manager_->is_user_bot(user_id)) { + if (!td_->user_manager_->is_user_bot(user_id)) { LOG(ERROR) << "Sponsor " << user_id << " is not a bot"; return nullptr; } - auto bot_username = td_->contacts_manager_->get_user_first_username(user_id); + auto bot_username = td_->user_manager_->get_user_first_username(user_id); if (bot_username.empty()) { LOG(ERROR) << "Sponsor " << user_id << " has no username"; return nullptr; @@ -298,12 +299,12 @@ td_api::object_ptr SponsoredMessageManager::get_message_ type = sponsored_message.web_app.get_message_sponsor_type_web_app(bot_username, sponsored_message.start_param); } else { type = td_api::make_object( - td_->contacts_manager_->get_user_id_object(user_id, "messageSponsorTypeBot"), + td_->user_manager_->get_user_id_object(user_id, "messageSponsorTypeBot"), td_api::make_object(bot_username, sponsored_message.start_param, false)); } if (sponsored_message.show_dialog_photo) { - photo = get_chat_photo_info_object(td_->file_manager_.get(), - td_->contacts_manager_->get_user_dialog_photo(user_id)); + photo = + get_chat_photo_info_object(td_->file_manager_.get(), td_->user_manager_->get_user_dialog_photo(user_id)); } break; } @@ -442,7 +443,7 @@ void SponsoredMessageManager::on_get_dialog_sponsored_messages( auto sponsored_messages = telegram_api::move_object_as(sponsored_messages_ptr); - td_->contacts_manager_->on_get_users(std::move(sponsored_messages->users_), "on_get_dialog_sponsored_messages"); + td_->user_manager_->on_get_users(std::move(sponsored_messages->users_), "on_get_dialog_sponsored_messages"); td_->contacts_manager_->on_get_chats(std::move(sponsored_messages->chats_), "on_get_dialog_sponsored_messages"); for (auto &sponsored_message : sponsored_messages->messages_) { @@ -493,7 +494,7 @@ void SponsoredMessageManager::on_get_dialog_sponsored_messages( continue; } - auto message_text = get_message_text(td_->contacts_manager_.get(), std::move(sponsored_message->message_), + auto message_text = get_message_text(td_->user_manager_.get(), std::move(sponsored_message->message_), std::move(sponsored_message->entities_), true, true, 0, false, "on_get_dialog_sponsored_messages"); MessageSelfDestructType ttl; diff --git a/td/telegram/StatisticsManager.cpp b/td/telegram/StatisticsManager.cpp index 046f1d84d..7ff312691 100644 --- a/td/telegram/StatisticsManager.cpp +++ b/td/telegram/StatisticsManager.cpp @@ -18,6 +18,7 @@ #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" @@ -84,7 +85,7 @@ static td_api::object_ptr convert_megagroup_st Td *td, telegram_api::object_ptr obj) { CHECK(obj != nullptr); - td->contacts_manager_->on_get_users(std::move(obj->users_), "convert_megagroup_stats"); + td->user_manager_->on_get_users(std::move(obj->users_), "convert_megagroup_stats"); // just in case td::remove_if(obj->top_posters_, [](auto &obj) { @@ -99,19 +100,19 @@ static td_api::object_ptr convert_megagroup_st auto top_senders = transform( std::move(obj->top_posters_), [td](telegram_api::object_ptr &&top_poster) { return td_api::make_object( - td->contacts_manager_->get_user_id_object(UserId(top_poster->user_id_), "get_top_senders"), + td->user_manager_->get_user_id_object(UserId(top_poster->user_id_), "get_top_senders"), top_poster->messages_, top_poster->avg_chars_); }); auto top_administrators = transform( std::move(obj->top_admins_), [td](telegram_api::object_ptr &&top_admin) { return td_api::make_object( - td->contacts_manager_->get_user_id_object(UserId(top_admin->user_id_), "get_top_administrators"), + td->user_manager_->get_user_id_object(UserId(top_admin->user_id_), "get_top_administrators"), top_admin->deleted_, top_admin->kicked_, top_admin->banned_); }); auto top_inviters = transform( std::move(obj->top_inviters_), [td](telegram_api::object_ptr &&top_inviter) { return td_api::make_object( - td->contacts_manager_->get_user_id_object(UserId(top_inviter->user_id_), "get_top_inviters"), + td->user_manager_->get_user_id_object(UserId(top_inviter->user_id_), "get_top_inviters"), top_inviter->invitations_); }); @@ -713,7 +714,7 @@ void StatisticsManager::on_get_public_forwards( void StatisticsManager::get_channel_differences_if_needed( telegram_api::object_ptr &&public_forwards, Promise> promise, const char *source) { - td_->contacts_manager_->on_get_users(std::move(public_forwards->users_), "stats_publicForwards"); + td_->user_manager_->on_get_users(std::move(public_forwards->users_), "stats_publicForwards"); td_->contacts_manager_->on_get_chats(std::move(public_forwards->chats_), "stats_publicForwards"); vector *> messages; diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 148721f48..0bcdba8f7 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -9,7 +9,6 @@ #include "td/telegram/AccessRights.h" #include "td/telegram/AuthManager.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DialogId.h" #include "td/telegram/DialogManager.h" #include "td/telegram/Document.h" @@ -38,6 +37,7 @@ #include "td/telegram/td_api.h" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/telegram/Version.h" #include "td/db/SqliteKeyValue.h" @@ -4405,12 +4405,12 @@ vector StickersManager::get_stickers(StickerType sticker_type, string qu if (sticker_type == StickerType::CustomEmoji) { switch (dialog_id.get_type()) { case DialogType::User: - if (dialog_id.get_user_id() == td_->contacts_manager_->get_my_id()) { + if (dialog_id.get_user_id() == td_->user_manager_->get_my_id()) { allow_premium = true; } break; case DialogType::SecretChat: - if (td_->contacts_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()) < + if (td_->user_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()) < static_cast(SecretChatLayer::SpoilerAndCustomEmojiEntities)) { promise.set_value(Unit()); return {}; @@ -7845,10 +7845,10 @@ FileId StickersManager::upload_sticker_file(UserId user_id, StickerFormat sticke Promise &&promise) { bool is_bot = td_->auth_manager_->is_bot(); if (!is_bot) { - user_id = td_->contacts_manager_->get_my_id(); + user_id = td_->user_manager_->get_my_id(); } - auto r_input_user = td_->contacts_manager_->get_input_user(user_id); + auto r_input_user = td_->user_manager_->get_input_user(user_id); if (r_input_user.is_error()) { promise.set_error(r_input_user.move_as_error()); return FileId(); @@ -7952,10 +7952,10 @@ void StickersManager::create_new_sticker_set(UserId user_id, string title, strin Promise> &&promise) { bool is_bot = td_->auth_manager_->is_bot(); if (!is_bot) { - user_id = td_->contacts_manager_->get_my_id(); + user_id = td_->user_manager_->get_my_id(); } - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); title = strip_empty_characters(title, MAX_STICKER_SET_TITLE_LENGTH); if (title.empty()) { @@ -8189,7 +8189,7 @@ void StickersManager::on_new_stickers_uploaded(int64 random_id, Result res CHECK(pending_new_sticker_set->upload_files_multipromise_.promise_count() == 0); auto &promise = pending_new_sticker_set->promise_; - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(pending_new_sticker_set->user_id_)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(pending_new_sticker_set->user_id_)); StickerType sticker_type = pending_new_sticker_set->sticker_type_; @@ -8224,10 +8224,10 @@ void StickersManager::add_sticker_to_set(UserId user_id, string short_name, td_api::object_ptr &&old_sticker, Promise &&promise) { bool is_bot = td_->auth_manager_->is_bot(); if (!is_bot) { - user_id = td_->contacts_manager_->get_my_id(); + user_id = td_->user_manager_->get_my_id(); } - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); short_name = clean_username(strip_empty_characters(short_name, MAX_STICKER_SET_SHORT_NAME_LENGTH)); if (short_name.empty()) { @@ -8340,10 +8340,10 @@ void StickersManager::set_sticker_set_thumbnail(UserId user_id, string short_nam Promise &&promise) { bool is_bot = td_->auth_manager_->is_bot(); if (!is_bot) { - user_id = td_->contacts_manager_->get_my_id(); + user_id = td_->user_manager_->get_my_id(); } - TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id)); + TRY_RESULT_PROMISE(promise, input_user, td_->user_manager_->get_input_user(user_id)); short_name = clean_username(strip_empty_characters(short_name, MAX_STICKER_SET_SHORT_NAME_LENGTH)); if (short_name.empty()) { diff --git a/td/telegram/StoryInteractionInfo.cpp b/td/telegram/StoryInteractionInfo.cpp index 06ccb75c6..ecc8c35de 100644 --- a/td/telegram/StoryInteractionInfo.cpp +++ b/td/telegram/StoryInteractionInfo.cpp @@ -6,10 +6,10 @@ // #include "td/telegram/StoryInteractionInfo.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/Dependencies.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/FlatHashSet.h" @@ -25,7 +25,7 @@ StoryInteractionInfo::StoryInteractionInfo(Td *td, telegram_api::object_ptrrecent_viewers_) { UserId user_id(viewer_id); - if (user_id.is_valid() && td->contacts_manager_->have_min_user(user_id)) { + if (user_id.is_valid() && td->user_manager_->have_min_user(user_id)) { if (recent_viewer_user_ids_.size() == MAX_RECENT_VIEWERS) { LOG(ERROR) << "Receive too many recent story viewers: " << story_views->recent_viewers_; break; @@ -135,7 +135,7 @@ td_api::object_ptr StoryInteractionInfo::get_story } return td_api::make_object( view_count_, forward_count_, reaction_count_, - td->contacts_manager_->get_user_ids_object(recent_viewer_user_ids_, "get_story_interaction_info_object")); + td->user_manager_->get_user_ids_object(recent_viewer_user_ids_, "get_story_interaction_info_object")); } bool operator==(const StoryInteractionInfo &lhs, const StoryInteractionInfo &rhs) { diff --git a/td/telegram/StoryManager.cpp b/td/telegram/StoryManager.cpp index bd4ecc6e2..bd66ec50b 100644 --- a/td/telegram/StoryManager.cpp +++ b/td/telegram/StoryManager.cpp @@ -38,6 +38,7 @@ #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserManager.h" #include "td/telegram/WebPagesManager.h" #include "td/db/binlog/BinlogEvent.h" @@ -941,7 +942,7 @@ class StoryManager::SendStoryQuery final : public Td::ResultHandler { } const FormattedText &caption = story->caption_; - auto entities = get_input_message_entities(td_->contacts_manager_.get(), &caption, "SendStoryQuery"); + auto entities = get_input_message_entities(td_->user_manager_.get(), &caption, "SendStoryQuery"); if (!td_->option_manager_->get_option_boolean("can_use_text_entities_in_story_caption")) { entities.clear(); } @@ -1057,7 +1058,7 @@ class StoryManager::EditStoryQuery final : public Td::ResultHandler { flags |= telegram_api::stories_editStory::CAPTION_MASK; if (td_->option_manager_->get_option_boolean("can_use_text_entities_in_story_caption")) { flags |= telegram_api::stories_editStory::ENTITIES_MASK; - entities = get_input_message_entities(td_->contacts_manager_.get(), &edited_story->caption_, "EditStoryQuery"); + entities = get_input_message_entities(td_->user_manager_.get(), &edited_story->caption_, "EditStoryQuery"); } } @@ -2100,7 +2101,7 @@ void StoryManager::on_load_active_stories_from_server( } case telegram_api::stories_allStories::ID: { auto stories = telegram_api::move_object_as(all_stories); - td_->contacts_manager_->on_get_users(std::move(stories->users_), "on_load_active_stories_from_server"); + td_->user_manager_->on_get_users(std::move(stories->users_), "on_load_active_stories_from_server"); td_->contacts_manager_->on_get_chats(std::move(stories->chats_), "on_load_active_stories_from_server"); if (stories->state_.empty()) { LOG(ERROR) << "Receive empty state in " << to_string(stories); @@ -2143,7 +2144,7 @@ void StoryManager::on_load_active_stories_from_server( } else { LOG(ERROR) << "Receive " << story_date << " after " << max_story_date << " for " << (is_next ? "next" : "first") << " request with state \"" << old_state << "\" in " - << story_list_id << " of " << td_->contacts_manager_->get_my_id(); + << story_list_id << " of " << td_->user_manager_->get_my_id(); } owner_dialog_ids.push_back(owner_dialog_id); } @@ -2501,7 +2502,7 @@ void StoryManager::on_get_dialog_expiring_stories(DialogId owner_dialog_id, telegram_api::object_ptr &&stories, Promise> &&promise) { TRY_STATUS_PROMISE(promise, G()->close_status()); - td_->contacts_manager_->on_get_users(std::move(stories->users_), "on_get_dialog_expiring_stories"); + td_->user_manager_->on_get_users(std::move(stories->users_), "on_get_dialog_expiring_stories"); td_->contacts_manager_->on_get_chats(std::move(stories->chats_), "on_get_dialog_expiring_stories"); owner_dialog_id = on_get_dialog_stories(owner_dialog_id, std::move(stories->stories_), Promise()); if (promise) { @@ -2632,7 +2633,7 @@ void StoryManager::view_story_message(StoryFullId story_full_id) { } void StoryManager::on_story_replied(StoryFullId story_full_id, UserId replier_user_id) { - if (!replier_user_id.is_valid() || replier_user_id == td_->contacts_manager_->get_my_id() || + if (!replier_user_id.is_valid() || replier_user_id == td_->user_manager_->get_my_id() || !story_full_id.get_story_id().is_server()) { return; } @@ -2893,7 +2894,7 @@ bool StoryManager::has_unexpired_viewers(StoryFullId story_full_id, const Story void StoryManager::get_channel_differences_if_needed( telegram_api::object_ptr &&story_views, Promise> promise) { - td_->contacts_manager_->on_get_users(std::move(story_views->users_), "stories_storyViewsList"); + td_->user_manager_->on_get_users(std::move(story_views->users_), "stories_storyViewsList"); td_->contacts_manager_->on_get_chats(std::move(story_views->chats_), "stories_storyViewsList"); vector *> messages; @@ -3000,7 +3001,7 @@ void StoryManager::on_get_story_interactions( void StoryManager::get_channel_differences_if_needed( telegram_api::object_ptr &&story_reactions, Promise> promise) { - td_->contacts_manager_->on_get_users(std::move(story_reactions->users_), "stories_storyReactionsList"); + td_->user_manager_->on_get_users(std::move(story_reactions->users_), "stories_storyReactionsList"); td_->contacts_manager_->on_get_chats(std::move(story_reactions->chats_), "stories_storyReactionsList"); vector *> messages; @@ -3408,7 +3409,7 @@ StoryId StoryManager::on_get_new_story(DialogId owner_dialog_id, bool is_bot = td_->auth_manager_->is_bot(); auto caption = - get_message_text(td_->contacts_manager_.get(), std::move(story_item->caption_), std::move(story_item->entities_), + get_message_text(td_->user_manager_.get(), std::move(story_item->caption_), std::move(story_item->entities_), true, is_bot, story_item->date_, false, "on_get_new_story"); auto content = get_story_content(td_, std::move(story_item->media_), owner_dialog_id); if (content == nullptr) { @@ -3795,7 +3796,7 @@ void StoryManager::unregister_story_global_id(const Story *story) { std::pair> StoryManager::on_get_stories( DialogId owner_dialog_id, vector &&expected_story_ids, telegram_api::object_ptr &&stories) { - td_->contacts_manager_->on_get_users(std::move(stories->users_), "on_get_stories"); + td_->user_manager_->on_get_users(std::move(stories->users_), "on_get_stories"); td_->contacts_manager_->on_get_chats(std::move(stories->chats_), "on_get_stories"); vector story_ids; @@ -3903,7 +3904,7 @@ void StoryManager::on_update_dialog_max_story_ids(DialogId owner_dialog_id, Stor switch (owner_dialog_id.get_type()) { case DialogType::User: // use send_closure_later because story order can be updated from update_user - send_closure_later(td_->contacts_manager_actor_, &ContactsManager::on_update_user_story_ids, + send_closure_later(td_->user_manager_actor_, &UserManager::on_update_user_story_ids, owner_dialog_id.get_user_id(), max_story_id, max_read_story_id); break; case DialogType::Channel: @@ -3922,7 +3923,7 @@ void StoryManager::on_update_dialog_max_story_ids(DialogId owner_dialog_id, Stor void StoryManager::on_update_dialog_max_read_story_id(DialogId owner_dialog_id, StoryId max_read_story_id) { switch (owner_dialog_id.get_type()) { case DialogType::User: - td_->contacts_manager_->on_update_user_max_read_story_id(owner_dialog_id.get_user_id(), max_read_story_id); + td_->user_manager_->on_update_user_max_read_story_id(owner_dialog_id.get_user_id(), max_read_story_id); break; case DialogType::Channel: td_->contacts_manager_->on_update_channel_max_read_story_id(owner_dialog_id.get_channel_id(), max_read_story_id); @@ -3938,7 +3939,7 @@ void StoryManager::on_update_dialog_max_read_story_id(DialogId owner_dialog_id, void StoryManager::on_update_dialog_has_pinned_stories(DialogId owner_dialog_id, bool has_pinned_stories) { switch (owner_dialog_id.get_type()) { case DialogType::User: - td_->contacts_manager_->on_update_user_has_pinned_stories(owner_dialog_id.get_user_id(), has_pinned_stories); + td_->user_manager_->on_update_user_has_pinned_stories(owner_dialog_id.get_user_id(), has_pinned_stories); break; case DialogType::Channel: td_->contacts_manager_->on_update_channel_has_pinned_stories(owner_dialog_id.get_channel_id(), @@ -3955,7 +3956,7 @@ void StoryManager::on_update_dialog_has_pinned_stories(DialogId owner_dialog_id, void StoryManager::on_update_dialog_stories_hidden(DialogId owner_dialog_id, bool stories_hidden) { switch (owner_dialog_id.get_type()) { case DialogType::User: - td_->contacts_manager_->on_update_user_stories_hidden(owner_dialog_id.get_user_id(), stories_hidden); + td_->user_manager_->on_update_user_stories_hidden(owner_dialog_id.get_user_id(), stories_hidden); break; case DialogType::Channel: td_->contacts_manager_->on_update_channel_stories_hidden(owner_dialog_id.get_channel_id(), stories_hidden); @@ -4079,7 +4080,7 @@ bool StoryManager::update_active_stories_order(DialogId owner_dialog_id, ActiveS int64 new_private_order = 0; new_private_order += last_story->date_; if (owner_dialog_id.get_type() == DialogType::User && - td_->contacts_manager_->is_user_premium(owner_dialog_id.get_user_id())) { + td_->user_manager_->is_user_premium(owner_dialog_id.get_user_id())) { new_private_order += static_cast(1) << 33; } if (owner_dialog_id == get_changelog_story_dialog_id()) { @@ -4369,7 +4370,7 @@ void StoryManager::update_stealth_mode() { DialogId StoryManager::get_changelog_story_dialog_id() const { return DialogId(UserId(td_->option_manager_->get_option_integer( - "stories_changelog_user_id", ContactsManager::get_service_notifications_user_id().get()))); + "stories_changelog_user_id", UserManager::get_service_notifications_user_id().get()))); } bool StoryManager::is_subscribed_to_dialog_stories(DialogId owner_dialog_id) const { @@ -4381,7 +4382,7 @@ bool StoryManager::is_subscribed_to_dialog_stories(DialogId owner_dialog_id) con if (is_my_story(owner_dialog_id)) { return true; } - return td_->contacts_manager_->is_user_contact(owner_dialog_id.get_user_id()); + return td_->user_manager_->is_user_contact(owner_dialog_id.get_user_id()); case DialogType::Channel: return td_->contacts_manager_->get_channel_status(owner_dialog_id.get_channel_id()).is_member(); case DialogType::Chat: @@ -4398,8 +4399,7 @@ StoryListId StoryManager::get_dialog_story_list_id(DialogId owner_dialog_id) con } switch (owner_dialog_id.get_type()) { case DialogType::User: - if (!is_my_story(owner_dialog_id) && - td_->contacts_manager_->get_user_stories_hidden(owner_dialog_id.get_user_id())) { + if (!is_my_story(owner_dialog_id) && td_->user_manager_->get_user_stories_hidden(owner_dialog_id.get_user_id())) { return StoryListId::archive(); } return StoryListId::main(); @@ -4432,7 +4432,7 @@ void StoryManager::on_dialog_active_stories_order_updated(DialogId owner_dialog_ void StoryManager::on_get_story_views(DialogId owner_dialog_id, const vector &story_ids, telegram_api::object_ptr &&story_views) { schedule_interaction_info_update(); - td_->contacts_manager_->on_get_users(std::move(story_views->users_), "on_get_story_views"); + td_->user_manager_->on_get_users(std::move(story_views->users_), "on_get_story_views"); if (story_ids.size() != story_views->views_.size()) { LOG(ERROR) << "Receive invalid views for " << story_ids << ": " << to_string(story_views); return; @@ -4483,7 +4483,7 @@ void StoryManager::on_view_dialog_active_stories(vector dialog_ids) { bool need_poll = [&] { switch (dialog_id.get_type()) { case DialogType::User: - return td_->contacts_manager_->can_poll_user_active_stories(dialog_id.get_user_id()); + return td_->user_manager_->can_poll_user_active_stories(dialog_id.get_user_id()); case DialogType::Channel: return td_->contacts_manager_->can_poll_channel_active_stories(dialog_id.get_channel_id()); case DialogType::Chat: @@ -4530,7 +4530,7 @@ void StoryManager::on_get_dialog_max_active_story_ids(const vector &di auto dialog_id = dialog_ids[i]; if (max_story_id == StoryId() || max_story_id.is_server()) { if (dialog_id.get_type() == DialogType::User) { - td_->contacts_manager_->on_update_user_story_ids(dialog_id.get_user_id(), max_story_id, StoryId()); + td_->user_manager_->on_update_user_story_ids(dialog_id.get_user_id(), max_story_id, StoryId()); } else { td_->contacts_manager_->on_update_channel_story_ids(dialog_id.get_channel_id(), max_story_id, StoryId()); } diff --git a/td/telegram/Support.cpp b/td/telegram/Support.cpp index db6d41e6a..a43d67178 100644 --- a/td/telegram/Support.cpp +++ b/td/telegram/Support.cpp @@ -6,12 +6,12 @@ // #include "td/telegram/Support.h" -#include "td/telegram/ContactsManager.h" #include "td/telegram/DialogManager.h" #include "td/telegram/Global.h" #include "td/telegram/MessageEntity.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/utils/buffer.h" #include "td/utils/Status.h" @@ -25,7 +25,7 @@ static td_api::object_ptr get_user_support_info_object( FormattedText message; if (user_info->get_id() == telegram_api::help_userInfo::ID) { auto info = telegram_api::move_object_as(user_info); - message = get_message_text(td->contacts_manager_.get(), std::move(info->message_), std::move(info->entities_), true, + message = get_message_text(td->user_manager_.get(), std::move(info->message_), std::move(info->entities_), true, true, info->date_, false, "get_user_support_info_object"); result->author_ = std::move(info->author_); result->date_ = info->date_; @@ -43,7 +43,7 @@ class GetUserInfoQuery final : public Td::ResultHandler { } void send(UserId user_id) { - auto r_input_user = td_->contacts_manager_->get_input_user(user_id); + auto r_input_user = td_->user_manager_->get_input_user(user_id); if (r_input_user.is_error()) { return on_error(r_input_user.move_as_error()); } @@ -74,14 +74,14 @@ class EditUserInfoQuery final : public Td::ResultHandler { } void send(UserId user_id, FormattedText &&formatted_text) { - auto r_input_user = td_->contacts_manager_->get_input_user(user_id); + auto r_input_user = td_->user_manager_->get_input_user(user_id); if (r_input_user.is_error()) { return on_error(r_input_user.move_as_error()); } send_query(G()->net_query_creator().create(telegram_api::help_editUserInfo( r_input_user.move_as_ok(), formatted_text.text, - get_input_message_entities(td_->contacts_manager_.get(), &formatted_text, "EditUserInfoQuery")))); + get_input_message_entities(td_->user_manager_.get(), &formatted_text, "EditUserInfoQuery")))); } void on_result(BufferSlice packet) final { diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index b3111222b..c1796f28a 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -267,7 +267,7 @@ class GetRecentMeUrlsQuery final : public Td::ResultHandler { } auto urls_full = result_ptr.move_as_ok(); - td_->contacts_manager_->on_get_users(std::move(urls_full->users_), "GetRecentMeUrlsQuery"); + td_->user_manager_->on_get_users(std::move(urls_full->users_), "GetRecentMeUrlsQuery"); td_->contacts_manager_->on_get_chats(std::move(urls_full->chats_), "GetRecentMeUrlsQuery"); auto urls = std::move(urls_full->urls_); @@ -286,8 +286,8 @@ class GetRecentMeUrlsQuery final : public Td::ResultHandler { result = nullptr; break; } - result->type_ = make_tl_object( - td_->contacts_manager_->get_user_id_object(user_id, "tMeUrlTypeUser")); + result->type_ = + make_tl_object(td_->user_manager_->get_user_id_object(user_id, "tMeUrlTypeUser")); break; } case telegram_api::recentMeUrlChat::ID: { @@ -601,11 +601,11 @@ class GetMeRequest final : public RequestActor<> { UserId user_id_; void do_run(Promise &&promise) final { - user_id_ = td_->contacts_manager_->get_me(std::move(promise)); + user_id_ = td_->user_manager_->get_me(std::move(promise)); } void do_send_result() final { - send_result(td_->contacts_manager_->get_user_object(user_id_)); + send_result(td_->user_manager_->get_user_object(user_id_)); } public: @@ -617,11 +617,11 @@ class GetUserRequest final : public RequestActor<> { UserId user_id_; void do_run(Promise &&promise) final { - td_->contacts_manager_->get_user(user_id_, get_tries(), std::move(promise)); + td_->user_manager_->get_user(user_id_, get_tries(), std::move(promise)); } void do_send_result() final { - send_result(td_->contacts_manager_->get_user_object(user_id_)); + send_result(td_->user_manager_->get_user_object(user_id_)); } public: @@ -635,11 +635,11 @@ class GetUserFullInfoRequest final : public RequestActor<> { UserId user_id_; void do_run(Promise &&promise) final { - td_->contacts_manager_->load_user_full(user_id_, get_tries() < 2, std::move(promise), "GetUserFullInfoRequest"); + td_->user_manager_->load_user_full(user_id_, get_tries() < 2, std::move(promise), "GetUserFullInfoRequest"); } void do_send_result() final { - send_result(td_->contacts_manager_->get_user_full_info_object(user_id_)); + send_result(td_->user_manager_->get_user_full_info_object(user_id_)); } public: @@ -723,11 +723,11 @@ class GetSecretChatRequest final : public RequestActor<> { SecretChatId secret_chat_id_; void do_run(Promise &&promise) final { - td_->contacts_manager_->get_secret_chat(secret_chat_id_, get_tries() < 2, std::move(promise)); + td_->user_manager_->get_secret_chat(secret_chat_id_, get_tries() < 2, std::move(promise)); } void do_send_result() final { - send_result(td_->contacts_manager_->get_secret_chat_object(secret_chat_id_)); + send_result(td_->user_manager_->get_secret_chat_object(secret_chat_id_)); } public: @@ -766,11 +766,11 @@ class SearchUserByPhoneNumberRequest final : public RequestActor<> { UserId user_id_; void do_run(Promise &&promise) final { - user_id_ = td_->contacts_manager_->search_user_by_phone_number(phone_number_, std::move(promise)); + user_id_ = td_->user_manager_->search_user_by_phone_number(phone_number_, std::move(promise)); } void do_send_result() final { - send_result(td_->contacts_manager_->get_user_object(user_id_)); + send_result(td_->user_manager_->get_user_object(user_id_)); } public: @@ -1729,7 +1729,7 @@ class ImportContactsRequest final : public RequestActor<> { std::pair, vector> imported_contacts_; void do_run(Promise &&promise) final { - imported_contacts_ = td_->contacts_manager_->import_contacts(contacts_, random_id_, std::move(promise)); + imported_contacts_ = td_->user_manager_->import_contacts(contacts_, random_id_, std::move(promise)); } void do_send_result() final { @@ -1737,7 +1737,7 @@ class ImportContactsRequest final : public RequestActor<> { CHECK(imported_contacts_.second.size() == contacts_.size()); send_result(make_tl_object(transform(imported_contacts_.first, [this](UserId user_id) { - return td_->contacts_manager_->get_user_id_object( + return td_->user_manager_->get_user_id_object( user_id, "ImportContactsRequest"); }), std::move(imported_contacts_.second))); @@ -1757,11 +1757,11 @@ class SearchContactsRequest final : public RequestActor<> { std::pair> user_ids_; void do_run(Promise &&promise) final { - user_ids_ = td_->contacts_manager_->search_contacts(query_, limit_, std::move(promise)); + user_ids_ = td_->user_manager_->search_contacts(query_, limit_, std::move(promise)); } void do_send_result() final { - send_result(td_->contacts_manager_->get_users_object(user_ids_.first, user_ids_.second)); + send_result(td_->user_manager_->get_users_object(user_ids_.first, user_ids_.second)); } public: @@ -1774,7 +1774,7 @@ class RemoveContactsRequest final : public RequestActor<> { vector user_ids_; void do_run(Promise &&promise) final { - td_->contacts_manager_->remove_contacts(user_ids_, std::move(promise)); + td_->user_manager_->remove_contacts(user_ids_, std::move(promise)); } public: @@ -1788,7 +1788,7 @@ class GetImportedContactCountRequest final : public RequestActor<> { int32 imported_contact_count_ = 0; void do_run(Promise &&promise) final { - imported_contact_count_ = td_->contacts_manager_->get_imported_contact_count(std::move(promise)); + imported_contact_count_ = td_->user_manager_->get_imported_contact_count(std::move(promise)); } void do_send_result() final { @@ -1808,7 +1808,7 @@ class ChangeImportedContactsRequest final : public RequestActor<> { std::pair, vector> imported_contacts_; void do_run(Promise &&promise) final { - imported_contacts_ = td_->contacts_manager_->change_imported_contacts(contacts_, random_id_, std::move(promise)); + imported_contacts_ = td_->user_manager_->change_imported_contacts(contacts_, random_id_, std::move(promise)); } void do_send_result() final { @@ -1816,7 +1816,7 @@ class ChangeImportedContactsRequest final : public RequestActor<> { CHECK(imported_contacts_.second.size() == contacts_size_); send_result(make_tl_object(transform(imported_contacts_.first, [this](UserId user_id) { - return td_->contacts_manager_->get_user_id_object( + return td_->user_manager_->get_user_id_object( user_id, "ChangeImportedContactsRequest"); }), std::move(imported_contacts_.second))); @@ -1836,11 +1836,11 @@ class GetCloseFriendsRequest final : public RequestActor<> { vector user_ids_; void do_run(Promise &&promise) final { - user_ids_ = td_->contacts_manager_->get_close_friends(std::move(promise)); + user_ids_ = td_->user_manager_->get_close_friends(std::move(promise)); } void do_send_result() final { - send_result(td_->contacts_manager_->get_users_object(-1, user_ids_)); + send_result(td_->user_manager_->get_users_object(-1, user_ids_)); } public: @@ -1856,7 +1856,7 @@ class GetRecentInlineBotsRequest final : public RequestActor<> { } void do_send_result() final { - send_result(td_->contacts_manager_->get_users_object(-1, user_ids_)); + send_result(td_->user_manager_->get_users_object(-1, user_ids_)); } public: @@ -2597,7 +2597,7 @@ void Td::on_online_updated(bool force, bool send_update) { return; } if (force || is_online_) { - contacts_manager_->set_my_online_status(is_online_, send_update, true); + user_manager_->set_my_online_status(is_online_, send_update, true); if (!update_status_query_.empty()) { LOG(INFO) << "Cancel previous update status query"; cancel_query(update_status_query_); @@ -2617,7 +2617,7 @@ void Td::on_update_status_success(bool is_online) { if (!update_status_query_.empty()) { update_status_query_ = NetQueryRef(); } - contacts_manager_->set_my_online_status(is_online_, true, false); + user_manager_->set_my_online_status(is_online_, true, false); } } @@ -3675,7 +3675,7 @@ void Td::init(Parameters parameters, Result r_opened_datab void Td::process_binlog_events(TdDb::OpenedDatabase &&events) { VLOG(td_init) << "Send binlog events"; for (auto &event : events.user_events) { - contacts_manager_->on_binlog_user_event(std::move(event)); + user_manager_->on_binlog_user_event(std::move(event)); } for (auto &event : events.channel_events) { @@ -3688,7 +3688,7 @@ void Td::process_binlog_events(TdDb::OpenedDatabase &&events) { } for (auto &event : events.secret_chat_events) { - contacts_manager_->on_binlog_secret_chat_event(std::move(event)); + user_manager_->on_binlog_secret_chat_event(std::move(event)); } for (auto &event : events.web_page_events) { @@ -6144,7 +6144,7 @@ void Td::on_request(uint64 id, td_api::createNewSupergroupChat &request) { void Td::on_request(uint64 id, const td_api::createNewSecretChat &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - contacts_manager_->create_new_secret_chat(UserId(request.user_id_), std::move(promise)); + user_manager_->create_new_secret_chat(UserId(request.user_id_), std::move(promise)); } void Td::on_request(uint64 id, const td_api::createCall &request) { @@ -6155,7 +6155,7 @@ void Td::on_request(uint64 id, const td_api::createCall &request) { } UserId user_id(request.user_id_); - auto r_input_user = contacts_manager_->get_input_user(user_id); + auto r_input_user = user_manager_->get_input_user(user_id); if (r_input_user.is_error()) { return send_error_raw(id, r_input_user.error().code(), r_input_user.error().message()); } @@ -6696,7 +6696,7 @@ void Td::on_request(uint64 id, td_api::setNewChatPrivacySettings &request) { void Td::on_request(uint64 id, const td_api::canSendMessageToUser &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - contacts_manager_->can_send_message_to_user(UserId(request.user_id_), request.only_local_, std::move(promise)); + user_manager_->can_send_message_to_user(UserId(request.user_id_), request.only_local_, std::move(promise)); } void Td::on_request(uint64 id, td_api::setChatTitle &request) { @@ -7052,7 +7052,7 @@ void Td::on_request(uint64 id, const td_api::unpinAllMessageThreadMessages &requ void Td::on_request(uint64 id, const td_api::joinChat &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - dialog_participant_manager_->add_dialog_participant(DialogId(request.chat_id_), contacts_manager_->get_my_id(), 0, + dialog_participant_manager_->add_dialog_participant(DialogId(request.chat_id_), user_manager_->get_my_id(), 0, std::move(promise)); } @@ -7545,7 +7545,7 @@ void Td::on_request(uint64 id, td_api::addContact &request) { return send_closure(actor_id(this), &Td::send_error, id, r_contact.move_as_error()); } CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->add_contact(r_contact.move_as_ok(), request.share_phone_number_, std::move(promise)); + user_manager_->add_contact(r_contact.move_as_ok(), request.share_phone_number_, std::move(promise)); } void Td::on_request(uint64 id, td_api::importContacts &request) { @@ -7600,7 +7600,7 @@ void Td::on_request(uint64 id, td_api::changeImportedContacts &request) { void Td::on_request(uint64 id, const td_api::clearImportedContacts &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->clear_imported_contacts(std::move(promise)); + user_manager_->clear_imported_contacts(std::move(promise)); } void Td::on_request(uint64 id, const td_api::getCloseFriends &request) { @@ -7611,19 +7611,19 @@ void Td::on_request(uint64 id, const td_api::getCloseFriends &request) { void Td::on_request(uint64 id, const td_api::setCloseFriends &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_close_friends(UserId::get_user_ids(request.user_ids_), std::move(promise)); + user_manager_->set_close_friends(UserId::get_user_ids(request.user_ids_), std::move(promise)); } void Td::on_request(uint64 id, td_api::setUserPersonalProfilePhoto &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_user_profile_photo(UserId(request.user_id_), request.photo_, false, std::move(promise)); + user_manager_->set_user_profile_photo(UserId(request.user_id_), request.photo_, false, std::move(promise)); } void Td::on_request(uint64 id, td_api::suggestUserProfilePhoto &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_user_profile_photo(UserId(request.user_id_), request.photo_, true, std::move(promise)); + user_manager_->set_user_profile_photo(UserId(request.user_id_), request.photo_, true, std::move(promise)); } void Td::on_request(uint64 id, td_api::searchUserByPhoneNumber &request) { @@ -7635,7 +7635,7 @@ void Td::on_request(uint64 id, td_api::searchUserByPhoneNumber &request) { void Td::on_request(uint64 id, const td_api::sharePhoneNumber &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->share_phone_number(UserId(request.user_id_), std::move(promise)); + user_manager_->share_phone_number(UserId(request.user_id_), std::move(promise)); } void Td::on_request(uint64 id, const td_api::getRecentInlineBots &request) { @@ -7648,28 +7648,28 @@ void Td::on_request(uint64 id, td_api::setName &request) { CLEAN_INPUT_STRING(request.first_name_); CLEAN_INPUT_STRING(request.last_name_); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_name(request.first_name_, request.last_name_, std::move(promise)); + user_manager_->set_name(request.first_name_, request.last_name_, std::move(promise)); } void Td::on_request(uint64 id, td_api::setBio &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.bio_); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_bio(request.bio_, std::move(promise)); + user_manager_->set_bio(request.bio_, std::move(promise)); } void Td::on_request(uint64 id, td_api::setUsername &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.username_); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_username(request.username_, std::move(promise)); + user_manager_->set_username(request.username_, std::move(promise)); } void Td::on_request(uint64 id, td_api::toggleUsernameIsActive &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.username_); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->toggle_username_is_active(std::move(request.username_), request.is_active_, std::move(promise)); + user_manager_->toggle_username_is_active(std::move(request.username_), request.is_active_, std::move(promise)); } void Td::on_request(uint64 id, td_api::reorderActiveUsernames &request) { @@ -7678,25 +7678,25 @@ void Td::on_request(uint64 id, td_api::reorderActiveUsernames &request) { CLEAN_INPUT_STRING(username); } CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->reorder_usernames(std::move(request.usernames_), std::move(promise)); + user_manager_->reorder_usernames(std::move(request.usernames_), std::move(promise)); } void Td::on_request(uint64 id, td_api::setBirthdate &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_birthdate(Birthdate(std::move(request.birthdate_)), std::move(promise)); + user_manager_->set_birthdate(Birthdate(std::move(request.birthdate_)), std::move(promise)); } void Td::on_request(uint64 id, const td_api::setPersonalChat &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_personal_channel(DialogId(request.chat_id_), std::move(promise)); + user_manager_->set_personal_channel(DialogId(request.chat_id_), std::move(promise)); } void Td::on_request(uint64 id, const td_api::setEmojiStatus &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_emoji_status(EmojiStatus(request.emoji_status_), std::move(promise)); + user_manager_->set_emoji_status(EmojiStatus(request.emoji_status_), std::move(promise)); } void Td::on_request(uint64 id, const td_api::getThemedEmojiStatuses &request) { @@ -7822,15 +7822,15 @@ void Td::on_request(uint64 id, const td_api::getBotName &request) { void Td::on_request(uint64 id, td_api::setBotProfilePhoto &request) { CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_bot_profile_photo(UserId(request.bot_user_id_), request.photo_, std::move(promise)); + user_manager_->set_bot_profile_photo(UserId(request.bot_user_id_), request.photo_, std::move(promise)); } void Td::on_request(uint64 id, td_api::toggleBotUsernameIsActive &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.username_); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->toggle_bot_username_is_active(UserId(request.bot_user_id_), std::move(request.username_), - request.is_active_, std::move(promise)); + user_manager_->toggle_bot_username_is_active(UserId(request.bot_user_id_), std::move(request.username_), + request.is_active_, std::move(promise)); } void Td::on_request(uint64 id, td_api::reorderBotActiveUsernames &request) { @@ -7839,8 +7839,7 @@ void Td::on_request(uint64 id, td_api::reorderBotActiveUsernames &request) { CLEAN_INPUT_STRING(username); } CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->reorder_bot_usernames(UserId(request.bot_user_id_), std::move(request.usernames_), - std::move(promise)); + user_manager_->reorder_bot_usernames(UserId(request.bot_user_id_), std::move(request.usernames_), std::move(promise)); } void Td::on_request(uint64 id, td_api::setBotInfoDescription &request) { @@ -7923,34 +7922,33 @@ void Td::on_request(uint64 id, td_api::setBusinessIntro &request) { void Td::on_request(uint64 id, td_api::setProfilePhoto &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_profile_photo(request.photo_, request.is_public_, std::move(promise)); + user_manager_->set_profile_photo(request.photo_, request.is_public_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::deleteProfilePhoto &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->delete_profile_photo(request.profile_photo_id_, false, std::move(promise)); + user_manager_->delete_profile_photo(request.profile_photo_id_, false, std::move(promise)); } void Td::on_request(uint64 id, const td_api::getUserProfilePhotos &request) { CREATE_REQUEST_PROMISE(); - contacts_manager_->get_user_profile_photos(UserId(request.user_id_), request.offset_, request.limit_, - std::move(promise)); + user_manager_->get_user_profile_photos(UserId(request.user_id_), request.offset_, request.limit_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::setAccentColor &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_accent_color(AccentColorId(request.accent_color_id_), - CustomEmojiId(request.background_custom_emoji_id_), std::move(promise)); + user_manager_->set_accent_color(AccentColorId(request.accent_color_id_), + CustomEmojiId(request.background_custom_emoji_id_), std::move(promise)); } void Td::on_request(uint64 id, const td_api::setProfileAccentColor &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_profile_accent_color(AccentColorId(request.profile_accent_color_id_), - CustomEmojiId(request.profile_background_custom_emoji_id_), - std::move(promise)); + user_manager_->set_profile_accent_color(AccentColorId(request.profile_accent_color_id_), + CustomEmojiId(request.profile_background_custom_emoji_id_), + std::move(promise)); } void Td::on_request(uint64 id, const td_api::getBusinessConnectedBot &request) { @@ -8984,7 +8982,7 @@ void Td::on_request(uint64 id, const td_api::deletePassportElement &request) { void Td::on_request(uint64 id, td_api::setPassportElementErrors &request) { CHECK_IS_BOT(); - auto r_input_user = contacts_manager_->get_input_user(UserId(request.user_id_)); + auto r_input_user = user_manager_->get_input_user(UserId(request.user_id_)); if (r_input_user.is_error()) { return send_error_raw(id, r_input_user.error().code(), r_input_user.error().message()); } @@ -9115,7 +9113,7 @@ void Td::on_request(uint64 id, td_api::checkPhoneNumberConfirmationCode &request void Td::on_request(uint64 id, const td_api::getSupportUser &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - contacts_manager_->get_support_user(std::move(promise)); + user_manager_->get_support_user(std::move(promise)); } void Td::on_request(uint64 id, const td_api::getInstalledBackgrounds &request) { diff --git a/td/telegram/TopDialogManager.cpp b/td/telegram/TopDialogManager.cpp index 3ad6a7cc2..00ce795ba 100644 --- a/td/telegram/TopDialogManager.cpp +++ b/td/telegram/TopDialogManager.cpp @@ -21,6 +21,7 @@ #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/actor/PromiseFuture.h" @@ -408,16 +409,16 @@ void TopDialogManager::on_load_dialogs(GetTopDialogsQuery &&query, vectorcontacts_manager_->is_user_deleted(user_id)) { + if (td_->user_manager_->is_user_deleted(user_id)) { LOG(INFO) << "Skip deleted " << user_id; continue; } - if (td_->contacts_manager_->get_my_id() == user_id) { + if (td_->user_manager_->get_my_id() == user_id) { LOG(INFO) << "Skip self " << user_id; continue; } if (query.category == TopDialogCategory::BotInline || query.category == TopDialogCategory::BotPM) { - auto r_bot_info = td_->contacts_manager_->get_bot_data(user_id); + auto r_bot_info = td_->user_manager_->get_bot_data(user_id); if (r_bot_info.is_error()) { LOG(INFO) << "Skip not a bot " << user_id; continue; @@ -495,7 +496,7 @@ void TopDialogManager::on_get_top_peers(Result(std::move(top_peers_parent)); - td_->contacts_manager_->on_get_users(std::move(top_peers->users_), "on get top chats"); + td_->user_manager_->on_get_users(std::move(top_peers->users_), "on get top chats"); td_->contacts_manager_->on_get_chats(std::move(top_peers->chats_), "on get top chats"); for (auto &category : top_peers->categories_) { auto dialog_category = get_top_dialog_category(category->category_); diff --git a/td/telegram/TranslationManager.cpp b/td/telegram/TranslationManager.cpp index 7e443ea37..016805995 100644 --- a/td/telegram/TranslationManager.cpp +++ b/td/telegram/TranslationManager.cpp @@ -28,10 +28,9 @@ class TranslateTextQuery final : public Td::ResultHandler { void send(vector &&texts, const string &to_language_code) { int flags = telegram_api::messages_translateText::TEXT_MASK; - auto input_texts = - transform(std::move(texts), [contacts_manager = td_->contacts_manager_.get()](FormattedText &&text) { - return get_input_text_with_entities(contacts_manager, std::move(text), "TranslateTextQuery"); - }); + auto input_texts = transform(std::move(texts), [user_manager = td_->user_manager_.get()](FormattedText &&text) { + return get_input_text_with_entities(user_manager, std::move(text), "TranslateTextQuery"); + }); send_query(G()->net_query_creator().create(telegram_api::messages_translateText( flags, nullptr, vector{}, std::move(input_texts), to_language_code))); } @@ -87,7 +86,7 @@ void TranslationManager::translate_text(td_api::object_ptrcontacts_manager_.get(), std::move(text->entities_))); + TRY_RESULT_PROMISE(promise, entities, get_message_entities(td_->user_manager_.get(), std::move(text->entities_))); TRY_STATUS_PROMISE(promise, fix_formatted_text(text->text_, entities, true, true, true, true, true)); translate_text(FormattedText{std::move(text->text_), std::move(entities)}, skip_bot_commands, max_media_timestamp, @@ -120,9 +119,8 @@ void TranslationManager::on_get_translated_texts(vectorcontacts_manager_.get(), std::move(texts[0]), true, true, skip_bot_commands, - max_media_timestamp == -1, true, "on_get_translated_texts"); + auto formatted_text = get_formatted_text(td_->user_manager_.get(), std::move(texts[0]), true, true, skip_bot_commands, + max_media_timestamp == -1, true, "on_get_translated_texts"); promise.set_value(get_formatted_text_object(formatted_text, skip_bot_commands, max_media_timestamp)); } diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index b2dd673b2..63917d699 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -81,6 +81,7 @@ #include "td/telegram/ThemeManager.h" #include "td/telegram/TimeZoneManager.h" #include "td/telegram/TranscriptionManager.h" +#include "td/telegram/UserManager.h" #include "td/telegram/Usernames.h" #include "td/telegram/WebPagesManager.h" @@ -703,8 +704,7 @@ void UpdatesManager::set_date(int32 date, bool from_update, string date_source) } bool UpdatesManager::is_acceptable_user(UserId user_id) const { - return td_->contacts_manager_->have_user_force(user_id, "is_acceptable_user") && - td_->contacts_manager_->have_user(user_id); + return td_->user_manager_->have_user_force(user_id, "is_acceptable_user") && td_->user_manager_->have_user(user_id); } bool UpdatesManager::is_acceptable_chat(ChatId chat_id) const { @@ -753,7 +753,7 @@ bool UpdatesManager::is_acceptable_message_entities( if (entity->get_id() == telegram_api::messageEntityMentionName::ID) { auto entity_mention_name = static_cast(entity.get()); UserId user_id(entity_mention_name->user_id_); - if (!is_acceptable_user(user_id) || td_->contacts_manager_->get_input_user(user_id).is_error()) { + if (!is_acceptable_user(user_id) || td_->user_manager_->get_input_user(user_id).is_error()) { return false; } } @@ -770,7 +770,7 @@ bool UpdatesManager::is_acceptable_reply_markup(const tl_object_ptrget_id() == telegram_api::keyboardButtonUserProfile::ID) { auto user_profile_button = static_cast(button.get()); UserId user_id(user_profile_button->user_id_); - if (!is_acceptable_user(user_id) || td_->contacts_manager_->get_input_user(user_id).is_error()) { + if (!is_acceptable_user(user_id) || td_->user_manager_->get_input_user(user_id).is_error()) { return false; } } @@ -1189,7 +1189,7 @@ void UpdatesManager::on_get_updates_impl(tl_object_ptr up break; case telegram_api::updateShortMessage::ID: { auto update = move_tl_object_as(updates_ptr); - auto from_id = update->out_ ? td_->contacts_manager_->get_my_id().get() : update->user_id_; + auto from_id = update->out_ ? td_->user_manager_->get_my_id().get() : update->user_id_; auto message = make_tl_object( fix_short_message_flags(update->flags_), update->out_, update->mentioned_, update->media_unread_, update->silent_, false, false, false, false, false, false, false, 0, false, update->id_, @@ -1231,7 +1231,7 @@ void UpdatesManager::on_get_updates_impl(tl_object_ptr up } case telegram_api::updatesCombined::ID: { auto updates = move_tl_object_as(updates_ptr); - td_->contacts_manager_->on_get_users(std::move(updates->users_), "updatesCombined"); + td_->user_manager_->on_get_users(std::move(updates->users_), "updatesCombined"); td_->contacts_manager_->on_get_chats(std::move(updates->chats_), "updatesCombined"); on_pending_updates(std::move(updates->updates_), updates->seq_start_, updates->seq_, updates->date_, Time::now(), std::move(promise), "telegram_api::updatesCombined"); @@ -1245,7 +1245,7 @@ void UpdatesManager::on_get_updates_impl(tl_object_ptr up source_str = PSTRING() << "update " << updates->updates_[0]->get_id(); source = source_str.c_str(); } - td_->contacts_manager_->on_get_users(std::move(updates->users_), source); + td_->user_manager_->on_get_users(std::move(updates->users_), source); td_->contacts_manager_->on_get_chats(std::move(updates->chats_), source); on_pending_updates(std::move(updates->updates_), updates->seq_, updates->seq_, updates->date_, Time::now(), std::move(promise), "telegram_api::updates"); @@ -1907,7 +1907,7 @@ void UpdatesManager::on_get_difference(tl_object_ptr(difference_ptr); VLOG(get_difference) << "In get difference receive " << difference->users_.size() << " users and " << difference->chats_.size() << " chats"; - td_->contacts_manager_->on_get_users(std::move(difference->users_), "updates.difference"); + td_->user_manager_->on_get_users(std::move(difference->users_), "updates.difference"); td_->contacts_manager_->on_get_chats(std::move(difference->chats_), "updates.difference"); if (get_difference_retry_count_ <= 5) { @@ -1943,7 +1943,7 @@ void UpdatesManager::on_get_difference(tl_object_ptrusers_.size() << " users and " << difference->chats_.size() << " chats"; - td_->contacts_manager_->on_get_users(std::move(difference->users_), "updates.differenceSlice"); + td_->user_manager_->on_get_users(std::move(difference->users_), "updates.differenceSlice"); td_->contacts_manager_->on_get_chats(std::move(difference->chats_), "updates.differenceSlice"); if (get_difference_retry_count_ <= 5) { @@ -2040,7 +2040,7 @@ void UpdatesManager::on_get_pts_update(int32 pts, return; } - td_->contacts_manager_->on_get_users(std::move(difference->users_), "on_get_pts_update"); + td_->user_manager_->on_get_users(std::move(difference->users_), "on_get_pts_update"); td_->contacts_manager_->on_get_chats(std::move(difference->chats_), "on_get_pts_update"); for (auto &message : difference->new_messages_) { @@ -2236,7 +2236,6 @@ void UpdatesManager::try_reload_data() { LOG(INFO) << "Reload data"; td_->animations_manager_->reload_saved_animations(true); td_->autosave_manager_->reload_autosave_settings(); - td_->contacts_manager_->reload_contact_birthdates(false); td_->contacts_manager_->reload_created_public_dialogs(PublicDialogType::HasUsername, std::move(promise)); td_->contacts_manager_->reload_created_public_dialogs(PublicDialogType::IsLocationBased, Auto()); td_->contacts_manager_->reload_created_public_dialogs(PublicDialogType::ForPersonalDialog, Auto()); @@ -2282,6 +2281,7 @@ void UpdatesManager::try_reload_data() { td_->theme_manager_->reload_chat_themes(); td_->theme_manager_->reload_profile_accent_colors(); td_->time_zone_manager_->reload_time_zones(Auto()); + td_->user_manager_->reload_contact_birthdates(false); schedule_data_reload(); } @@ -2402,7 +2402,7 @@ void UpdatesManager::on_pending_updates(vectorcontacts_manager_->on_update_user_local_was_online(user_id, date); + td_->user_manager_->on_update_user_local_was_online(user_id, date); } } } @@ -3953,36 +3953,36 @@ void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { SecretChatId secret_chat_id(update->chat_id_); - UserId user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id); + UserId user_id = td_->user_manager_->get_secret_chat_user_id(secret_chat_id); td_->dialog_action_manager_->on_dialog_action(DialogId(secret_chat_id), MessageId(), DialogId(user_id), DialogAction::get_typing_action(), get_short_update_date()); promise.set_value(Unit()); } void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { - td_->contacts_manager_->on_update_user_online(UserId(update->user_id_), std::move(update->status_)); + td_->user_manager_->on_update_user_online(UserId(update->user_id_), std::move(update->status_)); promise.set_value(Unit()); } void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { - td_->contacts_manager_->on_update_user_name(UserId(update->user_id_), std::move(update->first_name_), - std::move(update->last_name_), - Usernames{string(), std::move(update->usernames_)}); + td_->user_manager_->on_update_user_name(UserId(update->user_id_), std::move(update->first_name_), + std::move(update->last_name_), + Usernames{string(), std::move(update->usernames_)}); promise.set_value(Unit()); } void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { - td_->contacts_manager_->on_update_user_phone_number(UserId(update->user_id_), std::move(update->phone_)); + td_->user_manager_->on_update_user_phone_number(UserId(update->user_id_), std::move(update->phone_)); promise.set_value(Unit()); } void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { - td_->contacts_manager_->invalidate_user_full(UserId(update->user_id_)); + td_->user_manager_->invalidate_user_full(UserId(update->user_id_)); promise.set_value(Unit()); } void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { - td_->contacts_manager_->on_update_user_emoji_status(UserId(update->user_id_), std::move(update->emoji_status_)); + td_->user_manager_->on_update_user_emoji_status(UserId(update->user_id_), std::move(update->emoji_status_)); promise.set_value(Unit()); } @@ -4004,7 +4004,7 @@ void UpdatesManager::on_update(tl_object_ptr up } void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { - td_->contacts_manager_->on_update_bot_menu_button(UserId(update->bot_id_), std::move(update->button_)); + td_->user_manager_->on_update_bot_menu_button(UserId(update->bot_id_), std::move(update->button_)); promise.set_value(Unit()); } @@ -4239,7 +4239,7 @@ void UpdatesManager::on_update(tl_object_ptrtd(), &Td::send_update, make_tl_object( - update->query_id_, td_->contacts_manager_->get_user_id_object(user_id, "updateNewShippingQuery"), + update->query_id_, td_->user_manager_->get_user_id_object(user_id, "updateNewShippingQuery"), update->payload_.as_slice().str(), get_address_object(get_address(std::move(update->shipping_address_))))); // TODO use convert_address } @@ -4253,12 +4253,11 @@ void UpdatesManager::on_update(tl_object_ptrtotal_amount_ <= 0 || !check_currency_amount(update->total_amount_)) { LOG(ERROR) << "Receive pre-checkout query with invalid total amount " << update->total_amount_; } else { - send_closure( - G()->td(), &Td::send_update, - make_tl_object( - update->query_id_, td_->contacts_manager_->get_user_id_object(user_id, "updateNewPreCheckoutQuery"), - update->currency_, update->total_amount_, update->payload_.as_slice().str(), update->shipping_option_id_, - get_order_info_object(get_order_info(std::move(update->info_))))); + send_closure(G()->td(), &Td::send_update, + make_tl_object( + update->query_id_, td_->user_manager_->get_user_id_object(user_id, "updateNewPreCheckoutQuery"), + update->currency_, update->total_amount_, update->payload_.as_slice().str(), + update->shipping_option_id_, get_order_info_object(get_order_info(std::move(update->info_))))); } promise.set_value(Unit()); } @@ -4316,7 +4315,7 @@ void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { - td_->contacts_manager_->on_update_contacts_reset(); + td_->user_manager_->on_update_contacts_reset(); promise.set_value(Unit()); } @@ -4419,7 +4418,7 @@ void UpdatesManager::on_update(tl_object_ptr update, void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { auto dialog_id = DialogId(update->peer_); if (dialog_id.get_type() == DialogType::User) { - td_->contacts_manager_->on_update_user_wallpaper_overridden(dialog_id.get_user_id(), update->wallpaper_overridden_); + td_->user_manager_->on_update_user_wallpaper_overridden(dialog_id.get_user_id(), update->wallpaper_overridden_); } td_->messages_manager_->on_update_dialog_background(dialog_id, std::move(update->wallpaper_)); promise.set_value(Unit()); diff --git a/td/telegram/UserManager.cpp b/td/telegram/UserManager.cpp index 4ba99d229..c0089ec03 100644 --- a/td/telegram/UserManager.cpp +++ b/td/telegram/UserManager.cpp @@ -6,13 +6,7956 @@ // #include "td/telegram/UserManager.h" +#include "td/telegram/AnimationsManager.h" +#include "td/telegram/AuthManager.h" +#include "td/telegram/Birthdate.hpp" +#include "td/telegram/BlockListId.h" +#include "td/telegram/BotMenuButton.h" +#include "td/telegram/BusinessAwayMessage.h" +#include "td/telegram/BusinessGreetingMessage.h" +#include "td/telegram/BusinessInfo.h" +#include "td/telegram/BusinessInfo.hpp" +#include "td/telegram/BusinessIntro.h" +#include "td/telegram/BusinessWorkHours.h" +#include "td/telegram/ChannelType.h" +#include "td/telegram/CommonDialogManager.h" +#include "td/telegram/ConfigManager.h" +#include "td/telegram/ContactsManager.h" +#include "td/telegram/Dependencies.h" +#include "td/telegram/DialogLocation.h" +#include "td/telegram/DialogManager.h" +#include "td/telegram/DialogParticipantManager.h" +#include "td/telegram/Document.h" +#include "td/telegram/DocumentsManager.h" +#include "td/telegram/FileReferenceManager.h" +#include "td/telegram/files/FileManager.h" +#include "td/telegram/files/FileType.h" +#include "td/telegram/FolderId.h" +#include "td/telegram/Global.h" +#include "td/telegram/GroupCallManager.h" +#include "td/telegram/InlineQueriesManager.h" +#include "td/telegram/LinkManager.h" +#include "td/telegram/logevent/LogEvent.h" +#include "td/telegram/logevent/LogEventHelper.h" +#include "td/telegram/MessageId.h" +#include "td/telegram/MessagesManager.h" +#include "td/telegram/MessageTtl.h" +#include "td/telegram/misc.h" +#include "td/telegram/net/NetQuery.h" +#include "td/telegram/NotificationManager.h" +#include "td/telegram/OptionManager.h" +#include "td/telegram/PeerColor.h" +#include "td/telegram/PeopleNearbyManager.h" +#include "td/telegram/Photo.h" +#include "td/telegram/Photo.hpp" +#include "td/telegram/PhotoSize.h" +#include "td/telegram/PremiumGiftOption.hpp" +#include "td/telegram/ReactionListType.h" +#include "td/telegram/ReactionManager.h" +#include "td/telegram/SecretChatLayer.h" +#include "td/telegram/SecretChatsManager.h" +#include "td/telegram/ServerMessageId.h" +#include "td/telegram/StickerPhotoSize.h" +#include "td/telegram/StoryManager.h" +#include "td/telegram/SuggestedAction.h" +#include "td/telegram/Td.h" +#include "td/telegram/TdDb.h" +#include "td/telegram/telegram_api.h" +#include "td/telegram/ThemeManager.h" +#include "td/telegram/UpdatesManager.h" +#include "td/telegram/Version.h" + +#include "td/db/binlog/BinlogEvent.h" +#include "td/db/binlog/BinlogHelper.h" +#include "td/db/SqliteKeyValue.h" +#include "td/db/SqliteKeyValueAsync.h" + +#include "td/utils/algorithm.h" +#include "td/utils/buffer.h" +#include "td/utils/format.h" +#include "td/utils/logging.h" +#include "td/utils/misc.h" +#include "td/utils/Random.h" +#include "td/utils/ScopeGuard.h" +#include "td/utils/Slice.h" +#include "td/utils/SliceBuilder.h" +#include "td/utils/StringBuilder.h" +#include "td/utils/Time.h" +#include "td/utils/tl_helpers.h" +#include "td/utils/utf8.h" + +#include +#include +#include +#include +#include +#include + namespace td { +class GetContactsQuery final : public Td::ResultHandler { + public: + void send(int64 hash) { + send_query(G()->net_query_creator().create(telegram_api::contacts_getContacts(hash))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for GetContactsQuery: " << to_string(ptr); + td_->user_manager_->on_get_contacts(std::move(ptr)); + } + + void on_error(Status status) final { + td_->user_manager_->on_get_contacts_failed(std::move(status)); + } +}; + +class GetContactsBirthdaysQuery final : public Td::ResultHandler { + public: + void send() { + send_query(G()->net_query_creator().create(telegram_api::contacts_getBirthdays())); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for GetContactsBirthdaysQuery: " << to_string(ptr); + td_->user_manager_->on_get_contact_birthdates(std::move(ptr)); + } + + void on_error(Status status) final { + td_->user_manager_->on_get_contact_birthdates(nullptr); + } +}; + +class GetContactsStatusesQuery final : public Td::ResultHandler { + public: + void send() { + send_query(G()->net_query_creator().create(telegram_api::contacts_getStatuses())); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + td_->user_manager_->on_get_contacts_statuses(result_ptr.move_as_ok()); + } + + void on_error(Status status) final { + if (!G()->is_expected_error(status)) { + LOG(ERROR) << "Receive error for GetContactsStatusesQuery: " << status; + } + } +}; + +class AddContactQuery final : public Td::ResultHandler { + Promise promise_; + UserId user_id_; + + public: + explicit AddContactQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(UserId user_id, telegram_api::object_ptr &&input_user, const Contact &contact, + bool share_phone_number) { + user_id_ = user_id; + int32 flags = 0; + if (share_phone_number) { + flags |= telegram_api::contacts_addContact::ADD_PHONE_PRIVACY_EXCEPTION_MASK; + } + send_query(G()->net_query_creator().create( + telegram_api::contacts_addContact(flags, false /*ignored*/, std::move(input_user), contact.get_first_name(), + contact.get_last_name(), contact.get_phone_number()), + {{DialogId(user_id)}})); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for AddContactQuery: " << to_string(ptr); + td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + td_->user_manager_->reload_contacts(true); + td_->messages_manager_->reget_dialog_action_bar(DialogId(user_id_), "AddContactQuery"); + } +}; + +class EditCloseFriendsQuery final : public Td::ResultHandler { + Promise promise_; + vector user_ids_; + + public: + explicit EditCloseFriendsQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(vector user_ids) { + user_ids_ = std::move(user_ids); + send_query(G()->net_query_creator().create( + telegram_api::contacts_editCloseFriends(UserId::get_input_user_ids(user_ids_)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + td_->user_manager_->on_set_close_friends(user_ids_, std::move(promise_)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class ResolvePhoneQuery final : public Td::ResultHandler { + Promise promise_; + string phone_number_; + + public: + explicit ResolvePhoneQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(const string &phone_number) { + phone_number_ = phone_number; + send_query(G()->net_query_creator().create(telegram_api::contacts_resolvePhone(phone_number))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(DEBUG) << "Receive result for ResolvePhoneQuery: " << to_string(ptr); + td_->user_manager_->on_get_users(std::move(ptr->users_), "ResolvePhoneQuery"); + // on_get_chats(std::move(ptr->chats_), "ResolvePhoneQuery"); + + DialogId dialog_id(ptr->peer_); + if (dialog_id.get_type() != DialogType::User) { + LOG(ERROR) << "Receive " << dialog_id << " by " << phone_number_; + return on_error(Status::Error(500, "Receive invalid response")); + } + + td_->user_manager_->on_resolved_phone_number(phone_number_, dialog_id.get_user_id()); + + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + if (status.message() == Slice("PHONE_NOT_OCCUPIED")) { + td_->user_manager_->on_resolved_phone_number(phone_number_, UserId()); + return promise_.set_value(Unit()); + } + promise_.set_error(std::move(status)); + } +}; + +class AcceptContactQuery final : public Td::ResultHandler { + Promise promise_; + UserId user_id_; + + public: + explicit AcceptContactQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(UserId user_id, telegram_api::object_ptr &&input_user) { + user_id_ = user_id; + send_query(G()->net_query_creator().create(telegram_api::contacts_acceptContact(std::move(input_user)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for AcceptContactQuery: " << to_string(ptr); + td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + td_->user_manager_->reload_contacts(true); + td_->messages_manager_->reget_dialog_action_bar(DialogId(user_id_), "AcceptContactQuery"); + } +}; + +class ImportContactsQuery final : public Td::ResultHandler { + int64 random_id_ = 0; + size_t sent_size_ = 0; + + public: + void send(vector> &&input_phone_contacts, int64 random_id) { + random_id_ = random_id; + sent_size_ = input_phone_contacts.size(); + send_query(G()->net_query_creator().create(telegram_api::contacts_importContacts(std::move(input_phone_contacts)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for ImportContactsQuery: " << to_string(ptr); + if (sent_size_ == ptr->retry_contacts_.size()) { + return on_error(Status::Error(429, "Too Many Requests: retry after 3600")); + } + td_->user_manager_->on_imported_contacts(random_id_, std::move(ptr)); + } + + void on_error(Status status) final { + td_->user_manager_->on_imported_contacts(random_id_, std::move(status)); + } +}; + +class DeleteContactsQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit DeleteContactsQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(vector> &&input_users) { + send_query(G()->net_query_creator().create(telegram_api::contacts_deleteContacts(std::move(input_users)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for DeleteContactsQuery: " << to_string(ptr); + td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + td_->user_manager_->reload_contacts(true); + } +}; + +class DeleteContactsByPhoneNumberQuery final : public Td::ResultHandler { + Promise promise_; + vector user_ids_; + + public: + explicit DeleteContactsByPhoneNumberQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(vector &&user_phone_numbers, vector &&user_ids) { + if (user_phone_numbers.empty()) { + return promise_.set_value(Unit()); + } + user_ids_ = std::move(user_ids); + send_query(G()->net_query_creator().create(telegram_api::contacts_deleteByPhones(std::move(user_phone_numbers)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.ok(); + if (!result) { + return on_error(Status::Error(500, "Some contacts can't be deleted")); + } + + td_->user_manager_->on_deleted_contacts(user_ids_); + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + td_->user_manager_->reload_contacts(true); + } +}; + +class ResetContactsQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit ResetContactsQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send() { + send_query(G()->net_query_creator().create(telegram_api::contacts_resetSaved())); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.ok(); + if (!result) { + LOG(ERROR) << "Failed to delete imported contacts"; + td_->user_manager_->reload_contacts(true); + } else { + td_->user_manager_->on_update_contacts_reset(); + } + + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + td_->user_manager_->reload_contacts(true); + } +}; + +class UploadProfilePhotoQuery final : public Td::ResultHandler { + Promise promise_; + UserId user_id_; + FileId file_id_; + bool is_fallback_; + bool only_suggest_; + + public: + explicit UploadProfilePhotoQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(UserId user_id, FileId file_id, telegram_api::object_ptr &&input_file, + bool is_fallback, bool only_suggest, bool is_animation, double main_frame_timestamp) { + CHECK(input_file != nullptr); + CHECK(file_id.is_valid()); + + user_id_ = user_id; + file_id_ = file_id; + is_fallback_ = is_fallback; + only_suggest_ = only_suggest; + + static_assert(static_cast(telegram_api::photos_uploadProfilePhoto::VIDEO_MASK) == + static_cast(telegram_api::photos_uploadContactProfilePhoto::VIDEO_MASK), + ""); + static_assert(static_cast(telegram_api::photos_uploadProfilePhoto::VIDEO_START_TS_MASK) == + static_cast(telegram_api::photos_uploadContactProfilePhoto::VIDEO_START_TS_MASK), + ""); + static_assert(static_cast(telegram_api::photos_uploadProfilePhoto::FILE_MASK) == + static_cast(telegram_api::photos_uploadContactProfilePhoto::FILE_MASK), + ""); + + int32 flags = 0; + telegram_api::object_ptr photo_input_file; + telegram_api::object_ptr video_input_file; + if (is_animation) { + flags |= telegram_api::photos_uploadProfilePhoto::VIDEO_MASK; + video_input_file = std::move(input_file); + + if (main_frame_timestamp != 0.0) { + flags |= telegram_api::photos_uploadProfilePhoto::VIDEO_START_TS_MASK; + } + } else { + flags |= telegram_api::photos_uploadProfilePhoto::FILE_MASK; + photo_input_file = std::move(input_file); + } + if (td_->user_manager_->is_user_bot(user_id)) { + auto r_input_user = td_->user_manager_->get_input_user(user_id); + if (r_input_user.is_error()) { + return on_error(r_input_user.move_as_error()); + } + flags |= telegram_api::photos_uploadProfilePhoto::BOT_MASK; + send_query(G()->net_query_creator().create( + telegram_api::photos_uploadProfilePhoto(flags, false /*ignored*/, r_input_user.move_as_ok(), + std::move(photo_input_file), std::move(video_input_file), + main_frame_timestamp, nullptr), + {{user_id}})); + } else if (user_id == td_->user_manager_->get_my_id()) { + if (is_fallback) { + flags |= telegram_api::photos_uploadProfilePhoto::FALLBACK_MASK; + } + send_query(G()->net_query_creator().create( + telegram_api::photos_uploadProfilePhoto(flags, false /*ignored*/, nullptr, std::move(photo_input_file), + std::move(video_input_file), main_frame_timestamp, nullptr), + {{"me"}})); + } else { + if (only_suggest) { + flags |= telegram_api::photos_uploadContactProfilePhoto::SUGGEST_MASK; + } else { + flags |= telegram_api::photos_uploadContactProfilePhoto::SAVE_MASK; + } + auto r_input_user = td_->user_manager_->get_input_user(user_id); + if (r_input_user.is_error()) { + return on_error(r_input_user.move_as_error()); + } + send_query(G()->net_query_creator().create( + telegram_api::photos_uploadContactProfilePhoto(flags, false /*ignored*/, false /*ignored*/, + r_input_user.move_as_ok(), std::move(photo_input_file), + std::move(video_input_file), main_frame_timestamp, nullptr), + {{user_id}})); + } + } + + void send(UserId user_id, unique_ptr sticker_photo_size, bool is_fallback, bool only_suggest) { + CHECK(sticker_photo_size != nullptr); + user_id_ = user_id; + file_id_ = FileId(); + is_fallback_ = is_fallback; + only_suggest_ = only_suggest; + + if (td_->user_manager_->is_user_bot(user_id)) { + auto r_input_user = td_->user_manager_->get_input_user(user_id); + if (r_input_user.is_error()) { + return on_error(r_input_user.move_as_error()); + } + int32 flags = telegram_api::photos_uploadProfilePhoto::VIDEO_EMOJI_MARKUP_MASK; + flags |= telegram_api::photos_uploadProfilePhoto::BOT_MASK; + send_query(G()->net_query_creator().create( + telegram_api::photos_uploadProfilePhoto(flags, false /*ignored*/, r_input_user.move_as_ok(), nullptr, nullptr, + 0.0, sticker_photo_size->get_input_video_size_object(td_)), + {{user_id}})); + } else if (user_id == td_->user_manager_->get_my_id()) { + int32 flags = telegram_api::photos_uploadProfilePhoto::VIDEO_EMOJI_MARKUP_MASK; + if (is_fallback) { + flags |= telegram_api::photos_uploadProfilePhoto::FALLBACK_MASK; + } + send_query(G()->net_query_creator().create( + telegram_api::photos_uploadProfilePhoto(flags, false /*ignored*/, nullptr, nullptr, nullptr, 0.0, + sticker_photo_size->get_input_video_size_object(td_)), + {{"me"}})); + } else { + int32 flags = telegram_api::photos_uploadContactProfilePhoto::VIDEO_EMOJI_MARKUP_MASK; + if (only_suggest) { + flags |= telegram_api::photos_uploadContactProfilePhoto::SUGGEST_MASK; + } else { + flags |= telegram_api::photos_uploadContactProfilePhoto::SAVE_MASK; + } + auto r_input_user = td_->user_manager_->get_input_user(user_id); + if (r_input_user.is_error()) { + return on_error(r_input_user.move_as_error()); + } + send_query(G()->net_query_creator().create( + telegram_api::photos_uploadContactProfilePhoto(flags, false /*ignored*/, false /*ignored*/, + r_input_user.move_as_ok(), nullptr, nullptr, 0.0, + sticker_photo_size->get_input_video_size_object(td_)), + {{user_id}})); + } + } + + void on_result(BufferSlice packet) final { + static_assert(std::is_same::value, + ""); + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + if (!only_suggest_) { + td_->user_manager_->on_set_profile_photo(user_id_, result_ptr.move_as_ok(), is_fallback_, 0, std::move(promise_)); + } else { + promise_.set_value(Unit()); + } + + if (file_id_.is_valid()) { + td_->file_manager_->delete_partial_remote_location(file_id_); + } + } + + void on_error(Status status) final { + if (file_id_.is_valid()) { + td_->file_manager_->delete_partial_remote_location(file_id_); + } + promise_.set_error(std::move(status)); + } +}; + +class UpdateProfilePhotoQuery final : public Td::ResultHandler { + Promise promise_; + UserId user_id_; + FileId file_id_; + int64 old_photo_id_; + bool is_fallback_; + string file_reference_; + + public: + explicit UpdateProfilePhotoQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(UserId user_id, FileId file_id, int64 old_photo_id, bool is_fallback, + telegram_api::object_ptr &&input_photo) { + CHECK(input_photo != nullptr); + user_id_ = user_id; + file_id_ = file_id; + old_photo_id_ = old_photo_id; + is_fallback_ = is_fallback; + file_reference_ = FileManager::extract_file_reference(input_photo); + int32 flags = 0; + if (is_fallback) { + flags |= telegram_api::photos_updateProfilePhoto::FALLBACK_MASK; + } + if (td_->user_manager_->is_user_bot(user_id)) { + auto r_input_user = td_->user_manager_->get_input_user(user_id); + if (r_input_user.is_error()) { + return on_error(r_input_user.move_as_error()); + } + flags |= telegram_api::photos_updateProfilePhoto::BOT_MASK; + send_query(G()->net_query_creator().create( + telegram_api::photos_updateProfilePhoto(flags, false /*ignored*/, r_input_user.move_as_ok(), + std::move(input_photo)), + {{user_id}})); + } else { + send_query(G()->net_query_creator().create( + telegram_api::photos_updateProfilePhoto(flags, false /*ignored*/, nullptr, std::move(input_photo)), + {{"me"}})); + } + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + td_->user_manager_->on_set_profile_photo(user_id_, result_ptr.move_as_ok(), is_fallback_, old_photo_id_, + std::move(promise_)); + } + + void on_error(Status status) final { + if (!td_->auth_manager_->is_bot() && FileReferenceManager::is_file_reference_error(status)) { + if (file_id_.is_valid()) { + VLOG(file_references) << "Receive " << status << " for " << file_id_; + td_->file_manager_->delete_file_reference(file_id_, file_reference_); + td_->file_reference_manager_->repair_file_reference( + file_id_, PromiseCreator::lambda([user_id = user_id_, file_id = file_id_, is_fallback = is_fallback_, + old_photo_id = old_photo_id_, + promise = std::move(promise_)](Result result) mutable { + if (result.is_error()) { + return promise.set_error(Status::Error(400, "Can't find the photo")); + } + + send_closure(G()->user_manager(), &UserManager::send_update_profile_photo_query, user_id, file_id, + old_photo_id, is_fallback, std::move(promise)); + })); + return; + } else { + LOG(ERROR) << "Receive file reference error, but file_id = " << file_id_; + } + } + + promise_.set_error(std::move(status)); + } +}; + +class DeleteContactProfilePhotoQuery final : public Td::ResultHandler { + Promise promise_; + UserId user_id_; + + public: + explicit DeleteContactProfilePhotoQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(UserId user_id, telegram_api::object_ptr &&input_user) { + CHECK(input_user != nullptr); + user_id_ = user_id; + + int32 flags = 0; + flags |= telegram_api::photos_uploadContactProfilePhoto::SAVE_MASK; + send_query(G()->net_query_creator().create( + telegram_api::photos_uploadContactProfilePhoto(flags, false /*ignored*/, false /*ignored*/, + std::move(input_user), nullptr, nullptr, 0, nullptr), + {{user_id}})); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + ptr->photo_ = nullptr; + td_->user_manager_->on_set_profile_photo(user_id_, std::move(ptr), false, 0, std::move(promise_)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class DeleteProfilePhotoQuery final : public Td::ResultHandler { + Promise promise_; + int64 profile_photo_id_; + + public: + explicit DeleteProfilePhotoQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(int64 profile_photo_id) { + profile_photo_id_ = profile_photo_id; + vector> input_photo_ids; + input_photo_ids.push_back(telegram_api::make_object(profile_photo_id, 0, BufferSlice())); + send_query(G()->net_query_creator().create(telegram_api::photos_deletePhotos(std::move(input_photo_ids)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto result = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for DeleteProfilePhotoQuery: " << format::as_array(result); + if (result.size() != 1u) { + LOG(WARNING) << "Photo can't be deleted"; + return on_error(Status::Error(400, "Photo can't be deleted")); + } + + td_->user_manager_->on_delete_profile_photo(profile_photo_id_, std::move(promise_)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class UpdateColorQuery final : public Td::ResultHandler { + Promise promise_; + bool for_profile_; + AccentColorId accent_color_id_; + CustomEmojiId background_custom_emoji_id_; + + public: + explicit UpdateColorQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(bool for_profile, AccentColorId accent_color_id, CustomEmojiId background_custom_emoji_id) { + for_profile_ = for_profile; + accent_color_id_ = accent_color_id; + background_custom_emoji_id_ = background_custom_emoji_id; + int32 flags = 0; + if (for_profile) { + flags |= telegram_api::account_updateColor::FOR_PROFILE_MASK; + } + if (accent_color_id.is_valid()) { + flags |= telegram_api::account_updateColor::COLOR_MASK; + } + if (background_custom_emoji_id.is_valid()) { + flags |= telegram_api::account_updateColor::BACKGROUND_EMOJI_ID_MASK; + } + send_query(G()->net_query_creator().create( + telegram_api::account_updateColor(flags, false /*ignored*/, accent_color_id.get(), + background_custom_emoji_id.get()), + {{"me"}})); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + LOG(DEBUG) << "Receive result for UpdateColorQuery: " << result_ptr.ok(); + td_->user_manager_->on_update_accent_color_success(for_profile_, accent_color_id_, background_custom_emoji_id_); + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class UpdateProfileQuery final : public Td::ResultHandler { + Promise promise_; + int32 flags_; + string first_name_; + string last_name_; + string about_; + + public: + explicit UpdateProfileQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(int32 flags, const string &first_name, const string &last_name, const string &about) { + flags_ = flags; + first_name_ = first_name; + last_name_ = last_name; + about_ = about; + send_query(G()->net_query_creator().create(telegram_api::account_updateProfile(flags, first_name, last_name, about), + {{"me"}})); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + LOG(DEBUG) << "Receive result for UpdateProfileQuery: " << to_string(result_ptr.ok()); + td_->user_manager_->on_get_user(result_ptr.move_as_ok(), "UpdateProfileQuery"); + td_->user_manager_->on_update_profile_success(flags_, first_name_, last_name_, about_); + + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class UpdateUsernameQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit UpdateUsernameQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(const string &username) { + send_query(G()->net_query_creator().create(telegram_api::account_updateUsername(username), {{"me"}})); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + LOG(DEBUG) << "Receive result for UpdateUsernameQuery: " << to_string(result_ptr.ok()); + td_->user_manager_->on_get_user(result_ptr.move_as_ok(), "UpdateUsernameQuery"); + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + if (status.message() == "USERNAME_NOT_MODIFIED" && !td_->auth_manager_->is_bot()) { + promise_.set_value(Unit()); + return; + } + promise_.set_error(std::move(status)); + } +}; + +class ToggleUsernameQuery final : public Td::ResultHandler { + Promise promise_; + string username_; + bool is_active_; + + public: + explicit ToggleUsernameQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(string &&username, bool is_active) { + username_ = std::move(username); + is_active_ = is_active; + send_query(G()->net_query_creator().create(telegram_api::account_toggleUsername(username_, is_active_), {{"me"}})); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.ok(); + LOG(DEBUG) << "Receive result for ToggleUsernameQuery: " << result; + td_->user_manager_->on_update_username_is_active(td_->user_manager_->get_my_id(), std::move(username_), is_active_, + std::move(promise_)); + } + + void on_error(Status status) final { + if (status.message() == "USERNAME_NOT_MODIFIED") { + td_->user_manager_->on_update_username_is_active(td_->user_manager_->get_my_id(), std::move(username_), + is_active_, std::move(promise_)); + return; + } + promise_.set_error(std::move(status)); + } +}; + +class ReorderUsernamesQuery final : public Td::ResultHandler { + Promise promise_; + vector usernames_; + + public: + explicit ReorderUsernamesQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(vector &&usernames) { + usernames_ = usernames; + send_query(G()->net_query_creator().create(telegram_api::account_reorderUsernames(std::move(usernames)), {{"me"}})); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.ok(); + LOG(DEBUG) << "Receive result for ReorderUsernamesQuery: " << result; + if (!result) { + return on_error(Status::Error(500, "Usernames weren't updated")); + } + + td_->user_manager_->on_update_active_usernames_order(td_->user_manager_->get_my_id(), std::move(usernames_), + std::move(promise_)); + } + + void on_error(Status status) final { + if (status.message() == "USERNAME_NOT_MODIFIED") { + td_->user_manager_->on_update_active_usernames_order(td_->user_manager_->get_my_id(), std::move(usernames_), + std::move(promise_)); + return; + } + promise_.set_error(std::move(status)); + } +}; + +class ToggleBotUsernameQuery final : public Td::ResultHandler { + Promise promise_; + UserId bot_user_id_; + string username_; + bool is_active_; + + public: + explicit ToggleBotUsernameQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(UserId bot_user_id, string &&username, bool is_active) { + bot_user_id_ = bot_user_id; + username_ = std::move(username); + is_active_ = is_active; + auto r_input_user = td_->user_manager_->get_input_user(bot_user_id_); + if (r_input_user.is_error()) { + return on_error(r_input_user.move_as_error()); + } + send_query(G()->net_query_creator().create( + telegram_api::bots_toggleUsername(r_input_user.move_as_ok(), username_, is_active_), {{bot_user_id_}})); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.ok(); + LOG(DEBUG) << "Receive result for ToggleBotUsernameQuery: " << result; + td_->user_manager_->on_update_username_is_active(bot_user_id_, std::move(username_), is_active_, + std::move(promise_)); + } + + void on_error(Status status) final { + if (status.message() == "USERNAME_NOT_MODIFIED") { + td_->user_manager_->on_update_username_is_active(bot_user_id_, std::move(username_), is_active_, + std::move(promise_)); + return; + } + promise_.set_error(std::move(status)); + } +}; + +class ReorderBotUsernamesQuery final : public Td::ResultHandler { + Promise promise_; + UserId bot_user_id_; + vector usernames_; + + public: + explicit ReorderBotUsernamesQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(UserId bot_user_id, vector &&usernames) { + bot_user_id_ = bot_user_id; + usernames_ = usernames; + auto r_input_user = td_->user_manager_->get_input_user(bot_user_id_); + if (r_input_user.is_error()) { + return on_error(r_input_user.move_as_error()); + } + send_query(G()->net_query_creator().create( + telegram_api::bots_reorderUsernames(r_input_user.move_as_ok(), std::move(usernames)), {{bot_user_id_}})); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.ok(); + LOG(DEBUG) << "Receive result for ReorderBotUsernamesQuery: " << result; + if (!result) { + return on_error(Status::Error(500, "Usernames weren't updated")); + } + + td_->user_manager_->on_update_active_usernames_order(bot_user_id_, std::move(usernames_), std::move(promise_)); + } + + void on_error(Status status) final { + if (status.message() == "USERNAME_NOT_MODIFIED") { + td_->user_manager_->on_update_active_usernames_order(bot_user_id_, std::move(usernames_), std::move(promise_)); + return; + } + promise_.set_error(std::move(status)); + } +}; + +class UpdateBirthdayQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit UpdateBirthdayQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(const Birthdate &birthdate) { + int32 flags = 0; + if (!birthdate.is_empty()) { + flags |= telegram_api::account_updateBirthday::BIRTHDAY_MASK; + } + send_query(G()->net_query_creator().create( + telegram_api::account_updateBirthday(flags, birthdate.get_input_birthday()), {{"me"}})); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + LOG(DEBUG) << "Receive result for UpdateBirthdayQuery: " << result_ptr.ok(); + if (result_ptr.ok()) { + promise_.set_value(Unit()); + } else { + promise_.set_error(Status::Error(400, "Failed to change birthdate")); + } + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class UpdatePersonalChannelQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit UpdatePersonalChannelQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(ChannelId channel_id) { + telegram_api::object_ptr input_channel; + if (channel_id == ChannelId()) { + input_channel = telegram_api::make_object(); + } else { + input_channel = td_->contacts_manager_->get_input_channel(channel_id); + CHECK(input_channel != nullptr); + } + send_query(G()->net_query_creator().create(telegram_api::account_updatePersonalChannel(std::move(input_channel)), + {{"me"}})); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + LOG(DEBUG) << "Receive result for UpdatePersonalChannelQuery: " << result_ptr.ok(); + if (result_ptr.ok()) { + promise_.set_value(Unit()); + } else { + promise_.set_error(Status::Error(400, "Failed to change personal chat")); + } + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class UpdateEmojiStatusQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit UpdateEmojiStatusQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(const EmojiStatus &emoji_status) { + send_query(G()->net_query_creator().create( + telegram_api::account_updateEmojiStatus(emoji_status.get_input_emoji_status()), {{"me"}})); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + LOG(DEBUG) << "Receive result for UpdateEmojiStatusQuery: " << result_ptr.ok(); + if (result_ptr.ok()) { + promise_.set_value(Unit()); + } else { + promise_.set_error(Status::Error(400, "Failed to change Premium badge")); + } + } + + void on_error(Status status) final { + get_recent_emoji_statuses(td_, Auto()); + promise_.set_error(std::move(status)); + } +}; + +class GetUsersQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit GetUsersQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(vector> &&input_users) { + send_query(G()->net_query_creator().create(telegram_api::users_getUsers(std::move(input_users)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + td_->user_manager_->on_get_users(result_ptr.move_as_ok(), "GetUsersQuery"); + + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class GetFullUserQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit GetFullUserQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(telegram_api::object_ptr &&input_user) { + send_query(G()->net_query_creator().create(telegram_api::users_getFullUser(std::move(input_user)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(DEBUG) << "Receive result for GetFullUserQuery: " << to_string(ptr); + td_->user_manager_->on_get_users(std::move(ptr->users_), "GetFullUserQuery"); + td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetFullUserQuery"); + td_->user_manager_->on_get_user_full(std::move(ptr->full_user_)); + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class GetUserPhotosQuery final : public Td::ResultHandler { + Promise promise_; + UserId user_id_; + int32 offset_; + int32 limit_; + + public: + explicit GetUserPhotosQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(UserId user_id, telegram_api::object_ptr &&input_user, int32 offset, int32 limit, + int64 photo_id) { + user_id_ = user_id; + offset_ = offset; + limit_ = limit; + send_query(G()->net_query_creator().create( + telegram_api::photos_getUserPhotos(std::move(input_user), offset, photo_id, limit))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + + LOG(INFO) << "Receive result for GetUserPhotosQuery: " << to_string(ptr); + int32 constructor_id = ptr->get_id(); + if (constructor_id == telegram_api::photos_photos::ID) { + auto photos = move_tl_object_as(ptr); + + td_->user_manager_->on_get_users(std::move(photos->users_), "GetUserPhotosQuery"); + auto photos_size = narrow_cast(photos->photos_.size()); + td_->user_manager_->on_get_user_photos(user_id_, offset_, limit_, photos_size, std::move(photos->photos_)); + } else { + CHECK(constructor_id == telegram_api::photos_photosSlice::ID); + auto photos = move_tl_object_as(ptr); + + td_->user_manager_->on_get_users(std::move(photos->users_), "GetUserPhotosQuery slice"); + td_->user_manager_->on_get_user_photos(user_id_, offset_, limit_, photos->count_, std::move(photos->photos_)); + } + + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class GetSupportUserQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit GetSupportUserQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send() { + send_query(G()->net_query_creator().create(telegram_api::help_getSupport())); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for GetSupportUserQuery: " << to_string(ptr); + + auto user_id = UserManager::get_user_id(ptr->user_); + td_->user_manager_->on_get_user(std::move(ptr->user_), "GetSupportUserQuery"); + + promise_.set_value(std::move(user_id)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class GetIsPremiumRequiredToContactQuery final : public Td::ResultHandler { + Promise promise_; + vector user_ids_; + + public: + explicit GetIsPremiumRequiredToContactQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(vector &&user_ids, vector> &&input_users) { + user_ids_ = std::move(user_ids); + send_query( + G()->net_query_creator().create(telegram_api::users_getIsPremiumRequiredToContact(std::move(input_users)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + td_->user_manager_->on_get_is_premium_required_to_contact_users(std::move(user_ids_), result_ptr.move_as_ok(), + std::move(promise_)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +template +void UserManager::User::store(StorerT &storer) const { + using td::store; + bool has_last_name = !last_name.empty(); + bool legacy_has_username = false; + bool has_photo = photo.small_file_id.is_valid(); + bool has_language_code = !language_code.empty(); + bool have_access_hash = access_hash != -1; + bool has_cache_version = cache_version != 0; + bool has_is_contact = true; + bool has_restriction_reasons = !restriction_reasons.empty(); + bool has_emoji_status = !emoji_status.is_empty(); + bool has_usernames = !usernames.is_empty(); + bool has_flags2 = true; + bool has_max_active_story_id = max_active_story_id.is_valid(); + bool has_max_read_story_id = max_read_story_id.is_valid(); + bool has_max_active_story_id_next_reload_time = max_active_story_id_next_reload_time > Time::now(); + bool has_accent_color_id = accent_color_id.is_valid(); + bool has_background_custom_emoji_id = background_custom_emoji_id.is_valid(); + bool has_profile_accent_color_id = profile_accent_color_id.is_valid(); + bool has_profile_background_custom_emoji_id = profile_background_custom_emoji_id.is_valid(); + BEGIN_STORE_FLAGS(); + STORE_FLAG(is_received); + STORE_FLAG(is_verified); + STORE_FLAG(is_deleted); + STORE_FLAG(is_bot); + STORE_FLAG(can_join_groups); + STORE_FLAG(can_read_all_group_messages); + STORE_FLAG(is_inline_bot); + STORE_FLAG(need_location_bot); + STORE_FLAG(has_last_name); + STORE_FLAG(legacy_has_username); + STORE_FLAG(has_photo); + STORE_FLAG(false); // legacy is_restricted + STORE_FLAG(has_language_code); + STORE_FLAG(have_access_hash); + STORE_FLAG(is_support); + STORE_FLAG(is_min_access_hash); + STORE_FLAG(is_scam); + STORE_FLAG(has_cache_version); + STORE_FLAG(has_is_contact); + STORE_FLAG(is_contact); + STORE_FLAG(is_mutual_contact); + STORE_FLAG(has_restriction_reasons); + STORE_FLAG(need_apply_min_photo); + STORE_FLAG(is_fake); + STORE_FLAG(can_be_added_to_attach_menu); + STORE_FLAG(is_premium); + STORE_FLAG(attach_menu_enabled); + STORE_FLAG(has_emoji_status); + STORE_FLAG(has_usernames); + STORE_FLAG(can_be_edited_bot); + END_STORE_FLAGS(); + if (has_flags2) { + BEGIN_STORE_FLAGS(); + STORE_FLAG(is_close_friend); + STORE_FLAG(stories_hidden); + STORE_FLAG(false); + STORE_FLAG(has_max_active_story_id); + STORE_FLAG(has_max_read_story_id); + STORE_FLAG(has_max_active_story_id_next_reload_time); + STORE_FLAG(has_accent_color_id); + STORE_FLAG(has_background_custom_emoji_id); + STORE_FLAG(has_profile_accent_color_id); + STORE_FLAG(has_profile_background_custom_emoji_id); + STORE_FLAG(contact_require_premium); + STORE_FLAG(is_business_bot); + END_STORE_FLAGS(); + } + store(first_name, storer); + if (has_last_name) { + store(last_name, storer); + } + store(phone_number, storer); + if (have_access_hash) { + store(access_hash, storer); + } + if (has_photo) { + store(photo, storer); + } + store(was_online, storer); + if (has_restriction_reasons) { + store(restriction_reasons, storer); + } + if (is_inline_bot) { + store(inline_query_placeholder, storer); + } + if (is_bot) { + store(bot_info_version, storer); + } + if (has_language_code) { + store(language_code, storer); + } + if (has_cache_version) { + store(cache_version, storer); + } + if (has_emoji_status) { + store(emoji_status, storer); + } + if (has_usernames) { + store(usernames, storer); + } + if (has_max_active_story_id) { + store(max_active_story_id, storer); + } + if (has_max_read_story_id) { + store(max_read_story_id, storer); + } + if (has_max_active_story_id_next_reload_time) { + store_time(max_active_story_id_next_reload_time, storer); + } + if (has_accent_color_id) { + store(accent_color_id, storer); + } + if (has_background_custom_emoji_id) { + store(background_custom_emoji_id, storer); + } + if (has_profile_accent_color_id) { + store(profile_accent_color_id, storer); + } + if (has_profile_background_custom_emoji_id) { + store(profile_background_custom_emoji_id, storer); + } +} + +template +void UserManager::User::parse(ParserT &parser) { + using td::parse; + bool has_last_name; + bool legacy_has_username; + bool has_photo; + bool legacy_is_restricted; + bool has_language_code; + bool have_access_hash; + bool has_cache_version; + bool has_is_contact; + bool has_restriction_reasons; + bool has_emoji_status; + bool has_usernames; + bool has_flags2 = parser.version() >= static_cast(Version::AddUserFlags2); + bool legacy_has_stories = false; + bool has_max_active_story_id = false; + bool has_max_read_story_id = false; + bool has_max_active_story_id_next_reload_time = false; + bool has_accent_color_id = false; + bool has_background_custom_emoji_id = false; + bool has_profile_accent_color_id = false; + bool has_profile_background_custom_emoji_id = false; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(is_received); + PARSE_FLAG(is_verified); + PARSE_FLAG(is_deleted); + PARSE_FLAG(is_bot); + PARSE_FLAG(can_join_groups); + PARSE_FLAG(can_read_all_group_messages); + PARSE_FLAG(is_inline_bot); + PARSE_FLAG(need_location_bot); + PARSE_FLAG(has_last_name); + PARSE_FLAG(legacy_has_username); + PARSE_FLAG(has_photo); + PARSE_FLAG(legacy_is_restricted); + PARSE_FLAG(has_language_code); + PARSE_FLAG(have_access_hash); + PARSE_FLAG(is_support); + PARSE_FLAG(is_min_access_hash); + PARSE_FLAG(is_scam); + PARSE_FLAG(has_cache_version); + PARSE_FLAG(has_is_contact); + PARSE_FLAG(is_contact); + PARSE_FLAG(is_mutual_contact); + PARSE_FLAG(has_restriction_reasons); + PARSE_FLAG(need_apply_min_photo); + PARSE_FLAG(is_fake); + PARSE_FLAG(can_be_added_to_attach_menu); + PARSE_FLAG(is_premium); + PARSE_FLAG(attach_menu_enabled); + PARSE_FLAG(has_emoji_status); + PARSE_FLAG(has_usernames); + PARSE_FLAG(can_be_edited_bot); + END_PARSE_FLAGS(); + if (has_flags2) { + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(is_close_friend); + PARSE_FLAG(stories_hidden); + PARSE_FLAG(legacy_has_stories); + PARSE_FLAG(has_max_active_story_id); + PARSE_FLAG(has_max_read_story_id); + PARSE_FLAG(has_max_active_story_id_next_reload_time); + PARSE_FLAG(has_accent_color_id); + PARSE_FLAG(has_background_custom_emoji_id); + PARSE_FLAG(has_profile_accent_color_id); + PARSE_FLAG(has_profile_background_custom_emoji_id); + PARSE_FLAG(contact_require_premium); + PARSE_FLAG(is_business_bot); + END_PARSE_FLAGS(); + } + parse(first_name, parser); + if (has_last_name) { + parse(last_name, parser); + } + if (legacy_has_username) { + CHECK(!has_usernames); + string username; + parse(username, parser); + usernames = Usernames(std::move(username), vector>()); + } + parse(phone_number, parser); + if (parser.version() < static_cast(Version::FixMinUsers)) { + have_access_hash = is_received; + } + if (have_access_hash) { + parse(access_hash, parser); + } else { + is_min_access_hash = true; + } + if (has_photo) { + parse(photo, parser); + } + if (!has_is_contact) { + // enum class LinkState : uint8 { Unknown, None, KnowsPhoneNumber, Contact }; + + uint32 link_state_inbound; + uint32 link_state_outbound; + parse(link_state_inbound, parser); + parse(link_state_outbound, parser); + + is_contact = link_state_outbound == 3; + is_mutual_contact = is_contact && link_state_inbound == 3; + is_close_friend = false; + } + parse(was_online, parser); + if (legacy_is_restricted) { + string restriction_reason; + parse(restriction_reason, parser); + restriction_reasons = get_restriction_reasons(restriction_reason); + } else if (has_restriction_reasons) { + parse(restriction_reasons, parser); + } + if (is_inline_bot) { + parse(inline_query_placeholder, parser); + } + if (is_bot) { + parse(bot_info_version, parser); + } + if (has_language_code) { + parse(language_code, parser); + } + if (has_cache_version) { + parse(cache_version, parser); + } + if (has_emoji_status) { + parse(emoji_status, parser); + } + if (has_usernames) { + CHECK(!legacy_has_username); + parse(usernames, parser); + } + if (has_max_active_story_id) { + parse(max_active_story_id, parser); + } + if (has_max_read_story_id) { + parse(max_read_story_id, parser); + } + if (has_max_active_story_id_next_reload_time) { + parse_time(max_active_story_id_next_reload_time, parser); + } + if (has_accent_color_id) { + parse(accent_color_id, parser); + } + if (has_background_custom_emoji_id) { + parse(background_custom_emoji_id, parser); + } + if (has_profile_accent_color_id) { + parse(profile_accent_color_id, parser); + } + if (has_profile_background_custom_emoji_id) { + parse(profile_background_custom_emoji_id, parser); + } + + if (!check_utf8(first_name)) { + LOG(ERROR) << "Have invalid first name \"" << first_name << '"'; + first_name.clear(); + cache_version = 0; + } + if (!check_utf8(last_name)) { + LOG(ERROR) << "Have invalid last name \"" << last_name << '"'; + last_name.clear(); + cache_version = 0; + } + + clean_phone_number(phone_number); + if (first_name.empty() && last_name.empty()) { + first_name = phone_number; + } + if (!is_contact && is_mutual_contact) { + LOG(ERROR) << "Have invalid flag is_mutual_contact"; + is_mutual_contact = false; + cache_version = 0; + } + if (!is_contact && is_close_friend) { + LOG(ERROR) << "Have invalid flag is_close_friend"; + is_close_friend = false; + cache_version = 0; + } +} + +template +void UserManager::UserFull::store(StorerT &storer) const { + using td::store; + bool has_about = !about.empty(); + bool has_photo = !photo.is_empty(); + bool has_description = !description.empty(); + bool has_commands = !commands.empty(); + bool has_private_forward_name = !private_forward_name.empty(); + bool has_group_administrator_rights = group_administrator_rights != AdministratorRights(); + bool has_broadcast_administrator_rights = broadcast_administrator_rights != AdministratorRights(); + bool has_menu_button = menu_button != nullptr; + bool has_description_photo = !description_photo.is_empty(); + bool has_description_animation = description_animation_file_id.is_valid(); + bool has_premium_gift_options = !premium_gift_options.empty(); + bool has_personal_photo = !personal_photo.is_empty(); + bool has_fallback_photo = !fallback_photo.is_empty(); + bool has_business_info = business_info != nullptr && !business_info->is_empty(); + bool has_birthdate = !birthdate.is_empty(); + bool has_personal_channel_id = personal_channel_id.is_valid(); + BEGIN_STORE_FLAGS(); + STORE_FLAG(has_about); + STORE_FLAG(is_blocked); + STORE_FLAG(can_be_called); + STORE_FLAG(has_private_calls); + STORE_FLAG(can_pin_messages); + STORE_FLAG(need_phone_number_privacy_exception); // 5 + STORE_FLAG(has_photo); + STORE_FLAG(supports_video_calls); + STORE_FLAG(has_description); + STORE_FLAG(has_commands); + STORE_FLAG(has_private_forward_name); // 10 + STORE_FLAG(has_group_administrator_rights); + STORE_FLAG(has_broadcast_administrator_rights); + STORE_FLAG(has_menu_button); + STORE_FLAG(has_description_photo); + STORE_FLAG(has_description_animation); // 15 + STORE_FLAG(has_premium_gift_options); + STORE_FLAG(voice_messages_forbidden); + STORE_FLAG(has_personal_photo); + STORE_FLAG(has_fallback_photo); + STORE_FLAG(has_pinned_stories); // 20 + STORE_FLAG(is_blocked_for_stories); + STORE_FLAG(wallpaper_overridden); + STORE_FLAG(read_dates_private); + STORE_FLAG(contact_require_premium); + STORE_FLAG(has_business_info); // 25 + STORE_FLAG(has_birthdate); + STORE_FLAG(has_personal_channel_id); + END_STORE_FLAGS(); + if (has_about) { + store(about, storer); + } + store(common_chat_count, storer); + store_time(expires_at, storer); + if (has_photo) { + store(photo, storer); + } + if (has_description) { + store(description, storer); + } + if (has_commands) { + store(commands, storer); + } + if (has_private_forward_name) { + store(private_forward_name, storer); + } + if (has_group_administrator_rights) { + store(group_administrator_rights, storer); + } + if (has_broadcast_administrator_rights) { + store(broadcast_administrator_rights, storer); + } + if (has_menu_button) { + store(menu_button, storer); + } + if (has_description_photo) { + store(description_photo, storer); + } + if (has_description_animation) { + storer.context()->td().get_actor_unsafe()->animations_manager_->store_animation(description_animation_file_id, + storer); + } + if (has_premium_gift_options) { + store(premium_gift_options, storer); + } + if (has_personal_photo) { + store(personal_photo, storer); + } + if (has_fallback_photo) { + store(fallback_photo, storer); + } + if (has_business_info) { + store(business_info, storer); + } + if (has_birthdate) { + store(birthdate, storer); + } + if (has_personal_channel_id) { + store(personal_channel_id, storer); + } +} + +template +void UserManager::UserFull::parse(ParserT &parser) { + using td::parse; + bool has_about; + bool has_photo; + bool has_description; + bool has_commands; + bool has_private_forward_name; + bool has_group_administrator_rights; + bool has_broadcast_administrator_rights; + bool has_menu_button; + bool has_description_photo; + bool has_description_animation; + bool has_premium_gift_options; + bool has_personal_photo; + bool has_fallback_photo; + bool has_business_info; + bool has_birthdate; + bool has_personal_channel_id; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(has_about); + PARSE_FLAG(is_blocked); + PARSE_FLAG(can_be_called); + PARSE_FLAG(has_private_calls); + PARSE_FLAG(can_pin_messages); + PARSE_FLAG(need_phone_number_privacy_exception); + PARSE_FLAG(has_photo); + PARSE_FLAG(supports_video_calls); + PARSE_FLAG(has_description); + PARSE_FLAG(has_commands); + PARSE_FLAG(has_private_forward_name); + PARSE_FLAG(has_group_administrator_rights); + PARSE_FLAG(has_broadcast_administrator_rights); + PARSE_FLAG(has_menu_button); + PARSE_FLAG(has_description_photo); + PARSE_FLAG(has_description_animation); + PARSE_FLAG(has_premium_gift_options); + PARSE_FLAG(voice_messages_forbidden); + PARSE_FLAG(has_personal_photo); + PARSE_FLAG(has_fallback_photo); + PARSE_FLAG(has_pinned_stories); + PARSE_FLAG(is_blocked_for_stories); + PARSE_FLAG(wallpaper_overridden); + PARSE_FLAG(read_dates_private); + PARSE_FLAG(contact_require_premium); + PARSE_FLAG(has_business_info); + PARSE_FLAG(has_birthdate); + PARSE_FLAG(has_personal_channel_id); + END_PARSE_FLAGS(); + if (has_about) { + parse(about, parser); + } + parse(common_chat_count, parser); + parse_time(expires_at, parser); + if (has_photo) { + parse(photo, parser); + } + if (has_description) { + parse(description, parser); + } + if (has_commands) { + parse(commands, parser); + } + if (has_private_forward_name) { + parse(private_forward_name, parser); + } + if (has_group_administrator_rights) { + parse(group_administrator_rights, parser); + } + if (has_broadcast_administrator_rights) { + parse(broadcast_administrator_rights, parser); + } + if (has_menu_button) { + parse(menu_button, parser); + } + if (has_description_photo) { + parse(description_photo, parser); + } + if (has_description_animation) { + description_animation_file_id = + parser.context()->td().get_actor_unsafe()->animations_manager_->parse_animation(parser); + } + if (has_premium_gift_options) { + parse(premium_gift_options, parser); + } + if (has_personal_photo) { + parse(personal_photo, parser); + } + if (has_fallback_photo) { + parse(fallback_photo, parser); + } + if (has_business_info) { + parse(business_info, parser); + } + if (has_birthdate) { + parse(birthdate, parser); + } + if (has_personal_channel_id) { + parse(personal_channel_id, parser); + } +} + +template +void UserManager::SecretChat::store(StorerT &storer) const { + using td::store; + bool has_layer = layer > static_cast(SecretChatLayer::Default); + bool has_initial_folder_id = initial_folder_id != FolderId(); + BEGIN_STORE_FLAGS(); + STORE_FLAG(is_outbound); + STORE_FLAG(has_layer); + STORE_FLAG(has_initial_folder_id); + END_STORE_FLAGS(); + + store(access_hash, storer); + store(user_id, storer); + store(state, storer); + store(ttl, storer); + store(date, storer); + store(key_hash, storer); + if (has_layer) { + store(layer, storer); + } + if (has_initial_folder_id) { + store(initial_folder_id, storer); + } +} + +template +void UserManager::SecretChat::parse(ParserT &parser) { + using td::parse; + bool has_layer; + bool has_initial_folder_id; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(is_outbound); + PARSE_FLAG(has_layer); + PARSE_FLAG(has_initial_folder_id); + END_PARSE_FLAGS(); + + if (parser.version() >= static_cast(Version::AddAccessHashToSecretChat)) { + parse(access_hash, parser); + } + parse(user_id, parser); + parse(state, parser); + parse(ttl, parser); + parse(date, parser); + if (parser.version() >= static_cast(Version::AddKeyHashToSecretChat)) { + parse(key_hash, parser); + } + if (has_layer) { + parse(layer, parser); + } else { + layer = static_cast(SecretChatLayer::Default); + } + if (has_initial_folder_id) { + parse(initial_folder_id, parser); + } +} + +class UserManager::UserLogEvent { + public: + UserId user_id; + const User *u_in = nullptr; + unique_ptr u_out; + + UserLogEvent() = default; + + UserLogEvent(UserId user_id, const User *u) : user_id(user_id), u_in(u) { + } + + template + void store(StorerT &storer) const { + td::store(user_id, storer); + td::store(*u_in, storer); + } + + template + void parse(ParserT &parser) { + td::parse(user_id, parser); + td::parse(u_out, parser); + } +}; + +class UserManager::SecretChatLogEvent { + public: + SecretChatId secret_chat_id; + const SecretChat *c_in = nullptr; + unique_ptr c_out; + + SecretChatLogEvent() = default; + + SecretChatLogEvent(SecretChatId secret_chat_id, const SecretChat *c) : secret_chat_id(secret_chat_id), c_in(c) { + } + + template + void store(StorerT &storer) const { + td::store(secret_chat_id, storer); + td::store(*c_in, storer); + } + + template + void parse(ParserT &parser) { + td::parse(secret_chat_id, parser); + td::parse(c_out, parser); + } +}; + +class UserManager::UploadProfilePhotoCallback final : public FileManager::UploadCallback { + public: + void on_upload_ok(FileId file_id, telegram_api::object_ptr input_file) final { + send_closure_later(G()->user_manager(), &UserManager::on_upload_profile_photo, file_id, std::move(input_file)); + } + void on_upload_encrypted_ok(FileId file_id, + telegram_api::object_ptr input_file) final { + UNREACHABLE(); + } + void on_upload_secure_ok(FileId file_id, telegram_api::object_ptr input_file) final { + UNREACHABLE(); + } + void on_upload_error(FileId file_id, Status error) final { + send_closure_later(G()->user_manager(), &UserManager::on_upload_profile_photo_error, file_id, std::move(error)); + } +}; + UserManager::UserManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { + upload_profile_photo_callback_ = std::make_shared(); + + my_id_ = load_my_id(); + + if (G()->use_chat_info_database()) { + auto next_contacts_sync_date_string = G()->td_db()->get_binlog_pmc()->get("next_contacts_sync_date"); + if (!next_contacts_sync_date_string.empty()) { + next_contacts_sync_date_ = min(to_integer(next_contacts_sync_date_string), G()->unix_time() + 100000); + } + + auto saved_contact_count_string = G()->td_db()->get_binlog_pmc()->get("saved_contact_count"); + if (!saved_contact_count_string.empty()) { + saved_contact_count_ = to_integer(saved_contact_count_string); + } + } else if (!td_->auth_manager_->is_bot()) { + G()->td_db()->get_binlog_pmc()->erase("next_contacts_sync_date"); + G()->td_db()->get_binlog_pmc()->erase("saved_contact_count"); + } + if (G()->use_sqlite_pmc()) { + G()->td_db()->get_sqlite_pmc()->erase_by_prefix("us_bot_info", Auto()); + } + + if (!td_->auth_manager_->is_bot()) { + was_online_local_ = to_integer(G()->td_db()->get_binlog_pmc()->get("my_was_online_local")); + was_online_remote_ = to_integer(G()->td_db()->get_binlog_pmc()->get("my_was_online_remote")); + auto unix_time = G()->unix_time(); + if (was_online_local_ >= unix_time && !td_->is_online()) { + was_online_local_ = unix_time - 1; + } + } + + user_online_timeout_.set_callback(on_user_online_timeout_callback); + user_online_timeout_.set_callback_data(static_cast(this)); + + user_emoji_status_timeout_.set_callback(on_user_emoji_status_timeout_callback); + user_emoji_status_timeout_.set_callback_data(static_cast(this)); + + get_user_queries_.set_merge_function([this](vector query_ids, Promise &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + auto input_users = transform(query_ids, [this](int64 query_id) { return get_input_user_force(UserId(query_id)); }); + td_->create_handler(std::move(promise))->send(std::move(input_users)); + }); + get_is_premium_required_to_contact_queries_.set_merge_function( + [this](vector query_ids, Promise &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + auto user_ids = UserId::get_user_ids(query_ids); + auto input_users = transform(user_ids, [this](UserId user_id) { return get_input_user_force(user_id); }); + td_->create_handler(std::move(promise)) + ->send(std::move(user_ids), std::move(input_users)); + }); +} + +UserManager::~UserManager() { + Scheduler::instance()->destroy_on_scheduler(G()->get_gc_scheduler_id(), users_, users_full_, user_photos_, + unknown_users_, pending_user_photos_, user_profile_photo_file_source_ids_, + my_photo_file_id_, user_full_file_source_ids_, secret_chats_, + unknown_secret_chats_, secret_chats_with_user_); + Scheduler::instance()->destroy_on_scheduler(G()->get_gc_scheduler_id(), loaded_from_database_users_, + unavailable_user_fulls_, loaded_from_database_secret_chats_, + resolved_phone_numbers_, all_imported_contacts_, restricted_user_ids_); } void UserManager::tear_down() { parent_.reset(); + + LOG(DEBUG) << "Have " << users_.calc_size() << " users and " << secret_chats_.calc_size() << " secret chats to free"; + LOG(DEBUG) << "Have " << users_full_.calc_size() << " full users to free"; +} + +void UserManager::on_user_online_timeout_callback(void *user_manager_ptr, int64 user_id_long) { + if (G()->close_flag()) { + return; + } + + auto user_manager = static_cast(user_manager_ptr); + send_closure_later(user_manager->actor_id(user_manager), &UserManager::on_user_online_timeout, UserId(user_id_long)); +} + +void UserManager::on_user_online_timeout(UserId user_id) { + if (G()->close_flag()) { + return; + } + + auto u = get_user(user_id); + CHECK(u != nullptr); + CHECK(u->is_update_user_sent); + + LOG(INFO) << "Update " << user_id << " online status to offline"; + send_closure(G()->td(), &Td::send_update, + td_api::make_object(user_id.get(), + get_user_status_object(user_id, u, G()->unix_time()))); + + td_->dialog_participant_manager_->update_user_online_member_count(user_id); +} + +void UserManager::on_user_emoji_status_timeout_callback(void *user_manager_ptr, int64 user_id_long) { + if (G()->close_flag()) { + return; + } + + auto user_manager = static_cast(user_manager_ptr); + send_closure_later(user_manager->actor_id(user_manager), &UserManager::on_user_emoji_status_timeout, + UserId(user_id_long)); +} + +void UserManager::on_user_emoji_status_timeout(UserId user_id) { + if (G()->close_flag()) { + return; + } + + auto u = get_user(user_id); + CHECK(u != nullptr); + CHECK(u->is_update_user_sent); + + update_user(u, user_id); +} + +UserId UserManager::get_user_id(const telegram_api::object_ptr &user) { + CHECK(user != nullptr); + switch (user->get_id()) { + case telegram_api::userEmpty::ID: + return UserId(static_cast(user.get())->id_); + case telegram_api::user::ID: + return UserId(static_cast(user.get())->id_); + default: + UNREACHABLE(); + return UserId(); + } +} + +UserId UserManager::load_my_id() { + auto id_string = G()->td_db()->get_binlog_pmc()->get("my_id"); + if (!id_string.empty()) { + UserId my_id(to_integer(id_string)); + if (my_id.is_valid()) { + return my_id; + } + + my_id = UserId(to_integer(Slice(id_string).substr(5))); + if (my_id.is_valid()) { + G()->td_db()->get_binlog_pmc()->set("my_id", to_string(my_id.get())); + return my_id; + } + + LOG(ERROR) << "Wrong my ID = \"" << id_string << "\" stored in database"; + } + return UserId(); +} + +UserId UserManager::get_my_id() const { + LOG_IF(ERROR, !my_id_.is_valid()) << "Wrong or unknown my ID returned"; + return my_id_; +} + +void UserManager::set_my_id(UserId my_id) { + UserId my_old_id = my_id_; + if (my_old_id.is_valid() && my_old_id != my_id) { + LOG(ERROR) << "Already know that me is " << my_old_id << " but received userSelf with " << my_id; + return; + } + if (!my_id.is_valid()) { + LOG(ERROR) << "Receive invalid my ID " << my_id; + return; + } + if (my_old_id != my_id) { + my_id_ = my_id; + G()->td_db()->get_binlog_pmc()->set("my_id", to_string(my_id.get())); + td_->option_manager_->set_option_integer("my_id", my_id_.get()); + if (!td_->auth_manager_->is_bot()) { + G()->td_db()->get_binlog_pmc()->force_sync(Promise(), "set_my_id"); + } + } +} + +UserId UserManager::get_service_notifications_user_id() { + return UserId(static_cast(777000)); +} + +UserId UserManager::add_service_notifications_user() { + auto user_id = get_service_notifications_user_id(); + if (!have_user_force(user_id, "add_service_notifications_user")) { + LOG(FATAL) << "Failed to load service notification user"; + } + return user_id; +} + +UserId UserManager::get_replies_bot_user_id() { + return UserId(static_cast(G()->is_test_dc() ? 708513 : 1271266957)); +} + +UserId UserManager::get_anonymous_bot_user_id() { + return UserId(static_cast(G()->is_test_dc() ? 552888 : 1087968824)); +} + +UserId UserManager::get_channel_bot_user_id() { + return UserId(static_cast(G()->is_test_dc() ? 936174 : 136817688)); +} + +UserId UserManager::get_anti_spam_bot_user_id() { + return UserId(static_cast(G()->is_test_dc() ? 2200583762ll : 5434988373ll)); +} + +UserId UserManager::add_anonymous_bot_user() { + auto user_id = get_anonymous_bot_user_id(); + if (!have_user_force(user_id, "add_anonymous_bot_user")) { + LOG(FATAL) << "Failed to load anonymous bot user"; + } + return user_id; +} + +UserId UserManager::add_channel_bot_user() { + auto user_id = get_channel_bot_user_id(); + if (!have_user_force(user_id, "add_channel_bot_user")) { + LOG(FATAL) << "Failed to load channel bot user"; + } + return user_id; +} + +UserManager::MyOnlineStatusInfo UserManager::get_my_online_status() const { + MyOnlineStatusInfo status_info; + status_info.is_online_local = td_->is_online(); + status_info.is_online_remote = was_online_remote_ > G()->unix_time(); + status_info.was_online_local = was_online_local_; + status_info.was_online_remote = was_online_remote_; + + return status_info; +} + +void UserManager::set_my_online_status(bool is_online, bool send_update, bool is_local) { + if (td_->auth_manager_->is_bot()) { + return; // just in case + } + + auto my_id = get_my_id(); + User *u = get_user_force(my_id, "set_my_online_status"); + if (u != nullptr) { + int32 new_online; + int32 unix_time = G()->unix_time(); + if (is_online) { + new_online = unix_time + 300; + } else { + new_online = unix_time - 1; + } + + auto old_was_online = get_user_was_online(u, my_id, unix_time); + if (is_local) { + LOG(INFO) << "Update my local online from " << my_was_online_local_ << " to " << new_online; + if (!is_online) { + new_online = min(new_online, u->was_online); + } + if (new_online != my_was_online_local_) { + my_was_online_local_ = new_online; + } + } else { + if (my_was_online_local_ != 0 || new_online != u->was_online) { + LOG(INFO) << "Update my online from " << u->was_online << " to " << new_online; + my_was_online_local_ = 0; + u->was_online = new_online; + u->need_save_to_database = true; + } + } + if (old_was_online != get_user_was_online(u, my_id, unix_time)) { + u->is_status_changed = true; + u->is_online_status_changed = true; + } + + if (was_online_local_ != new_online) { + was_online_local_ = new_online; + VLOG(notifications) << "Set was_online_local to " << was_online_local_; + G()->td_db()->get_binlog_pmc()->set("my_was_online_local", to_string(was_online_local_)); + } + + if (send_update) { + update_user(u, my_id); + } + } +} + +void UserManager::on_get_user(telegram_api::object_ptr &&user_ptr, const char *source) { + LOG(DEBUG) << "Receive from " << source << ' ' << to_string(user_ptr); + int32 constructor_id = user_ptr->get_id(); + if (constructor_id == telegram_api::userEmpty::ID) { + auto user = move_tl_object_as(user_ptr); + UserId user_id(user->id_); + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id << " from " << source; + return; + } + LOG(INFO) << "Receive empty " << user_id << " from " << source; + + User *u = get_user_force(user_id, source); + if (u == nullptr && Slice(source) != Slice("GetUsersQuery")) { + // userEmpty should be received only through getUsers for nonexistent users + LOG(ERROR) << "Have no information about " << user_id << ", but received userEmpty from " << source; + } + return; + } + + CHECK(constructor_id == telegram_api::user::ID); + auto user = move_tl_object_as(user_ptr); + UserId user_id(user->id_); + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + int32 flags = user->flags_; + int32 flags2 = user->flags2_; + LOG(INFO) << "Receive " << user_id << " with flags " << flags << ' ' << flags2 << " from " << source; + + // the True fields aren't set for manually created telegram_api::user objects, therefore the flags must be used + bool is_bot = (flags & USER_FLAG_IS_BOT) != 0; + if (flags & USER_FLAG_IS_ME) { + set_my_id(user_id); + if (!is_bot) { + td_->option_manager_->set_option_string("my_phone_number", user->phone_); + } + } + + bool have_access_hash = (flags & USER_FLAG_HAS_ACCESS_HASH) != 0; + bool is_received = (flags & USER_FLAG_IS_INACCESSIBLE) == 0; + bool is_contact = (flags & USER_FLAG_IS_CONTACT) != 0; + + User *u = get_user(user_id); + if (u == nullptr) { + if (!is_received) { + // we must preload received inaccessible users from database in order to not save + // the min-user to the database and to not override access_hash and other data + u = get_user_force(user_id, "on_get_user 2"); + if (u == nullptr) { + LOG(INFO) << "Receive inaccessible " << user_id; + u = add_user(user_id); + } + } else if (is_contact && !are_contacts_loaded_) { + // preload contact users from database to know that is_contact didn't changed + // and the list of contacts doesn't need to be saved to the database + u = get_user_force(user_id, "on_get_user 3"); + if (u == nullptr) { + LOG(INFO) << "Receive contact " << user_id << " for the first time"; + u = add_user(user_id); + } + } else { + u = add_user(user_id); + } + CHECK(u != nullptr); + } + + if (have_access_hash) { // access_hash must be updated before photo + auto access_hash = user->access_hash_; + bool is_min_access_hash = !is_received && !((flags & USER_FLAG_HAS_PHONE_NUMBER) != 0 && user->phone_.empty()); + if (u->access_hash != access_hash && (!is_min_access_hash || u->is_min_access_hash || u->access_hash == -1)) { + LOG(DEBUG) << "Access hash has changed for " << user_id << " from " << u->access_hash << "/" + << u->is_min_access_hash << " to " << access_hash << "/" << is_min_access_hash; + u->access_hash = access_hash; + u->is_min_access_hash = is_min_access_hash; + u->need_save_to_database = true; + } + } + + bool is_verified = (flags & USER_FLAG_IS_VERIFIED) != 0; + bool is_premium = (flags & USER_FLAG_IS_PREMIUM) != 0; + bool is_support = (flags & USER_FLAG_IS_SUPPORT) != 0; + bool is_deleted = (flags & USER_FLAG_IS_DELETED) != 0; + bool can_join_groups = (flags & USER_FLAG_IS_PRIVATE_BOT) == 0; + bool can_read_all_group_messages = (flags & USER_FLAG_IS_BOT_WITH_PRIVACY_DISABLED) != 0; + bool can_be_added_to_attach_menu = (flags & USER_FLAG_IS_ATTACH_MENU_BOT) != 0; + bool attach_menu_enabled = (flags & USER_FLAG_ATTACH_MENU_ENABLED) != 0; + bool is_scam = (flags & USER_FLAG_IS_SCAM) != 0; + bool can_be_edited_bot = (flags2 & USER_FLAG_CAN_BE_EDITED_BOT) != 0; + bool is_inline_bot = (flags & USER_FLAG_IS_INLINE_BOT) != 0; + bool is_business_bot = user->bot_business_; + string inline_query_placeholder = std::move(user->bot_inline_placeholder_); + bool need_location_bot = (flags & USER_FLAG_NEED_LOCATION_BOT) != 0; + bool has_bot_info_version = (flags & USER_FLAG_HAS_BOT_INFO_VERSION) != 0; + bool need_apply_min_photo = (flags & USER_FLAG_NEED_APPLY_MIN_PHOTO) != 0; + bool is_fake = (flags & USER_FLAG_IS_FAKE) != 0; + bool stories_available = user->stories_max_id_ > 0; + bool stories_unavailable = user->stories_unavailable_; + bool stories_hidden = user->stories_hidden_; + bool contact_require_premium = user->contact_require_premium_; + + if (!is_bot && (!can_join_groups || can_read_all_group_messages || can_be_added_to_attach_menu || can_be_edited_bot || + is_inline_bot || is_business_bot)) { + LOG(ERROR) << "Receive not bot " << user_id << " with bot properties from " << source; + can_join_groups = true; + can_read_all_group_messages = false; + can_be_added_to_attach_menu = false; + can_be_edited_bot = false; + is_inline_bot = false; + is_business_bot = false; + } + if (need_location_bot && !is_inline_bot) { + LOG(ERROR) << "Receive not inline bot " << user_id << " which needs user location from " << source; + need_location_bot = false; + } + + if (is_deleted) { + // just in case + is_verified = false; + is_premium = false; + is_support = false; + is_bot = false; + can_join_groups = false; + can_read_all_group_messages = false; + can_be_added_to_attach_menu = false; + can_be_edited_bot = false; + is_inline_bot = false; + is_business_bot = false; + inline_query_placeholder = string(); + need_location_bot = false; + has_bot_info_version = false; + need_apply_min_photo = false; + } + + LOG_IF(ERROR, has_bot_info_version && !is_bot) + << "Receive not bot " << user_id << " which has bot info version from " << source; + + int32 bot_info_version = has_bot_info_version ? user->bot_info_version_ : -1; + if (is_verified != u->is_verified || is_support != u->is_support || is_bot != u->is_bot || + can_join_groups != u->can_join_groups || can_read_all_group_messages != u->can_read_all_group_messages || + is_scam != u->is_scam || is_fake != u->is_fake || is_inline_bot != u->is_inline_bot || + is_business_bot != u->is_business_bot || inline_query_placeholder != u->inline_query_placeholder || + need_location_bot != u->need_location_bot || can_be_added_to_attach_menu != u->can_be_added_to_attach_menu) { + if (is_bot != u->is_bot) { + LOG_IF(ERROR, !is_deleted && !u->is_deleted && u->is_received) + << "User.is_bot has changed for " << user_id << "/" << u->usernames << " from " << source << " from " + << u->is_bot << " to " << is_bot; + u->is_full_info_changed = true; + } + u->is_verified = is_verified; + u->is_support = is_support; + u->is_bot = is_bot; + u->can_join_groups = can_join_groups; + u->can_read_all_group_messages = can_read_all_group_messages; + u->is_scam = is_scam; + u->is_fake = is_fake; + u->is_inline_bot = is_inline_bot; + u->is_business_bot = is_business_bot; + u->inline_query_placeholder = std::move(inline_query_placeholder); + u->need_location_bot = need_location_bot; + u->can_be_added_to_attach_menu = can_be_added_to_attach_menu; + + LOG(DEBUG) << "Info has changed for " << user_id; + u->is_changed = true; + } + if (u->contact_require_premium != contact_require_premium) { + u->contact_require_premium = contact_require_premium; + u->is_changed = true; + user_full_contact_require_premium_.erase(user_id); + } + if (is_received && attach_menu_enabled != u->attach_menu_enabled) { + u->attach_menu_enabled = attach_menu_enabled; + u->is_changed = true; + } + if (is_premium != u->is_premium) { + u->is_premium = is_premium; + u->is_is_premium_changed = true; + u->is_changed = true; + u->is_full_info_changed = true; + } + if (is_received && can_be_edited_bot != u->can_be_edited_bot) { + u->can_be_edited_bot = can_be_edited_bot; + u->is_changed = true; + u->is_full_info_changed = true; + } + + if (u->bot_info_version != bot_info_version) { + u->bot_info_version = bot_info_version; + LOG(DEBUG) << "Bot info version has changed for " << user_id; + u->need_save_to_database = true; + } + if (is_received && u->need_apply_min_photo != need_apply_min_photo) { + LOG(DEBUG) << "Need apply min photo has changed for " << user_id; + u->need_apply_min_photo = need_apply_min_photo; + u->need_save_to_database = true; + } + + if (is_received && !u->is_received) { + u->is_received = true; + + LOG(DEBUG) << "Receive " << user_id; + u->is_changed = true; + } + + if (is_deleted != u->is_deleted) { + u->is_deleted = is_deleted; + + LOG(DEBUG) << "User.is_deleted has changed for " << user_id << " to " << u->is_deleted; + u->is_is_deleted_changed = true; + u->is_changed = true; + } + + bool has_language_code = (flags & USER_FLAG_HAS_LANGUAGE_CODE) != 0; + LOG_IF(ERROR, has_language_code && !td_->auth_manager_->is_bot()) + << "Receive language code for " << user_id << " from " << source; + if (u->language_code != user->lang_code_ && !user->lang_code_.empty()) { + u->language_code = user->lang_code_; + + LOG(DEBUG) << "Language code has changed for " << user_id << " to " << u->language_code; + u->is_changed = true; + } + + bool is_me_regular_user = !td_->auth_manager_->is_bot(); + if (is_received || u->need_apply_min_photo || !u->is_received) { + on_update_user_photo(u, user_id, std::move(user->photo_), source); + } + if (is_me_regular_user) { + if (is_received || !u->is_received) { + on_update_user_phone_number(u, user_id, std::move(user->phone_)); + } + if (is_received || !u->is_received || u->was_online == 0) { + on_update_user_online(u, user_id, std::move(user->status_)); + } + if (is_received) { + auto is_mutual_contact = (flags & USER_FLAG_IS_MUTUAL_CONTACT) != 0; + auto is_close_friend = (flags2 & USER_FLAG_IS_CLOSE_FRIEND) != 0; + on_update_user_is_contact(u, user_id, is_contact, is_mutual_contact, is_close_friend); + } + } + + if (is_received || !u->is_received) { + on_update_user_name(u, user_id, std::move(user->first_name_), std::move(user->last_name_)); + on_update_user_usernames(u, user_id, Usernames{std::move(user->username_), std::move(user->usernames_)}); + } + on_update_user_emoji_status(u, user_id, EmojiStatus(std::move(user->emoji_status_))); + PeerColor peer_color(user->color_); + on_update_user_accent_color_id(u, user_id, peer_color.accent_color_id_); + on_update_user_background_custom_emoji_id(u, user_id, peer_color.background_custom_emoji_id_); + PeerColor profile_peer_color(user->profile_color_); + on_update_user_profile_accent_color_id(u, user_id, profile_peer_color.accent_color_id_); + on_update_user_profile_background_custom_emoji_id(u, user_id, profile_peer_color.background_custom_emoji_id_); + if (is_me_regular_user) { + if (is_received) { + on_update_user_stories_hidden(u, user_id, stories_hidden); + } + if (stories_available || stories_unavailable) { + // update at the end, because it calls need_poll_user_active_stories + on_update_user_story_ids_impl(u, user_id, StoryId(user->stories_max_id_), StoryId()); + } + auto restriction_reasons = get_restriction_reasons(std::move(user->restriction_reason_)); + if (restriction_reasons != u->restriction_reasons) { + u->restriction_reasons = std::move(restriction_reasons); + u->is_changed = true; + } + } + + if (u->cache_version != User::CACHE_VERSION && u->is_received) { + u->cache_version = User::CACHE_VERSION; + u->need_save_to_database = true; + } + u->is_received_from_server = true; + update_user(u, user_id); +} + +void UserManager::on_get_users(vector> &&users, const char *source) { + for (auto &user : users) { + on_get_user(std::move(user), source); + } +} + +void UserManager::on_binlog_user_event(BinlogEvent &&event) { + if (!G()->use_chat_info_database()) { + binlog_erase(G()->td_db()->get_binlog(), event.id_); + return; + } + + UserLogEvent log_event; + if (log_event_parse(log_event, event.get_data()).is_error()) { + LOG(ERROR) << "Failed to load a user from binlog"; + binlog_erase(G()->td_db()->get_binlog(), event.id_); + return; + } + + auto user_id = log_event.user_id; + if (have_min_user(user_id) || !user_id.is_valid()) { + LOG(ERROR) << "Skip adding already added " << user_id; + binlog_erase(G()->td_db()->get_binlog(), event.id_); + return; + } + + LOG(INFO) << "Add " << user_id << " from binlog"; + users_.set(user_id, std::move(log_event.u_out)); + + User *u = get_user(user_id); + CHECK(u != nullptr); + u->log_event_id = event.id_; + + update_user(u, user_id, true, false); +} + +void UserManager::on_binlog_secret_chat_event(BinlogEvent &&event) { + if (!G()->use_chat_info_database()) { + binlog_erase(G()->td_db()->get_binlog(), event.id_); + return; + } + + SecretChatLogEvent log_event; + if (log_event_parse(log_event, event.get_data()).is_error()) { + LOG(ERROR) << "Failed to load a secret chat from binlog"; + binlog_erase(G()->td_db()->get_binlog(), event.id_); + return; + } + + auto secret_chat_id = log_event.secret_chat_id; + if (have_secret_chat(secret_chat_id) || !secret_chat_id.is_valid()) { + LOG(ERROR) << "Skip adding already added " << secret_chat_id; + binlog_erase(G()->td_db()->get_binlog(), event.id_); + return; + } + + LOG(INFO) << "Add " << secret_chat_id << " from binlog"; + secret_chats_.set(secret_chat_id, std::move(log_event.c_out)); + + SecretChat *c = get_secret_chat(secret_chat_id); + CHECK(c != nullptr); + c->log_event_id = event.id_; + + update_secret_chat(c, secret_chat_id, true, false); +} + +void UserManager::on_update_user_name(UserId user_id, string &&first_name, string &&last_name, Usernames &&usernames) { + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + User *u = get_user_force(user_id, "on_update_user_name"); + if (u != nullptr) { + on_update_user_name(u, user_id, std::move(first_name), std::move(last_name)); + on_update_user_usernames(u, user_id, std::move(usernames)); + update_user(u, user_id); + } else { + LOG(INFO) << "Ignore update user name about unknown " << user_id; + } +} + +void UserManager::on_update_user_name(User *u, UserId user_id, string &&first_name, string &&last_name) { + if (first_name.empty() && last_name.empty()) { + first_name = u->phone_number; + } + if (u->first_name != first_name || u->last_name != last_name) { + u->first_name = std::move(first_name); + u->last_name = std::move(last_name); + u->is_name_changed = true; + LOG(DEBUG) << "Name has changed for " << user_id; + u->is_changed = true; + } +} + +void UserManager::on_update_user_usernames(User *u, UserId user_id, Usernames &&usernames) { + if (u->usernames != usernames) { + td_->dialog_manager_->on_dialog_usernames_updated(DialogId(user_id), u->usernames, usernames); + td_->messages_manager_->on_dialog_usernames_updated(DialogId(user_id), u->usernames, usernames); + if (u->can_be_edited_bot && u->usernames.get_editable_username() != usernames.get_editable_username()) { + u->is_full_info_changed = true; + } + u->usernames = std::move(usernames); + u->is_username_changed = true; + LOG(DEBUG) << "Usernames have changed for " << user_id; + u->is_changed = true; + } else if (u->is_bot || !td_->auth_manager_->is_bot()) { + td_->dialog_manager_->on_dialog_usernames_received(DialogId(user_id), usernames, false); + } +} + +void UserManager::on_update_user_phone_number(UserId user_id, string &&phone_number) { + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + User *u = get_user_force(user_id, "on_update_user_phone_number"); + if (u != nullptr) { + on_update_user_phone_number(u, user_id, std::move(phone_number)); + update_user(u, user_id); + } else { + LOG(INFO) << "Ignore update user phone number about unknown " << user_id; + } +} + +void UserManager::on_update_user_phone_number(User *u, UserId user_id, string &&phone_number) { + if (td_->auth_manager_->is_bot()) { + return; + } + + clean_phone_number(phone_number); + if (u->phone_number != phone_number) { + if (!u->phone_number.empty()) { + auto it = resolved_phone_numbers_.find(u->phone_number); + if (it != resolved_phone_numbers_.end() && it->second == user_id) { + resolved_phone_numbers_.erase(it); + } + } + + u->phone_number = std::move(phone_number); + u->is_phone_number_changed = true; + LOG(DEBUG) << "Phone number has changed for " << user_id; + u->is_changed = true; + } +} + +void UserManager::on_update_user_photo(User *u, UserId user_id, + telegram_api::object_ptr &&photo, + const char *source) { + if (td_->auth_manager_->is_bot() && !G()->use_chat_info_database()) { + if (!u->is_photo_inited) { + auto new_photo_id = get_profile_photo_id(photo); + auto &old_photo = pending_user_photos_[user_id]; + if (new_photo_id == get_profile_photo_id(old_photo)) { + return; + } + if (photo != nullptr && photo->get_id() == telegram_api::userProfilePhoto::ID) { + auto *profile_photo = static_cast(photo.get()); + if ((profile_photo->flags_ & telegram_api::userProfilePhoto::STRIPPED_THUMB_MASK) != 0) { + profile_photo->flags_ -= telegram_api::userProfilePhoto::STRIPPED_THUMB_MASK; + profile_photo->stripped_thumb_ = BufferSlice(); + } + } + + old_photo = std::move(photo); + + drop_user_photos(user_id, new_photo_id == 0, "on_update_user_photo"); + auto user_full = get_user_full(user_id); // must not load UserFull + if (user_full != nullptr && new_photo_id != get_user_full_profile_photo_id(user_full)) { + // we didn't sent updateUser yet, so we must not sent updateUserFull with new_photo_id yet + drop_user_full_photos(user_full, user_id, 0, "on_update_user_photo"); + } + return; + } + if (u->is_received) { + auto new_photo_id = get_profile_photo_id(photo); + if (new_photo_id == u->photo.id) { + return; + } + } + } + + do_update_user_photo(u, user_id, std::move(photo), source); +} + +void UserManager::do_update_user_photo(User *u, UserId user_id, + telegram_api::object_ptr &&photo, + const char *source) { + ProfilePhoto new_photo = get_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, std::move(photo)); + if (td_->auth_manager_->is_bot()) { + new_photo.minithumbnail.clear(); + } + do_update_user_photo(u, user_id, std::move(new_photo), true, source); +} + +void UserManager::do_update_user_photo(User *u, UserId user_id, ProfilePhoto &&new_photo, bool invalidate_photo_cache, + const char *source) { + u->is_photo_inited = true; + if (need_update_profile_photo(u->photo, new_photo)) { + LOG_IF(ERROR, u->access_hash == -1 && new_photo.small_file_id.is_valid()) + << "Update profile photo of " << user_id << " without access hash from " << source; + u->photo = new_photo; + u->is_photo_changed = true; + LOG(DEBUG) << "Photo has changed for " << user_id << " to " << u->photo + << ", invalidate_photo_cache = " << invalidate_photo_cache << " from " << source; + u->is_changed = true; + + if (invalidate_photo_cache) { + drop_user_photos(user_id, u->photo.id == 0, source); + } + auto user_full = get_user_full(user_id); // must not load UserFull + if (user_full != nullptr && u->photo.id != get_user_full_profile_photo_id(user_full)) { + // we didn't sent updateUser yet, so we must not sent updateUserFull with u->photo.id yet + drop_user_full_photos(user_full, user_id, 0, "do_update_user_photo"); + } + } else if (need_update_dialog_photo_minithumbnail(u->photo.minithumbnail, new_photo.minithumbnail)) { + LOG(DEBUG) << "Photo minithumbnail has changed for " << user_id << " from " << source; + u->photo.minithumbnail = std::move(new_photo.minithumbnail); + u->is_photo_changed = true; + u->is_changed = true; + } +} + +void UserManager::register_suggested_profile_photo(const Photo &photo) { + auto photo_file_ids = photo_get_file_ids(photo); + if (photo.is_empty() || photo_file_ids.empty()) { + return; + } + auto first_file_id = photo_file_ids[0]; + auto file_type = td_->file_manager_->get_file_view(first_file_id).get_type(); + if (file_type == FileType::ProfilePhoto) { + return; + } + CHECK(file_type == FileType::Photo); + auto photo_id = photo.id.get(); + if (photo_id != 0) { + my_photo_file_id_[photo_id] = first_file_id; + } +} + +void UserManager::register_user_photo(User *u, UserId user_id, const Photo &photo) { + auto photo_file_ids = photo_get_file_ids(photo); + if (photo.is_empty() || photo_file_ids.empty()) { + return; + } + auto first_file_id = photo_file_ids[0]; + auto file_type = td_->file_manager_->get_file_view(first_file_id).get_type(); + if (file_type == FileType::ProfilePhoto) { + return; + } + CHECK(file_type == FileType::Photo); + CHECK(u != nullptr); + auto photo_id = photo.id.get(); + if (photo_id != 0 && u->photo_ids.emplace(photo_id).second) { + VLOG(file_references) << "Register photo " << photo_id << " of " << user_id; + if (user_id == get_my_id()) { + my_photo_file_id_[photo_id] = first_file_id; + } + auto file_source_id = user_profile_photo_file_source_ids_.get(std::make_pair(user_id, photo_id)); + if (file_source_id.is_valid()) { + VLOG(file_references) << "Move " << file_source_id << " inside of " << user_id; + user_profile_photo_file_source_ids_.erase(std::make_pair(user_id, photo_id)); + } else { + VLOG(file_references) << "Need to create new file source for photo " << photo_id << " of " << user_id; + file_source_id = td_->file_reference_manager_->create_user_photo_file_source(user_id, photo_id); + } + for (auto &file_id : photo_file_ids) { + td_->file_manager_->add_file_source(file_id, file_source_id); + } + } +} + +void UserManager::on_update_user_accent_color_id(User *u, UserId user_id, AccentColorId accent_color_id) { + if (accent_color_id == AccentColorId(user_id) || !accent_color_id.is_valid()) { + accent_color_id = AccentColorId(); + } + if (u->accent_color_id != accent_color_id) { + u->accent_color_id = accent_color_id; + u->is_accent_color_changed = true; + u->is_changed = true; + } +} + +void UserManager::on_update_user_background_custom_emoji_id(User *u, UserId user_id, + CustomEmojiId background_custom_emoji_id) { + if (u->background_custom_emoji_id != background_custom_emoji_id) { + u->background_custom_emoji_id = background_custom_emoji_id; + u->is_accent_color_changed = true; + u->is_changed = true; + } +} + +void UserManager::on_update_user_profile_accent_color_id(User *u, UserId user_id, AccentColorId accent_color_id) { + if (!accent_color_id.is_valid()) { + accent_color_id = AccentColorId(); + } + if (u->profile_accent_color_id != accent_color_id) { + u->profile_accent_color_id = accent_color_id; + u->is_accent_color_changed = true; + u->is_changed = true; + } +} + +void UserManager::on_update_user_profile_background_custom_emoji_id(User *u, UserId user_id, + CustomEmojiId background_custom_emoji_id) { + if (u->profile_background_custom_emoji_id != background_custom_emoji_id) { + u->profile_background_custom_emoji_id = background_custom_emoji_id; + u->is_accent_color_changed = true; + u->is_changed = true; + } +} + +void UserManager::on_update_user_emoji_status(UserId user_id, + telegram_api::object_ptr &&emoji_status) { + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + User *u = get_user_force(user_id, "on_update_user_emoji_status"); + if (u != nullptr) { + on_update_user_emoji_status(u, user_id, EmojiStatus(std::move(emoji_status))); + update_user(u, user_id); + } else { + LOG(INFO) << "Ignore update user emoji status about unknown " << user_id; + } +} + +void UserManager::on_update_user_emoji_status(User *u, UserId user_id, EmojiStatus emoji_status) { + if (u->emoji_status != emoji_status) { + LOG(DEBUG) << "Change emoji status of " << user_id << " from " << u->emoji_status << " to " << emoji_status; + u->emoji_status = std::move(emoji_status); + u->is_emoji_status_changed = true; + // effective emoji status might not be changed; checked in update_user + // u->is_changed = true; + } +} + +void UserManager::on_update_user_story_ids(UserId user_id, StoryId max_active_story_id, StoryId max_read_story_id) { + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + User *u = get_user_force(user_id, "on_update_user_story_ids"); + if (u != nullptr) { + on_update_user_story_ids_impl(u, user_id, max_active_story_id, max_read_story_id); + update_user(u, user_id); + } else { + LOG(INFO) << "Ignore update user story identifiers about unknown " << user_id; + } +} + +void UserManager::on_update_user_story_ids_impl(User *u, UserId user_id, StoryId max_active_story_id, + StoryId max_read_story_id) { + if (td_->auth_manager_->is_bot()) { + return; + } + if (max_active_story_id != StoryId() && !max_active_story_id.is_server()) { + LOG(ERROR) << "Receive max active " << max_active_story_id << " for " << user_id; + return; + } + if (max_read_story_id != StoryId() && !max_read_story_id.is_server()) { + LOG(ERROR) << "Receive max read " << max_read_story_id << " for " << user_id; + return; + } + + auto has_unread_stories = get_user_has_unread_stories(u); + if (u->max_active_story_id != max_active_story_id) { + LOG(DEBUG) << "Change last active story of " << user_id << " from " << u->max_active_story_id << " to " + << max_active_story_id; + u->max_active_story_id = max_active_story_id; + u->need_save_to_database = true; + } + if (need_poll_user_active_stories(u, user_id)) { + auto max_active_story_id_next_reload_time = Time::now() + MAX_ACTIVE_STORY_ID_RELOAD_TIME; + if (max_active_story_id_next_reload_time > + u->max_active_story_id_next_reload_time + MAX_ACTIVE_STORY_ID_RELOAD_TIME / 5) { + LOG(DEBUG) << "Change max_active_story_id_next_reload_time of " << user_id; + u->max_active_story_id_next_reload_time = max_active_story_id_next_reload_time; + u->need_save_to_database = true; + } + } + if (!max_active_story_id.is_valid()) { + CHECK(max_read_story_id == StoryId()); + if (u->max_read_story_id != StoryId()) { + LOG(DEBUG) << "Drop last read " << u->max_read_story_id << " of " << user_id; + u->max_read_story_id = StoryId(); + u->need_save_to_database = true; + } + } else if (max_read_story_id.get() > u->max_read_story_id.get()) { + LOG(DEBUG) << "Change last read story of " << user_id << " from " << u->max_read_story_id << " to " + << max_read_story_id; + u->max_read_story_id = max_read_story_id; + u->need_save_to_database = true; + } + if (has_unread_stories != get_user_has_unread_stories(u)) { + LOG(DEBUG) << "Change has_unread_stories of " << user_id << " to " << !has_unread_stories; + u->is_changed = true; + } +} + +void UserManager::on_update_user_max_read_story_id(UserId user_id, StoryId max_read_story_id) { + CHECK(user_id.is_valid()); + + User *u = get_user(user_id); + if (u != nullptr) { + on_update_user_max_read_story_id(u, user_id, max_read_story_id); + update_user(u, user_id); + } +} + +void UserManager::on_update_user_max_read_story_id(User *u, UserId user_id, StoryId max_read_story_id) { + if (td_->auth_manager_->is_bot() || !u->is_received) { + return; + } + + auto has_unread_stories = get_user_has_unread_stories(u); + if (max_read_story_id.get() > u->max_read_story_id.get()) { + LOG(DEBUG) << "Change last read story of " << user_id << " from " << u->max_read_story_id << " to " + << max_read_story_id; + u->max_read_story_id = max_read_story_id; + u->need_save_to_database = true; + } + if (has_unread_stories != get_user_has_unread_stories(u)) { + LOG(DEBUG) << "Change has_unread_stories of " << user_id << " to " << !has_unread_stories; + u->is_changed = true; + } +} + +void UserManager::on_update_user_stories_hidden(UserId user_id, bool stories_hidden) { + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + User *u = get_user_force(user_id, "on_update_user_stories_hidden"); + if (u != nullptr) { + on_update_user_stories_hidden(u, user_id, stories_hidden); + update_user(u, user_id); + } else { + LOG(INFO) << "Ignore update user stories are archived about unknown " << user_id; + } +} + +void UserManager::on_update_user_stories_hidden(User *u, UserId user_id, bool stories_hidden) { + if (td_->auth_manager_->is_bot()) { + return; + } + + if (u->stories_hidden != stories_hidden) { + LOG(DEBUG) << "Change stories are archived of " << user_id << " to " << stories_hidden; + u->stories_hidden = stories_hidden; + u->is_stories_hidden_changed = true; + u->need_save_to_database = true; + } +} + +void UserManager::on_update_user_is_contact(User *u, UserId user_id, bool is_contact, bool is_mutual_contact, + bool is_close_friend) { + if (td_->auth_manager_->is_bot()) { + return; + } + + UserId my_id = get_my_id(); + if (user_id == my_id) { + is_mutual_contact = is_contact; + is_close_friend = false; + } + if (!is_contact && (is_mutual_contact || is_close_friend)) { + LOG(ERROR) << "Receive is_mutual_contact = " << is_mutual_contact << ", and is_close_friend = " << is_close_friend + << " for non-contact " << user_id; + is_mutual_contact = false; + is_close_friend = false; + } + + if (u->is_contact != is_contact || u->is_mutual_contact != is_mutual_contact || + u->is_close_friend != is_close_friend) { + LOG(DEBUG) << "Update " << user_id << " is_contact from (" << u->is_contact << ", " << u->is_mutual_contact << ", " + << u->is_close_friend << ") to (" << is_contact << ", " << is_mutual_contact << ", " << is_close_friend + << ")"; + if (u->is_contact != is_contact) { + u->is_contact = is_contact; + u->is_is_contact_changed = true; + + reload_contact_birthdates(true); + } + if (u->is_mutual_contact != is_mutual_contact) { + u->is_mutual_contact = is_mutual_contact; + u->is_is_mutual_contact_changed = true; + } + u->is_close_friend = is_close_friend; + u->is_changed = true; + } +} + +void UserManager::on_update_user_online(UserId user_id, telegram_api::object_ptr &&status) { + if (td_->auth_manager_->is_bot()) { + return; + } + + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + User *u = get_user_force(user_id, "on_update_user_online"); + if (u != nullptr) { + if (u->is_bot) { + LOG(ERROR) << "Receive updateUserStatus about bot " << user_id; + return; + } + on_update_user_online(u, user_id, std::move(status)); + update_user(u, user_id); + + if (user_id == get_my_id() && + was_online_remote_ != u->was_online) { // only update was_online_remote_ from updateUserStatus + was_online_remote_ = u->was_online; + VLOG(notifications) << "Set was_online_remote to " << was_online_remote_; + G()->td_db()->get_binlog_pmc()->set("my_was_online_remote", to_string(was_online_remote_)); + } + } else { + LOG(INFO) << "Ignore update user online about unknown " << user_id; + } +} + +void UserManager::on_update_user_online(User *u, UserId user_id, + telegram_api::object_ptr &&status) { + if (td_->auth_manager_->is_bot()) { + return; + } + + int32 id = status == nullptr ? telegram_api::userStatusEmpty::ID : status->get_id(); + int32 new_online; + bool is_offline = false; + if (id == telegram_api::userStatusOnline::ID) { + int32 now = G()->unix_time(); + + auto st = move_tl_object_as(status); + new_online = st->expires_; + LOG_IF(ERROR, new_online < now - 86400) + << "Receive userStatusOnline expired more than one day in past " << new_online; + } else if (id == telegram_api::userStatusOffline::ID) { + int32 now = G()->unix_time(); + + auto st = move_tl_object_as(status); + new_online = st->was_online_; + if (new_online >= now) { + LOG_IF(ERROR, new_online > now + 10) + << "Receive userStatusOffline but was online points to future time " << new_online << ", now is " << now; + new_online = now - 1; + } + is_offline = true; + } else if (id == telegram_api::userStatusRecently::ID) { + auto st = telegram_api::move_object_as(status); + new_online = st->by_me_ ? -4 : -1; + } else if (id == telegram_api::userStatusLastWeek::ID) { + auto st = telegram_api::move_object_as(status); + new_online = st->by_me_ ? -5 : -2; + } else if (id == telegram_api::userStatusLastMonth::ID) { + auto st = telegram_api::move_object_as(status); + new_online = st->by_me_ ? -6 : -3; + } else { + CHECK(id == telegram_api::userStatusEmpty::ID); + new_online = 0; + } + + if (new_online != u->was_online && !(new_online < 0 && user_id == get_my_id())) { + LOG(DEBUG) << "Update " << user_id << " online from " << u->was_online << " to " << new_online; + auto unix_time = G()->unix_time(); + bool old_is_online = u->was_online > unix_time; + bool new_is_online = new_online > unix_time; + u->was_online = new_online; + u->is_status_changed = true; + if (u->was_online > 0) { + u->local_was_online = 0; + } + + if (user_id == get_my_id()) { + if (my_was_online_local_ != 0 || old_is_online != new_is_online) { + my_was_online_local_ = 0; + u->is_online_status_changed = true; + } + if (is_offline) { + td_->on_online_updated(false, false); + } + } else if (old_is_online != new_is_online) { + u->is_online_status_changed = true; + } + } +} + +void UserManager::on_update_user_local_was_online(UserId user_id, int32 local_was_online) { + CHECK(user_id.is_valid()); + if (td_->auth_manager_->is_bot()) { + return; + } + + User *u = get_user_force(user_id, "on_update_user_local_was_online"); + if (u == nullptr) { + return; + } + + on_update_user_local_was_online(u, user_id, local_was_online); + update_user(u, user_id); +} + +void UserManager::on_update_user_local_was_online(User *u, UserId user_id, int32 local_was_online) { + CHECK(u != nullptr); + if (u->is_deleted || u->is_bot || u->is_support || user_id == get_my_id()) { + return; + } + int32 unix_time = G()->unix_time(); + if (u->was_online > unix_time) { + // if user is currently online, ignore local online + return; + } + + // bring users online for 30 seconds + local_was_online += 30; + if (local_was_online < unix_time + 2 || local_was_online <= u->local_was_online || + local_was_online <= u->was_online) { + return; + } + + LOG(DEBUG) << "Update " << user_id << " local online from " << u->local_was_online << " to " << local_was_online; + bool old_is_online = u->local_was_online > unix_time; + u->local_was_online = local_was_online; + u->is_status_changed = true; + + if (!old_is_online) { + u->is_online_status_changed = true; + } +} + +void UserManager::on_update_user_is_blocked(UserId user_id, bool is_blocked, bool is_blocked_for_stories) { + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + UserFull *user_full = get_user_full_force(user_id, "on_update_user_is_blocked"); + if (user_full == nullptr) { + return; + } + on_update_user_full_is_blocked(user_full, user_id, is_blocked, is_blocked_for_stories); + update_user_full(user_full, user_id, "on_update_user_is_blocked"); +} + +void UserManager::on_update_user_full_is_blocked(UserFull *user_full, UserId user_id, bool is_blocked, + bool is_blocked_for_stories) { + CHECK(user_full != nullptr); + if (user_full->is_blocked != is_blocked || user_full->is_blocked_for_stories != is_blocked_for_stories) { + LOG(INFO) << "Receive update user full is blocked with " << user_id << " and is_blocked = " << is_blocked << '/' + << is_blocked_for_stories; + user_full->is_blocked = is_blocked; + user_full->is_blocked_for_stories = is_blocked_for_stories; + user_full->is_changed = true; + } +} + +void UserManager::on_update_user_has_pinned_stories(UserId user_id, bool has_pinned_stories) { + if (td_->auth_manager_->is_bot()) { + return; + } + + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + UserFull *user_full = get_user_full_force(user_id, "on_update_user_has_pinned_stories"); + if (user_full == nullptr || user_full->has_pinned_stories == has_pinned_stories) { + return; + } + user_full->has_pinned_stories = has_pinned_stories; + user_full->is_changed = true; + update_user_full(user_full, user_id, "on_update_user_has_pinned_stories"); +} + +void UserManager::on_update_user_common_chat_count(UserId user_id, int32 common_chat_count) { + LOG(INFO) << "Receive " << common_chat_count << " common chat count with " << user_id; + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + UserFull *user_full = get_user_full_force(user_id, "on_update_user_common_chat_count"); + if (user_full == nullptr) { + return; + } + on_update_user_full_common_chat_count(user_full, user_id, common_chat_count); + update_user_full(user_full, user_id, "on_update_user_common_chat_count"); +} + +void UserManager::on_update_user_full_common_chat_count(UserFull *user_full, UserId user_id, int32 common_chat_count) { + CHECK(user_full != nullptr); + if (common_chat_count < 0) { + LOG(ERROR) << "Receive " << common_chat_count << " as common group count with " << user_id; + common_chat_count = 0; + } + if (user_full->common_chat_count != common_chat_count) { + user_full->common_chat_count = common_chat_count; + user_full->is_common_chat_count_changed = true; + user_full->is_changed = true; + } +} + +void UserManager::on_update_user_location(UserId user_id, DialogLocation &&location) { + LOG(INFO) << "Receive " << location << " for " << user_id; + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + UserFull *user_full = get_user_full_force(user_id, "on_update_user_location"); + if (user_full == nullptr) { + return; + } + on_update_user_full_location(user_full, user_id, std::move(location)); + update_user_full(user_full, user_id, "on_update_user_location"); +} + +void UserManager::on_update_user_full_location(UserFull *user_full, UserId user_id, DialogLocation &&location) { + CHECK(user_full != nullptr); + if (BusinessInfo::set_location(user_full->business_info, std::move(location))) { + user_full->is_changed = true; + } +} + +void UserManager::on_update_user_work_hours(UserId user_id, BusinessWorkHours &&work_hours) { + LOG(INFO) << "Receive " << work_hours << " for " << user_id; + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + UserFull *user_full = get_user_full_force(user_id, "on_update_user_work_hours"); + if (user_full == nullptr) { + return; + } + on_update_user_full_work_hours(user_full, user_id, std::move(work_hours)); + update_user_full(user_full, user_id, "on_update_user_work_hours"); +} + +void UserManager::on_update_user_full_work_hours(UserFull *user_full, UserId user_id, BusinessWorkHours &&work_hours) { + CHECK(user_full != nullptr); + if (BusinessInfo::set_work_hours(user_full->business_info, std::move(work_hours))) { + user_full->is_changed = true; + } +} + +void UserManager::on_update_user_away_message(UserId user_id, BusinessAwayMessage &&away_message) { + LOG(INFO) << "Receive " << away_message << " for " << user_id; + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + UserFull *user_full = get_user_full_force(user_id, "on_update_user_away_message"); + if (user_full == nullptr) { + return; + } + on_update_user_full_away_message(user_full, user_id, std::move(away_message)); + update_user_full(user_full, user_id, "on_update_user_away_message"); +} + +void UserManager::on_update_user_full_away_message(UserFull *user_full, UserId user_id, + BusinessAwayMessage &&away_message) const { + CHECK(user_full != nullptr); + if (away_message.is_valid() && user_id != get_my_id()) { + LOG(ERROR) << "Receive " << away_message << " for " << user_id; + return; + } + if (BusinessInfo::set_away_message(user_full->business_info, std::move(away_message))) { + user_full->is_changed = true; + } +} + +void UserManager::on_update_user_greeting_message(UserId user_id, BusinessGreetingMessage &&greeting_message) { + LOG(INFO) << "Receive " << greeting_message << " for " << user_id; + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + UserFull *user_full = get_user_full_force(user_id, "on_update_user_greeting_message"); + if (user_full == nullptr) { + return; + } + on_update_user_full_greeting_message(user_full, user_id, std::move(greeting_message)); + update_user_full(user_full, user_id, "on_update_user_greeting_message"); +} + +void UserManager::on_update_user_full_greeting_message(UserFull *user_full, UserId user_id, + BusinessGreetingMessage &&greeting_message) const { + CHECK(user_full != nullptr); + if (greeting_message.is_valid() && user_id != get_my_id()) { + LOG(ERROR) << "Receive " << greeting_message << " for " << user_id; + return; + } + if (BusinessInfo::set_greeting_message(user_full->business_info, std::move(greeting_message))) { + user_full->is_changed = true; + } +} + +void UserManager::on_update_user_intro(UserId user_id, BusinessIntro &&intro) { + LOG(INFO) << "Receive " << intro << " for " << user_id; + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + UserFull *user_full = get_user_full_force(user_id, "on_update_user_intro"); + if (user_full == nullptr) { + return; + } + on_update_user_full_intro(user_full, user_id, std::move(intro)); + update_user_full(user_full, user_id, "on_update_user_intro"); +} + +void UserManager::on_update_user_full_intro(UserFull *user_full, UserId user_id, BusinessIntro &&intro) { + CHECK(user_full != nullptr); + if (BusinessInfo::set_intro(user_full->business_info, std::move(intro))) { + user_full->is_changed = true; + } +} + +void UserManager::on_update_user_commands(UserId user_id, + vector> &&bot_commands) { + UserFull *user_full = get_user_full_force(user_id, "on_update_user_commands"); + if (user_full != nullptr) { + on_update_user_full_commands(user_full, user_id, std::move(bot_commands)); + update_user_full(user_full, user_id, "on_update_user_commands"); + } +} + +void UserManager::on_update_user_full_commands( + UserFull *user_full, UserId user_id, vector> &&bot_commands) { + CHECK(user_full != nullptr); + auto commands = + transform(std::move(bot_commands), [](telegram_api::object_ptr &&bot_command) { + return BotCommand(std::move(bot_command)); + }); + if (user_full->commands != commands) { + user_full->commands = std::move(commands); + user_full->is_changed = true; + } +} + +void UserManager::on_update_user_need_phone_number_privacy_exception(UserId user_id, + bool need_phone_number_privacy_exception) { + LOG(INFO) << "Receive " << need_phone_number_privacy_exception << " need phone number privacy exception with " + << user_id; + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + UserFull *user_full = get_user_full_force(user_id, "on_update_user_need_phone_number_privacy_exception"); + if (user_full == nullptr) { + return; + } + on_update_user_full_need_phone_number_privacy_exception(user_full, user_id, need_phone_number_privacy_exception); + update_user_full(user_full, user_id, "on_update_user_need_phone_number_privacy_exception"); +} + +void UserManager::on_update_user_full_need_phone_number_privacy_exception( + UserFull *user_full, UserId user_id, bool need_phone_number_privacy_exception) const { + CHECK(user_full != nullptr); + if (need_phone_number_privacy_exception) { + const User *u = get_user(user_id); + if (u == nullptr || u->is_contact || user_id == get_my_id()) { + need_phone_number_privacy_exception = false; + } + } + if (user_full->need_phone_number_privacy_exception != need_phone_number_privacy_exception) { + user_full->need_phone_number_privacy_exception = need_phone_number_privacy_exception; + user_full->is_changed = true; + } +} + +void UserManager::on_update_user_wallpaper_overridden(UserId user_id, bool wallpaper_overridden) { + LOG(INFO) << "Receive " << wallpaper_overridden << " set chat background for " << user_id; + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + UserFull *user_full = get_user_full_force(user_id, "on_update_user_wallpaper_overridden"); + if (user_full == nullptr) { + return; + } + on_update_user_full_wallpaper_overridden(user_full, user_id, wallpaper_overridden); + update_user_full(user_full, user_id, "on_update_user_wallpaper_overridden"); +} + +void UserManager::on_update_user_full_wallpaper_overridden(UserFull *user_full, UserId user_id, + bool wallpaper_overridden) const { + CHECK(user_full != nullptr); + if (user_full->wallpaper_overridden != wallpaper_overridden) { + user_full->wallpaper_overridden = wallpaper_overridden; + user_full->is_changed = true; + } +} + +void UserManager::on_update_bot_menu_button(UserId bot_user_id, + telegram_api::object_ptr &&bot_menu_button) { + if (!bot_user_id.is_valid()) { + LOG(ERROR) << "Receive updateBotMenuButton about invalid " << bot_user_id; + return; + } + if (!have_user_force(bot_user_id, "on_update_bot_menu_button") || !is_user_bot(bot_user_id)) { + return; + } + if (td_->auth_manager_->is_bot()) { + return; + } + + auto user_full = get_user_full_force(bot_user_id, "on_update_bot_menu_button"); + if (user_full != nullptr) { + on_update_user_full_menu_button(user_full, bot_user_id, std::move(bot_menu_button)); + update_user_full(user_full, bot_user_id, "on_update_bot_menu_button"); + } +} + +void UserManager::on_update_user_full_menu_button( + UserFull *user_full, UserId user_id, telegram_api::object_ptr &&bot_menu_button) { + CHECK(user_full != nullptr); + auto new_button = get_bot_menu_button(std::move(bot_menu_button)); + bool is_changed; + if (user_full->menu_button == nullptr) { + is_changed = (new_button != nullptr); + } else { + is_changed = (new_button == nullptr || *user_full->menu_button != *new_button); + } + if (is_changed) { + user_full->menu_button = std::move(new_button); + user_full->is_changed = true; + } +} + +void UserManager::on_update_secret_chat(SecretChatId secret_chat_id, int64 access_hash, UserId user_id, + SecretChatState state, bool is_outbound, int32 ttl, int32 date, string key_hash, + int32 layer, FolderId initial_folder_id) { + LOG(INFO) << "Update " << secret_chat_id << " with " << user_id << " and access_hash " << access_hash; + auto *secret_chat = add_secret_chat(secret_chat_id); + if (access_hash != secret_chat->access_hash) { + secret_chat->access_hash = access_hash; + secret_chat->need_save_to_database = true; + } + if (user_id.is_valid() && user_id != secret_chat->user_id) { + if (secret_chat->user_id.is_valid()) { + LOG(ERROR) << "Secret chat user has changed from " << secret_chat->user_id << " to " << user_id; + auto &old_secret_chat_ids = secret_chats_with_user_[secret_chat->user_id]; + td::remove(old_secret_chat_ids, secret_chat_id); + } + secret_chat->user_id = user_id; + secret_chats_with_user_[secret_chat->user_id].push_back(secret_chat_id); + secret_chat->is_changed = true; + } + if (state != SecretChatState::Unknown && state != secret_chat->state) { + secret_chat->state = state; + secret_chat->is_changed = true; + secret_chat->is_state_changed = true; + } + if (is_outbound != secret_chat->is_outbound) { + secret_chat->is_outbound = is_outbound; + secret_chat->is_changed = true; + } + + if (ttl != -1 && ttl != secret_chat->ttl) { + secret_chat->ttl = ttl; + secret_chat->need_save_to_database = true; + secret_chat->is_ttl_changed = true; + } + if (date != 0 && date != secret_chat->date) { + secret_chat->date = date; + secret_chat->need_save_to_database = true; + } + if (!key_hash.empty() && key_hash != secret_chat->key_hash) { + secret_chat->key_hash = std::move(key_hash); + secret_chat->is_changed = true; + } + if (layer != 0 && layer != secret_chat->layer) { + secret_chat->layer = layer; + secret_chat->is_changed = true; + } + if (initial_folder_id != FolderId() && initial_folder_id != secret_chat->initial_folder_id) { + secret_chat->initial_folder_id = initial_folder_id; + secret_chat->is_changed = true; + } + + update_secret_chat(secret_chat, secret_chat_id); +} + +void UserManager::on_update_online_status_privacy() { + td_->create_handler()->send(); +} + +void UserManager::on_update_phone_number_privacy() { + // all UserFull.need_phone_number_privacy_exception can be outdated now, + // so mark all of them as expired + users_full_.foreach([&](const UserId &user_id, unique_ptr &user_full) { user_full->expires_at = 0.0; }); +} + +void UserManager::on_ignored_restriction_reasons_changed() { + restricted_user_ids_.foreach([&](const UserId &user_id) { + send_closure(G()->td(), &Td::send_update, get_update_user_object(user_id, get_user(user_id))); + }); +} + +void UserManager::invalidate_user_full(UserId user_id) { + auto user_full = get_user_full_force(user_id, "invalidate_user_full"); + if (user_full != nullptr) { + td_->dialog_manager_->on_dialog_info_full_invalidated(DialogId(user_id)); + + if (!user_full->is_expired()) { + user_full->expires_at = 0.0; + user_full->need_save_to_database = true; + + update_user_full(user_full, user_id, "invalidate_user_full"); + } + } +} + +bool UserManager::have_user(UserId user_id) const { + auto u = get_user(user_id); + return u != nullptr && u->is_received; +} + +bool UserManager::have_min_user(UserId user_id) const { + return users_.count(user_id) > 0; +} + +const UserManager::User *UserManager::get_user(UserId user_id) const { + return users_.get_pointer(user_id); +} + +UserManager::User *UserManager::get_user(UserId user_id) { + return users_.get_pointer(user_id); +} + +UserManager::User *UserManager::add_user(UserId user_id) { + CHECK(user_id.is_valid()); + auto &user_ptr = users_[user_id]; + if (user_ptr == nullptr) { + user_ptr = make_unique(); + } + return user_ptr.get(); +} + +void UserManager::save_user(User *u, UserId user_id, bool from_binlog) { + if (!G()->use_chat_info_database()) { + return; + } + CHECK(u != nullptr); + if (!u->is_saved || !u->is_status_saved) { // TODO more effective handling of !u->is_status_saved + if (!from_binlog) { + auto log_event = UserLogEvent(user_id, u); + auto storer = get_log_event_storer(log_event); + if (u->log_event_id == 0) { + u->log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::Users, storer); + } else { + binlog_rewrite(G()->td_db()->get_binlog(), u->log_event_id, LogEvent::HandlerType::Users, storer); + } + } + + save_user_to_database(u, user_id); + } +} + +string UserManager::get_user_database_key(UserId user_id) { + return PSTRING() << "us" << user_id.get(); +} + +string UserManager::get_user_database_value(const User *u) { + return log_event_store(*u).as_slice().str(); +} + +void UserManager::save_user_to_database(User *u, UserId user_id) { + CHECK(u != nullptr); + if (u->is_being_saved) { + return; + } + if (loaded_from_database_users_.count(user_id)) { + save_user_to_database_impl(u, user_id, get_user_database_value(u)); + return; + } + if (load_user_from_database_queries_.count(user_id) != 0) { + return; + } + + load_user_from_database_impl(user_id, Auto()); +} + +void UserManager::save_user_to_database_impl(User *u, UserId user_id, string value) { + CHECK(u != nullptr); + CHECK(load_user_from_database_queries_.count(user_id) == 0); + CHECK(!u->is_being_saved); + u->is_being_saved = true; + u->is_saved = true; + u->is_status_saved = true; + LOG(INFO) << "Trying to save to database " << user_id; + G()->td_db()->get_sqlite_pmc()->set( + get_user_database_key(user_id), std::move(value), PromiseCreator::lambda([user_id](Result<> result) { + send_closure(G()->user_manager(), &UserManager::on_save_user_to_database, user_id, result.is_ok()); + })); +} + +void UserManager::on_save_user_to_database(UserId user_id, bool success) { + if (G()->close_flag()) { + return; + } + + User *u = get_user(user_id); + CHECK(u != nullptr); + LOG_CHECK(u->is_being_saved) << success << ' ' << user_id << ' ' << u->is_saved << ' ' << u->is_status_saved << ' ' + << load_user_from_database_queries_.count(user_id) << ' ' << u->is_received << ' ' + << u->is_deleted << ' ' << u->is_bot << ' ' << u->need_save_to_database << ' ' + << u->is_changed << ' ' << u->is_status_changed << ' ' << u->is_name_changed << ' ' + << u->is_username_changed << ' ' << u->is_photo_changed << ' ' + << u->is_is_contact_changed << ' ' << u->is_is_deleted_changed << ' ' + << u->is_stories_hidden_changed << ' ' << u->log_event_id; + CHECK(load_user_from_database_queries_.count(user_id) == 0); + u->is_being_saved = false; + + if (!success) { + LOG(ERROR) << "Failed to save " << user_id << " to database"; + u->is_saved = false; + u->is_status_saved = false; + } else { + LOG(INFO) << "Successfully saved " << user_id << " to database"; + } + if (u->is_saved && u->is_status_saved) { + if (u->log_event_id != 0) { + binlog_erase(G()->td_db()->get_binlog(), u->log_event_id); + u->log_event_id = 0; + } + } else { + save_user(u, user_id, u->log_event_id != 0); + } +} + +void UserManager::load_user_from_database(User *u, UserId user_id, Promise promise) { + if (loaded_from_database_users_.count(user_id)) { + promise.set_value(Unit()); + return; + } + + CHECK(u == nullptr || !u->is_being_saved); + load_user_from_database_impl(user_id, std::move(promise)); +} + +void UserManager::load_user_from_database_impl(UserId user_id, Promise promise) { + LOG(INFO) << "Load " << user_id << " from database"; + auto &load_user_queries = load_user_from_database_queries_[user_id]; + load_user_queries.push_back(std::move(promise)); + if (load_user_queries.size() == 1u) { + G()->td_db()->get_sqlite_pmc()->get(get_user_database_key(user_id), PromiseCreator::lambda([user_id](string value) { + send_closure(G()->user_manager(), &UserManager::on_load_user_from_database, + user_id, std::move(value), false); + })); + } +} + +void UserManager::on_load_user_from_database(UserId user_id, string value, bool force) { + if (G()->close_flag() && !force) { + // the user is in Binlog and will be saved after restart + return; + } + + CHECK(user_id.is_valid()); + if (!loaded_from_database_users_.insert(user_id).second) { + return; + } + + auto it = load_user_from_database_queries_.find(user_id); + vector> promises; + if (it != load_user_from_database_queries_.end()) { + promises = std::move(it->second); + CHECK(!promises.empty()); + load_user_from_database_queries_.erase(it); + } + + LOG(INFO) << "Successfully loaded " << user_id << " of size " << value.size() << " from database"; + // G()->td_db()->get_sqlite_pmc()->erase(get_user_database_key(user_id), Auto()); + // return; + + User *u = get_user(user_id); + if (u == nullptr) { + if (!value.empty()) { + u = add_user(user_id); + + if (log_event_parse(*u, value).is_error()) { + LOG(ERROR) << "Failed to load " << user_id << " from database"; + users_.erase(user_id); + } else { + u->is_saved = true; + u->is_status_saved = true; + update_user(u, user_id, true, true); + } + } + } else { + CHECK(!u->is_saved); // user can't be saved before load completes + CHECK(!u->is_being_saved); + auto new_value = get_user_database_value(u); + if (value != new_value) { + save_user_to_database_impl(u, user_id, std::move(new_value)); + } else if (u->log_event_id != 0) { + binlog_erase(G()->td_db()->get_binlog(), u->log_event_id); + u->log_event_id = 0; + } + } + + set_promises(promises); +} + +bool UserManager::have_user_force(UserId user_id, const char *source) { + return get_user_force(user_id, source) != nullptr; +} + +UserManager::User *UserManager::get_user_force(UserId user_id, const char *source) { + auto u = get_user_force_impl(user_id, source); + if ((u == nullptr || !u->is_received) && + (user_id == get_service_notifications_user_id() || user_id == get_replies_bot_user_id() || + user_id == get_anonymous_bot_user_id() || user_id == get_channel_bot_user_id() || + user_id == get_anti_spam_bot_user_id())) { + int32 flags = USER_FLAG_HAS_ACCESS_HASH | USER_FLAG_HAS_FIRST_NAME | USER_FLAG_NEED_APPLY_MIN_PHOTO; + int64 profile_photo_id = 0; + int32 profile_photo_dc_id = 1; + string first_name; + string last_name; + string username; + string phone_number; + int32 bot_info_version = 0; + + if (user_id == get_service_notifications_user_id()) { + flags |= USER_FLAG_HAS_PHONE_NUMBER | USER_FLAG_IS_VERIFIED | USER_FLAG_IS_SUPPORT; + first_name = "Telegram"; + if (G()->is_test_dc()) { + flags |= USER_FLAG_HAS_LAST_NAME; + last_name = "Notifications"; + } + phone_number = "42777"; + profile_photo_id = 3337190045231023; + } else if (user_id == get_replies_bot_user_id()) { + flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT; + if (!G()->is_test_dc()) { + flags |= USER_FLAG_IS_PRIVATE_BOT; + } + first_name = "Replies"; + username = "replies"; + bot_info_version = G()->is_test_dc() ? 1 : 3; + } else if (user_id == get_anonymous_bot_user_id()) { + flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT; + if (!G()->is_test_dc()) { + flags |= USER_FLAG_IS_PRIVATE_BOT; + } + first_name = "Group"; + username = G()->is_test_dc() ? "izgroupbot" : "GroupAnonymousBot"; + bot_info_version = G()->is_test_dc() ? 1 : 3; + profile_photo_id = 5159307831025969322; + } else if (user_id == get_channel_bot_user_id()) { + flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT; + if (!G()->is_test_dc()) { + flags |= USER_FLAG_IS_PRIVATE_BOT; + } + first_name = G()->is_test_dc() ? "Channels" : "Channel"; + username = G()->is_test_dc() ? "channelsbot" : "Channel_Bot"; + bot_info_version = G()->is_test_dc() ? 1 : 4; + profile_photo_id = 587627495930570665; + } else if (user_id == get_service_notifications_user_id()) { + flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT; + if (G()->is_test_dc()) { + first_name = "antispambot"; + username = "tantispambot"; + } else { + flags |= USER_FLAG_IS_VERIFIED; + first_name = "Telegram Anti-Spam"; + username = "tgsantispambot"; + profile_photo_id = 5170408289966598902; + } + } + + telegram_api::object_ptr profile_photo; + if (!G()->is_test_dc() && profile_photo_id != 0) { + profile_photo = telegram_api::make_object(0, false, false, profile_photo_id, + BufferSlice(), profile_photo_dc_id); + } + + auto user = telegram_api::make_object( + flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, + false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, + false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, + false /*ignored*/, false /*ignored*/, false /*ignored*/, 0, false /*ignored*/, false /*ignored*/, + false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, user_id.get(), 1, first_name, + string(), username, phone_number, std::move(profile_photo), nullptr, bot_info_version, Auto(), string(), + string(), nullptr, vector>(), 0, nullptr, nullptr); + on_get_user(std::move(user), "get_user_force"); + u = get_user(user_id); + CHECK(u != nullptr && u->is_received); + + reload_user(user_id, Promise(), "get_user_force"); + } + return u; +} + +UserManager::User *UserManager::get_user_force_impl(UserId user_id, const char *source) { + if (!user_id.is_valid()) { + return nullptr; + } + + User *u = get_user(user_id); + if (u != nullptr) { + return u; + } + if (!G()->use_chat_info_database()) { + return nullptr; + } + if (loaded_from_database_users_.count(user_id)) { + return nullptr; + } + + LOG(INFO) << "Trying to load " << user_id << " from database from " << source; + on_load_user_from_database(user_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_user_database_key(user_id)), true); + return get_user(user_id); +} + +void UserManager::send_get_me_query(Td *td, Promise &&promise) { + vector> users; + users.push_back(telegram_api::make_object()); + td->create_handler(std::move(promise))->send(std::move(users)); +} + +UserId UserManager::get_me(Promise &&promise) { + auto my_id = get_my_id(); + if (!have_user_force(my_id, "get_me")) { + get_user_queries_.add_query(my_id.get(), std::move(promise), "get_me"); + return UserId(); + } + + promise.set_value(Unit()); + return my_id; +} + +bool UserManager::get_user(UserId user_id, int left_tries, Promise &&promise) { + if (!user_id.is_valid()) { + promise.set_error(Status::Error(400, "Invalid user identifier")); + return false; + } + + if (user_id == get_service_notifications_user_id() || user_id == get_replies_bot_user_id() || + user_id == get_anonymous_bot_user_id() || user_id == get_channel_bot_user_id() || + user_id == get_anti_spam_bot_user_id()) { + get_user_force(user_id, "get_user"); + } + + if (td_->auth_manager_->is_bot() ? !have_user(user_id) : !have_min_user(user_id)) { + if (left_tries > 2 && G()->use_chat_info_database()) { + send_closure_later(actor_id(this), &UserManager::load_user_from_database, nullptr, user_id, std::move(promise)); + return false; + } + auto r_input_user = get_input_user(user_id); + if (left_tries == 1 || r_input_user.is_error()) { + if (r_input_user.is_error()) { + promise.set_error(r_input_user.move_as_error()); + } else { + promise.set_error(Status::Error(400, "User not found")); + } + return false; + } + + get_user_queries_.add_query(user_id.get(), std::move(promise), "get_user"); + return false; + } + + promise.set_value(Unit()); + return true; +} + +void UserManager::reload_user(UserId user_id, Promise &&promise, const char *source) { + if (!user_id.is_valid()) { + return promise.set_error(Status::Error(400, "Invalid user identifier")); + } + + have_user_force(user_id, source); + + TRY_STATUS_PROMISE(promise, get_input_user(user_id)); + + get_user_queries_.add_query(user_id.get(), std::move(promise), source); +} + +Result> UserManager::get_input_user(UserId user_id) const { + if (user_id == get_my_id()) { + return telegram_api::make_object(); + } + + const User *u = get_user(user_id); + if (u == nullptr || u->access_hash == -1 || u->is_min_access_hash) { + if (td_->auth_manager_->is_bot() && user_id.is_valid()) { + return telegram_api::make_object(user_id.get(), 0); + } + auto it = user_messages_.find(user_id); + if (it != user_messages_.end()) { + CHECK(!it->second.empty()); + auto message_full_id = *it->second.begin(); + return telegram_api::make_object( + td_->contacts_manager_->get_simple_input_peer(message_full_id.get_dialog_id()), + message_full_id.get_message_id().get_server_message_id().get(), user_id.get()); + } + if (u == nullptr) { + return Status::Error(400, "User not found"); + } else { + return Status::Error(400, "Have no access to the user"); + } + } + + return telegram_api::make_object(user_id.get(), u->access_hash); +} + +telegram_api::object_ptr UserManager::get_input_user_force(UserId user_id) const { + auto r_input_user = get_input_user(user_id); + if (r_input_user.is_error()) { + CHECK(user_id.is_valid()); + return telegram_api::make_object(user_id.get(), 0); + } + return r_input_user.move_as_ok(); +} + +bool UserManager::have_input_peer_user(UserId user_id, AccessRights access_rights) const { + if (user_id == get_my_id()) { + return true; + } + return have_input_peer_user(get_user(user_id), user_id, access_rights); +} + +bool UserManager::have_input_peer_user(const User *u, UserId user_id, AccessRights access_rights) const { + if (u == nullptr || u->access_hash == -1 || u->is_min_access_hash) { + if (u == nullptr) { + LOG(DEBUG) << "Have no user"; + } else { + LOG(DEBUG) << "Have user without access hash"; + } + if (td_->auth_manager_->is_bot() && user_id.is_valid()) { + return true; + } + if (user_messages_.count(user_id) != 0) { + return true; + } + return false; + } + if (access_rights == AccessRights::Know) { + return true; + } + if (access_rights == AccessRights::Read) { + return true; + } + if (u->is_deleted) { + LOG(DEBUG) << "Have a deleted user"; + return false; + } + return true; +} + +telegram_api::object_ptr UserManager::get_input_peer_user(UserId user_id, + AccessRights access_rights) const { + if (user_id == get_my_id()) { + return telegram_api::make_object(); + } + const User *u = get_user(user_id); + if (!have_input_peer_user(u, user_id, access_rights)) { + return nullptr; + } + if (u == nullptr || u->access_hash == -1 || u->is_min_access_hash) { + if (td_->auth_manager_->is_bot() && user_id.is_valid()) { + return telegram_api::make_object(user_id.get(), 0); + } + auto it = user_messages_.find(user_id); + CHECK(it != user_messages_.end()); + CHECK(!it->second.empty()); + auto message_full_id = *it->second.begin(); + return telegram_api::make_object( + td_->contacts_manager_->get_simple_input_peer(message_full_id.get_dialog_id()), + message_full_id.get_message_id().get_server_message_id().get(), user_id.get()); + } + + return telegram_api::make_object(user_id.get(), u->access_hash); +} + +bool UserManager::have_input_encrypted_peer(SecretChatId secret_chat_id, AccessRights access_rights) const { + return have_input_encrypted_peer(get_secret_chat(secret_chat_id), access_rights); +} + +bool UserManager::have_input_encrypted_peer(const SecretChat *secret_chat, AccessRights access_rights) { + if (secret_chat == nullptr) { + LOG(DEBUG) << "Have no secret chat"; + return false; + } + if (access_rights == AccessRights::Know) { + return true; + } + if (access_rights == AccessRights::Read) { + return true; + } + return secret_chat->state == SecretChatState::Active; +} + +telegram_api::object_ptr UserManager::get_input_encrypted_chat( + SecretChatId secret_chat_id, AccessRights access_rights) const { + auto sc = get_secret_chat(secret_chat_id); + if (!have_input_encrypted_peer(sc, access_rights)) { + return nullptr; + } + + return telegram_api::make_object(secret_chat_id.get(), sc->access_hash); +} + +bool UserManager::is_user_contact(UserId user_id, bool is_mutual) const { + return is_user_contact(get_user(user_id), user_id, is_mutual); +} + +bool UserManager::is_user_contact(const User *u, UserId user_id, bool is_mutual) const { + return u != nullptr && (is_mutual ? u->is_mutual_contact : u->is_contact) && user_id != get_my_id(); +} + +bool UserManager::is_user_premium(UserId user_id) const { + return is_user_premium(get_user(user_id)); +} + +bool UserManager::is_user_premium(const User *u) { + return u != nullptr && u->is_premium; +} + +bool UserManager::is_user_deleted(UserId user_id) const { + return is_user_deleted(get_user(user_id)); +} + +bool UserManager::is_user_deleted(const User *u) { + return u == nullptr || u->is_deleted; +} + +bool UserManager::is_user_support(UserId user_id) const { + return is_user_support(get_user(user_id)); +} + +bool UserManager::is_user_support(const User *u) { + return u != nullptr && !u->is_deleted && u->is_support; +} + +bool UserManager::is_user_bot(UserId user_id) const { + return is_user_bot(get_user(user_id)); +} + +bool UserManager::is_user_bot(const User *u) { + return u != nullptr && !u->is_deleted && u->is_bot; +} + +Result UserManager::get_bot_data(UserId user_id) const { + auto u = get_user(user_id); + if (u == nullptr) { + return Status::Error(400, "Bot not found"); + } + if (!u->is_bot) { + return Status::Error(400, "User is not a bot"); + } + if (u->is_deleted) { + return Status::Error(400, "Bot is deleted"); + } + if (!u->is_received) { + return Status::Error(400, "Bot is inaccessible"); + } + + BotData bot_data; + bot_data.username = u->usernames.get_first_username(); + bot_data.can_be_edited = u->can_be_edited_bot; + bot_data.can_join_groups = u->can_join_groups; + bot_data.can_read_all_group_messages = u->can_read_all_group_messages; + bot_data.is_inline = u->is_inline_bot; + bot_data.is_business = u->is_business_bot; + bot_data.need_location = u->need_location_bot; + bot_data.can_be_added_to_attach_menu = u->can_be_added_to_attach_menu; + return bot_data; +} + +bool UserManager::is_user_online(UserId user_id, int32 tolerance, int32 unix_time) const { + if (unix_time <= 0) { + unix_time = G()->unix_time(); + } + int32 was_online = get_user_was_online(get_user(user_id), user_id, unix_time); + return was_online > unix_time - tolerance; +} + +int32 UserManager::get_user_was_online(UserId user_id, int32 unix_time) const { + if (unix_time <= 0) { + unix_time = G()->unix_time(); + } + return get_user_was_online(get_user(user_id), user_id, unix_time); +} + +int32 UserManager::get_user_was_online(const User *u, UserId user_id, int32 unix_time) const { + if (u == nullptr || u->is_deleted) { + return 0; + } + + int32 was_online = u->was_online; + if (user_id == get_my_id()) { + if (my_was_online_local_ != 0) { + was_online = my_was_online_local_; + } + } else { + if (u->local_was_online > 0 && u->local_was_online > was_online && u->local_was_online > unix_time) { + was_online = u->local_was_online; + } + } + return was_online; +} + +bool UserManager::is_user_status_exact(UserId user_id) const { + auto u = get_user(user_id); + return u != nullptr && !u->is_deleted && !u->is_bot && u->was_online > 0; +} + +bool UserManager::is_user_received_from_server(UserId user_id) const { + const auto *u = get_user(user_id); + return u != nullptr && u->is_received_from_server; +} + +bool UserManager::can_report_user(UserId user_id) const { + auto u = get_user(user_id); + return u != nullptr && !u->is_deleted && !u->is_support && + (u->is_bot || td_->people_nearby_manager_->is_user_nearby(user_id)); +} + +const DialogPhoto *UserManager::get_user_dialog_photo(UserId user_id) { + auto u = get_user(user_id); + if (u == nullptr) { + return nullptr; + } + + apply_pending_user_photo(u, user_id); + return &u->photo; +} + +const DialogPhoto *UserManager::get_secret_chat_dialog_photo(SecretChatId secret_chat_id) { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return nullptr; + } + return get_user_dialog_photo(c->user_id); +} + +int32 UserManager::get_user_accent_color_id_object(UserId user_id) const { + auto u = get_user(user_id); + if (u == nullptr || !u->accent_color_id.is_valid()) { + return td_->theme_manager_->get_accent_color_id_object(AccentColorId(user_id)); + } + + return td_->theme_manager_->get_accent_color_id_object(u->accent_color_id, AccentColorId(user_id)); +} + +int32 UserManager::get_secret_chat_accent_color_id_object(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return 5; + } + return get_user_accent_color_id_object(c->user_id); +} + +CustomEmojiId UserManager::get_user_background_custom_emoji_id(UserId user_id) const { + auto u = get_user(user_id); + if (u == nullptr) { + return CustomEmojiId(); + } + + return u->background_custom_emoji_id; +} + +CustomEmojiId UserManager::get_secret_chat_background_custom_emoji_id(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return CustomEmojiId(); + } + return get_user_background_custom_emoji_id(c->user_id); +} + +int32 UserManager::get_user_profile_accent_color_id_object(UserId user_id) const { + auto u = get_user(user_id); + if (u == nullptr) { + return -1; + } + + return td_->theme_manager_->get_profile_accent_color_id_object(u->profile_accent_color_id); +} + +int32 UserManager::get_secret_chat_profile_accent_color_id_object(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return -1; + } + return get_user_profile_accent_color_id_object(c->user_id); +} + +CustomEmojiId UserManager::get_user_profile_background_custom_emoji_id(UserId user_id) const { + auto u = get_user(user_id); + if (u == nullptr) { + return CustomEmojiId(); + } + + return u->profile_background_custom_emoji_id; +} + +CustomEmojiId UserManager::get_secret_chat_profile_background_custom_emoji_id(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return CustomEmojiId(); + } + return get_user_profile_background_custom_emoji_id(c->user_id); +} + +string UserManager::get_user_title(UserId user_id) const { + auto u = get_user(user_id); + if (u == nullptr) { + return string(); + } + if (u->last_name.empty()) { + return u->first_name; + } + if (u->first_name.empty()) { + return u->last_name; + } + return PSTRING() << u->first_name << ' ' << u->last_name; +} + +string UserManager::get_secret_chat_title(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return string(); + } + return get_user_title(c->user_id); +} + +RestrictedRights UserManager::get_user_default_permissions(UserId user_id) const { + auto u = get_user(user_id); + if (u == nullptr || user_id == get_replies_bot_user_id()) { + return RestrictedRights(false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, u != nullptr, false, ChannelType::Unknown); + } + return RestrictedRights(true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, + true, false, ChannelType::Unknown); +} + +RestrictedRights UserManager::get_secret_chat_default_permissions(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return RestrictedRights(false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, ChannelType::Unknown); + } + return RestrictedRights(true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, + false, false, ChannelType::Unknown); +} + +td_api::object_ptr UserManager::get_user_emoji_status_object(UserId user_id) const { + auto u = get_user(user_id); + if (u == nullptr) { + return nullptr; + } + return u->last_sent_emoji_status.get_emoji_status_object(); +} + +td_api::object_ptr UserManager::get_secret_chat_emoji_status_object( + SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return nullptr; + } + return get_user_emoji_status_object(c->user_id); +} + +bool UserManager::get_user_stories_hidden(UserId user_id) const { + auto u = get_user(user_id); + if (u == nullptr) { + return false; + } + return u->stories_hidden; +} + +bool UserManager::can_poll_user_active_stories(UserId user_id) const { + const User *u = get_user(user_id); + return need_poll_user_active_stories(u, user_id) && Time::now() >= u->max_active_story_id_next_reload_time; +} + +bool UserManager::need_poll_user_active_stories(const User *u, UserId user_id) const { + return u != nullptr && user_id != get_my_id() && !is_user_contact(u, user_id, false) && !is_user_bot(u) && + !is_user_support(u) && !is_user_deleted(u) && u->was_online != 0; +} + +string UserManager::get_user_about(UserId user_id) { + auto user_full = get_user_full_force(user_id, "get_user_about"); + if (user_full != nullptr) { + return user_full->about; + } + return string(); +} + +string UserManager::get_secret_chat_about(SecretChatId secret_chat_id) { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return string(); + } + return get_user_about(c->user_id); +} + +string UserManager::get_user_private_forward_name(UserId user_id) { + auto user_full = get_user_full_force(user_id, "get_user_private_forward_name"); + if (user_full != nullptr) { + return user_full->private_forward_name; + } + return string(); +} + +bool UserManager::get_user_voice_messages_forbidden(UserId user_id) const { + if (!is_user_premium(user_id)) { + return false; + } + auto user_full = get_user_full(user_id); + if (user_full != nullptr) { + return user_full->voice_messages_forbidden; + } + return false; +} + +bool UserManager::get_user_read_dates_private(UserId user_id) { + auto user_full = get_user_full_force(user_id, "get_user_read_dates_private"); + if (user_full != nullptr) { + return user_full->read_dates_private; + } + return false; +} + +string UserManager::get_user_search_text(UserId user_id) const { + auto u = get_user(user_id); + if (u == nullptr) { + return string(); + } + return get_user_search_text(u); +} + +string UserManager::get_user_search_text(const User *u) { + CHECK(u != nullptr); + return PSTRING() << u->first_name << ' ' << u->last_name << ' ' << implode(u->usernames.get_active_usernames()); +} + +void UserManager::for_each_secret_chat_with_user(UserId user_id, const std::function &f) { + auto it = secret_chats_with_user_.find(user_id); + if (it != secret_chats_with_user_.end()) { + for (auto secret_chat_id : it->second) { + f(secret_chat_id); + } + } +} + +string UserManager::get_user_first_username(UserId user_id) const { + if (!user_id.is_valid()) { + return string(); + } + + auto u = get_user(user_id); + if (u == nullptr) { + return string(); + } + return u->usernames.get_first_username(); +} + +int32 UserManager::get_secret_chat_date(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return 0; + } + return c->date; +} + +int32 UserManager::get_secret_chat_ttl(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return 0; + } + return c->ttl; +} + +UserId UserManager::get_secret_chat_user_id(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return UserId(); + } + return c->user_id; +} + +bool UserManager::get_secret_chat_is_outbound(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return false; + } + return c->is_outbound; +} + +SecretChatState UserManager::get_secret_chat_state(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return SecretChatState::Unknown; + } + return c->state; +} + +int32 UserManager::get_secret_chat_layer(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return 0; + } + return c->layer; +} + +FolderId UserManager::get_secret_chat_initial_folder_id(SecretChatId secret_chat_id) const { + auto c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + return FolderId::main(); + } + return c->initial_folder_id; +} + +vector UserManager::get_bot_commands(vector> &&bot_infos, + const vector *participants) { + vector result; + if (td_->auth_manager_->is_bot()) { + return result; + } + for (auto &bot_info : bot_infos) { + if (bot_info->commands_.empty()) { + continue; + } + + auto user_id = UserId(bot_info->user_id_); + const User *u = get_user_force(user_id, "get_bot_commands"); + if (u == nullptr) { + LOG(ERROR) << "Receive unknown " << user_id; + continue; + } + if (!is_user_bot(u)) { + if (!is_user_deleted(u)) { + LOG(ERROR) << "Receive non-bot " << user_id; + } + continue; + } + if (participants != nullptr) { + bool is_participant = false; + for (auto &participant : *participants) { + if (participant.dialog_id_ == DialogId(user_id)) { + is_participant = true; + break; + } + } + if (!is_participant) { + LOG(ERROR) << "Skip commands of non-member bot " << user_id; + continue; + } + } + result.emplace_back(user_id, std::move(bot_info->commands_)); + } + return result; +} + +void UserManager::set_name(const string &first_name, const string &last_name, Promise &&promise) { + auto new_first_name = clean_name(first_name, MAX_NAME_LENGTH); + auto new_last_name = clean_name(last_name, MAX_NAME_LENGTH); + if (new_first_name.empty()) { + return promise.set_error(Status::Error(400, "First name must be non-empty")); + } + + const User *u = get_user(get_my_id()); + int32 flags = 0; + // TODO we can already send request for changing first_name and last_name and wanting to set initial values + // TODO need to be rewritten using invoke after and cancelling previous request + if (u == nullptr || u->first_name != new_first_name) { + flags |= ACCOUNT_UPDATE_FIRST_NAME; + } + if (u == nullptr || u->last_name != new_last_name) { + flags |= ACCOUNT_UPDATE_LAST_NAME; + } + if (flags == 0) { + return promise.set_value(Unit()); + } + + td_->create_handler(std::move(promise))->send(flags, new_first_name, new_last_name, ""); +} + +void UserManager::set_bio(const string &bio, Promise &&promise) { + auto max_bio_length = static_cast(td_->option_manager_->get_option_integer("bio_length_max")); + auto new_bio = strip_empty_characters(bio, max_bio_length); + for (auto &c : new_bio) { + if (c == '\n') { + c = ' '; + } + } + + const UserFull *user_full = get_user_full(get_my_id()); + int32 flags = 0; + // TODO we can already send request for changing bio and wanting to set initial values + // TODO need to be rewritten using invoke after and cancelling previous request + if (user_full == nullptr || user_full->about != new_bio) { + flags |= ACCOUNT_UPDATE_ABOUT; + } + if (flags == 0) { + return promise.set_value(Unit()); + } + + td_->create_handler(std::move(promise))->send(flags, "", "", new_bio); +} + +void UserManager::on_update_profile_success(int32 flags, const string &first_name, const string &last_name, + const string &about) { + CHECK(flags != 0); + + auto my_user_id = get_my_id(); + const User *u = get_user(my_user_id); + if (u == nullptr) { + LOG(ERROR) << "Doesn't receive info about me during update profile"; + return; + } + LOG_IF(ERROR, (flags & ACCOUNT_UPDATE_FIRST_NAME) != 0 && u->first_name != first_name) + << "Wrong first name \"" << u->first_name << "\", expected \"" << first_name << '"'; + LOG_IF(ERROR, (flags & ACCOUNT_UPDATE_LAST_NAME) != 0 && u->last_name != last_name) + << "Wrong last name \"" << u->last_name << "\", expected \"" << last_name << '"'; + + if ((flags & ACCOUNT_UPDATE_ABOUT) != 0) { + UserFull *user_full = get_user_full_force(my_user_id, "on_update_profile_success"); + if (user_full != nullptr) { + user_full->about = about; + user_full->is_changed = true; + update_user_full(user_full, my_user_id, "on_update_profile_success"); + td_->group_call_manager_->on_update_dialog_about(DialogId(my_user_id), user_full->about, true); + } + } +} + +FileId UserManager::get_profile_photo_file_id(int64 photo_id) const { + auto it = my_photo_file_id_.find(photo_id); + if (it == my_photo_file_id_.end()) { + return FileId(); + } + return it->second; +} + +void UserManager::set_bot_profile_photo(UserId bot_user_id, + const td_api::object_ptr &input_photo, + Promise &&promise) { + if (td_->auth_manager_->is_bot()) { + if (bot_user_id != UserId() && bot_user_id != get_my_id()) { + return promise.set_error(Status::Error(400, "Invalid bot user identifier specified")); + } + bot_user_id = get_my_id(); + } else { + TRY_RESULT_PROMISE(promise, bot_data, get_bot_data(bot_user_id)); + if (!bot_data.can_be_edited) { + return promise.set_error(Status::Error(400, "The bot can't be edited")); + } + } + if (input_photo == nullptr) { + td_->create_handler(std::move(promise)) + ->send(bot_user_id, FileId(), 0, false, telegram_api::make_object()); + return; + } + set_profile_photo_impl(bot_user_id, input_photo, false, false, std::move(promise)); +} + +void UserManager::set_profile_photo(const td_api::object_ptr &input_photo, bool is_fallback, + Promise &&promise) { + set_profile_photo_impl(get_my_id(), input_photo, is_fallback, false, std::move(promise)); +} + +void UserManager::set_profile_photo_impl(UserId user_id, const td_api::object_ptr &input_photo, + bool is_fallback, bool only_suggest, Promise &&promise) { + if (input_photo == nullptr) { + return promise.set_error(Status::Error(400, "New profile photo must be non-empty")); + } + + const td_api::object_ptr *input_file = nullptr; + double main_frame_timestamp = 0.0; + bool is_animation = false; + switch (input_photo->get_id()) { + case td_api::inputChatPhotoPrevious::ID: { + if (user_id != get_my_id() || td_->auth_manager_->is_bot()) { + return promise.set_error(Status::Error(400, "Can't use inputChatPhotoPrevious")); + } + auto photo = static_cast(input_photo.get()); + auto photo_id = photo->chat_photo_id_; + auto *u = get_user(user_id); + if (u != nullptr && u->photo.id > 0 && photo_id == u->photo.id) { + // it is possible that u->photo.is_fallback != is_fallback, so we need to set the photo anyway + // return promise.set_value(Unit()); + } + + auto file_id = get_profile_photo_file_id(photo_id); + if (!file_id.is_valid()) { + return promise.set_error(Status::Error(400, "Unknown profile photo ID specified")); + } + return send_update_profile_photo_query(user_id, + td_->file_manager_->dup_file_id(file_id, "set_profile_photo_impl"), + photo_id, is_fallback, std::move(promise)); + } + case td_api::inputChatPhotoStatic::ID: { + auto photo = static_cast(input_photo.get()); + input_file = &photo->photo_; + break; + } + case td_api::inputChatPhotoAnimation::ID: { + auto photo = static_cast(input_photo.get()); + input_file = &photo->animation_; + main_frame_timestamp = photo->main_frame_timestamp_; + is_animation = true; + break; + } + case td_api::inputChatPhotoSticker::ID: { + auto photo = static_cast(input_photo.get()); + TRY_RESULT_PROMISE(promise, sticker_photo_size, StickerPhotoSize::get_sticker_photo_size(td_, photo->sticker_)); + + td_->create_handler(std::move(promise)) + ->send(user_id, std::move(sticker_photo_size), is_fallback, only_suggest); + return; + } + default: + UNREACHABLE(); + break; + } + + const double MAX_ANIMATION_DURATION = 10.0; + if (main_frame_timestamp < 0.0 || main_frame_timestamp > MAX_ANIMATION_DURATION) { + return promise.set_error(Status::Error(400, "Wrong main frame timestamp specified")); + } + + auto file_type = is_animation ? FileType::Animation : FileType::Photo; + TRY_RESULT_PROMISE(promise, file_id, + td_->file_manager_->get_input_file_id(file_type, *input_file, DialogId(user_id), false, false)); + CHECK(file_id.is_valid()); + + upload_profile_photo(user_id, td_->file_manager_->dup_file_id(file_id, "set_profile_photo_impl"), is_fallback, + only_suggest, is_animation, main_frame_timestamp, std::move(promise)); +} + +void UserManager::set_user_profile_photo(UserId user_id, const td_api::object_ptr &input_photo, + bool only_suggest, Promise &&promise) { + TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); + if (!only_suggest && !is_user_contact(user_id)) { + return promise.set_error(Status::Error(400, "User isn't a contact")); + } + if (user_id == get_my_id()) { + return promise.set_error(Status::Error(400, "Can't set personal or suggest photo to self")); + } + if (is_user_bot(user_id)) { + return promise.set_error(Status::Error(400, "Can't set personal or suggest photo to bots")); + } + if (input_photo == nullptr) { + td_->create_handler(std::move(promise))->send(user_id, std::move(input_user)); + return; + } + + set_profile_photo_impl(user_id, input_photo, false, only_suggest, std::move(promise)); +} + +void UserManager::send_update_profile_photo_query(UserId user_id, FileId file_id, int64 old_photo_id, bool is_fallback, + Promise &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + FileView file_view = td_->file_manager_->get_file_view(file_id); + td_->create_handler(std::move(promise)) + ->send(user_id, file_id, old_photo_id, is_fallback, file_view.main_remote_location().as_input_photo()); +} + +void UserManager::upload_profile_photo(UserId user_id, FileId file_id, bool is_fallback, bool only_suggest, + bool is_animation, double main_frame_timestamp, Promise &&promise, + int reupload_count, vector bad_parts) { + CHECK(file_id.is_valid()); + bool is_inserted = + uploaded_profile_photos_ + .emplace(file_id, UploadedProfilePhoto{user_id, is_fallback, only_suggest, main_frame_timestamp, is_animation, + reupload_count, std::move(promise)}) + .second; + CHECK(is_inserted); + LOG(INFO) << "Ask to upload " << (is_animation ? "animated" : "static") << " profile photo " << file_id + << " for user " << user_id << " with bad parts " << bad_parts; + // TODO use force_reupload if reupload_count >= 1, replace reupload_count with is_reupload + td_->file_manager_->resume_upload(file_id, std::move(bad_parts), upload_profile_photo_callback_, 32, 0); +} + +void UserManager::on_upload_profile_photo(FileId file_id, + telegram_api::object_ptr input_file) { + auto it = uploaded_profile_photos_.find(file_id); + CHECK(it != uploaded_profile_photos_.end()); + + UserId user_id = it->second.user_id; + bool is_fallback = it->second.is_fallback; + bool only_suggest = it->second.only_suggest; + double main_frame_timestamp = it->second.main_frame_timestamp; + bool is_animation = it->second.is_animation; + int32 reupload_count = it->second.reupload_count; + auto promise = std::move(it->second.promise); + + uploaded_profile_photos_.erase(it); + + LOG(INFO) << "Uploaded " << (is_animation ? "animated" : "static") << " profile photo " << file_id << " for " + << user_id << " with reupload_count = " << reupload_count; + FileView file_view = td_->file_manager_->get_file_view(file_id); + if (file_view.has_remote_location() && input_file == nullptr) { + if (file_view.main_remote_location().is_web()) { + return promise.set_error(Status::Error(400, "Can't use web photo as profile photo")); + } + if (reupload_count == 3) { // upload, ForceReupload repair file reference, reupload + return promise.set_error(Status::Error(400, "Failed to reupload the file")); + } + + // delete file reference and forcely reupload the file + if (is_animation) { + CHECK(file_view.get_type() == FileType::Animation); + LOG_CHECK(file_view.main_remote_location().is_common()) << file_view.main_remote_location(); + } else { + CHECK(file_view.get_type() == FileType::Photo); + LOG_CHECK(file_view.main_remote_location().is_photo()) << file_view.main_remote_location(); + } + auto file_reference = + is_animation ? FileManager::extract_file_reference(file_view.main_remote_location().as_input_document()) + : FileManager::extract_file_reference(file_view.main_remote_location().as_input_photo()); + td_->file_manager_->delete_file_reference(file_id, file_reference); + upload_profile_photo(user_id, file_id, is_fallback, only_suggest, is_animation, main_frame_timestamp, + std::move(promise), reupload_count + 1, {-1}); + return; + } + CHECK(input_file != nullptr); + + td_->create_handler(std::move(promise)) + ->send(user_id, file_id, std::move(input_file), is_fallback, only_suggest, is_animation, main_frame_timestamp); +} + +void UserManager::on_upload_profile_photo_error(FileId file_id, Status status) { + LOG(INFO) << "File " << file_id << " has upload error " << status; + CHECK(status.is_error()); + + auto it = uploaded_profile_photos_.find(file_id); + CHECK(it != uploaded_profile_photos_.end()); + + auto promise = std::move(it->second.promise); + + uploaded_profile_photos_.erase(it); + + promise.set_error(std::move(status)); // TODO check that status has valid error code +} + +void UserManager::on_set_profile_photo(UserId user_id, telegram_api::object_ptr &&photo, + bool is_fallback, int64 old_photo_id, Promise &&promise) { + LOG(INFO) << "Changed profile photo to " << to_string(photo); + + bool is_bot = is_user_bot(user_id); + bool is_my = (user_id == get_my_id()); + if (is_my && !is_fallback) { + delete_my_profile_photo_from_cache(old_photo_id); + } + bool have_user = false; + for (const auto &user : photo->users_) { + if (get_user_id(user) == user_id) { + have_user = true; + } + } + on_get_users(std::move(photo->users_), "on_set_profile_photo"); + if (!is_bot) { + add_set_profile_photo_to_cache(user_id, get_photo(td_, std::move(photo->photo_), DialogId(user_id)), is_fallback); + } + if (have_user) { + promise.set_value(Unit()); + } else { + reload_user(user_id, std::move(promise), "on_set_profile_photo"); + } +} + +void UserManager::add_set_profile_photo_to_cache(UserId user_id, Photo &&photo, bool is_fallback) { + // we have subsequence of user photos in user_photos_ + // ProfilePhoto in User and Photo in UserFull + + User *u = get_user_force(user_id, "add_set_profile_photo_to_cache"); + if (u == nullptr) { + return; + } + + LOG(INFO) << "Add profile photo " << photo.id.get() << " to cache"; + + bool is_me = user_id == get_my_id(); + + // update photo list + auto user_photos = user_photos_.get_pointer(user_id); + if (is_me && !is_fallback && user_photos != nullptr && user_photos->count != -1 && !photo.is_empty()) { + if (user_photos->offset == 0) { + if (user_photos->photos.empty() || user_photos->photos[0].id.get() != photo.id.get()) { + user_photos->photos.insert(user_photos->photos.begin(), photo); + user_photos->count++; + register_user_photo(u, user_id, user_photos->photos[0]); + } + } else { + user_photos->count++; + user_photos->offset++; + } + } + + // update ProfilePhoto in User + if ((!is_fallback || u->photo.id == 0) && !photo.is_empty()) { + do_update_user_photo(u, user_id, as_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, photo, !is_me), + false, "add_set_profile_photo_to_cache"); + update_user(u, user_id); + } + + // update Photo in UserFull + auto user_full = get_user_full_force(user_id, "add_set_profile_photo_to_cache"); + if (user_full != nullptr) { + Photo *current_photo = nullptr; + // don't update the changed photo if other photos aren't known to avoid having only some photos known + bool need_apply = get_user_full_profile_photo_id(user_full) > 0; + if (!is_me) { + current_photo = &user_full->personal_photo; + if (photo.is_empty()) { + // always can apply empty personal photo + need_apply = true; + } + } else if (!is_fallback) { + current_photo = &user_full->photo; + if (photo.is_empty()) { + // never can apply empty photo + need_apply = false; + } + } else { + current_photo = &user_full->fallback_photo; + if (photo.is_empty()) { + // always can apply empty fallback photo + need_apply = true; + } + } + if (*current_photo != photo && need_apply) { + LOG(INFO) << "Update full photo of " << user_id << " to " << photo; + *current_photo = photo; + user_full->is_changed = true; + if (is_me && !photo.is_empty()) { + if (!is_fallback) { + register_user_photo(u, user_id, photo); + } else { + register_suggested_profile_photo(photo); + } + } + drop_user_full_photos(user_full, user_id, u->photo.id, "add_set_profile_photo_to_cache"); // just in case + } + if (user_full->expires_at > 0.0) { + user_full->expires_at = 0.0; + user_full->need_save_to_database = true; + } + update_user_full(user_full, user_id, "add_set_profile_photo_to_cache"); + reload_user_full(user_id, Auto(), "add_set_profile_photo_to_cache"); + } +} + +bool UserManager::delete_my_profile_photo_from_cache(int64 profile_photo_id) { + if (profile_photo_id == 0 || profile_photo_id == -2) { + return false; + } + + // we have subsequence of user photos in user_photos_ + // ProfilePhoto in User and Photo in UserFull + + LOG(INFO) << "Delete profile photo " << profile_photo_id << " from cache"; + + auto user_id = get_my_id(); + User *u = get_user_force(user_id, "delete_my_profile_photo_from_cache"); + bool is_main_photo_deleted = u != nullptr && u->photo.id == profile_photo_id; + + // update photo list + auto user_photos = user_photos_.get_pointer(user_id); + if (user_photos != nullptr && user_photos->count > 0) { + auto old_size = user_photos->photos.size(); + if (td::remove_if(user_photos->photos, + [profile_photo_id](const auto &photo) { return photo.id.get() == profile_photo_id; })) { + auto removed_photos = old_size - user_photos->photos.size(); + CHECK(removed_photos > 0); + LOG_IF(ERROR, removed_photos != 1) << "Had " << removed_photos << " photos with ID " << profile_photo_id; + user_photos->count -= narrow_cast(removed_photos); + // offset was not changed + CHECK(user_photos->count >= 0); + } else { + // failed to find photo to remove from cache + // don't know how to adjust user_photos->offset, so drop photos cache + LOG(INFO) << "Drop photos of " << user_id; + user_photos->photos.clear(); + user_photos->count = -1; + user_photos->offset = -1; + } + } + bool have_new_photo = + user_photos != nullptr && user_photos->count != -1 && user_photos->offset == 0 && !user_photos->photos.empty(); + + auto user_full = get_user_full_force(user_id, "delete_my_profile_photo_from_cache"); + + // update ProfilePhoto in User + bool need_reget_user = false; + if (is_main_photo_deleted) { + if (have_new_photo) { + do_update_user_photo( + u, user_id, + as_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, user_photos->photos[0], false), false, + "delete_my_profile_photo_from_cache"); + } else { + do_update_user_photo(u, user_id, ProfilePhoto(), false, "delete_my_profile_photo_from_cache 2"); + need_reget_user = user_photos == nullptr || user_photos->count != 0; + } + update_user(u, user_id); + + // update Photo in UserFull + if (user_full != nullptr) { + if (user_full->fallback_photo.id.get() == profile_photo_id) { + LOG(INFO) << "Drop full public photo of " << user_id; + user_full->photo = Photo(); + user_full->is_changed = true; + } else if (have_new_photo) { + if (user_full->photo.id.get() == profile_photo_id && user_photos->photos[0] != user_full->photo) { + LOG(INFO) << "Update full photo of " << user_id << " to " << user_photos->photos[0]; + user_full->photo = user_photos->photos[0]; + user_full->is_changed = true; + } + } else { + // repair UserFull photo + if (!user_full->photo.is_empty()) { + user_full->photo = Photo(); + user_full->is_changed = true; + } + if (!user_full->fallback_photo.is_empty()) { + user_full->fallback_photo = Photo(); + user_full->is_changed = true; + } + } + if (user_full->expires_at > 0.0) { + user_full->expires_at = 0.0; + user_full->need_save_to_database = true; + } + reload_user_full(user_id, Auto(), "delete_my_profile_photo_from_cache"); + update_user_full(user_full, user_id, "delete_my_profile_photo_from_cache"); + } + } + + return need_reget_user; +} + +void UserManager::delete_profile_photo(int64 profile_photo_id, bool is_recursive, Promise &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + const UserFull *user_full = get_user_full_force(get_my_id(), "delete_profile_photo"); + if (user_full == nullptr) { + // must load UserFull first, because fallback photo can't be deleted via DeleteProfilePhotoQuery + if (is_recursive) { + return promise.set_error(Status::Error(500, "Failed to load UserFullInfo")); + } + auto reload_promise = PromiseCreator::lambda( + [actor_id = actor_id(this), profile_photo_id, promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + return promise.set_error(result.move_as_error()); + } + send_closure(actor_id, &UserManager::delete_profile_photo, profile_photo_id, true, std::move(promise)); + }); + reload_user_full(get_my_id(), std::move(reload_promise), "delete_profile_photo"); + return; + } + if (user_full->photo.id.get() == profile_photo_id || user_full->fallback_photo.id.get() == profile_photo_id) { + td_->create_handler(std::move(promise)) + ->send(get_my_id(), FileId(), profile_photo_id, user_full->fallback_photo.id.get() == profile_photo_id, + telegram_api::make_object()); + return; + } + + td_->create_handler(std::move(promise))->send(profile_photo_id); +} + +void UserManager::on_delete_profile_photo(int64 profile_photo_id, Promise promise) { + bool need_reget_user = delete_my_profile_photo_from_cache(profile_photo_id); + if (need_reget_user && !G()->close_flag()) { + return reload_user(get_my_id(), std::move(promise), "on_delete_profile_photo"); + } + + promise.set_value(Unit()); +} + +void UserManager::set_username(const string &username, Promise &&promise) { + if (!username.empty() && !is_allowed_username(username)) { + return promise.set_error(Status::Error(400, "Username is invalid")); + } + td_->create_handler(std::move(promise))->send(username); +} + +void UserManager::toggle_username_is_active(string &&username, bool is_active, Promise &&promise) { + get_me(PromiseCreator::lambda([actor_id = actor_id(this), username = std::move(username), is_active, + promise = std::move(promise)](Result &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &UserManager::toggle_username_is_active_impl, std::move(username), is_active, + std::move(promise)); + } + })); +} + +void UserManager::toggle_username_is_active_impl(string &&username, bool is_active, Promise &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + const User *u = get_user(get_my_id()); + CHECK(u != nullptr); + if (!u->usernames.can_toggle(username)) { + return promise.set_error(Status::Error(400, "Wrong username specified")); + } + td_->create_handler(std::move(promise))->send(std::move(username), is_active); +} + +void UserManager::reorder_usernames(vector &&usernames, Promise &&promise) { + get_me(PromiseCreator::lambda([actor_id = actor_id(this), usernames = std::move(usernames), + promise = std::move(promise)](Result &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &UserManager::reorder_usernames_impl, std::move(usernames), std::move(promise)); + } + })); +} + +void UserManager::reorder_usernames_impl(vector &&usernames, Promise &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + const User *u = get_user(get_my_id()); + CHECK(u != nullptr); + if (!u->usernames.can_reorder_to(usernames)) { + return promise.set_error(Status::Error(400, "Invalid username order specified")); + } + if (usernames.size() <= 1) { + return promise.set_value(Unit()); + } + td_->create_handler(std::move(promise))->send(std::move(usernames)); +} + +void UserManager::on_update_username_is_active(UserId user_id, string &&username, bool is_active, + Promise &&promise) { + User *u = get_user(user_id); + CHECK(u != nullptr); + if (!u->usernames.can_toggle(username)) { + return reload_user(user_id, std::move(promise), "on_update_username_is_active"); + } + on_update_user_usernames(u, user_id, u->usernames.toggle(username, is_active)); + update_user(u, user_id); + promise.set_value(Unit()); +} + +void UserManager::on_update_active_usernames_order(UserId user_id, vector &&usernames, + Promise &&promise) { + User *u = get_user(user_id); + CHECK(u != nullptr); + if (!u->usernames.can_reorder_to(usernames)) { + return reload_user(user_id, std::move(promise), "on_update_active_usernames_order"); + } + on_update_user_usernames(u, user_id, u->usernames.reorder_to(std::move(usernames))); + update_user(u, user_id); + promise.set_value(Unit()); +} + +void UserManager::toggle_bot_username_is_active(UserId bot_user_id, string &&username, bool is_active, + Promise &&promise) { + TRY_RESULT_PROMISE(promise, bot_data, get_bot_data(bot_user_id)); + if (!bot_data.can_be_edited) { + return promise.set_error(Status::Error(400, "The bot can't be edited")); + } + const User *u = get_user(bot_user_id); + CHECK(u != nullptr); + if (!u->usernames.can_toggle(username)) { + return promise.set_error(Status::Error(400, "Wrong username specified")); + } + td_->create_handler(std::move(promise))->send(bot_user_id, std::move(username), is_active); +} + +void UserManager::reorder_bot_usernames(UserId bot_user_id, vector &&usernames, Promise &&promise) { + TRY_RESULT_PROMISE(promise, bot_data, get_bot_data(bot_user_id)); + if (!bot_data.can_be_edited) { + return promise.set_error(Status::Error(400, "The bot can't be edited")); + } + const User *u = get_user(bot_user_id); + CHECK(u != nullptr); + if (!u->usernames.can_reorder_to(usernames)) { + return promise.set_error(Status::Error(400, "Invalid username order specified")); + } + if (usernames.size() <= 1) { + return promise.set_value(Unit()); + } + td_->create_handler(std::move(promise))->send(bot_user_id, std::move(usernames)); +} + +void UserManager::set_accent_color(AccentColorId accent_color_id, CustomEmojiId background_custom_emoji_id, + Promise &&promise) { + if (!accent_color_id.is_valid()) { + return promise.set_error(Status::Error(400, "Invalid accent color identifier specified")); + } + if (accent_color_id == AccentColorId(get_my_id())) { + accent_color_id = AccentColorId(); + } + + td_->create_handler(std::move(promise))->send(false, accent_color_id, background_custom_emoji_id); +} + +void UserManager::set_profile_accent_color(AccentColorId accent_color_id, CustomEmojiId background_custom_emoji_id, + Promise &&promise) { + td_->create_handler(std::move(promise))->send(true, accent_color_id, background_custom_emoji_id); +} + +void UserManager::on_update_accent_color_success(bool for_profile, AccentColorId accent_color_id, + CustomEmojiId background_custom_emoji_id) { + auto user_id = get_my_id(); + User *u = get_user_force(user_id, "on_update_accent_color_success"); + if (u == nullptr) { + return; + } + if (for_profile) { + on_update_user_profile_accent_color_id(u, user_id, accent_color_id); + on_update_user_profile_background_custom_emoji_id(u, user_id, background_custom_emoji_id); + } else { + on_update_user_accent_color_id(u, user_id, accent_color_id); + on_update_user_background_custom_emoji_id(u, user_id, background_custom_emoji_id); + } + update_user(u, user_id); +} + +void UserManager::set_birthdate(Birthdate &&birthdate, Promise &&promise) { + dismiss_suggested_action(SuggestedAction{SuggestedAction::Type::BirthdaySetup}, Promise()); + auto query_promise = PromiseCreator::lambda( + [actor_id = actor_id(this), birthdate, promise = std::move(promise)](Result result) mutable { + if (result.is_ok()) { + send_closure(actor_id, &UserManager::on_set_birthdate, birthdate, std::move(promise)); + } else { + promise.set_error(result.move_as_error()); + } + }); + td_->create_handler(std::move(query_promise))->send(birthdate); +} + +void UserManager::on_set_birthdate(Birthdate birthdate, Promise &&promise) { + auto my_user_id = get_my_id(); + UserFull *user_full = get_user_full_force(my_user_id, "on_set_birthdate"); + if (user_full != nullptr && user_full->birthdate != birthdate) { + user_full->birthdate = std::move(birthdate); + user_full->is_changed = true; + update_user_full(user_full, my_user_id, "on_set_birthdate"); + } + promise.set_value(Unit()); +} + +void UserManager::set_personal_channel(DialogId dialog_id, Promise &&promise) { + ChannelId channel_id; + if (dialog_id != DialogId() && !td_->dialog_manager_->have_dialog_force(dialog_id, "set_personal_channel")) { + return promise.set_error(Status::Error(400, "Chat not found")); + } + if (dialog_id != DialogId() && dialog_id.get_type() != DialogType::Channel) { + return promise.set_error(Status::Error(400, "Chat can't be set as a personal chat")); + } + auto query_promise = PromiseCreator::lambda( + [actor_id = actor_id(this), channel_id, promise = std::move(promise)](Result result) mutable { + if (result.is_ok()) { + send_closure(actor_id, &UserManager::on_set_personal_channel, channel_id, std::move(promise)); + } else { + promise.set_error(result.move_as_error()); + } + }); + td_->create_handler(std::move(query_promise))->send(channel_id); +} + +void UserManager::on_set_personal_channel(ChannelId channel_id, Promise &&promise) { + auto my_user_id = get_my_id(); + UserFull *user_full = get_user_full_force(my_user_id, "on_set_personal_channel"); + if (user_full != nullptr && user_full->personal_channel_id != channel_id) { + user_full->personal_channel_id = channel_id; + user_full->is_changed = true; + update_user_full(user_full, my_user_id, "on_set_personal_channel"); + } + promise.set_value(Unit()); +} + +void UserManager::set_emoji_status(const EmojiStatus &emoji_status, Promise &&promise) { + if (!td_->option_manager_->get_option_boolean("is_premium")) { + return promise.set_error(Status::Error(400, "The method is available only to Telegram Premium users")); + } + add_recent_emoji_status(td_, emoji_status); + auto query_promise = PromiseCreator::lambda( + [actor_id = actor_id(this), emoji_status, promise = std::move(promise)](Result result) mutable { + if (result.is_ok()) { + send_closure(actor_id, &UserManager::on_set_emoji_status, emoji_status, std::move(promise)); + } else { + promise.set_error(result.move_as_error()); + } + }); + td_->create_handler(std::move(query_promise))->send(emoji_status); +} + +void UserManager::on_set_emoji_status(EmojiStatus emoji_status, Promise &&promise) { + auto user_id = get_my_id(); + User *u = get_user(user_id); + if (u != nullptr) { + on_update_user_emoji_status(u, user_id, emoji_status); + update_user(u, user_id); + } + promise.set_value(Unit()); +} + +void UserManager::get_support_user(Promise> &&promise) { + if (support_user_id_.is_valid()) { + return promise.set_value(get_user_object(support_user_id_)); + } + + auto query_promise = PromiseCreator::lambda( + [actor_id = actor_id(this), promise = std::move(promise)](Result &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &UserManager::on_get_support_user, result.move_as_ok(), std::move(promise)); + } + }); + td_->create_handler(std::move(query_promise))->send(); +} + +void UserManager::on_get_support_user(UserId user_id, Promise> &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + + const User *u = get_user(user_id); + if (u == nullptr) { + return promise.set_error(Status::Error(500, "Can't find support user")); + } + if (!u->is_support) { + LOG(ERROR) << "Receive non-support " << user_id << ", but expected a support user"; + } + + support_user_id_ = user_id; + promise.set_value(get_user_object(user_id, u)); +} + +void UserManager::get_user_profile_photos(UserId user_id, int32 offset, int32 limit, + Promise> &&promise) { + if (offset < 0) { + return promise.set_error(Status::Error(400, "Parameter offset must be non-negative")); + } + if (limit <= 0) { + return promise.set_error(Status::Error(400, "Parameter limit must be positive")); + } + if (limit > MAX_GET_PROFILE_PHOTOS) { + limit = MAX_GET_PROFILE_PHOTOS; + } + + TRY_STATUS_PROMISE(promise, get_input_user(user_id)); + + auto *u = get_user(user_id); + if (u == nullptr) { + return promise.set_error(Status::Error(400, "User not found")); + } + + apply_pending_user_photo(u, user_id); + + auto user_photos = add_user_photos(user_id); + if (user_photos->count != -1) { // know photo count + CHECK(user_photos->offset != -1); + LOG(INFO) << "Have " << user_photos->count << " cached user profile photos at offset " << user_photos->offset; + vector> photo_objects; + + if (offset >= user_photos->count) { + // offset if too big + return promise.set_value(td_api::make_object(user_photos->count, std::move(photo_objects))); + } + + if (limit > user_photos->count - offset) { + limit = user_photos->count - offset; + } + + int32 cache_begin = user_photos->offset; + int32 cache_end = cache_begin + narrow_cast(user_photos->photos.size()); + if (cache_begin <= offset && offset + limit <= cache_end) { + // answer query from cache + for (int i = 0; i < limit; i++) { + photo_objects.push_back( + get_chat_photo_object(td_->file_manager_.get(), user_photos->photos[i + offset - cache_begin])); + } + return promise.set_value(td_api::make_object(user_photos->count, std::move(photo_objects))); + } + } + + PendingGetPhotoRequest pending_request; + pending_request.offset = offset; + pending_request.limit = limit; + pending_request.promise = std::move(promise); + user_photos->pending_requests.push_back(std::move(pending_request)); + if (user_photos->pending_requests.size() != 1u) { + return; + } + + send_get_user_photos_query(user_id, user_photos); +} + +void UserManager::send_get_user_photos_query(UserId user_id, const UserPhotos *user_photos) { + CHECK(!user_photos->pending_requests.empty()); + auto offset = user_photos->pending_requests[0].offset; + auto limit = user_photos->pending_requests[0].limit; + + if (user_photos->count != -1 && offset >= user_photos->offset) { + int32 cache_end = user_photos->offset + narrow_cast(user_photos->photos.size()); + if (offset < cache_end) { + // adjust offset to the end of cache + CHECK(offset + limit > cache_end); // otherwise the request has already been answered + limit = offset + limit - cache_end; + offset = cache_end; + } + } + + auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), user_id](Result &&result) { + send_closure(actor_id, &UserManager::on_get_user_profile_photos, user_id, std::move(result)); + }); + + td_->create_handler(std::move(query_promise)) + ->send(user_id, get_input_user_force(user_id), offset, max(limit, MAX_GET_PROFILE_PHOTOS / 5), 0); +} + +void UserManager::on_get_user_profile_photos(UserId user_id, Result &&result) { + G()->ignore_result_if_closing(result); + auto user_photos = add_user_photos(user_id); + auto pending_requests = std::move(user_photos->pending_requests); + CHECK(!pending_requests.empty()); + if (result.is_error()) { + for (auto &request : pending_requests) { + request.promise.set_error(result.error().clone()); + } + return; + } + if (user_photos->count == -1) { + CHECK(have_user(user_id)); + // received result has just been dropped; resend request + if (++pending_requests[0].retry_count >= 3) { + pending_requests[0].promise.set_error(Status::Error(500, "Failed to return profile photos")); + pending_requests.erase(pending_requests.begin()); + if (pending_requests.empty()) { + return; + } + } + user_photos->pending_requests = std::move(pending_requests); + return send_get_user_photos_query(user_id, user_photos); + } + + CHECK(user_photos->offset != -1); + LOG(INFO) << "Have " << user_photos->count << " cached user profile photos at offset " << user_photos->offset; + vector left_requests; + for (size_t request_index = 0; request_index < pending_requests.size(); request_index++) { + auto &request = pending_requests[request_index]; + vector> photo_objects; + + if (request.offset >= user_photos->count) { + // offset if too big + request.promise.set_value(td_api::make_object(user_photos->count, std::move(photo_objects))); + continue; + } + + if (request.limit > user_photos->count - request.offset) { + request.limit = user_photos->count - request.offset; + } + + int32 cache_begin = user_photos->offset; + int32 cache_end = cache_begin + narrow_cast(user_photos->photos.size()); + if (cache_begin <= request.offset && request.offset + request.limit <= cache_end) { + // answer query from cache + for (int i = 0; i < request.limit; i++) { + photo_objects.push_back( + get_chat_photo_object(td_->file_manager_.get(), user_photos->photos[i + request.offset - cache_begin])); + } + request.promise.set_value(td_api::make_object(user_photos->count, std::move(photo_objects))); + continue; + } + + if (request_index == 0 && ++request.retry_count >= 3) { + request.promise.set_error(Status::Error(500, "Failed to get profile photos")); + continue; + } + + left_requests.push_back(std::move(request)); + } + + if (!left_requests.empty()) { + bool need_send = user_photos->pending_requests.empty(); + append(user_photos->pending_requests, std::move(left_requests)); + if (need_send) { + send_get_user_photos_query(user_id, user_photos); + } + } +} + +void UserManager::reload_user_profile_photo(UserId user_id, int64 photo_id, Promise &&promise) { + get_user_force(user_id, "reload_user_profile_photo"); + TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); + + // this request will be needed only to download the photo, + // so there is no reason to combine different requests for a photo into one request + td_->create_handler(std::move(promise))->send(user_id, std::move(input_user), -1, 1, photo_id); +} + +FileSourceId UserManager::get_user_profile_photo_file_source_id(UserId user_id, int64 photo_id) { + if (!user_id.is_valid()) { + return FileSourceId(); + } + + auto u = get_user(user_id); + if (u != nullptr && u->photo_ids.count(photo_id) != 0) { + VLOG(file_references) << "Don't need to create file source for photo " << photo_id << " of " << user_id; + // photo was already added, source ID was registered and shouldn't be needed + return FileSourceId(); + } + + auto &source_id = user_profile_photo_file_source_ids_[std::make_pair(user_id, photo_id)]; + if (!source_id.is_valid()) { + source_id = td_->file_reference_manager_->create_user_photo_file_source(user_id, photo_id); + } + VLOG(file_references) << "Return " << source_id << " for photo " << photo_id << " of " << user_id; + return source_id; +} + +UserManager::UserPhotos *UserManager::add_user_photos(UserId user_id) { + CHECK(user_id.is_valid()); + auto &user_photos_ptr = user_photos_[user_id]; + if (user_photos_ptr == nullptr) { + user_photos_ptr = make_unique(); + } + return user_photos_ptr.get(); +} + +void UserManager::on_get_user_photos(UserId user_id, int32 offset, int32 limit, int32 total_count, + vector> photos) { + auto photo_count = narrow_cast(photos.size()); + int32 min_total_count = (offset >= 0 && photo_count > 0 ? offset : 0) + photo_count; + if (total_count < min_total_count) { + LOG(ERROR) << "Receive wrong photos total_count " << total_count << " for user " << user_id << ": receive " + << photo_count << " photos with offset " << offset; + total_count = min_total_count; + } + LOG_IF(ERROR, limit < photo_count) << "Requested not more than " << limit << " photos, but " << photo_count + << " received"; + + User *u = get_user(user_id); + if (u == nullptr) { + LOG(ERROR) << "Can't find " << user_id; + return; + } + + if (offset == -1) { + // from reload_user_profile_photo + CHECK(limit == 1); + for (auto &photo_ptr : photos) { + if (photo_ptr->get_id() == telegram_api::photo::ID) { + auto server_photo = telegram_api::move_object_as(photo_ptr); + if (server_photo->id_ == u->photo.id) { + auto profile_photo = convert_photo_to_profile_photo(server_photo, u->photo.is_personal); + if (profile_photo) { + LOG_IF(ERROR, u->access_hash == -1) << "Receive profile photo of " << user_id << " without access hash"; + get_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, std::move(profile_photo)); + } else { + LOG(ERROR) << "Failed to get profile photo from " << to_string(server_photo); + } + } + + auto photo = get_photo(td_, std::move(server_photo), DialogId(user_id)); + register_user_photo(u, user_id, photo); + } + } + return; + } + + LOG(INFO) << "Receive " << photo_count << " photos of " << user_id << " out of " << total_count << " with offset " + << offset << " and limit " << limit; + UserPhotos *user_photos = add_user_photos(user_id); + user_photos->count = total_count; + CHECK(!user_photos->pending_requests.empty()); + + if (user_photos->offset == -1) { + user_photos->offset = 0; + CHECK(user_photos->photos.empty()); + } + + if (offset != narrow_cast(user_photos->photos.size()) + user_photos->offset) { + LOG(INFO) << "Inappropriate offset to append " << user_id << " profile photos to cache: offset = " << offset + << ", current_offset = " << user_photos->offset << ", photo_count = " << user_photos->photos.size(); + user_photos->photos.clear(); + user_photos->offset = offset; + } + + for (auto &photo : photos) { + auto user_photo = get_photo(td_, std::move(photo), DialogId(user_id)); + if (user_photo.is_empty()) { + LOG(ERROR) << "Receive empty profile photo in getUserPhotos request for " << user_id << " with offset " << offset + << " and limit " << limit << ". Receive " << photo_count << " photos out of " << total_count + << " photos"; + user_photos->count--; + CHECK(user_photos->count >= 0); + continue; + } + + user_photos->photos.push_back(std::move(user_photo)); + register_user_photo(u, user_id, user_photos->photos.back()); + } + if (user_photos->offset > user_photos->count) { + user_photos->offset = user_photos->count; + user_photos->photos.clear(); + } + + auto known_photo_count = narrow_cast(user_photos->photos.size()); + if (user_photos->offset + known_photo_count > user_photos->count) { + user_photos->photos.resize(user_photos->count - user_photos->offset); + } +} + +void UserManager::apply_pending_user_photo(User *u, UserId user_id) { + if (u == nullptr || u->is_photo_inited) { + return; + } + + if (pending_user_photos_.count(user_id) > 0) { + do_update_user_photo(u, user_id, std::move(pending_user_photos_[user_id]), "apply_pending_user_photo"); + pending_user_photos_.erase(user_id); + update_user(u, user_id); + } +} + +void UserManager::register_message_users(MessageFullId message_full_id, vector user_ids) { + auto dialog_id = message_full_id.get_dialog_id(); + CHECK(dialog_id.get_type() == DialogType::Channel); + if (!td_->contacts_manager_->have_channel(dialog_id.get_channel_id())) { + return; + } + for (auto user_id : user_ids) { + CHECK(user_id.is_valid()); + const User *u = get_user(user_id); + if (u == nullptr || u->access_hash == -1 || u->is_min_access_hash) { + auto &user_messages = user_messages_[user_id]; + auto need_update = user_messages.empty(); + user_messages.insert(message_full_id); + if (need_update) { + send_closure(G()->td(), &Td::send_update, get_update_user_object(user_id, u)); + } + } + } +} + +void UserManager::unregister_message_users(MessageFullId message_full_id, vector user_ids) { + if (user_messages_.empty()) { + // fast path + return; + } + for (auto user_id : user_ids) { + auto it = user_messages_.find(user_id); + if (it != user_messages_.end()) { + it->second.erase(message_full_id); + if (it->second.empty()) { + user_messages_.erase(it); + + const User *u = get_user(user_id); + if (u == nullptr || u->access_hash == -1 || u->is_min_access_hash) { + send_closure(G()->td(), &Td::send_update, get_update_user_object(user_id, u)); + } + } + } + } +} + +void UserManager::can_send_message_to_user(UserId user_id, bool force, + Promise> &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + if (user_id == get_my_id()) { + return promise.set_value(td_api::make_object()); + } + const auto *u = get_user(user_id); + if (!have_input_peer_user(u, user_id, AccessRights::Write)) { + return promise.set_value(td_api::make_object()); + } + CHECK(user_id.is_valid()); + if ((u != nullptr && (!u->contact_require_premium || u->is_mutual_contact)) || + td_->option_manager_->get_option_boolean("is_premium")) { + return promise.set_value(td_api::make_object()); + } + + auto user_full = get_user_full_force(user_id, "can_send_message_to_user"); + if (user_full != nullptr) { + if (!user_full->contact_require_premium) { + return promise.set_value(td_api::make_object()); + } + return promise.set_value(td_api::make_object()); + } + + auto it = user_full_contact_require_premium_.find(user_id); + if (it != user_full_contact_require_premium_.end()) { + if (!it->second) { + return promise.set_value(td_api::make_object()); + } + return promise.set_value(td_api::make_object()); + } + + if (force) { + return promise.set_value(td_api::make_object()); + } + + auto query_promise = PromiseCreator::lambda( + [actor_id = actor_id(this), user_id, promise = std::move(promise)](Result &&result) mutable { + if (result.is_error()) { + return promise.set_error(result.move_as_error()); + } + send_closure(actor_id, &UserManager::can_send_message_to_user, user_id, true, std::move(promise)); + }); + get_is_premium_required_to_contact_queries_.add_query(user_id.get(), std::move(query_promise), + "can_send_message_to_user"); +} + +void UserManager::on_get_is_premium_required_to_contact_users(vector &&user_ids, + vector &&is_premium_required, + Promise &&promise) { + if (user_ids.size() != is_premium_required.size()) { + LOG(ERROR) << "Receive " << is_premium_required.size() << " flags instead of " << user_ids.size(); + return promise.set_error(Status::Error(500, "Receive invalid response")); + } + for (size_t i = 0; i < user_ids.size(); i++) { + auto user_id = user_ids[i]; + CHECK(user_id.is_valid()); + if (get_user_full(user_id) == nullptr) { + user_full_contact_require_premium_[user_id] = is_premium_required[i]; + } + } + promise.set_value(Unit()); +} + +void UserManager::allow_send_message_to_user(UserId user_id) { + if (get_user_full(user_id) == nullptr) { + CHECK(user_id.is_valid()); + user_full_contact_require_premium_[user_id] = true; + } +} + +void UserManager::share_phone_number(UserId user_id, Promise &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + + if (!are_contacts_loaded_) { + load_contacts(PromiseCreator::lambda( + [actor_id = actor_id(this), user_id, promise = std::move(promise)](Result &&) mutable { + send_closure(actor_id, &UserManager::share_phone_number, user_id, std::move(promise)); + })); + return; + } + + LOG(INFO) << "Share phone number with " << user_id; + TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); + + td_->messages_manager_->hide_dialog_action_bar(DialogId(user_id)); + + td_->create_handler(std::move(promise))->send(user_id, std::move(input_user)); +} + +void UserManager::load_contacts(Promise &&promise) { + if (td_->auth_manager_->is_bot()) { + are_contacts_loaded_ = true; + saved_contact_count_ = 0; + } + if (are_contacts_loaded_ && saved_contact_count_ != -1) { + LOG(INFO) << "Contacts are already loaded"; + return promise.set_value(Unit()); + } + load_contacts_queries_.push_back(std::move(promise)); + if (load_contacts_queries_.size() == 1u) { + if (G()->use_chat_info_database() && next_contacts_sync_date_ > 0 && saved_contact_count_ != -1) { + LOG(INFO) << "Load contacts from database"; + G()->td_db()->get_sqlite_pmc()->get( + "user_contacts", PromiseCreator::lambda([](string value) { + send_closure(G()->user_manager(), &UserManager::on_load_contacts_from_database, std::move(value)); + })); + } else { + LOG(INFO) << "Load contacts from server"; + reload_contacts(true); + } + } else { + LOG(INFO) << "Load contacts request has already been sent"; + } +} + +int64 UserManager::get_contacts_hash() { + if (!are_contacts_loaded_) { + return 0; + } + + vector user_ids = contacts_hints_.search_empty(100000).second; + CHECK(std::is_sorted(user_ids.begin(), user_ids.end())); + auto my_id = get_my_id(); + const User *u = get_user_force(my_id, "get_contacts_hash"); + if (u != nullptr && u->is_contact) { + user_ids.insert(std::upper_bound(user_ids.begin(), user_ids.end(), my_id.get()), my_id.get()); + } + + vector numbers; + numbers.reserve(user_ids.size() + 1); + numbers.push_back(saved_contact_count_); + for (auto user_id : user_ids) { + numbers.push_back(user_id); + } + return get_vector_hash(numbers); +} + +void UserManager::reload_contacts(bool force) { + if (!G()->close_flag() && !td_->auth_manager_->is_bot() && + next_contacts_sync_date_ != std::numeric_limits::max() && + (next_contacts_sync_date_ < G()->unix_time() || force)) { + next_contacts_sync_date_ = std::numeric_limits::max(); + td_->create_handler()->send(get_contacts_hash()); + } +} + +void UserManager::save_next_contacts_sync_date() { + if (G()->close_flag()) { + return; + } + if (!G()->use_chat_info_database()) { + return; + } + G()->td_db()->get_binlog_pmc()->set("next_contacts_sync_date", to_string(next_contacts_sync_date_)); +} + +void UserManager::save_contacts_to_database() { + if (!G()->use_chat_info_database() || !are_contacts_loaded_) { + return; + } + + LOG(INFO) << "Schedule save contacts to database"; + vector user_ids = + transform(contacts_hints_.search_empty(100000).second, [](int64 key) { return UserId(key); }); + + G()->td_db()->get_binlog_pmc()->set("saved_contact_count", to_string(saved_contact_count_)); + G()->td_db()->get_binlog()->force_sync( + PromiseCreator::lambda([user_ids = std::move(user_ids)](Result<> result) { + if (result.is_ok()) { + LOG(INFO) << "Saved contacts to database"; + G()->td_db()->get_sqlite_pmc()->set( + "user_contacts", log_event_store(user_ids).as_slice().str(), PromiseCreator::lambda([](Result<> result) { + if (result.is_ok()) { + send_closure(G()->user_manager(), &UserManager::save_next_contacts_sync_date); + } + })); + } + }), + "save_contacts_to_database"); +} + +void UserManager::on_get_contacts(telegram_api::object_ptr &&new_contacts) { + next_contacts_sync_date_ = G()->unix_time() + Random::fast(70000, 100000); + + CHECK(new_contacts != nullptr); + if (new_contacts->get_id() == telegram_api::contacts_contactsNotModified::ID) { + if (saved_contact_count_ == -1) { + saved_contact_count_ = 0; + } + on_get_contacts_finished(contacts_hints_.size()); + td_->create_handler()->send(); + return; + } + + auto contacts = move_tl_object_as(new_contacts); + FlatHashSet contact_user_ids; + for (auto &user : contacts->users_) { + auto user_id = get_user_id(user); + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + continue; + } + contact_user_ids.insert(user_id); + } + on_get_users(std::move(contacts->users_), "on_get_contacts"); + + UserId my_id = get_my_id(); + users_.foreach([&](const UserId &user_id, unique_ptr &user) { + User *u = user.get(); + bool should_be_contact = contact_user_ids.count(user_id) == 1; + if (u->is_contact != should_be_contact) { + if (u->is_contact) { + LOG(INFO) << "Drop contact with " << user_id; + if (user_id != my_id) { + LOG_CHECK(contacts_hints_.has_key(user_id.get())) + << my_id << " " << user_id << " " << to_string(get_user_object(user_id, u)); + } + on_update_user_is_contact(u, user_id, false, false, false); + CHECK(u->is_is_contact_changed); + u->cache_version = 0; + u->is_repaired = false; + update_user(u, user_id); + CHECK(!u->is_contact); + if (user_id != my_id) { + CHECK(!contacts_hints_.has_key(user_id.get())); + } + } else { + LOG(ERROR) << "Receive non-contact " << user_id << " in the list of contacts"; + } + } + }); + + saved_contact_count_ = contacts->saved_count_; + on_get_contacts_finished(std::numeric_limits::max()); +} + +void UserManager::on_get_contacts_failed(Status error) { + CHECK(error.is_error()); + next_contacts_sync_date_ = G()->unix_time() + Random::fast(5, 10); + fail_promises(load_contacts_queries_, std::move(error)); +} + +void UserManager::on_load_contacts_from_database(string value) { + if (G()->close_flag()) { + return; + } + if (value.empty()) { + reload_contacts(true); + return; + } + + vector user_ids; + if (log_event_parse(user_ids, value).is_error()) { + LOG(ERROR) << "Failed to load contacts from database"; + reload_contacts(true); + return; + } + + if (log_event_get_version(value) < static_cast(Version::AddUserFlags2)) { + next_contacts_sync_date_ = 0; + save_next_contacts_sync_date(); + reload_contacts(true); + } + + LOG(INFO) << "Successfully loaded " << user_ids.size() << " contacts from database"; + + load_contact_users_multipromise_.add_promise(PromiseCreator::lambda( + [actor_id = actor_id(this), expected_contact_count = user_ids.size()](Result result) { + if (result.is_ok()) { + send_closure(actor_id, &UserManager::on_get_contacts_finished, expected_contact_count); + } else { + LOG(INFO) << "Failed to load contact users from database: " << result.error(); + send_closure(actor_id, &UserManager::reload_contacts, true); + } + })); + + auto lock_promise = load_contact_users_multipromise_.get_promise(); + + for (auto user_id : user_ids) { + get_user(user_id, 3, load_contact_users_multipromise_.get_promise()); + } + + lock_promise.set_value(Unit()); +} + +void UserManager::on_get_contacts_finished(size_t expected_contact_count) { + LOG(INFO) << "Finished to get " << contacts_hints_.size() << " contacts out of expected " << expected_contact_count; + are_contacts_loaded_ = true; + set_promises(load_contacts_queries_); + if (expected_contact_count != contacts_hints_.size()) { + save_contacts_to_database(); + } +} + +void UserManager::on_get_contacts_statuses(vector> &&statuses) { + auto my_user_id = get_my_id(); + for (auto &status : statuses) { + UserId user_id(status->user_id_); + if (user_id != my_user_id) { + on_update_user_online(user_id, std::move(status->status_)); + } + } + save_next_contacts_sync_date(); +} + +void UserManager::add_contact(Contact contact, bool share_phone_number, Promise &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + + if (!are_contacts_loaded_) { + load_contacts(PromiseCreator::lambda([actor_id = actor_id(this), contact = std::move(contact), share_phone_number, + promise = std::move(promise)](Result &&) mutable { + send_closure(actor_id, &UserManager::add_contact, std::move(contact), share_phone_number, std::move(promise)); + })); + return; + } + + LOG(INFO) << "Add " << contact << " with share_phone_number = " << share_phone_number; + + auto user_id = contact.get_user_id(); + TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); + + td_->create_handler(std::move(promise)) + ->send(user_id, std::move(input_user), contact, share_phone_number); +} + +std::pair, vector> UserManager::import_contacts(const vector &contacts, int64 &random_id, + Promise &&promise) { + if (!are_contacts_loaded_) { + load_contacts(std::move(promise)); + return {}; + } + + LOG(INFO) << "Asked to import " << contacts.size() << " contacts with random_id = " << random_id; + if (random_id != 0) { + // request has already been sent before + auto it = imported_contacts_.find(random_id); + CHECK(it != imported_contacts_.end()); + auto result = std::move(it->second); + imported_contacts_.erase(it); + + promise.set_value(Unit()); + return result; + } + + do { + random_id = Random::secure_int64(); + } while (random_id == 0 || random_id == 1 || imported_contacts_.count(random_id) > 0); + imported_contacts_[random_id]; // reserve place for result + + do_import_contacts(contacts, random_id, std::move(promise)); + return {}; +} + +void UserManager::do_import_contacts(vector contacts, int64 random_id, Promise &&promise) { + size_t size = contacts.size(); + if (size == 0) { + on_import_contacts_finished(random_id, {}, {}); + return promise.set_value(Unit()); + } + + vector> input_phone_contacts; + input_phone_contacts.reserve(size); + for (size_t i = 0; i < size; i++) { + input_phone_contacts.push_back(contacts[i].get_input_phone_contact(static_cast(i))); + } + + auto task = make_unique(); + task->promise_ = std::move(promise); + task->input_contacts_ = std::move(contacts); + task->imported_user_ids_.resize(size); + task->unimported_contact_invites_.resize(size); + + bool is_added = import_contact_tasks_.emplace(random_id, std::move(task)).second; + CHECK(is_added); + + td_->create_handler()->send(std::move(input_phone_contacts), random_id); +} + +void UserManager::on_imported_contacts( + int64 random_id, Result> result) { + auto it = import_contact_tasks_.find(random_id); + CHECK(it != import_contact_tasks_.end()); + CHECK(it->second != nullptr); + + auto task = it->second.get(); + if (result.is_error()) { + auto promise = std::move(task->promise_); + import_contact_tasks_.erase(it); + return promise.set_error(result.move_as_error()); + } + + auto imported_contacts = result.move_as_ok(); + on_get_users(std::move(imported_contacts->users_), "on_imported_contacts"); + + for (auto &imported_contact : imported_contacts->imported_) { + int64 client_id = imported_contact->client_id_; + if (client_id < 0 || client_id >= static_cast(task->imported_user_ids_.size())) { + LOG(ERROR) << "Wrong client_id " << client_id << " returned"; + continue; + } + + task->imported_user_ids_[static_cast(client_id)] = UserId(imported_contact->user_id_); + } + for (auto &popular_contact : imported_contacts->popular_invites_) { + int64 client_id = popular_contact->client_id_; + if (client_id < 0 || client_id >= static_cast(task->unimported_contact_invites_.size())) { + LOG(ERROR) << "Wrong client_id " << client_id << " returned"; + continue; + } + if (popular_contact->importers_ < 0) { + LOG(ERROR) << "Wrong number of importers " << popular_contact->importers_ << " returned"; + continue; + } + + task->unimported_contact_invites_[static_cast(client_id)] = popular_contact->importers_; + } + + if (!imported_contacts->retry_contacts_.empty()) { + auto total_size = static_cast(task->input_contacts_.size()); + vector> input_phone_contacts; + input_phone_contacts.reserve(imported_contacts->retry_contacts_.size()); + for (auto &client_id : imported_contacts->retry_contacts_) { + if (client_id < 0 || client_id >= total_size) { + LOG(ERROR) << "Wrong client_id " << client_id << " returned"; + continue; + } + auto i = static_cast(client_id); + input_phone_contacts.push_back(task->input_contacts_[i].get_input_phone_contact(client_id)); + } + td_->create_handler()->send(std::move(input_phone_contacts), random_id); + return; + } + + auto promise = std::move(task->promise_); + on_import_contacts_finished(random_id, std::move(task->imported_user_ids_), + std::move(task->unimported_contact_invites_)); + import_contact_tasks_.erase(it); + promise.set_value(Unit()); +} + +void UserManager::on_import_contacts_finished(int64 random_id, vector imported_contact_user_ids, + vector unimported_contact_invites) { + LOG(INFO) << "Contacts import with random_id " << random_id + << " has finished: " << format::as_array(imported_contact_user_ids); + if (random_id == 1) { + // import from change_imported_contacts + all_imported_contacts_ = std::move(next_all_imported_contacts_); + next_all_imported_contacts_.clear(); + + auto result_size = imported_contacts_unique_id_.size(); + auto unique_size = all_imported_contacts_.size(); + auto add_size = imported_contacts_pos_.size(); + + imported_contact_user_ids_.resize(result_size); + unimported_contact_invites_.resize(result_size); + + CHECK(imported_contact_user_ids.size() == add_size); + CHECK(unimported_contact_invites.size() == add_size); + CHECK(imported_contacts_unique_id_.size() == result_size); + + std::unordered_map> unique_id_to_unimported_contact_invites; + for (size_t i = 0; i < add_size; i++) { + auto unique_id = imported_contacts_pos_[i]; + get_user_id_object(imported_contact_user_ids[i], "on_import_contacts_finished"); // to ensure updateUser + all_imported_contacts_[unique_id].set_user_id(imported_contact_user_ids[i]); + unique_id_to_unimported_contact_invites[narrow_cast(unique_id)] = unimported_contact_invites[i]; + } + + if (G()->use_chat_info_database()) { + G()->td_db()->get_binlog()->force_sync( + PromiseCreator::lambda( + [log_event = log_event_store(all_imported_contacts_).as_slice().str()](Result<> result) mutable { + if (result.is_ok()) { + LOG(INFO) << "Save imported contacts to database"; + G()->td_db()->get_sqlite_pmc()->set("user_imported_contacts", std::move(log_event), Auto()); + } + }), + "on_import_contacts_finished"); + } + + for (size_t i = 0; i < result_size; i++) { + auto unique_id = imported_contacts_unique_id_[i]; + CHECK(unique_id < unique_size); + imported_contact_user_ids_[i] = all_imported_contacts_[unique_id].get_user_id(); + auto it = unique_id_to_unimported_contact_invites.find(narrow_cast(unique_id)); + if (it == unique_id_to_unimported_contact_invites.end()) { + unimported_contact_invites_[i] = 0; + } else { + unimported_contact_invites_[i] = it->second; + } + } + return; + } + + auto it = imported_contacts_.find(random_id); + CHECK(it != imported_contacts_.end()); + CHECK(it->second.first.empty()); + CHECK(it->second.second.empty()); + imported_contacts_[random_id] = {std::move(imported_contact_user_ids), std::move(unimported_contact_invites)}; +} + +void UserManager::remove_contacts(const vector &user_ids, Promise &&promise) { + LOG(INFO) << "Delete contacts: " << format::as_array(user_ids); + if (!are_contacts_loaded_) { + load_contacts(std::move(promise)); + return; + } + + vector to_delete_user_ids; + vector> input_users; + for (auto &user_id : user_ids) { + const User *u = get_user(user_id); + if (u != nullptr && u->is_contact) { + auto r_input_user = get_input_user(user_id); + if (r_input_user.is_ok()) { + to_delete_user_ids.push_back(user_id); + input_users.push_back(r_input_user.move_as_ok()); + } + } + } + + if (input_users.empty()) { + return promise.set_value(Unit()); + } + + td_->create_handler(std::move(promise))->send(std::move(input_users)); +} + +void UserManager::remove_contacts_by_phone_number(vector user_phone_numbers, vector user_ids, + Promise &&promise) { + LOG(INFO) << "Delete contacts by phone number: " << format::as_array(user_phone_numbers); + if (!are_contacts_loaded_) { + load_contacts(std::move(promise)); + return; + } + + td_->create_handler(std::move(promise)) + ->send(std::move(user_phone_numbers), std::move(user_ids)); +} + +void UserManager::on_deleted_contacts(const vector &deleted_contact_user_ids) { + LOG(INFO) << "Contacts deletion has finished for " << deleted_contact_user_ids; + + for (auto user_id : deleted_contact_user_ids) { + auto u = get_user(user_id); + CHECK(u != nullptr); + if (!u->is_contact) { + continue; + } + + LOG(INFO) << "Drop contact with " << user_id; + on_update_user_is_contact(u, user_id, false, false, false); + CHECK(u->is_is_contact_changed); + u->cache_version = 0; + u->is_repaired = false; + update_user(u, user_id); + CHECK(!u->is_contact); + CHECK(!contacts_hints_.has_key(user_id.get())); + } +} + +int32 UserManager::get_imported_contact_count(Promise &&promise) { + LOG(INFO) << "Get imported contact count"; + + if (!are_contacts_loaded_ || saved_contact_count_ == -1) { + load_contacts(std::move(promise)); + return 0; + } + reload_contacts(false); + + promise.set_value(Unit()); + return saved_contact_count_; +} + +void UserManager::load_imported_contacts(Promise &&promise) { + if (td_->auth_manager_->is_bot()) { + are_imported_contacts_loaded_ = true; + } + if (are_imported_contacts_loaded_) { + LOG(INFO) << "Imported contacts are already loaded"; + promise.set_value(Unit()); + return; + } + load_imported_contacts_queries_.push_back(std::move(promise)); + if (load_imported_contacts_queries_.size() == 1u) { + if (G()->use_chat_info_database()) { + LOG(INFO) << "Load imported contacts from database"; + G()->td_db()->get_sqlite_pmc()->get("user_imported_contacts", PromiseCreator::lambda([](string value) { + send_closure_later(G()->user_manager(), + &UserManager::on_load_imported_contacts_from_database, + std::move(value)); + })); + } else { + LOG(INFO) << "Have no previously imported contacts"; + send_closure_later(G()->user_manager(), &UserManager::on_load_imported_contacts_from_database, string()); + } + } else { + LOG(INFO) << "Load imported contacts request has already been sent"; + } +} + +void UserManager::on_load_imported_contacts_from_database(string value) { + if (G()->close_flag()) { + return; + } + + CHECK(!are_imported_contacts_loaded_); + if (need_clear_imported_contacts_) { + need_clear_imported_contacts_ = false; + value.clear(); + } + if (value.empty()) { + CHECK(all_imported_contacts_.empty()); + } else { + if (log_event_parse(all_imported_contacts_, value).is_error()) { + LOG(ERROR) << "Failed to load all imported contacts from database"; + all_imported_contacts_.clear(); + } else { + LOG(INFO) << "Successfully loaded " << all_imported_contacts_.size() << " imported contacts from database"; + } + } + + load_imported_contact_users_multipromise_.add_promise( + PromiseCreator::lambda([actor_id = actor_id(this)](Result result) { + if (result.is_ok()) { + send_closure_later(actor_id, &UserManager::on_load_imported_contacts_finished); + } + })); + + auto lock_promise = load_imported_contact_users_multipromise_.get_promise(); + + for (const auto &contact : all_imported_contacts_) { + auto user_id = contact.get_user_id(); + if (user_id.is_valid()) { + get_user(user_id, 3, load_imported_contact_users_multipromise_.get_promise()); + } + } + + lock_promise.set_value(Unit()); +} + +void UserManager::on_load_imported_contacts_finished() { + LOG(INFO) << "Finished to load " << all_imported_contacts_.size() << " imported contacts"; + + for (const auto &contact : all_imported_contacts_) { + get_user_id_object(contact.get_user_id(), "on_load_imported_contacts_finished"); // to ensure updateUser + } + + if (need_clear_imported_contacts_) { + need_clear_imported_contacts_ = false; + all_imported_contacts_.clear(); + } + are_imported_contacts_loaded_ = true; + set_promises(load_imported_contacts_queries_); +} + +std::pair, vector> UserManager::change_imported_contacts(vector &contacts, + int64 &random_id, + Promise &&promise) { + if (!are_contacts_loaded_) { + load_contacts(std::move(promise)); + return {}; + } + if (!are_imported_contacts_loaded_) { + load_imported_contacts(std::move(promise)); + return {}; + } + + LOG(INFO) << "Asked to change imported contacts to a list of " << contacts.size() + << " contacts with random_id = " << random_id; + if (random_id != 0) { + // request has already been sent before + if (need_clear_imported_contacts_) { + need_clear_imported_contacts_ = false; + all_imported_contacts_.clear(); + if (G()->use_chat_info_database()) { + G()->td_db()->get_sqlite_pmc()->erase("user_imported_contacts", Auto()); + } + reload_contacts(true); + } + + CHECK(are_imported_contacts_changing_); + are_imported_contacts_changing_ = false; + + auto unimported_contact_invites = std::move(unimported_contact_invites_); + unimported_contact_invites_.clear(); + + auto imported_contact_user_ids = std::move(imported_contact_user_ids_); + imported_contact_user_ids_.clear(); + + promise.set_value(Unit()); + return {std::move(imported_contact_user_ids), std::move(unimported_contact_invites)}; + } + + if (are_imported_contacts_changing_) { + promise.set_error(Status::Error(400, "ChangeImportedContacts can be called only once at the same time")); + return {}; + } + + vector new_contacts_unique_id(contacts.size()); + vector unique_new_contacts; + unique_new_contacts.reserve(contacts.size()); + std::unordered_map different_new_contacts; + std::unordered_set> different_new_phone_numbers; + size_t unique_size = 0; + for (size_t i = 0; i < contacts.size(); i++) { + auto it_success = different_new_contacts.emplace(std::move(contacts[i]), unique_size); + new_contacts_unique_id[i] = it_success.first->second; + if (it_success.second) { + unique_new_contacts.push_back(it_success.first->first); + different_new_phone_numbers.insert(unique_new_contacts.back().get_phone_number()); + unique_size++; + } + } + + vector to_delete; + vector to_delete_user_ids; + for (auto &old_contact : all_imported_contacts_) { + auto user_id = old_contact.get_user_id(); + auto it = different_new_contacts.find(old_contact); + if (it == different_new_contacts.end()) { + auto phone_number = old_contact.get_phone_number(); + if (different_new_phone_numbers.count(phone_number) == 0) { + to_delete.push_back(std::move(phone_number)); + if (user_id.is_valid()) { + to_delete_user_ids.push_back(user_id); + } + } + } else { + unique_new_contacts[it->second].set_user_id(user_id); + different_new_contacts.erase(it); + } + } + std::pair, vector> to_add; + for (auto &new_contact : different_new_contacts) { + to_add.first.push_back(new_contact.second); + to_add.second.push_back(new_contact.first); + } + + if (to_add.first.empty() && to_delete.empty()) { + for (size_t i = 0; i < contacts.size(); i++) { + auto unique_id = new_contacts_unique_id[i]; + contacts[i].set_user_id(unique_new_contacts[unique_id].get_user_id()); + } + + promise.set_value(Unit()); + return {transform(contacts, [&](const Contact &contact) { return contact.get_user_id(); }), + vector(contacts.size())}; + } + + are_imported_contacts_changing_ = true; + random_id = 1; + + remove_contacts_by_phone_number( + std::move(to_delete), std::move(to_delete_user_ids), + PromiseCreator::lambda([new_contacts = std::move(unique_new_contacts), + new_contacts_unique_id = std::move(new_contacts_unique_id), to_add = std::move(to_add), + promise = std::move(promise)](Result<> result) mutable { + if (result.is_ok()) { + send_closure_later(G()->user_manager(), &UserManager::on_clear_imported_contacts, std::move(new_contacts), + std::move(new_contacts_unique_id), std::move(to_add), std::move(promise)); + } else { + promise.set_error(result.move_as_error()); + } + })); + return {}; +} + +void UserManager::clear_imported_contacts(Promise &&promise) { + LOG(INFO) << "Delete imported contacts"; + + if (saved_contact_count_ == 0) { + promise.set_value(Unit()); + return; + } + + td_->create_handler(std::move(promise))->send(); +} + +void UserManager::on_clear_imported_contacts(vector &&contacts, vector contacts_unique_id, + std::pair, vector> &&to_add, + Promise &&promise) { + LOG(INFO) << "Add " << to_add.first.size() << " contacts"; + next_all_imported_contacts_ = std::move(contacts); + imported_contacts_unique_id_ = std::move(contacts_unique_id); + imported_contacts_pos_ = std::move(to_add.first); + + do_import_contacts(std::move(to_add.second), 1, std::move(promise)); +} + +void UserManager::on_update_contacts_reset() { + /* + UserId my_id = get_my_id(); + users_.foreach([&](const UserId &user_id, unique_ptr &user) { + User *u = user.get(); + if (u->is_contact) { + LOG(INFO) << "Drop contact with " << user_id; + if (user_id != my_id) { + CHECK(contacts_hints_.has_key(user_id.get())); + } + on_update_user_is_contact(u, user_id, false, false, false); + CHECK(u->is_is_contact_changed); + u->cache_version = 0; + u->is_repaired = false; + update_user(u, user_id); + CHECK(!u->is_contact); + if (user_id != my_id) { + CHECK(!contacts_hints_.has_key(user_id.get())); + } + } + }); + */ + + saved_contact_count_ = 0; + if (G()->use_chat_info_database()) { + G()->td_db()->get_binlog_pmc()->set("saved_contact_count", "0"); + G()->td_db()->get_sqlite_pmc()->erase("user_imported_contacts", Auto()); + } + if (!are_imported_contacts_loaded_) { + if (load_imported_contacts_queries_.empty()) { + CHECK(all_imported_contacts_.empty()); + LOG(INFO) << "Imported contacts were never loaded, just clear them"; + } else { + LOG(INFO) << "Imported contacts are being loaded, clear them after they will be loaded"; + need_clear_imported_contacts_ = true; + } + } else { + if (!are_imported_contacts_changing_) { + LOG(INFO) << "Imported contacts were loaded, but aren't changing now, just clear them"; + all_imported_contacts_.clear(); + } else { + LOG(INFO) << "Imported contacts are changing now, clear them after they will be changed"; + need_clear_imported_contacts_ = true; + } + } + reload_contacts(true); +} + +void UserManager::update_contacts_hints(const User *u, UserId user_id, bool from_database) { + bool is_contact = is_user_contact(u, user_id, false); + if (td_->auth_manager_->is_bot()) { + LOG_IF(ERROR, is_contact) << "Bot has " << user_id << " in the contacts list"; + return; + } + + int64 key = user_id.get(); + string old_value = contacts_hints_.key_to_string(key); + string new_value = is_contact ? get_user_search_text(u) : string(); + + if (new_value != old_value) { + if (is_contact) { + contacts_hints_.add(key, new_value); + } else { + contacts_hints_.remove(key); + } + } + + if (G()->use_chat_info_database()) { + // update contacts database + if (!are_contacts_loaded_) { + if (!from_database && load_contacts_queries_.empty() && is_contact && u->is_is_contact_changed) { + search_contacts("", std::numeric_limits::max(), Auto()); + } + } else { + if (old_value.empty() == is_contact) { + save_contacts_to_database(); + } + } + } +} + +std::pair> UserManager::search_contacts(const string &query, int32 limit, + Promise &&promise) { + LOG(INFO) << "Search contacts with query = \"" << query << "\" and limit = " << limit; + + if (limit < 0) { + promise.set_error(Status::Error(400, "Limit must be non-negative")); + return {}; + } + + if (!are_contacts_loaded_) { + load_contacts(std::move(promise)); + return {}; + } + reload_contacts(false); + + std::pair> result; + if (query.empty()) { + result = contacts_hints_.search_empty(limit); + } else { + result = contacts_hints_.search(query, limit); + } + + vector user_ids; + user_ids.reserve(result.second.size()); + for (auto key : result.second) { + user_ids.emplace_back(key); + } + + promise.set_value(Unit()); + return {narrow_cast(result.first), std::move(user_ids)}; +} + +void UserManager::reload_contact_birthdates(bool force) { + if (!G()->close_flag() && !td_->auth_manager_->is_bot() && !contact_birthdates_.is_being_synced_ && + (contact_birthdates_.next_sync_time_ < Time::now() || force)) { + contact_birthdates_.is_being_synced_ = true; + td_->create_handler()->send(); + } +} + +void UserManager::on_get_contact_birthdates( + telegram_api::object_ptr &&birthdays) { + CHECK(contact_birthdates_.is_being_synced_); + contact_birthdates_.is_being_synced_ = false; + if (birthdays == nullptr) { + contact_birthdates_.next_sync_time_ = Time::now() + Random::fast(120, 180); + return; + } + contact_birthdates_.next_sync_time_ = Time::now() + Random::fast(86400 / 4, 86400 / 3); + + on_get_users(std::move(birthdays->users_), "on_get_contact_birthdates"); + vector> users; + for (auto &contact : birthdays->contacts_) { + UserId user_id(contact->contact_id_); + if (is_user_contact(user_id)) { + Birthdate birthdate(std::move(contact->birthday_)); + UserFull *user_full = get_user_full_force(user_id, "on_get_contact_birthdates"); + if (user_full != nullptr && user_full->birthdate != birthdate) { + user_full->birthdate = birthdate; + user_full->is_changed = true; + update_user_full(user_full, user_id, "on_get_contact_birthdates"); + } + if (!birthdate.is_empty()) { + users.emplace_back(user_id, birthdate); + } + } + } + if (contact_birthdates_.users_ != users) { + contact_birthdates_.users_ = std::move(users); + send_closure(G()->td(), &Td::send_update, get_update_contact_close_birthdays()); + } + // there is no need to save them between restarts +} + +vector UserManager::get_close_friends(Promise &&promise) { + if (!are_contacts_loaded_) { + load_contacts(std::move(promise)); + return {}; + } + reload_contacts(false); + + auto result = contacts_hints_.search_empty(10000); + + vector user_ids; + for (auto key : result.second) { + UserId user_id(key); + const User *u = get_user(user_id); + if (u != nullptr && u->is_close_friend) { + user_ids.push_back(user_id); + } + } + + promise.set_value(Unit()); + return user_ids; +} + +void UserManager::set_close_friends(vector user_ids, Promise &&promise) { + for (auto &user_id : user_ids) { + if (!have_user(user_id)) { + return promise.set_error(Status::Error(400, "User not found")); + } + } + + td_->create_handler(std::move(promise))->send(std::move(user_ids)); +} + +void UserManager::on_set_close_friends(const vector &user_ids, Promise &&promise) { + FlatHashSet close_friend_user_ids; + for (auto &user_id : user_ids) { + CHECK(user_id.is_valid()); + close_friend_user_ids.insert(user_id); + } + users_.foreach([&](const UserId &user_id, unique_ptr &user) { + User *u = user.get(); + if (u->is_contact && u->is_close_friend != (close_friend_user_ids.count(user_id) > 0)) { + on_update_user_is_contact(u, user_id, u->is_contact, u->is_mutual_contact, !u->is_close_friend); + update_user(u, user_id); + } + }); + promise.set_value(Unit()); +} + +UserId UserManager::search_user_by_phone_number(string phone_number, Promise &&promise) { + clean_phone_number(phone_number); + if (phone_number.empty()) { + promise.set_error(Status::Error(200, "Phone number is invalid")); + return UserId(); + } + + auto it = resolved_phone_numbers_.find(phone_number); + if (it != resolved_phone_numbers_.end()) { + promise.set_value(Unit()); + return it->second; + } + + td_->create_handler(std::move(promise))->send(phone_number); + return UserId(); +} + +void UserManager::on_resolved_phone_number(const string &phone_number, UserId user_id) { + if (!user_id.is_valid()) { + resolved_phone_numbers_.emplace(phone_number, UserId()); // negative cache + return; + } + + auto it = resolved_phone_numbers_.find(phone_number); + if (it != resolved_phone_numbers_.end()) { + if (it->second != user_id) { + LOG(WARNING) << "Resolve phone number \"" << phone_number << "\" to " << user_id << ", but have it in " + << it->second; + it->second = user_id; + } + return; + } + + auto *u = get_user(user_id); + if (u == nullptr) { + LOG(ERROR) << "Resolve phone number \"" << phone_number << "\" to unknown " << user_id; + } else if (!u->phone_number.empty()) { + LOG(ERROR) << "Resolve phone number \"" << phone_number << "\" to " << user_id << " with phone number " + << u->phone_number; + } else { + // the user's phone number can be hidden by privacy settings, despite the user can be found by the phone number + } + resolved_phone_numbers_[phone_number] = user_id; // always update cached value +} + +const UserManager::UserFull *UserManager::get_user_full(UserId user_id) const { + return users_full_.get_pointer(user_id); +} + +UserManager::UserFull *UserManager::get_user_full(UserId user_id) { + return users_full_.get_pointer(user_id); +} + +UserManager::UserFull *UserManager::add_user_full(UserId user_id) { + CHECK(user_id.is_valid()); + auto &user_full_ptr = users_full_[user_id]; + if (user_full_ptr == nullptr) { + user_full_ptr = make_unique(); + user_full_contact_require_premium_.erase(user_id); + } + return user_full_ptr.get(); +} + +UserManager::UserFull *UserManager::get_user_full_force(UserId user_id, const char *source) { + if (!have_user_force(user_id, source)) { + return nullptr; + } + + UserFull *user_full = get_user_full(user_id); + if (user_full != nullptr) { + return user_full; + } + if (!G()->use_chat_info_database()) { + return nullptr; + } + if (!unavailable_user_fulls_.insert(user_id).second) { + return nullptr; + } + + LOG(INFO) << "Trying to load full " << user_id << " from database from " << source; + on_load_user_full_from_database(user_id, + G()->td_db()->get_sqlite_sync_pmc()->get(get_user_full_database_key(user_id))); + return get_user_full(user_id); +} + +void UserManager::load_user_full(UserId user_id, bool force, Promise &&promise, const char *source) { + auto u = get_user(user_id); + if (u == nullptr) { + return promise.set_error(Status::Error(400, "User not found")); + } + + auto user_full = get_user_full_force(user_id, source); + if (user_full == nullptr) { + TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); + return send_get_user_full_query(user_id, std::move(input_user), std::move(promise), source); + } + if (user_full->is_expired()) { + auto input_user = get_input_user_force(user_id); + if (td_->auth_manager_->is_bot() && !force) { + return send_get_user_full_query(user_id, std::move(input_user), std::move(promise), "load expired user_full"); + } + + send_get_user_full_query(user_id, std::move(input_user), Auto(), "load expired user_full"); + } + + td_->story_manager_->on_view_dialog_active_stories({DialogId(user_id)}); + promise.set_value(Unit()); +} + +void UserManager::reload_user_full(UserId user_id, Promise &&promise, const char *source) { + TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); + send_get_user_full_query(user_id, std::move(input_user), std::move(promise), source); +} + +void UserManager::send_get_user_full_query(UserId user_id, + telegram_api::object_ptr &&input_user, + Promise &&promise, const char *source) { + LOG(INFO) << "Get full " << user_id << " from " << source; + if (!user_id.is_valid()) { + return promise.set_error(Status::Error(500, "Invalid user_id")); + } + auto send_query = + PromiseCreator::lambda([td = td_, input_user = std::move(input_user)](Result> &&promise) mutable { + if (promise.is_ok() && !G()->close_flag()) { + td->create_handler(promise.move_as_ok())->send(std::move(input_user)); + } + }); + get_user_full_queries_.add_query(user_id.get(), std::move(send_query), std::move(promise)); +} + +void UserManager::on_get_user_full(telegram_api::object_ptr &&user) { + LOG(INFO) << "Receive " << to_string(user); + + UserId user_id(user->id_); + User *u = get_user(user_id); + if (u == nullptr) { + LOG(ERROR) << "Failed to find " << user_id; + return; + } + + apply_pending_user_photo(u, user_id); + + td_->messages_manager_->on_update_dialog_notify_settings(DialogId(user_id), std::move(user->notify_settings_), + "on_get_user_full"); + + td_->messages_manager_->on_update_dialog_background(DialogId(user_id), std::move(user->wallpaper_)); + + td_->messages_manager_->on_update_dialog_theme_name(DialogId(user_id), std::move(user->theme_emoticon_)); + + td_->messages_manager_->on_update_dialog_last_pinned_message_id(DialogId(user_id), + MessageId(ServerMessageId(user->pinned_msg_id_))); + + td_->messages_manager_->on_update_dialog_folder_id(DialogId(user_id), FolderId(user->folder_id_)); + + td_->messages_manager_->on_update_dialog_has_scheduled_server_messages(DialogId(user_id), user->has_scheduled_); + + td_->messages_manager_->on_update_dialog_message_ttl(DialogId(user_id), MessageTtl(user->ttl_period_)); + + td_->messages_manager_->on_update_dialog_is_blocked(DialogId(user_id), user->blocked_, + user->blocked_my_stories_from_); + + td_->messages_manager_->on_update_dialog_is_translatable(DialogId(user_id), !user->translations_disabled_); + + send_closure_later(td_->story_manager_actor_, &StoryManager::on_get_dialog_stories, DialogId(user_id), + std::move(user->stories_), Promise()); + + UserFull *user_full = add_user_full(user_id); + user_full->expires_at = Time::now() + USER_FULL_EXPIRE_TIME; + + on_update_user_full_is_blocked(user_full, user_id, user->blocked_, user->blocked_my_stories_from_); + on_update_user_full_common_chat_count(user_full, user_id, user->common_chats_count_); + on_update_user_full_location(user_full, user_id, DialogLocation(td_, std::move(user->business_location_))); + on_update_user_full_work_hours(user_full, user_id, BusinessWorkHours(std::move(user->business_work_hours_))); + on_update_user_full_away_message(user_full, user_id, BusinessAwayMessage(std::move(user->business_away_message_))); + on_update_user_full_greeting_message(user_full, user_id, + BusinessGreetingMessage(std::move(user->business_greeting_message_))); + on_update_user_full_intro(user_full, user_id, BusinessIntro(td_, std::move(user->business_intro_))); + on_update_user_full_need_phone_number_privacy_exception(user_full, user_id, + user->settings_->need_contacts_exception_); + on_update_user_full_wallpaper_overridden(user_full, user_id, user->wallpaper_overridden_); + + bool can_pin_messages = user->can_pin_message_; + bool can_be_called = user->phone_calls_available_ && !user->phone_calls_private_; + bool supports_video_calls = user->video_calls_available_ && !user->phone_calls_private_; + bool has_private_calls = user->phone_calls_private_; + bool voice_messages_forbidden = u->is_premium ? user->voice_messages_forbidden_ : false; + auto premium_gift_options = get_premium_gift_options(std::move(user->premium_gifts_)); + AdministratorRights group_administrator_rights(user->bot_group_admin_rights_, ChannelType::Megagroup); + AdministratorRights broadcast_administrator_rights(user->bot_broadcast_admin_rights_, ChannelType::Broadcast); + bool has_pinned_stories = user->stories_pinned_available_; + auto birthdate = Birthdate(std::move(user->birthday_)); + auto personal_channel_id = ChannelId(user->personal_channel_id_); + if (user_full->can_be_called != can_be_called || user_full->supports_video_calls != supports_video_calls || + user_full->has_private_calls != has_private_calls || + user_full->group_administrator_rights != group_administrator_rights || + user_full->broadcast_administrator_rights != broadcast_administrator_rights || + user_full->premium_gift_options != premium_gift_options || + user_full->voice_messages_forbidden != voice_messages_forbidden || + user_full->can_pin_messages != can_pin_messages || user_full->has_pinned_stories != has_pinned_stories) { + user_full->can_be_called = can_be_called; + user_full->supports_video_calls = supports_video_calls; + user_full->has_private_calls = has_private_calls; + user_full->group_administrator_rights = group_administrator_rights; + user_full->broadcast_administrator_rights = broadcast_administrator_rights; + user_full->premium_gift_options = std::move(premium_gift_options); + user_full->voice_messages_forbidden = voice_messages_forbidden; + user_full->can_pin_messages = can_pin_messages; + user_full->has_pinned_stories = has_pinned_stories; + + user_full->is_changed = true; + } + if (user_full->birthdate != birthdate) { + user_full->birthdate = birthdate; + user_full->is_changed = true; + + if (u->is_contact) { + reload_contact_birthdates(true); + } + } + + if (user_full->private_forward_name != user->private_forward_name_) { + if (user_full->private_forward_name.empty() != user->private_forward_name_.empty()) { + user_full->is_changed = true; + } + user_full->private_forward_name = std::move(user->private_forward_name_); + user_full->need_save_to_database = true; + } + if (user_full->read_dates_private != user->read_dates_private_ || + user_full->contact_require_premium != user->contact_require_premium_) { + user_full->read_dates_private = user->read_dates_private_; + user_full->contact_require_premium = user->contact_require_premium_; + user_full->need_save_to_database = true; + } + if (user_full->about != user->about_) { + user_full->about = std::move(user->about_); + user_full->is_changed = true; + td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, true); + } + string description; + Photo description_photo; + FileId description_animation_file_id; + if (user->bot_info_ != nullptr && !td_->auth_manager_->is_bot()) { + description = std::move(user->bot_info_->description_); + description_photo = get_photo(td_, std::move(user->bot_info_->description_photo_), DialogId(user_id)); + auto document = std::move(user->bot_info_->description_document_); + if (document != nullptr) { + int32 document_id = document->get_id(); + if (document_id == telegram_api::document::ID) { + auto parsed_document = td_->documents_manager_->on_get_document( + move_tl_object_as(document), DialogId(user_id)); + if (parsed_document.type == Document::Type::Animation) { + description_animation_file_id = parsed_document.file_id; + } else { + LOG(ERROR) << "Receive non-animation document in bot description"; + } + } + } + + on_update_user_full_commands(user_full, user_id, std::move(user->bot_info_->commands_)); + on_update_user_full_menu_button(user_full, user_id, std::move(user->bot_info_->menu_button_)); + } + if (user_full->description != description) { + user_full->description = std::move(description); + user_full->is_changed = true; + } + if (user_full->description_photo != description_photo || + user_full->description_animation_file_id != description_animation_file_id) { + user_full->description_photo = std::move(description_photo); + user_full->description_animation_file_id = description_animation_file_id; + user_full->is_changed = true; + } + if (personal_channel_id != ChannelId() && !personal_channel_id.is_valid()) { + LOG(ERROR) << "Receive personal " << personal_channel_id; + personal_channel_id = ChannelId(); + } + if (user_full->personal_channel_id != personal_channel_id) { + user_full->personal_channel_id = personal_channel_id; + user_full->is_changed = true; + } + if (user_full->personal_channel_id != ChannelId()) { + auto personal_message_id = MessageId(ServerMessageId(user->personal_channel_message_)); + td_->messages_manager_->get_channel_difference_if_needed(DialogId(user_full->personal_channel_id), + personal_message_id, "on_get_user_full personal chat"); + } + + auto photo = get_photo(td_, std::move(user->profile_photo_), DialogId(user_id)); + auto personal_photo = get_photo(td_, std::move(user->personal_photo_), DialogId(user_id)); + auto fallback_photo = get_photo(td_, std::move(user->fallback_photo_), DialogId(user_id)); + // do_update_user_photo should be a no-op if server sent consistent data + const Photo *photo_ptr = nullptr; + bool is_personal = false; + if (!personal_photo.is_empty()) { + photo_ptr = &personal_photo; + is_personal = true; + } else if (!photo.is_empty()) { + photo_ptr = &photo; + } else { + photo_ptr = &fallback_photo; + } + bool is_photo_empty = photo_ptr->is_empty(); + do_update_user_photo(u, user_id, + as_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, *photo_ptr, is_personal), + false, "on_get_user_full"); + if (photo != user_full->photo) { + user_full->photo = std::move(photo); + user_full->is_changed = true; + } + if (personal_photo != user_full->personal_photo) { + user_full->personal_photo = std::move(personal_photo); + user_full->is_changed = true; + } + if (fallback_photo != user_full->fallback_photo) { + user_full->fallback_photo = std::move(fallback_photo); + user_full->is_changed = true; + } + if (!user_full->photo.is_empty()) { + register_user_photo(u, user_id, user_full->photo); + } + if (user_id == get_my_id() && !user_full->fallback_photo.is_empty()) { + register_suggested_profile_photo(user_full->fallback_photo); + } + if (is_photo_empty) { + drop_user_photos(user_id, true, "on_get_user_full"); + } + + // User must be updated before UserFull + if (u->is_changed) { + LOG(ERROR) << "Receive inconsistent chatPhoto and chatPhotoInfo for " << user_id; + update_user(u, user_id); + } + + user_full->is_update_user_full_sent = true; + update_user_full(user_full, user_id, "on_get_user_full"); + + // update peer settings after UserFull is created and updated to not update twice need_phone_number_privacy_exception + td_->messages_manager_->on_get_peer_settings(DialogId(user_id), std::move(user->settings_)); +} + +FileSourceId UserManager::get_user_full_file_source_id(UserId user_id) { + if (!user_id.is_valid()) { + return FileSourceId(); + } + + auto user_full = get_user_full(user_id); + if (user_full != nullptr) { + VLOG(file_references) << "Don't need to create file source for full " << user_id; + // user full was already added, source ID was registered and shouldn't be needed + return user_full->is_update_user_full_sent ? FileSourceId() : user_full->file_source_id; + } + + auto &source_id = user_full_file_source_ids_[user_id]; + if (!source_id.is_valid()) { + source_id = td_->file_reference_manager_->create_user_full_file_source(user_id); + } + VLOG(file_references) << "Return " << source_id << " for full " << user_id; + return source_id; +} + +void UserManager::save_user_full(const UserFull *user_full, UserId user_id) { + if (!G()->use_chat_info_database()) { + return; + } + + LOG(INFO) << "Trying to save to database full " << user_id; + CHECK(user_full != nullptr); + G()->td_db()->get_sqlite_pmc()->set(get_user_full_database_key(user_id), get_user_full_database_value(user_full), + Auto()); +} + +string UserManager::get_user_full_database_key(UserId user_id) { + return PSTRING() << "usf" << user_id.get(); +} + +string UserManager::get_user_full_database_value(const UserFull *user_full) { + return log_event_store(*user_full).as_slice().str(); +} + +void UserManager::on_load_user_full_from_database(UserId user_id, string value) { + LOG(INFO) << "Successfully loaded full " << user_id << " of size " << value.size() << " from database"; + // G()->td_db()->get_sqlite_pmc()->erase(get_user_full_database_key(user_id), Auto()); + // return; + + if (get_user_full(user_id) != nullptr || value.empty()) { + return; + } + + UserFull *user_full = add_user_full(user_id); + auto status = log_event_parse(*user_full, value); + if (status.is_error()) { + // can't happen unless database is broken + LOG(ERROR) << "Repair broken full " << user_id << ' ' << format::as_hex_dump<4>(Slice(value)); + + // just clean all known data about the user and pretend that there was nothing in the database + users_full_.erase(user_id); + G()->td_db()->get_sqlite_pmc()->erase(get_user_full_database_key(user_id), Auto()); + return; + } + + Dependencies dependencies; + dependencies.add(user_id); + if (user_full->business_info != nullptr) { + user_full->business_info->add_dependencies(dependencies); + } + dependencies.add(user_full->personal_channel_id); + if (!dependencies.resolve_force(td_, "on_load_user_full_from_database")) { + users_full_.erase(user_id); + G()->td_db()->get_sqlite_pmc()->erase(get_user_full_database_key(user_id), Auto()); + return; + } + + if (user_full->need_phone_number_privacy_exception && is_user_contact(user_id)) { + user_full->need_phone_number_privacy_exception = false; + } + + User *u = get_user(user_id); + CHECK(u != nullptr); + drop_user_full_photos(user_full, user_id, u->photo.id, "on_load_user_full_from_database"); + if (!user_full->photo.is_empty()) { + register_user_photo(u, user_id, user_full->photo); + } + if (user_id == get_my_id() && !user_full->fallback_photo.is_empty()) { + register_suggested_profile_photo(user_full->fallback_photo); + } + + td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, false); + + user_full->is_update_user_full_sent = true; + update_user_full(user_full, user_id, "on_load_user_full_from_database", true); + + if (is_user_deleted(u)) { + drop_user_full(user_id); + } else if (user_full->expires_at == 0.0) { + reload_user_full(user_id, Auto(), "on_load_user_full_from_database"); + } +} + +int64 UserManager::get_user_full_profile_photo_id(const UserFull *user_full) { + if (!user_full->personal_photo.is_empty()) { + return user_full->personal_photo.id.get(); + } + if (!user_full->photo.is_empty()) { + return user_full->photo.id.get(); + } + return user_full->fallback_photo.id.get(); +} + +void UserManager::drop_user_full_photos(UserFull *user_full, UserId user_id, int64 expected_photo_id, + const char *source) { + if (user_full == nullptr) { + return; + } + LOG(INFO) << "Expect full photo " << expected_photo_id << " from " << source; + for (auto photo_ptr : {&user_full->personal_photo, &user_full->photo, &user_full->fallback_photo}) { + if (photo_ptr->is_empty()) { + continue; + } + if (expected_photo_id == 0) { + // if profile photo is empty, we must drop the full photo + *photo_ptr = Photo(); + user_full->is_changed = true; + } else if (expected_photo_id != photo_ptr->id.get()) { + LOG(INFO) << "Drop full photo " << photo_ptr->id.get(); + // if full profile photo is unknown, we must drop the full photo + *photo_ptr = Photo(); + user_full->is_changed = true; + } else { + // nothing to drop + break; + } + } + if (expected_photo_id != get_user_full_profile_photo_id(user_full)) { + user_full->expires_at = 0.0; + } + if (user_full->is_update_user_full_sent) { + update_user_full(user_full, user_id, "drop_user_full_photos"); + } +} + +void UserManager::drop_user_photos(UserId user_id, bool is_empty, const char *source) { + LOG(INFO) << "Drop user photos to " << (is_empty ? "empty" : "unknown") << " from " << source; + auto user_photos = user_photos_.get_pointer(user_id); + if (user_photos != nullptr) { + int32 new_count = is_empty ? 0 : -1; + if (user_photos->count == new_count) { + CHECK(user_photos->photos.empty()); + CHECK(user_photos->offset == user_photos->count); + } else { + LOG(INFO) << "Drop photos of " << user_id << " to " << (is_empty ? "empty" : "unknown") << " from " << source; + user_photos->photos.clear(); + user_photos->count = new_count; + user_photos->offset = user_photos->count; + } + } +} + +void UserManager::drop_user_full(UserId user_id) { + auto user_full = get_user_full_force(user_id, "drop_user_full"); + + drop_user_photos(user_id, false, "drop_user_full"); + + if (user_full == nullptr) { + return; + } + + user_full->expires_at = 0.0; + + user_full->photo = Photo(); + user_full->personal_photo = Photo(); + user_full->fallback_photo = Photo(); + // user_full->is_blocked = false; + // user_full->is_blocked_for_stories = false; + user_full->can_be_called = false; + user_full->supports_video_calls = false; + user_full->has_private_calls = false; + user_full->need_phone_number_privacy_exception = false; + user_full->wallpaper_overridden = false; + user_full->about = string(); + user_full->description = string(); + user_full->description_photo = Photo(); + user_full->description_animation_file_id = FileId(); + user_full->menu_button = nullptr; + user_full->commands.clear(); + user_full->common_chat_count = 0; + user_full->personal_channel_id = ChannelId(); + user_full->business_info = nullptr; + user_full->private_forward_name.clear(); + user_full->group_administrator_rights = {}; + user_full->broadcast_administrator_rights = {}; + user_full->premium_gift_options.clear(); + user_full->voice_messages_forbidden = false; + user_full->has_pinned_stories = false; + user_full->read_dates_private = false; + user_full->contact_require_premium = false; + user_full->birthdate = {}; + user_full->is_changed = true; + + update_user_full(user_full, user_id, "drop_user_full"); + td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, true); +} + +bool UserManager::have_secret_chat(SecretChatId secret_chat_id) const { + return secret_chats_.count(secret_chat_id) > 0; +} + +const UserManager::SecretChat *UserManager::get_secret_chat(SecretChatId secret_chat_id) const { + return secret_chats_.get_pointer(secret_chat_id); +} + +UserManager::SecretChat *UserManager::get_secret_chat(SecretChatId secret_chat_id) { + return secret_chats_.get_pointer(secret_chat_id); +} + +UserManager::SecretChat *UserManager::add_secret_chat(SecretChatId secret_chat_id) { + CHECK(secret_chat_id.is_valid()); + auto &secret_chat_ptr = secret_chats_[secret_chat_id]; + if (secret_chat_ptr == nullptr) { + secret_chat_ptr = make_unique(); + } + return secret_chat_ptr.get(); +} + +bool UserManager::have_secret_chat_force(SecretChatId secret_chat_id, const char *source) { + return get_secret_chat_force(secret_chat_id, source) != nullptr; +} + +UserManager::SecretChat *UserManager::get_secret_chat_force(SecretChatId secret_chat_id, const char *source) { + if (!secret_chat_id.is_valid()) { + return nullptr; + } + + SecretChat *c = get_secret_chat(secret_chat_id); + if (c != nullptr) { + if (!have_user_force(c->user_id, source)) { + LOG(ERROR) << "Can't find " << c->user_id << " from " << secret_chat_id << " from " << source; + } + return c; + } + if (!G()->use_chat_info_database()) { + return nullptr; + } + if (loaded_from_database_secret_chats_.count(secret_chat_id)) { + return nullptr; + } + + LOG(INFO) << "Trying to load " << secret_chat_id << " from database from " << source; + on_load_secret_chat_from_database( + secret_chat_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_secret_chat_database_key(secret_chat_id)), true); + return get_secret_chat(secret_chat_id); +} + +bool UserManager::get_secret_chat(SecretChatId secret_chat_id, bool force, Promise &&promise) { + if (!secret_chat_id.is_valid()) { + promise.set_error(Status::Error(400, "Invalid secret chat identifier")); + return false; + } + + if (!have_secret_chat(secret_chat_id)) { + if (!force && G()->use_chat_info_database()) { + send_closure_later(actor_id(this), &UserManager::load_secret_chat_from_database, nullptr, secret_chat_id, + std::move(promise)); + return false; + } + + promise.set_error(Status::Error(400, "Secret chat not found")); + return false; + } + + promise.set_value(Unit()); + return true; +} + +void UserManager::save_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog) { + if (!G()->use_chat_info_database()) { + return; + } + CHECK(c != nullptr); + if (!c->is_saved) { + if (!from_binlog) { + auto log_event = SecretChatLogEvent(secret_chat_id, c); + auto storer = get_log_event_storer(log_event); + if (c->log_event_id == 0) { + c->log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::SecretChatInfos, storer); + } else { + binlog_rewrite(G()->td_db()->get_binlog(), c->log_event_id, LogEvent::HandlerType::SecretChatInfos, storer); + } + } + + save_secret_chat_to_database(c, secret_chat_id); + return; + } +} + +string UserManager::get_secret_chat_database_key(SecretChatId secret_chat_id) { + return PSTRING() << "sc" << secret_chat_id.get(); +} + +string UserManager::get_secret_chat_database_value(const SecretChat *c) { + return log_event_store(*c).as_slice().str(); +} + +void UserManager::save_secret_chat_to_database(SecretChat *c, SecretChatId secret_chat_id) { + CHECK(c != nullptr); + if (c->is_being_saved) { + return; + } + if (loaded_from_database_secret_chats_.count(secret_chat_id)) { + save_secret_chat_to_database_impl(c, secret_chat_id, get_secret_chat_database_value(c)); + return; + } + if (load_secret_chat_from_database_queries_.count(secret_chat_id) != 0) { + return; + } + + load_secret_chat_from_database_impl(secret_chat_id, Auto()); +} + +void UserManager::save_secret_chat_to_database_impl(SecretChat *c, SecretChatId secret_chat_id, string value) { + CHECK(c != nullptr); + CHECK(load_secret_chat_from_database_queries_.count(secret_chat_id) == 0); + CHECK(!c->is_being_saved); + c->is_being_saved = true; + c->is_saved = true; + LOG(INFO) << "Trying to save to database " << secret_chat_id; + G()->td_db()->get_sqlite_pmc()->set(get_secret_chat_database_key(secret_chat_id), std::move(value), + PromiseCreator::lambda([secret_chat_id](Result<> result) { + send_closure(G()->user_manager(), &UserManager::on_save_secret_chat_to_database, + secret_chat_id, result.is_ok()); + })); +} + +void UserManager::on_save_secret_chat_to_database(SecretChatId secret_chat_id, bool success) { + if (G()->close_flag()) { + return; + } + + SecretChat *c = get_secret_chat(secret_chat_id); + CHECK(c != nullptr); + CHECK(c->is_being_saved); + CHECK(load_secret_chat_from_database_queries_.count(secret_chat_id) == 0); + c->is_being_saved = false; + + if (!success) { + LOG(ERROR) << "Failed to save " << secret_chat_id << " to database"; + c->is_saved = false; + } else { + LOG(INFO) << "Successfully saved " << secret_chat_id << " to database"; + } + if (c->is_saved) { + if (c->log_event_id != 0) { + binlog_erase(G()->td_db()->get_binlog(), c->log_event_id); + c->log_event_id = 0; + } + } else { + save_secret_chat(c, secret_chat_id, c->log_event_id != 0); + } +} + +void UserManager::load_secret_chat_from_database(SecretChat *c, SecretChatId secret_chat_id, Promise promise) { + if (loaded_from_database_secret_chats_.count(secret_chat_id)) { + promise.set_value(Unit()); + return; + } + + CHECK(c == nullptr || !c->is_being_saved); + load_secret_chat_from_database_impl(secret_chat_id, std::move(promise)); +} + +void UserManager::load_secret_chat_from_database_impl(SecretChatId secret_chat_id, Promise promise) { + LOG(INFO) << "Load " << secret_chat_id << " from database"; + auto &load_secret_chat_queries = load_secret_chat_from_database_queries_[secret_chat_id]; + load_secret_chat_queries.push_back(std::move(promise)); + if (load_secret_chat_queries.size() == 1u) { + G()->td_db()->get_sqlite_pmc()->get( + get_secret_chat_database_key(secret_chat_id), PromiseCreator::lambda([secret_chat_id](string value) { + send_closure(G()->user_manager(), &UserManager::on_load_secret_chat_from_database, secret_chat_id, + std::move(value), false); + })); + } +} + +void UserManager::on_load_secret_chat_from_database(SecretChatId secret_chat_id, string value, bool force) { + if (G()->close_flag() && !force) { + // the secret chat is in Binlog and will be saved after restart + return; + } + + CHECK(secret_chat_id.is_valid()); + if (!loaded_from_database_secret_chats_.insert(secret_chat_id).second) { + return; + } + + auto it = load_secret_chat_from_database_queries_.find(secret_chat_id); + vector> promises; + if (it != load_secret_chat_from_database_queries_.end()) { + promises = std::move(it->second); + CHECK(!promises.empty()); + load_secret_chat_from_database_queries_.erase(it); + } + + LOG(INFO) << "Successfully loaded " << secret_chat_id << " of size " << value.size() << " from database"; + // G()->td_db()->get_sqlite_pmc()->erase(get_secret_chat_database_key(secret_chat_id), Auto()); + // return; + + SecretChat *c = get_secret_chat(secret_chat_id); + if (c == nullptr) { + if (!value.empty()) { + c = add_secret_chat(secret_chat_id); + + if (log_event_parse(*c, value).is_error()) { + LOG(ERROR) << "Failed to load " << secret_chat_id << " from database"; + secret_chats_.erase(secret_chat_id); + } else { + c->is_saved = true; + update_secret_chat(c, secret_chat_id, true, true); + } + } + } else { + CHECK(!c->is_saved); // secret chat can't be saved before load completes + CHECK(!c->is_being_saved); + auto new_value = get_secret_chat_database_value(c); + if (value != new_value) { + save_secret_chat_to_database_impl(c, secret_chat_id, std::move(new_value)); + } else if (c->log_event_id != 0) { + binlog_erase(G()->td_db()->get_binlog(), c->log_event_id); + c->log_event_id = 0; + } + } + + // TODO load users asynchronously + if (c != nullptr && !have_user_force(c->user_id, "on_load_secret_chat_from_database")) { + LOG(ERROR) << "Can't find " << c->user_id << " from " << secret_chat_id; + } + + set_promises(promises); +} + +void UserManager::create_new_secret_chat(UserId user_id, Promise> &&promise) { + TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id)); + if (input_user->get_id() != telegram_api::inputUser::ID) { + return promise.set_error(Status::Error(400, "Can't create secret chat with the user")); + } + auto user = static_cast(input_user.get()); + + send_closure( + G()->secret_chats_manager(), &SecretChatsManager::create_chat, UserId(user->user_id_), user->access_hash_, + PromiseCreator::lambda( + [actor_id = actor_id(this), promise = std::move(promise)](Result r_secret_chat_id) mutable { + if (r_secret_chat_id.is_error()) { + return promise.set_error(r_secret_chat_id.move_as_error()); + } + send_closure(actor_id, &UserManager::on_create_new_secret_chat, r_secret_chat_id.ok(), std::move(promise)); + })); +} + +void UserManager::on_create_new_secret_chat(SecretChatId secret_chat_id, + Promise> &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + CHECK(secret_chat_id.is_valid()); + DialogId dialog_id(secret_chat_id); + td_->dialog_manager_->force_create_dialog(dialog_id, "on_create_new_secret_chat"); + promise.set_value(td_->messages_manager_->get_chat_object(dialog_id, "on_create_new_secret_chat")); +} + +void UserManager::update_user(User *u, UserId user_id, bool from_binlog, bool from_database) { + CHECK(u != nullptr); + + if (u->is_being_updated) { + LOG(ERROR) << "Detected recursive update of " << user_id; + } + u->is_being_updated = true; + SCOPE_EXIT { + u->is_being_updated = false; + }; + + if (user_id == get_my_id()) { + if (td_->option_manager_->get_option_boolean("is_premium") != u->is_premium) { + td_->option_manager_->set_option_boolean("is_premium", u->is_premium); + send_closure(td_->config_manager_, &ConfigManager::request_config, true); + if (!td_->auth_manager_->is_bot()) { + td_->reaction_manager_->reload_reaction_list(ReactionListType::Top, "update_user is_premium"); + td_->messages_manager_->update_is_translatable(u->is_premium); + } + } + } + if (u->is_name_changed || u->is_username_changed || u->is_is_contact_changed) { + update_contacts_hints(u, user_id, from_database); + u->is_username_changed = false; + } + if (u->is_is_contact_changed) { + td_->messages_manager_->on_dialog_user_is_contact_updated(DialogId(user_id), u->is_contact); + send_closure_later(td_->story_manager_actor_, &StoryManager::on_dialog_active_stories_order_updated, + DialogId(user_id), "is_contact"); + if (is_user_contact(u, user_id, false)) { + auto user_full = get_user_full(user_id); + if (user_full != nullptr && user_full->need_phone_number_privacy_exception) { + on_update_user_full_need_phone_number_privacy_exception(user_full, user_id, false); + update_user_full(user_full, user_id, "update_user"); + } + } + u->is_is_contact_changed = false; + } + if (u->is_is_mutual_contact_changed) { + if (!from_database && u->is_update_user_sent) { + send_closure_later(td_->story_manager_actor_, &StoryManager::reload_dialog_expiring_stories, DialogId(user_id)); + } + u->is_is_mutual_contact_changed = false; + } + if (u->is_is_deleted_changed) { + td_->messages_manager_->on_dialog_user_is_deleted_updated(DialogId(user_id), u->is_deleted); + if (u->is_deleted) { + auto user_full = get_user_full(user_id); // must not load user_full from database before sending updateUser + if (user_full != nullptr) { + u->is_full_info_changed = false; + drop_user_full(user_id); + } + } + u->is_is_deleted_changed = false; + } + if (u->is_is_premium_changed) { + send_closure_later(td_->story_manager_actor_, &StoryManager::on_dialog_active_stories_order_updated, + DialogId(user_id), "is_premium"); + u->is_is_premium_changed = false; + } + if (u->is_name_changed) { + auto messages_manager = td_->messages_manager_.get(); + messages_manager->on_dialog_title_updated(DialogId(user_id)); + for_each_secret_chat_with_user(user_id, [messages_manager](SecretChatId secret_chat_id) { + messages_manager->on_dialog_title_updated(DialogId(secret_chat_id)); + }); + u->is_name_changed = false; + } + if (u->is_photo_changed) { + auto messages_manager = td_->messages_manager_.get(); + messages_manager->on_dialog_photo_updated(DialogId(user_id)); + for_each_secret_chat_with_user(user_id, [messages_manager](SecretChatId secret_chat_id) { + messages_manager->on_dialog_photo_updated(DialogId(secret_chat_id)); + }); + u->is_photo_changed = false; + } + if (u->is_accent_color_changed) { + auto messages_manager = td_->messages_manager_.get(); + messages_manager->on_dialog_accent_colors_updated(DialogId(user_id)); + for_each_secret_chat_with_user(user_id, [messages_manager](SecretChatId secret_chat_id) { + messages_manager->on_dialog_accent_colors_updated(DialogId(secret_chat_id)); + }); + u->is_accent_color_changed = false; + } + if (u->is_phone_number_changed) { + if (!u->phone_number.empty() && !td_->auth_manager_->is_bot()) { + resolved_phone_numbers_[u->phone_number] = user_id; + } + u->is_phone_number_changed = false; + } + auto unix_time = G()->unix_time(); + if (u->is_status_changed && user_id != get_my_id()) { + auto left_time = get_user_was_online(u, user_id, unix_time) - G()->server_time(); + if (left_time >= 0 && left_time < 30 * 86400) { + left_time += 2.0; // to guarantee expiration + LOG(DEBUG) << "Set online timeout for " << user_id << " in " << left_time << " seconds"; + user_online_timeout_.set_timeout_in(user_id.get(), left_time); + } else { + LOG(DEBUG) << "Cancel online timeout for " << user_id; + user_online_timeout_.cancel_timeout(user_id.get()); + } + } + if (u->is_stories_hidden_changed) { + send_closure_later(td_->story_manager_actor_, &StoryManager::on_dialog_active_stories_order_updated, + DialogId(user_id), "stories_hidden"); + u->is_stories_hidden_changed = false; + } + if (!td_->auth_manager_->is_bot()) { + if (u->restriction_reasons.empty()) { + restricted_user_ids_.erase(user_id); + } else { + restricted_user_ids_.insert(user_id); + } + } + + auto effective_emoji_status = u->emoji_status.get_effective_emoji_status(u->is_premium, unix_time); + if (effective_emoji_status != u->last_sent_emoji_status) { + if (!u->last_sent_emoji_status.is_empty()) { + user_emoji_status_timeout_.cancel_timeout(user_id.get()); + } + u->last_sent_emoji_status = effective_emoji_status; + if (!u->last_sent_emoji_status.is_empty()) { + auto until_date = u->last_sent_emoji_status.get_until_date(); + auto left_time = until_date - unix_time; + if (left_time >= 0 && left_time < 30 * 86400) { + user_emoji_status_timeout_.set_timeout_in(user_id.get(), left_time); + } + } + u->is_changed = true; + + auto messages_manager = td_->messages_manager_.get(); + messages_manager->on_dialog_emoji_status_updated(DialogId(user_id)); + for_each_secret_chat_with_user(user_id, [messages_manager](SecretChatId secret_chat_id) { + messages_manager->on_dialog_emoji_status_updated(DialogId(secret_chat_id)); + }); + u->is_emoji_status_changed = false; + } else if (u->is_emoji_status_changed) { + LOG(DEBUG) << "Emoji status for " << user_id << " has changed"; + u->need_save_to_database = true; + u->is_emoji_status_changed = false; + } + + if (u->is_deleted) { + td_->inline_queries_manager_->remove_recent_inline_bot(user_id, Promise<>()); + } + if (from_binlog || from_database) { + td_->dialog_manager_->on_dialog_usernames_received(DialogId(user_id), u->usernames, true); + } + + LOG(DEBUG) << "Update " << user_id << ": need_save_to_database = " << u->need_save_to_database + << ", is_changed = " << u->is_changed << ", is_status_changed = " << u->is_status_changed + << ", from_binlog = " << from_binlog << ", from_database = " << from_database; + u->need_save_to_database |= u->is_changed; + if (u->need_save_to_database) { + if (!from_database) { + u->is_saved = false; + } + u->need_save_to_database = false; + } + if (u->is_changed) { + send_closure(G()->td(), &Td::send_update, get_update_user_object(user_id, u)); + u->is_changed = false; + u->is_status_changed = false; + u->is_update_user_sent = true; + } + if (u->is_status_changed) { + if (!from_database) { + u->is_status_saved = false; + } + CHECK(u->is_update_user_sent); + send_closure( + G()->td(), &Td::send_update, + td_api::make_object(user_id.get(), get_user_status_object(user_id, u, unix_time))); + u->is_status_changed = false; + } + if (u->is_online_status_changed) { + td_->dialog_participant_manager_->update_user_online_member_count(user_id); + u->is_online_status_changed = false; + } + + if (!from_database) { + save_user(u, user_id, from_binlog); + } + + if (u->cache_version != User::CACHE_VERSION && !u->is_repaired && + have_input_peer_user(u, user_id, AccessRights::Read) && !G()->close_flag()) { + u->is_repaired = true; + + LOG(INFO) << "Repairing cache of " << user_id; + reload_user(user_id, Promise(), "update_user"); + } + + if (u->is_full_info_changed) { + u->is_full_info_changed = false; + auto user_full = get_user_full(user_id); + if (user_full != nullptr) { + user_full->need_send_update = true; + update_user_full(user_full, user_id, "update_user is_full_info_changed"); + reload_user_full(user_id, Promise(), "update_user"); + } + } +} + +void UserManager::update_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog, bool from_database) { + CHECK(c != nullptr); + + if (c->is_being_updated) { + LOG(ERROR) << "Detected recursive update of " << secret_chat_id; + } + c->is_being_updated = true; + SCOPE_EXIT { + c->is_being_updated = false; + }; + + LOG(DEBUG) << "Update " << secret_chat_id << ": need_save_to_database = " << c->need_save_to_database + << ", is_changed = " << c->is_changed; + c->need_save_to_database |= c->is_changed; + if (c->need_save_to_database) { + if (!from_database) { + c->is_saved = false; + } + c->need_save_to_database = false; + + DialogId dialog_id(secret_chat_id); + send_closure_later(G()->messages_manager(), &MessagesManager::force_create_dialog, dialog_id, "update secret chat", + true, true); + if (c->is_state_changed) { + send_closure_later(G()->messages_manager(), &MessagesManager::on_update_secret_chat_state, secret_chat_id, + c->state); + c->is_state_changed = false; + } + if (c->is_ttl_changed) { + send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_message_ttl, + DialogId(secret_chat_id), MessageTtl(c->ttl)); + c->is_ttl_changed = false; + } + } + if (c->is_changed) { + send_closure(G()->td(), &Td::send_update, get_update_secret_chat_object(secret_chat_id, c)); + c->is_changed = false; + } + + if (!from_database) { + save_secret_chat(c, secret_chat_id, from_binlog); + } +} + +void UserManager::update_user_full(UserFull *user_full, UserId user_id, const char *source, bool from_database) { + CHECK(user_full != nullptr); + + if (user_full->is_being_updated) { + LOG(ERROR) << "Detected recursive update of full " << user_id << " from " << source; + } + user_full->is_being_updated = true; + SCOPE_EXIT { + user_full->is_being_updated = false; + }; + + unavailable_user_fulls_.erase(user_id); // don't needed anymore + if (user_full->is_common_chat_count_changed) { + td_->common_dialog_manager_->drop_common_dialogs_cache(user_id); + user_full->is_common_chat_count_changed = false; + } + if (true) { + vector file_ids; + if (!user_full->personal_photo.is_empty()) { + append(file_ids, photo_get_file_ids(user_full->personal_photo)); + } + if (!user_full->fallback_photo.is_empty()) { + append(file_ids, photo_get_file_ids(user_full->fallback_photo)); + } + if (!user_full->description_photo.is_empty()) { + append(file_ids, photo_get_file_ids(user_full->description_photo)); + } + if (user_full->description_animation_file_id.is_valid()) { + file_ids.push_back(user_full->description_animation_file_id); + } + if (user_full->business_info != nullptr) { + append(file_ids, user_full->business_info->get_file_ids(td_)); + } + if (user_full->registered_file_ids != file_ids) { + auto &file_source_id = user_full->file_source_id; + if (!file_source_id.is_valid()) { + file_source_id = user_full_file_source_ids_.get(user_id); + if (file_source_id.is_valid()) { + VLOG(file_references) << "Move " << file_source_id << " inside of " << user_id; + user_full_file_source_ids_.erase(user_id); + } else { + VLOG(file_references) << "Need to create new file source for full " << user_id; + file_source_id = td_->file_reference_manager_->create_user_full_file_source(user_id); + } + } + + td_->file_manager_->change_files_source(file_source_id, user_full->registered_file_ids, file_ids); + user_full->registered_file_ids = std::move(file_ids); + } + } + + user_full->need_send_update |= user_full->is_changed; + user_full->need_save_to_database |= user_full->is_changed; + user_full->is_changed = false; + if (user_full->need_send_update || user_full->need_save_to_database) { + LOG(INFO) << "Update full " << user_id << " from " << source; + } + if (user_full->need_send_update) { + { + auto u = get_user(user_id); + CHECK(u == nullptr || u->is_update_user_sent); + } + if (!user_full->is_update_user_full_sent) { + LOG(ERROR) << "Send partial updateUserFullInfo for " << user_id << " from " << source; + user_full->is_update_user_full_sent = true; + } + send_closure(G()->td(), &Td::send_update, + td_api::make_object(get_user_id_object(user_id, "updateUserFullInfo"), + get_user_full_info_object(user_id, user_full))); + user_full->need_send_update = false; + + if (user_id == get_my_id() && !user_full->birthdate.is_empty() && !td_->auth_manager_->is_bot()) { + dismiss_suggested_action(SuggestedAction{SuggestedAction::Type::BirthdaySetup}, Promise()); + } + } + if (user_full->need_save_to_database) { + if (!from_database) { + save_user_full(user_full, user_id); + } + user_full->need_save_to_database = false; + } +} + +td_api::object_ptr UserManager::get_user_status_object(UserId user_id, const User *u, + int32 unix_time) const { + if (u->is_bot) { + return td_api::make_object(std::numeric_limits::max()); + } + + int32 was_online = get_user_was_online(u, user_id, unix_time); + switch (was_online) { + case -6: + case -3: + return td_api::make_object(was_online == -6); + case -5: + case -2: + return td_api::make_object(was_online == -5); + case -4: + case -1: + return td_api::make_object(was_online == -4); + case 0: + return td_api::make_object(); + default: { + int32 time = G()->unix_time(); + if (was_online > time) { + return td_api::make_object(was_online); + } else { + return td_api::make_object(was_online); + } + } + } +} + +bool UserManager::get_user_has_unread_stories(const User *u) { + CHECK(u != nullptr); + return u->max_active_story_id.get() > u->max_read_story_id.get(); +} + +td_api::object_ptr UserManager::get_update_user_object(UserId user_id, const User *u) const { + if (u == nullptr) { + return get_update_unknown_user_object(user_id); + } + return td_api::make_object(get_user_object(user_id, u)); +} + +td_api::object_ptr UserManager::get_update_unknown_user_object(UserId user_id) const { + auto have_access = user_id == get_my_id() || user_messages_.count(user_id) != 0; + return td_api::make_object(td_api::make_object( + user_id.get(), "", "", nullptr, "", td_api::make_object(), nullptr, + td_->theme_manager_->get_accent_color_id_object(AccentColorId(user_id)), 0, -1, 0, nullptr, false, false, false, + false, false, false, "", false, false, false, false, false, have_access, + td_api::make_object(), "", false)); +} + +int64 UserManager::get_user_id_object(UserId user_id, const char *source) const { + if (user_id.is_valid() && get_user(user_id) == nullptr && unknown_users_.count(user_id) == 0) { + LOG(ERROR) << "Have no information about " << user_id << " from " << source; + unknown_users_.insert(user_id); + send_closure(G()->td(), &Td::send_update, get_update_unknown_user_object(user_id)); + } + return user_id.get(); +} + +td_api::object_ptr UserManager::get_user_object(UserId user_id) const { + return get_user_object(user_id, get_user(user_id)); +} + +td_api::object_ptr UserManager::get_user_object(UserId user_id, const User *u) const { + if (u == nullptr) { + return nullptr; + } + td_api::object_ptr type; + if (u->is_deleted) { + type = td_api::make_object(); + } else if (u->is_bot) { + type = td_api::make_object( + u->can_be_edited_bot, u->can_join_groups, u->can_read_all_group_messages, u->is_inline_bot, + u->inline_query_placeholder, u->need_location_bot, u->is_business_bot, u->can_be_added_to_attach_menu); + } else { + type = td_api::make_object(); + } + + auto emoji_status = u->last_sent_emoji_status.get_emoji_status_object(); + auto have_access = user_id == get_my_id() || have_input_peer_user(u, user_id, AccessRights::Know); + auto accent_color_id = u->accent_color_id.is_valid() ? u->accent_color_id : AccentColorId(user_id); + auto restricts_new_chats = u->contact_require_premium && !u->is_mutual_contact; + return td_api::make_object( + user_id.get(), u->first_name, u->last_name, u->usernames.get_usernames_object(), u->phone_number, + get_user_status_object(user_id, u, G()->unix_time()), + get_profile_photo_object(td_->file_manager_.get(), u->photo), + td_->theme_manager_->get_accent_color_id_object(accent_color_id, AccentColorId(user_id)), + u->background_custom_emoji_id.get(), + td_->theme_manager_->get_profile_accent_color_id_object(u->profile_accent_color_id), + u->profile_background_custom_emoji_id.get(), std::move(emoji_status), u->is_contact, u->is_mutual_contact, + u->is_close_friend, u->is_verified, u->is_premium, u->is_support, + get_restriction_reason_description(u->restriction_reasons), u->is_scam, u->is_fake, + u->max_active_story_id.is_valid(), get_user_has_unread_stories(u), restricts_new_chats, have_access, + std::move(type), u->language_code, u->attach_menu_enabled); +} + +vector UserManager::get_user_ids_object(const vector &user_ids, const char *source) const { + return transform(user_ids, [this, source](UserId user_id) { return get_user_id_object(user_id, source); }); +} + +td_api::object_ptr UserManager::get_users_object(int32 total_count, + const vector &user_ids) const { + if (total_count == -1) { + total_count = narrow_cast(user_ids.size()); + } + return td_api::make_object(total_count, get_user_ids_object(user_ids, "get_users_object")); +} + +td_api::object_ptr UserManager::get_user_full_info_object(UserId user_id) const { + return get_user_full_info_object(user_id, get_user_full(user_id)); +} + +td_api::object_ptr UserManager::get_user_full_info_object(UserId user_id, + const UserFull *user_full) const { + CHECK(user_full != nullptr); + td_api::object_ptr bot_info; + const User *u = get_user(user_id); + bool is_bot = is_user_bot(u); + bool is_premium = is_user_premium(u); + td_api::object_ptr bio_object; + if (is_bot) { + auto menu_button = get_bot_menu_button_object(td_, user_full->menu_button.get()); + auto commands = + transform(user_full->commands, [](const auto &command) { return command.get_bot_command_object(); }); + bot_info = td_api::make_object( + user_full->about, user_full->description, + get_photo_object(td_->file_manager_.get(), user_full->description_photo), + td_->animations_manager_->get_animation_object(user_full->description_animation_file_id), + std::move(menu_button), std::move(commands), + user_full->group_administrator_rights == AdministratorRights() + ? nullptr + : user_full->group_administrator_rights.get_chat_administrator_rights_object(), + user_full->broadcast_administrator_rights == AdministratorRights() + ? nullptr + : user_full->broadcast_administrator_rights.get_chat_administrator_rights_object(), + nullptr, nullptr, nullptr, nullptr); + if (u != nullptr && u->can_be_edited_bot && u->usernames.has_editable_username()) { + auto bot_username = u->usernames.get_editable_username(); + bot_info->edit_commands_link_ = td_api::make_object( + "botfather", PSTRING() << bot_username << "-commands", true); + bot_info->edit_description_link_ = td_api::make_object( + "botfather", PSTRING() << bot_username << "-intro", true); + bot_info->edit_description_media_link_ = td_api::make_object( + "botfather", PSTRING() << bot_username << "-intropic", true); + bot_info->edit_settings_link_ = + td_api::make_object("botfather", bot_username, true); + } + } else { + FormattedText bio; + bio.text = user_full->about; + bio.entities = find_entities(bio.text, true, true); + if (!is_premium) { + td::remove_if(bio.entities, [&](const MessageEntity &entity) { + if (entity.type == MessageEntity::Type::EmailAddress) { + return true; + } + if (entity.type == MessageEntity::Type::Url && + !LinkManager::is_internal_link(utf8_utf16_substr(bio.text, entity.offset, entity.length))) { + return true; + } + return false; + }); + } + bio_object = get_formatted_text_object(bio, true, 0); + } + auto voice_messages_forbidden = is_premium ? user_full->voice_messages_forbidden : false; + auto block_list_id = BlockListId(user_full->is_blocked, user_full->is_blocked_for_stories); + auto business_info = is_premium && user_full->business_info != nullptr + ? user_full->business_info->get_business_info_object(td_) + : nullptr; + int64 personal_chat_id = 0; + if (user_full->personal_channel_id.is_valid()) { + DialogId dialog_id(user_full->personal_channel_id); + td_->dialog_manager_->force_create_dialog(dialog_id, "get_user_full_info_object", true); + personal_chat_id = td_->dialog_manager_->get_chat_id_object(dialog_id, "get_user_full_info_object"); + } + return td_api::make_object( + get_chat_photo_object(td_->file_manager_.get(), user_full->personal_photo), + get_chat_photo_object(td_->file_manager_.get(), user_full->photo), + get_chat_photo_object(td_->file_manager_.get(), user_full->fallback_photo), block_list_id.get_block_list_object(), + user_full->can_be_called, user_full->supports_video_calls, user_full->has_private_calls, + !user_full->private_forward_name.empty(), voice_messages_forbidden, user_full->has_pinned_stories, + user_full->need_phone_number_privacy_exception, user_full->wallpaper_overridden, std::move(bio_object), + user_full->birthdate.get_birthdate_object(), personal_chat_id, + get_premium_payment_options_object(user_full->premium_gift_options), user_full->common_chat_count, + std::move(business_info), std::move(bot_info)); +} + +td_api::object_ptr UserManager::get_update_contact_close_birthdays() const { + return td_api::make_object( + transform(contact_birthdates_.users_, [this](const std::pair &user) { + return td_api::make_object(get_user_id_object(user.first, "closeBirthdayUser"), + user.second.get_birthdate_object()); + })); +} + +td_api::object_ptr UserManager::get_secret_chat_state_object(SecretChatState state) { + switch (state) { + case SecretChatState::Waiting: + return td_api::make_object(); + case SecretChatState::Active: + return td_api::make_object(); + case SecretChatState::Closed: + case SecretChatState::Unknown: + return td_api::make_object(); + default: + UNREACHABLE(); + return nullptr; + } +} + +td_api::object_ptr UserManager::get_update_secret_chat_object(SecretChatId secret_chat_id, + const SecretChat *secret_chat) { + if (secret_chat == nullptr) { + return get_update_unknown_secret_chat_object(secret_chat_id); + } + return td_api::make_object(get_secret_chat_object(secret_chat_id, secret_chat)); +} + +td_api::object_ptr UserManager::get_update_unknown_secret_chat_object( + SecretChatId secret_chat_id) { + return td_api::make_object(td_api::make_object( + secret_chat_id.get(), 0, get_secret_chat_state_object(SecretChatState::Unknown), false, string(), 0)); +} + +int32 UserManager::get_secret_chat_id_object(SecretChatId secret_chat_id, const char *source) const { + if (secret_chat_id.is_valid() && get_secret_chat(secret_chat_id) == nullptr && + unknown_secret_chats_.count(secret_chat_id) == 0) { + LOG(ERROR) << "Have no information about " << secret_chat_id << " from " << source; + unknown_secret_chats_.insert(secret_chat_id); + send_closure(G()->td(), &Td::send_update, get_update_unknown_secret_chat_object(secret_chat_id)); + } + return secret_chat_id.get(); +} + +td_api::object_ptr UserManager::get_secret_chat_object(SecretChatId secret_chat_id) { + return get_secret_chat_object(secret_chat_id, get_secret_chat(secret_chat_id)); +} + +td_api::object_ptr UserManager::get_secret_chat_object(SecretChatId secret_chat_id, + const SecretChat *secret_chat) { + if (secret_chat == nullptr) { + return nullptr; + } + get_user_force(secret_chat->user_id, "get_secret_chat_object"); + return get_secret_chat_object_const(secret_chat_id, secret_chat); +} + +td_api::object_ptr UserManager::get_secret_chat_object_const(SecretChatId secret_chat_id, + const SecretChat *secret_chat) const { + return td_api::make_object(secret_chat_id.get(), + get_user_id_object(secret_chat->user_id, "secretChat"), + get_secret_chat_state_object(secret_chat->state), + secret_chat->is_outbound, secret_chat->key_hash, secret_chat->layer); +} + +void UserManager::get_current_state(vector> &updates) const { + for (auto user_id : unknown_users_) { + if (!have_min_user(user_id)) { + updates.push_back(get_update_unknown_user_object(user_id)); + } + } + for (auto secret_chat_id : unknown_secret_chats_) { + if (!have_secret_chat(secret_chat_id)) { + updates.push_back(get_update_unknown_secret_chat_object(secret_chat_id)); + } + } + + users_.foreach([&](const UserId &user_id, const unique_ptr &user) { + updates.push_back(get_update_user_object(user_id, user.get())); + }); + // secret chat objects contain user_id, so they must be sent after users + secret_chats_.foreach([&](const SecretChatId &secret_chat_id, const unique_ptr &secret_chat) { + updates.push_back( + td_api::make_object(get_secret_chat_object_const(secret_chat_id, secret_chat.get()))); + }); + + users_full_.foreach([&](const UserId &user_id, const unique_ptr &user_full) { + updates.push_back(td_api::make_object( + user_id.get(), get_user_full_info_object(user_id, user_full.get()))); + }); + + if (!contact_birthdates_.users_.empty()) { + updates.push_back(get_update_contact_close_birthdays()); + } } } // namespace td diff --git a/td/telegram/UserManager.h b/td/telegram/UserManager.h index f80789af7..e7befda63 100644 --- a/td/telegram/UserManager.h +++ b/td/telegram/UserManager.h @@ -6,23 +6,1106 @@ // #pragma once +#include "td/telegram/AccentColorId.h" +#include "td/telegram/AccessRights.h" +#include "td/telegram/Birthdate.h" +#include "td/telegram/BotCommand.h" +#include "td/telegram/BotMenuButton.h" +#include "td/telegram/ChannelId.h" +#include "td/telegram/Contact.h" +#include "td/telegram/CustomEmojiId.h" +#include "td/telegram/DialogId.h" +#include "td/telegram/DialogLocation.h" +#include "td/telegram/DialogParticipant.h" +#include "td/telegram/EmojiStatus.h" +#include "td/telegram/files/FileId.h" +#include "td/telegram/files/FileSourceId.h" +#include "td/telegram/FolderId.h" +#include "td/telegram/MessageFullId.h" +#include "td/telegram/Photo.h" +#include "td/telegram/PremiumGiftOption.h" +#include "td/telegram/QueryCombiner.h" +#include "td/telegram/QueryMerger.h" +#include "td/telegram/RestrictionReason.h" +#include "td/telegram/SecretChatId.h" +#include "td/telegram/StoryId.h" +#include "td/telegram/td_api.h" +#include "td/telegram/telegram_api.h" +#include "td/telegram/UserId.h" +#include "td/telegram/Usernames.h" + #include "td/actor/actor.h" +#include "td/actor/MultiPromise.h" +#include "td/actor/MultiTimeout.h" #include "td/utils/common.h" +#include "td/utils/FlatHashMap.h" +#include "td/utils/FlatHashSet.h" +#include "td/utils/HashTableUtils.h" +#include "td/utils/Hints.h" +#include "td/utils/Promise.h" +#include "td/utils/Status.h" +#include "td/utils/StringBuilder.h" +#include "td/utils/Time.h" +#include "td/utils/WaitFreeHashMap.h" +#include "td/utils/WaitFreeHashSet.h" + +#include +#include +#include namespace td { +struct BinlogEvent; +class BusinessAwayMessage; +class BusinessGreetingMessage; +class BusinessInfo; +class BusinessIntro; +class BusinessWorkHours; class Td; class UserManager final : public Actor { public: UserManager(Td *td, ActorShared<> parent); + UserManager(const UserManager &) = delete; + UserManager &operator=(const UserManager &) = delete; + UserManager(UserManager &&) = delete; + UserManager &operator=(UserManager &&) = delete; + ~UserManager() final; + + static UserId get_user_id(const telegram_api::object_ptr &user); + + static UserId load_my_id(); + + UserId get_my_id() const; + + static UserId get_service_notifications_user_id(); + + UserId add_service_notifications_user(); + + static UserId get_replies_bot_user_id(); + + static UserId get_anonymous_bot_user_id(); + + static UserId get_channel_bot_user_id(); + + static UserId get_anti_spam_bot_user_id(); + + UserId add_anonymous_bot_user(); + + UserId add_channel_bot_user(); + + struct MyOnlineStatusInfo { + bool is_online_local = false; + bool is_online_remote = false; + int32 was_online_local = 0; + int32 was_online_remote = 0; + }; + MyOnlineStatusInfo get_my_online_status() const; + + void set_my_online_status(bool is_online, bool send_update, bool is_local); + + void on_get_user(telegram_api::object_ptr &&user, const char *source); + + void on_get_users(vector> &&users, const char *source); + + void on_binlog_user_event(BinlogEvent &&event); + + void on_binlog_secret_chat_event(BinlogEvent &&event); + + void on_update_user_name(UserId user_id, string &&first_name, string &&last_name, Usernames &&usernames); + + void on_update_user_phone_number(UserId user_id, string &&phone_number); + + void register_suggested_profile_photo(const Photo &photo); + + void on_update_user_emoji_status(UserId user_id, telegram_api::object_ptr &&emoji_status); + + void on_update_user_story_ids(UserId user_id, StoryId max_active_story_id, StoryId max_read_story_id); + + void on_update_user_max_read_story_id(UserId user_id, StoryId max_read_story_id); + + void on_update_user_stories_hidden(UserId user_id, bool stories_hidden); + + void on_update_user_online(UserId user_id, telegram_api::object_ptr &&status); + + void on_update_user_local_was_online(UserId user_id, int32 local_was_online); + + // use on_update_dialog_is_blocked instead + void on_update_user_is_blocked(UserId user_id, bool is_blocked, bool is_blocked_for_stories); + + void on_update_user_has_pinned_stories(UserId user_id, bool has_pinned_stories); + + void on_update_user_common_chat_count(UserId user_id, int32 common_chat_count); + + void on_update_user_location(UserId user_id, DialogLocation &&location); + + void on_update_user_work_hours(UserId user_id, BusinessWorkHours &&work_hours); + + void on_update_user_away_message(UserId user_id, BusinessAwayMessage &&away_message); + + void on_update_user_greeting_message(UserId user_id, BusinessGreetingMessage &&greeting_message); + + void on_update_user_intro(UserId user_id, BusinessIntro &&intro); + + void on_update_user_commands(UserId user_id, + vector> &&bot_commands); + + void on_update_user_need_phone_number_privacy_exception(UserId user_id, bool need_phone_number_privacy_exception); + + void on_update_user_wallpaper_overridden(UserId user_id, bool wallpaper_overridden); + + void on_update_bot_menu_button(UserId bot_user_id, + telegram_api::object_ptr &&bot_menu_button); + + void on_update_secret_chat(SecretChatId secret_chat_id, int64 access_hash, UserId user_id, SecretChatState state, + bool is_outbound, int32 ttl, int32 date, string key_hash, int32 layer, + FolderId initial_folder_id); + + void on_update_online_status_privacy(); + + void on_update_phone_number_privacy(); + + void on_ignored_restriction_reasons_changed(); + + void invalidate_user_full(UserId user_id); + + bool have_user(UserId user_id) const; + + bool have_min_user(UserId user_id) const; + + bool have_user_force(UserId user_id, const char *source); + + static void send_get_me_query(Td *td, Promise &&promise); + + UserId get_me(Promise &&promise); + + bool get_user(UserId user_id, int left_tries, Promise &&promise); + + void reload_user(UserId user_id, Promise &&promise, const char *source); + + Result> get_input_user(UserId user_id) const; + + telegram_api::object_ptr get_input_user_force(UserId user_id) const; + + bool have_input_peer_user(UserId user_id, AccessRights access_rights) const; + + telegram_api::object_ptr get_input_peer_user(UserId user_id, + AccessRights access_rights) const; + + bool have_input_encrypted_peer(SecretChatId secret_chat_id, AccessRights access_rights) const; + + telegram_api::object_ptr get_input_encrypted_chat(SecretChatId secret_chat_id, + AccessRights access_rights) const; + + bool is_user_contact(UserId user_id, bool is_mutual = false) const; + + bool is_user_premium(UserId user_id) const; + + bool is_user_deleted(UserId user_id) const; + + bool is_user_support(UserId user_id) const; + + bool is_user_bot(UserId user_id) const; + + struct BotData { + string username; + bool can_be_edited; + bool can_join_groups; + bool can_read_all_group_messages; + bool is_inline; + bool is_business; + bool need_location; + bool can_be_added_to_attach_menu; + }; + Result get_bot_data(UserId user_id) const TD_WARN_UNUSED_RESULT; + + bool is_user_online(UserId user_id, int32 tolerance = 0, int32 unix_time = 0) const; + + int32 get_user_was_online(UserId user_id, int32 unix_time = 0) const; + + bool is_user_status_exact(UserId user_id) const; + + bool is_user_received_from_server(UserId user_id) const; + + bool can_report_user(UserId user_id) const; + + const DialogPhoto *get_user_dialog_photo(UserId user_id); + + const DialogPhoto *get_secret_chat_dialog_photo(SecretChatId secret_chat_id); + + int32 get_user_accent_color_id_object(UserId user_id) const; + + int32 get_secret_chat_accent_color_id_object(SecretChatId secret_chat_id) const; + + CustomEmojiId get_user_background_custom_emoji_id(UserId user_id) const; + + CustomEmojiId get_secret_chat_background_custom_emoji_id(SecretChatId secret_chat_id) const; + + int32 get_user_profile_accent_color_id_object(UserId user_id) const; + + int32 get_secret_chat_profile_accent_color_id_object(SecretChatId secret_chat_id) const; + + CustomEmojiId get_user_profile_background_custom_emoji_id(UserId user_id) const; + + CustomEmojiId get_secret_chat_profile_background_custom_emoji_id(SecretChatId secret_chat_id) const; + + string get_user_title(UserId user_id) const; + + string get_secret_chat_title(SecretChatId secret_chat_id) const; + + RestrictedRights get_user_default_permissions(UserId user_id) const; + + RestrictedRights get_secret_chat_default_permissions(SecretChatId secret_chat_id) const; + + td_api::object_ptr get_user_emoji_status_object(UserId user_id) const; + + td_api::object_ptr get_secret_chat_emoji_status_object(SecretChatId secret_chat_id) const; + + bool get_user_stories_hidden(UserId user_id) const; + + bool can_poll_user_active_stories(UserId user_id) const; + + string get_user_about(UserId user_id); + + string get_secret_chat_about(SecretChatId secret_chat_id); + + string get_user_private_forward_name(UserId user_id); + + bool get_user_voice_messages_forbidden(UserId user_id) const; + + bool get_user_read_dates_private(UserId user_id); + + string get_user_search_text(UserId user_id) const; + + void for_each_secret_chat_with_user(UserId user_id, const std::function &f); + + string get_user_first_username(UserId user_id) const; + + int32 get_secret_chat_date(SecretChatId secret_chat_id) const; + + int32 get_secret_chat_ttl(SecretChatId secret_chat_id) const; + + UserId get_secret_chat_user_id(SecretChatId secret_chat_id) const; + + bool get_secret_chat_is_outbound(SecretChatId secret_chat_id) const; + + SecretChatState get_secret_chat_state(SecretChatId secret_chat_id) const; + + int32 get_secret_chat_layer(SecretChatId secret_chat_id) const; + + FolderId get_secret_chat_initial_folder_id(SecretChatId secret_chat_id) const; + + vector get_bot_commands(vector> &&bot_infos, + const vector *participants); + + void set_name(const string &first_name, const string &last_name, Promise &&promise); + + void set_bio(const string &bio, Promise &&promise); + + void on_update_profile_success(int32 flags, const string &first_name, const string &last_name, const string &about); + + FileId get_profile_photo_file_id(int64 photo_id) const; + + void set_bot_profile_photo(UserId bot_user_id, const td_api::object_ptr &input_photo, + Promise &&promise); + + void set_profile_photo(const td_api::object_ptr &input_photo, bool is_fallback, + Promise &&promise); + + void set_user_profile_photo(UserId user_id, const td_api::object_ptr &input_photo, + bool only_suggest, Promise &&promise); + + void send_update_profile_photo_query(UserId user_id, FileId file_id, int64 old_photo_id, bool is_fallback, + Promise &&promise); + + void on_set_profile_photo(UserId user_id, telegram_api::object_ptr &&photo, + bool is_fallback, int64 old_photo_id, Promise &&promise); + + void delete_profile_photo(int64 profile_photo_id, bool is_recursive, Promise &&promise); + + void on_delete_profile_photo(int64 profile_photo_id, Promise promise); + + void set_username(const string &username, Promise &&promise); + + void toggle_username_is_active(string &&username, bool is_active, Promise &&promise); + + void reorder_usernames(vector &&usernames, Promise &&promise); + + void toggle_bot_username_is_active(UserId bot_user_id, string &&username, bool is_active, Promise &&promise); + + void reorder_bot_usernames(UserId bot_user_id, vector &&usernames, Promise &&promise); + + void on_update_username_is_active(UserId user_id, string &&username, bool is_active, Promise &&promise); + + void on_update_active_usernames_order(UserId user_id, vector &&usernames, Promise &&promise); + + void set_accent_color(AccentColorId accent_color_id, CustomEmojiId background_custom_emoji_id, + Promise &&promise); + + void set_profile_accent_color(AccentColorId accent_color_id, CustomEmojiId background_custom_emoji_id, + Promise &&promise); + + void on_update_accent_color_success(bool for_profile, AccentColorId accent_color_id, + CustomEmojiId background_custom_emoji_id); + + void set_birthdate(Birthdate &&birthdate, Promise &&promise); + + void set_personal_channel(DialogId dialog_id, Promise &&promise); + + void set_emoji_status(const EmojiStatus &emoji_status, Promise &&promise); + + void get_support_user(Promise> &&promise); + + void get_user_profile_photos(UserId user_id, int32 offset, int32 limit, + Promise> &&promise); + + void reload_user_profile_photo(UserId user_id, int64 photo_id, Promise &&promise); + + FileSourceId get_user_profile_photo_file_source_id(UserId user_id, int64 photo_id); + + void on_get_user_photos(UserId user_id, int32 offset, int32 limit, int32 total_count, + vector> photos); + + void register_message_users(MessageFullId message_full_id, vector user_ids); + + void unregister_message_users(MessageFullId message_full_id, vector user_ids); + + void can_send_message_to_user(UserId user_id, bool force, + Promise> &&promise); + + void on_get_is_premium_required_to_contact_users(vector &&user_ids, vector &&is_premium_required, + Promise &&promise); + + void allow_send_message_to_user(UserId user_id); + + void share_phone_number(UserId user_id, Promise &&promise); + + void reload_contacts(bool force); + + void on_get_contacts(telegram_api::object_ptr &&new_contacts); + + void on_get_contacts_failed(Status error); + + void on_get_contacts_statuses(vector> &&statuses); + + void add_contact(Contact contact, bool share_phone_number, Promise &&promise); + + std::pair, vector> import_contacts(const vector &contacts, int64 &random_id, + Promise &&promise); + + void on_imported_contacts(int64 random_id, + Result> result); + + void remove_contacts(const vector &user_ids, Promise &&promise); + + void remove_contacts_by_phone_number(vector user_phone_numbers, vector user_ids, + Promise &&promise); + + void on_deleted_contacts(const vector &deleted_contact_user_ids); + + int32 get_imported_contact_count(Promise &&promise); + + std::pair, vector> change_imported_contacts(vector &contacts, int64 &random_id, + Promise &&promise); + + void clear_imported_contacts(Promise &&promise); + + void on_update_contacts_reset(); + + std::pair> search_contacts(const string &query, int32 limit, Promise &&promise); + + void reload_contact_birthdates(bool force); + + void on_get_contact_birthdates(telegram_api::object_ptr &&birthdays); + + vector get_close_friends(Promise &&promise); + + void set_close_friends(vector user_ids, Promise &&promise); + + void on_set_close_friends(const vector &user_ids, Promise &&promise); + + UserId search_user_by_phone_number(string phone_number, Promise &&promise); + + void on_resolved_phone_number(const string &phone_number, UserId user_id); + + void load_user_full(UserId user_id, bool force, Promise &&promise, const char *source); + + void reload_user_full(UserId user_id, Promise &&promise, const char *source); + + void on_get_user_full(telegram_api::object_ptr &&user); + + FileSourceId get_user_full_file_source_id(UserId user_id); + + bool have_secret_chat(SecretChatId secret_chat_id) const; + + bool have_secret_chat_force(SecretChatId secret_chat_id, const char *source); + + bool get_secret_chat(SecretChatId secret_chat_id, bool force, Promise &&promise); + + void create_new_secret_chat(UserId user_id, Promise> &&promise); + + int64 get_user_id_object(UserId user_id, const char *source) const; + + td_api::object_ptr get_user_object(UserId user_id) const; + + vector get_user_ids_object(const vector &user_ids, const char *source) const; + + td_api::object_ptr get_users_object(int32 total_count, const vector &user_ids) const; + + td_api::object_ptr get_user_full_info_object(UserId user_id) const; + + int32 get_secret_chat_id_object(SecretChatId secret_chat_id, const char *source) const; + + td_api::object_ptr get_secret_chat_object(SecretChatId secret_chat_id); + + void get_current_state(vector> &updates) const; private: + struct User { + string first_name; + string last_name; + Usernames usernames; + string phone_number; + int64 access_hash = -1; + EmojiStatus emoji_status; + EmojiStatus last_sent_emoji_status; + + ProfilePhoto photo; + + vector restriction_reasons; + string inline_query_placeholder; + int32 bot_info_version = -1; + + AccentColorId accent_color_id; + CustomEmojiId background_custom_emoji_id; + AccentColorId profile_accent_color_id; + CustomEmojiId profile_background_custom_emoji_id; + + int32 was_online = 0; + int32 local_was_online = 0; + + double max_active_story_id_next_reload_time = 0.0; + StoryId max_active_story_id; + StoryId max_read_story_id; + + string language_code; + + FlatHashSet photo_ids; + + static constexpr uint32 CACHE_VERSION = 4; + uint32 cache_version = 0; + + bool is_min_access_hash = true; + bool is_received = false; + bool is_verified = false; + bool is_premium = false; + bool is_support = false; + bool is_deleted = true; + bool is_bot = true; + bool can_join_groups = true; + bool can_read_all_group_messages = true; + bool can_be_edited_bot = false; + bool is_inline_bot = false; + bool is_business_bot = false; + bool need_location_bot = false; + bool is_scam = false; + bool is_fake = false; + bool is_contact = false; + bool is_mutual_contact = false; + bool is_close_friend = false; + bool need_apply_min_photo = false; + bool can_be_added_to_attach_menu = false; + bool attach_menu_enabled = false; + bool stories_hidden = false; + bool contact_require_premium = false; + + bool is_photo_inited = false; + + bool is_repaired = false; // whether cached value is rechecked + + bool is_name_changed = true; + bool is_username_changed = true; + bool is_photo_changed = true; + bool is_accent_color_changed = true; + bool is_phone_number_changed = true; + bool is_emoji_status_changed = true; + bool is_is_contact_changed = true; + bool is_is_mutual_contact_changed = true; + bool is_is_deleted_changed = true; + bool is_is_premium_changed = true; + bool is_stories_hidden_changed = true; + bool is_full_info_changed = false; + bool is_being_updated = false; + bool is_changed = true; // have new changes that need to be sent to the client and database + bool need_save_to_database = true; // have new changes that need only to be saved to the database + bool is_status_changed = true; + bool is_online_status_changed = true; // whether online/offline has changed + bool is_update_user_sent = false; + + bool is_saved = false; // is current user version being saved/is saved to the database + bool is_being_saved = false; // is current user being saved to the database + bool is_status_saved = false; // is current user status being saved/is saved to the database + + bool is_received_from_server = false; // true, if the user was received from the server and not the database + + uint64 log_event_id = 0; + + template + void store(StorerT &storer) const; + + template + void parse(ParserT &parser); + }; + + // do not forget to update drop_user_full and on_get_user_full + struct UserFull { + Photo photo; + Photo fallback_photo; + Photo personal_photo; + + string about; + string private_forward_name; + string description; + Photo description_photo; + FileId description_animation_file_id; + vector registered_file_ids; + FileSourceId file_source_id; + + vector premium_gift_options; + + unique_ptr menu_button; + vector commands; + AdministratorRights group_administrator_rights; + AdministratorRights broadcast_administrator_rights; + + int32 common_chat_count = 0; + Birthdate birthdate; + + ChannelId personal_channel_id; + + unique_ptr business_info; + + bool is_blocked = false; + bool is_blocked_for_stories = false; + bool can_be_called = false; + bool supports_video_calls = false; + bool has_private_calls = false; + bool can_pin_messages = true; + bool need_phone_number_privacy_exception = false; + bool wallpaper_overridden = false; + bool voice_messages_forbidden = false; + bool has_pinned_stories = false; + bool read_dates_private = false; + bool contact_require_premium = false; + + bool is_common_chat_count_changed = true; + bool is_being_updated = false; + bool is_changed = true; // have new changes that need to be sent to the client and database + bool need_send_update = true; // have new changes that need only to be sent to the client + bool need_save_to_database = true; // have new changes that need only to be saved to the database + bool is_update_user_full_sent = false; + + double expires_at = 0.0; + + bool is_expired() const { + return expires_at < Time::now(); + } + + template + void store(StorerT &storer) const; + + template + void parse(ParserT &parser); + }; + + struct SecretChat { + int64 access_hash = 0; + UserId user_id; + SecretChatState state = SecretChatState::Unknown; + string key_hash; + int32 ttl = 0; + int32 date = 0; + int32 layer = 0; + FolderId initial_folder_id; + + bool is_outbound = false; + + bool is_ttl_changed = true; + bool is_state_changed = true; + bool is_being_updated = false; + bool is_changed = true; // have new changes that need to be sent to the client and database + bool need_save_to_database = true; // have new changes that need only to be saved to the database + + bool is_saved = false; // is current secret chat version being saved/is saved to the database + bool is_being_saved = false; // is current secret chat being saved to the database + + uint64 log_event_id = 0; + + template + void store(StorerT &storer) const; + + template + void parse(ParserT &parser); + }; + + struct PendingGetPhotoRequest { + int32 offset = 0; + int32 limit = 0; + int32 retry_count = 0; + Promise> promise; + }; + + struct UserPhotos { + vector photos; + int32 count = -1; + int32 offset = -1; + + vector pending_requests; + }; + + class UserLogEvent; + class SecretChatLogEvent; + + static constexpr int32 MAX_GET_PROFILE_PHOTOS = 100; // server side limit + static constexpr size_t MAX_NAME_LENGTH = 64; // server side limit for first/last name + + static constexpr int32 MAX_ACTIVE_STORY_ID_RELOAD_TIME = 3600; // some reasonable limit + + // the True fields aren't set for manually created telegram_api::user objects, therefore the flags must be used + static constexpr int32 USER_FLAG_HAS_ACCESS_HASH = 1 << 0; + static constexpr int32 USER_FLAG_HAS_FIRST_NAME = 1 << 1; + static constexpr int32 USER_FLAG_HAS_LAST_NAME = 1 << 2; + static constexpr int32 USER_FLAG_HAS_USERNAME = 1 << 3; + static constexpr int32 USER_FLAG_HAS_PHONE_NUMBER = 1 << 4; + static constexpr int32 USER_FLAG_HAS_PHOTO = 1 << 5; + static constexpr int32 USER_FLAG_HAS_STATUS = 1 << 6; + static constexpr int32 USER_FLAG_HAS_BOT_INFO_VERSION = 1 << 14; + static constexpr int32 USER_FLAG_IS_ME = 1 << 10; + static constexpr int32 USER_FLAG_IS_CONTACT = 1 << 11; + static constexpr int32 USER_FLAG_IS_MUTUAL_CONTACT = 1 << 12; + static constexpr int32 USER_FLAG_IS_DELETED = 1 << 13; + static constexpr int32 USER_FLAG_IS_BOT = 1 << 14; + static constexpr int32 USER_FLAG_IS_BOT_WITH_PRIVACY_DISABLED = 1 << 15; + static constexpr int32 USER_FLAG_IS_PRIVATE_BOT = 1 << 16; + static constexpr int32 USER_FLAG_IS_VERIFIED = 1 << 17; + static constexpr int32 USER_FLAG_IS_RESTRICTED = 1 << 18; + static constexpr int32 USER_FLAG_IS_INLINE_BOT = 1 << 19; + static constexpr int32 USER_FLAG_IS_INACCESSIBLE = 1 << 20; + static constexpr int32 USER_FLAG_NEED_LOCATION_BOT = 1 << 21; + static constexpr int32 USER_FLAG_HAS_LANGUAGE_CODE = 1 << 22; + static constexpr int32 USER_FLAG_IS_SUPPORT = 1 << 23; + static constexpr int32 USER_FLAG_IS_SCAM = 1 << 24; + static constexpr int32 USER_FLAG_NEED_APPLY_MIN_PHOTO = 1 << 25; + static constexpr int32 USER_FLAG_IS_FAKE = 1 << 26; + static constexpr int32 USER_FLAG_IS_ATTACH_MENU_BOT = 1 << 27; + static constexpr int32 USER_FLAG_IS_PREMIUM = 1 << 28; + static constexpr int32 USER_FLAG_ATTACH_MENU_ENABLED = 1 << 29; + static constexpr int32 USER_FLAG_HAS_EMOJI_STATUS = 1 << 30; + static constexpr int32 USER_FLAG_HAS_USERNAMES = 1 << 0; + static constexpr int32 USER_FLAG_CAN_BE_EDITED_BOT = 1 << 1; + static constexpr int32 USER_FLAG_IS_CLOSE_FRIEND = 1 << 2; + + static constexpr int32 USER_FULL_EXPIRE_TIME = 60; + + static constexpr int32 ACCOUNT_UPDATE_FIRST_NAME = 1 << 0; + static constexpr int32 ACCOUNT_UPDATE_LAST_NAME = 1 << 1; + static constexpr int32 ACCOUNT_UPDATE_ABOUT = 1 << 2; + void tear_down() final; + static void on_user_online_timeout_callback(void *user_manager_ptr, int64 user_id_long); + + void on_user_online_timeout(UserId user_id); + + static void on_user_emoji_status_timeout_callback(void *user_manager_ptr, int64 user_id_long); + + void on_user_emoji_status_timeout(UserId user_id); + + void set_my_id(UserId my_id); + + const User *get_user(UserId user_id) const; + + User *get_user(UserId user_id); + + User *add_user(UserId user_id); + + void save_user(User *u, UserId user_id, bool from_binlog); + + static string get_user_database_key(UserId user_id); + + static string get_user_database_value(const User *u); + + void save_user_to_database(User *u, UserId user_id); + + void save_user_to_database_impl(User *u, UserId user_id, string value); + + void on_save_user_to_database(UserId user_id, bool success); + + void load_user_from_database(User *u, UserId user_id, Promise promise); + + void load_user_from_database_impl(UserId user_id, Promise promise); + + void on_load_user_from_database(UserId user_id, string value, bool force); + + User *get_user_force(UserId user_id, const char *source); + + User *get_user_force_impl(UserId user_id, const char *source); + + bool is_user_contact(const User *u, UserId user_id, bool is_mutual) const; + + static bool is_user_premium(const User *u); + + static bool is_user_deleted(const User *u); + + static bool is_user_support(const User *u); + + static bool is_user_bot(const User *u); + + int32 get_user_was_online(const User *u, UserId user_id, int32 unix_time) const; + + void on_update_user_name(User *u, UserId user_id, string &&first_name, string &&last_name); + + void on_update_user_usernames(User *u, UserId user_id, Usernames &&usernames); + + void on_update_user_phone_number(User *u, UserId user_id, string &&phone_number); + + void on_update_user_photo(User *u, UserId user_id, telegram_api::object_ptr &&photo, + const char *source); + + void do_update_user_photo(User *u, UserId user_id, telegram_api::object_ptr &&photo, + const char *source); + + void do_update_user_photo(User *u, UserId user_id, ProfilePhoto &&new_photo, bool invalidate_photo_cache, + const char *source); + + void register_user_photo(User *u, UserId user_id, const Photo &photo); + + void on_update_user_accent_color_id(User *u, UserId user_id, AccentColorId accent_color_id); + + void on_update_user_background_custom_emoji_id(User *u, UserId user_id, CustomEmojiId background_custom_emoji_id); + + void on_update_user_profile_accent_color_id(User *u, UserId user_id, AccentColorId accent_color_id); + + void on_update_user_profile_background_custom_emoji_id(User *u, UserId user_id, + CustomEmojiId background_custom_emoji_id); + + void on_update_user_emoji_status(User *u, UserId user_id, EmojiStatus emoji_status); + + void on_update_user_story_ids_impl(User *u, UserId user_id, StoryId max_active_story_id, StoryId max_read_story_id); + + void on_update_user_max_read_story_id(User *u, UserId user_id, StoryId max_read_story_id); + + void on_update_user_stories_hidden(User *u, UserId user_id, bool stories_hidden); + + void on_update_user_is_contact(User *u, UserId user_id, bool is_contact, bool is_mutual_contact, + bool is_close_friend); + + void on_update_user_online(User *u, UserId user_id, telegram_api::object_ptr &&status); + + void on_update_user_local_was_online(User *u, UserId user_id, int32 local_was_online); + + static void on_update_user_full_is_blocked(UserFull *user_full, UserId user_id, bool is_blocked, + bool is_blocked_for_stories); + + static void on_update_user_full_common_chat_count(UserFull *user_full, UserId user_id, int32 common_chat_count); + + static void on_update_user_full_location(UserFull *user_full, UserId user_id, DialogLocation &&location); + + static void on_update_user_full_work_hours(UserFull *user_full, UserId user_id, BusinessWorkHours &&work_hours); + + void on_update_user_full_away_message(UserFull *user_full, UserId user_id, BusinessAwayMessage &&away_message) const; + + void on_update_user_full_greeting_message(UserFull *user_full, UserId user_id, + BusinessGreetingMessage &&greeting_message) const; + + static void on_update_user_full_intro(UserFull *user_full, UserId user_id, BusinessIntro &&intro); + + static void on_update_user_full_commands(UserFull *user_full, UserId user_id, + vector> &&bot_commands); + + void on_update_user_full_need_phone_number_privacy_exception(UserFull *user_full, UserId user_id, + bool need_phone_number_privacy_exception) const; + + void on_update_user_full_wallpaper_overridden(UserFull *user_full, UserId user_id, bool wallpaper_overridden) const; + + static void on_update_user_full_menu_button(UserFull *user_full, UserId user_id, + telegram_api::object_ptr &&bot_menu_button); + + bool have_input_peer_user(const User *u, UserId user_id, AccessRights access_rights) const; + + static bool have_input_encrypted_peer(const SecretChat *secret_chat, AccessRights access_rights); + + bool need_poll_user_active_stories(const User *u, UserId user_id) const; + + static string get_user_search_text(const User *u); + + void set_profile_photo_impl(UserId user_id, const td_api::object_ptr &input_photo, + bool is_fallback, bool only_suggest, Promise &&promise); + + void upload_profile_photo(UserId user_id, FileId file_id, bool is_fallback, bool only_suggest, bool is_animation, + double main_frame_timestamp, Promise &&promise, int reupload_count = 0, + vector bad_parts = {}); + + void on_upload_profile_photo(FileId file_id, telegram_api::object_ptr input_file); + + void on_upload_profile_photo_error(FileId file_id, Status status); + + void add_set_profile_photo_to_cache(UserId user_id, Photo &&photo, bool is_fallback); + + bool delete_my_profile_photo_from_cache(int64 profile_photo_id); + + void toggle_username_is_active_impl(string &&username, bool is_active, Promise &&promise); + + void reorder_usernames_impl(vector &&usernames, Promise &&promise); + + void on_set_birthdate(Birthdate birthdate, Promise &&promise); + + void on_set_personal_channel(ChannelId channel_id, Promise &&promise); + + void on_set_emoji_status(EmojiStatus emoji_status, Promise &&promise); + + void on_get_support_user(UserId user_id, Promise> &&promise); + + void send_get_user_photos_query(UserId user_id, const UserPhotos *user_photos); + + void on_get_user_profile_photos(UserId user_id, Result &&result); + + UserPhotos *add_user_photos(UserId user_id); + + void apply_pending_user_photo(User *u, UserId user_id); + + void load_contacts(Promise &&promise); + + int64 get_contacts_hash(); + + void save_next_contacts_sync_date(); + + void save_contacts_to_database(); + + void on_load_contacts_from_database(string value); + + void on_get_contacts_finished(size_t expected_contact_count); + + void do_import_contacts(vector contacts, int64 random_id, Promise &&promise); + + void on_import_contacts_finished(int64 random_id, vector imported_contact_user_ids, + vector unimported_contact_invites); + + void load_imported_contacts(Promise &&promise); + + void on_load_imported_contacts_from_database(string value); + + void on_load_imported_contacts_finished(); + + void on_clear_imported_contacts(vector &&contacts, vector contacts_unique_id, + std::pair, vector> &&to_add, Promise &&promise); + + void update_contacts_hints(const User *u, UserId user_id, bool from_database); + + const UserFull *get_user_full(UserId user_id) const; + + UserFull *get_user_full(UserId user_id); + + UserFull *add_user_full(UserId user_id); + + UserFull *get_user_full_force(UserId user_id, const char *source); + + void send_get_user_full_query(UserId user_id, telegram_api::object_ptr &&input_user, + Promise &&promise, const char *source); + + static void save_user_full(const UserFull *user_full, UserId user_id); + + static string get_user_full_database_key(UserId user_id); + + static string get_user_full_database_value(const UserFull *user_full); + + void on_load_user_full_from_database(UserId user_id, string value); + + int64 get_user_full_profile_photo_id(const UserFull *user_full); + + void drop_user_full_photos(UserFull *user_full, UserId user_id, int64 expected_photo_id, const char *source); + + void drop_user_photos(UserId user_id, bool is_empty, const char *source); + + void drop_user_full(UserId user_id); + + const SecretChat *get_secret_chat(SecretChatId secret_chat_id) const; + + SecretChat *get_secret_chat(SecretChatId secret_chat_id); + + SecretChat *add_secret_chat(SecretChatId secret_chat_id); + + SecretChat *get_secret_chat_force(SecretChatId secret_chat_id, const char *source); + + void save_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog); + + static string get_secret_chat_database_key(SecretChatId secret_chat_id); + + static string get_secret_chat_database_value(const SecretChat *c); + + void save_secret_chat_to_database(SecretChat *c, SecretChatId secret_chat_id); + + void save_secret_chat_to_database_impl(SecretChat *c, SecretChatId secret_chat_id, string value); + + void on_save_secret_chat_to_database(SecretChatId secret_chat_id, bool success); + + void load_secret_chat_from_database(SecretChat *c, SecretChatId secret_chat_id, Promise promise); + + void load_secret_chat_from_database_impl(SecretChatId secret_chat_id, Promise promise); + + void on_load_secret_chat_from_database(SecretChatId secret_chat_id, string value, bool force); + + void on_create_new_secret_chat(SecretChatId secret_chat_id, Promise> &&promise); + + void update_user(User *u, UserId user_id, bool from_binlog = false, bool from_database = false); + + void update_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog = false, + bool from_database = false); + + void update_user_full(UserFull *user_full, UserId user_id, const char *source, bool from_database = false); + + td_api::object_ptr get_user_status_object(UserId user_id, const User *u, int32 unix_time) const; + + static bool get_user_has_unread_stories(const User *u); + + td_api::object_ptr get_update_user_object(UserId user_id, const User *u) const; + + td_api::object_ptr get_update_unknown_user_object(UserId user_id) const; + + td_api::object_ptr get_user_object(UserId user_id, const User *u) const; + + td_api::object_ptr get_user_full_info_object(UserId user_id, const UserFull *user_full) const; + + td_api::object_ptr get_update_contact_close_birthdays() const; + + static td_api::object_ptr get_secret_chat_state_object(SecretChatState state); + + td_api::object_ptr get_update_secret_chat_object(SecretChatId secret_chat_id, + const SecretChat *secret_chat); + + static td_api::object_ptr get_update_unknown_secret_chat_object( + SecretChatId secret_chat_id); + + td_api::object_ptr get_secret_chat_object(SecretChatId secret_chat_id, + const SecretChat *secret_chat); + + td_api::object_ptr get_secret_chat_object_const(SecretChatId secret_chat_id, + const SecretChat *secret_chat) const; + Td *td_; ActorShared<> parent_; + UserId my_id_; + UserId support_user_id_; + int32 my_was_online_local_ = 0; + + WaitFreeHashMap, UserIdHash> users_; + WaitFreeHashMap, UserIdHash> users_full_; + WaitFreeHashMap, UserIdHash> user_photos_; + mutable FlatHashSet unknown_users_; + WaitFreeHashMap, UserIdHash> pending_user_photos_; + struct UserIdPhotoIdHash { + uint32 operator()(const std::pair &pair) const { + return combine_hashes(UserIdHash()(pair.first), Hash()(pair.second)); + } + }; + WaitFreeHashMap, FileSourceId, UserIdPhotoIdHash> user_profile_photo_file_source_ids_; + FlatHashMap my_photo_file_id_; + WaitFreeHashMap user_full_file_source_ids_; + + WaitFreeHashMap, SecretChatIdHash> secret_chats_; + mutable FlatHashSet unknown_secret_chats_; + + FlatHashMap, UserIdHash> secret_chats_with_user_; + + FlatHashMap>, UserIdHash> load_user_from_database_queries_; + FlatHashSet loaded_from_database_users_; + FlatHashSet unavailable_user_fulls_; + + FlatHashMap>, SecretChatIdHash> load_secret_chat_from_database_queries_; + FlatHashSet loaded_from_database_secret_chats_; + + QueryMerger get_user_queries_{"GetUserMerger", 3, 50}; + + QueryMerger get_is_premium_required_to_contact_queries_{"GetIsPremiumRequiredToContactMerger", 3, 100}; + + QueryCombiner get_user_full_queries_{"GetUserFullCombiner", 2.0}; + class UploadProfilePhotoCallback; + std::shared_ptr upload_profile_photo_callback_; + + struct UploadedProfilePhoto { + UserId user_id; + bool is_fallback; + bool only_suggest; + double main_frame_timestamp; + bool is_animation; + int reupload_count; + Promise promise; + + UploadedProfilePhoto(UserId user_id, bool is_fallback, bool only_suggest, double main_frame_timestamp, + bool is_animation, int32 reupload_count, Promise promise) + : user_id(user_id) + , is_fallback(is_fallback) + , only_suggest(only_suggest) + , main_frame_timestamp(main_frame_timestamp) + , is_animation(is_animation) + , reupload_count(reupload_count) + , promise(std::move(promise)) { + } + }; + FlatHashMap uploaded_profile_photos_; + + struct ImportContactsTask { + Promise promise_; + vector input_contacts_; + vector imported_user_ids_; + vector unimported_contact_invites_; + }; + FlatHashMap> import_contact_tasks_; + + FlatHashMap, vector>> imported_contacts_; + + FlatHashMap resolved_phone_numbers_; + + FlatHashMap, UserIdHash> user_messages_; + + bool are_contacts_loaded_ = false; + int32 next_contacts_sync_date_ = 0; + Hints contacts_hints_; // search contacts by first name, last name and usernames + vector> load_contacts_queries_; + MultiPromiseActor load_contact_users_multipromise_{"LoadContactUsersMultiPromiseActor"}; + int32 saved_contact_count_ = -1; + + int32 was_online_local_ = 0; + int32 was_online_remote_ = 0; + + bool are_imported_contacts_loaded_ = false; + vector> load_imported_contacts_queries_; + MultiPromiseActor load_imported_contact_users_multipromise_{"LoadImportedContactUsersMultiPromiseActor"}; + vector all_imported_contacts_; + bool are_imported_contacts_changing_ = false; + bool need_clear_imported_contacts_ = false; + + FlatHashMap user_full_contact_require_premium_; + + WaitFreeHashSet restricted_user_ids_; + + struct ContactBirthdates { + vector> users_; + double next_sync_time_ = 0.0; + bool is_being_synced_ = false; + }; + ContactBirthdates contact_birthdates_; + + vector next_all_imported_contacts_; + vector imported_contacts_unique_id_; + vector imported_contacts_pos_; + + vector imported_contact_user_ids_; // result of change_imported_contacts + vector unimported_contact_invites_; // result of change_imported_contacts + + MultiTimeout user_online_timeout_{"UserOnlineTimeout"}; + MultiTimeout user_emoji_status_timeout_{"UserEmojiStatusTimeout"}; }; } // namespace td diff --git a/td/telegram/UserPrivacySettingRule.cpp b/td/telegram/UserPrivacySettingRule.cpp index 0b92616b0..f2402b4f2 100644 --- a/td/telegram/UserPrivacySettingRule.cpp +++ b/td/telegram/UserPrivacySettingRule.cpp @@ -12,6 +12,7 @@ #include "td/telegram/Dependencies.h" #include "td/telegram/DialogManager.h" #include "td/telegram/Td.h" +#include "td/telegram/UserManager.h" #include "td/utils/algorithm.h" #include "td/utils/logging.h" @@ -131,7 +132,7 @@ UserPrivacySettingRule::UserPrivacySettingRule(Td *td, UNREACHABLE(); } td::remove_if(user_ids_, [td](UserId user_id) { - if (!td->contacts_manager_->have_user(user_id)) { + if (!td->user_manager_->have_user(user_id)) { LOG(ERROR) << "Receive unknown " << user_id; return true; } @@ -171,7 +172,7 @@ td_api::object_ptr UserPrivacySettingRule::get_u return make_tl_object(); case Type::AllowUsers: return make_tl_object( - td->contacts_manager_->get_user_ids_object(user_ids_, "userPrivacySettingRuleAllowUsers")); + td->user_manager_->get_user_ids_object(user_ids_, "userPrivacySettingRuleAllowUsers")); case Type::AllowChatParticipants: return make_tl_object( td->dialog_manager_->get_chat_ids_object(dialog_ids_, "UserPrivacySettingRule")); @@ -181,7 +182,7 @@ td_api::object_ptr UserPrivacySettingRule::get_u return make_tl_object(); case Type::RestrictUsers: return make_tl_object( - td->contacts_manager_->get_user_ids_object(user_ids_, "userPrivacySettingRuleRestrictUsers")); + td->user_manager_->get_user_ids_object(user_ids_, "userPrivacySettingRuleRestrictUsers")); case Type::RestrictChatParticipants: return make_tl_object( td->dialog_manager_->get_chat_ids_object(dialog_ids_, "UserPrivacySettingRule")); @@ -221,7 +222,7 @@ telegram_api::object_ptr UserPrivacySettingRule: vector> UserPrivacySettingRule::get_input_users(Td *td) const { vector> result; for (auto user_id : user_ids_) { - auto r_input_user = td->contacts_manager_->get_input_user(user_id); + auto r_input_user = td->user_manager_->get_input_user(user_id); if (r_input_user.is_ok()) { result.push_back(r_input_user.move_as_ok()); } else { @@ -266,7 +267,7 @@ void UserPrivacySettingRule::add_dependencies(Dependencies &dependencies) const UserPrivacySettingRules UserPrivacySettingRules::get_user_privacy_setting_rules( Td *td, telegram_api::object_ptr rules) { - td->contacts_manager_->on_get_users(std::move(rules->users_), "on get privacy rules"); + td->user_manager_->on_get_users(std::move(rules->users_), "on get privacy rules"); td->contacts_manager_->on_get_chats(std::move(rules->chats_), "on get privacy rules"); return get_user_privacy_setting_rules(td, std::move(rules->rules_)); } @@ -355,7 +356,7 @@ td_api::object_ptr UserPrivacySettingRules::get_st if (rules_.size() == 2u && rules_[0].type_ == UserPrivacySettingRule::Type::RestrictUsers && rules_[1].type_ == UserPrivacySettingRule::Type::AllowAll) { return td_api::make_object( - td->contacts_manager_->get_user_ids_object(rules_[0].user_ids_, "storyPrivacySettingsEveryone")); + td->user_manager_->get_user_ids_object(rules_[0].user_ids_, "storyPrivacySettingsEveryone")); } if (rules_.size() == 1u && rules_[0].type_ == UserPrivacySettingRule::Type::AllowContacts) { return td_api::make_object(); @@ -363,14 +364,14 @@ td_api::object_ptr UserPrivacySettingRules::get_st if (rules_.size() == 2u && rules_[0].type_ == UserPrivacySettingRule::Type::RestrictUsers && rules_[1].type_ == UserPrivacySettingRule::Type::AllowContacts) { return td_api::make_object( - td->contacts_manager_->get_user_ids_object(rules_[0].user_ids_, "storyPrivacySettingsContacts")); + td->user_manager_->get_user_ids_object(rules_[0].user_ids_, "storyPrivacySettingsContacts")); } if (rules_.size() == 1u && rules_[0].type_ == UserPrivacySettingRule::Type::AllowCloseFriends) { return td_api::make_object(); } if (rules_.size() == 1u && rules_[0].type_ == UserPrivacySettingRule::Type::AllowUsers) { return td_api::make_object( - td->contacts_manager_->get_user_ids_object(rules_[0].user_ids_, "storyPrivacySettingsSelectedUsers")); + td->user_manager_->get_user_ids_object(rules_[0].user_ids_, "storyPrivacySettingsSelectedUsers")); } return td_api::make_object(); } diff --git a/td/telegram/WebPagesManager.cpp b/td/telegram/WebPagesManager.cpp index 7e0d24a22..11f8e4489 100644 --- a/td/telegram/WebPagesManager.cpp +++ b/td/telegram/WebPagesManager.cpp @@ -33,6 +33,7 @@ #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserManager.h" #include "td/telegram/VideoNotesManager.h" #include "td/telegram/VideosManager.h" #include "td/telegram/VoiceNotesManager.h" @@ -125,7 +126,7 @@ class GetWebPageQuery final : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for GetWebPageQuery: " << to_string(ptr); - td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetWebPageQuery"); + td_->user_manager_->on_get_users(std::move(ptr->users_), "GetWebPageQuery"); td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetWebPageQuery"); auto page = std::move(ptr->webpage_); if (page->get_id() == telegram_api::webPageNotModified::ID) { @@ -920,7 +921,7 @@ void WebPagesManager::get_web_page_preview(td_api::object_ptrlink_preview_options_ = std::move(link_preview_options); td_->create_handler(std::move(promise)) ->send(formatted_text.text, - get_input_message_entities(td_->contacts_manager_.get(), formatted_text.entities, "get_web_page_preview"), + get_input_message_entities(td_->user_manager_.get(), formatted_text.entities, "get_web_page_preview"), std::move(options)); } diff --git a/test/secret.cpp b/test/secret.cpp index be3274d0a..158027569 100644 --- a/test/secret.cpp +++ b/test/secret.cpp @@ -530,7 +530,7 @@ class FakeSecretChatContext final : public SecretChatActor::Context { return false; } - // We don't want to expose the whole NetQueryDispatcher, MessagesManager and ContactsManager. + // We don't want to expose the whole NetQueryDispatcher, MessagesManager and UserManager. // So it is more clear which parts of MessagesManager is really used. And it is much easier to create tests. void send_net_query(NetQueryPtr query, ActorShared callback, bool ordered) final;