Allow to reply stories.

This commit is contained in:
levlam 2023-06-08 17:27:24 +03:00
parent 6116573a3b
commit fa94abaccb
14 changed files with 388 additions and 226 deletions

View File

@ -391,6 +391,7 @@ set(TDLIB_SOURCE
td/telegram/MessageEntity.cpp td/telegram/MessageEntity.cpp
td/telegram/MessageExtendedMedia.cpp td/telegram/MessageExtendedMedia.cpp
td/telegram/MessageId.cpp td/telegram/MessageId.cpp
td/telegram/MessageInputReplyTo.cpp
td/telegram/MessageReaction.cpp td/telegram/MessageReaction.cpp
td/telegram/MessageReplyHeader.cpp td/telegram/MessageReplyHeader.cpp
td/telegram/MessageReplyInfo.cpp td/telegram/MessageReplyInfo.cpp
@ -659,6 +660,7 @@ set(TDLIB_SOURCE
td/telegram/MessageEntity.h td/telegram/MessageEntity.h
td/telegram/MessageExtendedMedia.h td/telegram/MessageExtendedMedia.h
td/telegram/MessageId.h td/telegram/MessageId.h
td/telegram/MessageInputReplyTo.h
td/telegram/MessageLinkInfo.h td/telegram/MessageLinkInfo.h
td/telegram/MessageReaction.h td/telegram/MessageReaction.h
td/telegram/MessageReplyHeader.h td/telegram/MessageReplyHeader.h

View File

@ -1131,12 +1131,12 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool n
//@class MessageReplyTo @description Contains information about the message or the story a message is replying to //@class MessageReplyTo @description Contains information about the message or the story a message is replying to
//@description Describes a replied message //@description Describes a replied message
//@chat_id The identifier of the chat to which the replied message belongs. For example, messages in the Replies chat are replies to messages in different chats //@chat_id The identifier of the chat to which the replied message belongs; ignored for outgoing replies. For example, messages in the Replies chat are replies to messages in different chats
//@message_id The identifier of the replied message //@message_id The identifier of the replied message
messageReplyToMessage chat_id:int53 message_id:int53 = MessageReplyTo; messageReplyToMessage chat_id:int53 message_id:int53 = MessageReplyTo;
//@description Describes a replied story @sender_user_id The identifier of the sender of the replied story @story_id The identifier of the replied story //@description Describes a replied story @sender_user_id The identifier of the sender of the replied story. Currently, stories can be replied only in the corresponding private chats @story_id The identifier of the replied story
messageReplyToStory sender_user_id:int53 story_id:int53 = MessageReplyTo; messageReplyToStory sender_user_id:int53 story_id:int32 = MessageReplyTo;
//@description Describes a message //@description Describes a message
@ -4359,7 +4359,7 @@ notificationTypeNewSecretChat = NotificationType;
notificationTypeNewCall call_id:int32 = NotificationType; notificationTypeNewCall call_id:int32 = NotificationType;
//@description New message was received through a push notification //@description New message was received through a push notification
//@message_id The message identifier. The message will not be available in the chat history, but the ID can be used in viewMessages, or as reply_to_message_id //@message_id The message identifier. The message will not be available in the chat history, but the ID can be used in viewMessages, or as a message to reply
//@sender_id Identifier of the sender of the message. Corresponding user or chat may be inaccessible //@sender_id Identifier of the sender of the message. Corresponding user or chat may be inaccessible
//@sender_name Name of the sender //@sender_name Name of the sender
//@is_outgoing True, if the message is outgoing //@is_outgoing True, if the message is outgoing
@ -6376,20 +6376,20 @@ setChatMessageSender chat_id:int53 message_sender_id:MessageSender = Ok;
//@description Sends a message. Returns the sent message //@description Sends a message. Returns the sent message
//@chat_id Target chat //@chat_id Target chat
//@message_thread_id If not 0, a message thread identifier in which the message will be sent //@message_thread_id If not 0, a message thread identifier in which the message will be sent
//@reply_to_message_id Identifier of the replied message; 0 if none //@reply_to Identifier of the replied message or story; pass null if none
//@options Options to be used to send the message; pass null to use default options //@options Options to be used to send the message; pass null to use default options
//@reply_markup Markup for replying to the message; pass null if none; for bots only //@reply_markup Markup for replying to the message; pass null if none; for bots only
//@input_message_content The content of the message to be sent //@input_message_content The content of the message to be sent
sendMessage chat_id:int53 message_thread_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:MessageReplyTo options:messageSendOptions reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message;
//@description Sends 2-10 messages grouped together into an album. Currently, only audio, document, photo and video messages can be grouped into an album. Documents and audio files can be only grouped in an album with messages of the same type. Returns sent messages //@description Sends 2-10 messages grouped together into an album. Currently, only audio, document, photo and video messages can be grouped into an album. Documents and audio files can be only grouped in an album with messages of the same type. Returns sent messages
//@chat_id Target chat //@chat_id Target chat
//@message_thread_id If not 0, a message thread identifier in which the messages will be sent //@message_thread_id If not 0, a message thread identifier in which the messages will be sent
//@reply_to_message_id Identifier of a replied message; 0 if none //@reply_to Identifier of the replied message or story; pass null if none
//@options Options to be used to send the messages; pass null to use default options //@options Options to be used to send the messages; pass null to use default options
//@input_message_contents Contents of messages to be sent. At most 10 messages can be added to an album //@input_message_contents Contents of messages to be sent. At most 10 messages can be added to an album
//@only_preview Pass true to get fake messages instead of actually sending them //@only_preview Pass true to get fake messages instead of actually sending them
sendMessageAlbum chat_id:int53 message_thread_id:int53 reply_to_message_id:int53 options:messageSendOptions input_message_contents:vector<InputMessageContent> only_preview:Bool = Messages; sendMessageAlbum chat_id:int53 message_thread_id:int53 reply_to:MessageReplyTo options:messageSendOptions input_message_contents:vector<InputMessageContent> only_preview:Bool = 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 //@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 //@bot_user_id Identifier of the bot
@ -6400,12 +6400,12 @@ sendBotStartMessage bot_user_id:int53 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 //@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 //@chat_id Target chat
//@message_thread_id If not 0, a message thread identifier in which the message will be sent //@message_thread_id If not 0, a message thread identifier in which the message will be sent
//@reply_to_message_id Identifier of a replied message; 0 if none //@reply_to Identifier of the replied message or story; pass null if none
//@options Options to be used to send the message; pass null to use default options //@options Options to be used to send the message; pass null to use default options
//@query_id Identifier of the inline query //@query_id Identifier of the inline query
//@result_id Identifier of the inline result //@result_id Identifier of the inline result
//@hide_via_bot Pass true to hide the 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") //@hide_via_bot Pass true to hide the 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 message_thread_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:MessageReplyTo 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 //@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 //@chat_id Identifier of the chat to which to forward messages
@ -6427,10 +6427,10 @@ resendMessages chat_id:int53 message_ids:vector<int53> = Messages;
//@description Adds a local message to a chat. The message is persistent across application restarts only if the message database is used. Returns the added message //@description Adds a local message to a chat. The message is persistent across application restarts only if the message database is used. Returns the added message
//@chat_id Target chat //@chat_id Target chat
//@sender_id Identifier of the sender of the message //@sender_id Identifier of the sender of the message
//@reply_to_message_id Identifier of the replied message; 0 if none //@reply_to Identifier of the replied message or story; pass null if none
//@disable_notification Pass true to disable notification for the message //@disable_notification Pass true to disable notification for the message
//@input_message_content The content of the message to be added //@input_message_content The content of the message to be added
addLocalMessage chat_id:int53 sender_id:MessageSender reply_to_message_id:int53 disable_notification:Bool input_message_content:InputMessageContent = Message; addLocalMessage chat_id:int53 sender_id:MessageSender reply_to:MessageReplyTo disable_notification:Bool input_message_content:InputMessageContent = Message;
//@description Deletes messages @chat_id Chat identifier @message_ids Identifiers of the messages to be deleted @revoke Pass true to delete messages for all chat members. Always true for supergroups, channels and secret chats //@description Deletes messages @chat_id Chat identifier @message_ids Identifiers of the messages to be deleted @revoke Pass true to delete messages for all chat members. Always true for supergroups, channels and secret chats
deleteMessages chat_id:int53 message_ids:vector<int53> revoke:Bool = Ok; deleteMessages chat_id:int53 message_ids:vector<int53> revoke:Bool = Ok;
@ -6778,8 +6778,8 @@ sendWebAppData bot_user_id:int53 button_text:string data:string = Ok;
//@theme Preferred Web App theme; pass null to use the default theme //@theme Preferred Web App theme; pass null to use the default theme
//@application_name Short name of the application; 0-64 English letters, digits, and underscores //@application_name Short name of the application; 0-64 English letters, digits, and underscores
//@message_thread_id If not 0, a message thread identifier in which the message will be sent //@message_thread_id If not 0, a message thread identifier in which the message will be sent
//@reply_to_message_id Identifier of the replied message for the message sent by the Web App; 0 if none //@reply_to Identifier of the replied message or story for the message sent by the Web App; pass null if none
openWebApp chat_id:int53 bot_user_id:int53 url:string theme:themeParameters application_name:string message_thread_id:int53 reply_to_message_id:int53 = WebAppInfo; openWebApp chat_id:int53 bot_user_id:int53 url:string theme:themeParameters application_name:string message_thread_id:int53 reply_to:MessageReplyTo = WebAppInfo;
//@description Informs TDLib that a previously opened Web App was closed @web_app_launch_id Identifier of Web App launch, received from openWebApp //@description Informs TDLib that a previously opened Web App was closed @web_app_launch_id Identifier of Web App launch, received from openWebApp
closeWebApp web_app_launch_id:int64 = Ok; closeWebApp web_app_launch_id:int64 = Ok;

View File

@ -119,7 +119,7 @@ class RequestWebViewQuery final : public Td::ResultHandler {
DialogId dialog_id_; DialogId dialog_id_;
UserId bot_user_id_; UserId bot_user_id_;
MessageId top_thread_message_id_; MessageId top_thread_message_id_;
MessageId reply_to_message_id_; MessageInputReplyTo input_reply_to_;
DialogId as_dialog_id_; DialogId as_dialog_id_;
bool from_attach_menu_ = false; bool from_attach_menu_ = false;
@ -130,11 +130,11 @@ class RequestWebViewQuery final : public Td::ResultHandler {
void send(DialogId dialog_id, UserId bot_user_id, tl_object_ptr<telegram_api::InputUser> &&input_user, string &&url, void send(DialogId dialog_id, UserId bot_user_id, tl_object_ptr<telegram_api::InputUser> &&input_user, string &&url,
td_api::object_ptr<td_api::themeParameters> &&theme, string &&platform, MessageId top_thread_message_id, td_api::object_ptr<td_api::themeParameters> &&theme, string &&platform, MessageId top_thread_message_id,
MessageId reply_to_message_id, bool silent, DialogId as_dialog_id) { MessageInputReplyTo input_reply_to, bool silent, DialogId as_dialog_id) {
dialog_id_ = dialog_id; dialog_id_ = dialog_id;
bot_user_id_ = bot_user_id; bot_user_id_ = bot_user_id;
top_thread_message_id_ = top_thread_message_id; top_thread_message_id_ = top_thread_message_id;
reply_to_message_id_ = reply_to_message_id; input_reply_to_ = input_reply_to;
as_dialog_id_ = as_dialog_id; as_dialog_id_ = as_dialog_id;
int32 flags = 0; int32 flags = 0;
@ -167,7 +167,7 @@ class RequestWebViewQuery final : public Td::ResultHandler {
flags |= telegram_api::messages_requestWebView::THEME_PARAMS_MASK; flags |= telegram_api::messages_requestWebView::THEME_PARAMS_MASK;
} }
auto reply_to = MessagesManager::get_input_reply_to(reply_to_message_id, top_thread_message_id); auto reply_to = input_reply_to_.get_input_reply_to(td_, top_thread_message_id);
if (reply_to != nullptr) { if (reply_to != nullptr) {
flags |= telegram_api::messages_requestWebView::REPLY_TO_MASK; flags |= telegram_api::messages_requestWebView::REPLY_TO_MASK;
} }
@ -197,7 +197,7 @@ class RequestWebViewQuery final : public Td::ResultHandler {
auto ptr = result_ptr.move_as_ok(); auto ptr = result_ptr.move_as_ok();
td_->attach_menu_manager_->open_web_view(ptr->query_id_, dialog_id_, bot_user_id_, top_thread_message_id_, td_->attach_menu_manager_->open_web_view(ptr->query_id_, dialog_id_, bot_user_id_, top_thread_message_id_,
reply_to_message_id_, as_dialog_id_); input_reply_to_, as_dialog_id_);
promise_.set_value(td_api::make_object<td_api::webAppInfo>(ptr->query_id_, ptr->url_)); promise_.set_value(td_api::make_object<td_api::webAppInfo>(ptr->query_id_, ptr->url_));
} }
@ -216,7 +216,7 @@ class ProlongWebViewQuery final : public Td::ResultHandler {
public: public:
void send(DialogId dialog_id, UserId bot_user_id, int64 query_id, MessageId top_thread_message_id, void send(DialogId dialog_id, UserId bot_user_id, int64 query_id, MessageId top_thread_message_id,
MessageId reply_to_message_id, bool silent, DialogId as_dialog_id) { MessageInputReplyTo input_reply_to, bool silent, DialogId as_dialog_id) {
dialog_id_ = dialog_id; dialog_id_ = dialog_id;
auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write); auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
@ -226,7 +226,7 @@ class ProlongWebViewQuery final : public Td::ResultHandler {
} }
int32 flags = 0; int32 flags = 0;
auto reply_to = MessagesManager::get_input_reply_to(reply_to_message_id, top_thread_message_id); auto reply_to = input_reply_to.get_input_reply_to(td_, top_thread_message_id);
if (reply_to != nullptr) { if (reply_to != nullptr) {
flags |= telegram_api::messages_prolongWebView::REPLY_TO_MASK; flags |= telegram_api::messages_prolongWebView::REPLY_TO_MASK;
} }
@ -673,7 +673,7 @@ void AttachMenuManager::ping_web_view() {
bool silent = td_->messages_manager_->get_dialog_silent_send_message(opened_web_view.dialog_id_); bool silent = td_->messages_manager_->get_dialog_silent_send_message(opened_web_view.dialog_id_);
td_->create_handler<ProlongWebViewQuery>()->send( td_->create_handler<ProlongWebViewQuery>()->send(
opened_web_view.dialog_id_, opened_web_view.bot_user_id_, it.first, opened_web_view.top_thread_message_id_, opened_web_view.dialog_id_, opened_web_view.bot_user_id_, it.first, opened_web_view.top_thread_message_id_,
opened_web_view.reply_to_message_id_, silent, opened_web_view.as_dialog_id_); opened_web_view.input_reply_to_, silent, opened_web_view.as_dialog_id_);
} }
schedule_ping_web_view(); schedule_ping_web_view();
@ -753,7 +753,7 @@ void AttachMenuManager::request_app_web_view(DialogId dialog_id, UserId bot_user
} }
void AttachMenuManager::request_web_view(DialogId dialog_id, UserId bot_user_id, MessageId top_thread_message_id, void AttachMenuManager::request_web_view(DialogId dialog_id, UserId bot_user_id, MessageId top_thread_message_id,
MessageId reply_to_message_id, string &&url, td_api::object_ptr<td_api::MessageReplyTo> &&reply_to, string &&url,
td_api::object_ptr<td_api::themeParameters> &&theme, string &&platform, td_api::object_ptr<td_api::themeParameters> &&theme, string &&platform,
Promise<td_api::object_ptr<td_api::webAppInfo>> &&promise) { Promise<td_api::object_ptr<td_api::webAppInfo>> &&promise) {
TRY_STATUS_PROMISE(promise, td_->contacts_manager_->get_bot_data(bot_user_id)); TRY_STATUS_PROMISE(promise, td_->contacts_manager_->get_bot_data(bot_user_id));
@ -781,26 +781,24 @@ void AttachMenuManager::request_web_view(DialogId dialog_id, UserId bot_user_id,
return promise.set_error(Status::Error(400, "Have no write access to the chat")); return promise.set_error(Status::Error(400, "Have no write access to the chat"));
} }
if (!reply_to_message_id.is_valid() || !reply_to_message_id.is_server() ||
!td_->messages_manager_->have_message_force({dialog_id, reply_to_message_id}, "request_web_view")) {
reply_to_message_id = MessageId();
}
if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server() || if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server() ||
dialog_id.get_type() != DialogType::Channel || dialog_id.get_type() != DialogType::Channel ||
!td_->contacts_manager_->is_megagroup_channel(dialog_id.get_channel_id())) { !td_->contacts_manager_->is_megagroup_channel(dialog_id.get_channel_id())) {
top_thread_message_id = MessageId(); top_thread_message_id = MessageId();
} }
auto input_reply_to =
td_->messages_manager_->get_message_input_reply_to(dialog_id, top_thread_message_id, std::move(reply_to), false);
bool silent = td_->messages_manager_->get_dialog_silent_send_message(dialog_id); bool silent = td_->messages_manager_->get_dialog_silent_send_message(dialog_id);
DialogId as_dialog_id = td_->messages_manager_->get_dialog_default_send_message_as_dialog_id(dialog_id); DialogId as_dialog_id = td_->messages_manager_->get_dialog_default_send_message_as_dialog_id(dialog_id);
td_->create_handler<RequestWebViewQuery>(std::move(promise)) td_->create_handler<RequestWebViewQuery>(std::move(promise))
->send(dialog_id, bot_user_id, std::move(input_user), std::move(url), std::move(theme), std::move(platform), ->send(dialog_id, bot_user_id, std::move(input_user), std::move(url), std::move(theme), std::move(platform),
top_thread_message_id, reply_to_message_id, silent, as_dialog_id); top_thread_message_id, input_reply_to, silent, as_dialog_id);
} }
void AttachMenuManager::open_web_view(int64 query_id, DialogId dialog_id, UserId bot_user_id, void AttachMenuManager::open_web_view(int64 query_id, DialogId dialog_id, UserId bot_user_id,
MessageId top_thread_message_id, MessageId reply_to_message_id, MessageId top_thread_message_id, MessageInputReplyTo input_reply_to,
DialogId as_dialog_id) { DialogId as_dialog_id) {
if (query_id == 0) { if (query_id == 0) {
LOG(ERROR) << "Receive Web App query identifier == 0"; LOG(ERROR) << "Receive Web App query identifier == 0";
@ -814,7 +812,7 @@ void AttachMenuManager::open_web_view(int64 query_id, DialogId dialog_id, UserId
opened_web_view.dialog_id_ = dialog_id; opened_web_view.dialog_id_ = dialog_id;
opened_web_view.bot_user_id_ = bot_user_id; opened_web_view.bot_user_id_ = bot_user_id;
opened_web_view.top_thread_message_id_ = top_thread_message_id; opened_web_view.top_thread_message_id_ = top_thread_message_id;
opened_web_view.reply_to_message_id_ = reply_to_message_id; opened_web_view.input_reply_to_ = std::move(input_reply_to);
opened_web_view.as_dialog_id_ = as_dialog_id; opened_web_view.as_dialog_id_ = as_dialog_id;
opened_web_views_.emplace(query_id, std::move(opened_web_view)); opened_web_views_.emplace(query_id, std::move(opened_web_view));
} }

View File

@ -10,6 +10,7 @@
#include "td/telegram/files/FileId.h" #include "td/telegram/files/FileId.h"
#include "td/telegram/files/FileSourceId.h" #include "td/telegram/files/FileSourceId.h"
#include "td/telegram/MessageId.h" #include "td/telegram/MessageId.h"
#include "td/telegram/MessageInputReplyTo.h"
#include "td/telegram/td_api.h" #include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h" #include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h" #include "td/telegram/UserId.h"
@ -42,12 +43,12 @@ class AttachMenuManager final : public Actor {
string &&platform, bool allow_write_access, Promise<string> &&promise); string &&platform, bool allow_write_access, Promise<string> &&promise);
void request_web_view(DialogId dialog_id, UserId bot_user_id, MessageId top_thread_message_id, void request_web_view(DialogId dialog_id, UserId bot_user_id, MessageId top_thread_message_id,
MessageId reply_to_message_id, string &&url, td_api::object_ptr<td_api::MessageReplyTo> &&reply_to, string &&url,
td_api::object_ptr<td_api::themeParameters> &&theme, string &&platform, td_api::object_ptr<td_api::themeParameters> &&theme, string &&platform,
Promise<td_api::object_ptr<td_api::webAppInfo>> &&promise); Promise<td_api::object_ptr<td_api::webAppInfo>> &&promise);
void open_web_view(int64 query_id, DialogId dialog_id, UserId bot_user_id, MessageId top_thread_message_id, void open_web_view(int64 query_id, DialogId dialog_id, UserId bot_user_id, MessageId top_thread_message_id,
MessageId reply_to_message_id, DialogId as_dialog_id); MessageInputReplyTo input_reply_to, DialogId as_dialog_id);
void close_web_view(int64 query_id, Promise<Unit> &&promise); void close_web_view(int64 query_id, Promise<Unit> &&promise);
@ -175,7 +176,7 @@ class AttachMenuManager final : public Actor {
DialogId dialog_id_; DialogId dialog_id_;
UserId bot_user_id_; UserId bot_user_id_;
MessageId top_thread_message_id_; MessageId top_thread_message_id_;
MessageId reply_to_message_id_; MessageInputReplyTo input_reply_to_;
DialogId as_dialog_id_; DialogId as_dialog_id_;
}; };
FlatHashMap<int64, OpenedWebView> opened_web_views_; FlatHashMap<int64, OpenedWebView> opened_web_views_;

View File

@ -194,8 +194,12 @@ Result<unique_ptr<DraftMessage>> DraftMessage::get_draft_message(
if (result->reply_to_message_id_ != MessageId() && !result->reply_to_message_id_.is_valid()) { if (result->reply_to_message_id_ != MessageId() && !result->reply_to_message_id_.is_valid()) {
return Status::Error(400, "Invalid reply_to_message_id specified"); return Status::Error(400, "Invalid reply_to_message_id specified");
} }
result->reply_to_message_id_ = td->messages_manager_->get_reply_to_message_id(dialog_id, top_thread_message_id, result->reply_to_message_id_ =
result->reply_to_message_id_, true); td->messages_manager_
->get_message_input_reply_to(
dialog_id, top_thread_message_id,
td_api::make_object<td_api::messageReplyToMessage>(0, result->reply_to_message_id_.get()), true)
.message_id_;
auto input_message_content = std::move(draft_message->input_message_text_); auto input_message_content = std::move(draft_message->input_message_text_);
if (input_message_content != nullptr) { if (input_message_content != nullptr) {

View File

@ -8,6 +8,7 @@
#include "td/telegram/MessageEntity.h" #include "td/telegram/MessageEntity.h"
#include "td/telegram/MessageId.h" #include "td/telegram/MessageId.h"
#include "td/telegram/MessageInputReplyTo.h"
#include "td/telegram/ReplyMarkup.h" #include "td/telegram/ReplyMarkup.h"
#include "td/utils/common.h" #include "td/utils/common.h"
@ -19,7 +20,7 @@ struct MessageCopyOptions {
bool send_copy = false; bool send_copy = false;
bool replace_caption = false; bool replace_caption = false;
FormattedText new_caption; FormattedText new_caption;
MessageId reply_to_message_id; MessageInputReplyTo input_reply_to;
unique_ptr<ReplyMarkup> reply_markup; unique_ptr<ReplyMarkup> reply_markup;
MessageCopyOptions() = default; MessageCopyOptions() = default;
@ -30,7 +31,7 @@ struct MessageCopyOptions {
if (!send_copy) { if (!send_copy) {
return true; return true;
} }
if ((replace_caption && !new_caption.text.empty()) || reply_to_message_id.is_valid() || reply_markup != nullptr) { if ((replace_caption && !new_caption.text.empty()) || input_reply_to.is_valid() || reply_markup != nullptr) {
return false; return false;
} }
return true; return true;
@ -43,8 +44,8 @@ inline StringBuilder &operator<<(StringBuilder &string_builder, MessageCopyOptio
if (copy_options.replace_caption) { if (copy_options.replace_caption) {
string_builder << ", new_caption = " << copy_options.new_caption; string_builder << ", new_caption = " << copy_options.new_caption;
} }
if (copy_options.reply_to_message_id.is_valid()) { if (copy_options.input_reply_to.is_valid()) {
string_builder << ", in reply to " << copy_options.reply_to_message_id; string_builder << ", in reply to " << copy_options.input_reply_to;
} }
if (copy_options.reply_markup != nullptr) { if (copy_options.reply_markup != nullptr) {
string_builder << ", with reply markup"; string_builder << ", with reply markup";

View File

@ -0,0 +1,74 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// 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/MessageInputReplyTo.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/Td.h"
namespace td {
MessageInputReplyTo::MessageInputReplyTo(const td_api::object_ptr<td_api::MessageReplyTo> &reply_to_ptr) {
if (reply_to_ptr == nullptr) {
return;
}
switch (reply_to_ptr->get_id()) {
case td_api::messageReplyToMessage::ID: {
auto reply_to = static_cast<const td_api::messageReplyToMessage *>(reply_to_ptr.get());
message_id_ = MessageId(reply_to->message_id_);
break;
}
case td_api::messageReplyToStory::ID: {
auto reply_to = static_cast<const td_api::messageReplyToStory *>(reply_to_ptr.get());
story_full_id_ = {DialogId(reply_to->sender_user_id_), StoryId(reply_to->story_id_)};
break;
}
default:
UNREACHABLE();
}
}
telegram_api::object_ptr<telegram_api::InputReplyTo> MessageInputReplyTo::get_input_reply_to(
Td *td, MessageId top_thread_message_id) const {
if (story_full_id_.is_valid()) {
auto dialog_id = story_full_id_.get_dialog_id();
CHECK(dialog_id.get_type() == DialogType::User);
auto r_input_user = td->contacts_manager_->get_input_user(dialog_id.get_user_id());
if (r_input_user.is_error()) {
LOG(ERROR) << "Failed to get input user for " << story_full_id_;
return nullptr;
}
return telegram_api::make_object<telegram_api::inputReplyToStory>(r_input_user.move_as_ok(),
story_full_id_.get_story_id().get());
}
auto reply_to_message_id = message_id_;
if (reply_to_message_id == MessageId()) {
if (top_thread_message_id == MessageId()) {
return nullptr;
}
reply_to_message_id = top_thread_message_id;
}
CHECK(reply_to_message_id.is_server());
int32 flags = 0;
if (top_thread_message_id != MessageId()) {
CHECK(top_thread_message_id.is_server());
flags |= telegram_api::inputReplyToMessage::TOP_MSG_ID_MASK;
}
return telegram_api::make_object<telegram_api::inputReplyToMessage>(
flags, reply_to_message_id.get_server_message_id().get(), top_thread_message_id.get_server_message_id().get());
}
StringBuilder &operator<<(StringBuilder &string_builder, const MessageInputReplyTo &input_reply_to) {
if (input_reply_to.message_id_.is_valid()) {
return string_builder << input_reply_to.message_id_;
}
if (input_reply_to.story_full_id_.is_valid()) {
return string_builder << input_reply_to.story_full_id_;
}
return string_builder << "nothing";
}
} // namespace td

View File

@ -0,0 +1,45 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// 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/MessageId.h"
#include "td/telegram/StoryFullId.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/StringBuilder.h"
namespace td {
class Td;
struct MessageInputReplyTo {
MessageId message_id_;
// or
StoryFullId story_full_id_;
bool is_valid() const {
return message_id_.is_valid() || story_full_id_.is_valid();
}
MessageInputReplyTo() = default;
MessageInputReplyTo(MessageId message_id, StoryFullId story_full_id)
: message_id_(message_id), story_full_id_(story_full_id) {
CHECK(!story_full_id_.is_valid() || !message_id_.is_valid());
}
explicit MessageInputReplyTo(const td_api::object_ptr<td_api::MessageReplyTo> &reply_to_ptr);
telegram_api::object_ptr<telegram_api::InputReplyTo> get_input_reply_to(Td *td,
MessageId top_thread_message_id) const;
};
StringBuilder &operator<<(StringBuilder &string_builder, const MessageInputReplyTo &input_reply_to);
} // namespace td

View File

@ -10,7 +10,6 @@
#include "td/telegram/MessageId.h" #include "td/telegram/MessageId.h"
#include "td/telegram/StoryFullId.h" #include "td/telegram/StoryFullId.h"
#include "td/telegram/telegram_api.h" #include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
#include "td/utils/common.h" #include "td/utils/common.h"

View File

@ -3132,7 +3132,7 @@ class SendMessageQuery final : public Td::ResultHandler {
public: public:
void send(int32 flags, DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> as_input_peer, void send(int32 flags, DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> as_input_peer,
MessageId reply_to_message_id, MessageId top_thread_message_id, int32 schedule_date, MessageInputReplyTo input_reply_to, MessageId top_thread_message_id, int32 schedule_date,
tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup, tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup,
vector<tl_object_ptr<telegram_api::MessageEntity>> &&entities, const string &text, bool is_copy, vector<tl_object_ptr<telegram_api::MessageEntity>> &&entities, const string &text, bool is_copy,
int64 random_id, NetQueryRef *send_query_ref) { int64 random_id, NetQueryRef *send_query_ref) {
@ -3144,6 +3144,11 @@ class SendMessageQuery final : public Td::ResultHandler {
return on_error(Status::Error(400, "Have no write access to the chat")); return on_error(Status::Error(400, "Have no write access to the chat"));
} }
auto reply_to = input_reply_to.get_input_reply_to(td_, top_thread_message_id);
if (reply_to != nullptr) {
flags |= telegram_api::messages_sendMessage::REPLY_TO_MASK;
}
if (!entities.empty()) { if (!entities.empty()) {
flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_ENTITIES; flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_ENTITIES;
} }
@ -3154,9 +3159,8 @@ class SendMessageQuery final : public Td::ResultHandler {
auto query = G()->net_query_creator().create( auto query = G()->net_query_creator().create(
telegram_api::messages_sendMessage( telegram_api::messages_sendMessage(
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, std::move(input_peer), false /*ignored*/, std::move(input_peer), std::move(reply_to), text, random_id, std::move(reply_markup),
MessagesManager::get_input_reply_to(reply_to_message_id, top_thread_message_id), text, random_id, std::move(entities), schedule_date, std::move(as_input_peer)),
std::move(reply_markup), std::move(entities), schedule_date, std::move(as_input_peer)),
{{dialog_id, MessageContentType::Text}, {{dialog_id, MessageContentType::Text},
{dialog_id, is_copy ? MessageContentType::Photo : MessageContentType::Text}}); {dialog_id, is_copy ? MessageContentType::Photo : MessageContentType::Text}});
if (td_->option_manager_->get_option_boolean("use_quick_ack")) { if (td_->option_manager_->get_option_boolean("use_quick_ack")) {
@ -3270,25 +3274,27 @@ class SendInlineBotResultQuery final : public Td::ResultHandler {
public: public:
NetQueryRef send(int32 flags, DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> as_input_peer, NetQueryRef send(int32 flags, DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> as_input_peer,
MessageId reply_to_message_id, MessageId top_thread_message_id, int32 schedule_date, int64 random_id, MessageInputReplyTo input_reply_to, MessageId top_thread_message_id, int32 schedule_date,
int64 query_id, const string &result_id) { int64 random_id, int64 query_id, const string &result_id) {
random_id_ = random_id; random_id_ = random_id;
dialog_id_ = dialog_id; dialog_id_ = dialog_id;
auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write); auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
CHECK(input_peer != nullptr); CHECK(input_peer != nullptr);
auto reply_to = input_reply_to.get_input_reply_to(td_, top_thread_message_id);
if (reply_to != nullptr) {
flags |= telegram_api::messages_sendInlineBotResult::REPLY_TO_MASK;
}
if (as_input_peer != nullptr) { if (as_input_peer != nullptr) {
flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS; flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS;
} }
CHECK(reply_to_message_id == MessageId() || reply_to_message_id.is_server());
CHECK(top_thread_message_id == MessageId() || top_thread_message_id.is_server());
auto query = G()->net_query_creator().create( auto query = G()->net_query_creator().create(
telegram_api::messages_sendInlineBotResult( telegram_api::messages_sendInlineBotResult(
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_peer), flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_peer),
MessagesManager::get_input_reply_to(reply_to_message_id, top_thread_message_id), random_id, query_id, std::move(reply_to), random_id, query_id, result_id, schedule_date, std::move(as_input_peer)),
result_id, schedule_date, std::move(as_input_peer)),
{{dialog_id, MessageContentType::Text}, {dialog_id, MessageContentType::Photo}}); {{dialog_id, MessageContentType::Text}, {dialog_id, MessageContentType::Photo}});
auto send_query_ref = query.get_weak(); auto send_query_ref = query.get_weak();
send_query(std::move(query)); send_query(std::move(query));
@ -3326,7 +3332,7 @@ class SendMultiMediaQuery final : public Td::ResultHandler {
public: public:
void send(int32 flags, DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> as_input_peer, void send(int32 flags, DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> as_input_peer,
MessageId reply_to_message_id, MessageId top_thread_message_id, int32 schedule_date, MessageInputReplyTo input_reply_to, MessageId top_thread_message_id, int32 schedule_date,
vector<FileId> &&file_ids, vector<tl_object_ptr<telegram_api::inputSingleMedia>> &&input_single_media, vector<FileId> &&file_ids, vector<tl_object_ptr<telegram_api::inputSingleMedia>> &&input_single_media,
bool is_copy) { bool is_copy) {
for (auto &single_media : input_single_media) { for (auto &single_media : input_single_media) {
@ -3343,18 +3349,21 @@ class SendMultiMediaQuery final : public Td::ResultHandler {
return on_error(Status::Error(400, "Have no write access to the chat")); return on_error(Status::Error(400, "Have no write access to the chat"));
} }
auto reply_to = input_reply_to.get_input_reply_to(td_, top_thread_message_id);
if (reply_to != nullptr) {
flags |= telegram_api::messages_sendMultiMedia::REPLY_TO_MASK;
}
if (as_input_peer != nullptr) { if (as_input_peer != nullptr) {
flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS; flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS;
} }
// no quick ack, because file reference errors are very likely to happen // no quick ack, because file reference errors are very likely to happen
CHECK(reply_to_message_id == MessageId() || reply_to_message_id.is_server());
CHECK(top_thread_message_id == MessageId() || top_thread_message_id.is_server());
send_query(G()->net_query_creator().create( send_query(G()->net_query_creator().create(
telegram_api::messages_sendMultiMedia( telegram_api::messages_sendMultiMedia(flags, false /*ignored*/, false /*ignored*/, false /*ignored*/,
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_peer),
std::move(input_peer), MessagesManager::get_input_reply_to(reply_to_message_id, top_thread_message_id), std::move(reply_to), std::move(input_single_media), schedule_date,
std::move(input_single_media), schedule_date, std::move(as_input_peer)), std::move(as_input_peer)),
{{dialog_id, is_copy ? MessageContentType::Text : MessageContentType::Photo}, {{dialog_id, is_copy ? MessageContentType::Text : MessageContentType::Photo},
{dialog_id, MessageContentType::Photo}})); {dialog_id, MessageContentType::Photo}}));
} }
@ -3441,7 +3450,7 @@ class SendMediaQuery final : public Td::ResultHandler {
public: public:
void send(FileId file_id, FileId thumbnail_file_id, int32 flags, DialogId dialog_id, void send(FileId file_id, FileId thumbnail_file_id, int32 flags, DialogId dialog_id,
tl_object_ptr<telegram_api::InputPeer> as_input_peer, MessageId reply_to_message_id, tl_object_ptr<telegram_api::InputPeer> as_input_peer, MessageInputReplyTo input_reply_to,
MessageId top_thread_message_id, int32 schedule_date, MessageId top_thread_message_id, int32 schedule_date,
tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup, tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup,
vector<tl_object_ptr<telegram_api::MessageEntity>> &&entities, const string &text, vector<tl_object_ptr<telegram_api::MessageEntity>> &&entities, const string &text,
@ -3460,6 +3469,11 @@ class SendMediaQuery final : public Td::ResultHandler {
return on_error(Status::Error(400, "Have no write access to the chat")); return on_error(Status::Error(400, "Have no write access to the chat"));
} }
auto reply_to = input_reply_to.get_input_reply_to(td_, top_thread_message_id);
if (reply_to != nullptr) {
flags |= telegram_api::messages_sendMedia::REPLY_TO_MASK;
}
if (!entities.empty()) { if (!entities.empty()) {
flags |= telegram_api::messages_sendMedia::ENTITIES_MASK; flags |= telegram_api::messages_sendMedia::ENTITIES_MASK;
} }
@ -3467,14 +3481,11 @@ class SendMediaQuery final : public Td::ResultHandler {
flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS; flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS;
} }
CHECK(reply_to_message_id == MessageId() || reply_to_message_id.is_server());
CHECK(top_thread_message_id == MessageId() || top_thread_message_id.is_server());
auto query = G()->net_query_creator().create( auto query = G()->net_query_creator().create(
telegram_api::messages_sendMedia( telegram_api::messages_sendMedia(
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
std::move(input_peer), MessagesManager::get_input_reply_to(reply_to_message_id, top_thread_message_id), std::move(input_peer), std::move(reply_to), std::move(input_media), text, random_id,
std::move(input_media), text, random_id, std::move(reply_markup), std::move(entities), schedule_date, std::move(reply_markup), std::move(entities), schedule_date, std::move(as_input_peer)),
std::move(as_input_peer)),
{{dialog_id, content_type}, {dialog_id, is_copy ? MessageContentType::Text : content_type}}); {{dialog_id, content_type}, {dialog_id, is_copy ? MessageContentType::Text : content_type}});
if (td_->option_manager_->get_option_boolean("use_quick_ack") && was_uploaded_) { if (td_->option_manager_->get_option_boolean("use_quick_ack") && was_uploaded_) {
query->quick_ack_promise_ = PromiseCreator::lambda([random_id](Result<Unit> result) { query->quick_ack_promise_ = PromiseCreator::lambda([random_id](Result<Unit> result) {
@ -12031,7 +12042,7 @@ void MessagesManager::read_all_dialog_mentions(DialogId dialog_id, MessageId top
return promise.set_error(Status::Error(400, "Chat not found")); return promise.set_error(Status::Error(400, "Chat not found"));
} }
TRY_STATUS_PROMISE(promise, can_use_top_thread_message_id(d, top_thread_message_id, MessageId())); TRY_STATUS_PROMISE(promise, can_use_top_thread_message_id(d, top_thread_message_id, MessageInputReplyTo()));
if (!have_input_peer(dialog_id, AccessRights::Read)) { if (!have_input_peer(dialog_id, AccessRights::Read)) {
return promise.set_error(Status::Error(400, "Chat is not accessible")); return promise.set_error(Status::Error(400, "Chat is not accessible"));
@ -12134,7 +12145,7 @@ void MessagesManager::read_all_dialog_reactions(DialogId dialog_id, MessageId to
return promise.set_error(Status::Error(400, "Chat not found")); return promise.set_error(Status::Error(400, "Chat not found"));
} }
TRY_STATUS_PROMISE(promise, can_use_top_thread_message_id(d, top_thread_message_id, MessageId())); TRY_STATUS_PROMISE(promise, can_use_top_thread_message_id(d, top_thread_message_id, MessageInputReplyTo()));
if (!have_input_peer(dialog_id, AccessRights::Read)) { if (!have_input_peer(dialog_id, AccessRights::Read)) {
return promise.set_error(Status::Error(400, "Chat is not accessible")); return promise.set_error(Status::Error(400, "Chat is not accessible"));
@ -19001,7 +19012,7 @@ Status MessagesManager::set_dialog_draft_message(DialogId dialog_id, MessageId t
} }
TRY_STATUS(can_send_message(dialog_id)); TRY_STATUS(can_send_message(dialog_id));
TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, MessageId())); TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, MessageInputReplyTo()));
TRY_RESULT(new_draft_message, TRY_RESULT(new_draft_message,
DraftMessage::get_draft_message(td_, dialog_id, top_thread_message_id, std::move(draft_message))); DraftMessage::get_draft_message(td_, dialog_id, top_thread_message_id, std::move(draft_message)));
@ -24298,9 +24309,10 @@ DialogId MessagesManager::get_dialog_default_send_message_as_dialog_id(DialogId
return d->default_send_message_as_dialog_id; return d->default_send_message_as_dialog_id;
} }
MessageId MessagesManager::get_reply_to_message_id(DialogId dialog_id, MessageId top_thread_message_id, MessageInputReplyTo MessagesManager::get_message_input_reply_to(DialogId dialog_id, MessageId top_thread_message_id,
MessageId message_id, bool for_draft) { td_api::object_ptr<td_api::MessageReplyTo> &&reply_to,
return get_reply_to_message_id(get_dialog(dialog_id), top_thread_message_id, message_id, for_draft); bool for_draft) {
return get_message_input_reply_to(get_dialog(dialog_id), top_thread_message_id, std::move(reply_to), for_draft);
} }
int64 MessagesManager::generate_new_random_id(const Dialog *d) { int64 MessagesManager::generate_new_random_id(const Dialog *d) {
@ -24313,7 +24325,7 @@ int64 MessagesManager::generate_new_random_id(const Dialog *d) {
} }
unique_ptr<MessagesManager::Message> MessagesManager::create_message_to_send( unique_ptr<MessagesManager::Message> MessagesManager::create_message_to_send(
Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id, const MessageSendOptions &options, Dialog *d, MessageId top_thread_message_id, MessageInputReplyTo input_reply_to, const MessageSendOptions &options,
unique_ptr<MessageContent> &&content, bool suppress_reply_info, unique_ptr<MessageForwardInfo> forward_info, unique_ptr<MessageContent> &&content, bool suppress_reply_info, unique_ptr<MessageForwardInfo> forward_info,
bool is_copy, DialogId send_as_dialog_id) const { bool is_copy, DialogId send_as_dialog_id) const {
CHECK(d != nullptr); CHECK(d != nullptr);
@ -24327,23 +24339,23 @@ unique_ptr<MessagesManager::Message> MessagesManager::create_message_to_send(
int64 reply_to_random_id = 0; int64 reply_to_random_id = 0;
bool is_topic_message = false; bool is_topic_message = false;
if (reply_to_message_id.is_valid()) { if (input_reply_to.message_id_.is_valid()) {
// the message was forcely preloaded in get_reply_to_message_id // the message was forcely preloaded in get_message_input_reply_to
// it can be missing, only if it is unknown message from a push notification, or an unknown top thread message // it can be missing, only if it is unknown message from a push notification, or an unknown top thread message
const Message *reply_m = get_message(d, reply_to_message_id); const Message *reply_m = get_message(d, input_reply_to.message_id_);
if (reply_m != nullptr) { if (reply_m != nullptr) {
if (reply_m->top_thread_message_id.is_valid()) { if (reply_m->top_thread_message_id.is_valid()) {
top_thread_message_id = reply_m->top_thread_message_id; top_thread_message_id = reply_m->top_thread_message_id;
} }
is_topic_message = reply_m->is_topic_message; is_topic_message = reply_m->is_topic_message;
} }
if (dialog_type == DialogType::SecretChat || reply_to_message_id.is_yet_unsent()) { if (dialog_type == DialogType::SecretChat || input_reply_to.message_id_.is_yet_unsent()) {
if (reply_m != nullptr) { if (reply_m != nullptr) {
reply_to_random_id = reply_m->random_id; reply_to_random_id = reply_m->random_id;
} else { } else {
CHECK(dialog_type == DialogType::SecretChat); CHECK(dialog_type == DialogType::SecretChat);
CHECK(top_thread_message_id == MessageId()); CHECK(top_thread_message_id == MessageId());
reply_to_message_id = MessageId(); input_reply_to.message_id_ = MessageId();
} }
} }
} else if (top_thread_message_id.is_valid()) { } else if (top_thread_message_id.is_valid()) {
@ -24388,8 +24400,9 @@ unique_ptr<MessagesManager::Message> MessagesManager::create_message_to_send(
} }
m->send_date = G()->unix_time(); m->send_date = G()->unix_time();
m->date = is_scheduled ? options.schedule_date : m->send_date; m->date = is_scheduled ? options.schedule_date : m->send_date;
m->reply_to_message_id = reply_to_message_id; m->reply_to_message_id = input_reply_to.message_id_;
m->reply_to_random_id = reply_to_random_id; m->reply_to_random_id = reply_to_random_id;
m->reply_to_story_full_id = input_reply_to.story_full_id_;
m->top_thread_message_id = top_thread_message_id; m->top_thread_message_id = top_thread_message_id;
m->is_topic_message = is_topic_message; m->is_topic_message = is_topic_message;
m->is_channel_post = is_channel_post; m->is_channel_post = is_channel_post;
@ -24415,7 +24428,7 @@ unique_ptr<MessagesManager::Message> MessagesManager::create_message_to_send(
if (is_channel_post) { if (is_channel_post) {
return td_->contacts_manager_->get_channel_has_linked_channel(dialog_id.get_channel_id()); return td_->contacts_manager_->get_channel_has_linked_channel(dialog_id.get_channel_id());
} }
return !reply_to_message_id.is_valid(); return !input_reply_to.is_valid();
}()) { }()) {
m->reply_info.reply_count_ = 0; m->reply_info.reply_count_ = 0;
if (is_channel_post) { if (is_channel_post) {
@ -24452,12 +24465,12 @@ unique_ptr<MessagesManager::Message> MessagesManager::create_message_to_send(
} }
MessagesManager::Message *MessagesManager::get_message_to_send( MessagesManager::Message *MessagesManager::get_message_to_send(
Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id, const MessageSendOptions &options, Dialog *d, MessageId top_thread_message_id, MessageInputReplyTo input_reply_to, const MessageSendOptions &options,
unique_ptr<MessageContent> &&content, bool *need_update_dialog_pos, bool suppress_reply_info, unique_ptr<MessageContent> &&content, bool *need_update_dialog_pos, bool suppress_reply_info,
unique_ptr<MessageForwardInfo> forward_info, bool is_copy, DialogId send_as_dialog_id) { unique_ptr<MessageForwardInfo> forward_info, bool is_copy, DialogId send_as_dialog_id) {
d->was_opened = true; d->was_opened = true;
auto message = create_message_to_send(d, top_thread_message_id, reply_to_message_id, options, std::move(content), auto message = create_message_to_send(d, top_thread_message_id, input_reply_to, options, std::move(content),
suppress_reply_info, std::move(forward_info), is_copy, send_as_dialog_id); suppress_reply_info, std::move(forward_info), is_copy, send_as_dialog_id);
MessageId message_id = options.schedule_date != 0 ? get_next_yet_unsent_scheduled_message_id(d, options.schedule_date) MessageId message_id = options.schedule_date != 0 ? get_next_yet_unsent_scheduled_message_id(d, options.schedule_date)
@ -24531,38 +24544,60 @@ MessageId MessagesManager::get_persistent_message_id(const Dialog *d, MessageId
return message_id; return message_id;
} }
MessageId MessagesManager::get_reply_to_message_id(Dialog *d, MessageId top_thread_message_id, MessageId message_id, MessageInputReplyTo MessagesManager::get_message_input_reply_to(Dialog *d, MessageId top_thread_message_id,
bool for_draft) { td_api::object_ptr<td_api::MessageReplyTo> &&reply_to,
bool for_draft) {
CHECK(d != nullptr); CHECK(d != nullptr);
if (top_thread_message_id.is_valid() && !have_message_force(d, top_thread_message_id, "get_reply_to_message_id 1")) { if (top_thread_message_id.is_valid() &&
LOG(INFO) << "Have reply to " << message_id << " in the thread of unknown " << top_thread_message_id; !have_message_force(d, top_thread_message_id, "get_message_input_reply_to 1")) {
LOG(INFO) << "Have reply in the thread of unknown " << top_thread_message_id;
}
if (reply_to != nullptr && reply_to->get_id() == td_api::messageReplyToStory::ID) {
CHECK(!for_draft);
auto reply_to_story = td_api::move_object_as<td_api::messageReplyToStory>(reply_to);
auto story_id = StoryId(reply_to_story->story_id_);
auto sender_user_id = UserId(reply_to_story->sender_user_id_);
if (d->dialog_id != DialogId(sender_user_id)) {
LOG(INFO) << "Ignore reply to story from " << sender_user_id << " in a wrong " << d->dialog_id;
return {};
}
if (!story_id.is_server()) {
LOG(INFO) << "Ignore reply to invalid " << story_id;
return {};
}
return {MessageId(), StoryFullId(DialogId(sender_user_id), story_id)};
}
MessageId message_id;
if (reply_to != nullptr && reply_to->get_id() == td_api::messageReplyToMessage::ID) {
auto reply_to_message = td_api::move_object_as<td_api::messageReplyToMessage>(reply_to);
message_id = MessageId(reply_to_message->message_id_);
} }
if (!message_id.is_valid()) { if (!message_id.is_valid()) {
if (!for_draft && message_id == MessageId() && top_thread_message_id.is_valid() && if (!for_draft && message_id == MessageId() && top_thread_message_id.is_valid() &&
top_thread_message_id.is_server()) { top_thread_message_id.is_server()) {
return top_thread_message_id; return {top_thread_message_id, StoryFullId()};
} }
return MessageId(); return {};
} }
message_id = get_persistent_message_id(d, message_id); message_id = get_persistent_message_id(d, message_id);
const Message *m = get_message_force(d, message_id, "get_reply_to_message_id 2"); const Message *m = get_message_force(d, message_id, "get_message_input_reply_to 2");
if (m == nullptr || m->message_id.is_yet_unsent() || if (m == nullptr || m->message_id.is_yet_unsent() ||
(m->message_id.is_local() && d->dialog_id.get_type() != DialogType::SecretChat)) { (m->message_id.is_local() && d->dialog_id.get_type() != DialogType::SecretChat)) {
if (message_id.is_server() && d->dialog_id.get_type() != DialogType::SecretChat && if (message_id.is_server() && d->dialog_id.get_type() != DialogType::SecretChat &&
message_id > d->last_new_message_id && message_id > d->last_new_message_id &&
(d->notification_info != nullptr && message_id <= d->notification_info->max_notification_message_id_)) { (d->notification_info != nullptr && message_id <= d->notification_info->max_notification_message_id_)) {
// allow to reply yet unreceived server message // allow to reply yet unreceived server message
return message_id; return {message_id, StoryFullId()};
} }
if (!for_draft && top_thread_message_id.is_valid() && top_thread_message_id.is_server()) { if (!for_draft && top_thread_message_id.is_valid() && top_thread_message_id.is_server()) {
return top_thread_message_id; return {top_thread_message_id, StoryFullId()};
} }
// TODO local replies to local messages can be allowed // 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 // TODO replies to yet unsent messages can be allowed with special handling of them on application restart
return MessageId(); return {};
} }
return m->message_id; return {m->message_id, StoryFullId()};
} }
void MessagesManager::fix_server_reply_to_message_id(DialogId dialog_id, MessageId message_id, void MessagesManager::fix_server_reply_to_message_id(DialogId dialog_id, MessageId message_id,
@ -24919,7 +24954,7 @@ class MessagesManager::SendMessageLogEvent {
}; };
Result<td_api::object_ptr<td_api::message>> MessagesManager::send_message( Result<td_api::object_ptr<td_api::message>> MessagesManager::send_message(
DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id, DialogId dialog_id, MessageId top_thread_message_id, td_api::object_ptr<td_api::MessageReplyTo> &&reply_to,
tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup, tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
tl_object_ptr<td_api::InputMessageContent> &&input_message_content) { tl_object_ptr<td_api::InputMessageContent> &&input_message_content) {
if (input_message_content == nullptr) { if (input_message_content == nullptr) {
@ -24931,14 +24966,12 @@ Result<td_api::object_ptr<td_api::message>> MessagesManager::send_message(
return Status::Error(400, "Chat not found"); return Status::Error(400, "Chat not found");
} }
LOG(INFO) << "Begin to send message to " << dialog_id << " in reply to " << reply_to_message_id; auto input_reply_to = get_message_input_reply_to(d, top_thread_message_id, std::move(reply_to), false);
reply_to_message_id = get_reply_to_message_id(d, top_thread_message_id, reply_to_message_id, false);
if (input_message_content->get_id() == td_api::inputMessageForwarded::ID) { if (input_message_content->get_id() == td_api::inputMessageForwarded::ID) {
auto input_message = td_api::move_object_as<td_api::inputMessageForwarded>(input_message_content); auto input_message = td_api::move_object_as<td_api::inputMessageForwarded>(input_message_content);
TRY_RESULT(copy_options, process_message_copy_options(dialog_id, std::move(input_message->copy_options_))); TRY_RESULT(copy_options, process_message_copy_options(dialog_id, std::move(input_message->copy_options_)));
copy_options.reply_to_message_id = reply_to_message_id; copy_options.input_reply_to = std::move(input_reply_to);
TRY_RESULT_ASSIGN(copy_options.reply_markup, get_dialog_reply_markup(dialog_id, std::move(reply_markup))); TRY_RESULT_ASSIGN(copy_options.reply_markup, get_dialog_reply_markup(dialog_id, std::move(reply_markup)));
return forward_message(dialog_id, top_thread_message_id, DialogId(input_message->from_chat_id_), 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_, MessageId(input_message->message_id_), std::move(options), input_message->in_game_share_,
@ -24950,12 +24983,12 @@ Result<td_api::object_ptr<td_api::message>> MessagesManager::send_message(
TRY_RESULT(message_content, process_input_message_content(dialog_id, std::move(input_message_content))); 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), true)); TRY_RESULT(message_send_options, process_message_send_options(dialog_id, std::move(options), true));
TRY_STATUS(can_use_message_send_options(message_send_options, message_content)); 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)); TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, input_reply_to));
// there must be no errors after get_message_to_send call // there must be no errors after get_message_to_send call
bool need_update_dialog_pos = false; bool need_update_dialog_pos = false;
Message *m = get_message_to_send(d, top_thread_message_id, reply_to_message_id, message_send_options, Message *m = get_message_to_send(d, top_thread_message_id, input_reply_to, message_send_options,
dup_message_content(td_, dialog_id, message_content.content.get(), dup_message_content(td_, dialog_id, message_content.content.get(),
MessageContentDupType::Send, MessageCopyOptions()), MessageContentDupType::Send, MessageCopyOptions()),
&need_update_dialog_pos, false, nullptr, message_content.via_bot_user_id.is_valid()); &need_update_dialog_pos, false, nullptr, message_content.via_bot_user_id.is_valid());
@ -25126,7 +25159,7 @@ Status MessagesManager::can_use_message_send_options(const MessageSendOptions &o
} }
Status MessagesManager::can_use_top_thread_message_id(Dialog *d, MessageId top_thread_message_id, Status MessagesManager::can_use_top_thread_message_id(Dialog *d, MessageId top_thread_message_id,
MessageId reply_to_message_id) { const MessageInputReplyTo &input_reply_to) {
if (top_thread_message_id == MessageId()) { if (top_thread_message_id == MessageId()) {
return Status::OK(); return Status::OK();
} }
@ -25137,8 +25170,11 @@ Status MessagesManager::can_use_top_thread_message_id(Dialog *d, MessageId top_t
if (d->dialog_id.get_type() != DialogType::Channel || is_broadcast_channel(d->dialog_id)) { if (d->dialog_id.get_type() != DialogType::Channel || is_broadcast_channel(d->dialog_id)) {
return Status::Error(400, "Chat doesn't have threads"); return Status::Error(400, "Chat doesn't have threads");
} }
if (reply_to_message_id.is_valid()) { if (input_reply_to.story_full_id_.is_valid()) {
const Message *reply_m = get_message_force(d, reply_to_message_id, "can_use_top_thread_message_id 1"); return Status::Error(400, "Can't send story replies to the thread");
}
if (input_reply_to.message_id_.is_valid()) {
const Message *reply_m = get_message_force(d, input_reply_to.message_id_, "can_use_top_thread_message_id 1");
if (reply_m != nullptr && top_thread_message_id != reply_m->top_thread_message_id) { if (reply_m != nullptr && top_thread_message_id != reply_m->top_thread_message_id) {
if (reply_m->top_thread_message_id.is_valid() || reply_m->media_album_id == 0) { if (reply_m->top_thread_message_id.is_valid() || reply_m->media_album_id == 0) {
return Status::Error(400, "The message to reply is not in the specified message thread"); return Status::Error(400, "The message to reply is not in the specified message thread");
@ -25165,7 +25201,7 @@ int64 MessagesManager::generate_new_media_album_id() {
} }
Result<td_api::object_ptr<td_api::messages>> MessagesManager::send_message_group( Result<td_api::object_ptr<td_api::messages>> MessagesManager::send_message_group(
DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id, DialogId dialog_id, MessageId top_thread_message_id, td_api::object_ptr<td_api::MessageReplyTo> &&reply_to,
tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::messageSendOptions> &&options,
vector<tl_object_ptr<td_api::InputMessageContent>> &&input_message_contents, bool only_preview) { vector<tl_object_ptr<td_api::InputMessageContent>> &&input_message_contents, bool only_preview) {
if (input_message_contents.size() > MAX_GROUPED_MESSAGES) { if (input_message_contents.size() > MAX_GROUPED_MESSAGES) {
@ -25204,8 +25240,8 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::send_message_group
} }
} }
reply_to_message_id = get_reply_to_message_id(d, top_thread_message_id, reply_to_message_id, false); auto input_reply_to = get_message_input_reply_to(d, top_thread_message_id, std::move(reply_to), false);
TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, reply_to_message_id)); TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, input_reply_to));
int64 media_album_id = 0; int64 media_album_id = 0;
if (message_contents.size() > 1) { if (message_contents.size() > 1) {
@ -25221,7 +25257,7 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::send_message_group
unique_ptr<Message> message; unique_ptr<Message> message;
Message *m; Message *m;
if (only_preview) { if (only_preview) {
message = create_message_to_send(d, top_thread_message_id, reply_to_message_id, message_send_options, message = create_message_to_send(d, top_thread_message_id, input_reply_to, message_send_options,
std::move(message_content.first), i != 0, nullptr, false, DialogId()); std::move(message_content.first), i != 0, nullptr, false, DialogId());
MessageId new_message_id = message_send_options.schedule_date != 0 MessageId new_message_id = message_send_options.schedule_date != 0
? get_next_yet_unsent_scheduled_message_id(d, message_send_options.schedule_date) ? get_next_yet_unsent_scheduled_message_id(d, message_send_options.schedule_date)
@ -25229,7 +25265,7 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::send_message_group
message->message_id = new_message_id; message->message_id = new_message_id;
m = message.get(); m = message.get();
} else { } else {
m = get_message_to_send(d, top_thread_message_id, reply_to_message_id, message_send_options, m = get_message_to_send(d, top_thread_message_id, input_reply_to, message_send_options,
dup_message_content(td_, dialog_id, message_content.first.get(), dup_message_content(td_, dialog_id, message_content.first.get(),
MessageContentDupType::Send, MessageCopyOptions()), MessageContentDupType::Send, MessageCopyOptions()),
&need_update_dialog_pos, i != 0); &need_update_dialog_pos, i != 0);
@ -25398,8 +25434,8 @@ void MessagesManager::on_message_media_uploaded(DialogId dialog_id, const Messag
int64 random_id = begin_send_message(dialog_id, m); int64 random_id = begin_send_message(dialog_id, m);
td_->create_handler<SendMediaQuery>()->send( td_->create_handler<SendMediaQuery>()->send(
file_id, thumbnail_file_id, get_message_flags(m), dialog_id, get_send_message_as_input_peer(m), file_id, thumbnail_file_id, get_message_flags(m), dialog_id, get_send_message_as_input_peer(m),
m->reply_to_message_id, m->top_thread_message_id, get_message_schedule_date(m), {m->reply_to_message_id, m->reply_to_story_full_id}, m->top_thread_message_id,
get_input_reply_markup(td_->contacts_manager_.get(), m->reply_markup), get_message_schedule_date(m), get_input_reply_markup(td_->contacts_manager_.get(), m->reply_markup),
get_input_message_entities(td_->contacts_manager_.get(), caption, "on_message_media_uploaded"), get_input_message_entities(td_->contacts_manager_.get(), caption, "on_message_media_uploaded"),
caption == nullptr ? "" : caption->text, std::move(input_media), m->content->get_type(), m->is_copy, caption == nullptr ? "" : caption->text, std::move(input_media), m->content->get_type(), m->is_copy,
random_id, &m->send_query_ref); random_id, &m->send_query_ref);
@ -25699,7 +25735,7 @@ void MessagesManager::do_send_message_group(int64 media_album_id) {
vector<int64> random_ids; vector<int64> random_ids;
vector<tl_object_ptr<telegram_api::inputSingleMedia>> input_single_media; vector<tl_object_ptr<telegram_api::inputSingleMedia>> input_single_media;
tl_object_ptr<telegram_api::InputPeer> as_input_peer; tl_object_ptr<telegram_api::InputPeer> as_input_peer;
MessageId reply_to_message_id; MessageInputReplyTo input_reply_to;
MessageId top_thread_message_id; MessageId top_thread_message_id;
int32 flags = 0; int32 flags = 0;
int32 schedule_date = 0; int32 schedule_date = 0;
@ -25712,7 +25748,7 @@ void MessagesManager::do_send_message_group(int64 media_album_id) {
continue; continue;
} }
reply_to_message_id = m->reply_to_message_id; input_reply_to = {m->reply_to_message_id, m->reply_to_story_full_id};
top_thread_message_id = m->top_thread_message_id; top_thread_message_id = m->top_thread_message_id;
flags = get_message_flags(m); flags = get_message_flags(m);
schedule_date = get_message_schedule_date(m); schedule_date = get_message_schedule_date(m);
@ -25779,7 +25815,7 @@ void MessagesManager::do_send_message_group(int64 media_album_id) {
if (input_single_media.empty()) { if (input_single_media.empty()) {
LOG(INFO) << "Media group " << media_album_id << " from " << dialog_id << " is empty"; LOG(INFO) << "Media group " << media_album_id << " from " << dialog_id << " is empty";
} }
td_->create_handler<SendMultiMediaQuery>()->send(flags, dialog_id, std::move(as_input_peer), reply_to_message_id, td_->create_handler<SendMultiMediaQuery>()->send(flags, dialog_id, std::move(as_input_peer), input_reply_to,
top_thread_message_id, schedule_date, std::move(file_ids), top_thread_message_id, schedule_date, std::move(file_ids),
std::move(input_single_media), is_copy); std::move(input_single_media), is_copy);
} }
@ -25811,8 +25847,8 @@ void MessagesManager::on_text_message_ready_to_send(DialogId dialog_id, MessageI
int64 random_id = begin_send_message(dialog_id, m); int64 random_id = begin_send_message(dialog_id, m);
td_->create_handler<SendMessageQuery>()->send( td_->create_handler<SendMessageQuery>()->send(
get_message_flags(m), dialog_id, get_send_message_as_input_peer(m), m->reply_to_message_id, get_message_flags(m), dialog_id, get_send_message_as_input_peer(m),
m->top_thread_message_id, get_message_schedule_date(m), {m->reply_to_message_id, m->reply_to_story_full_id}, m->top_thread_message_id, get_message_schedule_date(m),
get_input_reply_markup(td_->contacts_manager_.get(), m->reply_markup), get_input_reply_markup(td_->contacts_manager_.get(), m->reply_markup),
get_input_message_entities(td_->contacts_manager_.get(), message_text->entities, "do_send_message"), get_input_message_entities(td_->contacts_manager_.get(), message_text->entities, "do_send_message"),
message_text->text, m->is_copy, random_id, &m->send_query_ref); message_text->text, m->is_copy, random_id, &m->send_query_ref);
@ -25892,7 +25928,6 @@ void MessagesManager::on_yet_unsent_media_queue_updated(DialogId dialog_id) {
Result<MessageId> MessagesManager::send_bot_start_message(UserId bot_user_id, DialogId dialog_id, Result<MessageId> MessagesManager::send_bot_start_message(UserId bot_user_id, DialogId dialog_id,
const string &parameter) { const string &parameter) {
LOG(INFO) << "Begin to send bot start message to " << dialog_id;
CHECK(!td_->auth_manager_->is_bot()); CHECK(!td_->auth_manager_->is_bot());
TRY_RESULT(bot_data, td_->contacts_manager_->get_bot_data(bot_user_id)); TRY_RESULT(bot_data, td_->contacts_manager_->get_bot_data(bot_user_id));
@ -25963,7 +25998,7 @@ Result<MessageId> MessagesManager::send_bot_start_message(UserId bot_user_id, Di
vector<MessageEntity> text_entities; vector<MessageEntity> text_entities;
text_entities.emplace_back(MessageEntity::Type::BotCommand, 0, narrow_cast<int32>(text.size())); text_entities.emplace_back(MessageEntity::Type::BotCommand, 0, narrow_cast<int32>(text.size()));
bool need_update_dialog_pos = false; bool need_update_dialog_pos = false;
Message *m = get_message_to_send(d, MessageId(), MessageId(), MessageSendOptions(), Message *m = get_message_to_send(d, MessageId(), MessageInputReplyTo(), MessageSendOptions(),
create_text_message_content(text, std::move(text_entities), WebPageId()), create_text_message_content(text, std::move(text_entities), WebPageId()),
&need_update_dialog_pos); &need_update_dialog_pos);
m->is_bot_start_message = true; m->is_bot_start_message = true;
@ -26056,13 +26091,9 @@ void MessagesManager::do_send_bot_start_message(UserId bot_user_id, DialogId dia
std::move(input_peer), parameter, random_id); std::move(input_peer), parameter, random_id);
} }
Result<MessageId> MessagesManager::send_inline_query_result_message(DialogId dialog_id, MessageId top_thread_message_id, Result<MessageId> MessagesManager::send_inline_query_result_message(
MessageId reply_to_message_id, DialogId dialog_id, MessageId top_thread_message_id, td_api::object_ptr<td_api::MessageReplyTo> &&reply_to,
tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::messageSendOptions> &&options, int64 query_id, const string &result_id, bool hide_via_bot) {
int64 query_id, const string &result_id,
bool hide_via_bot) {
LOG(INFO) << "Begin to send inline query result message to " << dialog_id << " in reply to " << reply_to_message_id;
Dialog *d = get_dialog_force(dialog_id, "send_inline_query_result_message"); Dialog *d = get_dialog_force(dialog_id, "send_inline_query_result_message");
if (d == nullptr) { if (d == nullptr) {
return Status::Error(400, "Chat not found"); return Status::Error(400, "Chat not found");
@ -26097,13 +26128,13 @@ Result<MessageId> MessagesManager::send_inline_query_result_message(DialogId dia
return Status::Error(400, "Inline query result not found"); return Status::Error(400, "Inline query result not found");
} }
reply_to_message_id = get_reply_to_message_id(d, top_thread_message_id, reply_to_message_id, false); auto input_reply_to = get_message_input_reply_to(d, top_thread_message_id, std::move(reply_to), false);
TRY_STATUS(can_use_message_send_options(message_send_options, content->message_content, 0)); 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, td_)); TRY_STATUS(can_send_message_content(dialog_id, content->message_content.get(), false, td_));
TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, reply_to_message_id)); TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, input_reply_to));
bool need_update_dialog_pos = false; bool need_update_dialog_pos = false;
Message *m = get_message_to_send(d, top_thread_message_id, reply_to_message_id, message_send_options, Message *m = get_message_to_send(d, top_thread_message_id, input_reply_to, message_send_options,
dup_message_content(td_, dialog_id, content->message_content.get(), dup_message_content(td_, dialog_id, content->message_content.get(),
MessageContentDupType::SendViaBot, MessageCopyOptions()), MessageContentDupType::SendViaBot, MessageCopyOptions()),
&need_update_dialog_pos, false, nullptr, true); &need_update_dialog_pos, false, nullptr, true);
@ -26204,8 +26235,8 @@ void MessagesManager::do_send_inline_query_result_message(DialogId dialog_id, Me
flags |= telegram_api::messages_sendInlineBotResult::HIDE_VIA_MASK; flags |= telegram_api::messages_sendInlineBotResult::HIDE_VIA_MASK;
} }
m->send_query_ref = td_->create_handler<SendInlineBotResultQuery>()->send( m->send_query_ref = td_->create_handler<SendInlineBotResultQuery>()->send(
flags, dialog_id, get_send_message_as_input_peer(m), m->reply_to_message_id, m->top_thread_message_id, flags, dialog_id, get_send_message_as_input_peer(m), {m->reply_to_message_id, m->reply_to_story_full_id},
get_message_schedule_date(m), random_id, query_id, result_id); m->top_thread_message_id, get_message_schedule_date(m), random_id, query_id, result_id);
} }
bool MessagesManager::has_qts_messages(DialogId dialog_id) const { bool MessagesManager::has_qts_messages(DialogId dialog_id) const {
@ -26521,7 +26552,6 @@ void MessagesManager::edit_message_text(FullMessageId full_message_id,
return promise.set_error(Status::Error(400, "Input message content type must be InputMessageText")); return promise.set_error(Status::Error(400, "Input message content type must be InputMessageText"));
} }
LOG(INFO) << "Begin to edit text of " << full_message_id;
auto dialog_id = full_message_id.get_dialog_id(); auto dialog_id = full_message_id.get_dialog_id();
Dialog *d = get_dialog_force(dialog_id, "edit_message_text"); Dialog *d = get_dialog_force(dialog_id, "edit_message_text");
if (d == nullptr) { if (d == nullptr) {
@ -26575,7 +26605,6 @@ void MessagesManager::edit_message_live_location(FullMessageId full_message_id,
tl_object_ptr<td_api::ReplyMarkup> &&reply_markup, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
tl_object_ptr<td_api::location> &&input_location, int32 heading, tl_object_ptr<td_api::location> &&input_location, int32 heading,
int32 proximity_alert_radius, Promise<Unit> &&promise) { int32 proximity_alert_radius, Promise<Unit> &&promise) {
LOG(INFO) << "Begin to edit live location of " << full_message_id;
auto dialog_id = full_message_id.get_dialog_id(); auto dialog_id = full_message_id.get_dialog_id();
Dialog *d = get_dialog_force(dialog_id, "edit_message_live_location"); Dialog *d = get_dialog_force(dialog_id, "edit_message_live_location");
if (d == nullptr) { if (d == nullptr) {
@ -26748,7 +26777,6 @@ void MessagesManager::edit_message_media(FullMessageId full_message_id,
return promise.set_error(Status::Error(400, "Unsupported input message content type")); return promise.set_error(Status::Error(400, "Unsupported input message content type"));
} }
LOG(INFO) << "Begin to edit media of " << full_message_id;
auto dialog_id = full_message_id.get_dialog_id(); auto dialog_id = full_message_id.get_dialog_id();
Dialog *d = get_dialog_force(dialog_id, "edit_message_media"); Dialog *d = get_dialog_force(dialog_id, "edit_message_media");
if (d == nullptr) { if (d == nullptr) {
@ -26824,8 +26852,6 @@ void MessagesManager::edit_message_caption(FullMessageId full_message_id,
tl_object_ptr<td_api::ReplyMarkup> &&reply_markup, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
tl_object_ptr<td_api::formattedText> &&input_caption, tl_object_ptr<td_api::formattedText> &&input_caption,
Promise<Unit> &&promise) { Promise<Unit> &&promise) {
LOG(INFO) << "Begin to edit caption of " << full_message_id;
auto dialog_id = full_message_id.get_dialog_id(); auto dialog_id = full_message_id.get_dialog_id();
Dialog *d = get_dialog_force(dialog_id, "edit_message_caption"); Dialog *d = get_dialog_force(dialog_id, "edit_message_caption");
if (d == nullptr) { if (d == nullptr) {
@ -26874,7 +26900,6 @@ void MessagesManager::edit_message_reply_markup(FullMessageId full_message_id,
Promise<Unit> &&promise) { Promise<Unit> &&promise) {
CHECK(td_->auth_manager_->is_bot()); CHECK(td_->auth_manager_->is_bot());
LOG(INFO) << "Begin to edit reply markup of " << full_message_id;
auto dialog_id = full_message_id.get_dialog_id(); auto dialog_id = full_message_id.get_dialog_id();
Dialog *d = get_dialog_force(dialog_id, "edit_message_reply_markup"); Dialog *d = get_dialog_force(dialog_id, "edit_message_reply_markup");
if (d == nullptr) { if (d == nullptr) {
@ -27091,8 +27116,6 @@ void MessagesManager::edit_message_scheduling_state(
} }
auto schedule_date = r_schedule_date.move_as_ok(); auto schedule_date = r_schedule_date.move_as_ok();
LOG(INFO) << "Begin to reschedule " << full_message_id << " to " << schedule_date;
auto dialog_id = full_message_id.get_dialog_id(); auto dialog_id = full_message_id.get_dialog_id();
Dialog *d = get_dialog_force(dialog_id, "edit_message_scheduling_state"); Dialog *d = get_dialog_force(dialog_id, "edit_message_scheduling_state");
if (d == nullptr) { if (d == nullptr) {
@ -27331,9 +27354,6 @@ bool MessagesManager::get_message_disable_web_page_preview(const Message *m) {
int32 MessagesManager::get_message_flags(const Message *m) { int32 MessagesManager::get_message_flags(const Message *m) {
int32 flags = 0; int32 flags = 0;
if (m->reply_to_message_id.is_valid() || m->top_thread_message_id.is_valid()) {
flags |= SEND_MESSAGE_FLAG_IS_REPLY;
}
if (m->disable_web_page_preview) { if (m->disable_web_page_preview) {
flags |= SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW; flags |= SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW;
} }
@ -27886,7 +27906,7 @@ Result<MessagesManager::ForwardedMessages> MessagesManager::get_forwarded_messag
TRY_STATUS(can_send_message(to_dialog_id)); 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_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())); TRY_STATUS(can_use_top_thread_message_id(to_dialog, top_thread_message_id, MessageInputReplyTo()));
{ {
MessageId last_message_id; MessageId last_message_id;
@ -27965,7 +27985,7 @@ Result<MessagesManager::ForwardedMessages> MessagesManager::get_forwarded_messag
auto type = need_copy ? (is_local_copy ? MessageContentDupType::Copy : MessageContentDupType::ServerCopy) auto type = need_copy ? (is_local_copy ? MessageContentDupType::Copy : MessageContentDupType::ServerCopy)
: MessageContentDupType::Forward; : MessageContentDupType::Forward;
auto reply_to_message_id = copy_options[i].reply_to_message_id; auto input_reply_to = std::move(copy_options[i].input_reply_to);
auto reply_markup = std::move(copy_options[i].reply_markup); auto reply_markup = std::move(copy_options[i].reply_markup);
unique_ptr<MessageContent> content = unique_ptr<MessageContent> content =
dup_message_content(td_, to_dialog_id, forwarded_message->content.get(), type, std::move(copy_options[i])); dup_message_content(td_, to_dialog_id, forwarded_message->content.get(), type, std::move(copy_options[i]));
@ -27974,8 +27994,6 @@ Result<MessagesManager::ForwardedMessages> MessagesManager::get_forwarded_messag
continue; continue;
} }
reply_to_message_id = get_reply_to_message_id(to_dialog, top_thread_message_id, reply_to_message_id, false);
auto can_send_status = can_send_message_content(to_dialog_id, content.get(), !is_local_copy, td_); auto can_send_status = can_send_message_content(to_dialog_id, content.get(), !is_local_copy, td_);
if (can_send_status.is_error()) { if (can_send_status.is_error()) {
LOG(INFO) << "Can't forward " << message_id << ": " << can_send_status.message(); LOG(INFO) << "Can't forward " << message_id << ": " << can_send_status.message();
@ -27988,7 +28006,7 @@ Result<MessagesManager::ForwardedMessages> MessagesManager::get_forwarded_messag
continue; continue;
} }
if (can_use_top_thread_message_id(to_dialog, top_thread_message_id, reply_to_message_id).is_error()) { if (can_use_top_thread_message_id(to_dialog, top_thread_message_id, input_reply_to).is_error()) {
LOG(INFO) << "Ignore invalid message thread ID " << top_thread_message_id; LOG(INFO) << "Ignore invalid message thread ID " << top_thread_message_id;
top_thread_message_id = MessageId(); top_thread_message_id = MessageId();
} }
@ -28010,7 +28028,7 @@ Result<MessagesManager::ForwardedMessages> MessagesManager::get_forwarded_messag
if (is_local_copy) { if (is_local_copy) {
auto original_reply_to_message_id = auto original_reply_to_message_id =
forwarded_message->reply_in_dialog_id == DialogId() ? forwarded_message->reply_to_message_id : MessageId(); forwarded_message->reply_in_dialog_id == DialogId() ? forwarded_message->reply_to_message_id : MessageId();
copied_messages.push_back({std::move(content), reply_to_message_id, forwarded_message->message_id, copied_messages.push_back({std::move(content), input_reply_to, forwarded_message->message_id,
original_reply_to_message_id, std::move(reply_markup), original_reply_to_message_id, std::move(reply_markup),
forwarded_message->media_album_id, forwarded_message->media_album_id,
get_message_disable_web_page_preview(forwarded_message), i}); get_message_disable_web_page_preview(forwarded_message), i});
@ -28108,9 +28126,9 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::forward_messages(
unique_ptr<Message> message; unique_ptr<Message> message;
Message *m; Message *m;
if (only_preview) { if (only_preview) {
message = create_message_to_send(to_dialog, top_thread_message_id, reply_to_message_id, message_send_options, message = create_message_to_send(
std::move(content), j + 1 != forwarded_message_contents.size(), to_dialog, top_thread_message_id, {reply_to_message_id, StoryFullId()}, message_send_options,
std::move(forward_info), false, DialogId()); std::move(content), j + 1 != forwarded_message_contents.size(), std::move(forward_info), false, DialogId());
MessageId new_message_id = MessageId new_message_id =
message_send_options.schedule_date != 0 message_send_options.schedule_date != 0
? get_next_yet_unsent_scheduled_message_id(to_dialog, message_send_options.schedule_date) ? get_next_yet_unsent_scheduled_message_id(to_dialog, message_send_options.schedule_date)
@ -28118,9 +28136,9 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::forward_messages(
message->message_id = new_message_id; message->message_id = new_message_id;
m = message.get(); m = message.get();
} else { } else {
m = get_message_to_send(to_dialog, top_thread_message_id, reply_to_message_id, message_send_options, m = get_message_to_send(to_dialog, top_thread_message_id, {reply_to_message_id, StoryFullId()},
std::move(content), &need_update_dialog_pos, j + 1 != forwarded_message_contents.size(), message_send_options, std::move(content), &need_update_dialog_pos,
std::move(forward_info)); 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, fix_forwarded_message(m, to_dialog_id, forwarded_message, forwarded_message_contents[j].media_album_id,
drop_author); drop_author);
@ -28159,18 +28177,18 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::forward_messages(
forwarded_message_id_to_new_message_id.emplace(copied_message.original_message_id, MessageId()); forwarded_message_id_to_new_message_id.emplace(copied_message.original_message_id, MessageId());
} }
for (auto &copied_message : copied_messages) { for (auto &copied_message : copied_messages) {
MessageId reply_to_message_id = copied_message.reply_to_message_id; auto input_reply_to = copied_message.input_reply_to;
if (!reply_to_message_id.is_valid() && copied_message.original_reply_to_message_id.is_valid() && is_secret) { if (!input_reply_to.is_valid() && copied_message.original_reply_to_message_id.is_valid() && is_secret) {
auto it = forwarded_message_id_to_new_message_id.find(copied_message.original_reply_to_message_id); auto it = forwarded_message_id_to_new_message_id.find(copied_message.original_reply_to_message_id);
if (it != forwarded_message_id_to_new_message_id.end()) { if (it != forwarded_message_id_to_new_message_id.end()) {
reply_to_message_id = it->second; input_reply_to.message_id_ = it->second;
} }
} }
unique_ptr<Message> message; unique_ptr<Message> message;
Message *m; Message *m;
if (only_preview) { if (only_preview) {
message = create_message_to_send(to_dialog, top_thread_message_id, reply_to_message_id, message_send_options, message = create_message_to_send(to_dialog, top_thread_message_id, input_reply_to, message_send_options,
std::move(copied_message.content), false, nullptr, is_copy, DialogId()); std::move(copied_message.content), false, nullptr, is_copy, DialogId());
MessageId new_message_id = MessageId new_message_id =
message_send_options.schedule_date != 0 message_send_options.schedule_date != 0
@ -28185,7 +28203,7 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::forward_messages(
extract_authentication_codes(from_dialog_id, forwarded_message, authentication_codes); extract_authentication_codes(from_dialog_id, forwarded_message, authentication_codes);
} }
m = get_message_to_send(to_dialog, top_thread_message_id, reply_to_message_id, message_send_options, m = get_message_to_send(to_dialog, top_thread_message_id, input_reply_to, message_send_options,
std::move(copied_message.content), &need_update_dialog_pos, false, nullptr, is_copy); 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->disable_web_page_preview = copied_message.disable_web_page_preview;
@ -28309,8 +28327,7 @@ Result<vector<MessageId>> MessagesManager::resend_messages(DialogId dialog_id, v
message->update_stickersets_order, message->noforwards, message->update_stickersets_order, message->noforwards,
get_message_schedule_date(message.get()), message->sending_id); get_message_schedule_date(message.get()), message->sending_id);
Message *m = get_message_to_send( Message *m = get_message_to_send(
d, message->top_thread_message_id, d, message->top_thread_message_id, {message->reply_to_message_id, message->reply_to_story_full_id}, options,
get_reply_to_message_id(d, message->top_thread_message_id, message->reply_to_message_id, false), options,
std::move(new_contents[i]), &need_update_dialog_pos, false, nullptr, message->is_copy, std::move(new_contents[i]), &need_update_dialog_pos, false, nullptr, message->is_copy,
need_another_sender ? DialogId() : get_message_sender(message.get())); need_another_sender ? DialogId() : get_message_sender(message.get()));
m->reply_markup = std::move(message->reply_markup); m->reply_markup = std::move(message->reply_markup);
@ -28344,7 +28361,7 @@ void MessagesManager::send_screenshot_taken_notification_message(Dialog *d) {
auto dialog_type = d->dialog_id.get_type(); auto dialog_type = d->dialog_id.get_type();
if (dialog_type == DialogType::User) { if (dialog_type == DialogType::User) {
bool need_update_dialog_pos = false; bool need_update_dialog_pos = false;
const Message *m = get_message_to_send(d, MessageId(), MessageId(), MessageSendOptions(), const Message *m = get_message_to_send(d, MessageId(), MessageInputReplyTo(), MessageSendOptions(),
create_screenshot_taken_message_content(), &need_update_dialog_pos); create_screenshot_taken_message_content(), &need_update_dialog_pos);
do_send_screenshot_taken_notification_message(d->dialog_id, m, 0); do_send_screenshot_taken_notification_message(d->dialog_id, m, 0);
@ -28441,13 +28458,13 @@ void MessagesManager::share_dialog_with_bot(FullMessageId full_message_id, int32
} }
Result<MessageId> MessagesManager::add_local_message( Result<MessageId> MessagesManager::add_local_message(
DialogId dialog_id, td_api::object_ptr<td_api::MessageSender> &&sender, MessageId reply_to_message_id, DialogId dialog_id, td_api::object_ptr<td_api::MessageSender> &&sender,
bool disable_notification, tl_object_ptr<td_api::InputMessageContent> &&input_message_content) { td_api::object_ptr<td_api::MessageReplyTo> &&reply_to, bool disable_notification,
tl_object_ptr<td_api::InputMessageContent> &&input_message_content) {
if (input_message_content == nullptr) { if (input_message_content == nullptr) {
return Status::Error(400, "Can't add local message without content"); return Status::Error(400, "Can't add local message without content");
} }
LOG(INFO) << "Begin to add local message to " << dialog_id << " in reply to " << reply_to_message_id;
Dialog *d = get_dialog_force(dialog_id, "add_local_message"); Dialog *d = get_dialog_force(dialog_id, "add_local_message");
if (d == nullptr) { if (d == nullptr) {
return Status::Error(400, "Chat not found"); return Status::Error(400, "Chat not found");
@ -28505,6 +28522,8 @@ Result<MessageId> MessagesManager::add_local_message(
} }
} }
auto input_reply_to = get_message_input_reply_to(d, MessageId(), std::move(reply_to), false);
MessageId message_id = get_next_local_message_id(d); MessageId message_id = get_next_local_message_id(d);
auto message = make_unique<Message>(); auto message = make_unique<Message>();
@ -28521,7 +28540,8 @@ Result<MessageId> MessagesManager::add_local_message(
m->sender_dialog_id = sender_dialog_id; m->sender_dialog_id = sender_dialog_id;
} }
m->date = G()->unix_time(); m->date = G()->unix_time();
m->reply_to_message_id = get_reply_to_message_id(d, MessageId(), reply_to_message_id, false); m->reply_to_message_id = input_reply_to.message_id_;
m->reply_to_story_full_id = input_reply_to.story_full_id_;
if (m->reply_to_message_id.is_valid() && !message_id.is_scheduled()) { if (m->reply_to_message_id.is_valid() && !message_id.is_scheduled()) {
const Message *reply_m = get_message(d, m->reply_to_message_id); const Message *reply_m = get_message(d, m->reply_to_message_id);
if (reply_m != nullptr) { if (reply_m != nullptr) {
@ -33696,8 +33716,6 @@ void MessagesManager::set_dialog_message_ttl(DialogId dialog_id, int32 ttl, Prom
return promise.set_error(Status::Error(400, "Have no write access to the chat")); return promise.set_error(Status::Error(400, "Have no write access to the chat"));
} }
LOG(INFO) << "Begin to set message auto-delete time in " << dialog_id << " to " << ttl;
switch (dialog_id.get_type()) { switch (dialog_id.get_type()) {
case DialogType::User: case DialogType::User:
if (dialog_id == get_my_dialog_id() || if (dialog_id == get_my_dialog_id() ||
@ -33734,7 +33752,7 @@ void MessagesManager::set_dialog_message_ttl(DialogId dialog_id, int32 ttl, Prom
td_->create_handler<SetHistoryTtlQuery>(std::move(promise))->send(dialog_id, ttl); td_->create_handler<SetHistoryTtlQuery>(std::move(promise))->send(dialog_id, ttl);
} else { } else {
bool need_update_dialog_pos = false; bool need_update_dialog_pos = false;
Message *m = get_message_to_send(d, MessageId(), MessageId(), MessageSendOptions(), Message *m = get_message_to_send(d, MessageId(), MessageInputReplyTo(), MessageSendOptions(),
create_chat_set_ttl_message_content(ttl, UserId()), &need_update_dialog_pos); create_chat_set_ttl_message_content(ttl, UserId()), &need_update_dialog_pos);
send_update_new_message(d, m); send_update_new_message(d, m);
@ -33975,7 +33993,7 @@ void MessagesManager::unpin_all_dialog_messages(DialogId dialog_id, MessageId to
return promise.set_error(Status::Error(400, "Chat not found")); return promise.set_error(Status::Error(400, "Chat not found"));
} }
TRY_STATUS_PROMISE(promise, can_pin_messages(dialog_id)); TRY_STATUS_PROMISE(promise, can_pin_messages(dialog_id));
TRY_STATUS_PROMISE(promise, can_use_top_thread_message_id(d, top_thread_message_id, MessageId())); TRY_STATUS_PROMISE(promise, can_use_top_thread_message_id(d, top_thread_message_id, MessageInputReplyTo()));
if (!td_->auth_manager_->is_bot()) { if (!td_->auth_manager_->is_bot()) {
auto message_ids = find_dialog_messages(d, [top_thread_message_id](const Message *m) { auto message_ids = find_dialog_messages(d, [top_thread_message_id](const Message *m) {

View File

@ -34,6 +34,7 @@
#include "td/telegram/MessageCopyOptions.h" #include "td/telegram/MessageCopyOptions.h"
#include "td/telegram/MessageDb.h" #include "td/telegram/MessageDb.h"
#include "td/telegram/MessageId.h" #include "td/telegram/MessageId.h"
#include "td/telegram/MessageInputReplyTo.h"
#include "td/telegram/MessageLinkInfo.h" #include "td/telegram/MessageLinkInfo.h"
#include "td/telegram/MessageReplyHeader.h" #include "td/telegram/MessageReplyHeader.h"
#include "td/telegram/MessageReplyInfo.h" #include "td/telegram/MessageReplyInfo.h"
@ -140,7 +141,6 @@ class MessagesManager final : public Actor {
static constexpr int32 MESSAGE_FLAG_HAS_TTL_PERIOD = 1 << 25; static constexpr int32 MESSAGE_FLAG_HAS_TTL_PERIOD = 1 << 25;
static constexpr int32 MESSAGE_FLAG_NOFORWARDS = 1 << 26; static constexpr int32 MESSAGE_FLAG_NOFORWARDS = 1 << 26;
static constexpr int32 SEND_MESSAGE_FLAG_IS_REPLY = 1 << 0;
static constexpr int32 SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW = 1 << 1; static constexpr int32 SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW = 1 << 1;
static constexpr int32 SEND_MESSAGE_FLAG_HAS_REPLY_MARKUP = 1 << 2; static constexpr int32 SEND_MESSAGE_FLAG_HAS_REPLY_MARKUP = 1 << 2;
static constexpr int32 SEND_MESSAGE_FLAG_HAS_ENTITIES = 1 << 3; static constexpr int32 SEND_MESSAGE_FLAG_HAS_ENTITIES = 1 << 3;
@ -165,24 +165,6 @@ class MessagesManager final : public Actor {
MessagesManager &operator=(MessagesManager &&) = delete; MessagesManager &operator=(MessagesManager &&) = delete;
~MessagesManager() final; ~MessagesManager() final;
static telegram_api::object_ptr<telegram_api::InputReplyTo> get_input_reply_to(MessageId reply_to_message_id,
MessageId top_thread_message_id) {
if (reply_to_message_id == MessageId()) {
if (top_thread_message_id == MessageId()) {
return nullptr;
}
reply_to_message_id = top_thread_message_id;
}
CHECK(reply_to_message_id.is_server());
int32 flags = 0;
if (top_thread_message_id != MessageId()) {
CHECK(top_thread_message_id.is_server());
flags |= telegram_api::inputReplyToMessage::TOP_MSG_ID_MASK;
}
return telegram_api::make_object<telegram_api::inputReplyToMessage>(
flags, reply_to_message_id.get_server_message_id().get(), top_thread_message_id.get_server_message_id().get());
}
tl_object_ptr<telegram_api::InputPeer> get_input_peer(DialogId dialog_id, AccessRights access_rights) const; tl_object_ptr<telegram_api::InputPeer> get_input_peer(DialogId dialog_id, AccessRights access_rights) const;
static tl_object_ptr<telegram_api::InputPeer> get_input_peer_force(DialogId dialog_id); static tl_object_ptr<telegram_api::InputPeer> get_input_peer_force(DialogId dialog_id);
@ -463,16 +445,16 @@ class MessagesManager final : public Actor {
DialogId get_dialog_default_send_message_as_dialog_id(DialogId dialog_id) const; DialogId get_dialog_default_send_message_as_dialog_id(DialogId dialog_id) const;
MessageId get_reply_to_message_id(DialogId dialog_id, MessageId top_thread_message_id, MessageId message_id, MessageInputReplyTo get_message_input_reply_to(DialogId dialog_id, MessageId top_thread_message_id,
bool for_draft); td_api::object_ptr<td_api::MessageReplyTo> &&reply_to, bool for_draft);
Result<td_api::object_ptr<td_api::message>> send_message( Result<td_api::object_ptr<td_api::message>> send_message(
DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id, DialogId dialog_id, MessageId top_thread_message_id, td_api::object_ptr<td_api::MessageReplyTo> &&reply_to,
tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup, tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
tl_object_ptr<td_api::InputMessageContent> &&input_message_content) TD_WARN_UNUSED_RESULT; tl_object_ptr<td_api::InputMessageContent> &&input_message_content) TD_WARN_UNUSED_RESULT;
Result<td_api::object_ptr<td_api::messages>> send_message_group( Result<td_api::object_ptr<td_api::messages>> send_message_group(
DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id, DialogId dialog_id, MessageId top_thread_message_id, td_api::object_ptr<td_api::MessageReplyTo> &&reply_to,
tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::messageSendOptions> &&options,
vector<tl_object_ptr<td_api::InputMessageContent>> &&input_message_contents, vector<tl_object_ptr<td_api::InputMessageContent>> &&input_message_contents,
bool only_preview) TD_WARN_UNUSED_RESULT; bool only_preview) TD_WARN_UNUSED_RESULT;
@ -481,7 +463,7 @@ class MessagesManager final : public Actor {
const string &parameter) TD_WARN_UNUSED_RESULT; const string &parameter) TD_WARN_UNUSED_RESULT;
Result<MessageId> send_inline_query_result_message(DialogId dialog_id, MessageId top_thread_message_id, Result<MessageId> send_inline_query_result_message(DialogId dialog_id, MessageId top_thread_message_id,
MessageId reply_to_message_id, td_api::object_ptr<td_api::MessageReplyTo> &&reply_to,
tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::messageSendOptions> &&options,
int64 query_id, const string &result_id, int64 query_id, const string &result_id,
bool hide_via_bot) TD_WARN_UNUSED_RESULT; bool hide_via_bot) TD_WARN_UNUSED_RESULT;
@ -501,7 +483,7 @@ class MessagesManager final : public Actor {
bool expect_user, bool only_check, Promise<Unit> &&promise); bool expect_user, bool only_check, Promise<Unit> &&promise);
Result<MessageId> add_local_message(DialogId dialog_id, td_api::object_ptr<td_api::MessageSender> &&sender, Result<MessageId> add_local_message(DialogId dialog_id, td_api::object_ptr<td_api::MessageSender> &&sender,
MessageId reply_to_message_id, bool disable_notification, td_api::object_ptr<td_api::MessageReplyTo> &&reply_to, bool disable_notification,
tl_object_ptr<td_api::InputMessageContent> &&input_message_content) tl_object_ptr<td_api::InputMessageContent> &&input_message_content)
TD_WARN_UNUSED_RESULT; TD_WARN_UNUSED_RESULT;
@ -1815,18 +1797,20 @@ class MessagesManager final : public Actor {
static Status can_use_message_send_options(const MessageSendOptions &options, const InputMessageContent &content); 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); Status can_use_top_thread_message_id(Dialog *d, MessageId top_thread_message_id,
const MessageInputReplyTo &input_reply_to);
bool is_anonymous_administrator(DialogId dialog_id, string *author_signature) const; bool is_anonymous_administrator(DialogId dialog_id, string *author_signature) const;
int64 generate_new_random_id(const Dialog *d); int64 generate_new_random_id(const Dialog *d);
unique_ptr<Message> create_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id, unique_ptr<Message> create_message_to_send(Dialog *d, MessageId top_thread_message_id,
const MessageSendOptions &options, unique_ptr<MessageContent> &&content, MessageInputReplyTo input_reply_to, const MessageSendOptions &options,
bool suppress_reply_info, unique_ptr<MessageForwardInfo> forward_info, unique_ptr<MessageContent> &&content, bool suppress_reply_info,
bool is_copy, DialogId send_as_dialog_id) const; unique_ptr<MessageForwardInfo> forward_info, bool is_copy,
DialogId send_as_dialog_id) const;
Message *get_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id, Message *get_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageInputReplyTo input_reply_to,
const MessageSendOptions &options, unique_ptr<MessageContent> &&content, const MessageSendOptions &options, unique_ptr<MessageContent> &&content,
bool *need_update_dialog_pos, bool suppress_reply_info = false, bool *need_update_dialog_pos, bool suppress_reply_info = false,
unique_ptr<MessageForwardInfo> forward_info = nullptr, bool is_copy = false, unique_ptr<MessageForwardInfo> forward_info = nullptr, bool is_copy = false,
@ -1864,7 +1848,8 @@ class MessagesManager final : public Actor {
static FullMessageId get_replied_message_id(DialogId dialog_id, const Message *m); static FullMessageId get_replied_message_id(DialogId dialog_id, const Message *m);
MessageId get_reply_to_message_id(Dialog *d, MessageId top_thread_message_id, MessageId message_id, bool for_draft); MessageInputReplyTo get_message_input_reply_to(Dialog *d, MessageId top_thread_message_id,
td_api::object_ptr<td_api::MessageReplyTo> &&reply_to, bool for_draft);
void fix_server_reply_to_message_id(DialogId dialog_id, MessageId message_id, DialogId reply_in_dialog_id, void fix_server_reply_to_message_id(DialogId dialog_id, MessageId message_id, DialogId reply_in_dialog_id,
MessageId &reply_to_message_id) const; MessageId &reply_to_message_id) const;
@ -1915,7 +1900,7 @@ class MessagesManager final : public Actor {
struct ForwardedMessages { struct ForwardedMessages {
struct CopiedMessage { struct CopiedMessage {
unique_ptr<MessageContent> content; unique_ptr<MessageContent> content;
MessageId reply_to_message_id; MessageInputReplyTo input_reply_to;
MessageId original_message_id; MessageId original_message_id;
MessageId original_reply_to_message_id; MessageId original_reply_to_message_id;
unique_ptr<ReplyMarkup> reply_markup; unique_ptr<ReplyMarkup> reply_markup;

View File

@ -42,6 +42,10 @@ struct StoryFullId {
return story_id; return story_id;
} }
bool is_valid() const {
return dialog_id.is_valid() && story_id.is_valid();
}
template <class StorerT> template <class StorerT>
void store(StorerT &storer) const { void store(StorerT &storer) const {
dialog_id.store(storer); dialog_id.store(storer);
@ -57,8 +61,7 @@ struct StoryFullId {
struct StoryFullIdHash { struct StoryFullIdHash {
uint32 operator()(StoryFullId story_full_id) const { uint32 operator()(StoryFullId story_full_id) const {
return DialogIdHash()(story_full_id.get_dialog_id()) * 2023654985u + return DialogIdHash()(story_full_id.get_dialog_id()) * 2023654985u + StoryIdHash()(story_full_id.get_story_id());
StoryIdHash()(story_full_id.get_story_id());
} }
}; };

View File

@ -5475,7 +5475,7 @@ void Td::on_request(uint64 id, const td_api::setChatMessageSender &request) {
void Td::on_request(uint64 id, td_api::sendMessage &request) { void Td::on_request(uint64 id, td_api::sendMessage &request) {
auto r_sent_message = messages_manager_->send_message( auto r_sent_message = messages_manager_->send_message(
DialogId(request.chat_id_), MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_), DialogId(request.chat_id_), MessageId(request.message_thread_id_), std::move(request.reply_to_),
std::move(request.options_), std::move(request.reply_markup_), std::move(request.input_message_content_)); std::move(request.options_), std::move(request.reply_markup_), std::move(request.input_message_content_));
if (r_sent_message.is_error()) { if (r_sent_message.is_error()) {
send_closure(actor_id(this), &Td::send_error, id, r_sent_message.move_as_error()); send_closure(actor_id(this), &Td::send_error, id, r_sent_message.move_as_error());
@ -5486,7 +5486,7 @@ void Td::on_request(uint64 id, td_api::sendMessage &request) {
void Td::on_request(uint64 id, td_api::sendMessageAlbum &request) { void Td::on_request(uint64 id, td_api::sendMessageAlbum &request) {
auto r_messages = messages_manager_->send_message_group( auto r_messages = messages_manager_->send_message_group(
DialogId(request.chat_id_), MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_), DialogId(request.chat_id_), MessageId(request.message_thread_id_), std::move(request.reply_to_),
std::move(request.options_), std::move(request.input_message_contents_), request.only_preview_); std::move(request.options_), std::move(request.input_message_contents_), request.only_preview_);
if (r_messages.is_error()) { if (r_messages.is_error()) {
send_closure(actor_id(this), &Td::send_error, id, r_messages.move_as_error()); send_closure(actor_id(this), &Td::send_error, id, r_messages.move_as_error());
@ -5517,8 +5517,8 @@ void Td::on_request(uint64 id, td_api::sendInlineQueryResultMessage &request) {
DialogId dialog_id(request.chat_id_); DialogId dialog_id(request.chat_id_);
auto r_new_message_id = messages_manager_->send_inline_query_result_message( auto r_new_message_id = messages_manager_->send_inline_query_result_message(
dialog_id, MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_), dialog_id, MessageId(request.message_thread_id_), std::move(request.reply_to_), std::move(request.options_),
std::move(request.options_), request.query_id_, request.result_id_, request.hide_via_bot_); request.query_id_, request.result_id_, request.hide_via_bot_);
if (r_new_message_id.is_error()) { if (r_new_message_id.is_error()) {
return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error()); return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error());
} }
@ -5533,9 +5533,9 @@ void Td::on_request(uint64 id, td_api::addLocalMessage &request) {
CHECK_IS_USER(); CHECK_IS_USER();
DialogId dialog_id(request.chat_id_); DialogId dialog_id(request.chat_id_);
auto r_new_message_id = messages_manager_->add_local_message( auto r_new_message_id =
dialog_id, std::move(request.sender_id_), MessageId(request.reply_to_message_id_), request.disable_notification_, messages_manager_->add_local_message(dialog_id, std::move(request.sender_id_), std::move(request.reply_to_),
std::move(request.input_message_content_)); request.disable_notification_, std::move(request.input_message_content_));
if (r_new_message_id.is_error()) { if (r_new_message_id.is_error()) {
return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error()); return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error());
} }
@ -8100,7 +8100,7 @@ void Td::on_request(uint64 id, td_api::openWebApp &request) {
CLEAN_INPUT_STRING(request.application_name_); CLEAN_INPUT_STRING(request.application_name_);
CREATE_REQUEST_PROMISE(); CREATE_REQUEST_PROMISE();
attach_menu_manager_->request_web_view(DialogId(request.chat_id_), UserId(request.bot_user_id_), attach_menu_manager_->request_web_view(DialogId(request.chat_id_), UserId(request.bot_user_id_),
MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_), MessageId(request.message_thread_id_), std::move(request.reply_to_),
std::move(request.url_), std::move(request.theme_), std::move(request.url_), std::move(request.theme_),
std::move(request.application_name_), std::move(promise)); std::move(request.application_name_), std::move(promise));
} }

View File

@ -878,6 +878,38 @@ class CliClient final : public Actor {
arg.file_id = as_file_id(args); arg.file_id = as_file_id(args);
} }
struct MessageReplyTo {
int64 message_id = 0;
// or
int64 user_id = 0;
int32 story_id = 0;
operator td_api::object_ptr<td_api::MessageReplyTo>() const {
if (message_id == 0 && user_id == 0 && story_id == 0) {
return nullptr;
}
if (message_id != 0) {
return td_api::make_object<td_api::messageReplyToMessage>(-1, message_id);
} else {
return td_api::make_object<td_api::messageReplyToStory>(user_id, story_id);
}
}
};
void get_args(string &args, MessageReplyTo &arg) const {
if (!args.empty() && args != "0") {
if (args.find('_') == string::npos) {
arg.message_id = as_message_id(args);
} else {
string user_id;
string story_id;
std::tie(user_id, story_id) = split(args, '_');
arg.user_id = as_user_id(user_id);
arg.story_id = as_story_id(story_id);
}
}
}
struct InputInvoice { struct InputInvoice {
int64 chat_id = 0; int64 chat_id = 0;
int64 message_id = 0; int64 message_id = 0;
@ -2059,9 +2091,10 @@ class CliClient final : public Actor {
} }
void send_message(int64 chat_id, td_api::object_ptr<td_api::InputMessageContent> &&input_message_content, void send_message(int64 chat_id, td_api::object_ptr<td_api::InputMessageContent> &&input_message_content,
bool disable_notification = false, bool from_background = false, int64 reply_to_message_id = 0) { bool disable_notification = false, bool from_background = false,
MessageReplyTo message_reply_to = {}) {
auto id = send_request(td_api::make_object<td_api::sendMessage>( auto id = send_request(td_api::make_object<td_api::sendMessage>(
chat_id, message_thread_id_, reply_to_message_id, chat_id, message_thread_id_, message_reply_to,
td_api::make_object<td_api::messageSendOptions>(disable_notification, from_background, true, true, td_api::make_object<td_api::messageSendOptions>(disable_notification, from_background, true, true,
as_message_scheduling_state(schedule_date_), as_message_scheduling_state(schedule_date_),
Random::fast(1, 1000)), Random::fast(1, 1000)),
@ -4057,11 +4090,11 @@ class CliClient final : public Actor {
ChatId chat_id; ChatId chat_id;
UserId bot_user_id; UserId bot_user_id;
string url; string url;
MessageId reply_to_message_id; MessageReplyTo message_reply_to;
MessageThreadId message_thread_id; MessageThreadId message_thread_id;
get_args(args, chat_id, bot_user_id, url, reply_to_message_id, message_thread_id); get_args(args, chat_id, bot_user_id, url, message_reply_to, message_thread_id);
send_request(td_api::make_object<td_api::openWebApp>(chat_id, bot_user_id, url, as_theme_parameters(), "android", send_request(td_api::make_object<td_api::openWebApp>(chat_id, bot_user_id, url, as_theme_parameters(), "android",
reply_to_message_id, message_thread_id)); message_thread_id, message_reply_to));
} else if (op == "cwa") { } else if (op == "cwa") {
int64 launch_id; int64 launch_id;
get_args(args, launch_id); get_args(args, launch_id);
@ -4115,17 +4148,17 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::setChatMessageSender>(chat_id, as_message_sender(sender_id))); send_request(td_api::make_object<td_api::setChatMessageSender>(chat_id, as_message_sender(sender_id)));
} else if (op == "sm" || op == "sms" || op == "smr" || op == "smf") { } else if (op == "sm" || op == "sms" || op == "smr" || op == "smf") {
ChatId chat_id; ChatId chat_id;
MessageId reply_to_message_id; MessageReplyTo message_reply_to;
string message; string message;
get_args(args, chat_id, message); get_args(args, chat_id, message);
if (op == "smr") { if (op == "smr") {
get_args(message, reply_to_message_id, message); get_args(message, message_reply_to, message);
} }
if (op == "smf") { if (op == "smf") {
message = string(5097, 'a'); message = string(5097, 'a');
} }
send_message(chat_id, td_api::make_object<td_api::inputMessageText>(as_formatted_text(message), false, true), send_message(chat_id, td_api::make_object<td_api::inputMessageText>(as_formatted_text(message), false, true),
op == "sms", false, reply_to_message_id); op == "sms", false, message_reply_to);
} else if (op == "smce") { } else if (op == "smce") {
ChatId chat_id; ChatId chat_id;
get_args(args, chat_id); get_args(args, chat_id);
@ -4137,26 +4170,25 @@ class CliClient final : public Actor {
entities.push_back(td_api::make_object<td_api::textEntity>( entities.push_back(td_api::make_object<td_api::textEntity>(
6, 5, td_api::make_object<td_api::textEntityTypeCustomEmoji>(5368324170671202286))); 6, 5, td_api::make_object<td_api::textEntityTypeCustomEmoji>(5368324170671202286)));
auto text = as_formatted_text("👍 😉 🧑‍🚒", std::move(entities)); auto text = as_formatted_text("👍 😉 🧑‍🚒", std::move(entities));
send_message(chat_id, td_api::make_object<td_api::inputMessageText>(std::move(text), false, true), false, false, send_message(chat_id, td_api::make_object<td_api::inputMessageText>(std::move(text), false, true));
0);
} else if (op == "alm" || op == "almr") { } else if (op == "alm" || op == "almr") {
ChatId chat_id; ChatId chat_id;
string sender_id; string sender_id;
MessageId reply_to_message_id; MessageReplyTo message_reply_to;
string message; string message;
get_args(args, chat_id, sender_id, message); get_args(args, chat_id, sender_id, message);
if (op == "almr") { if (op == "almr") {
get_args(message, reply_to_message_id, message); get_args(message, message_reply_to, message);
} }
send_request(td_api::make_object<td_api::addLocalMessage>( send_request(td_api::make_object<td_api::addLocalMessage>(
chat_id, as_message_sender(sender_id), reply_to_message_id, false, chat_id, as_message_sender(sender_id), message_reply_to, false,
td_api::make_object<td_api::inputMessageText>(as_formatted_text(message), false, true))); td_api::make_object<td_api::inputMessageText>(as_formatted_text(message), false, true)));
} else if (op == "smap" || op == "smapr" || op == "smapp" || op == "smaprp") { } else if (op == "smap" || op == "smapr" || op == "smapp" || op == "smaprp") {
ChatId chat_id; ChatId chat_id;
MessageId reply_to_message_id; MessageReplyTo message_reply_to;
get_args(args, chat_id, args); get_args(args, chat_id, args);
if (op == "smapr" || op == "smaprp") { if (op == "smapr" || op == "smaprp") {
get_args(args, reply_to_message_id, args); get_args(args, message_reply_to, args);
} }
auto input_message_contents = transform(full_split(args), [this](const string &photo) { auto input_message_contents = transform(full_split(args), [this](const string &photo) {
td_api::object_ptr<td_api::InputMessageContent> content = td_api::make_object<td_api::inputMessagePhoto>( td_api::object_ptr<td_api::InputMessageContent> content = td_api::make_object<td_api::inputMessagePhoto>(
@ -4165,7 +4197,7 @@ class CliClient final : public Actor {
return content; return content;
}); });
send_request(td_api::make_object<td_api::sendMessageAlbum>( send_request(td_api::make_object<td_api::sendMessageAlbum>(
chat_id, message_thread_id_, reply_to_message_id, default_message_send_options(), chat_id, message_thread_id_, message_reply_to, default_message_send_options(),
std::move(input_message_contents), op == "smapp" || op == "smaprp")); std::move(input_message_contents), op == "smapp" || op == "smaprp"));
} else if (op == "smad" || op == "smadp") { } else if (op == "smad" || op == "smadp") {
ChatId chat_id; ChatId chat_id;
@ -4175,7 +4207,7 @@ class CliClient final : public Actor {
td_api::make_object<td_api::inputMessageDocument>(as_input_file(document), nullptr, true, as_caption("")); td_api::make_object<td_api::inputMessageDocument>(as_input_file(document), nullptr, true, as_caption(""));
return content; return content;
}); });
send_request(td_api::make_object<td_api::sendMessageAlbum>(chat_id, message_thread_id_, 0, send_request(td_api::make_object<td_api::sendMessageAlbum>(chat_id, message_thread_id_, nullptr,
default_message_send_options(), default_message_send_options(),
std::move(input_message_contents), op.back() == 'p')); std::move(input_message_contents), op.back() == 'p'));
} else if (op == "gmft") { } else if (op == "gmft") {
@ -4368,7 +4400,7 @@ class CliClient final : public Actor {
string result_id; string result_id;
get_args(args, chat_id, query_id, result_id); get_args(args, chat_id, query_id, result_id);
send_request(td_api::make_object<td_api::sendInlineQueryResultMessage>( send_request(td_api::make_object<td_api::sendInlineQueryResultMessage>(
chat_id, message_thread_id_, 0, default_message_send_options(), query_id, result_id, op == "siqrh")); chat_id, message_thread_id_, nullptr, default_message_send_options(), query_id, result_id, op == "siqrh"));
} else if (op == "gcqa") { } else if (op == "gcqa") {
ChatId chat_id; ChatId chat_id;
MessageId message_id; MessageId message_id;