diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 09997644..c9a0fd5f 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -10301,9 +10301,8 @@ void MessagesManager::set_dialog_pinned_message_notification(Dialog *d, MessageI remove_message_notification_id(d, m, true, false); on_message_changed(d, m, false, "set_dialog_pinned_message_notification"); - } else if (d->mention_notification_group.group_id.is_valid()) { - // remove temporary notification - send_closure_later(G()->notification_manager(), &NotificationManager::remove_notification_by_message_id, + } else { + send_closure_later(G()->notification_manager(), &NotificationManager::remove_temporary_notification_by_message_id, d->mention_notification_group.group_id, old_message_id); } } @@ -10900,6 +10899,7 @@ void MessagesManager::remove_message_notification_id(Dialog *d, Message *m, bool << '/' << d->dialog_id << " from database, was_active = " << had_active_notification << ", is_permanent = " << is_permanent; delete_notification_id_to_message_id_correspondence(d, notification_id, m->message_id); + m->removed_notification_id = m->notification_id; m->notification_id = NotificationId(); if (d->pinned_message_notification_message_id == m->message_id && is_permanent) { remove_dialog_pinned_message_notification(d); // must be called after notification_id is removed @@ -10980,7 +10980,7 @@ void MessagesManager::do_fix_dialog_last_notification_id(DialogId dialog_id, boo CHECK(d != nullptr); auto &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group; VLOG(notifications) << "Receive " << result.ok().size() << " message notifications in " << group_info.group_id << '/' - << dialog_id; + << dialog_id << " from " << prev_last_notification_id; if (group_info.last_notification_id != prev_last_notification_id) { // last_notification_id was changed return; @@ -18355,7 +18355,7 @@ Result MessagesManager::get_messag } if (random_id != 0) { CHECK(dialog_id.get_type() == DialogType::SecretChat); - if (get_message_id_by_random_id(d, random_id, "need_message_push_notification").is_valid()) { + if (get_message_id_by_random_id(d, random_id, "get_message_push_notification_info").is_valid()) { return Status::Error(406, "Ignore notification about known secret message"); } } @@ -18611,12 +18611,38 @@ vector MessagesManager::get_message_notifications_from_database_fo for (auto &message : messages) { auto m = on_get_message_from_database(d->dialog_id, d, std::move(message), "get_message_notifications_from_database_force"); - if (m == nullptr || !m->notification_id.is_valid() || is_from_mention_notification_group(d, m) != from_mentions) { - // notification_id can be empty if it is deleted in memory, but not in the database + if (m == nullptr) { + VLOG(notifications) << "Receive from database a broken message"; continue; } - if (m->notification_id.get() <= group_info.max_removed_notification_id.get() || + auto notification_id = m->notification_id.is_valid() ? m->notification_id : m->removed_notification_id; + if (!notification_id.is_valid()) { + VLOG(ERROR) << "Can't find notification ID for " << m->message_id << " in " << d->dialog_id; + continue; + } + CHECK(m->message_id.is_valid()); + + bool is_correct = true; + if (notification_id.get() >= from_notification_id.get()) { + // possible if two messages has the same notification_id + LOG(ERROR) << "Have nonmonotoic notification ids: " << d->dialog_id << " " << m->message_id << " " + << notification_id << " " << from_message_id << " " << from_notification_id; + is_correct = false; + } else { + from_notification_id = notification_id; + is_found = true; + } + if (m->message_id.get() >= from_message_id.get()) { + LOG(ERROR) << "Have nonmonotoic message ids: " << d->dialog_id << " " << m->message_id << " " << notification_id + << " " << from_message_id << " " << from_notification_id; + is_correct = false; + } else { + from_message_id = m->message_id; + is_found = true; + } + + if (notification_id.get() <= group_info.max_removed_notification_id.get() || m->message_id.get() <= group_info.max_removed_message_id.get() || (!from_mentions && m->message_id.get() <= d->last_read_inbox_message_id.get())) { // if message still has notification_id, but it was removed via max_removed_notification_id, @@ -18626,37 +18652,33 @@ vector MessagesManager::get_message_notifications_from_database_fo break; } + if (!m->notification_id.is_valid()) { + // notification_id can be empty if it is deleted in memory, but not in the database + VLOG(notifications) << "Receive from database " << m->message_id << " with removed " + << m->removed_notification_id; + continue; + } + + if (is_from_mention_notification_group(d, m) != from_mentions) { + VLOG(notifications) << "Receive from database " << m->message_id << " with " << m->notification_id + << " from another group"; + continue; + } + if (!is_message_notification_active(d, m)) { CHECK(from_mentions); CHECK(!m->contains_unread_mention); + CHECK(m->message_id != d->pinned_message_notification_message_id); // skip read mentions continue; } - bool is_correct = true; - if (m->notification_id.get() >= from_notification_id.get()) { - // possible if two messages has the same notification_id - LOG(ERROR) << "Have nonmonotoic notification ids: " << d->dialog_id << " " << m->message_id << " " - << m->notification_id << " " << from_message_id << " " << from_notification_id; - is_correct = false; - } else { - from_notification_id = m->notification_id; - is_found = true; - } - if (m->message_id.get() >= from_message_id.get()) { - LOG(ERROR) << "Have nonmonotoic message ids: " << d->dialog_id << " " << m->message_id << " " - << m->notification_id << " " << from_message_id << " " << from_notification_id; - is_correct = false; - } else { - from_message_id = m->message_id; - is_found = true; - } - - if (is_correct && is_from_mention_notification_group(d, m) == from_mentions) { + if (is_correct) { // skip mention messages returned among unread messages res.emplace_back(m->notification_id, m->date, create_new_message_notification(m->message_id)); - } else if (!is_correct) { + } else { remove_message_notification_id(d, m, true, false); + on_message_changed(d, m, false, "get_message_notifications_from_database_force"); } } if (!res.empty() || !is_found) { @@ -18832,11 +18854,35 @@ void MessagesManager::on_get_message_notifications_from_database(DialogId dialog for (auto &message : messages) { auto m = on_get_message_from_database(dialog_id, d, std::move(message), "on_get_message_notifications_from_database"); - if (m == nullptr || !m->notification_id.is_valid() || is_from_mention_notification_group(d, m) != from_mentions) { + if (m == nullptr) { + VLOG(notifications) << "Receive from database a broken message"; continue; } - if (m->notification_id.get() <= group_info.max_removed_notification_id.get() || + auto notification_id = m->notification_id.is_valid() ? m->notification_id : m->removed_notification_id; + if (!notification_id.is_valid()) { + VLOG(ERROR) << "Can't find notification ID for " << m->message_id << " in " << d->dialog_id; + continue; + } + CHECK(m->message_id.is_valid()); + + bool is_correct = true; + if (from_notification_id.is_valid() && notification_id.get() >= from_notification_id.get()) { + LOG(ERROR) << "Receive " << m->message_id << "/" << notification_id << " after " << from_message_id << "/" + << from_notification_id; + is_correct = false; + } else { + from_notification_id = notification_id; + } + if (from_message_id.is_valid() && m->message_id.get() >= from_message_id.get()) { + LOG(ERROR) << "Receive " << m->message_id << "/" << notification_id << " after " << from_message_id << "/" + << from_notification_id; + is_correct = false; + } else { + from_message_id = m->message_id; + } + + if (notification_id.get() <= group_info.max_removed_notification_id.get() || m->message_id.get() <= group_info.max_removed_message_id.get() || (!from_mentions && m->message_id.get() <= d->last_read_inbox_message_id.get())) { // if message still has notification_id, but it was removed via max_removed_notification_id, @@ -18846,34 +18892,33 @@ void MessagesManager::on_get_message_notifications_from_database(DialogId dialog break; } + if (!m->notification_id.is_valid()) { + // notification_id can be empty if it is deleted in memory, but not in the database + VLOG(notifications) << "Receive from database " << m->message_id << " with removed " + << m->removed_notification_id; + continue; + } + + if (is_from_mention_notification_group(d, m) != from_mentions) { + VLOG(notifications) << "Receive from database " << m->message_id << " with " << m->notification_id + << " from another category"; + continue; + } + if (!is_message_notification_active(d, m)) { CHECK(from_mentions); CHECK(!m->contains_unread_mention); + CHECK(m->message_id != d->pinned_message_notification_message_id); // skip read mentions continue; } - bool is_correct = true; - if (from_notification_id.is_valid() && m->notification_id.get() >= from_notification_id.get()) { - LOG(ERROR) << "Receive " << m->message_id << "/" << m->notification_id << " after " << from_message_id << "/" - << from_notification_id; - is_correct = false; - } else { - from_notification_id = m->notification_id; - } - if (from_message_id.is_valid() && m->message_id.get() >= from_message_id.get()) { - LOG(ERROR) << "Receive " << m->message_id << "/" << m->notification_id << " after " << from_message_id << "/" - << from_notification_id; - is_correct = false; - } else { - from_message_id = m->message_id; - } - - if (is_correct && is_from_mention_notification_group(d, m) == from_mentions) { + if (is_correct) { // skip mention messages returned among unread messages res.emplace_back(m->notification_id, m->date, create_new_message_notification(m->message_id)); - } else if (!is_correct) { + } else { remove_message_notification_id(d, m, true, false); + on_message_changed(d, m, false, "on_get_message_notifications_from_database"); } } if (!res.empty() || !from_notification_id.is_valid() || static_cast(limit) > messages.size()) { @@ -18935,6 +18980,39 @@ void MessagesManager::remove_message_notification(DialogId dialog_id, Notificati } } +void MessagesManager::remove_message_notifications_by_message_ids(DialogId dialog_id, + const vector &message_ids) { + VLOG(notifications) << "Trying to remove notification about " << message_ids << " in " << dialog_id; + Dialog *d = get_dialog_force(dialog_id); + if (d == nullptr) { + return; + } + + bool need_update_dialog_pos = false; + vector deleted_message_ids; + for (auto message_id : message_ids) { + // can't remove just notification_id, because total_count will stay wrong after restart + // auto m = get_message_force(d, message_id, "remove_message_notifications_by_message_ids"); + // if (m != nullptr) { + // remove_message_notification_id(d, m, true, false); + // on_message_changed(d, m, false, "remove_message_notifications_by_message_ids"); + // } + + auto m = + delete_message(d, message_id, true, &need_update_dialog_pos, "remove_message_notifications_by_message_ids"); + if (m == nullptr) { + LOG(INFO) << "Can't delete " << message_id << " because it is not found"; + continue; + } + deleted_message_ids.push_back(m->message_id.get()); + } + + if (need_update_dialog_pos) { + send_update_chat_last_message(d, "remove_message_notifications_by_message_ids"); + } + send_update_delete_messages(dialog_id, std::move(deleted_message_ids), true, false); +} + void MessagesManager::do_remove_message_notification(DialogId dialog_id, bool from_mentions, NotificationId notification_id, vector result) { if (result.empty()) { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index d21a9196..455cf94f 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -721,6 +721,8 @@ class MessagesManager : public Actor { void remove_message_notification(DialogId dialog_id, NotificationGroupId group_id, NotificationId notification_id); + void remove_message_notifications_by_message_ids(DialogId dialog_id, const vector &message_ids); + void remove_message_notifications(DialogId dialog_id, NotificationGroupId group_id, NotificationId max_notification_id, MessageId max_message_id); @@ -865,6 +867,7 @@ class MessagesManager : public Actor { bool from_database = false; NotificationId notification_id; + NotificationId removed_notification_id; int32 views = 0; diff --git a/td/telegram/NotificationManager.cpp b/td/telegram/NotificationManager.cpp index 2d4839b2..91960445 100644 --- a/td/telegram/NotificationManager.cpp +++ b/td/telegram/NotificationManager.cpp @@ -1851,9 +1851,13 @@ void NotificationManager::remove_notification(NotificationGroupId group_id, Noti promise.set_value(Unit()); } -void NotificationManager::remove_notification_by_message_id(NotificationGroupId group_id, MessageId message_id) { +void NotificationManager::remove_temporary_notification_by_message_id(NotificationGroupId group_id, + MessageId message_id) { + if (!group_id.is_valid()) { + return; + } + VLOG(notifications) << "Remove notification for " << message_id << " in " << group_id; - CHECK(group_id.is_valid()); CHECK(message_id.is_valid()); auto group_it = get_group(group_id); @@ -2989,6 +2993,26 @@ Status NotificationManager::process_push_notification_payload(string payload, Pr return Status::OK(); } + if (loc_key == "MESSAGE_DELETED") { + if (dialog_id.get_type() == DialogType::SecretChat) { + return Status::Error("Receive MESSAGE_DELETED in a secret chat"); + } + TRY_RESULT(server_message_ids_str, get_json_object_string_field(custom, "messages", false)); + auto server_message_ids = full_split(server_message_ids_str, ','); + vector message_ids; + for (const auto &server_message_id_str : server_message_ids) { + TRY_RESULT(server_message_id_int, to_integer_safe(server_message_id_str)); + ServerMessageId server_message_id(server_message_id_int); + if (!server_message_id.is_valid()) { + return Status::Error("Receive invalid message_id"); + } + message_ids.push_back(MessageId(server_message_id)); + } + td_->messages_manager_->remove_message_notifications_by_message_ids(dialog_id, message_ids); + promise.set_value(Unit()); + return Status::OK(); + } + TRY_RESULT(msg_id, get_json_object_int_field(custom, "msg_id")); ServerMessageId server_message_id(msg_id); if (server_message_id != ServerMessageId() && !server_message_id.is_valid()) { @@ -3450,10 +3474,9 @@ void NotificationManager::after_get_difference_impl() { VLOG(notifications) << "After get difference"; vector to_remove_temporary_notifications_group_ids; - size_t cur_pos = 0; - for (auto it = groups_.begin(); it != groups_.end() && cur_pos < max_notification_group_count_; ++it, cur_pos++) { - const auto &group_key = it->first; - const auto &group = it->second; + for (auto &group_it : groups_) { + const auto &group_key = group_it.first; + const auto &group = group_it.second; if (running_get_chat_difference_.count(group_key.group_id.get()) == 0 && get_temporary_notification_total_count(group) > 0) { to_remove_temporary_notifications_group_ids.push_back(group_key.group_id); diff --git a/td/telegram/NotificationManager.h b/td/telegram/NotificationManager.h index 392b1b76..eb3c7c40 100644 --- a/td/telegram/NotificationManager.h +++ b/td/telegram/NotificationManager.h @@ -73,7 +73,7 @@ class NotificationManager : public Actor { void remove_notification(NotificationGroupId group_id, NotificationId notification_id, bool is_permanent, bool force_update, Promise &&promise); - void remove_notification_by_message_id(NotificationGroupId group_id, MessageId message_id); + void remove_temporary_notification_by_message_id(NotificationGroupId group_id, MessageId message_id); void remove_notification_group(NotificationGroupId group_id, NotificationId max_notification_id, MessageId max_message_id, int32 new_total_count, bool force_update,