diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 54d3a9167..f49662885 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -1842,7 +1842,7 @@ searchMessagesFilterVoiceAndVideoNote = SearchMessagesFilter; //@description Returns only messages with mentions of the current user, or messages that are replies to their messages searchMessagesFilterMention = SearchMessagesFilter; -//@description Returns only messages with unread mentions of the current user, or messages that are replies to their messages. When using this filter the results can't be additionally filtered by a query or by the sending user +//@description Returns only messages with unread mentions of the current user, or messages that are replies to their messages. When using this filter the results can't be additionally filtered by a query, a message thread or by the sending user searchMessagesFilterUnreadMention = SearchMessagesFilter; //@description Returns only failed to send messages. This filter can be used only if the message database is used @@ -3610,7 +3610,8 @@ deleteChatHistory chat_id:int53 remove_from_chat_list:Bool revoke:Bool = Ok; //@offset Specify 0 to get results from exactly the from_message_id or a negative offset to get the specified message and some newer messages //@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. If the offset is negative, the limit must be greater than -offset. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached //@filter Filter for message content in the search results -searchChatMessages chat_id:int53 query:string sender_user_id:int32 from_message_id:int53 offset:int32 limit:int32 filter:SearchMessagesFilter = Messages; +//@message_thread_id If not 0, only messages in the specified thread will be returned; supergroups only +searchChatMessages chat_id:int53 query:string sender_user_id:int32 from_message_id:int53 offset:int32 limit:int32 filter:SearchMessagesFilter message_thread_id:int53 = Messages; //@description Searches for messages in all chats except secret chats. Returns the results in reverse chronological order (i.e., in order of decreasing (date, chat_id, message_id)). //-For optimal performance the number of returned messages is chosen by the library diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index dbfff2331..74b6d8b40 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 19f78f1d1..108e86250 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -1591,7 +1591,7 @@ class SearchMessagesQuery : public Td::ResultHandler { void send(DialogId dialog_id, const string &query, UserId sender_user_id, telegram_api::object_ptr &&sender_input_user, MessageId from_message_id, - int32 offset, int32 limit, MessageSearchFilter filter, int64 random_id) { + int32 offset, int32 limit, MessageSearchFilter filter, MessageId top_thread_message_id, int64 random_id) { auto input_peer = dialog_id.is_valid() ? td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read) : make_tl_object(); if (input_peer == nullptr) { @@ -1617,9 +1617,13 @@ class SearchMessagesQuery : public Td::ResultHandler { if (sender_input_user != nullptr) { flags |= telegram_api::messages_search::FROM_ID_MASK; } + 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), query, std::move(sender_input_user), 0, get_input_messages_filter(filter), 0, + flags, std::move(input_peer), query, std::move(sender_input_user), + top_thread_message_id.get_server_message_id().get(), get_input_messages_filter(filter), 0, std::numeric_limits::max(), from_message_id.get_server_message_id().get(), offset, limit, std::numeric_limits::max(), 0, 0))); } @@ -18460,7 +18464,8 @@ void MessagesManager::on_read_history_finished(DialogId dialog_id, uint64 genera std::pair> MessagesManager::search_dialog_messages( DialogId dialog_id, const string &query, UserId sender_user_id, MessageId from_message_id, int32 offset, - int32 limit, MessageSearchFilter filter, int64 &random_id, bool use_db, Promise &&promise) { + int32 limit, MessageSearchFilter filter, MessageId top_thread_message_id, int64 &random_id, bool use_db, + Promise &&promise) { if (random_id != 0) { // request has already been sent before auto it = found_dialog_messages_.find(random_id); @@ -18473,8 +18478,8 @@ std::pair> MessagesManager::search_dialog_messages( random_id = 0; } LOG(INFO) << "Search messages with query \"" << query << "\" in " << dialog_id << " sent by " << sender_user_id - << " filtered by " << filter << " from " << from_message_id << " with offset " << offset << " and limit " - << limit; + << " in thread of " << top_thread_message_id << " filtered by " << filter << " from " << from_message_id + << " with offset " << offset << " and limit " << limit; std::pair> result; if (limit <= 0) { @@ -18523,6 +18528,17 @@ std::pair> MessagesManager::search_dialog_messages( return result; } + if (top_thread_message_id != MessageId()) { + if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server()) { + promise.set_error(Status::Error(400, "Invalid message thread ID specified")); + return result; + } + if (dialog_id.get_type() != DialogType::Channel || is_broadcast_channel(dialog_id)) { + promise.set_error(Status::Error(400, "Can't filter by message thread ID in the chat")); + return result; + } + } + do { random_id = Random::secure_int64(); } while (random_id == 0 || found_dialog_messages_.find(random_id) != found_dialog_messages_.end()); @@ -18534,14 +18550,18 @@ std::pair> MessagesManager::search_dialog_messages( return result; } if (input_user != nullptr) { - promise.set_error(Status::Error(6, "Non-empty sender user is unsupported with the specified filter")); + promise.set_error(Status::Error(6, "Filtering by sender user is unsupported with the specified filter")); + return result; + } + if (top_thread_message_id != MessageId()) { + promise.set_error(Status::Error(6, "Filtering by message thread is unsupported with the specified filter")); return result; } } // Trying to use database if (use_db && query.empty() && G()->parameters().use_message_db && filter != MessageSearchFilter::Empty && - input_user == nullptr) { // TODO support filter by users in the database + input_user == nullptr && top_thread_message_id == MessageId()) { // TODO support filter by users in the database MessageId first_db_message_id = get_first_database_message_id_by_index(d, filter); int32 message_count = d->message_count_by_index[message_search_filter_index(filter)]; auto fixed_from_message_id = from_message_id; @@ -18577,7 +18597,8 @@ std::pair> MessagesManager::search_dialog_messages( } LOG(DEBUG) << "Search messages on server in " << dialog_id << " with query \"" << query << "\" from user " - << sender_user_id << " from " << from_message_id << " and with limit " << limit; + << sender_user_id << " in thread of " << top_thread_message_id << " from " << from_message_id + << " and with limit " << limit; switch (dialog_id.get_type()) { case DialogType::None: @@ -18586,7 +18607,7 @@ std::pair> MessagesManager::search_dialog_messages( case DialogType::Channel: td_->create_handler(std::move(promise)) ->send(dialog_id, query, sender_user_id, std::move(input_user), from_message_id, offset, limit, filter, - random_id); + top_thread_message_id, random_id); break; case DialogType::SecretChat: if (filter == MessageSearchFilter::UnreadMention) { @@ -18675,7 +18696,7 @@ std::pair> MessagesManager::search_call_messages(Me LOG(DEBUG) << "Search call messages on server from " << from_message_id << " and with limit " << limit; td_->create_handler(std::move(promise)) - ->send(DialogId(), "", UserId(), nullptr, from_message_id, 0, limit, filter, random_id); + ->send(DialogId(), "", UserId(), nullptr, from_message_id, 0, limit, filter, MessageId(), random_id); return result; } @@ -19549,7 +19570,7 @@ int32 MessagesManager::get_dialog_message_count(DialogId dialog_id, MessageSearc case DialogType::Chat: case DialogType::Channel: td_->create_handler(std::move(promise)) - ->send(dialog_id, "", UserId(), nullptr, MessageId(), 0, 1, filter, random_id); + ->send(dialog_id, "", UserId(), nullptr, MessageId(), 0, 1, filter, MessageId(), random_id); break; case DialogType::None: case DialogType::SecretChat: diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index d2ef8a319..6a01c181d 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -661,7 +661,8 @@ class MessagesManager : public Actor { std::pair> search_dialog_messages(DialogId dialog_id, const string &query, UserId sender_user_id, MessageId from_message_id, int32 offset, int32 limit, MessageSearchFilter filter, - int64 &random_id, bool use_db, Promise &&promise); + MessageId top_thread_message_id, int64 &random_id, + bool use_db, Promise &&promise); struct FoundMessages { vector full_message_ids; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index a6a63a9e7..94b74dc64 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -1398,14 +1398,15 @@ class SearchChatMessagesRequest : public RequestActor<> { int32 offset_; int32 limit_; MessageSearchFilter filter_; + MessageId top_thread_message_id_; int64 random_id_; std::pair> messages_; void do_run(Promise &&promise) override { messages_ = td->messages_manager_->search_dialog_messages(dialog_id_, query_, sender_user_id_, from_message_id_, - offset_, limit_, filter_, random_id_, get_tries() == 3, - std::move(promise)); + offset_, limit_, filter_, top_thread_message_id_, + random_id_, get_tries() == 3, std::move(promise)); } void do_send_result() override { @@ -1424,7 +1425,7 @@ class SearchChatMessagesRequest : public RequestActor<> { public: SearchChatMessagesRequest(ActorShared td, uint64 request_id, int64 dialog_id, string query, int32 user_id, int64 from_message_id, int32 offset, int32 limit, - tl_object_ptr filter) + tl_object_ptr filter, int64 message_thread_id) : RequestActor(std::move(td), request_id) , dialog_id_(dialog_id) , query_(std::move(query)) @@ -1433,6 +1434,7 @@ class SearchChatMessagesRequest : public RequestActor<> { , offset_(offset) , limit_(limit) , filter_(get_message_search_filter(filter)) + , top_thread_message_id_(message_thread_id) , random_id_(0) { set_tries(3); } @@ -5459,7 +5461,8 @@ void Td::on_request(uint64 id, td_api::searchChatMessages &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.query_); CREATE_REQUEST(SearchChatMessagesRequest, request.chat_id_, std::move(request.query_), request.sender_user_id_, - request.from_message_id_, request.offset_, request.limit_, std::move(request.filter_)); + request.from_message_id_, request.offset_, request.limit_, std::move(request.filter_), + request.message_thread_id_); } void Td::on_request(uint64 id, td_api::searchSecretMessages &request) { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 1693fa3cc..81f6bcc98 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -319,7 +319,7 @@ class CliClient final : public Actor { LOG(ERROR) << (last_message_id >> 20); send_request(td_api::make_object( search_chat_id_, "", 0, last_message_id, 0, 100, - td_api::make_object())); + td_api::make_object(), 0)); } else { search_chat_id_ = 0; } @@ -1864,7 +1864,7 @@ class CliClient final : public Actor { search_chat_id_ = as_chat_id(args); send_request(td_api::make_object( - search_chat_id_, "", 0, 0, 0, 100, td_api::make_object())); + search_chat_id_, "", 0, 0, 0, 100, td_api::make_object(), 0)); } else if (op == "Search" || op == "SearchA" || op == "SearchM") { string from_date; string limit; @@ -1899,7 +1899,7 @@ class CliClient final : public Actor { } send_request(td_api::make_object(as_chat_id(chat_id), query, 0, 0, 0, - to_integer(limit), nullptr)); + to_integer(limit), nullptr, 0)); } else if (op == "SMME") { string chat_id; string limit; @@ -1910,7 +1910,7 @@ class CliClient final : public Actor { } send_request(td_api::make_object(as_chat_id(chat_id), "", my_id_, 0, 0, - to_integer(limit), nullptr)); + to_integer(limit), nullptr, 0)); } else if (op == "SMU") { string chat_id; string user_id; @@ -1923,7 +1923,7 @@ class CliClient final : public Actor { } send_request(td_api::make_object(as_chat_id(chat_id), "", as_user_id(user_id), 0, 0, - to_integer(limit), nullptr)); + to_integer(limit), nullptr, 0)); } else if (op == "SM") { string chat_id; string filter; @@ -1947,7 +1947,7 @@ class CliClient final : public Actor { send_request(td_api::make_object( as_chat_id(chat_id), "", 0, as_message_id(offset_message_id), to_integer(offset), - to_integer(limit), as_search_messages_filter(filter))); + to_integer(limit), as_search_messages_filter(filter), 0)); } else if (op == "SC") { string limit; string offset_message_id; @@ -1992,7 +1992,7 @@ class CliClient final : public Actor { } send_request(td_api::make_object( as_chat_id(chat_id), query, 0, as_message_id(offset_message_id), 0, to_integer(limit), - td_api::make_object())); + td_api::make_object(), 0)); } else if (op == "SearchDocument") { string chat_id; string offset_message_id; @@ -2010,7 +2010,7 @@ class CliClient final : public Actor { } send_request(td_api::make_object( as_chat_id(chat_id), query, 0, to_integer(offset_message_id), 0, to_integer(limit), - td_api::make_object())); + td_api::make_object(), 0)); } else if (op == "SearchPhoto") { string chat_id; string offset_message_id; @@ -2028,7 +2028,7 @@ class CliClient final : public Actor { } send_request(td_api::make_object( as_chat_id(chat_id), query, 0, as_message_id(offset_message_id), 0, to_integer(limit), - td_api::make_object())); + td_api::make_object(), 0)); } else if (op == "SearchChatPhoto") { string chat_id; string offset_message_id; @@ -2046,7 +2046,7 @@ class CliClient final : public Actor { } send_request(td_api::make_object( as_chat_id(chat_id), query, 0, as_message_id(offset_message_id), 0, to_integer(limit), - td_api::make_object())); + td_api::make_object(), 0)); } else if (op == "gcmc") { string chat_id; string filter;