From d381323f56d3acaa1a59f605128922633079dc7a Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 24 Nov 2021 20:03:38 +0300 Subject: [PATCH] Add chat.allow_saving_content flag. --- td/generate/scheme/td_api.tl | 6 ++- td/telegram/ContactsManager.cpp | 66 ++++++++++++++++++++++++++++++--- td/telegram/ContactsManager.h | 9 +++++ td/telegram/MessagesManager.cpp | 39 +++++++++++++++---- td/telegram/MessagesManager.h | 5 ++- 5 files changed, 109 insertions(+), 16 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 4d0b2a22e..04940b090 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -963,6 +963,7 @@ videoChat group_call_id:int32 has_participants:Bool default_participant_id:Messa //@last_message Last message in the chat; may be null //@positions Positions of the chat in chat lists //@default_message_sender_id Default identifier of a user or chat that is chosen to send messages in the chat; may be null if the user can't change message sender +//@allow_saving_content True, if chat content can be saved locally, forwarded, or copied //@is_marked_as_unread True, if the chat is marked as unread //@is_blocked True, if the chat is blocked by the current user and private messages from the chat can't be received //@has_scheduled_messages True, if the chat has scheduled messages @@ -983,7 +984,7 @@ videoChat group_call_id:int32 has_participants:Bool default_participant_id:Messa //@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat //@draft_message A draft of a message in the chat; may be null //@client_data Application-specific data associated with the chat. (For example, the chat scroll position or local chat notification settings can be stored here.) Persistent if the message database is used -chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector default_message_sender_id:MessageSender is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl_setting:int32 theme_name:string action_bar:ChatActionBar video_chat:videoChat pending_join_requests:chatJoinRequestsInfo reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; +chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector default_message_sender_id:MessageSender allow_saving_content:Bool is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl_setting:int32 theme_name:string action_bar:ChatActionBar video_chat:videoChat pending_join_requests:chatJoinRequestsInfo reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; //@description Represents a list of chats @total_count Approximate total count of chats found @chat_ids List of chat identifiers chats total_count:int32 chat_ids:vector = Chats; @@ -3724,6 +3725,9 @@ updateChatPosition chat_id:int53 position:chatPosition = Update; //@description The default message sender that is chosen to send messages in a chat has changed @chat_id Chat identifier @default_message_sender_id New value of default_message_sender_id; may be null if the user can't change message sender updateChatDefaultMessageSenderId chat_id:int53 default_message_sender_id:MessageSender = Update; +//@description A chat content was allowed or restricted for saving @chat_id Chat identifier @allow_saving_content New value of allow_saving_content +updateChatAllowSavingContent chat_id:int53 allow_saving_content:Bool = Update; + //@description A chat was marked as unread or was read @chat_id Chat identifier @is_marked_as_unread New value of is_marked_as_unread updateChatIsMarkedAsUnread chat_id:int53 is_marked_as_unread:Bool = Update; diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 498c4e6a5..a47ebc9d3 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -3731,6 +3731,7 @@ void ContactsManager::Chat::store(StorerT &storer) const { STORE_FLAG(has_default_permissions_version); STORE_FLAG(has_pinned_message_version); STORE_FLAG(has_cache_version); + STORE_FLAG(allow_saving_content); END_STORE_FLAGS(); store(title, storer); @@ -3781,6 +3782,7 @@ void ContactsManager::Chat::parse(ParserT &parser) { PARSE_FLAG(has_default_permissions_version); PARSE_FLAG(has_pinned_message_version); PARSE_FLAG(has_cache_version); + PARSE_FLAG(allow_saving_content); END_PARSE_FLAGS(); parse(title, parser); @@ -3921,25 +3923,26 @@ void ContactsManager::Channel::store(StorerT &storer) const { STORE_FLAG(false); STORE_FLAG(sign_messages); STORE_FLAG(false); - STORE_FLAG(false); + STORE_FLAG(false); // 5 STORE_FLAG(false); STORE_FLAG(is_megagroup); STORE_FLAG(is_verified); STORE_FLAG(has_photo); - STORE_FLAG(has_username); + STORE_FLAG(has_username); // 10 STORE_FLAG(false); STORE_FLAG(use_new_rights); STORE_FLAG(has_participant_count); STORE_FLAG(have_default_permissions); - STORE_FLAG(is_scam); + STORE_FLAG(is_scam); // 15 STORE_FLAG(has_cache_version); STORE_FLAG(has_linked_channel); STORE_FLAG(has_location); STORE_FLAG(is_slow_mode_enabled); - STORE_FLAG(has_restriction_reasons); + STORE_FLAG(has_restriction_reasons); // 20 STORE_FLAG(legacy_has_active_group_call); STORE_FLAG(is_fake); STORE_FLAG(is_gigagroup); + STORE_FLAG(allow_saving_content); END_STORE_FLAGS(); store(status, storer); @@ -4009,6 +4012,7 @@ void ContactsManager::Channel::parse(ParserT &parser) { PARSE_FLAG(legacy_has_active_group_call); PARSE_FLAG(is_fake); PARSE_FLAG(is_gigagroup); + PARSE_FLAG(allow_saving_content); END_PARSE_FLAGS(); if (use_new_rights) { @@ -4672,6 +4676,22 @@ RestrictedRights ContactsManager::get_secret_chat_default_permissions(SecretChat return RestrictedRights(true, true, true, true, true, true, true, true, false, false, false); } +bool ContactsManager::get_chat_allow_saving_content(ChatId chat_id) const { + auto c = get_chat(chat_id); + if (c == nullptr) { + return false; + } + return c->allow_saving_content; +} + +bool ContactsManager::get_channel_allow_saving_content(ChannelId channel_id) const { + auto c = get_channel(channel_id); + if (c == nullptr) { + return false; + } + return c->allow_saving_content; +} + string ContactsManager::get_user_private_forward_name(UserId user_id) { auto user_full = get_user_full_force(user_id); if (user_full != nullptr) { @@ -9730,7 +9750,7 @@ void ContactsManager::update_chat(Chat *c, ChatId chat_id, bool from_binlog, boo c->is_title_changed = false; } if (c->is_default_permissions_changed) { - td_->messages_manager_->on_dialog_permissions_updated(DialogId(chat_id)); + td_->messages_manager_->on_dialog_default_permissions_updated(DialogId(chat_id)); c->is_default_permissions_changed = false; } if (c->is_is_active_changed) { @@ -9743,6 +9763,10 @@ void ContactsManager::update_chat(Chat *c, ChatId chat_id, bool from_binlog, boo } c->is_status_changed = false; } + if (c->is_allow_saving_content_changed) { + td_->messages_manager_->on_dialog_allow_saving_content_updated(DialogId(chat_id)); + c->is_allow_saving_content_changed = false; + } LOG(DEBUG) << "Update " << chat_id << ": need_save_to_database = " << c->need_save_to_database << ", is_changed = " << c->is_changed; @@ -9822,13 +9846,18 @@ void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from c->is_username_changed = false; } if (c->is_default_permissions_changed) { - td_->messages_manager_->on_dialog_permissions_updated(DialogId(channel_id)); + td_->messages_manager_->on_dialog_default_permissions_updated(DialogId(channel_id)); if (c->default_permissions != RestrictedRights(false, false, false, false, false, false, false, false, false, false, false)) { remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); } c->is_default_permissions_changed = false; } + if (c->is_allow_saving_content_changed) { + td_->messages_manager_->on_dialog_allow_saving_content_updated(DialogId(channel_id)); + c->is_allow_saving_content_changed = false; + } + if (!td_->auth_manager_->is_bot()) { if (c->restriction_reasons.empty()) { restricted_channel_ids_.erase(channel_id); @@ -12880,6 +12909,16 @@ void ContactsManager::on_update_chat_default_permissions(Chat *c, ChatId chat_id } } +void ContactsManager::on_update_chat_allow_saving_content(Chat *c, ChatId chat_id, bool allow_saving_content) { + if (c->allow_saving_content != allow_saving_content) { + LOG(INFO) << "Update " << chat_id << " allow_saving_content from " << c->allow_saving_content << " to " + << allow_saving_content; + c->allow_saving_content = allow_saving_content; + c->is_allow_saving_content_changed = true; + c->need_save_to_database = true; + } +} + void ContactsManager::on_update_chat_pinned_message(ChatId chat_id, MessageId pinned_message_id, int32 version) { if (!chat_id.is_valid()) { LOG(ERROR) << "Receive invalid " << chat_id; @@ -13201,6 +13240,17 @@ void ContactsManager::on_update_channel_default_permissions(Channel *c, ChannelI } } +void ContactsManager::on_update_channel_allow_saving_content(Channel *c, ChannelId channel_id, + bool allow_saving_content) { + if (c->allow_saving_content != allow_saving_content) { + LOG(INFO) << "Update " << channel_id << " allow_saving_content from " << c->allow_saving_content << " to " + << allow_saving_content; + c->allow_saving_content = allow_saving_content; + c->is_allow_saving_content_changed = true; + c->need_save_to_database = true; + } +} + void ContactsManager::on_update_channel_username(ChannelId channel_id, string &&username) { if (!channel_id.is_valid()) { LOG(ERROR) << "Receive invalid " << channel_id; @@ -15248,6 +15298,7 @@ void ContactsManager::on_chat_update(telegram_api::chat &chat, const char *sourc chat.version_); on_update_chat_photo(c, chat_id, std::move(chat.photo_)); on_update_chat_active(c, chat_id, is_active); + on_update_chat_allow_saving_content(c, chat_id, !chat.noforwards_); on_update_chat_migrated_to_channel_id(c, chat_id, migrated_to_channel_id); LOG_IF(INFO, !is_active && !migrated_to_channel_id.is_valid()) << chat_id << " is deactivated" << debug_str; if (c->cache_version != Chat::CACHE_VERSION) { @@ -15384,6 +15435,7 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char on_update_channel_photo(c, channel_id, std::move(channel.photo_)); on_update_channel_default_permissions(c, channel_id, get_restricted_rights(std::move(channel.default_banned_rights_))); + on_update_channel_allow_saving_content(c, channel_id, !channel.noforwards_); if (c->has_linked_channel != has_linked_channel || c->has_location != has_location || c->is_slow_mode_enabled != is_slow_mode_enabled || c->is_megagroup != is_megagroup || @@ -15442,6 +15494,7 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char on_update_channel_username(c, channel_id, std::move(channel.username_)); // uses status, must be called after on_update_channel_default_permissions(c, channel_id, get_restricted_rights(std::move(channel.default_banned_rights_))); + on_update_channel_allow_saving_content(c, channel_id, !channel.noforwards_); bool need_update_participant_count = have_participant_count && participant_count != c->participant_count; if (need_update_participant_count) { @@ -15535,6 +15588,7 @@ void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, co // on_update_channel_username(c, channel_id, ""); // don't know if channel username is empty, so don't update it tl_object_ptr banned_rights; // == nullptr on_update_channel_default_permissions(c, channel_id, get_restricted_rights(std::move(banned_rights))); + on_update_channel_allow_saving_content(c, channel_id, true); td_->messages_manager_->on_update_dialog_group_call(DialogId(channel_id), false, false, "receive channelForbidden"); bool sign_messages = false; diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 47827a1c7..664d285d1 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -107,6 +107,9 @@ class ContactsManager final : public Actor { RestrictedRights get_channel_default_permissions(ChannelId channel_id) const; RestrictedRights get_secret_chat_default_permissions(SecretChatId secret_chat_id) const; + bool get_chat_allow_saving_content(ChatId chat_id) const; + bool get_channel_allow_saving_content(ChannelId channel_id) const; + string get_user_private_forward_name(UserId user_id); string get_dialog_about(DialogId dialog_id); @@ -720,12 +723,14 @@ class ContactsManager final : public Actor { uint32 cache_version = 0; bool is_active = false; + bool allow_saving_content = true; bool is_title_changed = true; bool is_photo_changed = true; bool is_default_permissions_changed = true; bool is_status_changed = true; bool is_is_active_changed = true; + bool is_allow_saving_content_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_update_basic_group_sent = false; @@ -794,6 +799,7 @@ class ContactsManager final : public Actor { bool has_location = false; bool sign_messages = false; bool is_slow_mode_enabled = false; + bool allow_saving_content = true; bool is_megagroup = false; bool is_gigagroup = false; @@ -806,6 +812,7 @@ class ContactsManager final : public Actor { bool is_photo_changed = true; bool is_default_permissions_changed = true; bool is_status_changed = true; + bool is_allow_saving_content_changed = true; bool had_read_access = true; bool was_member = false; bool is_changed = true; // have new changes that need to be sent to the client and database @@ -1209,6 +1216,7 @@ class ContactsManager final : public Actor { static void on_update_chat_title(Chat *c, ChatId chat_id, string &&title); static void on_update_chat_active(Chat *c, ChatId chat_id, bool is_active); static void on_update_chat_migrated_to_channel_id(Chat *c, ChatId chat_id, ChannelId migrated_to_channel_id); + static void on_update_chat_allow_saving_content(Chat *c, ChatId chat_id, bool allow_saving_content); void on_update_chat_full_photo(ChatFull *chat_full, ChatId chat_id, Photo photo); bool on_update_chat_full_participants_short(ChatFull *chat_full, ChatId chat_id, int32 version); @@ -1224,6 +1232,7 @@ class ContactsManager final : public Actor { void on_update_channel_status(Channel *c, ChannelId channel_id, DialogParticipantStatus &&status); static void on_update_channel_default_permissions(Channel *c, ChannelId channel_id, RestrictedRights default_permissions); + static void on_update_channel_allow_saving_content(Channel *c, ChannelId channel_id, bool allow_saving_content); void on_update_channel_bot_user_ids(ChannelId channel_id, vector &&bot_user_ids); diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 6caa5127a..fcd1fead2 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -20260,9 +20260,9 @@ td_api::object_ptr MessagesManager::get_chat_object(const Dialog * get_chat_photo_info_object(td_->file_manager_.get(), get_dialog_photo(d->dialog_id)), get_dialog_default_permissions(d->dialog_id).get_chat_permissions_object(), get_message_object(d->dialog_id, get_message(d, d->last_message_id), "get_chat_object"), - get_chat_positions_object(d), get_default_sender_id_object(d), d->is_marked_as_unread, d->is_blocked, - get_dialog_has_scheduled_messages(d), can_delete_for_self, can_delete_for_all_users, - can_report_dialog(d->dialog_id), d->notification_settings.silent_send_message, + get_chat_positions_object(d), get_default_sender_id_object(d), get_dialog_allow_saving_content(d->dialog_id), + d->is_marked_as_unread, d->is_blocked, get_dialog_has_scheduled_messages(d), can_delete_for_self, + can_delete_for_all_users, can_report_dialog(d->dialog_id), d->notification_settings.silent_send_message, d->server_unread_count + d->local_unread_count, d->last_read_inbox_message_id.get(), d->last_read_outbox_message_id.get(), d->unread_mention_count, get_chat_notification_settings_object(&d->notification_settings), @@ -30492,10 +30492,7 @@ void MessagesManager::repair_dialog_scheduled_messages(Dialog *d) { void MessagesManager::on_update_dialog_has_scheduled_server_messages(DialogId dialog_id, bool has_scheduled_server_messages) { - if (!dialog_id.is_valid()) { - LOG(ERROR) << "Receive has_scheduled_server_messages in invalid " << dialog_id; - return; - } + CHECK(dialog_id.is_valid()); if (td_->auth_manager_->is_bot() || dialog_id.get_type() == DialogType::SecretChat) { return; } @@ -30918,7 +30915,7 @@ void MessagesManager::on_dialog_title_updated(DialogId dialog_id) { } } -void MessagesManager::on_dialog_permissions_updated(DialogId dialog_id) { +void MessagesManager::on_dialog_default_permissions_updated(DialogId dialog_id) { auto d = get_dialog(dialog_id); // called from update_user, must not create the dialog if (d != nullptr && d->is_update_new_chat_sent) { send_closure(G()->td(), &Td::send_update, @@ -30927,6 +30924,15 @@ void MessagesManager::on_dialog_permissions_updated(DialogId dialog_id) { } } +void MessagesManager::on_dialog_allow_saving_content_updated(DialogId dialog_id) { + auto d = get_dialog(dialog_id); // called from update_chat, must not create the dialog + if (d != nullptr && d->is_update_new_chat_sent) { + send_closure(G()->td(), &Td::send_update, + td_api::make_object(dialog_id.get(), + get_dialog_allow_saving_content(dialog_id))); + } +} + void MessagesManager::on_dialog_user_is_contact_updated(DialogId dialog_id, bool is_contact) { CHECK(dialog_id.get_type() == DialogType::User); auto d = get_dialog(dialog_id); // called from update_user, must not create the dialog @@ -31377,6 +31383,23 @@ RestrictedRights MessagesManager::get_dialog_default_permissions(DialogId dialog } } +bool MessagesManager::get_dialog_allow_saving_content(DialogId dialog_id) const { + switch (dialog_id.get_type()) { + case DialogType::User: + return true; + case DialogType::Chat: + return td_->contacts_manager_->get_chat_allow_saving_content(dialog_id.get_chat_id()); + case DialogType::Channel: + return td_->contacts_manager_->get_channel_allow_saving_content(dialog_id.get_channel_id()); + case DialogType::SecretChat: + return true; + case DialogType::None: + default: + UNREACHABLE(); + return false; + } +} + bool MessagesManager::get_dialog_has_scheduled_messages(const Dialog *d) const { if (!have_input_peer(d->dialog_id, AccessRights::Read)) { return false; diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index b03dbb305..3bb98ee45 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -792,7 +792,8 @@ class MessagesManager final : public Actor { void on_dialog_photo_updated(DialogId dialog_id); void on_dialog_title_updated(DialogId dialog_id); void on_dialog_username_updated(DialogId dialog_id, const string &old_username, const string &new_username); - void on_dialog_permissions_updated(DialogId dialog_id); + void on_dialog_default_permissions_updated(DialogId dialog_id); + void on_dialog_allow_saving_content_updated(DialogId dialog_id); void on_dialog_user_is_contact_updated(DialogId dialog_id, bool is_contact); void on_dialog_user_is_deleted_updated(DialogId dialog_id, bool is_deleted); @@ -2883,6 +2884,8 @@ class MessagesManager final : public Actor { RestrictedRights get_dialog_default_permissions(DialogId dialog_id) const; + bool get_dialog_allow_saving_content(DialogId dialog_id) const; + bool get_dialog_has_scheduled_messages(const Dialog *d) const; static int64 get_dialog_order(MessageId message_id, int32 message_date);