diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index e9a9039a0..0a5dd0185 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -3916,9 +3916,12 @@ openChat chat_id:int53 = Ok; //@description Informs TDLib that the chat is closed by the user. Many useful activities depend on the chat being opened or closed @chat_id Chat identifier closeChat chat_id:int53 = Ok; -//@description Informs TDLib that messages are being viewed by the user. Many useful activities depend on whether the messages are currently being viewed or not (e.g., marking messages as read, incrementing a view counter, updating a view counter, removing deleted messages in supergroups and channels) @chat_id Chat identifier @message_ids The identifiers of the messages being viewed -//@force_read True, if messages in closed chats should be marked as read -viewMessages chat_id:int53 message_ids:vector force_read:Bool = Ok; +//@description Informs TDLib that messages are being viewed by the user. Many useful activities depend on whether the messages are currently being viewed or not (e.g., marking messages as read, incrementing a view counter, updating a view counter, removing deleted messages in supergroups and channels) +//@chat_id Chat identifier +//@message_thread_id If not 0, a message thread identifier in which the messages are being viewed +//@message_ids The identifiers of the messages being viewed +//@force_read True, if messages in closed chats should be marked as read by the request +viewMessages chat_id:int53 message_thread_id:int53 message_ids:vector force_read:Bool = Ok; //@description Informs TDLib that the message content has been opened (e.g., the user has opened a photo, video, document, location or venue, or has listened to an audio file or voice note message). An updateMessageContentOpened update will be generated if something has changed @chat_id Chat identifier of the message @message_id Identifier of the message with the opened content openMessageContent chat_id:int53 message_id:int53 = Ok; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 7e3ea2eb3..088c16ac6 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 1c191f86b..9db923998 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -1713,9 +1713,10 @@ class ReadHistoryQuery : public Td::ResultHandler { void send(DialogId dialog_id, MessageId max_message_id) { dialog_id_ = dialog_id; + auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + CHECK(input_peer != nullptr); send_query(G()->net_query_creator().create( - telegram_api::messages_readHistory(td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read), - max_message_id.get_server_message_id().get()))); + telegram_api::messages_readHistory(std::move(input_peer), max_message_id.get_server_message_id().get()))); } void on_result(uint64 id, BufferSlice packet) override { @@ -1778,6 +1779,38 @@ class ReadChannelHistoryQuery : public Td::ResultHandler { } }; +class ReadDiscussionQuery : public Td::ResultHandler { + Promise promise_; + DialogId dialog_id_; + + public: + explicit ReadDiscussionQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(DialogId dialog_id, MessageId top_thread_message_id, MessageId max_message_id) { + dialog_id_ = dialog_id; + auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + CHECK(input_peer != nullptr); + send_query(G()->net_query_creator().create(telegram_api::messages_readDiscussion( + std::move(input_peer), top_thread_message_id.get_server_message_id().get(), + max_message_id.get_server_message_id().get()))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + promise_.set_value(Unit()); + } + + void on_error(uint64 id, Status status) override { + td->messages_manager_->on_get_dialog_error(dialog_id_, status, "ReadDiscussionQuery"); + promise_.set_error(std::move(status)); + } +}; + class SearchMessagesQuery : public Td::ResultHandler { Promise promise_; DialogId dialog_id_; @@ -5331,8 +5364,8 @@ void MessagesManager::on_pending_read_history_timeout_callback(void *messages_ma } auto messages_manager = static_cast(messages_manager_ptr); - send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::read_history_on_server_impl, - DialogId(dialog_id_int), MessageId()); + send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::do_read_history_on_server, + DialogId(dialog_id_int)); } void MessagesManager::on_pending_updated_dialog_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) { @@ -16090,9 +16123,7 @@ Result> MessagesManager::get_message_link(FullMessageId auto t_me = G()->shared_config().get_option_string("t_me_url", "https://t.me/"); if (for_comment) { auto *top_m = get_message_force(d, m->top_reply_message_id, "get_public_message_link"); - if (is_discussion_message(dialog_id, top_m) && - top_m->forward_info->sender_dialog_id == - DialogId(td_->contacts_manager_->get_channel_linked_channel_id(dialog_id.get_channel_id()))) { + if (is_discussion_message(dialog_id, top_m) && is_active_message_reply_info(dialog_id, top_m->reply_info)) { auto linked_dialog_id = top_m->forward_info->sender_dialog_id; auto linked_message_id = top_m->forward_info->message_id; auto linked_d = get_dialog(linked_dialog_id); @@ -16100,9 +16131,9 @@ Result> MessagesManager::get_message_link(FullMessageId CHECK(linked_dialog_id.get_type() == DialogType::Channel); auto *linked_m = get_message_force(linked_d, linked_message_id, "get_public_message_link"); auto channel_username = td_->contacts_manager_->get_channel_username(linked_dialog_id.get_channel_id()); - if (linked_m != nullptr && linked_message_id.is_server() && - have_input_peer(linked_dialog_id, AccessRights::Read) && !channel_username.empty() && - linked_d->deleted_message_ids.count(linked_message_id) == 0) { + if (linked_m != nullptr && is_active_message_reply_info(linked_dialog_id, linked_m->reply_info) && + linked_message_id.is_server() && have_input_peer(linked_dialog_id, AccessRights::Read) && + !channel_username.empty()) { return std::make_pair( PSTRING() << t_me << channel_username << '/' << linked_message_id.get_server_message_id().get() << "?comment=" << m->message_id.get_server_message_id().get() << (for_group ? "" : "&single"), @@ -18079,7 +18110,8 @@ DialogId MessagesManager::get_my_dialog_id() const { return DialogId(td_->contacts_manager_->get_my_id()); } -Status MessagesManager::view_messages(DialogId dialog_id, const vector &message_ids, bool force_read) { +Status MessagesManager::view_messages(DialogId dialog_id, MessageId top_thread_message_id, + const vector &message_ids, bool force_read) { CHECK(!td_->auth_manager_->is_bot()); Dialog *d = get_dialog_force(dialog_id); @@ -18095,6 +18127,15 @@ Status MessagesManager::view_messages(DialogId dialog_id, const vectoris_opened; MessageId max_message_id; // max server or local viewed message_id vector read_content_message_ids; @@ -18138,9 +18179,55 @@ Status MessagesManager::view_messages(DialogId dialog_id, const vector d->last_read_inbox_message_id) { - MessageId last_read_message_id = max_message_id; - MessageId prev_last_read_inbox_message_id = d->last_read_inbox_message_id; + if (!need_read) { + return Status::OK(); + } + + if (top_thread_message_id.is_valid()) { + MessageId prev_last_read_inbox_message_id; + MessageId max_thread_message_id; + Message *top_m = get_message_force(d, top_thread_message_id, "view_messages 2"); + if (top_m != nullptr && is_active_message_reply_info(dialog_id, top_m->reply_info)) { + prev_last_read_inbox_message_id = top_m->reply_info.last_read_inbox_message_id; + if (top_m->reply_info.update_max_message_ids(MessageId(), max_message_id, MessageId())) { + send_update_message_interaction_info(dialog_id, top_m); + on_message_changed(d, top_m, true, "view_messages 3"); + } + max_thread_message_id = top_m->reply_info.max_message_id; + + if (is_discussion_message(dialog_id, top_m)) { + auto linked_dialog_id = top_m->forward_info->sender_dialog_id; + auto linked_d = get_dialog(linked_dialog_id); + CHECK(linked_d != nullptr); + CHECK(linked_dialog_id.get_type() == DialogType::Channel); + auto *linked_m = get_message_force(linked_d, top_m->forward_info->message_id, "view_messages 4"); + if (linked_m != nullptr && is_active_message_reply_info(linked_dialog_id, linked_m->reply_info)) { + if (linked_m->reply_info.last_read_inbox_message_id < prev_last_read_inbox_message_id) { + prev_last_read_inbox_message_id = linked_m->reply_info.last_read_inbox_message_id; + } + if (linked_m->reply_info.update_max_message_ids(MessageId(), max_message_id, MessageId())) { + send_update_message_interaction_info(linked_dialog_id, linked_m); + on_message_changed(linked_d, linked_m, true, "view_messages 5"); + } + if (linked_m->reply_info.max_message_id > max_thread_message_id) { + max_thread_message_id = linked_m->reply_info.max_message_id; + } + } + } + } + + if (max_message_id.get_prev_server_message_id().get() > + prev_last_read_inbox_message_id.get_prev_server_message_id().get()) { + read_message_thread_history_on_server(d, top_thread_message_id, max_message_id.get_prev_server_message_id(), + max_thread_message_id.get_prev_server_message_id()); + } + + return Status::OK(); + } + + if (max_message_id > d->last_read_inbox_message_id) { + const MessageId last_read_message_id = max_message_id; + const MessageId prev_last_read_inbox_message_id = d->last_read_inbox_message_id; MessageId read_history_on_server_message_id; if (dialog_id.get_type() != DialogType::SecretChat) { if (last_read_message_id.get_prev_server_message_id().get() > @@ -18164,7 +18251,7 @@ Status MessagesManager::view_messages(DialogId dialog_id, const vectoris_marked_as_unread) { + if (d->is_marked_as_unread) { set_dialog_is_marked_as_unread(d, false); } @@ -19106,6 +19193,27 @@ class MessagesManager::ReadHistoryInSecretChatLogEvent { } }; +class MessagesManager::ReadMessageThreadHistoryOnServerLogEvent { + public: + DialogId dialog_id_; + MessageId top_thread_message_id_; + MessageId max_message_id_; + + template + void store(StorerT &storer) const { + td::store(dialog_id_, storer); + td::store(top_thread_message_id_, storer); + td::store(max_message_id_, storer); + } + + template + void parse(ParserT &parser) { + td::parse(dialog_id_, parser); + td::parse(top_thread_message_id_, parser); + td::parse(max_message_id_, parser); + } +}; + void MessagesManager::read_history_on_server(Dialog *d, MessageId max_message_id) { if (td_->auth_manager_->is_bot()) { return; @@ -19128,7 +19236,7 @@ void MessagesManager::read_history_on_server(Dialog *d, MessageId max_message_id ReadHistoryInSecretChatLogEvent logevent; logevent.dialog_id_ = dialog_id; logevent.max_date_ = m->date; - add_log_event(d->read_history_logevent_id, LogEventStorerImpl(logevent), + add_log_event(d->read_history_logevent_ids[0], LogEventStorerImpl(logevent), LogEvent::HandlerType::ReadHistoryInSecretChat, "read history"); d->last_read_inbox_message_date = m->date; @@ -19136,37 +19244,87 @@ void MessagesManager::read_history_on_server(Dialog *d, MessageId max_message_id ReadHistoryOnServerLogEvent logevent; logevent.dialog_id_ = dialog_id; logevent.max_message_id_ = max_message_id; - add_log_event(d->read_history_logevent_id, LogEventStorerImpl(logevent), + add_log_event(d->read_history_logevent_ids[0], LogEventStorerImpl(logevent), LogEvent::HandlerType::ReadHistoryOnServer, "read history"); } + d->updated_read_history_message_ids.insert(MessageId()); + bool need_delay = d->is_opened && !is_secret && d->server_unread_count > 0; pending_read_history_timeout_.set_timeout_in(dialog_id.get(), need_delay ? MIN_READ_HISTORY_DELAY : 0); } -void MessagesManager::read_history_on_server_impl(DialogId dialog_id, MessageId max_message_id) { +void MessagesManager::read_message_thread_history_on_server(Dialog *d, MessageId top_thread_message_id, + MessageId max_message_id, MessageId last_message_id) { + if (td_->auth_manager_->is_bot()) { + return; + } + + CHECK(d != nullptr); + CHECK(top_thread_message_id.is_valid()); + CHECK(top_thread_message_id.is_server()); + CHECK(max_message_id.is_server()); + + auto dialog_id = d->dialog_id; + LOG(INFO) << "Read history in thread of " << top_thread_message_id << " in " << dialog_id << " on server up to " + << max_message_id; + + if (G()->parameters().use_message_db) { + ReadMessageThreadHistoryOnServerLogEvent logevent; + logevent.dialog_id_ = dialog_id; + logevent.top_thread_message_id_ = top_thread_message_id; + logevent.max_message_id_ = max_message_id; + add_log_event(d->read_history_logevent_ids[top_thread_message_id.get()], + LogEventStorerImpl(logevent), + LogEvent::HandlerType::ReadMessageThreadHistoryOnServer, "read history"); + } + + d->updated_read_history_message_ids.insert(top_thread_message_id); + + bool need_delay = d->is_opened && last_message_id.is_valid() && max_message_id != last_message_id; + pending_read_history_timeout_.set_timeout_in(dialog_id.get(), need_delay ? MIN_READ_HISTORY_DELAY : 0); +} + +void MessagesManager::do_read_history_on_server(DialogId dialog_id) { if (G()->close_flag()) { return; } Dialog *d = get_dialog(dialog_id); CHECK(d != nullptr); + CHECK(!d->updated_read_history_message_ids.empty()); - auto message_id = d->last_read_inbox_message_id; - if (dialog_id.get_type() != DialogType::SecretChat) { - message_id = message_id.get_prev_server_message_id(); + for (auto top_thread_message_id : d->updated_read_history_message_ids) { + if (!top_thread_message_id.is_valid()) { + read_history_on_server_impl(d, MessageId()); + } else { + read_message_thread_history_on_server_impl(d, top_thread_message_id, MessageId()); + } } - if (message_id > max_message_id) { - max_message_id = message_id; + reset_to_empty(d->updated_read_history_message_ids); +} + +void MessagesManager::read_history_on_server_impl(Dialog *d, MessageId max_message_id) { + CHECK(d != nullptr); + auto dialog_id = d->dialog_id; + + { + auto message_id = d->last_read_inbox_message_id; + if (dialog_id.get_type() != DialogType::SecretChat) { + message_id = message_id.get_prev_server_message_id(); + } + if (message_id > max_message_id) { + max_message_id = message_id; + } } Promise<> promise; - if (d->read_history_logevent_id.logevent_id != 0) { - d->read_history_logevent_id.generation++; + if (d->read_history_logevent_ids[0].logevent_id != 0) { + d->read_history_logevent_ids[0].generation++; promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, - generation = d->read_history_logevent_id.generation](Result result) { + generation = d->read_history_logevent_ids[0].generation](Result result) { if (!G()->close_flag()) { - send_closure(actor_id, &MessagesManager::on_read_history_finished, dialog_id, generation); + send_closure(actor_id, &MessagesManager::on_read_history_finished, dialog_id, MessageId(), generation); } }); } @@ -19174,7 +19332,7 @@ void MessagesManager::read_history_on_server_impl(DialogId dialog_id, MessageId repair_server_unread_count(dialog_id, d->server_unread_count); } - if (!max_message_id.is_valid()) { + if (!max_message_id.is_valid() || !have_input_peer(dialog_id, AccessRights::Read)) { return promise.set_value(Unit()); } @@ -19210,10 +19368,53 @@ void MessagesManager::read_history_on_server_impl(DialogId dialog_id, MessageId } } -void MessagesManager::on_read_history_finished(DialogId dialog_id, uint64 generation) { +void MessagesManager::read_message_thread_history_on_server_impl(Dialog *d, MessageId top_thread_message_id, + MessageId max_message_id) { + CHECK(d != nullptr); + auto dialog_id = d->dialog_id; + CHECK(dialog_id.get_type() == DialogType::Channel); + + const Message *m = get_message_force(d, top_thread_message_id, "read_message_thread_history_on_server_impl"); + if (m != nullptr) { + auto message_id = m->reply_info.last_read_inbox_message_id.get_prev_server_message_id(); + if (message_id > max_message_id) { + max_message_id = message_id; + } + } + + Promise<> promise; + if (d->read_history_logevent_ids[top_thread_message_id.get()].logevent_id != 0) { + d->read_history_logevent_ids[top_thread_message_id.get()].generation++; + promise = PromiseCreator::lambda( + [actor_id = actor_id(this), dialog_id, top_thread_message_id, + generation = d->read_history_logevent_ids[top_thread_message_id.get()].generation](Result result) { + if (!G()->close_flag()) { + send_closure(actor_id, &MessagesManager::on_read_history_finished, dialog_id, top_thread_message_id, + generation); + } + }); + } + + if (!max_message_id.is_valid() || !have_input_peer(dialog_id, AccessRights::Read)) { + return promise.set_value(Unit()); + } + + LOG(INFO) << "Send read history request in thread of " << top_thread_message_id << " in " << dialog_id << " up to " + << max_message_id; + td_->create_handler(std::move(promise))->send(dialog_id, top_thread_message_id, max_message_id); +} + +void MessagesManager::on_read_history_finished(DialogId dialog_id, MessageId top_thread_message_id, uint64 generation) { auto d = get_dialog(dialog_id); CHECK(d != nullptr); - delete_log_event(d->read_history_logevent_id, generation, "read history"); + auto it = d->read_history_logevent_ids.find(top_thread_message_id.get()); + if (it == d->read_history_logevent_ids.end()) { + return; + } + delete_log_event(it->second, generation, "read history"); + if (it->second.logevent_id == 0) { + d->read_history_logevent_ids.erase(it); + } } std::pair> MessagesManager::search_dialog_messages( @@ -23634,6 +23835,9 @@ bool MessagesManager::is_discussion_message(DialogId dialog_id, const Message *m if (m->forward_info->sender_dialog_id == dialog_id) { return false; } + if (m->forward_info->sender_dialog_id.get_type() != DialogType::Channel) { + return false; + } return true; } @@ -34162,13 +34366,13 @@ void MessagesManager::on_binlog_events(vector &&events) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; } - if (d->read_history_logevent_id.logevent_id != 0) { + if (d->read_history_logevent_ids[0].logevent_id != 0) { // we need only latest read history event - binlog_erase(G()->td_db()->get_binlog(), d->read_history_logevent_id.logevent_id); + binlog_erase(G()->td_db()->get_binlog(), d->read_history_logevent_ids[0].logevent_id); } - d->read_history_logevent_id.logevent_id = event.id_; + d->read_history_logevent_ids[0].logevent_id = event.id_; - read_history_on_server_impl(dialog_id, log_event.max_message_id_); + read_history_on_server_impl(d, log_event.max_message_id_); break; } case LogEvent::HandlerType::ReadHistoryInSecretChat: { @@ -34188,14 +34392,40 @@ void MessagesManager::on_binlog_events(vector &&events) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; } - if (d->read_history_logevent_id.logevent_id != 0) { + if (d->read_history_logevent_ids[0].logevent_id != 0) { // we need only latest read history event - binlog_erase(G()->td_db()->get_binlog(), d->read_history_logevent_id.logevent_id); + binlog_erase(G()->td_db()->get_binlog(), d->read_history_logevent_ids[0].logevent_id); } - d->read_history_logevent_id.logevent_id = event.id_; + d->read_history_logevent_ids[0].logevent_id = event.id_; d->last_read_inbox_message_date = log_event.max_date_; - read_history_on_server_impl(dialog_id, MessageId()); + read_history_on_server_impl(d, MessageId()); + break; + } + case LogEvent::HandlerType::ReadMessageThreadHistoryOnServer: { + if (!G()->parameters().use_message_db) { + binlog_erase(G()->td_db()->get_binlog(), event.id_); + break; + } + + ReadMessageThreadHistoryOnServerLogEvent log_event; + log_event_parse(log_event, event.data_).ensure(); + + auto dialog_id = log_event.dialog_id_; + Dialog *d = get_dialog_force(dialog_id); + if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { + binlog_erase(G()->td_db()->get_binlog(), event.id_); + break; + } + auto top_thread_message_id = log_event.top_thread_message_id_; + if (d->read_history_logevent_ids[top_thread_message_id.get()].logevent_id != 0) { + // we need only latest read history event + binlog_erase(G()->td_db()->get_binlog(), + d->read_history_logevent_ids[top_thread_message_id.get()].logevent_id); + } + d->read_history_logevent_ids[top_thread_message_id.get()].logevent_id = event.id_; + + read_message_thread_history_on_server_impl(d, top_thread_message_id, log_event.max_message_id_); break; } case LogEvent::HandlerType::ReadMessageContentsOnServer: { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 1775e5ee2..46e53c7b9 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -654,7 +654,8 @@ class MessagesManager : public Actor { Status close_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT; - Status view_messages(DialogId dialog_id, const vector &message_ids, bool force_read) TD_WARN_UNUSED_RESULT; + Status view_messages(DialogId dialog_id, MessageId top_thread_message_id, const vector &message_ids, + bool force_read) TD_WARN_UNUSED_RESULT; Status open_message_content(FullMessageId full_message_id) TD_WARN_UNUSED_RESULT; @@ -1147,7 +1148,8 @@ class MessagesManager : public Actor { unique_ptr draft_message; LogeventIdWithGeneration save_draft_message_logevent_id; LogeventIdWithGeneration save_notification_settings_logevent_id; - LogeventIdWithGeneration read_history_logevent_id; + std::unordered_map read_history_logevent_ids; + std::unordered_set updated_read_history_message_ids; LogeventIdWithGeneration set_folder_id_logevent_id; FolderId folder_id; @@ -1592,9 +1594,10 @@ class MessagesManager : public Actor { class GetChannelDifferenceLogEvent; class GetDialogFromServerLogEvent; class ReadAllDialogMentionsOnServerLogEvent; - class ReadHistoryOnServerLogEvent; class ReadHistoryInSecretChatLogEvent; + class ReadHistoryOnServerLogEvent; class ReadMessageContentsOnServerLogEvent; + class ReadMessageThreadHistoryOnServerLogEvent; class ReorderPinnedDialogsOnServerLogEvent; class ResetAllNotificationSettingsOnServerLogEvent; class SaveDialogDraftMessageOnServerLogEvent; @@ -1603,9 +1606,9 @@ class MessagesManager : public Actor { class SendMessageLogEvent; class SendScreenshotTakenNotificationMessageLogEvent; class SetDialogFolderIdOnServerLogEvent; - class ToggleDialogIsPinnedOnServerLogEvent; - class ToggleDialogIsMarkedAsUnreadOnServerLogEvent; class ToggleDialogIsBlockedOnServerLogEvent; + class ToggleDialogIsMarkedAsUnreadOnServerLogEvent; + class ToggleDialogIsPinnedOnServerLogEvent; class UpdateDialogNotificationSettingsOnServerLogEvent; class UpdateScopeNotificationSettingsOnServerLogEvent; @@ -1935,9 +1938,16 @@ class MessagesManager : public Actor { void read_history_on_server(Dialog *d, MessageId max_message_id); - void read_history_on_server_impl(DialogId dialog_id, MessageId max_message_id); + void do_read_history_on_server(DialogId dialog_id); - void on_read_history_finished(DialogId dialog_id, uint64 generation); + void read_history_on_server_impl(Dialog *d, MessageId max_message_id); + + void read_message_thread_history_on_server_impl(Dialog *d, MessageId top_thread_message_id, MessageId max_message_id); + + void on_read_history_finished(DialogId dialog_id, MessageId top_thread_message_id, uint64 generation); + + void read_message_thread_history_on_server(Dialog *d, MessageId top_thread_message_id, MessageId max_message_id, + MessageId last_message_id); void read_secret_chat_outbox_inner(DialogId dialog_id, int32 up_to_date, int32 read_date); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index ff117cd77..b95007460 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5454,9 +5454,9 @@ void Td::on_request(uint64 id, const td_api::closeChat &request) { void Td::on_request(uint64 id, const td_api::viewMessages &request) { CHECK_IS_USER(); - answer_ok_query( - id, messages_manager_->view_messages( - DialogId(request.chat_id_), MessagesManager::get_message_ids(request.message_ids_), request.force_read_)); + answer_ok_query(id, messages_manager_->view_messages( + DialogId(request.chat_id_), MessageId(request.message_thread_id_), + MessagesManager::get_message_ids(request.message_ids_), request.force_read_)); } void Td::on_request(uint64 id, const td_api::openMessageContent &request) { diff --git a/td/telegram/TdDb.cpp b/td/telegram/TdDb.cpp index 2f1cf18d2..981d26a9f 100644 --- a/td/telegram/TdDb.cpp +++ b/td/telegram/TdDb.cpp @@ -113,6 +113,7 @@ Status init_binlog(Binlog &binlog, string path, BinlogKeyValue &binlog_p case LogEvent::HandlerType::SetDialogFolderIdOnServer: case LogEvent::HandlerType::DeleteScheduledMessagesFromServer: case LogEvent::HandlerType::ToggleDialogIsBlockedOnServer: + case LogEvent::HandlerType::ReadMessageThreadHistoryOnServer: events.to_messages_manager.push_back(event.clone()); break; case LogEvent::HandlerType::AddMessagePushNotification: diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index d8fa528e6..dbdd47865 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -3960,12 +3960,17 @@ class CliClient final : public Actor { } else if (op == "rrh") { auto hashtag = std::move(args); send_request(td_api::make_object(hashtag)); - } else if (op == "view") { + } else if (op == "view" || op == "viewt") { string chat_id; + string message_thread_id; string message_ids; std::tie(chat_id, message_ids) = split(args); + if (op == "viewt") { + std::tie(message_thread_id, message_ids) = split(message_ids); + } - send_request(td_api::make_object(as_chat_id(chat_id), as_message_ids(message_ids), true)); + send_request(td_api::make_object( + as_chat_id(chat_id), as_message_thread_id(message_thread_id), as_message_ids(message_ids), true)); } else if (op == "omc") { string chat_id; string message_id; diff --git a/td/telegram/logevent/LogEvent.h b/td/telegram/logevent/LogEvent.h index 6b843b1d1..378ceecad 100644 --- a/td/telegram/logevent/LogEvent.h +++ b/td/telegram/logevent/LogEvent.h @@ -97,6 +97,7 @@ class LogEvent { SetDialogFolderIdOnServer = 0x116, DeleteScheduledMessagesFromServer = 0x117, ToggleDialogIsBlockedOnServer = 0x118, + ReadMessageThreadHistoryOnServer = 0x119, GetChannelDifference = 0x140, AddMessagePushNotification = 0x200, EditMessagePushNotification = 0x201,