diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 738907981..5e9012eda 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4995,6 +4995,12 @@ getChatMessageCalendar chat_id:int53 filter:SearchMessagesFilter from_message_id //@description Returns approximate number of messages of the specified type in the chat @chat_id Identifier of the chat in which to count messages @filter Filter for message content; searchMessagesFilterEmpty is unsupported in this function @return_local Pass true to get the number of messages without sending network requests, or -1 if the number of messages is unknown locally getChatMessageCount chat_id:int53 filter:SearchMessagesFilter return_local:Bool = Count; +//@description Returns approximate 1-based position of a message among messages, which can be found by the specified filter in the chat. Cannot be used in secret chats +//@chat_id Identifier of the chat in which to find message position @message_id Message identifier +//@filter Filter for message content; searchMessagesFilterEmpty, searchMessagesFilterUnreadMention, searchMessagesFilterUnreadReaction, and searchMessagesFilterFailedToSend are unsupported in this function +//@message_thread_id If not 0, only messages in the specified thread will be considered; supergroups only +getChatMessagePosition chat_id:int53 message_id:int53 filter:SearchMessagesFilter message_thread_id:int53 = Count; + //@description Returns all scheduled messages in a chat. The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id) @chat_id Chat identifier getChatScheduledMessages chat_id:int53 = Messages; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 0f8afa79e..4a5a9686a 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -2354,6 +2354,8 @@ class GetSearchResultCalendarQuery final : public Td::ResultHandler { td_->contacts_manager_->on_get_users(std::move(result->users_), "GetSearchResultCalendarQuery"); td_->contacts_manager_->on_get_chats(std::move(result->chats_), "GetSearchResultCalendarQuery"); + // unused: inexact:flags.0?true min_date:int min_msg_id:int offset_id_offset:flags.1?int + MessagesManager::MessagesInfo info; info.messages = std::move(result->messages_); info.total_count = result->count_; @@ -2383,6 +2385,90 @@ class GetSearchResultCalendarQuery final : public Td::ResultHandler { } }; +class GetMessagePositionQuery final : public Td::ResultHandler { + Promise promise_; + DialogId dialog_id_; + MessageId message_id_; + MessageSearchFilter filter_; + + public: + explicit GetMessagePositionQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(DialogId dialog_id, MessageId message_id, MessageSearchFilter filter, MessageId top_thread_message_id) { + auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + CHECK(input_peer != nullptr); + + dialog_id_ = dialog_id; + message_id_ = message_id; + filter_ = filter; + + int32 flags = 0; + if (top_thread_message_id.is_valid()) { + flags |= telegram_api::messages_search::TOP_MSG_ID_MASK; + } + send_query(G()->net_query_creator().create(telegram_api::messages_search( + flags, std::move(input_peer), string(), nullptr, top_thread_message_id.get_server_message_id().get(), + get_input_messages_filter(filter), 0, std::numeric_limits::max(), + message_id.get_server_message_id().get(), -1, 1, std::numeric_limits::max(), 0, 0))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto messages_ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for GetMessagePositionQuery: " << to_string(messages_ptr); + switch (messages_ptr->get_id()) { + case telegram_api::messages_messages::ID: { + auto messages = move_tl_object_as(messages_ptr); + if (messages->messages_.size() != 1 || + MessagesManager::get_message_id(messages->messages_[0], false) != message_id_) { + return promise_.set_error(Status::Error(400, "Message not found by the filter")); + } + return promise_.set_value(narrow_cast(messages->messages_.size())); + } + case telegram_api::messages_messagesSlice::ID: { + auto messages = move_tl_object_as(messages_ptr); + if (messages->messages_.size() != 1 || + MessagesManager::get_message_id(messages->messages_[0], false) != message_id_) { + return promise_.set_error(Status::Error(400, "Message not found by the filter")); + } + if (messages->offset_id_offset_ <= 0) { + LOG(ERROR) << "Failed to receive position for " << message_id_ << " in " << dialog_id_ << " by " << filter_; + return promise_.set_error(Status::Error(400, "Message position is unknown")); + } + return promise_.set_value(std::move(messages->offset_id_offset_)); + } + case telegram_api::messages_channelMessages::ID: { + auto messages = move_tl_object_as(messages_ptr); + if (messages->messages_.size() != 1 || + MessagesManager::get_message_id(messages->messages_[0], false) != message_id_) { + return promise_.set_error(Status::Error(400, "Message not found by the filter")); + } + if (messages->offset_id_offset_ <= 0) { + LOG(ERROR) << "Failed to receive position for " << message_id_ << " in " << dialog_id_ << " by " << filter_; + return promise_.set_error(Status::Error(500, "Message position is unknown")); + } + return promise_.set_value(std::move(messages->offset_id_offset_)); + } + case telegram_api::messages_messagesNotModified::ID: + LOG(ERROR) << "Server returned messagesNotModified in response to GetMessagePositionQuery"; + return promise_.set_error(Status::Error(500, "Receive invalid response")); + default: + UNREACHABLE(); + break; + } + } + + void on_error(Status status) final { + td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetMessagePositionQuery"); + promise_.set_error(std::move(status)); + } +}; + class SearchMessagesQuery final : public Td::ResultHandler { Promise promise_; DialogId dialog_id_; @@ -23881,6 +23967,51 @@ void MessagesManager::get_dialog_message_count_from_server(DialogId dialog_id, M } } +void MessagesManager::get_dialog_message_position(FullMessageId full_message_id, MessageSearchFilter filter, + MessageId top_thread_message_id, Promise &&promise) { + auto dialog_id = full_message_id.get_dialog_id(); + Dialog *d = get_dialog_force(dialog_id, "get_dialog_message_position"); + if (d == nullptr) { + return promise.set_error(Status::Error(400, "Chat not found")); + } + if (!have_input_peer(dialog_id, AccessRights::Read)) { + return promise.set_error(Status::Error(400, "Can't access the chat")); + } + + auto message_id = full_message_id.get_message_id(); + const Message *m = get_message_force(d, message_id, "get_dialog_message_position"); + if (m == nullptr) { + return promise.set_error(Status::Error(400, "Message not found")); + } + if (!m->message_id.is_valid() || !m->message_id.is_server() || + (get_message_index_mask(d->dialog_id, m) & message_search_filter_index_mask(filter)) == 0) { + return promise.set_error(Status::Error(400, "Message can't be found in the filter")); + } + + if (top_thread_message_id != MessageId()) { + if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server()) { + return promise.set_error(Status::Error(400, "Invalid message thread identifier specified")); + } + if (dialog_id.get_type() != DialogType::Channel || is_broadcast_channel(dialog_id)) { + return promise.set_error(Status::Error(400, "Can't filter by message thread identifier in the chat")); + } + if (m->top_thread_message_id != top_thread_message_id) { + return promise.set_error(Status::Error(400, "Message doesn't belong to the message thread")); + } + } + if (dialog_id.get_type() == DialogType::SecretChat) { + return promise.set_error(Status::Error(400, "The method can't be used in secret chats")); + } + + if (filter == MessageSearchFilter::Empty || filter == MessageSearchFilter::UnreadMention || + filter == MessageSearchFilter::UnreadReaction || filter == MessageSearchFilter::FailedToSend) { + return promise.set_error(Status::Error(400, "The filter is not supported")); + } + + td_->create_handler(std::move(promise)) + ->send(dialog_id, message_id, filter, top_thread_message_id); +} + void MessagesManager::preload_newer_messages(const Dialog *d, MessageId max_message_id) { CHECK(d != nullptr); CHECK(max_message_id.is_valid()); diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 654adbc0b..878c42f59 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -809,6 +809,9 @@ class MessagesManager final : public Actor { void get_dialog_message_count(DialogId dialog_id, MessageSearchFilter filter, bool return_local, Promise &&promise); + void get_dialog_message_position(FullMessageId full_message_id, MessageSearchFilter filter, + MessageId top_thread_message_id, Promise &&promise); + vector get_dialog_scheduled_messages(DialogId dialog_id, bool force, bool ignore_result, Promise &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index f96456e70..95a5d02b0 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5194,6 +5194,21 @@ void Td::on_request(uint64 id, const td_api::getChatMessageCount &request) { request.return_local_, std::move(query_promise)); } +void Td::on_request(uint64 id, const td_api::getChatMessagePosition &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(make_tl_object(result.move_as_ok())); + } + }); + messages_manager_->get_dialog_message_position({DialogId(request.chat_id_), MessageId(request.message_id_)}, + get_message_search_filter(request.filter_), + MessageId(request.message_thread_id_), std::move(query_promise)); +} + void Td::on_request(uint64 id, const td_api::getChatScheduledMessages &request) { CHECK_IS_USER(); CREATE_REQUEST(GetChatScheduledMessagesRequest, request.chat_id_); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index ea7e51aef..e14693216 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -654,6 +654,8 @@ class Td final : public Actor { void on_request(uint64 id, const td_api::getChatMessageCount &request); + void on_request(uint64 id, const td_api::getChatMessagePosition &request); + void on_request(uint64 id, const td_api::getChatScheduledMessages &request); void on_request(uint64 id, const td_api::getEmojiReaction &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 5c622950a..2ccc85c96 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2391,6 +2391,14 @@ class CliClient final : public Actor { get_args(args, chat_id, filter, return_local); send_request( td_api::make_object(chat_id, as_search_messages_filter(filter), return_local)); + } else if (op == "gcmp") { + ChatId chat_id; + MessageId message_id; + string filter; + string message_thread_id; + get_args(args, chat_id, message_id, filter, message_thread_id); + send_request(td_api::make_object( + chat_id, message_id, as_search_messages_filter(filter), as_message_thread_id(message_thread_id))); } else if (op == "gup" || op == "gupp") { UserId user_id; int32 offset;