diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index ea95d7a4c..1af73f74a 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2486,6 +2486,9 @@ getActiveLiveLocationMessages = Messages; //@description Returns the last message sent in a chat no later than the specified date @chat_id Chat identifier @date Point in time (Unix timestamp) relative to which to search for messages getChatMessageByDate chat_id:int53 date:int32 = Message; +//@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 If true, returns count that is available locally without sending network requests, returning -1 if the number of messages is unknown +getChatMessageCount chat_id:int53 filter:SearchMessagesFilter return_local:Bool = Count; + //@description Returns a public HTTPS link to a message. Available only for messages in public supergroups and channels //@chat_id Identifier of the chat to which the message belongs diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 64f58903c..4c21404b5 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 711c595bf..8cc47fd51 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -15000,6 +15000,68 @@ tl_object_ptr MessagesManager::get_dialog_message_by_date_objec return get_message_object(full_message_id); } +int32 MessagesManager::get_dialog_message_count(DialogId dialog_id, + const tl_object_ptr &filter, + bool return_local, int64 &random_id, Promise &&promise) { + if (random_id != 0) { + // request has already been sent before + auto it = found_dialog_messages_.find(random_id); + CHECK(it != found_dialog_messages_.end()); + auto result = std::move(it->second); + found_dialog_messages_.erase(it); + promise.set_value(Unit()); + return result.first; + } + + LOG(INFO) << "Get " << (return_local ? "local " : "") << "number of messages in " << dialog_id << " filtered by " + << to_string(filter); + + const Dialog *d = get_dialog_force(dialog_id); + if (d == nullptr) { + promise.set_error(Status::Error(6, "Chat not found")); + return -1; + } + + auto filter_type = get_search_messages_filter(filter); + if (filter_type == SearchMessagesFilter::Empty) { + promise.set_error(Status::Error(6, "SearchMessagesFilterEmpty is not supported")); + return -1; + } + + auto dialog_type = dialog_id.get_type(); + int32 message_count = d->message_count_by_index[search_messages_filter_index(filter_type)]; + if (message_count == -1) { + if (filter_type == SearchMessagesFilter::UnreadMention) { + message_count = d->unread_mention_count; + } + } + if (message_count != -1 || return_local || dialog_type == DialogType::SecretChat) { + promise.set_value(Unit()); + return message_count; + } + + LOG(INFO) << "Get number of messages in " << dialog_id << " filtered by " << to_string(filter) << " from the server"; + + do { + random_id = Random::secure_int64(); + } while (random_id == 0 || found_dialog_messages_.find(random_id) != found_dialog_messages_.end()); + found_dialog_messages_[random_id]; // reserve place for result + + switch (dialog_id.get_type()) { + case DialogType::User: + case DialogType::Chat: + case DialogType::Channel: + td_->create_handler(std::move(promise)) + ->send(dialog_id, "", UserId(), nullptr, MessageId(), 0, 1, filter_type, random_id); + break; + case DialogType::None: + case DialogType::SecretChat: + default: + UNREACHABLE(); + } + return -1; +} + void MessagesManager::preload_newer_messages(const Dialog *d, MessageId max_message_id) { if (td_->auth_manager_->is_bot()) { return; diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index a68e4a96a..190ffdca3 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -1324,6 +1324,9 @@ class MessagesManager : public Actor { void on_get_dialog_message_by_date_fail(int64 random_id); + int32 get_dialog_message_count(DialogId dialog_id, const tl_object_ptr &filter, + bool return_local, int64 &random_id, Promise &&promise); + tl_object_ptr get_dialog_message_by_date_object(int64 random_id); tl_object_ptr get_message_object(FullMessageId full_message_id); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 3ad924c3c..630ed72f6 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -1619,6 +1619,34 @@ class GetChatMessageByDateRequest : public RequestOnceActor { } }; +class GetChatMessageCountRequest : public RequestActor<> { + DialogId dialog_id_; + tl_object_ptr filter_; + bool return_local_; + int64 random_id_; + + int32 result_ = 0; + + void do_run(Promise &&promise) override { + result_ = td->messages_manager_->get_dialog_message_count(dialog_id_, filter_, return_local_, random_id_, + std::move(promise)); + } + + void do_send_result() override { + send_result(td_api::make_object(result_)); + } + + public: + GetChatMessageCountRequest(ActorShared td, uint64 request_id, int64 dialog_id, + tl_object_ptr filter, bool return_local) + : RequestActor(std::move(td), request_id) + , dialog_id_(dialog_id) + , filter_(std::move(filter)) + , return_local_(return_local) + , random_id_(0) { + } +}; + class GetWebPagePreviewRequest : public RequestOnceActor { td_api::object_ptr text_; @@ -5028,6 +5056,11 @@ void Td::on_request(uint64 id, const td_api::getChatMessageByDate &request) { CREATE_REQUEST(GetChatMessageByDateRequest, request.chat_id_, request.date_); } +void Td::on_request(uint64 id, td_api::getChatMessageCount &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetChatMessageCountRequest, request.chat_id_, std::move(request.filter_), request.return_local_); +} + void Td::on_request(uint64 id, const td_api::deleteMessages &request) { CREATE_OK_REQUEST_PROMISE(); messages_manager_->delete_messages(DialogId(request.chat_id_), MessagesManager::get_message_ids(request.message_ids_), diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 478b2baac..6310e7ce3 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -487,6 +487,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::getChatMessageByDate &request); + void on_request(uint64 id, td_api::getChatMessageCount &request); + void on_request(uint64 id, const td_api::deleteMessages &request); void on_request(uint64 id, const td_api::deleteChatMessagesFromUser &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 49085bd63..b40b399d7 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -890,7 +890,7 @@ class CliClient final : public Actor { if (filter == "vo" || filter == "voice") { return make_tl_object(); } - if (filter == "pvo") { + if (filter == "pvi") { return make_tl_object(); } if (filter == "u" || filter == "url") { @@ -899,10 +899,10 @@ class CliClient final : public Actor { if (filter == "cp" || filter == "chatphoto") { return make_tl_object(); } - if (filter == "vc" || filter == "call") { + if (filter == "c" || filter == "call") { return make_tl_object(); } - if (filter == "mvc" || filter == "missedcall") { + if (filter == "mc" || filter == "missedcall") { return make_tl_object(); } if (filter == "vn" || filter == "videonote") { @@ -1673,6 +1673,16 @@ class CliClient final : public Actor { send_request(make_tl_object( as_chat_id(chat_id), query, 0, as_message_id(offset_message_id), 0, to_integer(limit), make_tl_object())); + } else if (op == "gcmc") { + string chat_id; + string filter; + string return_local; + + std::tie(chat_id, args) = split(args); + std::tie(filter, return_local) = split(args); + + send_request(make_tl_object(as_chat_id(chat_id), get_search_messages_filter(filter), + as_bool(return_local))); } else if (op == "gup" || op == "GetUserPhotos") { string user_id; string offset;