diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 9d32dfd5e..5100fa27b 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -42,7 +42,6 @@ #include "td/telegram/net/NetQuery.h" #include "td/telegram/NotificationManager.h" #include "td/telegram/OptionManager.h" -#include "td/telegram/PasswordManager.h" #include "td/telegram/PeerColor.h" #include "td/telegram/Photo.h" #include "td/telegram/Photo.hpp" @@ -2270,84 +2269,6 @@ class DeleteChannelQuery final : public Td::ResultHandler { } }; -class CanEditChannelCreatorQuery final : public Td::ResultHandler { - Promise promise_; - - public: - explicit CanEditChannelCreatorQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send() { - auto r_input_user = td_->contacts_manager_->get_input_user(td_->contacts_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(), - make_tl_object()))); - } - - 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(ERROR) << "Receive result for CanEditChannelCreatorQuery: " << to_string(ptr); - promise_.set_error(Status::Error(500, "Server doesn't returned error")); - } - - void on_error(Status status) final { - promise_.set_error(std::move(status)); - } -}; - -class EditChannelCreatorQuery final : public Td::ResultHandler { - Promise promise_; - ChannelId channel_id_; - UserId user_id_; - - public: - explicit EditChannelCreatorQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(ChannelId channel_id, UserId user_id, - tl_object_ptr input_check_password) { - channel_id_ = channel_id; - user_id_ = user_id; - auto input_channel = td_->contacts_manager_->get_input_channel(channel_id); - 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)); - send_query(G()->net_query_creator().create( - telegram_api::channels_editCreator(std::move(input_channel), std::move(input_user), - std::move(input_check_password)), - {{channel_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 EditChannelCreatorQuery: " << to_string(ptr); - td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelCreatorQuery"); - td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); - } - - void on_error(Status status) final { - if (!td_->auth_manager_->is_bot() && status.message() == "USER_PRIVACY_RESTRICTED") { - td_->dialog_participant_manager_->send_update_add_chat_members_privacy_forbidden( - DialogId(channel_id_), {user_id_}, "EditChannelCreatorQuery"); - return promise_.set_error(Status::Error(406, "USER_PRIVACY_RESTRICTED")); - } - td_->contacts_manager_->on_get_channel_error(channel_id_, status, "EditChannelCreatorQuery"); - promise_.set_error(std::move(status)); - } -}; - class MigrateChatQuery final : public Td::ResultHandler { Promise promise_; @@ -7818,109 +7739,6 @@ void ContactsManager::delete_channel(ChannelId channel_id, Promise &&promi td_->create_handler(std::move(promise))->send(channel_id); } -void ContactsManager::can_transfer_ownership(Promise &&promise) { - auto request_promise = PromiseCreator::lambda([promise = std::move(promise)](Result r_result) mutable { - CHECK(r_result.is_error()); - - auto error = r_result.move_as_error(); - CanTransferOwnershipResult result; - if (error.message() == "PASSWORD_HASH_INVALID") { - return promise.set_value(std::move(result)); - } - if (error.message() == "PASSWORD_MISSING") { - result.type = CanTransferOwnershipResult::Type::PasswordNeeded; - return promise.set_value(std::move(result)); - } - if (begins_with(error.message(), "PASSWORD_TOO_FRESH_")) { - result.type = CanTransferOwnershipResult::Type::PasswordTooFresh; - result.retry_after = to_integer(error.message().substr(Slice("PASSWORD_TOO_FRESH_").size())); - if (result.retry_after < 0) { - result.retry_after = 0; - } - return promise.set_value(std::move(result)); - } - if (begins_with(error.message(), "SESSION_TOO_FRESH_")) { - result.type = CanTransferOwnershipResult::Type::SessionTooFresh; - result.retry_after = to_integer(error.message().substr(Slice("SESSION_TOO_FRESH_").size())); - if (result.retry_after < 0) { - result.retry_after = 0; - } - return promise.set_value(std::move(result)); - } - promise.set_error(std::move(error)); - }); - - td_->create_handler(std::move(request_promise))->send(); -} - -td_api::object_ptr ContactsManager::get_can_transfer_ownership_result_object( - CanTransferOwnershipResult result) { - switch (result.type) { - case CanTransferOwnershipResult::Type::Ok: - return td_api::make_object(); - case CanTransferOwnershipResult::Type::PasswordNeeded: - return td_api::make_object(); - case CanTransferOwnershipResult::Type::PasswordTooFresh: - return td_api::make_object(result.retry_after); - case CanTransferOwnershipResult::Type::SessionTooFresh: - return td_api::make_object(result.retry_after); - default: - UNREACHABLE(); - return nullptr; - } -} - -void ContactsManager::transfer_dialog_ownership(DialogId dialog_id, UserId user_id, const string &password, - Promise &&promise) { - if (!td_->dialog_manager_->have_dialog_force(dialog_id, "transfer_dialog_ownership")) { - return promise.set_error(Status::Error(400, "Chat not found")); - } - if (!have_user_force(user_id, "transfer_dialog_ownership")) { - return promise.set_error(Status::Error(400, "User not found")); - } - if (is_user_bot(user_id)) { - return promise.set_error(Status::Error(400, "User is a bot")); - } - if (is_user_deleted(user_id)) { - return promise.set_error(Status::Error(400, "User is deleted")); - } - if (password.empty()) { - return promise.set_error(Status::Error(400, "PASSWORD_HASH_INVALID")); - } - - switch (dialog_id.get_type()) { - case DialogType::User: - case DialogType::Chat: - case DialogType::SecretChat: - return promise.set_error(Status::Error(400, "Can't transfer chat ownership")); - case DialogType::Channel: - send_closure( - td_->password_manager_, &PasswordManager::get_input_check_password_srp, password, - PromiseCreator::lambda([actor_id = actor_id(this), channel_id = dialog_id.get_channel_id(), 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::transfer_channel_ownership, channel_id, user_id, - result.move_as_ok(), std::move(promise)); - })); - break; - case DialogType::None: - default: - UNREACHABLE(); - } -} - -void ContactsManager::transfer_channel_ownership( - ChannelId channel_id, UserId user_id, tl_object_ptr input_check_password, - Promise &&promise) { - TRY_STATUS_PROMISE(promise, G()->close_status()); - - td_->create_handler(std::move(promise)) - ->send(channel_id, user_id, std::move(input_check_password)); -} - void ContactsManager::migrate_dialog_to_megagroup(DialogId dialog_id, Promise> &&promise) { LOG(INFO) << "Trying to upgrade " << dialog_id << " to a supergroup"; diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 72429b4d0..c1b1691a0 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -526,18 +526,6 @@ class ContactsManager final : public Actor { bool can_get_channel_story_statistics(DialogId dialog_id) const; - struct CanTransferOwnershipResult { - enum class Type : uint8 { Ok, PasswordNeeded, PasswordTooFresh, SessionTooFresh }; - Type type = Type::Ok; - int32 retry_after = 0; - }; - void can_transfer_ownership(Promise &&promise); - - static td_api::object_ptr get_can_transfer_ownership_result_object( - CanTransferOwnershipResult result); - - void transfer_dialog_ownership(DialogId dialog_id, UserId user_id, const string &password, Promise &&promise); - void migrate_dialog_to_megagroup(DialogId dialog_id, Promise> &&promise); void get_channel_recommendations(DialogId dialog_id, bool return_local, @@ -1818,10 +1806,6 @@ class ContactsManager final : public Actor { tl_object_ptr &&channel_participants, Promise &&promise); - void transfer_channel_ownership(ChannelId channel_id, UserId user_id, - tl_object_ptr input_check_password, - Promise &&promise); - 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); diff --git a/td/telegram/DialogParticipantManager.cpp b/td/telegram/DialogParticipantManager.cpp index 85abbdd9e..956dbdcc4 100644 --- a/td/telegram/DialogParticipantManager.cpp +++ b/td/telegram/DialogParticipantManager.cpp @@ -16,6 +16,7 @@ #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/misc.h" +#include "td/telegram/PasswordManager.h" #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" @@ -695,6 +696,84 @@ class LeaveChannelQuery final : public Td::ResultHandler { } }; +class CanEditChannelCreatorQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit CanEditChannelCreatorQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send() { + auto r_input_user = td_->contacts_manager_->get_input_user(td_->contacts_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(), + make_tl_object()))); + } + + 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(ERROR) << "Receive result for CanEditChannelCreatorQuery: " << to_string(ptr); + promise_.set_error(Status::Error(500, "Server doesn't returned error")); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class EditChannelCreatorQuery final : public Td::ResultHandler { + Promise promise_; + ChannelId channel_id_; + UserId user_id_; + + public: + explicit EditChannelCreatorQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(ChannelId channel_id, UserId user_id, + tl_object_ptr input_check_password) { + channel_id_ = channel_id; + user_id_ = user_id; + auto input_channel = td_->contacts_manager_->get_input_channel(channel_id); + 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)); + send_query(G()->net_query_creator().create( + telegram_api::channels_editCreator(std::move(input_channel), std::move(input_user), + std::move(input_check_password)), + {{channel_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 EditChannelCreatorQuery: " << to_string(ptr); + td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelCreatorQuery"); + td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); + } + + void on_error(Status status) final { + if (!td_->auth_manager_->is_bot() && status.message() == "USER_PRIVACY_RESTRICTED") { + td_->dialog_participant_manager_->send_update_add_chat_members_privacy_forbidden( + DialogId(channel_id_), {user_id_}, "EditChannelCreatorQuery"); + return promise_.set_error(Status::Error(406, "USER_PRIVACY_RESTRICTED")); + } + td_->contacts_manager_->on_get_channel_error(channel_id_, status, "EditChannelCreatorQuery"); + promise_.set_error(std::move(status)); + } +}; + DialogParticipantManager::DialogParticipantManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { update_dialog_online_member_count_timeout_.set_callback(on_update_dialog_online_member_count_timeout_callback); update_dialog_online_member_count_timeout_.set_callback_data(static_cast(this)); @@ -2328,6 +2407,109 @@ const DialogParticipant *DialogParticipantManager::get_channel_participant_from_ return nullptr; } +void DialogParticipantManager::can_transfer_ownership(Promise &&promise) { + auto request_promise = PromiseCreator::lambda([promise = std::move(promise)](Result r_result) mutable { + CHECK(r_result.is_error()); + + auto error = r_result.move_as_error(); + CanTransferOwnershipResult result; + if (error.message() == "PASSWORD_HASH_INVALID") { + return promise.set_value(std::move(result)); + } + if (error.message() == "PASSWORD_MISSING") { + result.type = CanTransferOwnershipResult::Type::PasswordNeeded; + return promise.set_value(std::move(result)); + } + if (begins_with(error.message(), "PASSWORD_TOO_FRESH_")) { + result.type = CanTransferOwnershipResult::Type::PasswordTooFresh; + result.retry_after = to_integer(error.message().substr(Slice("PASSWORD_TOO_FRESH_").size())); + if (result.retry_after < 0) { + result.retry_after = 0; + } + return promise.set_value(std::move(result)); + } + if (begins_with(error.message(), "SESSION_TOO_FRESH_")) { + result.type = CanTransferOwnershipResult::Type::SessionTooFresh; + result.retry_after = to_integer(error.message().substr(Slice("SESSION_TOO_FRESH_").size())); + if (result.retry_after < 0) { + result.retry_after = 0; + } + return promise.set_value(std::move(result)); + } + promise.set_error(std::move(error)); + }); + + td_->create_handler(std::move(request_promise))->send(); +} + +td_api::object_ptr +DialogParticipantManager::get_can_transfer_ownership_result_object(CanTransferOwnershipResult result) { + switch (result.type) { + case CanTransferOwnershipResult::Type::Ok: + return td_api::make_object(); + case CanTransferOwnershipResult::Type::PasswordNeeded: + return td_api::make_object(); + case CanTransferOwnershipResult::Type::PasswordTooFresh: + return td_api::make_object(result.retry_after); + case CanTransferOwnershipResult::Type::SessionTooFresh: + return td_api::make_object(result.retry_after); + default: + UNREACHABLE(); + return nullptr; + } +} + +void DialogParticipantManager::transfer_dialog_ownership(DialogId dialog_id, UserId user_id, const string &password, + Promise &&promise) { + 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")) { + return promise.set_error(Status::Error(400, "User not found")); + } + if (td_->contacts_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)) { + return promise.set_error(Status::Error(400, "User is deleted")); + } + if (password.empty()) { + return promise.set_error(Status::Error(400, "PASSWORD_HASH_INVALID")); + } + + switch (dialog_id.get_type()) { + case DialogType::User: + case DialogType::Chat: + case DialogType::SecretChat: + return promise.set_error(Status::Error(400, "Can't transfer chat ownership")); + case DialogType::Channel: + send_closure( + td_->password_manager_, &PasswordManager::get_input_check_password_srp, password, + PromiseCreator::lambda([actor_id = actor_id(this), channel_id = dialog_id.get_channel_id(), 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, &DialogParticipantManager::transfer_channel_ownership, channel_id, user_id, + result.move_as_ok(), std::move(promise)); + })); + break; + case DialogType::None: + default: + UNREACHABLE(); + } +} + +void DialogParticipantManager::transfer_channel_ownership( + ChannelId channel_id, UserId user_id, + telegram_api::object_ptr input_check_password, Promise &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + + td_->create_handler(std::move(promise)) + ->send(channel_id, user_id, std::move(input_check_password)); +} + void DialogParticipantManager::get_current_state(vector> &updates) const { for (const auto &it : dialog_online_member_counts_) { auto dialog_id = it.first; diff --git a/td/telegram/DialogParticipantManager.h b/td/telegram/DialogParticipantManager.h index d3914cad9..81b5d225d 100644 --- a/td/telegram/DialogParticipantManager.h +++ b/td/telegram/DialogParticipantManager.h @@ -114,6 +114,18 @@ class DialogParticipantManager final : public Actor { void drop_channel_participant_cache(ChannelId channel_id); + struct CanTransferOwnershipResult { + enum class Type : uint8 { Ok, PasswordNeeded, PasswordTooFresh, SessionTooFresh }; + Type type = Type::Ok; + int32 retry_after = 0; + }; + void can_transfer_ownership(Promise &&promise); + + static td_api::object_ptr get_can_transfer_ownership_result_object( + CanTransferOwnershipResult result); + + void transfer_dialog_ownership(DialogId dialog_id, UserId user_id, const string &password, Promise &&promise); + void get_current_state(vector> &updates) const; private: @@ -210,6 +222,10 @@ class DialogParticipantManager final : public Actor { void on_channel_participant_cache_timeout(ChannelId channel_id); + void transfer_channel_ownership(ChannelId channel_id, UserId user_id, + tl_object_ptr input_check_password, + Promise &&promise); + struct OnlineMemberCountInfo { int32 online_member_count = 0; double update_time = 0; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index e635428b9..94a157bbf 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6966,22 +6966,22 @@ void Td::on_request(uint64 id, const td_api::canTransferOwnership &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); auto query_promise = PromiseCreator::lambda( - [promise = std::move(promise)](Result result) mutable { + [promise = std::move(promise)](Result result) mutable { if (result.is_error()) { promise.set_error(result.move_as_error()); } else { - promise.set_value(ContactsManager::get_can_transfer_ownership_result_object(result.ok())); + promise.set_value(DialogParticipantManager::get_can_transfer_ownership_result_object(result.ok())); } }); - contacts_manager_->can_transfer_ownership(std::move(query_promise)); + dialog_participant_manager_->can_transfer_ownership(std::move(query_promise)); } void Td::on_request(uint64 id, td_api::transferChatOwnership &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.password_); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->transfer_dialog_ownership(DialogId(request.chat_id_), UserId(request.user_id_), request.password_, - std::move(promise)); + dialog_participant_manager_->transfer_dialog_ownership(DialogId(request.chat_id_), UserId(request.user_id_), + request.password_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::getChatMember &request) {