From 25676d7ff07368082c1dc77a1fb45defa59d6158 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 23 Sep 2020 01:52:16 +0300 Subject: [PATCH] Allow to specify message_thread_id in sendMessage/sendMessageAlbum/sendInlineQueryResult. GitOrigin-RevId: b9d3545b42355c04afe305f05c0366b0bf3095b0 --- example/csharp/TdExample.cs | 2 +- .../org/drinkless/tdlib/example/Example.java | 2 +- .../DoxygenTlDocumentationGenerator.php | 2 +- td/generate/scheme/td_api.tl | 18 ++-- td/generate/scheme/td_api.tlo | Bin 182280 -> 182412 bytes td/telegram/MessageCopyOptions.h | 6 +- td/telegram/MessagesManager.cpp | 88 +++++++++++++++--- td/telegram/MessagesManager.h | 15 ++- td/telegram/Td.cpp | 16 ++-- td/telegram/cli.cpp | 12 ++- td/tl/TlObject.h | 2 +- test/tdclient.cpp | 12 +-- 12 files changed, 126 insertions(+), 49 deletions(-) diff --git a/example/csharp/TdExample.cs b/example/csharp/TdExample.cs index 87a8328f4..d544799be 100644 --- a/example/csharp/TdExample.cs +++ b/example/csharp/TdExample.cs @@ -209,7 +209,7 @@ namespace TdExample TdApi.ReplyMarkup replyMarkup = new TdApi.ReplyMarkupInlineKeyboard(new TdApi.InlineKeyboardButton[][] { row, row, row }); TdApi.InputMessageContent content = new TdApi.InputMessageText(new TdApi.FormattedText(message, null), false, true); - _client.Send(new TdApi.SendMessage(chatId, 0, null, replyMarkup, content), _defaultHandler); + _client.Send(new TdApi.SendMessage(chatId, 0, 0, null, replyMarkup, content), _defaultHandler); } static void Main() diff --git a/example/java/org/drinkless/tdlib/example/Example.java b/example/java/org/drinkless/tdlib/example/Example.java index 6496ad8b4..c6e3f8e8e 100644 --- a/example/java/org/drinkless/tdlib/example/Example.java +++ b/example/java/org/drinkless/tdlib/example/Example.java @@ -299,7 +299,7 @@ public final class Example { TdApi.ReplyMarkup replyMarkup = new TdApi.ReplyMarkupInlineKeyboard(new TdApi.InlineKeyboardButton[][]{row, row, row}); TdApi.InputMessageContent content = new TdApi.InputMessageText(new TdApi.FormattedText(message, null), false, true); - client.send(new TdApi.SendMessage(chatId, 0, null, replyMarkup, content), defaultHandler); + client.send(new TdApi.SendMessage(chatId, 0, 0, null, replyMarkup, content), defaultHandler); } public static void main(String[] args) throws InterruptedException { diff --git a/td/generate/DoxygenTlDocumentationGenerator.php b/td/generate/DoxygenTlDocumentationGenerator.php index 641c1a125..99675fb7c 100644 --- a/td/generate/DoxygenTlDocumentationGenerator.php +++ b/td/generate/DoxygenTlDocumentationGenerator.php @@ -226,7 +226,7 @@ EOT * auto get_authorization_state_request = td::td_api::make_object(); * auto message_text = td::td_api::make_object("Hello, world!!!", * std::vector>()); - * auto send_message_request = td::td_api::make_object(chat_id, 0, nullptr, nullptr, + * auto send_message_request = td::td_api::make_object(chat_id, 0, 0, nullptr, nullptr, * td::td_api::make_object(std::move(message_text), false, true)); * \\endcode * diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index f2a3bb780..37152659c 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -3712,27 +3712,33 @@ getMessageLinkInfo url:string = MessageLinkInfo; //@description Sends a message. Returns the sent message -//@chat_id Target chat @reply_to_message_id Identifier of the message to reply to or 0 +//@chat_id Target chat +//@message_thread_id If not 0, a message thread identifier in which the message will be sent +//@reply_to_message_id Identifier of the message to reply to or 0 //@options Options to be used to send the message //@reply_markup Markup for replying to the message; for bots only @input_message_content The content of the message to be sent -sendMessage chat_id:int53 reply_to_message_id:int53 options:messageSendOptions reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message; +sendMessage chat_id:int53 message_thread_id:int53 reply_to_message_id:int53 options:messageSendOptions reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message; //@description Sends messages grouped together into an album. Currently only photo and video messages can be grouped into an album. Returns sent messages -//@chat_id Target chat @reply_to_message_id Identifier of a message to reply to or 0 +//@chat_id Target chat +//@message_thread_id If not 0, a message thread identifier in which the messages will be sent +//@reply_to_message_id Identifier of a message to reply to or 0 //@options Options to be used to send the messages //@input_message_contents Contents of messages to be sent -sendMessageAlbum chat_id:int53 reply_to_message_id:int53 options:messageSendOptions input_message_contents:vector = Messages; +sendMessageAlbum chat_id:int53 message_thread_id:int53 reply_to_message_id:int53 options:messageSendOptions input_message_contents:vector = Messages; //@description Invites a bot to a chat (if it is not yet a member) and sends it the /start command. Bots can't be invited to a private chat other than the chat with the bot. Bots can't be invited to channels (although they can be added as admins) and secret chats. Returns the sent message //@bot_user_id Identifier of the bot @chat_id Identifier of the target chat @parameter A hidden parameter sent to the bot for deep linking purposes (https://core.telegram.org/bots#deep-linking) sendBotStartMessage bot_user_id:int32 chat_id:int53 parameter:string = Message; //@description Sends the result of an inline query as a message. Returns the sent message. Always clears a chat draft message -//@chat_id Target chat @reply_to_message_id Identifier of a message to reply to or 0 +//@chat_id Target chat +//@message_thread_id If not 0, a message thread identifier in which the message will be sent +//@reply_to_message_id Identifier of a message to reply to or 0 //@options Options to be used to send the message //@query_id Identifier of the inline query @result_id Identifier of the inline result //@hide_via_bot If true, there will be no mention of a bot, via which the message is sent. Can be used only for bots GetOption("animation_search_bot_username"), GetOption("photo_search_bot_username") and GetOption("venue_search_bot_username") -sendInlineQueryResultMessage chat_id:int53 reply_to_message_id:int53 options:messageSendOptions query_id:int64 result_id:string hide_via_bot:Bool = Message; +sendInlineQueryResultMessage chat_id:int53 message_thread_id:int53 reply_to_message_id:int53 options:messageSendOptions query_id:int64 result_id:string hide_via_bot:Bool = Message; //@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 @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 diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index bb9f1ec6b50222c1b203179e390d1a0bd3d5b604..775522baa4e6024ce2d2bbfa7ad59cdd7adbecf0 100644 GIT binary patch delta 105 zcmeB}z}+*EyP<_~3zNW1mN_p reply_markup; @@ -32,8 +33,11 @@ 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 << ", reply to = " << copy_options.reply_to_message_id; + string_builder << ", in reply to " << copy_options.reply_to_message_id; } if (copy_options.reply_markup != nullptr) { string_builder << ", with reply markup"; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index fb2d90b83..f5bd1950a 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -4498,6 +4498,7 @@ void MessagesManager::Message::store(StorerT &storer) const { STORE_FLAG(has_reply_in_dialog_id); STORE_FLAG(has_top_reply_message_id); STORE_FLAG(has_thread_draft_message); + STORE_FLAG(is_in_thread); END_STORE_FLAGS(); } @@ -4687,6 +4688,7 @@ void MessagesManager::Message::parse(ParserT &parser) { PARSE_FLAG(has_reply_in_dialog_id); PARSE_FLAG(has_top_reply_message_id); PARSE_FLAG(has_thread_draft_message); + PARSE_FLAG(is_in_thread); END_PARSE_FLAGS(); } @@ -17299,7 +17301,8 @@ Status MessagesManager::set_dialog_draft_message(DialogId dialog_id, MessageId t if (draft_message != nullptr) { new_draft_message = make_unique(); new_draft_message->date = G()->unix_time(); - new_draft_message->reply_to_message_id = get_reply_to_message_id(d, MessageId(draft_message->reply_to_message_id_)); + new_draft_message->reply_to_message_id = + get_reply_to_message_id(d, top_thread_message_id, MessageId(draft_message->reply_to_message_id_)); auto input_message_content = std::move(draft_message->input_message_text_); if (input_message_content != nullptr) { @@ -21746,13 +21749,17 @@ MessageId MessagesManager::get_persistent_message_id(const Dialog *d, MessageId return message_id; } -MessageId MessagesManager::get_reply_to_message_id(Dialog *d, MessageId message_id) { +MessageId MessagesManager::get_reply_to_message_id(Dialog *d, MessageId top_thread_message_id, MessageId message_id) { CHECK(d != nullptr); if (!message_id.is_valid()) { + if (message_id == MessageId() && top_thread_message_id.is_valid() && top_thread_message_id.is_server() && + get_message_force(d, top_thread_message_id, "get_reply_to_message_id 1") != nullptr) { + return top_thread_message_id; + } return MessageId(); } message_id = get_persistent_message_id(d, message_id); - const Message *m = get_message_force(d, message_id, "get_reply_to_message_id"); + const Message *m = get_message_force(d, message_id, "get_reply_to_message_id 2"); if (m == nullptr || m->message_id.is_yet_unsent() || (m->message_id.is_local() && d->dialog_id.get_type() != DialogType::SecretChat)) { if (message_id.is_server() && d->dialog_id.get_type() != DialogType::SecretChat && @@ -21760,6 +21767,10 @@ MessageId MessagesManager::get_reply_to_message_id(Dialog *d, MessageId message_ // allow to reply yet unreceived server message return message_id; } + if (top_thread_message_id.is_valid() && top_thread_message_id.is_server() && + get_message_force(d, top_thread_message_id, "get_reply_to_message_id 1") != nullptr) { + return top_thread_message_id; + } // TODO local replies to local messages can be allowed // TODO replies to yet unsent messages can be allowed with special handling of them on application restart @@ -21951,7 +21962,8 @@ class MessagesManager::SendMessageLogEvent { } }; -Result MessagesManager::send_message(DialogId dialog_id, MessageId reply_to_message_id, +Result MessagesManager::send_message(DialogId dialog_id, MessageId top_thread_message_id, + MessageId reply_to_message_id, tl_object_ptr &&options, tl_object_ptr &&reply_markup, tl_object_ptr &&input_message_content) { @@ -21965,10 +21977,14 @@ Result MessagesManager::send_message(DialogId dialog_id, MessageId re } LOG(INFO) << "Begin to send message to " << dialog_id << " in reply to " << reply_to_message_id; + + reply_to_message_id = get_reply_to_message_id(d, top_thread_message_id, reply_to_message_id); + 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.reply_to_message_id = get_reply_to_message_id(d, reply_to_message_id); + 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)); @@ -21979,11 +21995,12 @@ Result MessagesManager::send_message(DialogId dialog_id, MessageId re TRY_RESULT(message_content, process_input_message_content(dialog_id, std::move(input_message_content))); TRY_RESULT(message_send_options, process_message_send_options(dialog_id, std::move(options))); TRY_STATUS(can_use_message_send_options(message_send_options, message_content)); + TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, reply_to_message_id)); // there must be no errors after get_message_to_send call bool need_update_dialog_pos = false; - Message *m = get_message_to_send(d, get_reply_to_message_id(d, reply_to_message_id), message_send_options, + Message *m = get_message_to_send(d, reply_to_message_id, message_send_options, dup_message_content(td_, dialog_id, message_content.content.get(), MessageContentDupType::Send, MessageCopyOptions()), &need_update_dialog_pos, nullptr, message_content.via_bot_user_id.is_valid()); @@ -21991,6 +22008,7 @@ Result MessagesManager::send_message(DialogId dialog_id, MessageId re m->via_bot_user_id = message_content.via_bot_user_id; m->disable_web_page_preview = message_content.disable_web_page_preview; m->clear_draft = message_content.clear_draft; + m->is_in_thread = top_thread_message_id.is_valid(); if (message_content.ttl > 0) { m->ttl = message_content.ttl; m->is_content_secret = is_secret_message_content(m->ttl, m->content->get_type()); @@ -22018,6 +22036,7 @@ Result MessagesManager::process_input_message_content( } if (input_message_content->get_id() == td_api::inputMessageForwarded::ID) { + // for sendMessageAlbum/editMessageMedia/addLocalMessage 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_))); if (!copy_options.send_copy) { @@ -22136,6 +22155,28 @@ Status MessagesManager::can_use_message_send_options(const MessageSendOptions &o return can_use_message_send_options(options, content.content, content.ttl); } +Status MessagesManager::can_use_top_thread_message_id(Dialog *d, MessageId top_thread_message_id, + MessageId reply_to_message_id) { + if (top_thread_message_id == MessageId()) { + return Status::OK(); + } + + if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server()) { + return Status::Error(400, "Invalid message thread ID specified"); + } + if (d->dialog_id.get_type() != DialogType::Channel || is_broadcast_channel(d->dialog_id)) { + return Status::Error(400, "Chat doesn't have threads"); + } + if (reply_to_message_id.is_valid()) { + const Message *reply_m = get_message(d, reply_to_message_id); + if (reply_m != nullptr && top_thread_message_id != reply_m->top_reply_message_id) { + return Status::Error(400, "The message to reply is not in the specified thread"); + } + } + + return Status::OK(); +} + int64 MessagesManager::generate_new_media_album_id() { int64 media_album_id = 0; do { @@ -22145,7 +22186,8 @@ int64 MessagesManager::generate_new_media_album_id() { } Result> MessagesManager::send_message_group( - DialogId dialog_id, MessageId reply_to_message_id, tl_object_ptr &&options, + DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id, + tl_object_ptr &&options, vector> &&input_message_contents) { if (input_message_contents.size() > MAX_GROUPED_MESSAGES) { return Status::Error(4, "Too much messages to send as an album"); @@ -22173,7 +22215,8 @@ Result> MessagesManager::send_message_group( message_contents.emplace_back(std::move(message_content.content), message_content.ttl); } - reply_to_message_id = get_reply_to_message_id(d, reply_to_message_id); + reply_to_message_id = get_reply_to_message_id(d, top_thread_message_id, reply_to_message_id); + TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, reply_to_message_id)); int64 media_album_id = 0; if (message_contents.size() > 1) { @@ -22196,6 +22239,7 @@ Result> MessagesManager::send_message_group( m->is_content_secret = is_secret_message_content(m->ttl, m->content->get_type()); } m->media_album_id = media_album_id; + m->is_in_thread = top_thread_message_id.is_valid(); save_send_message_log_event(dialog_id, m); do_send_message(dialog_id, m); @@ -22919,7 +22963,8 @@ void MessagesManager::do_send_bot_start_message(UserId bot_user_id, DialogId dia std::move(input_peer), parameter, random_id); } -Result MessagesManager::send_inline_query_result_message(DialogId dialog_id, MessageId reply_to_message_id, +Result MessagesManager::send_inline_query_result_message(DialogId dialog_id, MessageId top_thread_message_id, + MessageId reply_to_message_id, tl_object_ptr &&options, int64 query_id, const string &result_id, bool hide_via_bot) { @@ -22959,11 +23004,13 @@ Result MessagesManager::send_inline_query_result_message(DialogId dia return Status::Error(5, "Inline query result not found"); } + reply_to_message_id = get_reply_to_message_id(d, top_thread_message_id, reply_to_message_id); TRY_STATUS(can_use_message_send_options(message_send_options, content->message_content, 0)); TRY_STATUS(can_send_message_content(dialog_id, content->message_content.get(), false)); + TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, reply_to_message_id)); bool need_update_dialog_pos = false; - Message *m = get_message_to_send(d, get_reply_to_message_id(d, reply_to_message_id), message_send_options, + Message *m = get_message_to_send(d, reply_to_message_id, message_send_options, dup_message_content(td_, dialog_id, content->message_content.get(), MessageContentDupType::SendViaBot, MessageCopyOptions()), &need_update_dialog_pos, nullptr, true); @@ -22976,6 +23023,7 @@ Result MessagesManager::send_inline_query_result_message(DialogId dia } m->disable_web_page_preview = content->disable_web_page_preview; m->clear_draft = true; + m->is_in_thread = top_thread_message_id.is_valid(); update_dialog_draft_message(d, nullptr, false, !need_update_dialog_pos); @@ -24476,6 +24524,7 @@ Result> MessagesManager::forward_messages(DialogId to_dialog_i struct CopiedMessage { unique_ptr content; + MessageId top_thread_message_id; MessageId reply_to_message_id; unique_ptr reply_markup; int64 media_album_id; @@ -24506,6 +24555,7 @@ Result> MessagesManager::forward_messages(DialogId to_dialog_i bool need_copy = !message_id.is_server() || to_secret || copy_options[i].send_copy; auto type = need_copy ? MessageContentDupType::Copy : 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 = @@ -24527,6 +24577,11 @@ Result> MessagesManager::forward_messages(DialogId to_dialog_i continue; } + if (can_use_top_thread_message_id(to_dialog, top_thread_message_id, reply_to_message_id).is_error()) { + LOG(INFO) << "Ignore invalid message thread ID " << top_thread_message_id; + top_thread_message_id = MessageId(); + } + if (forwarded_message->media_album_id != 0) { auto &new_media_album_id = new_media_album_ids[forwarded_message->media_album_id]; new_media_album_id.second++; @@ -24541,8 +24596,8 @@ Result> MessagesManager::forward_messages(DialogId to_dialog_i } if (need_copy) { - copied_messages.push_back({std::move(content), reply_to_message_id, std::move(reply_markup), - forwarded_message->media_album_id, + copied_messages.push_back({std::move(content), top_thread_message_id, reply_to_message_id, + std::move(reply_markup), forwarded_message->media_album_id, get_message_disable_web_page_preview(forwarded_message), i}); continue; } @@ -24671,6 +24726,7 @@ Result> MessagesManager::forward_messages(DialogId to_dialog_i m->media_album_id = new_media_album_ids[copied_message.media_album_id].first; } m->reply_markup = std::move(copied_message.reply_markup); + m->is_in_thread = copied_message.top_thread_message_id.is_valid(); save_send_message_log_event(to_dialog_id, m); do_send_message(to_dialog_id, m); @@ -24776,8 +24832,9 @@ Result> MessagesManager::resend_messages(DialogId dialog_id, v MessageSendOptions options(message->disable_notification, message->from_background, get_message_schedule_date(message.get())); - Message *m = get_message_to_send(d, get_reply_to_message_id(d, message->reply_to_message_id), options, - std::move(new_contents[i]), &need_update_dialog_pos, nullptr, message->is_copy); + Message *m = + get_message_to_send(d, get_reply_to_message_id(d, message->top_reply_message_id, message->reply_to_message_id), + options, std::move(new_contents[i]), &need_update_dialog_pos, nullptr, message->is_copy); m->reply_markup = std::move(message->reply_markup); m->via_bot_user_id = message->via_bot_user_id; m->disable_web_page_preview = message->disable_web_page_preview; @@ -24785,6 +24842,7 @@ Result> MessagesManager::resend_messages(DialogId dialog_id, v m->ttl = message->ttl; m->is_content_secret = message->is_content_secret; m->media_album_id = new_media_album_ids[message->media_album_id].first; + m->is_in_thread = message->is_in_thread; save_send_message_log_event(dialog_id, m); do_send_message(dialog_id, m); @@ -24983,7 +25041,7 @@ Result MessagesManager::add_local_message( } } m->date = G()->unix_time(); - m->reply_to_message_id = get_reply_to_message_id(d, reply_to_message_id); + m->reply_to_message_id = get_reply_to_message_id(d, MessageId(), reply_to_message_id); if (m->reply_to_message_id.is_valid()) { const Message *reply_m = get_message(d, m->reply_to_message_id); if (reply_m != nullptr) { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 61870e27a..d8e744d93 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -394,18 +394,20 @@ class MessagesManager : public Actor { DialogId search_public_dialog(const string &username_to_search, bool force, Promise &&promise); Result send_message( - DialogId dialog_id, MessageId reply_to_message_id, tl_object_ptr &&options, - tl_object_ptr &&reply_markup, + DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id, + tl_object_ptr &&options, tl_object_ptr &&reply_markup, tl_object_ptr &&input_message_content) TD_WARN_UNUSED_RESULT; Result> send_message_group( - DialogId dialog_id, MessageId reply_to_message_id, tl_object_ptr &&options, + DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id, + tl_object_ptr &&options, vector> &&input_message_contents) TD_WARN_UNUSED_RESULT; Result send_bot_start_message(UserId bot_user_id, DialogId dialog_id, const string ¶meter) TD_WARN_UNUSED_RESULT; - Result send_inline_query_result_message(DialogId dialog_id, MessageId reply_to_message_id, + Result send_inline_query_result_message(DialogId dialog_id, MessageId top_thread_message_id, + MessageId reply_to_message_id, tl_object_ptr &&options, int64 query_id, const string &result_id, bool hide_via_bot) TD_WARN_UNUSED_RESULT; @@ -1057,6 +1059,7 @@ class MessagesManager : public Actor { bool in_game_share = false; // for send_message bool hide_via_bot = false; // for resend_message bool is_bot_start_message = false; // for resend_message + bool is_in_thread = false; // for resend_message bool have_previous = false; bool have_next = false; @@ -1731,6 +1734,8 @@ class MessagesManager : public Actor { const unique_ptr &content, int32 ttl); static Status can_use_message_send_options(const MessageSendOptions &options, const InputMessageContent &content); + Status can_use_top_thread_message_id(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id); + bool is_anonymous_administrator(DialogId dialog_id) const; bool is_anonymous_administrator(UserId sender_user_id, DialogId dialog_id, string *author_signature) const; @@ -1762,7 +1767,7 @@ class MessagesManager : public Actor { static FullMessageId get_replied_message_id(DialogId dialog_id, const Message *m); - MessageId get_reply_to_message_id(Dialog *d, MessageId message_id); + MessageId get_reply_to_message_id(Dialog *d, MessageId top_thread_message_id, MessageId message_id); static void fix_server_reply_to_message_id(DialogId dialog_id, MessageId message_id, DialogId reply_in_dialog_id, MessageId &reply_to_message_id); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 9ec14d05b..fdb8ef8eb 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5584,9 +5584,9 @@ void Td::on_request(uint64 id, const td_api::readAllChatMentions &request) { void Td::on_request(uint64 id, td_api::sendMessage &request) { DialogId dialog_id(request.chat_id_); - auto r_new_message_id = - messages_manager_->send_message(dialog_id, MessageId(request.reply_to_message_id_), std::move(request.options_), - std::move(request.reply_markup_), std::move(request.input_message_content_)); + auto r_new_message_id = messages_manager_->send_message( + dialog_id, MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_), + std::move(request.options_), std::move(request.reply_markup_), std::move(request.input_message_content_)); if (r_new_message_id.is_error()) { return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error()); } @@ -5598,9 +5598,9 @@ void Td::on_request(uint64 id, td_api::sendMessage &request) { void Td::on_request(uint64 id, td_api::sendMessageAlbum &request) { DialogId dialog_id(request.chat_id_); - auto r_message_ids = - messages_manager_->send_message_group(dialog_id, MessageId(request.reply_to_message_id_), - std::move(request.options_), std::move(request.input_message_contents_)); + auto r_message_ids = messages_manager_->send_message_group( + dialog_id, MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_), + std::move(request.options_), std::move(request.input_message_contents_)); if (r_message_ids.is_error()) { return send_closure(actor_id(this), &Td::send_error, id, r_message_ids.move_as_error()); } @@ -5631,8 +5631,8 @@ void Td::on_request(uint64 id, td_api::sendInlineQueryResultMessage &request) { DialogId dialog_id(request.chat_id_); auto r_new_message_id = messages_manager_->send_inline_query_result_message( - dialog_id, MessageId(request.reply_to_message_id_), std::move(request.options_), request.query_id_, - request.result_id_, request.hide_via_bot_); + dialog_id, MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_), + std::move(request.options_), request.query_id_, request.result_id_, request.hide_via_bot_); if (r_new_message_id.is_error()) { return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error()); } diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 620adc73a..1b7f6b670 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1394,7 +1394,7 @@ class CliClient final : public Actor { bool disable_notification = false, bool from_background = false, int64 reply_to_message_id = 0) { auto chat = as_chat_id(chat_id); auto id = send_request(td_api::make_object( - chat, reply_to_message_id, + chat, as_message_thread_id(message_thread_id_), reply_to_message_id, td_api::make_object(disable_notification, from_background, as_message_scheduling_state(schedule_date_)), nullptr, std::move(input_message_content))); @@ -2976,6 +2976,8 @@ class CliClient final : public Actor { as_chat_id(chat_id), query, offset, to_integer(limit), as_search_messages_filter(filter))); } else if (op == "ssd") { schedule_date_ = args; + } else if (op == "smti") { + message_thread_id_ = args; } else if (op == "sm" || op == "sms" || op == "smr" || op == "smf") { string chat_id; string reply_to_message_id; @@ -3018,8 +3020,8 @@ class CliClient final : public Actor { photos = full_split(args); send_request(td_api::make_object( - as_chat_id(chat_id), as_message_id(reply_to_message_id), default_message_send_options(), - transform(photos, [](const string &photo_path) { + as_chat_id(chat_id), as_message_thread_id(message_thread_id_), as_message_id(reply_to_message_id), + default_message_send_options(), transform(photos, [](const string &photo_path) { td_api::object_ptr content = td_api::make_object( as_input_file(photo_path), nullptr, Auto(), 0, 0, as_caption(""), 0); return content; @@ -3147,7 +3149,8 @@ class CliClient final : public Actor { auto chat = as_chat_id(chat_id); send_request(td_api::make_object( - chat, 0, default_message_send_options(), to_integer(query_id), result_id, op == "siqrh")); + chat, as_message_thread_id(message_thread_id_), 0, default_message_send_options(), + to_integer(query_id), result_id, op == "siqrh")); } else if (op == "gcqa") { string chat_id; string message_id; @@ -4382,6 +4385,7 @@ class CliClient final : public Actor { int32 my_id_ = 0; string schedule_date_; + string message_thread_id_; ConcurrentScheduler *scheduler_{nullptr}; diff --git a/td/tl/TlObject.h b/td/tl/TlObject.h index 6a7d3620b..9cf698ebc 100644 --- a/td/tl/TlObject.h +++ b/td/tl/TlObject.h @@ -187,7 +187,7 @@ using tl_object_ptr = tl::unique_ptr; * auto get_authorization_state_request = td::make_tl_object(); * auto message_text = td::make_tl_object("Hello, world!!!", * std::vector>()); - * auto send_message_request = td::make_tl_object(chat_id, 0, nullptr, nullptr, + * auto send_message_request = td::make_tl_object(chat_id, 0, 0, nullptr, nullptr, * td::make_tl_object(std::move(message_text), false, true)); * \endcode * diff --git a/test/tdclient.cpp b/test/tdclient.cpp index ac35b2739..4e56a0c5a 100644 --- a/test/tdclient.cpp +++ b/test/tdclient.cpp @@ -309,7 +309,7 @@ class SetUsername : public Task { auto chat = move_tl_object_as(res); this->send_query( make_tl_object( - chat->id_, 0, nullptr, nullptr, + chat->id_, 0, 0, nullptr, nullptr, make_tl_object( make_tl_object(PSTRING() << tag_ << " INIT", Auto()), false, false)), [](auto res) {}); @@ -376,7 +376,7 @@ class TestA : public Task { auto chat = move_tl_object_as(res); for (int i = 0; i < 20; i++) { this->send_query(make_tl_object( - chat->id_, 0, nullptr, nullptr, + chat->id_, 0, 0, nullptr, nullptr, make_tl_object( make_tl_object(PSTRING() << tag_ << " " << (1000 + i), Auto()), false, false)), @@ -424,7 +424,7 @@ class TestSecretChat : public Task { LOG(INFO) << "SEND ENCRYPTED MESSAGES"; for (int i = 0; i < 20; i++) { send_query(make_tl_object( - chat_id_, 0, nullptr, nullptr, + chat_id_, 0, 0, nullptr, nullptr, make_tl_object( make_tl_object(PSTRING() << tag_ << " " << (1000 + i), Auto()), false, false)), @@ -486,7 +486,7 @@ class TestFileGenerated : public Task { file.flush_write().ensure(); // important file.close(); this->send_query(make_tl_object( - chat_id_, 0, nullptr, nullptr, + chat_id_, 0, 0, nullptr, nullptr, make_tl_object( make_tl_object(file_path, "square", 0), make_tl_object( @@ -495,7 +495,7 @@ class TestFileGenerated : public Task { [](auto res) { check_td_error(res); }); this->send_query( - make_tl_object(chat_id_, 0, nullptr, nullptr, + make_tl_object(chat_id_, 0, 0, nullptr, nullptr, make_tl_object( make_tl_object(file_path, "square", 0), nullptr, true, make_tl_object(tag_, Auto()))), @@ -601,7 +601,7 @@ class CheckTestC : public Task { void one_file() { this->send_query( make_tl_object( - chat_id_, 0, nullptr, nullptr, + chat_id_, 0, 0, nullptr, nullptr, make_tl_object( make_tl_object(PSTRING() << tag_ << " ONE_FILE", Auto()), false, false)), [](auto res) { check_td_error(res); });