diff --git a/CMakeLists.txt b/CMakeLists.txt index 2aa34c786..c4431e268 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -305,6 +305,7 @@ set(TDLIB_SOURCE td/telegram/DeviceTokenManager.cpp td/telegram/DhCache.cpp td/telegram/DialogAction.cpp + td/telegram/DialogActionBar.cpp td/telegram/DialogAdministrator.cpp td/telegram/DialogDb.cpp td/telegram/DialogEventLog.cpp @@ -490,6 +491,7 @@ set(TDLIB_SOURCE td/telegram/DhCache.h td/telegram/DhConfig.h td/telegram/DialogAction.h + td/telegram/DialogActionBar.h td/telegram/DialogAdministrator.h td/telegram/DialogDate.h td/telegram/DialogDb.h diff --git a/td/mtproto/Handshake.cpp b/td/mtproto/Handshake.cpp index f47d2f8f1..421ad5788 100644 --- a/td/mtproto/Handshake.cpp +++ b/td/mtproto/Handshake.cpp @@ -50,17 +50,20 @@ AuthKeyHandshake::AuthKeyHandshake(int32 dc_id, int32 expires_in) : mode_(expires_in == 0 ? Mode::Main : Mode::Temp) , dc_id_(dc_id) , expires_in_(expires_in) - , timeout_at_(Time::now() + 1e9) { + , start_time_(Time::now()) + , timeout_in_(1e9) { } void AuthKeyHandshake::set_timeout_in(double timeout_in) { - timeout_at_ = Time::now() + timeout_in; + start_time_ = Time::now(); + timeout_in_ = timeout_in; } void AuthKeyHandshake::clear() { last_query_ = BufferSlice(); state_ = Start; - timeout_at_ = Time::now() + 1e9; + start_time_ = Time::now(); + timeout_in_ = 1e9; } bool AuthKeyHandshake::is_ready_for_finish() const { @@ -81,6 +84,10 @@ string AuthKeyHandshake::store_object(const mtproto_api::Object &object) { } Status AuthKeyHandshake::on_res_pq(Slice message, Callback *connection, PublicRsaKeyInterface *public_rsa_key) { + if (Time::now() >= start_time_ + timeout_in_ * 0.6) { + return Status::Error("Handshake ResPQ timeout expired"); + } + TRY_RESULT(res_pq, fetch_result(message, false)); if (res_pq->nonce_ != nonce_) { return Status::Error("Nonce mismatch"); @@ -155,6 +162,10 @@ Status AuthKeyHandshake::on_res_pq(Slice message, Callback *connection, PublicRs } Status AuthKeyHandshake::on_server_dh_params(Slice message, Callback *connection, DhCallback *dh_callback) { + if (Time::now() >= start_time_ + timeout_in_ * 0.8) { + return Status::Error("Handshake DH params timeout expired"); + } + TRY_RESULT(dh_params, fetch_result(message, false)); // server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; @@ -318,10 +329,6 @@ Status AuthKeyHandshake::on_start(Callback *connection) { Status AuthKeyHandshake::on_message(Slice message, Callback *connection, AuthKeyHandshakeContext *context) { Status status = [&] { - if (Time::now() >= timeout_at_) { - return Status::Error("Handshake timeout expired"); - } - switch (state_) { case ResPQ: return on_res_pq(message, connection, context->get_public_rsa_key_interface()); diff --git a/td/mtproto/Handshake.h b/td/mtproto/Handshake.h index b3979ed20..5baf7657d 100644 --- a/td/mtproto/Handshake.h +++ b/td/mtproto/Handshake.h @@ -82,7 +82,8 @@ class AuthKeyHandshake { int32 expires_in_ = 0; double expires_at_ = 0; - double timeout_at_ = 0; + double start_time_ = 0; + double timeout_in_ = 0; AuthKey auth_key_; double server_time_diff_ = 0; diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 787316bc8..1aca57e84 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -1600,6 +1600,7 @@ class GetChatInviteImportersQuery final : public Td::ResultHandler { class GetChatJoinRequestsQuery final : public Td::ResultHandler { Promise> promise_; DialogId dialog_id_; + bool is_full_list_ = false; public: explicit GetChatJoinRequestsQuery(Promise> &&promise) @@ -1609,6 +1610,8 @@ class GetChatJoinRequestsQuery final : public Td::ResultHandler { void send(DialogId dialog_id, const string &invite_link, const string &query, int32 offset_date, UserId offset_user_id, int32 limit) { dialog_id_ = dialog_id; + is_full_list_ = invite_link.empty() && query.empty() && offset_date == 0 && !offset_user_id.is_valid() && limit >= 3; + auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write); if (input_peer == nullptr) { return on_error(Status::Error(400, "Can't access the chat")); @@ -1663,8 +1666,10 @@ class GetChatJoinRequestsQuery final : public Td::ResultHandler { join_requests.push_back(td_api::make_object( td_->contacts_manager_->get_user_id_object(user_id, "chatJoinRequest"), request->date_, request->about_)); } - td_->messages_manager_->on_update_dialog_pending_join_requests(dialog_id_, total_count, - std::move(recent_requesters)); + if (is_full_list_) { + td_->messages_manager_->on_update_dialog_pending_join_requests(dialog_id_, total_count, + std::move(recent_requesters)); + } promise_.set_value(td_api::make_object(total_count, std::move(join_requests))); } @@ -7595,17 +7600,8 @@ void ContactsManager::remove_dialog_suggested_action(SuggestedAction action) { } } -void ContactsManager::dismiss_suggested_action(SuggestedAction action, Promise &&promise) { - if (action.is_empty()) { - return promise.set_error(Status::Error(400, "Action must be non-empty")); - } +void ContactsManager::dismiss_dialog_suggested_action(SuggestedAction action, Promise &&promise) { auto dialog_id = action.dialog_id_; - if (dialog_id == DialogId()) { - send_closure_later(G()->config_manager(), &ConfigManager::dismiss_suggested_action, std::move(action), - std::move(promise)); - return; - } - if (!td_->messages_manager_->have_dialog(dialog_id)) { return promise.set_error(Status::Error(400, "Chat not found")); } @@ -9547,6 +9543,7 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo CHECK(u != nullptr); 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); @@ -9557,6 +9554,7 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo update_user_full(user_full, user_id, "update_user"); } } + u->is_is_contact_changed = false; } if (u->is_is_deleted_changed) { td_->messages_manager_->on_dialog_user_is_deleted_updated(DialogId(user_id), u->is_deleted); @@ -9566,6 +9564,7 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo drop_user_full(user_id); } } + u->is_is_deleted_changed = false; } if (u->is_name_changed) { auto messages_manager = td_->messages_manager_.get(); @@ -9573,6 +9572,7 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo 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(); @@ -9580,6 +9580,7 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo 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_status_changed && user_id != get_my_id()) { auto left_time = get_user_was_online(u, user_id) - G()->server_time_cached(); @@ -9592,9 +9593,6 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo user_online_timeout_.cancel_timeout(user_id.get()); } } - if (u->is_default_permissions_changed) { - td_->messages_manager_->on_dialog_permissions_updated(DialogId(user_id)); - } if (!td_->auth_manager_->is_bot()) { if (u->restriction_reasons.empty()) { restricted_user_ids_.erase(user_id); @@ -9603,13 +9601,6 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo } } - u->is_name_changed = false; - u->is_username_changed = false; - u->is_photo_changed = false; - u->is_is_contact_changed = false; - u->is_is_deleted_changed = false; - u->is_default_permissions_changed = false; - if (u->is_deleted) { td_->inline_queries_manager_->remove_recent_inline_bot(user_id, Promise<>()); } diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 33f12cbe5..72169b341 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -420,7 +420,7 @@ class ContactsManager final : public Actor { vector get_inactive_channels(Promise &&promise); - void dismiss_suggested_action(SuggestedAction action, Promise &&promise); + void dismiss_dialog_suggested_action(SuggestedAction action, Promise &&promise); bool is_user_contact(UserId user_id, bool is_mutual = false) const; @@ -642,7 +642,6 @@ class ContactsManager final : public Actor { bool is_photo_changed = true; bool is_is_contact_changed = true; bool is_is_deleted_changed = true; - bool is_default_permissions_changed = true; bool is_changed = true; // have new changes that need to be sent to the client and database bool need_save_to_database = true; // have new changes that need only to be saved to the database bool is_status_changed = true; diff --git a/td/telegram/DialogActionBar.cpp b/td/telegram/DialogActionBar.cpp new file mode 100644 index 000000000..0fdab829c --- /dev/null +++ b/td/telegram/DialogActionBar.cpp @@ -0,0 +1,249 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/DialogActionBar.h" + +#include "td/telegram/ContactsManager.h" +#include "td/telegram/Td.h" + +namespace td { + +unique_ptr DialogActionBar::create(bool can_report_spam, bool can_add_contact, bool can_block_user, + bool can_share_phone_number, bool can_report_location, + bool can_unarchive, int32 distance, bool can_invite_members) { + if (!can_report_spam && !can_add_contact && !can_block_user && !can_share_phone_number && !can_report_location && + !can_invite_members) { + return nullptr; + } + + auto action_bar = make_unique(); + action_bar->can_report_spam_ = can_report_spam; + action_bar->can_add_contact_ = can_add_contact; + action_bar->can_block_user_ = can_block_user; + action_bar->can_share_phone_number_ = can_share_phone_number; + action_bar->can_report_location_ = can_report_location; + action_bar->can_unarchive_ = can_unarchive; + action_bar->distance_ = distance >= 0 ? distance : -1; + action_bar->can_invite_members_ = can_invite_members; + return action_bar; +} + +bool DialogActionBar::is_empty() const { + return !can_report_spam_ && !can_add_contact_ && !can_block_user_ && !can_share_phone_number_ && + !can_report_location_ && !can_invite_members_; +} + +void DialogActionBar::fix(Td *td, DialogId dialog_id, bool is_dialog_blocked, FolderId folder_id) { + auto dialog_type = dialog_id.get_type(); + if (distance_ >= 0 && dialog_type != DialogType::User) { + LOG(ERROR) << "Receive distance_ " << distance_ << " to " << dialog_id; + distance_ = -1; + } + + if (can_report_location_) { + if (dialog_type != DialogType::Channel) { + LOG(ERROR) << "Receive can_report_location_ in " << dialog_id; + can_report_location_ = false; + } else if (can_report_spam_ || can_add_contact_ || can_block_user_ || can_share_phone_number_ || can_unarchive_ || + can_invite_members_) { + LOG(ERROR) << "Receive action bar " << can_report_spam_ << "/" << can_add_contact_ << "/" << can_block_user_ + << "/" << can_share_phone_number_ << "/" << can_report_location_ << "/" << can_unarchive_ << "/" + << can_invite_members_; + can_report_spam_ = false; + can_add_contact_ = false; + can_block_user_ = false; + can_share_phone_number_ = false; + can_unarchive_ = false; + can_invite_members_ = false; + CHECK(distance_ == -1); + } + } + if (can_invite_members_) { + if (dialog_type != DialogType::Chat && + (dialog_type != DialogType::Channel || td->contacts_manager_->get_channel_type(dialog_id.get_channel_id()) == + ContactsManager::ChannelType::Broadcast)) { + LOG(ERROR) << "Receive can_invite_members_ in " << dialog_id; + can_invite_members_ = false; + } else if (can_report_spam_ || can_add_contact_ || can_block_user_ || can_share_phone_number_ || can_unarchive_) { + LOG(ERROR) << "Receive action bar " << can_report_spam_ << "/" << can_add_contact_ << "/" << can_block_user_ + << "/" << can_share_phone_number_ << "/" << can_unarchive_ << "/" << can_invite_members_; + can_report_spam_ = false; + can_add_contact_ = false; + can_block_user_ = false; + can_share_phone_number_ = false; + can_unarchive_ = false; + CHECK(distance_ == -1); + } + } + 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); + if (is_me || is_dialog_blocked) { + can_report_spam_ = false; + can_unarchive_ = false; + } + if (is_me || is_dialog_blocked || is_deleted) { + can_share_phone_number_ = false; + } + if (is_me || is_dialog_blocked || is_deleted || is_contact) { + can_block_user_ = false; + can_add_contact_ = false; + } + } + if (folder_id != FolderId::archive()) { + can_unarchive_ = false; + } + if (can_share_phone_number_) { + CHECK(!can_report_location_); + CHECK(!can_invite_members_); + if (dialog_type != DialogType::User) { + LOG(ERROR) << "Receive can_share_phone_number_ in " << dialog_id; + can_share_phone_number_ = false; + } else if (can_report_spam_ || can_add_contact_ || can_block_user_ || can_unarchive_ || distance_ >= 0) { + LOG(ERROR) << "Receive action bar " << can_report_spam_ << "/" << can_add_contact_ << "/" << can_block_user_ + << "/" << can_share_phone_number_ << "/" << can_unarchive_ << "/" << distance_; + can_report_spam_ = false; + can_add_contact_ = false; + can_block_user_ = false; + can_unarchive_ = false; + } + } + if (can_block_user_) { + CHECK(!can_report_location_); + CHECK(!can_invite_members_); + CHECK(!can_share_phone_number_); + if (dialog_type != DialogType::User) { + LOG(ERROR) << "Receive can_block_user_ in " << dialog_id; + can_block_user_ = false; + } else if (!can_report_spam_ || !can_add_contact_) { + LOG(ERROR) << "Receive action bar " << can_report_spam_ << "/" << can_add_contact_ << "/" << can_block_user_; + can_report_spam_ = true; + can_add_contact_ = true; + } + } + if (can_add_contact_) { + CHECK(!can_report_location_); + CHECK(!can_invite_members_); + CHECK(!can_share_phone_number_); + if (dialog_type != DialogType::User) { + LOG(ERROR) << "Receive can_add_contact_ in " << dialog_id; + can_add_contact_ = false; + } else if (can_report_spam_ != can_block_user_) { + LOG(ERROR) << "Receive action bar " << can_report_spam_ << "/" << can_add_contact_ << "/" << can_block_user_; + can_report_spam_ = false; + can_block_user_ = false; + can_unarchive_ = false; + } + } + if (!can_block_user_) { + distance_ = -1; + } + if (!can_report_spam_) { + can_unarchive_ = false; + } +} + +td_api::object_ptr DialogActionBar::get_chat_action_bar_object(DialogType dialog_type, + bool hide_unarchive) const { + if (can_report_location_) { + CHECK(dialog_type == DialogType::Channel); + CHECK(!can_share_phone_number_ && !can_block_user_ && !can_add_contact_ && !can_report_spam_ && + !can_invite_members_); + return td_api::make_object(); + } + if (can_invite_members_) { + CHECK(!can_share_phone_number_ && !can_block_user_ && !can_add_contact_ && !can_report_spam_); + return td_api::make_object(); + } + if (can_share_phone_number_) { + CHECK(dialog_type == DialogType::User); + CHECK(!can_block_user_ && !can_add_contact_ && !can_report_spam_); + return td_api::make_object(); + } + if (hide_unarchive) { + if (can_add_contact_) { + return td_api::make_object(); + } else { + return nullptr; + } + } + if (can_block_user_) { + CHECK(dialog_type == DialogType::User); + CHECK(can_report_spam_ && can_add_contact_); + return td_api::make_object(can_unarchive_, distance_); + } + if (can_add_contact_) { + CHECK(dialog_type == DialogType::User); + CHECK(!can_report_spam_); + return td_api::make_object(); + } + if (can_report_spam_) { + return td_api::make_object(can_unarchive_); + } + return nullptr; +} + +bool DialogActionBar::on_dialog_unarchived() { + if (!can_unarchive_) { + return false; + } + + can_unarchive_ = false; + can_report_spam_ = false; + can_block_user_ = false; + // keep can_add_contact_ + return true; +} + +bool DialogActionBar::on_user_contact_added() { + if (!can_block_user_ && !can_add_contact_) { + return false; + } + + can_block_user_ = false; + can_add_contact_ = false; + // keep can_unarchive_ + distance_ = -1; + return true; +} + +bool DialogActionBar::on_user_deleted() { + if (!can_share_phone_number_ && !can_block_user_ && !can_add_contact_ && distance_ < 0) { + return false; + } + + can_share_phone_number_ = false; + can_block_user_ = false; + can_add_contact_ = false; + distance_ = -1; + return true; +} + +bool DialogActionBar::on_outgoing_message() { + if (distance_ < 0) { + return false; + } + + distance_ = -1; + return true; +} + +bool operator==(const unique_ptr &lhs, const unique_ptr &rhs) { + if (lhs == nullptr) { + return rhs == nullptr; + } + if (rhs == nullptr) { + return false; + } + return lhs->can_report_spam_ == rhs->can_report_spam_ && lhs->can_add_contact_ == rhs->can_add_contact_ && + lhs->can_block_user_ == rhs->can_block_user_ && lhs->can_share_phone_number_ == rhs->can_share_phone_number_ && + lhs->can_report_location_ == rhs->can_report_location_ && lhs->can_unarchive_ == rhs->can_unarchive_ && + lhs->distance_ == rhs->distance_ && lhs->can_invite_members_ == rhs->can_invite_members_; +} + +} // namespace td diff --git a/td/telegram/DialogActionBar.h b/td/telegram/DialogActionBar.h new file mode 100644 index 000000000..f395c0daf --- /dev/null +++ b/td/telegram/DialogActionBar.h @@ -0,0 +1,100 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/DialogId.h" +#include "td/telegram/FolderId.h" +#include "td/telegram/td_api.h" + +#include "td/utils/common.h" +#include "td/utils/tl_helpers.h" + +namespace td { + +class Td; + +class DialogActionBar { + int32 distance_ = -1; // distance to the peer + + bool can_report_spam_ = false; + bool can_add_contact_ = false; + bool can_block_user_ = false; + bool can_share_phone_number_ = false; + bool can_report_location_ = false; + bool can_unarchive_ = false; + bool can_invite_members_ = false; + + friend bool operator==(const unique_ptr &lhs, const unique_ptr &rhs); + + public: + static unique_ptr create(bool can_report_spam, bool can_add_contact, bool can_block_user, + bool can_share_phone_number, bool can_report_location, bool can_unarchive, + int32 distance, bool can_invite_members); + + bool is_empty() const; + + bool can_report_spam() const { + return can_report_spam_; + } + + bool can_unarchive() const { + return can_unarchive_; + } + + td_api::object_ptr get_chat_action_bar_object(DialogType dialog_type, + bool hide_unarchive) const; + + void fix(Td *td, DialogId dialog_id, bool is_dialog_blocked, FolderId folder_id); + + bool on_dialog_unarchived(); + + bool on_user_contact_added(); + + bool on_user_deleted(); + + bool on_outgoing_message(); + + template + void store(StorerT &storer) const { + bool has_distance = distance_ >= 0; + BEGIN_STORE_FLAGS(); + STORE_FLAG(can_report_spam_); + STORE_FLAG(can_add_contact_); + STORE_FLAG(can_block_user_); + STORE_FLAG(can_share_phone_number_); + STORE_FLAG(can_report_location_); + STORE_FLAG(can_unarchive_); + STORE_FLAG(can_invite_members_); + STORE_FLAG(has_distance); + END_STORE_FLAGS(); + if (has_distance) { + td::store(distance_, storer); + } + } + + template + void parse(ParserT &parser) { + bool has_distance; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(can_report_spam_); + PARSE_FLAG(can_add_contact_); + PARSE_FLAG(can_block_user_); + PARSE_FLAG(can_share_phone_number_); + PARSE_FLAG(can_report_location_); + PARSE_FLAG(can_unarchive_); + PARSE_FLAG(can_invite_members_); + PARSE_FLAG(has_distance); + END_PARSE_FLAGS(); + if (has_distance) { + td::parse(distance_, parser); + } + } +}; + +bool operator==(const unique_ptr &lhs, const unique_ptr &rhs); + +} // namespace td diff --git a/td/telegram/LinkManager.cpp b/td/telegram/LinkManager.cpp index d377ebead..c0e75f264 100644 --- a/td/telegram/LinkManager.cpp +++ b/td/telegram/LinkManager.cpp @@ -35,6 +35,8 @@ #include "td/utils/StringBuilder.h" #include "td/utils/Time.h" +#include + namespace td { static bool is_valid_start_parameter(Slice start_parameter) { @@ -1233,6 +1235,48 @@ string LinkManager::get_dialog_invite_link_hash(Slice invite_link) { return get_url_query_hash(link_info.is_tg_, url_query); } +UserId LinkManager::get_link_user_id(Slice url) { + string lower_cased_url = to_lower(url); + url = lower_cased_url; + + Slice link_scheme("tg:"); + if (!begins_with(url, link_scheme)) { + return UserId(); + } + url.remove_prefix(link_scheme.size()); + if (begins_with(url, "//")) { + url.remove_prefix(2); + } + + Slice host("user"); + if (!begins_with(url, host)) { + return UserId(); + } + url.remove_prefix(host.size()); + if (begins_with(url, "/")) { + url.remove_prefix(1); + } + if (!begins_with(url, "?")) { + return UserId(); + } + url.remove_prefix(1); + url.truncate(url.find('#')); + + for (auto parameter : full_split(url, '&')) { + Slice key; + Slice value; + std::tie(key, value) = split(parameter, '='); + if (key == Slice("id")) { + auto r_user_id = to_integer_safe(value); + if (r_user_id.is_error()) { + return UserId(); + } + return UserId(r_user_id.ok()); + } + } + return UserId(); +} + Result LinkManager::get_message_link_info(Slice url) { if (url.empty()) { return Status::Error("URL must be non-empty"); diff --git a/td/telegram/LinkManager.h b/td/telegram/LinkManager.h index e55c7e57f..2bc65a72b 100644 --- a/td/telegram/LinkManager.h +++ b/td/telegram/LinkManager.h @@ -9,6 +9,7 @@ #include "td/telegram/FullMessageId.h" #include "td/telegram/MessageLinkInfo.h" #include "td/telegram/td_api.h" +#include "td/telegram/UserId.h" #include "td/actor/actor.h" #include "td/actor/PromiseFuture.h" @@ -69,6 +70,8 @@ class LinkManager final : public Actor { static string get_dialog_invite_link_hash(Slice invite_link); + static UserId get_link_user_id(Slice url); + static Result get_message_link_info(Slice url); private: diff --git a/td/telegram/MessageEntity.cpp b/td/telegram/MessageEntity.cpp index c091b7ec7..af43bad42 100644 --- a/td/telegram/MessageEntity.cpp +++ b/td/telegram/MessageEntity.cpp @@ -1773,48 +1773,6 @@ string get_first_url(Slice text, const vector &entities) { return string(); } -static UserId get_link_user_id(Slice url) { - string lower_cased_url = to_lower(url); - url = lower_cased_url; - - Slice link_scheme("tg:"); - if (!begins_with(url, link_scheme)) { - return UserId(); - } - url.remove_prefix(link_scheme.size()); - if (begins_with(url, "//")) { - url.remove_prefix(2); - } - - Slice host("user"); - if (!begins_with(url, host)) { - return UserId(); - } - url.remove_prefix(host.size()); - if (begins_with(url, "/")) { - url.remove_prefix(1); - } - if (!begins_with(url, "?")) { - return UserId(); - } - url.remove_prefix(1); - url.truncate(url.find('#')); - - for (auto parameter : full_split(url, '&')) { - Slice key; - Slice value; - std::tie(key, value) = split(parameter, '='); - if (key == Slice("id")) { - auto r_user_id = to_integer_safe(value); - if (r_user_id.is_error()) { - return UserId(); - } - return UserId(r_user_id.ok()); - } - } - return UserId(); -} - Result> parse_markdown(string &text) { string result; vector entities; @@ -1900,7 +1858,7 @@ Result> parse_markdown(string &text) { url.push_back(text[i++]); } } - auto user_id = get_link_user_id(url); + auto user_id = LinkManager::get_link_user_id(url); if (user_id.is_valid()) { entities.emplace_back(entity_offset, entity_length, user_id); } else { @@ -2106,7 +2064,7 @@ static Result> do_parse_markdown_v2(CSlice text, string &r return Status::Error(400, PSLICE() << "Can't find end of a URL at byte offset " << url_begin_pos); } } - user_id = get_link_user_id(url); + user_id = LinkManager::get_link_user_id(url); if (!user_id.is_valid()) { auto r_url = LinkManager::check_link(url); if (r_url.is_error()) { @@ -3056,7 +3014,7 @@ static Result> do_parse_html(CSlice text, string &result) if (url.empty()) { url = result.substr(nested_entities.back().entity_begin_pos); } - auto user_id = get_link_user_id(url); + auto user_id = LinkManager::get_link_user_id(url); if (user_id.is_valid()) { entities.emplace_back(entity_offset, entity_length, user_id); } else { diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 2bf33db67..999a6811e 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -11,6 +11,7 @@ #include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/Dependencies.h" +#include "td/telegram/DialogActionBar.h" #include "td/telegram/DialogDb.h" #include "td/telegram/DialogFilter.h" #include "td/telegram/DialogFilter.hpp" @@ -5170,7 +5171,6 @@ void MessagesManager::Dialog::store(StorerT &storer) const { max_notification_message_id.is_valid() && max_notification_message_id > last_new_message_id; bool has_folder_id = folder_id != FolderId(); bool has_pending_read_channel_inbox = pending_read_channel_inbox_pts != 0; - bool has_distance = distance >= 0; bool has_last_yet_unsent_message = last_message_id.is_valid() && last_message_id.is_yet_unsent(); bool has_active_group_call_id = active_group_call_id.is_valid(); bool has_message_ttl_setting = !message_ttl_setting.is_empty(); @@ -5179,13 +5179,14 @@ void MessagesManager::Dialog::store(StorerT &storer) const { bool has_theme_name = !theme_name.empty(); bool has_flags3 = true; bool has_pending_join_requests = pending_join_request_count != 0; + bool has_action_bar = action_bar != nullptr; BEGIN_STORE_FLAGS(); STORE_FLAG(has_draft_message); STORE_FLAG(has_last_database_message); - STORE_FLAG(know_can_report_spam); - STORE_FLAG(can_report_spam); + STORE_FLAG(false); // legacy_know_can_report_spam + STORE_FLAG(false); // action_bar->can_report_spam STORE_FLAG(has_first_database_message_id); - STORE_FLAG(false); + STORE_FLAG(false); // legacy_is_pinned STORE_FLAG(has_first_database_message_id_by_index); STORE_FLAG(has_message_count_by_index); STORE_FLAG(has_client_data); @@ -5221,23 +5222,23 @@ void MessagesManager::Dialog::store(StorerT &storer) const { STORE_FLAG(is_folder_id_inited); STORE_FLAG(has_pending_read_channel_inbox); STORE_FLAG(know_action_bar); - STORE_FLAG(can_add_contact); - STORE_FLAG(can_block_user); - STORE_FLAG(can_share_phone_number); - STORE_FLAG(can_report_location); + STORE_FLAG(false); // action_bar->can_add_contact + STORE_FLAG(false); // action_bar->can_block_user + STORE_FLAG(false); // action_bar->can_share_phone_number + STORE_FLAG(false); // action_bar->can_report_location STORE_FLAG(has_scheduled_server_messages); STORE_FLAG(has_scheduled_database_messages); STORE_FLAG(need_repair_channel_server_unread_count); - STORE_FLAG(can_unarchive); - STORE_FLAG(has_distance); - STORE_FLAG(hide_distance); + STORE_FLAG(false); // action_bar->can_unarchive + STORE_FLAG(false); // action_bar_has_distance + STORE_FLAG(has_outgoing_messages); STORE_FLAG(has_last_yet_unsent_message); STORE_FLAG(is_blocked); STORE_FLAG(is_is_blocked_inited); STORE_FLAG(has_active_group_call); STORE_FLAG(is_group_call_empty); STORE_FLAG(has_active_group_call_id); - STORE_FLAG(can_invite_members); + STORE_FLAG(false); // action_bar->can_invite_members STORE_FLAG(has_message_ttl_setting); STORE_FLAG(is_message_ttl_setting_inited); STORE_FLAG(has_default_join_group_call_as_dialog_id); @@ -5251,6 +5252,8 @@ void MessagesManager::Dialog::store(StorerT &storer) const { if (has_flags3) { BEGIN_STORE_FLAGS(); STORE_FLAG(has_pending_join_requests); + STORE_FLAG(need_repair_action_bar); + STORE_FLAG(has_action_bar); END_STORE_FLAGS(); } @@ -5332,9 +5335,6 @@ void MessagesManager::Dialog::store(StorerT &storer) const { store(pending_read_channel_inbox_max_message_id, storer); store(pending_read_channel_inbox_server_unread_count, storer); } - if (has_distance) { - store(distance, storer); - } if (has_active_group_call_id) { store(active_group_call_id, storer); } @@ -5351,6 +5351,9 @@ void MessagesManager::Dialog::store(StorerT &storer) const { store(pending_join_request_count, storer); store(pending_join_request_user_ids, storer); } + if (has_action_bar) { + store(action_bar, storer); + } } // do not forget to resolve dialog dependencies including dependencies of last_message @@ -5359,6 +5362,7 @@ void MessagesManager::Dialog::parse(ParserT &parser) { using td::parse; bool has_draft_message; bool has_last_database_message; + bool legacy_know_can_report_spam; bool has_first_database_message_id; bool legacy_is_pinned; bool has_first_database_message_id_by_index; @@ -5379,18 +5383,26 @@ void MessagesManager::Dialog::parse(ParserT &parser) { bool has_max_notification_message_id = false; bool has_folder_id = false; bool has_pending_read_channel_inbox = false; - bool has_distance = false; bool has_active_group_call_id = false; bool has_message_ttl_setting = false; bool has_default_join_group_call_as_dialog_id = false; bool has_theme_name = false; bool has_flags3 = false; bool has_pending_join_requests = false; + bool action_bar_can_report_spam = false; + bool action_bar_can_add_contact = false; + bool action_bar_can_block_user = false; + bool action_bar_can_share_phone_number = false; + bool action_bar_can_report_location = false; + bool action_bar_can_unarchive = false; + bool action_bar_has_distance = false; + bool action_bar_can_invite_members = false; + bool has_action_bar = false; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_draft_message); PARSE_FLAG(has_last_database_message); - PARSE_FLAG(know_can_report_spam); - PARSE_FLAG(can_report_spam); + PARSE_FLAG(legacy_know_can_report_spam); + PARSE_FLAG(action_bar_can_report_spam); PARSE_FLAG(has_first_database_message_id); PARSE_FLAG(legacy_is_pinned); PARSE_FLAG(has_first_database_message_id_by_index); @@ -5428,23 +5440,23 @@ void MessagesManager::Dialog::parse(ParserT &parser) { PARSE_FLAG(is_folder_id_inited); PARSE_FLAG(has_pending_read_channel_inbox); PARSE_FLAG(know_action_bar); - PARSE_FLAG(can_add_contact); - PARSE_FLAG(can_block_user); - PARSE_FLAG(can_share_phone_number); - PARSE_FLAG(can_report_location); + PARSE_FLAG(action_bar_can_add_contact); + PARSE_FLAG(action_bar_can_block_user); + PARSE_FLAG(action_bar_can_share_phone_number); + PARSE_FLAG(action_bar_can_report_location); PARSE_FLAG(has_scheduled_server_messages); PARSE_FLAG(has_scheduled_database_messages); PARSE_FLAG(need_repair_channel_server_unread_count); - PARSE_FLAG(can_unarchive); - PARSE_FLAG(has_distance); - PARSE_FLAG(hide_distance); + PARSE_FLAG(action_bar_can_unarchive); + PARSE_FLAG(action_bar_has_distance); + PARSE_FLAG(has_outgoing_messages); PARSE_FLAG(had_last_yet_unsent_message); PARSE_FLAG(is_blocked); PARSE_FLAG(is_is_blocked_inited); PARSE_FLAG(has_active_group_call); PARSE_FLAG(is_group_call_empty); PARSE_FLAG(has_active_group_call_id); - PARSE_FLAG(can_invite_members); + PARSE_FLAG(action_bar_can_invite_members); PARSE_FLAG(has_message_ttl_setting); PARSE_FLAG(is_message_ttl_setting_inited); PARSE_FLAG(has_default_join_group_call_as_dialog_id); @@ -5456,22 +5468,15 @@ void MessagesManager::Dialog::parse(ParserT &parser) { END_PARSE_FLAGS(); } else { is_folder_id_inited = false; - know_action_bar = false; - can_add_contact = false; - can_block_user = false; - can_share_phone_number = false; - can_report_location = false; has_scheduled_server_messages = false; has_scheduled_database_messages = false; need_repair_channel_server_unread_count = false; - can_unarchive = false; - hide_distance = false; + has_outgoing_messages = false; had_last_yet_unsent_message = false; is_blocked = false; is_is_blocked_inited = false; has_active_group_call = false; is_group_call_empty = false; - can_invite_members = false; is_message_ttl_setting_inited = false; has_bots = false; is_has_bots_inited = false; @@ -5480,7 +5485,11 @@ void MessagesManager::Dialog::parse(ParserT &parser) { if (has_flags3) { BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_pending_join_requests); + PARSE_FLAG(need_repair_action_bar); + PARSE_FLAG(has_action_bar); END_PARSE_FLAGS(); + } else { + need_repair_action_bar = false; } parse(last_new_message_id, parser); @@ -5594,8 +5603,9 @@ void MessagesManager::Dialog::parse(ParserT &parser) { parse(pending_read_channel_inbox_max_message_id, parser); parse(pending_read_channel_inbox_server_unread_count, parser); } - if (has_distance) { - parse(distance, parser); + int32 action_bar_distance = -1; + if (action_bar_has_distance) { + parse(action_bar_distance, parser); } if (has_active_group_call_id) { parse(active_group_call_id, parser); @@ -5613,6 +5623,17 @@ void MessagesManager::Dialog::parse(ParserT &parser) { parse(pending_join_request_count, parser); parse(pending_join_request_user_ids, parser); } + if (has_action_bar) { + parse(action_bar, parser); + } + + (void)legacy_know_can_report_spam; + if (know_action_bar && !has_action_bar) { + action_bar = DialogActionBar::create( + action_bar_can_report_spam, action_bar_can_add_contact, action_bar_can_block_user, + action_bar_can_share_phone_number, action_bar_can_report_location, action_bar_can_unarchive, + has_outgoing_messages ? -1 : action_bar_distance, action_bar_can_invite_members); + } } template @@ -7972,11 +7993,21 @@ bool MessagesManager::update_dialog_silent_send_message(Dialog *d, bool silent_s return true; } -void MessagesManager::reget_dialog_action_bar(DialogId dialog_id, const char *source) { +void MessagesManager::reget_dialog_action_bar(DialogId dialog_id, const char *source, bool is_repair) { if (G()->close_flag() || !dialog_id.is_valid() || td_->auth_manager_->is_bot()) { return; } + Dialog *d = get_dialog_force(dialog_id, source); + if (d == nullptr) { + return; + } + + if (is_repair && !d->need_repair_action_bar) { + d->need_repair_action_bar = true; + on_dialog_updated(dialog_id, source); + } + LOG(INFO) << "Reget action bar in " << dialog_id << " from " << source; switch (dialog_id.get_type()) { case DialogType::User: @@ -7999,12 +8030,12 @@ void MessagesManager::reget_dialog_action_bar(DialogId dialog_id, const char *so void MessagesManager::repair_dialog_action_bar(Dialog *d, const char *source) { CHECK(d != nullptr); auto dialog_id = d->dialog_id; - d->know_action_bar = false; + d->need_repair_action_bar = true; if (have_input_peer(dialog_id, AccessRights::Read)) { create_actor( "RepairChatActionBarActor", 1.0, PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, source](Result result) { - send_closure(actor_id, &MessagesManager::reget_dialog_action_bar, dialog_id, source); + send_closure(actor_id, &MessagesManager::reget_dialog_action_bar, dialog_id, source, true); })) .release(); } @@ -8022,22 +8053,18 @@ void MessagesManager::hide_dialog_action_bar(DialogId dialog_id) { void MessagesManager::hide_dialog_action_bar(Dialog *d) { CHECK(d->dialog_id.get_type() != DialogType::SecretChat); - if (!d->know_can_report_spam) { + if (!d->know_action_bar) { return; } - if (!d->can_report_spam && !d->can_add_contact && !d->can_block_user && !d->can_share_phone_number && - !d->can_report_location && !d->can_unarchive && d->distance < 0 && !d->can_invite_members) { + if (d->need_repair_action_bar) { + d->need_repair_action_bar = false; + on_dialog_updated(d->dialog_id, "hide_dialog_action_bar"); + } + if (d->action_bar == nullptr) { return; } - d->can_report_spam = false; - d->can_add_contact = false; - d->can_block_user = false; - d->can_share_phone_number = false; - d->can_report_location = false; - d->can_unarchive = false; - d->distance = -1; - d->can_invite_members = false; + d->action_bar = nullptr; send_update_chat_action_bar(d); } @@ -8062,16 +8089,19 @@ void MessagesManager::remove_dialog_action_bar(DialogId dialog_id, Promise } } - if (!d->know_can_report_spam) { + if (!d->know_action_bar) { return promise.set_error(Status::Error(400, "Can't update chat action bar")); } - - if (!d->can_report_spam && !d->can_add_contact && !d->can_block_user && !d->can_share_phone_number && - !d->can_report_location && !d->can_unarchive && d->distance < 0 && !d->can_invite_members) { + if (d->need_repair_action_bar) { + d->need_repair_action_bar = false; + on_dialog_updated(dialog_id, "remove_dialog_action_bar"); + } + if (d->action_bar == nullptr) { return promise.set_value(Unit()); } - hide_dialog_action_bar(d); + d->action_bar = nullptr; + send_update_chat_action_bar(d); toggle_dialog_report_spam_state_on_server(dialog_id, false, 0, std::move(promise)); } @@ -8196,7 +8226,7 @@ void MessagesManager::report_dialog(DialogId dialog_id, const vector Dialog *user_d = d; bool is_dialog_spam_report = false; - bool can_report_spam = d->can_report_spam; + bool can_report_spam = false; if (reason.is_spam() && message_ids.empty()) { // report from action bar if (dialog_id.get_type() == DialogType::SecretChat) { @@ -8205,12 +8235,9 @@ void MessagesManager::report_dialog(DialogId dialog_id, const vector if (user_d == nullptr) { return promise.set_error(Status::Error(400, "Chat with the user not found")); } - - is_dialog_spam_report = user_d->know_can_report_spam; - can_report_spam = user_d->can_report_spam; - } else { - is_dialog_spam_report = d->know_can_report_spam; } + is_dialog_spam_report = user_d->know_action_bar; + can_report_spam = user_d->action_bar != nullptr && user_d->action_bar->can_report_spam(); } if (is_dialog_spam_report && can_report_spam) { @@ -8275,6 +8302,10 @@ void MessagesManager::on_get_peer_settings(DialogId dialog_id, tl_object_ptr &&peer_settings, bool ignore_privacy_exception) { CHECK(peer_settings != nullptr); + if (td_->auth_manager_->is_bot()) { + return; + } + 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_); @@ -8285,160 +8316,41 @@ void MessagesManager::on_get_peer_settings(DialogId dialog_id, return; } - auto can_report_spam = peer_settings->report_spam_; - auto can_add_contact = peer_settings->add_contact_; - auto can_block_user = peer_settings->block_contact_; - auto can_share_phone_number = peer_settings->share_contact_; - auto can_report_location = peer_settings->report_geo_; - auto can_unarchive = peer_settings->autoarchived_; auto distance = (peer_settings->flags_ & telegram_api::peerSettings::GEO_DISTANCE_MASK) != 0 ? peer_settings->geo_distance_ : -1; - auto can_invite_members = peer_settings->invite_members_; - if (d->can_report_spam == can_report_spam && d->can_add_contact == can_add_contact && - d->can_block_user == can_block_user && d->can_share_phone_number == can_share_phone_number && - d->can_report_location == can_report_location && d->can_unarchive == can_unarchive && d->distance == distance && - d->can_invite_members == can_invite_members) { - if (!d->know_action_bar || !d->know_can_report_spam) { - d->know_can_report_spam = true; + if (distance < -1 || d->has_outgoing_messages) { + distance = -1; + } + auto action_bar = + DialogActionBar::create(peer_settings->report_spam_, peer_settings->add_contact_, peer_settings->block_contact_, + peer_settings->share_contact_, peer_settings->report_geo_, peer_settings->autoarchived_, + distance, peer_settings->invite_members_); + + fix_dialog_action_bar(d, action_bar.get()); + + if (d->action_bar == action_bar) { + if (!d->know_action_bar || d->need_repair_action_bar) { d->know_action_bar = true; + d->need_repair_action_bar = false; on_dialog_updated(d->dialog_id, "on_get_peer_settings"); } return; } - d->know_can_report_spam = true; d->know_action_bar = true; - d->can_report_spam = can_report_spam; - d->can_add_contact = can_add_contact; - d->can_block_user = can_block_user; - d->can_share_phone_number = can_share_phone_number; - d->can_report_location = can_report_location; - d->can_unarchive = can_unarchive; - d->distance = distance < 0 ? -1 : distance; - d->can_invite_members = can_invite_members; - - fix_dialog_action_bar(d); + d->need_repair_action_bar = false; + d->action_bar = std::move(action_bar); send_update_chat_action_bar(d); } -void MessagesManager::fix_dialog_action_bar(Dialog *d) { - CHECK(d != nullptr); - if (!d->know_action_bar) { +void MessagesManager::fix_dialog_action_bar(const Dialog *d, DialogActionBar *action_bar) { + if (action_bar == nullptr) { return; } - auto dialog_type = d->dialog_id.get_type(); - if (d->distance >= 0 && dialog_type != DialogType::User) { - LOG(ERROR) << "Receive distance " << d->distance << " to " << d->dialog_id; - d->distance = -1; - } - - if (d->can_report_location) { - if (dialog_type != DialogType::Channel) { - LOG(ERROR) << "Receive can_report_location in " << d->dialog_id; - d->can_report_location = false; - } else if (d->can_report_spam || d->can_add_contact || d->can_block_user || d->can_share_phone_number || - d->can_unarchive || d->can_invite_members) { - LOG(ERROR) << "Receive action bar " << d->can_report_spam << "/" << d->can_add_contact << "/" << d->can_block_user - << "/" << d->can_share_phone_number << "/" << d->can_report_location << "/" << d->can_unarchive << "/" - << d->can_invite_members; - d->can_report_spam = false; - d->can_add_contact = false; - d->can_block_user = false; - d->can_share_phone_number = false; - d->can_unarchive = false; - d->can_invite_members = false; - CHECK(d->distance == -1); - } - } - if (d->can_invite_members) { - if (dialog_type != DialogType::Chat && (dialog_type != DialogType::Channel || is_broadcast_channel(d->dialog_id))) { - LOG(ERROR) << "Receive can_invite_members in " << d->dialog_id; - d->can_invite_members = false; - } else if (d->can_report_spam || d->can_add_contact || d->can_block_user || d->can_share_phone_number || - d->can_unarchive) { - LOG(ERROR) << "Receive action bar " << d->can_report_spam << "/" << d->can_add_contact << "/" << d->can_block_user - << "/" << d->can_share_phone_number << "/" << d->can_unarchive << "/" << d->can_invite_members; - d->can_report_spam = false; - d->can_add_contact = false; - d->can_block_user = false; - d->can_share_phone_number = false; - d->can_unarchive = false; - CHECK(d->distance == -1); - } - } - if (dialog_type == DialogType::User) { - auto user_id = d->dialog_id.get_user_id(); - bool is_me = user_id == td_->contacts_manager_->get_my_id(); - bool is_blocked = d->is_blocked; - bool is_deleted = td_->contacts_manager_->is_user_deleted(user_id); - bool is_contact = td_->contacts_manager_->is_user_contact(user_id); - if (is_me || is_blocked) { - d->can_report_spam = false; - d->can_unarchive = false; - } - if (is_me || is_blocked || is_deleted) { - d->can_share_phone_number = false; - } - if (is_me || is_blocked || is_deleted || is_contact) { - d->can_block_user = false; - d->can_add_contact = false; - } - } - if (d->folder_id != FolderId::archive()) { - d->can_unarchive = false; - } - if (d->can_share_phone_number) { - CHECK(!d->can_report_location); - CHECK(!d->can_invite_members); - if (dialog_type != DialogType::User) { - LOG(ERROR) << "Receive can_share_phone_number in " << d->dialog_id; - d->can_share_phone_number = false; - } else if (d->can_report_spam || d->can_add_contact || d->can_block_user || d->can_unarchive || d->distance >= 0) { - LOG(ERROR) << "Receive action bar " << d->can_report_spam << "/" << d->can_add_contact << "/" << d->can_block_user - << "/" << d->can_share_phone_number << "/" << d->can_unarchive << "/" << d->distance; - d->can_report_spam = false; - d->can_add_contact = false; - d->can_block_user = false; - d->can_unarchive = false; - } - } - if (d->can_block_user) { - CHECK(!d->can_report_location); - CHECK(!d->can_invite_members); - CHECK(!d->can_share_phone_number); - if (dialog_type != DialogType::User) { - LOG(ERROR) << "Receive can_block_user in " << d->dialog_id; - d->can_block_user = false; - } else if (!d->can_report_spam || !d->can_add_contact) { - LOG(ERROR) << "Receive action bar " << d->can_report_spam << "/" << d->can_add_contact << "/" - << d->can_block_user; - d->can_report_spam = true; - d->can_add_contact = true; - } - } - if (d->can_add_contact) { - CHECK(!d->can_report_location); - CHECK(!d->can_invite_members); - CHECK(!d->can_share_phone_number); - if (dialog_type != DialogType::User) { - LOG(ERROR) << "Receive can_add_contact in " << d->dialog_id; - d->can_add_contact = false; - } else if (d->can_report_spam != d->can_block_user) { - LOG(ERROR) << "Receive action bar " << d->can_report_spam << "/" << d->can_add_contact << "/" - << d->can_block_user; - d->can_report_spam = false; - d->can_block_user = false; - d->can_unarchive = false; - } - } - if (!d->can_block_user) { - d->distance = -1; - } - if (!d->can_report_spam) { - d->can_unarchive = false; - } + CHECK(d != nullptr); + action_bar->fix(td_, d->dialog_id, d->is_blocked, d->folder_id); } Result MessagesManager::get_login_button_url(FullMessageId full_message_id, int64 button_id) { @@ -20030,7 +19942,7 @@ void MessagesManager::open_dialog(Dialog *d) { break; case DialogType::Chat: td_->contacts_manager_->repair_chat_participants(dialog_id.get_chat_id()); - reget_dialog_action_bar(dialog_id, "open_dialog"); + reget_dialog_action_bar(dialog_id, "open_dialog", false); break; case DialogType::Channel: if (!is_broadcast_channel(dialog_id)) { @@ -20042,7 +19954,7 @@ void MessagesManager::open_dialog(Dialog *d) { } } get_channel_difference(dialog_id, d->pts, true, "open_dialog"); - reget_dialog_action_bar(dialog_id, "open_dialog"); + reget_dialog_action_bar(dialog_id, "open_dialog", false); break; case DialogType::SecretChat: { // to repair dialog action bar @@ -20181,65 +20093,25 @@ td_api::object_ptr MessagesManager::get_chat_type_object(Dialo } } -td_api::object_ptr MessagesManager::get_chat_action_bar_object(const Dialog *d, - bool hide_unarchive) const { +td_api::object_ptr MessagesManager::get_chat_action_bar_object(const Dialog *d) const { CHECK(d != nullptr); - if (d->dialog_id.get_type() == DialogType::SecretChat) { + 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()); if (!user_id.is_valid()) { return nullptr; } const Dialog *user_d = get_dialog(DialogId(user_id)); - if (user_d == nullptr) { + if (user_d == nullptr || user_d->action_bar == nullptr) { return nullptr; } - return get_chat_action_bar_object(user_d, d->folder_id != FolderId::archive()); + return user_d->action_bar->get_chat_action_bar_object(DialogType::User, d->folder_id != FolderId::archive()); } - if (!d->know_action_bar) { - if (d->know_can_report_spam && d->dialog_id.get_type() != DialogType::SecretChat && d->can_report_spam) { - return td_api::make_object(false); - } + if (d->action_bar == nullptr) { return nullptr; } - - if (d->can_report_location) { - CHECK(d->dialog_id.get_type() == DialogType::Channel); - CHECK(!d->can_share_phone_number && !d->can_block_user && !d->can_add_contact && !d->can_report_spam && - !d->can_invite_members); - return td_api::make_object(); - } - if (d->can_invite_members) { - CHECK(!d->can_share_phone_number && !d->can_block_user && !d->can_add_contact && !d->can_report_spam); - return td_api::make_object(); - } - if (d->can_share_phone_number) { - CHECK(d->dialog_id.get_type() == DialogType::User); - CHECK(!d->can_block_user && !d->can_add_contact && !d->can_report_spam); - return td_api::make_object(); - } - if (hide_unarchive) { - if (d->can_add_contact) { - return td_api::make_object(); - } else { - return nullptr; - } - } - if (d->can_block_user) { - CHECK(d->dialog_id.get_type() == DialogType::User); - CHECK(d->can_report_spam && d->can_add_contact); - auto distance = d->hide_distance ? -1 : d->distance; - return td_api::make_object(d->can_unarchive, distance); - } - if (d->can_add_contact) { - CHECK(d->dialog_id.get_type() == DialogType::User); - CHECK(!d->can_report_spam); - return td_api::make_object(); - } - if (d->can_report_spam) { - return td_api::make_object(d->can_unarchive); - } - return nullptr; + return d->action_bar->get_chat_action_bar_object(dialog_type, false); } string MessagesManager::get_dialog_theme_name(const Dialog *d) const { @@ -29279,10 +29151,13 @@ void MessagesManager::send_update_secret_chats_with_user_action_bar(const Dialog }); } -void MessagesManager::send_update_chat_action_bar(const Dialog *d) { +void MessagesManager::send_update_chat_action_bar(Dialog *d) { if (td_->auth_manager_->is_bot()) { return; } + if (d->action_bar != nullptr && d->action_bar->is_empty()) { + d->action_bar = nullptr; + } CHECK(d != nullptr); LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_action_bar"; @@ -30255,14 +30130,8 @@ void MessagesManager::set_dialog_is_blocked(Dialog *d, bool is_blocked) { if (d->know_action_bar) { if (is_blocked) { - if (d->can_report_spam || d->can_share_phone_number || d->can_block_user || d->can_add_contact || - d->can_unarchive || d->distance >= 0) { - d->can_report_spam = false; - d->can_share_phone_number = false; - d->can_block_user = false; - d->can_add_contact = false; - d->can_unarchive = false; - d->distance = -1; + if (d->action_bar != nullptr) { + d->action_bar = nullptr; send_update_chat_action_bar(d); } } else { @@ -30605,17 +30474,13 @@ void MessagesManager::do_set_dialog_folder_id(Dialog *d, FolderId folder_id) { auto user_id = td_->contacts_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->can_unarchive && user_d->know_action_bar) { + if (user_d != nullptr && user_d->action_bar != nullptr && user_d->action_bar->can_unarchive()) { send_closure( G()->td(), &Td::send_update, td_api::make_object(d->dialog_id.get(), get_chat_action_bar_object(d))); } } - } else if (d->can_unarchive && folder_id != FolderId::archive()) { - d->can_unarchive = false; - d->can_report_spam = false; - d->can_block_user = false; - // keep d->can_add_contact + } else if (folder_id != FolderId::archive() && d->action_bar != nullptr && d->action_bar->on_dialog_unarchived()) { send_update_chat_action_bar(d); } @@ -30890,11 +30755,7 @@ void MessagesManager::on_dialog_user_is_contact_updated(DialogId dialog_id, bool if (d != nullptr && d->is_update_new_chat_sent) { if (d->know_action_bar) { if (is_contact) { - if (d->can_block_user || d->can_add_contact) { - d->can_block_user = false; - d->can_add_contact = false; - // keep d->can_unarchive - d->distance = -1; + if (d->action_bar != nullptr && d->action_bar->on_user_contact_added()) { send_update_chat_action_bar(d); } } else { @@ -30922,11 +30783,7 @@ void MessagesManager::on_dialog_user_is_deleted_updated(DialogId dialog_id, bool if (d != nullptr && d->is_update_new_chat_sent) { if (d->know_action_bar) { if (is_deleted) { - if (d->can_share_phone_number || d->can_block_user || d->can_add_contact || d->distance >= 0) { - d->can_share_phone_number = false; - d->can_block_user = false; - d->can_add_contact = false; - d->distance = -1; + if (d->action_bar != nullptr && d->action_bar->on_user_deleted()) { send_update_chat_action_bar(d); } } else { @@ -33119,7 +32976,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq update_used_hashtags(dialog_id, m); update_top_dialogs(dialog_id, m); cancel_user_dialog_action(dialog_id, m); - try_hide_distance(dialog_id, m); + update_has_outgoing_messages(dialog_id, m); if (!td_->auth_manager_->is_bot() && d->messages == nullptr && !m->is_outgoing && dialog_id != get_my_dialog_id()) { switch (dialog_type) { @@ -33333,7 +33190,7 @@ MessagesManager::Message *MessagesManager::add_scheduled_message_to_dialog(Dialo if (from_update) { update_sent_message_contents(dialog_id, m); update_used_hashtags(dialog_id, m); - try_hide_distance(dialog_id, m); + update_has_outgoing_messages(dialog_id, m); } if (m->message_id.is_scheduled_server()) { @@ -34558,7 +34415,7 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&d, Dialog *dialog = dialog_it->second.get(); - fix_dialog_action_bar(dialog); + fix_dialog_action_bar(dialog, dialog->action_bar.get()); send_update_new_chat(dialog); @@ -34621,10 +34478,11 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab // asynchronously get dialog message TTL setting from the server get_dialog_info_full(dialog_id, Auto(), "fix_new_dialog init message_ttl_setting"); } - if (!d->know_action_bar && !td_->auth_manager_->is_bot() && dialog_type != DialogType::SecretChat && - dialog_id != get_my_dialog_id() && have_input_peer(dialog_id, AccessRights::Read)) { + if ((!d->know_action_bar || d->need_repair_action_bar) && !td_->auth_manager_->is_bot() && + dialog_type != DialogType::SecretChat && dialog_id != get_my_dialog_id() && + have_input_peer(dialog_id, AccessRights::Read)) { // asynchronously get action bar from the server - reget_dialog_action_bar(dialog_id, "fix_new_dialog"); + reget_dialog_action_bar(dialog_id, "fix_new_dialog", false); } if (d->has_active_group_call && !d->active_group_call_id.is_valid() && !td_->auth_manager_->is_bot()) { repair_dialog_active_group_call_id(dialog_id); @@ -36942,7 +36800,7 @@ void MessagesManager::update_forward_count(DialogId dialog_id, MessageId message } } -void MessagesManager::try_hide_distance(DialogId dialog_id, const Message *m) { +void MessagesManager::update_has_outgoing_messages(DialogId dialog_id, const Message *m) { CHECK(m != nullptr); if (td_->auth_manager_->is_bot() || (!m->is_outgoing && dialog_id != get_my_dialog_id())) { return; @@ -36959,21 +36817,21 @@ void MessagesManager::try_hide_distance(DialogId dialog_id, const Message *m) { case DialogType::SecretChat: { auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (user_id.is_valid()) { - d = get_dialog_force(DialogId(user_id), "try_hide_distance"); + d = get_dialog_force(DialogId(user_id), "update_has_outgoing_messages"); } break; } default: UNREACHABLE(); } - if (d == nullptr || d->hide_distance) { + if (d == nullptr || d->has_outgoing_messages) { return; } - d->hide_distance = true; - on_dialog_updated(dialog_id, "try_hide_distance"); + d->has_outgoing_messages = true; + on_dialog_updated(dialog_id, "update_has_outgoing_messages"); - if (d->distance != -1) { + if (d->action_bar != nullptr && d->action_bar->on_outgoing_message()) { send_update_chat_action_bar(d); } } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 45f456b18..b6b0a7902 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -86,6 +86,7 @@ namespace td { struct BinlogEvent; struct Dependencies; +class DialogActionBar; class DialogFilter; class DraftMessage; struct InputMessageContent; @@ -806,7 +807,7 @@ class MessagesManager final : public Actor { void remove_dialog_action_bar(DialogId dialog_id, Promise &&promise); - void reget_dialog_action_bar(DialogId dialog_id, const char *source); + void reget_dialog_action_bar(DialogId dialog_id, const char *source, bool is_repair = true); void report_dialog(DialogId dialog_id, const vector &message_ids, ReportReason &&reason, Promise &&promise); @@ -1183,6 +1184,7 @@ class MessagesManager final : public Actor { DialogNotificationSettings notification_settings; MessageTtlSetting message_ttl_setting; unique_ptr draft_message; + unique_ptr action_bar; LogEventIdWithGeneration save_draft_message_log_event_id; LogEventIdWithGeneration save_notification_settings_log_event_id; std::unordered_map read_history_log_event_ids; @@ -1203,8 +1205,6 @@ class MessagesManager final : public Actor { MessageId max_unavailable_message_id; // maximum unavailable message identifier for dialogs with cleared/unavailable history - int32 distance = -1; // distance to the peer - int32 last_clear_history_date = 0; MessageId last_clear_history_message_id; int64 order = DEFAULT_ORDER; @@ -1232,16 +1232,9 @@ class MessagesManager final : public Actor { bool is_last_message_deleted_locally = false; - bool know_can_report_spam = false; - bool can_report_spam = false; + bool need_repair_action_bar = false; bool know_action_bar = false; - bool can_add_contact = false; - bool can_block_user = false; - bool can_share_phone_number = false; - bool can_report_location = false; - bool can_unarchive = false; - bool hide_distance = false; - bool can_invite_members = false; + bool has_outgoing_messages = false; bool is_opened = false; bool was_opened = false; @@ -2363,7 +2356,7 @@ class MessagesManager final : public Actor { void send_update_secret_chats_with_user_action_bar(const Dialog *d) const; - void send_update_chat_action_bar(const Dialog *d); + void send_update_chat_action_bar(Dialog *d); void send_update_secret_chats_with_user_theme(const Dialog *d) const; @@ -2559,12 +2552,11 @@ class MessagesManager final : public Actor { void add_dialog_last_database_message(Dialog *d, unique_ptr &&last_database_message); - void fix_dialog_action_bar(Dialog *d); + void fix_dialog_action_bar(const Dialog *d, DialogActionBar *action_bar); td_api::object_ptr get_chat_type_object(DialogId dialog_id) const; - td_api::object_ptr get_chat_action_bar_object(const Dialog *d, - bool hide_unarchive = false) const; + td_api::object_ptr get_chat_action_bar_object(const Dialog *d) const; string get_dialog_theme_name(const Dialog *d) const; @@ -3062,7 +3054,7 @@ class MessagesManager final : public Actor { void update_forward_count(DialogId dialog_id, MessageId message_id, int32 update_date); - void try_hide_distance(DialogId dialog_id, const Message *m); + void update_has_outgoing_messages(DialogId dialog_id, const Message *m); string get_message_search_text(const Message *m) const; diff --git a/td/telegram/SponsoredMessageManager.cpp b/td/telegram/SponsoredMessageManager.cpp index 080a9543b..068e76823 100644 --- a/td/telegram/SponsoredMessageManager.cpp +++ b/td/telegram/SponsoredMessageManager.cpp @@ -168,13 +168,14 @@ td_api::object_ptr SponsoredMessageManager::get_sponso link = td_api::make_object(bot_username, sponsored_message.start_param); break; } - case DialogType::Channel: { - auto channel_id = sponsored_message.sponsor_dialog_id.get_channel_id(); - auto t_me = G()->shared_config().get_option_string("t_me_url", "https://t.me/"); - link = td_api::make_object( - PSTRING() << t_me << "/c" << channel_id.get() << '/' << sponsored_message.server_message_id.get()); + case DialogType::Channel: + if (sponsored_message.server_message_id.is_valid()) { + auto channel_id = sponsored_message.sponsor_dialog_id.get_channel_id(); + auto t_me = G()->shared_config().get_option_string("t_me_url", "https://t.me/"); + link = td_api::make_object( + PSTRING() << t_me << "c/" << channel_id.get() << '/' << sponsored_message.server_message_id.get()); + } break; - } default: break; } diff --git a/td/telegram/SuggestedAction.cpp b/td/telegram/SuggestedAction.cpp index 97251965a..57721ffe5 100644 --- a/td/telegram/SuggestedAction.cpp +++ b/td/telegram/SuggestedAction.cpp @@ -7,6 +7,8 @@ #include "td/telegram/SuggestedAction.h" #include "td/telegram/ChannelId.h" +#include "td/telegram/ConfigManager.h" +#include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" #include "td/telegram/Td.h" @@ -151,4 +153,23 @@ void remove_suggested_action(vector &suggested_actions, Suggest } } +void dismiss_suggested_action(SuggestedAction action, Promise &&promise) { + switch (action.type_) { + case SuggestedAction::Type::Empty: + return promise.set_error(Status::Error(400, "Action must be non-empty")); + case SuggestedAction::Type::EnableArchiveAndMuteNewChats: + case SuggestedAction::Type::CheckPassword: + case SuggestedAction::Type::CheckPhoneNumber: + case SuggestedAction::Type::SeeTicksHint: + return send_closure_later(G()->config_manager(), &ConfigManager::dismiss_suggested_action, std::move(action), + std::move(promise)); + case SuggestedAction::Type::ConvertToGigagroup: + return send_closure_later(G()->contacts_manager(), &ContactsManager::dismiss_dialog_suggested_action, + std::move(action), std::move(promise)); + default: + UNREACHABLE(); + return; + } +} + } // namespace td diff --git a/td/telegram/SuggestedAction.h b/td/telegram/SuggestedAction.h index a4e1b6df6..460a186bc 100644 --- a/td/telegram/SuggestedAction.h +++ b/td/telegram/SuggestedAction.h @@ -9,6 +9,8 @@ #include "td/telegram/DialogId.h" #include "td/telegram/td_api.h" +#include "td/actor/PromiseFuture.h" + #include "td/utils/common.h" #include "td/utils/Slice.h" @@ -70,4 +72,6 @@ void update_suggested_actions(vector &suggested_actions, void remove_suggested_action(vector &suggested_actions, SuggestedAction suggested_action); +void dismiss_suggested_action(SuggestedAction action, Promise &&promise); + } // namespace td diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index e06321ede..25d9ce63b 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -7718,7 +7718,7 @@ void Td::on_request(uint64 id, td_api::stopPoll &request) { void Td::on_request(uint64 id, const td_api::hideSuggestedAction &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->dismiss_suggested_action(SuggestedAction(request.action_), std::move(promise)); + dismiss_suggested_action(SuggestedAction(request.action_), std::move(promise)); } void Td::on_request(uint64 id, const td_api::getLoginUrlInfo &request) { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 11cca8317..eacdbdd42 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -441,6 +441,9 @@ class CliClient final : public Actor { if (str == "me") { return my_id_; } + if (str == ".") { + return opened_chat_id_; + } if (str[0] == '@') { str.remove_prefix(1); } @@ -2596,7 +2599,9 @@ class CliClient final : public Actor { } else if (op == "gdialog" || op == "gd") { send_request(td_api::make_object(as_chat_id(args))); } else if (op == "open") { - send_request(td_api::make_object(as_chat_id(args))); + auto chat_id = as_chat_id(args); + opened_chat_id_ = chat_id; + send_request(td_api::make_object(chat_id)); } else if (op == "close") { send_request(td_api::make_object(as_chat_id(args))); } else if (op == "gm") { @@ -4554,6 +4559,7 @@ class CliClient final : public Actor { int64 my_id_ = 0; string schedule_date_; string message_thread_id_; + int64 opened_chat_id_ = 0; ConcurrentScheduler *scheduler_{nullptr};