From 62bcac0198638fab03579ebb19f7de9599450332 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 21 Oct 2022 18:02:39 +0300 Subject: [PATCH] Support forwarding of messages to message threads. --- td/generate/scheme/td_api.tl | 3 +- td/telegram/MessageCopyOptions.h | 7 +--- td/telegram/MessagesManager.cpp | 69 +++++++++++++++++--------------- td/telegram/MessagesManager.h | 21 +++++----- td/telegram/Td.cpp | 7 ++-- td/telegram/cli.cpp | 13 +++--- 6 files changed, 61 insertions(+), 59 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index c67adfebc..3501e48ce 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -5161,13 +5161,14 @@ sendInlineQueryResultMessage chat_id:int53 message_thread_id:int53 reply_to_mess //@description Forwards previously sent messages. Returns the forwarded messages in the same order as the message identifiers passed in message_ids. If a message can't be forwarded, null will be returned instead of the message //@chat_id Identifier of the chat to which to forward messages +//@message_thread_id If not 0, a message thread identifier in which the message will be sent //@from_chat_id Identifier of the chat from which to forward messages //@message_ids Identifiers of the messages to forward. Message identifiers must be in a strictly increasing order. At most 100 messages can be forwarded simultaneously //@options Options to be used to send the messages; pass null to use default options //@send_copy Pass true to copy content of the messages without reference to the original sender. Always true if the messages are forwarded to a secret chat or are local //@remove_caption Pass true to remove media captions of message copies. Ignored if send_copy is false //@only_preview Pass true to get fake messages instead of actually forwarding them -forwardMessages chat_id:int53 from_chat_id:int53 message_ids:vector options:messageSendOptions send_copy:Bool remove_caption:Bool only_preview:Bool = Messages; +forwardMessages chat_id:int53 message_thread_id:int53 from_chat_id:int53 message_ids:vector options:messageSendOptions send_copy:Bool remove_caption:Bool only_preview:Bool = Messages; //@description Resends messages which failed to send. Can be called only for messages for which messageSendingStateFailed.can_retry is true and after specified in messageSendingStateFailed.retry_after time passed. //-If a message is re-sent, the corresponding failed to send message is deleted. Returns the sent messages in the same order as the message identifiers passed in message_ids. If a message can't be re-sent, null will be returned instead of the message diff --git a/td/telegram/MessageCopyOptions.h b/td/telegram/MessageCopyOptions.h index 262a5d751..c0b490eed 100644 --- a/td/telegram/MessageCopyOptions.h +++ b/td/telegram/MessageCopyOptions.h @@ -19,7 +19,6 @@ struct MessageCopyOptions { bool send_copy = false; bool replace_caption = false; FormattedText new_caption; - MessageId top_thread_message_id; MessageId reply_to_message_id; unique_ptr reply_markup; @@ -31,8 +30,7 @@ struct MessageCopyOptions { if (!send_copy) { return true; } - if ((replace_caption && !new_caption.text.empty()) || top_thread_message_id.is_valid() || - reply_to_message_id.is_valid() || reply_markup != nullptr) { + if ((replace_caption && !new_caption.text.empty()) || reply_to_message_id.is_valid() || reply_markup != nullptr) { return false; } return true; @@ -45,9 +43,6 @@ inline StringBuilder &operator<<(StringBuilder &string_builder, MessageCopyOptio if (copy_options.replace_caption) { string_builder << ", new_caption = " << copy_options.new_caption; } - if (copy_options.top_thread_message_id.is_valid()) { - string_builder << ", in thread of " << copy_options.top_thread_message_id; - } if (copy_options.reply_to_message_id.is_valid()) { string_builder << ", in reply to " << copy_options.reply_to_message_id; } diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index a8c88e93b..f482e326e 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -4018,7 +4018,7 @@ class ForwardMessagesQuery final : public Td::ResultHandler { explicit ForwardMessagesQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(int32 flags, DialogId to_dialog_id, DialogId from_dialog_id, + void send(int32 flags, DialogId to_dialog_id, MessageId top_thread_message_id, DialogId from_dialog_id, tl_object_ptr as_input_peer, const vector &message_ids, vector &&random_ids, int32 schedule_date) { random_ids_ = random_ids; @@ -4038,12 +4038,16 @@ class ForwardMessagesQuery final : public Td::ResultHandler { if (as_input_peer != nullptr) { flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS; } + if (top_thread_message_id.is_valid()) { + flags |= MessagesManager::SEND_MESSAGE_FLAG_IS_FROM_THREAD; + } auto query = G()->net_query_creator().create( telegram_api::messages_forwardMessages( flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(from_input_peer), MessagesManager::get_server_message_ids(message_ids), - std::move(random_ids), std::move(to_input_peer), 0, schedule_date, std::move(as_input_peer)), + std::move(random_ids), std::move(to_input_peer), top_thread_message_id.get_server_message_id().get(), + schedule_date, std::move(as_input_peer)), {{to_dialog_id, MessageContentType::Text}, {to_dialog_id, MessageContentType::Photo}}); if (td_->option_manager_->get_option_boolean("use_quick_ack")) { query->quick_ack_promise_ = PromiseCreator::lambda([random_ids = random_ids_](Result result) { @@ -26015,11 +26019,11 @@ Result> MessagesManager::send_message( if (input_message_content->get_id() == td_api::inputMessageForwarded::ID) { auto input_message = td_api::move_object_as(input_message_content); TRY_RESULT(copy_options, process_message_copy_options(dialog_id, std::move(input_message->copy_options_))); - copy_options.top_thread_message_id = top_thread_message_id; copy_options.reply_to_message_id = reply_to_message_id; TRY_RESULT_ASSIGN(copy_options.reply_markup, get_dialog_reply_markup(dialog_id, std::move(reply_markup))); - return forward_message(dialog_id, DialogId(input_message->from_chat_id_), MessageId(input_message->message_id_), - std::move(options), input_message->in_game_share_, std::move(copy_options)); + return forward_message(dialog_id, top_thread_message_id, DialogId(input_message->from_chat_id_), + MessageId(input_message->message_id_), std::move(options), input_message->in_game_share_, + std::move(copy_options)); } TRY_STATUS(can_send_message(dialog_id)); @@ -28773,28 +28777,29 @@ void MessagesManager::do_forward_messages(DialogId to_dialog_id, DialogId from_d vector random_ids = transform(messages, [this, to_dialog_id](const Message *m) { return begin_send_message(to_dialog_id, m); }); - send_closure_later(actor_id(this), &MessagesManager::send_forward_message_query, flags, to_dialog_id, from_dialog_id, - std::move(as_input_peer), message_ids, std::move(random_ids), schedule_date, - get_erase_log_event_promise(log_event_id)); + send_closure_later(actor_id(this), &MessagesManager::send_forward_message_query, flags, to_dialog_id, + messages[0]->top_thread_message_id, from_dialog_id, std::move(as_input_peer), message_ids, + std::move(random_ids), schedule_date, get_erase_log_event_promise(log_event_id)); } -void MessagesManager::send_forward_message_query(int32 flags, DialogId to_dialog_id, DialogId from_dialog_id, +void MessagesManager::send_forward_message_query(int32 flags, DialogId to_dialog_id, MessageId top_thread_message_id, + DialogId from_dialog_id, tl_object_ptr as_input_peer, vector message_ids, vector random_ids, int32 schedule_date, Promise promise) { td_->create_handler(std::move(promise)) - ->send(flags, to_dialog_id, from_dialog_id, std::move(as_input_peer), message_ids, std::move(random_ids), - schedule_date); + ->send(flags, to_dialog_id, top_thread_message_id, from_dialog_id, std::move(as_input_peer), message_ids, + std::move(random_ids), schedule_date); } Result> MessagesManager::forward_message( - DialogId to_dialog_id, DialogId from_dialog_id, MessageId message_id, + DialogId to_dialog_id, MessageId top_thread_message_id, DialogId from_dialog_id, MessageId message_id, tl_object_ptr &&options, bool in_game_share, MessageCopyOptions &©_options) { bool need_copy = copy_options.send_copy; vector all_copy_options; all_copy_options.push_back(std::move(copy_options)); - TRY_RESULT(result, forward_messages(to_dialog_id, from_dialog_id, {message_id}, std::move(options), in_game_share, - std::move(all_copy_options), false)); + TRY_RESULT(result, forward_messages(to_dialog_id, top_thread_message_id, from_dialog_id, {message_id}, + std::move(options), in_game_share, std::move(all_copy_options), false)); CHECK(result->messages_.size() == 1); if (result->messages_[0] == nullptr) { return Status::Error(400, @@ -28915,8 +28920,8 @@ void MessagesManager::fix_forwarded_message(Message *m, DialogId to_dialog_id, c } Result MessagesManager::get_forwarded_messages( - DialogId to_dialog_id, DialogId from_dialog_id, const vector &message_ids, - tl_object_ptr &&options, bool in_game_share, + DialogId to_dialog_id, MessageId top_thread_message_id, DialogId from_dialog_id, + const vector &message_ids, tl_object_ptr &&options, bool in_game_share, vector &©_options) { CHECK(copy_options.size() == message_ids.size()); if (message_ids.size() > 100) { // TODO replace with const from config or implement mass-forward @@ -28951,6 +28956,7 @@ Result MessagesManager::get_forwarded_messag TRY_STATUS(can_send_message(to_dialog_id)); TRY_RESULT(message_send_options, process_message_send_options(to_dialog_id, std::move(options), false)); + TRY_STATUS(can_use_top_thread_message_id(to_dialog, top_thread_message_id, MessageId())); { MessageId last_message_id; @@ -29029,7 +29035,6 @@ Result MessagesManager::get_forwarded_messag auto type = need_copy ? (is_local_copy ? MessageContentDupType::Copy : MessageContentDupType::ServerCopy) : MessageContentDupType::Forward; - auto top_thread_message_id = copy_options[i].top_thread_message_id; auto reply_to_message_id = copy_options[i].reply_to_message_id; auto reply_markup = std::move(copy_options[i].reply_markup); unique_ptr content = @@ -29073,14 +29078,15 @@ Result MessagesManager::get_forwarded_messag } if (is_local_copy) { - copied_messages.push_back({std::move(content), top_thread_message_id, reply_to_message_id, - forwarded_message->message_id, forwarded_message->reply_to_message_id, - std::move(reply_markup), forwarded_message->media_album_id, + copied_messages.push_back({std::move(content), reply_to_message_id, forwarded_message->message_id, + forwarded_message->reply_to_message_id, std::move(reply_markup), + forwarded_message->media_album_id, get_message_disable_web_page_preview(forwarded_message), i}); } else { forwarded_message_contents.push_back({std::move(content), forwarded_message->media_album_id, i}); } } + result.top_thread_message_id = top_thread_message_id; if (2 <= forwarded_message_contents.size() && forwarded_message_contents.size() <= MAX_GROUPED_MESSAGES) { std::unordered_set message_content_types; @@ -29122,12 +29128,12 @@ Result MessagesManager::get_forwarded_messag } Result> MessagesManager::forward_messages( - DialogId to_dialog_id, DialogId from_dialog_id, vector message_ids, + DialogId to_dialog_id, MessageId top_thread_message_id, DialogId from_dialog_id, vector message_ids, tl_object_ptr &&options, bool in_game_share, vector &©_options, bool only_preview) { TRY_RESULT(forwarded_messages_info, - get_forwarded_messages(to_dialog_id, from_dialog_id, message_ids, std::move(options), in_game_share, - std::move(copy_options))); + get_forwarded_messages(to_dialog_id, top_thread_message_id, from_dialog_id, message_ids, + std::move(options), in_game_share, std::move(copy_options))); auto from_dialog = forwarded_messages_info.from_dialog; auto to_dialog = forwarded_messages_info.to_dialog; auto message_send_options = forwarded_messages_info.message_send_options; @@ -29135,6 +29141,7 @@ Result> MessagesManager::forward_messages( auto &forwarded_message_contents = forwarded_messages_info.forwarded_message_contents; auto drop_author = forwarded_messages_info.drop_author; auto drop_media_captions = forwarded_messages_info.drop_media_captions; + top_thread_message_id = forwarded_messages_info.top_thread_message_id; FlatHashMap forwarded_message_id_to_new_message_id; vector> result(message_ids.size()); @@ -29169,7 +29176,7 @@ Result> MessagesManager::forward_messages( unique_ptr message; Message *m; if (only_preview) { - message = create_message_to_send(to_dialog, MessageId(), reply_to_message_id, message_send_options, + message = create_message_to_send(to_dialog, top_thread_message_id, reply_to_message_id, message_send_options, std::move(content), j + 1 != forwarded_message_contents.size(), std::move(forward_info), false, DialogId()); MessageId new_message_id = @@ -29179,8 +29186,8 @@ Result> MessagesManager::forward_messages( set_message_id(message, new_message_id); m = message.get(); } else { - m = get_message_to_send(to_dialog, MessageId(), reply_to_message_id, message_send_options, std::move(content), - &need_update_dialog_pos, j + 1 != forwarded_message_contents.size(), + m = get_message_to_send(to_dialog, top_thread_message_id, reply_to_message_id, message_send_options, + std::move(content), &need_update_dialog_pos, j + 1 != forwarded_message_contents.size(), std::move(forward_info)); } fix_forwarded_message(m, to_dialog_id, forwarded_message, forwarded_message_contents[j].media_album_id, @@ -29226,9 +29233,8 @@ Result> MessagesManager::forward_messages( unique_ptr message; Message *m; if (only_preview) { - message = create_message_to_send(to_dialog, copied_message.top_thread_message_id, reply_to_message_id, - message_send_options, std::move(copied_message.content), false, nullptr, is_copy, - DialogId()); + message = create_message_to_send(to_dialog, top_thread_message_id, reply_to_message_id, message_send_options, + std::move(copied_message.content), false, nullptr, is_copy, DialogId()); MessageId new_message_id = message_send_options.schedule_date != 0 ? get_next_yet_unsent_scheduled_message_id(to_dialog, message_send_options.schedule_date) @@ -29236,9 +29242,8 @@ Result> MessagesManager::forward_messages( set_message_id(message, new_message_id); m = message.get(); } else { - m = get_message_to_send(to_dialog, copied_message.top_thread_message_id, reply_to_message_id, - message_send_options, std::move(copied_message.content), &need_update_dialog_pos, false, - nullptr, is_copy); + m = get_message_to_send(to_dialog, top_thread_message_id, reply_to_message_id, message_send_options, + std::move(copied_message.content), &need_update_dialog_pos, false, nullptr, is_copy); } m->disable_web_page_preview = copied_message.disable_web_page_preview; m->media_album_id = copied_message.media_album_id; diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index ff042cc39..704d99b33 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -461,8 +461,8 @@ class MessagesManager final : public Actor { int64 query_id, const string &result_id, bool hide_via_bot) TD_WARN_UNUSED_RESULT; - Result> forward_messages(DialogId to_dialog_id, DialogId from_dialog_id, - vector message_ids, + Result> forward_messages(DialogId to_dialog_id, MessageId top_thread_message_id, + DialogId from_dialog_id, vector message_ids, tl_object_ptr &&options, bool in_game_share, vector &©_options, @@ -1989,12 +1989,13 @@ class MessagesManager final : public Actor { const vector &message_ids, bool drop_author, bool drop_media_captions, uint64 log_event_id); - void send_forward_message_query(int32 flags, DialogId to_dialog_id, DialogId from_dialog_id, - tl_object_ptr as_input_peer, vector message_ids, - vector random_ids, int32 schedule_date, Promise promise); + void send_forward_message_query(int32 flags, DialogId to_dialog_id, MessageId top_thread_message_id, + DialogId from_dialog_id, tl_object_ptr as_input_peer, + vector message_ids, vector random_ids, int32 schedule_date, + Promise promise); - Result> forward_message(DialogId to_dialog_id, DialogId from_dialog_id, - MessageId message_id, + Result> forward_message(DialogId to_dialog_id, MessageId top_thread_message_id, + DialogId from_dialog_id, MessageId message_id, tl_object_ptr &&options, bool in_game_share, MessageCopyOptions &©_options) TD_WARN_UNUSED_RESULT; @@ -2008,7 +2009,6 @@ class MessagesManager final : public Actor { struct ForwardedMessages { struct CopiedMessage { unique_ptr content; - MessageId top_thread_message_id; MessageId reply_to_message_id; MessageId original_message_id; MessageId original_reply_to_message_id; @@ -2029,12 +2029,13 @@ class MessagesManager final : public Actor { bool drop_media_captions = false; Dialog *from_dialog; + MessageId top_thread_message_id; Dialog *to_dialog; MessageSendOptions message_send_options; }; - Result get_forwarded_messages(DialogId to_dialog_id, DialogId from_dialog_id, - const vector &message_ids, + Result get_forwarded_messages(DialogId to_dialog_id, MessageId top_thread_message_id, + DialogId from_dialog_id, const vector &message_ids, tl_object_ptr &&options, bool in_game_share, vector &©_options); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 9e7a7f495..8a74cc90c 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5550,9 +5550,10 @@ void Td::on_request(uint64 id, td_api::forwardMessages &request) { auto message_copy_options = transform(input_message_ids, [send_copy = request.send_copy_, remove_caption = request.remove_caption_]( MessageId) { return MessageCopyOptions(send_copy, remove_caption); }); - auto r_messages = messages_manager_->forward_messages(DialogId(request.chat_id_), DialogId(request.from_chat_id_), - std::move(input_message_ids), std::move(request.options_), - false, std::move(message_copy_options), request.only_preview_); + auto r_messages = messages_manager_->forward_messages( + DialogId(request.chat_id_), MessageId(request.message_thread_id_), DialogId(request.from_chat_id_), + std::move(input_message_ids), std::move(request.options_), false, std::move(message_copy_options), + request.only_preview_); if (r_messages.is_error()) { send_closure(actor_id(this), &Td::send_error, id, r_messages.move_as_error()); } else { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 112579e50..e2586691e 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -3131,11 +3131,11 @@ class CliClient final : public Actor { ChatId chat_id; ChatId from_chat_id; string message_ids; - get_args(args, chat_id, from_chat_id, message_ids); - auto chat = chat_id; - send_request(td_api::make_object(chat, from_chat_id, as_message_ids(message_ids), - default_message_send_options(), op[0] == 'c', - rand_bool(), op.back() == 'p')); + string message_thread_id; + get_args(args, chat_id, from_chat_id, message_ids, message_thread_id); + send_request(td_api::make_object( + chat_id, as_message_thread_id(message_thread_id), from_chat_id, as_message_ids(message_ids), + default_message_send_options(), op[0] == 'c', rand_bool(), op.back() == 'p')); } else if (op == "resend") { ChatId chat_id; string message_ids; @@ -3871,9 +3871,8 @@ class CliClient final : public Actor { int64 query_id; string result_id; get_args(args, chat_id, query_id, result_id); - auto chat = chat_id; send_request(td_api::make_object( - chat, as_message_thread_id(message_thread_id_), 0, default_message_send_options(), query_id, result_id, + chat_id, as_message_thread_id(message_thread_id_), 0, default_message_send_options(), query_id, result_id, op == "siqrh")); } else if (op == "gcqa") { ChatId chat_id;