diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index ba2eb0628..7ce24721a 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -635,8 +635,8 @@ messageForwardOriginChannel chat_id:int53 message_id:int53 author_signature:stri //@origin Origin of a forwarded message //@date Point in time (Unix timestamp) when the message was originally sent //@public_service_announcement_type The type of a public service announcement for the forwarded message -//@from_chat_id For messages forwarded to the chat with the current user (Saved Messages) or to the channel's discussion group, the identifier of the chat from which the message was forwarded last time; 0 if unknown -//@from_message_id For messages forwarded to the chat with the current user (Saved Messages) or to the channel's discussion group, the identifier of the original message from which the new message was forwarded last time; 0 if unknown +//@from_chat_id For messages forwarded to the chat with the current user (Saved Messages), to the Replies bot chat, or to the channel's discussion group, the identifier of the chat from which the message was forwarded last time; 0 if unknown +//@from_message_id For messages forwarded to the chat with the current user (Saved Messages), to the Replies bot chat, or to the channel's discussion group, the identifier of the original message from which the new message was forwarded last time; 0 if unknown messageForwardInfo origin:MessageForwardOrigin date:int32 public_service_announcement_type:string from_chat_id:int53 from_message_id:int53 = MessageForwardInfo; //@description Contains information about interactions with a message @@ -4187,6 +4187,13 @@ sendCallRating call_id:int32 rating:int32 comment:string problems:vector = messages.Messages; messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; diff --git a/td/generate/scheme/telegram_api.tlo b/td/generate/scheme/telegram_api.tlo index 0e568197c..8a6e15667 100644 Binary files a/td/generate/scheme/telegram_api.tlo and b/td/generate/scheme/telegram_api.tlo differ diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index afd3b869c..c495e5929 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -1037,7 +1037,7 @@ class EditDialogPhotoQuery : public Td::ResultHandler { } auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for editDialogPhoto: " << to_string(ptr); + LOG(INFO) << "Receive result for EditDialogPhoto: " << to_string(ptr); td->updates_manager_->on_get_updates(std::move(ptr)); if (file_id_.is_valid() && was_uploaded_) { @@ -1113,7 +1113,7 @@ class EditDialogTitleQuery : public Td::ResultHandler { } auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for editDialogTitle " << to_string(ptr); + LOG(INFO) << "Receive result for EditDialogTitle: " << to_string(ptr); td->updates_manager_->on_get_updates(std::move(ptr)); promise_.set_value(Unit()); @@ -1157,7 +1157,7 @@ class EditDialogDefaultBannedRightsQuery : public Td::ResultHandler { } auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for editDialogPermissions " << to_string(ptr); + LOG(INFO) << "Receive result for EditDialogPermissions: " << to_string(ptr); td->updates_manager_->on_get_updates(std::move(ptr)); promise_.set_value(Unit()); @@ -2239,6 +2239,46 @@ class DeleteChannelHistoryQuery : public Td::ResultHandler { } }; +class BlockFromRepliesQuery : public Td::ResultHandler { + Promise promise_; + + public: + explicit BlockFromRepliesQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(MessageId message_id, bool delete_message, bool delete_all_messages, bool report_spam) { + int32 flags = 0; + if (delete_message) { + flags |= telegram_api::contacts_blockFromReplies::DELETE_MESSAGE_MASK; + } + if (delete_all_messages) { + flags |= telegram_api::contacts_blockFromReplies::DELETE_HISTORY_MASK; + } + if (report_spam) { + flags |= telegram_api::contacts_blockFromReplies::REPORT_SPAM_MASK; + } + send_query(G()->net_query_creator().create(telegram_api::contacts_blockFromReplies( + flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, message_id.get_server_message_id().get()))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for BlockFromReplies: " << to_string(ptr); + td->updates_manager_->on_get_updates(std::move(ptr)); + + promise_.set_value(Unit()); + } + + void on_error(uint64 id, Status status) override { + promise_.set_error(std::move(status)); + } +}; + class DeleteUserHistoryQuery : public Td::ResultHandler { Promise promise_; ChannelId channel_id_; @@ -2990,7 +3030,7 @@ class EditMessageActor : public NetActorOnce { } auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for editMessage: " << to_string(ptr); + LOG(INFO) << "Receive result for EditMessage: " << to_string(ptr); td->updates_manager_->on_get_updates(std::move(ptr)); promise_.set_value(Unit()); @@ -3108,7 +3148,7 @@ class SetGameScoreActor : public NetActorOnce { } auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for setGameScore: " << to_string(ptr); + LOG(INFO) << "Receive result for SetGameScore: " << to_string(ptr); td->updates_manager_->on_get_updates(std::move(ptr)); promise_.set_value(Unit()); @@ -15615,6 +15655,109 @@ void MessagesManager::on_get_common_dialogs(UserId user_id, int32 offset_chat_id common_dialogs.total_count = total_count; } +void MessagesManager::block_dialog_from_replies(MessageId message_id, bool delete_message, bool delete_all_messages, + bool report_spam, Promise &&promise) { + auto dialog_id = DialogId(ContactsManager::get_replies_bot_user_id()); + Dialog *d = get_dialog_force(dialog_id); + if (d == nullptr) { + return promise.set_error(Status::Error(400, "Chat not found")); + } + if (!have_input_peer(dialog_id, AccessRights::Read)) { + return promise.set_error(Status::Error(400, "Not enough rights")); + } + + auto *m = get_message_force(d, message_id, "block_dialog_from_replies"); + if (m == nullptr) { + return promise.set_error(Status::Error(400, "Message not found")); + } + if (m->is_outgoing || m->message_id.is_scheduled() || !m->message_id.is_server()) { + return promise.set_error(Status::Error(400, "Wrong message specified")); + } + + auto sender_user_id = m->sender_user_id; + bool need_update_dialog_pos = false; + vector deleted_message_ids; + if (delete_message) { + auto p = this->delete_message(d, message_id, true, &need_update_dialog_pos, "block_dialog_from_replies"); + CHECK(p.get() == m); + deleted_message_ids.push_back(p->message_id.get()); + } + if (delete_all_messages) { + if (sender_user_id.is_valid()) { + if (G()->parameters().use_message_db) { + LOG(INFO) << "Delete all messages from " << sender_user_id << " in " << dialog_id << " from database"; + G()->td_db()->get_messages_db_async()->delete_dialog_messages_from_user(dialog_id, sender_user_id, Auto()); + } + + vector message_ids; + find_messages_from_user(d->messages.get(), sender_user_id, message_ids); + + for (auto user_message_id : message_ids) { + auto p = this->delete_message(d, user_message_id, true, &need_update_dialog_pos, "block_dialog_from_replies 2"); + deleted_message_ids.push_back(p->message_id.get()); + } + } + } + + if (need_update_dialog_pos) { + send_update_chat_last_message(d, "block_dialog_from_replies"); + } + + send_update_delete_messages(dialog_id, std::move(deleted_message_ids), true, false); + + block_dialog_from_replies_on_server(message_id, delete_message, delete_all_messages, report_spam, 0, + std::move(promise)); +} + +class MessagesManager::BlockDialogFromRepliesOnServerLogEvent { + public: + MessageId message_id_; + bool delete_message_; + bool delete_all_messages_; + bool report_spam_; + + template + void store(StorerT &storer) const { + BEGIN_STORE_FLAGS(); + STORE_FLAG(delete_message_); + STORE_FLAG(delete_all_messages_); + STORE_FLAG(report_spam_); + END_STORE_FLAGS(); + + td::store(message_id_, storer); + } + + template + void parse(ParserT &parser) { + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(delete_message_); + PARSE_FLAG(delete_all_messages_); + PARSE_FLAG(report_spam_); + END_PARSE_FLAGS(); + + td::parse(message_id_, parser); + } +}; + +uint64 MessagesManager::save_block_dialog_from_replies_on_server_log_event(MessageId message_id, bool delete_message, + bool delete_all_messages, bool report_spam) { + BlockDialogFromRepliesOnServerLogEvent log_event{message_id, delete_message, delete_all_messages, report_spam}; + return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::BlockDialogFromRepliesOnServer, + get_log_event_storer(log_event)); +} + +void MessagesManager::block_dialog_from_replies_on_server(MessageId message_id, bool delete_message, + bool delete_all_messages, bool report_spam, + uint64 log_event_id, Promise &&promise) { + if (log_event_id == 0) { + log_event_id = save_block_dialog_from_replies_on_server_log_event(message_id, delete_message, delete_all_messages, + report_spam); + } + + td_->create_handler(get_erase_log_event_promise(log_event_id, std::move(promise))) + ->send(message_id, delete_message, delete_all_messages, report_spam); +} + std::pair> MessagesManager::get_blocked_dialogs(int32 offset, int32 limit, int64 &random_id, Promise &&promise) { LOG(INFO) << "Get blocked chats with offset = " << offset << " and limit = " << limit; @@ -34464,6 +34607,14 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event.revoke_, true, event.id_, Auto()); break; } + case LogEvent::HandlerType::BlockDialogFromRepliesOnServer: { + BlockDialogFromRepliesOnServerLogEvent log_event; + log_event_parse(log_event, event.data_).ensure(); + + block_dialog_from_replies_on_server(log_event.message_id_, log_event.delete_message_, + log_event.delete_all_messages_, log_event.report_spam_, event.id_, Auto()); + break; + } case LogEvent::HandlerType::DeleteAllChannelMessagesFromUserOnServer: { if (!G()->parameters().use_chat_info_db) { binlog_erase(G()->td_db()->get_binlog(), event.id_); diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 0e80eea7a..79deff4f0 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -556,6 +556,9 @@ class MessagesManager : public Actor { std::pair> get_common_dialogs(UserId user_id, DialogId offset_dialog_id, int32 limit, bool force, Promise &&promise); + void block_dialog_from_replies(MessageId message_id, bool delete_message, bool delete_all_messages, bool report_spam, + Promise &&promise); + std::pair> get_blocked_dialogs(int32 offset, int32 limit, int64 &random_id, Promise &&promise); @@ -1592,6 +1595,7 @@ class MessagesManager : public Actor { } }; + class BlockDialogFromRepliesOnServerLogEvent; class ChangeDialogReportSpamStateOnServerLogEvent; class DeleteAllChannelMessagesFromUserOnServerLogEvent; class DeleteDialogHistoryFromServerLogEvent; @@ -1739,9 +1743,10 @@ class MessagesManager : public Actor { bool is_anonymous_administrator(UserId sender_user_id, DialogId dialog_id, string *author_signature) const; - Message *get_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id, const MessageSendOptions &options, - unique_ptr &&content, bool *need_update_dialog_pos, - unique_ptr forward_info = nullptr, bool is_copy = false); + Message *get_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id, + const MessageSendOptions &options, unique_ptr &&content, + bool *need_update_dialog_pos, unique_ptr forward_info = nullptr, + bool is_copy = false); int64 begin_send_message(DialogId dialog_id, const Message *m); @@ -1886,6 +1891,9 @@ class MessagesManager : public Actor { void delete_dialog_history_from_server(DialogId dialog_id, MessageId max_message_id, bool remove_from_dialog_list, bool revoke, bool allow_error, uint64 log_event_id, Promise &&promise); + void block_dialog_from_replies_on_server(MessageId message_id, bool delete_message, bool delete_all_messages, + bool report_spam, uint64 log_event_id, Promise &&promise); + void delete_all_channel_messages_from_user_on_server(ChannelId channel_id, UserId user_id, uint64 log_event_id, Promise &&promise); @@ -2843,6 +2851,9 @@ class MessagesManager : public Actor { uint64 save_delete_dialog_history_from_server_log_event(DialogId dialog_id, MessageId max_message_id, bool remove_from_dialog_list, bool revoke); + uint64 save_block_dialog_from_replies_on_server_log_event(MessageId message_id, bool delete_message, + bool delete_all_messages, bool report_spam); + uint64 save_delete_all_channel_messages_from_user_on_server_log_event(ChannelId channel_id, UserId user_id); uint64 save_read_all_dialog_mentions_on_server_log_event(DialogId dialog_id); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index fdb8ef8eb..03a8a1816 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6360,6 +6360,13 @@ void Td::on_request(uint64 id, const td_api::deleteFile &request) { "td_api::deleteFile"); } +void Td::on_request(uint64 id, const td_api::blockChatFromReplies &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + messages_manager_->block_dialog_from_replies(MessageId(request.message_id_), request.delete_message_, + request.delete_all_messages_, request.report_spam_, std::move(promise)); +} + void Td::on_request(uint64 id, const td_api::getBlockedChats &request) { CHECK_IS_USER(); CREATE_REQUEST(GetBlockedChatsRequest, request.offset_, request.limit_); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 161ef3478..37a6d7cd9 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -784,6 +784,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::deleteFile &request); + void on_request(uint64 id, const td_api::blockChatFromReplies &request); + void on_request(uint64 id, const td_api::getBlockedChats &request); void on_request(uint64 id, td_api::addContact &request); diff --git a/td/telegram/TdDb.cpp b/td/telegram/TdDb.cpp index 8f33b9e62..f828a04a9 100644 --- a/td/telegram/TdDb.cpp +++ b/td/telegram/TdDb.cpp @@ -114,6 +114,7 @@ Status init_binlog(Binlog &binlog, string path, BinlogKeyValue &binlog_p case LogEvent::HandlerType::DeleteScheduledMessagesFromServer: case LogEvent::HandlerType::ToggleDialogIsBlockedOnServer: case LogEvent::HandlerType::ReadMessageThreadHistoryOnServer: + case LogEvent::HandlerType::BlockDialogFromRepliesOnServer: events.to_messages_manager.push_back(event.clone()); break; case LogEvent::HandlerType::AddMessagePushNotification: diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 1b7f6b670..b7db6a0c1 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2925,6 +2925,16 @@ class CliClient final : public Actor { string is_blocked; std::tie(chat_id, is_blocked) = split(args); send_request(td_api::make_object(as_chat_id(chat_id), as_bool(is_blocked))); + } else if (op == "bcfr") { + string message_id; + string delete_message; + string delete_all_messages; + string report_spam; + std::tie(message_id, args) = split(args); + std::tie(delete_message, args) = split(args); + std::tie(delete_all_messages, report_spam) = split(args); + send_request(td_api::make_object( + as_message_id(message_id), as_bool(delete_message), as_bool(delete_all_messages), as_bool(report_spam))); } else if (op == "tcddn") { string chat_id; string default_disable_notification; diff --git a/td/telegram/logevent/LogEvent.h b/td/telegram/logevent/LogEvent.h index 1d3cf8cba..73a25dc7b 100644 --- a/td/telegram/logevent/LogEvent.h +++ b/td/telegram/logevent/LogEvent.h @@ -98,6 +98,7 @@ class LogEvent { DeleteScheduledMessagesFromServer = 0x117, ToggleDialogIsBlockedOnServer = 0x118, ReadMessageThreadHistoryOnServer = 0x119, + BlockDialogFromRepliesOnServer = 0x120, GetChannelDifference = 0x140, AddMessagePushNotification = 0x200, EditMessagePushNotification = 0x201,