From 1e660fc2a2d83da301ad52aa917dd35f64e64f8d Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 30 Sep 2021 10:04:55 +0400 Subject: [PATCH] Allocate 64 bits for message ids. --- Telegram/CMakeLists.txt | 1 + Telegram/SourceFiles/apiwrap.cpp | 10 +- .../boxes/background_preview_box.cpp | 3 +- Telegram/SourceFiles/boxes/share_box.cpp | 5 +- .../calls/calls_box_controller.cpp | 2 +- .../SourceFiles/chat_helpers/bot_command.h | 2 +- Telegram/SourceFiles/data/data_drafts.cpp | 15 ++ Telegram/SourceFiles/data/data_drafts.h | 17 +- Telegram/SourceFiles/data/data_histories.cpp | 35 ++-- Telegram/SourceFiles/data/data_msg_id.h | 187 ++++++++++++++++++ .../data/data_scheduled_messages.cpp | 2 +- Telegram/SourceFiles/data/data_session.cpp | 4 +- .../SourceFiles/data/data_shared_media.cpp | 2 +- Telegram/SourceFiles/data/data_types.h | 79 +------- Telegram/SourceFiles/history/history.cpp | 12 +- .../SourceFiles/history/history_message.cpp | 19 +- .../SourceFiles/history/history_widget.cpp | 6 +- .../view/history_view_pinned_section.cpp | 2 +- .../view/history_view_pinned_section.h | 2 +- .../view/history_view_pinned_tracker.cpp | 2 +- .../view/history_view_pinned_tracker.h | 2 +- .../history/view/media/history_view_media.cpp | 2 +- .../info/media/info_media_list_widget.cpp | 2 +- .../info/media/info_media_list_widget.h | 2 +- .../main/main_session_settings.cpp | 27 ++- .../settings/settings_privacy_controllers.cpp | 4 +- .../details/storage_settings_scheme.cpp | 4 +- .../SourceFiles/storage/storage_account.cpp | 44 +++-- .../support/support_autocomplete.cpp | 5 +- 29 files changed, 337 insertions(+), 162 deletions(-) create mode 100644 Telegram/SourceFiles/data/data_msg_id.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 4a48af07e..ec4ea2a6f 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -415,6 +415,7 @@ PRIVATE data/data_media_types.h data/data_messages.cpp data/data_messages.h + data/data_msg_id.h data/data_notify_settings.cpp data/data_notify_settings.h data/data_peer.cpp diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 2cf8b0e8d..0f9f034b5 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -662,8 +662,8 @@ QString ApiWrap::exportDirectMessageLink( const auto fallback = [&] { auto linkChannel = channel; auto linkItemId = item->id; - auto linkCommentId = 0; - auto linkThreadId = 0; + auto linkCommentId = MsgId(); + auto linkThreadId = MsgId(); if (inRepliesContext) { if (const auto rootId = item->replyToTop()) { const auto root = item->history()->owner().message( @@ -693,11 +693,11 @@ QString ApiWrap::exportDirectMessageLink( : "c/" + QString::number(peerToChannel(linkChannel->id).bare); const auto query = base + '/' - + QString::number(linkItemId) + + QString::number(linkItemId.bare) + (linkCommentId - ? "?comment=" + QString::number(linkCommentId) + ? "?comment=" + QString::number(linkCommentId.bare) : linkThreadId - ? "?thread=" + QString::number(linkThreadId) + ? "?thread=" + QString::number(linkThreadId.bare) : ""); if (linkChannel->hasUsername() && !linkChannel->isMegagroup() diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp index 173c27b40..441197117 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp @@ -288,7 +288,6 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const { bool out) { Expects(history->peer->isUser()); - static auto id = ServerMaxMsgId + (ServerMaxMsgId / 3); const auto flags = MessageFlag::FakeHistoryItem | MessageFlag::HasFromId | (out ? MessageFlag::Outgoing : MessageFlag(0)); @@ -296,7 +295,7 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const { const auto viaBotId = UserId(); const auto groupedId = uint64(); const auto item = history->makeMessage( - ++id, + history->owner().nextNonHistoryEntryId(), flags, replyTo, viaBotId, diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp index 2fd76bd12..9fbbe4cbd 100644 --- a/Telegram/SourceFiles/boxes/share_box.cpp +++ b/Telegram/SourceFiles/boxes/share_box.cpp @@ -1113,7 +1113,7 @@ QString AppendShareGameScoreUrl( auto channelAccessHash = uint64(channel ? channel->access : 0); shareHashDataInts[0] = session->userId().bare; shareHashDataInts[1] = fullId.channel.bare; - shareHashDataInts[2] = fullId.msg; + shareHashDataInts[2] = uint64(fullId.msg.bare); shareHashDataInts[3] = channelAccessHash; // Count SHA1() of data. @@ -1200,7 +1200,6 @@ void ShareGameScoreByHash( //} if (((hashDataInts[1] >> 40) != 0) - || ((hashDataInts[2] >> 32) != 0) || (!hashDataInts[1] && channelAccessHash)) { // If there is no channel id, there should be no channel access_hash. Ui::show(Box(tr::lng_share_wrong_user(tr::now))); @@ -1208,7 +1207,7 @@ void ShareGameScoreByHash( } auto channelId = ChannelId(hashDataInts[1]); - auto msgId = MsgId(hashDataInts[2]); + auto msgId = MsgId(int64(hashDataInts[2])); if (const auto item = session->data().message(channelId, msgId)) { FastShareMessage(item); } else { diff --git a/Telegram/SourceFiles/calls/calls_box_controller.cpp b/Telegram/SourceFiles/calls/calls_box_controller.cpp index 4dd8e6351..fac2508ce 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.cpp +++ b/Telegram/SourceFiles/calls/calls_box_controller.cpp @@ -141,7 +141,7 @@ private: }; BoxController::Row::Row(not_null item) -: PeerListRow(item->history()->peer, item->id) +: PeerListRow(item->history()->peer, item->id.bare) , _items(1, item) , _date(ItemDateTime(item).date()) , _type(ComputeType(item)) diff --git a/Telegram/SourceFiles/chat_helpers/bot_command.h b/Telegram/SourceFiles/chat_helpers/bot_command.h index 79f79f9bb..d5e0c9511 100644 --- a/Telegram/SourceFiles/chat_helpers/bot_command.h +++ b/Telegram/SourceFiles/chat_helpers/bot_command.h @@ -16,7 +16,7 @@ struct SendCommandRequest { not_null peer; QString command; FullMsgId context; - int replyTo = 0; + MsgId replyTo = 0; }; [[nodiscard]] QString WrapCommandInChat( diff --git a/Telegram/SourceFiles/data/data_drafts.cpp b/Telegram/SourceFiles/data/data_drafts.cpp index eaeb3ec21..88d614f0b 100644 --- a/Telegram/SourceFiles/data/data_drafts.cpp +++ b/Telegram/SourceFiles/data/data_drafts.cpp @@ -19,6 +19,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Data { +DraftKey DraftKey::FromSerializedOld(int32 value) { + return !value + ? DraftKey::None() + : (value == kLocalDraftIndex + kEditDraftShiftOld) + ? DraftKey::LocalEdit() + : (value == kScheduledDraftIndex + kEditDraftShiftOld) + ? DraftKey::ScheduledEdit() + : (value > 0 && value < 0x4000'0000) + ? DraftKey::Replies(int64(value)) + : (value > kEditDraftShiftOld + && value < kEditDraftShiftOld + 0x4000'000) + ? DraftKey::RepliesEdit(int64(value - kEditDraftShiftOld)) + : DraftKey::None(); +} + Draft::Draft( const TextWithTags &textWithTags, MsgId msgId, diff --git a/Telegram/SourceFiles/data/data_drafts.h b/Telegram/SourceFiles/data/data_drafts.h index 7641b1eea..533c74167 100644 --- a/Telegram/SourceFiles/data/data_drafts.h +++ b/Telegram/SourceFiles/data/data_drafts.h @@ -75,19 +75,21 @@ public: return kScheduledDraftIndex + kEditDraftShift; } [[nodiscard]] static DraftKey Replies(MsgId rootId) { - return rootId; + return rootId.bare; } [[nodiscard]] static DraftKey RepliesEdit(MsgId rootId) { - return rootId + kEditDraftShift; + return rootId.bare + kEditDraftShift; } - [[nodiscard]] static DraftKey FromSerialized(int32 value) { + [[nodiscard]] static DraftKey FromSerialized(qint64 value) { return value; } - [[nodiscard]] int32 serialize() const { + [[nodiscard]] qint64 serialize() const { return _value; } + [[nodiscard]] static DraftKey FromSerializedOld(int32 value); + inline bool operator<(const DraftKey &other) const { return _value < other._value; } @@ -111,15 +113,16 @@ public: } private: - DraftKey(int value) : _value(value) { + DraftKey(int64 value) : _value(value) { } static constexpr auto kLocalDraftIndex = -1; static constexpr auto kCloudDraftIndex = -2; static constexpr auto kScheduledDraftIndex = -3; - static constexpr auto kEditDraftShift = ServerMaxMsgId; + static constexpr auto kEditDraftShift = ServerMaxMsgId.bare; + static constexpr auto kEditDraftShiftOld = 0x3FFF'FFFF; - int _value = 0; + int64 _value = 0; }; diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 04e7fb811..ac61bd8f7 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -72,13 +72,13 @@ void Histories::readInbox(not_null history) { if (history->lastServerMessageKnown()) { const auto last = history->lastServerMessage(); DEBUG_LOG(("Reading: last known, reading till %1." - ).arg(last ? last->id : 0)); + ).arg(last ? last->id.bare : 0)); readInboxTill(history, last ? last->id : 0); return; } else if (history->loadedAtBottom()) { if (const auto lastId = history->maxMsgId()) { DEBUG_LOG(("Reading: loaded at bottom, maxMsgId %1." - ).arg(lastId)); + ).arg(lastId.bare)); readInboxTill(history, lastId); return; } else if (history->loadedAtTop()) { @@ -93,7 +93,7 @@ void Histories::readInbox(not_null history) { const auto last = history->lastServerMessage(); DEBUG_LOG(("Reading: got entry, reading till %1." - ).arg(last ? last->id : 0)); + ).arg(last ? last->id.bare : 0)); readInboxTill(history, last ? last->id : 0); }); } @@ -147,7 +147,7 @@ void Histories::readInboxTill( Expects(IsServerMsgId(tillId) || (!tillId && !force)); DEBUG_LOG(("Reading: readInboxTill %1, force %2." - ).arg(tillId + ).arg(tillId.bare ).arg(Logs::b(force))); const auto syncGuard = gsl::finally([&] { @@ -156,8 +156,8 @@ void Histories::readInboxTill( if (history->unreadCount() > 0) { if (const auto last = history->lastServerMessage()) { DEBUG_LOG(("Reading: checking last %1 and %2." - ).arg(last->id - ).arg(tillId)); + ).arg(last->id.bare + ).arg(tillId.bare)); if (last->id == tillId) { DEBUG_LOG(("Reading: locally marked as read.")); history->setUnreadCount(0); @@ -180,11 +180,11 @@ void Histories::readInboxTill( const auto maybeState = lookup(history); if (maybeState && maybeState->sentReadTill >= tillId) { DEBUG_LOG(("Reading: readInboxTill finish 3 with %1." - ).arg(maybeState->sentReadTill)); + ).arg(maybeState->sentReadTill.bare)); return; } else if (maybeState && maybeState->willReadTill >= tillId) { DEBUG_LOG(("Reading: readInboxTill finish 4 with %1 and force %2." - ).arg(maybeState->sentReadTill + ).arg(maybeState->sentReadTill.bare ).arg(Logs::b(force))); if (force) { sendPendingReadInbox(history); @@ -200,7 +200,7 @@ void Histories::readInboxTill( && history->unreadCountKnown() && *stillUnread == history->unreadCount()) { DEBUG_LOG(("Reading: count didn't change so just update till %1" - ).arg(tillId)); + ).arg(tillId.bare)); history->setInboxReadTill(tillId); return; } @@ -208,7 +208,7 @@ void Histories::readInboxTill( state.willReadTill = tillId; if (force || !stillUnread || !*stillUnread) { DEBUG_LOG(("Reading: will read till %1 with still unread %2" - ).arg(tillId + ).arg(tillId.bare ).arg(stillUnread.value_or(-666))); state.willReadWhen = 0; sendReadRequests(); @@ -216,17 +216,18 @@ void Histories::readInboxTill( return; } } else if (!state.willReadWhen) { - DEBUG_LOG(("Reading: will read till %1 with postponed").arg(tillId)); + DEBUG_LOG(("Reading: will read till %1 with postponed" + ).arg(tillId.bare)); state.willReadWhen = crl::now() + kReadRequestTimeout; if (!_readRequestsTimer.isActive()) { _readRequestsTimer.callOnce(kReadRequestTimeout); } } else { DEBUG_LOG(("Reading: will read till %1 postponed already" - ).arg(tillId)); + ).arg(tillId.bare)); } DEBUG_LOG(("Reading: marking now with till %1 and still %2" - ).arg(tillId + ).arg(tillId.bare ).arg(*stillUnread)); history->setInboxReadTill(tillId); history->setUnreadCount(*stillUnread); @@ -440,7 +441,7 @@ void Histories::requestFakeChatListMessage( void Histories::sendPendingReadInbox(not_null history) { if (const auto state = lookup(history)) { DEBUG_LOG(("Reading: send pending now with till %1 and when %2" - ).arg(state->willReadTill + ).arg(state->willReadTill.bare ).arg(state->willReadWhen)); if (state->willReadTill && state->willReadWhen) { state->willReadWhen = 0; @@ -462,7 +463,7 @@ void Histories::sendReadRequests() { continue; } else if (state.willReadWhen <= now) { DEBUG_LOG(("Reading: sending with till %1." - ).arg(state.willReadTill)); + ).arg(state.willReadTill.bare)); sendReadRequest(history, state); } else if (!next || *next > state.willReadWhen) { DEBUG_LOG(("Reading: scheduling for later send.")); @@ -483,10 +484,10 @@ void Histories::sendReadRequest(not_null history, State &state) { state.willReadWhen = 0; state.sentReadDone = false; DEBUG_LOG(("Reading: sending request now with till %1." - ).arg(tillId)); + ).arg(tillId.bare)); sendRequest(history, RequestType::ReadInbox, [=](Fn finish) { DEBUG_LOG(("Reading: sending request invoked with till %1." - ).arg(tillId)); + ).arg(tillId.bare)); const auto finished = [=] { const auto state = lookup(history); Assert(state != nullptr); diff --git a/Telegram/SourceFiles/data/data_msg_id.h b/Telegram/SourceFiles/data/data_msg_id.h new file mode 100644 index 000000000..9d53cb37d --- /dev/null +++ b/Telegram/SourceFiles/data/data_msg_id.h @@ -0,0 +1,187 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "data/data_peer_id.h" + +struct MsgId { + constexpr MsgId() noexcept = default; + constexpr MsgId(int64 value) noexcept : bare(value) { + } + + [[nodiscard]] constexpr explicit operator bool() const noexcept { + return (bare != 0); + } + [[nodiscard]] constexpr bool operator!() const noexcept { + return !bare; + } + [[nodiscard]] constexpr MsgId operator-() const noexcept { + return -bare; + } + constexpr MsgId operator++() noexcept { + return ++bare; + } + constexpr MsgId operator++(int) noexcept { + return bare++; + } + constexpr MsgId operator--() noexcept { + return --bare; + } + constexpr MsgId operator--(int) noexcept { + return bare--; + } + + int64 bare = 0; +}; + +Q_DECLARE_METATYPE(MsgId); + +[[nodiscard]] inline constexpr MsgId operator+(MsgId a, MsgId b) noexcept { + return MsgId(a.bare + b.bare); +} + +[[nodiscard]] inline constexpr MsgId operator-(MsgId a, MsgId b) noexcept { + return MsgId(a.bare - b.bare); +} + +[[nodiscard]] inline constexpr bool operator==(MsgId a, MsgId b) noexcept { + return (a.bare == b.bare); +} + +[[nodiscard]] inline constexpr bool operator!=(MsgId a, MsgId b) noexcept { + return (a.bare != b.bare); +} + +[[nodiscard]] inline constexpr bool operator<(MsgId a, MsgId b) noexcept { + return (a.bare < b.bare); +} + +[[nodiscard]] inline constexpr bool operator>(MsgId a, MsgId b) noexcept { + return (a.bare > b.bare); +} + +[[nodiscard]] inline constexpr bool operator<=(MsgId a, MsgId b) noexcept { + return (a.bare <= b.bare); +} + +[[nodiscard]] inline constexpr bool operator>=(MsgId a, MsgId b) noexcept { + return (a.bare >= b.bare); +} + +constexpr auto StartClientMsgId = MsgId(-0x7FFFFFFF); +constexpr auto EndClientMsgId = MsgId(-0x40000000); +constexpr auto ShowAtTheEndMsgId = MsgId(-0x40000000); +constexpr auto SwitchAtTopMsgId = MsgId(-0x3FFFFFFF); +constexpr auto ShowAtProfileMsgId = MsgId(-0x3FFFFFFE); +constexpr auto ShowAndStartBotMsgId = MsgId(-0x3FFFFFFD); +constexpr auto ShowAtGameShareMsgId = MsgId(-0x3FFFFFFC); +constexpr auto ShowForChooseMessagesMsgId = MsgId(-0x3FFFFFFB); +constexpr auto ServerMaxMsgId = MsgId(1LL << 56); +constexpr auto ShowAtUnreadMsgId = MsgId(0); + +[[nodiscard]] constexpr inline bool IsClientMsgId(MsgId id) noexcept { + return (id >= StartClientMsgId && id < EndClientMsgId); +} + +[[nodiscard]] constexpr inline bool IsServerMsgId(MsgId id) noexcept { + return (id > 0 && id < ServerMaxMsgId); +} + +struct MsgRange { + constexpr MsgRange() noexcept = default; + constexpr MsgRange(MsgId from, MsgId till) noexcept + : from(from) + , till(till) { + } + + MsgId from = 0; + MsgId till = 0; +}; + +[[nodiscard]] inline constexpr bool operator==( + MsgRange a, + MsgRange b) noexcept { + return (a.from == b.from) && (a.till == b.till); +} + +[[nodiscard]] inline constexpr bool operator!=( + MsgRange a, + MsgRange b) noexcept { + return !(a == b); +} + +struct FullMsgId { + constexpr FullMsgId() noexcept = default; + constexpr FullMsgId(ChannelId channel, MsgId msg) noexcept + : channel(channel), msg(msg) { + } + + constexpr explicit operator bool() const noexcept { + return msg != 0; + } + constexpr bool operator!() const noexcept { + return msg == 0; + } + + ChannelId channel = NoChannel; + MsgId msg = 0; +}; + +[[nodiscard]] inline constexpr bool operator<( + const FullMsgId &a, + const FullMsgId &b) noexcept { + if (a.channel < b.channel) { + return true; + } else if (a.channel > b.channel) { + return false; + } + return a.msg < b.msg; +} + +[[nodiscard]] inline constexpr bool operator>( + const FullMsgId &a, + const FullMsgId &b) noexcept { + return b < a; +} + +[[nodiscard]] inline constexpr bool operator<=( + const FullMsgId &a, + const FullMsgId &b) noexcept { + return !(b < a); +} + +[[nodiscard]] inline constexpr bool operator>=( + const FullMsgId &a, + const FullMsgId &b) noexcept { + return !(a < b); +} + +[[nodiscard]] inline constexpr bool operator==( + const FullMsgId &a, + const FullMsgId &b) noexcept { + return (a.channel == b.channel) && (a.msg == b.msg); +} + +[[nodiscard]] inline constexpr bool operator!=( + const FullMsgId &a, + const FullMsgId &b) noexcept { + return !(a == b); +} + +Q_DECLARE_METATYPE(FullMsgId); + +namespace std { + +template <> +struct hash : private hash { + size_t operator()(MsgId value) const noexcept { + return hash::operator()(value.bare); + } +}; + +} // namespace std diff --git a/Telegram/SourceFiles/data/data_scheduled_messages.cpp b/Telegram/SourceFiles/data/data_scheduled_messages.cpp index 756cede9b..ba5cb3a12 100644 --- a/Telegram/SourceFiles/data/data_scheduled_messages.cpp +++ b/Telegram/SourceFiles/data/data_scheduled_messages.cpp @@ -546,7 +546,7 @@ uint64 ScheduledMessages::countListHash(const List &list) const { }) | ranges::views::reverse; for (const auto &item : serverside) { const auto j = list.idByItem.find(item.get()); - HashUpdate(hash, j->second); + HashUpdate(hash, j->second.bare); if (const auto edited = item->Get()) { HashUpdate(hash, edited->date); } else { diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 5078d8728..3402ff998 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1838,8 +1838,8 @@ void Session::processMessages( continue; } } - const auto id = IdFromMessage(message); - indices.emplace((uint64(uint32(id)) << 32) | uint64(i), i); + const auto id = IdFromMessage(message); // Only 32 bit values here. + indices.emplace((uint64(uint32(id.bare)) << 32) | uint64(i), i); } for (const auto &[position, index] : indices) { addNewMessage( diff --git a/Telegram/SourceFiles/data/data_shared_media.cpp b/Telegram/SourceFiles/data/data_shared_media.cpp index 75b6299c0..e6afc073f 100644 --- a/Telegram/SourceFiles/data/data_shared_media.cpp +++ b/Telegram/SourceFiles/data/data_shared_media.cpp @@ -366,7 +366,7 @@ std::optional SharedMediaWithLastSlice::indexOf(Value value) const { : QString("-")); if (const auto msgId = std::get_if(&value)) { info.push_back("value:" + QString::number(msgId->channel.bare)); - info.push_back(QString::number(msgId->msg)); + info.push_back(QString::number(msgId->msg.bare)); const auto index = _slice.indexOf(*std::get_if(&value)); info.push_back("index:" + (index ? QString::number(*index) diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h index dc257df8e..5984ae624 100644 --- a/Telegram/SourceFiles/data/data_types.h +++ b/Telegram/SourceFiles/data/data_types.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/value_ordering.h" #include "ui/text/text.h" // For QFIXED_MAX #include "data/data_peer_id.h" +#include "data/data_msg_id.h" class HistoryItem; using HistoryItemsList = std::vector>; @@ -100,80 +101,6 @@ class Folder; using FolderId = int32; using FilterId = int32; -using MsgId = int32; -constexpr auto StartClientMsgId = MsgId(-0x7FFFFFFF); -constexpr auto EndClientMsgId = MsgId(-0x40000000); -constexpr auto ShowAtTheEndMsgId = MsgId(-0x40000000); -constexpr auto SwitchAtTopMsgId = MsgId(-0x3FFFFFFF); -constexpr auto ShowAtProfileMsgId = MsgId(-0x3FFFFFFE); -constexpr auto ShowAndStartBotMsgId = MsgId(-0x3FFFFFFD); -constexpr auto ShowAtGameShareMsgId = MsgId(-0x3FFFFFFC); -constexpr auto ShowForChooseMessagesMsgId = MsgId(-0x3FFFFFFB); -constexpr auto ServerMaxMsgId = MsgId(0x3FFFFFFF); -constexpr auto ShowAtUnreadMsgId = MsgId(0); -constexpr inline bool IsClientMsgId(MsgId id) { - return (id >= StartClientMsgId && id < EndClientMsgId); -} -constexpr inline bool IsServerMsgId(MsgId id) { - return (id > 0 && id < ServerMaxMsgId); -} - -struct MsgRange { - MsgRange() = default; - MsgRange(MsgId from, MsgId till) : from(from), till(till) { - } - - MsgId from = 0; - MsgId till = 0; -}; -inline bool operator==(const MsgRange &a, const MsgRange &b) { - return (a.from == b.from) && (a.till == b.till); -} -inline bool operator!=(const MsgRange &a, const MsgRange &b) { - return !(a == b); -} - -struct FullMsgId { - constexpr FullMsgId() = default; - constexpr FullMsgId(ChannelId channel, MsgId msg) - : channel(channel), msg(msg) { - } - - explicit operator bool() const { - return msg != 0; - } - - - inline constexpr bool operator<(const FullMsgId &other) const { - if (channel < other.channel) { - return true; - } else if (channel > other.channel) { - return false; - } - return msg < other.msg; - } - inline constexpr bool operator>(const FullMsgId &other) const { - return other < *this; - } - inline constexpr bool operator<=(const FullMsgId &other) const { - return !(other < *this); - } - inline constexpr bool operator>=(const FullMsgId &other) const { - return !(*this < other); - } - inline constexpr bool operator==(const FullMsgId &other) const { - return (channel == other.channel) && (msg == other.msg); - } - inline constexpr bool operator!=(const FullMsgId &other) const { - return !(*this == other); - } - - ChannelId channel = NoChannel; - MsgId msg = 0; - -}; - -Q_DECLARE_METATYPE(FullMsgId); using MessageIdsList = std::vector; @@ -182,6 +109,10 @@ MTPDmessage::Flags FlagsFromMessage(const MTPmessage &message); MsgId IdFromMessage(const MTPmessage &message); TimeId DateFromMessage(const MTPmessage &message); +[[nodiscard]] inline MTPint MTP_int(MsgId id) noexcept { + return MTP_int(id.bare); +} + class DocumentData; class PhotoData; struct WebPageData; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index b2bba99d8..b77562154 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1173,7 +1173,7 @@ HistoryItem *History::latestSendingMessage() const { }); const auto i = ranges::max_element(sending, ranges::less(), []( not_null item) { - return uint64(item->date()) << 32 | uint32(item->id); + return std::pair(item->date(), item->id.bare); }); return (i == sending.end()) ? nullptr : i->get(); } @@ -1466,7 +1466,7 @@ bool History::readInboxTillNeedsRequest(MsgId tillId) { } DEBUG_LOG(("Reading: readInboxTillNeedsRequest is_server %1, before %2." ).arg(Logs::b(IsServerMsgId(tillId)) - ).arg(_inboxReadBefore.value_or(-666))); + ).arg(_inboxReadBefore.value_or(-666).bare)); return IsServerMsgId(tillId) && (_inboxReadBefore.value_or(1) <= tillId); } @@ -1492,9 +1492,9 @@ std::optional History::countStillUnreadLocal(MsgId readTillId) const { if (_inboxReadBefore) { const auto before = *_inboxReadBefore; DEBUG_LOG(("Reading: check before %1 with min %2 and max %3." - ).arg(before - ).arg(minMsgId() - ).arg(maxMsgId())); + ).arg(before.bare + ).arg(minMsgId().bare + ).arg(maxMsgId().bare)); if (minMsgId() <= before && maxMsgId() >= readTillId) { auto result = 0; for (const auto &block : blocks) { @@ -1520,7 +1520,7 @@ std::optional History::countStillUnreadLocal(MsgId readTillId) const { } const auto minimalServerId = minMsgId(); DEBUG_LOG(("Reading: check at end loaded from %1 loaded %2 - %3").arg( - QString::number(minimalServerId), + QString::number(minimalServerId.bare), Logs::b(loadedAtBottom()), Logs::b(loadedAtTop()))); if (!loadedAtBottom() diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 19b9569f9..16df90221 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -477,7 +477,7 @@ HistoryMessage::HistoryMessage( } config.replyTo = data.vreply_to_msg_id().v; config.replyToTop = data.vreply_to_top_id().value_or( - config.replyTo); + data.vreply_to_msg_id().v); }); } config.viaBotId = data.vvia_bot_id().value_or_empty(); @@ -527,7 +527,7 @@ HistoryMessage::HistoryMessage( if (!peer || peer == history->peer->id) { config.replyTo = data.vreply_to_msg_id().v; config.replyToTop = data.vreply_to_top_id().value_or( - config.replyTo); + data.vreply_to_msg_id().v); } }); } @@ -820,7 +820,7 @@ void HistoryMessage::setRepliesInboxReadTill( MsgId readTillId, std::optional unreadCount) { if (const auto views = Get()) { - const auto newReadTillId = std::max(readTillId, 1); + const auto newReadTillId = std::max(readTillId.bare, int64(1)); const auto ignore = (newReadTillId < views->repliesInboxReadTillId); if (ignore) { return; @@ -870,7 +870,7 @@ MsgId HistoryMessage::repliesOutboxReadTill() const { void HistoryMessage::setRepliesOutboxReadTill(MsgId readTillId) { if (const auto views = Get()) { - const auto newReadTillId = std::max(readTillId, 1); + const auto newReadTillId = std::max(readTillId.bare, int64(1)); if (newReadTillId > views->repliesOutboxReadTillId) { views->repliesOutboxReadTillId = newReadTillId; if (!repliesAreComments()) { @@ -1747,10 +1747,15 @@ void HistoryMessage::setReplies(const MTPMessageReplies &data) { const auto channelId = ChannelId( data.vchannel_id().value_or_empty()); const auto readTillId = data.vread_max_id() - ? std::max( - { views->repliesInboxReadTillId, data.vread_max_id()->v, 1 }) + ? std::max({ + views->repliesInboxReadTillId.bare, + int64(data.vread_max_id()->v), + int64(1), + }) : views->repliesInboxReadTillId; - const auto maxId = data.vmax_id().value_or(views->repliesMaxId); + const auto maxId = data.vmax_id() + ? data.vmax_id()->v + : views->repliesMaxId; const auto countsChanged = (views->replies.count != count) || (views->repliesInboxReadTillId != readTillId) || (views->repliesMaxId != maxId); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index c2b22980b..d2a291cca 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1172,7 +1172,7 @@ void HistoryWidget::checkNextHighlight() { return msgId; } } - return 0; + return MsgId(); }(); if (!nextHighlight) { return; @@ -2844,7 +2844,7 @@ void HistoryWidget::firstLoadMessages() { } auto from = _history; - auto offsetId = 0; + auto offsetId = MsgId(); auto offset = 0; auto loadCount = kMessagesPerPage; if (_showAtMsgId == ShowAtUnreadMsgId) { @@ -3018,7 +3018,7 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { _delayedShowAtMsgId = showAtMsgId; auto from = _history; - auto offsetId = 0; + auto offsetId = MsgId(); auto offset = 0; auto loadCount = kMessagesPerPage; if (_delayedShowAtMsgId == ShowAtUnreadMsgId) { diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp index 09d3e5ace..7c6d5a8dc 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp @@ -60,7 +60,7 @@ namespace { PinnedMemento::PinnedMemento( not_null history, - MsgId highlightId) + UniversalMsgId highlightId) : _history(history) , _highlightId(highlightId) { _list.setAroundPosition({ diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.h b/Telegram/SourceFiles/history/view/history_view_pinned_section.h index 6cff5bb06..27c81678b 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.h +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.h @@ -166,7 +166,7 @@ private: class PinnedMemento : public Window::SectionMemento { public: - using UniversalMsgId = int32; + using UniversalMsgId = MsgId; explicit PinnedMemento( not_null history, diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp index 874a951bc..ef26258d8 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp @@ -153,7 +153,7 @@ void PinnedTracker::clear() { _current = PinnedId(); } -void PinnedTracker::trackAround(MsgId messageId) { +void PinnedTracker::trackAround(UniversalMsgId messageId) { if (_aroundId == messageId) { return; } diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.h b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.h index bf4a2b8cb..65ff734f3 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.h +++ b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.h @@ -19,7 +19,7 @@ namespace HistoryView { class PinnedTracker final { public: - using UniversalMsgId = int32; + using UniversalMsgId = MsgId; explicit PinnedTracker(not_null history); ~PinnedTracker(); diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.cpp b/Telegram/SourceFiles/history/view/media/history_view_media.cpp index 183fdd946..d0138ffa5 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media.cpp @@ -49,7 +49,7 @@ QString DocumentTimestampLinkBase( FullMsgId context) { return QString( "doc%1_%2_%3" - ).arg(document->id).arg(context.channel.bare).arg(context.msg); + ).arg(document->id).arg(context.channel.bare).arg(context.msg.bare); } TextWithEntities AddTimestampLinks( diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 00b38329c..d75b088a7 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -986,7 +986,7 @@ SparseIdsMergedSlice::Key ListWidget::sliceKey( } if (universalId < 0) { // Convert back to plain id for non-migrated histories. - universalId += ServerMaxMsgId; + universalId = universalId + ServerMaxMsgId; } return Key(_peer->id, 0, universalId); } diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h index 926354533..2c145942e 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h @@ -46,7 +46,7 @@ class AbstractController; namespace Media { using BaseLayout = Overview::Layout::ItemBase; -using UniversalMsgId = int32; +using UniversalMsgId = MsgId; class ListWidget final : public Ui::RpWidget diff --git a/Telegram/SourceFiles/main/main_session_settings.cpp b/Telegram/SourceFiles/main/main_session_settings.cpp index d8caa3e60..88a7fc041 100644 --- a/Telegram/SourceFiles/main/main_session_settings.cpp +++ b/Telegram/SourceFiles/main/main_session_settings.cpp @@ -64,13 +64,14 @@ QByteArray SessionSettings::serialize() const { for (const auto &[id, time] : _mediaLastPlaybackPosition) { stream << quint64(id) << qint64(time); } - stream << qint32(_hiddenPinnedMessages.size()); - for (const auto &[key, value] : _hiddenPinnedMessages) { - stream << SerializePeerId(key) << qint32(value); - } + stream << qint32(0); stream << qint32(_dialogsFiltersEnabled ? 1 : 0); stream << qint32(_supportAllSilent ? 1 : 0); stream << qint32(_photoEditorHintShowsCount); + stream << qint32(_hiddenPinnedMessages.size()); + for (const auto &[key, value] : _hiddenPinnedMessages) { + stream << SerializePeerId(key) << qint64(value.bare); + } } return result; } @@ -310,6 +311,7 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) { auto count = qint32(0); stream >> count; if (stream.status() == QDataStream::Ok) { + // Legacy. for (auto i = 0; i != count; ++i) { auto key = quint64(); auto value = qint32(); @@ -332,6 +334,23 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) { if (!stream.atEnd()) { stream >> photoEditorHintShowsCount; } + if (!stream.atEnd()) { + auto count = qint32(0); + stream >> count; + if (stream.status() == QDataStream::Ok) { + for (auto i = 0; i != count; ++i) { + auto key = quint64(); + auto value = qint64(); + stream >> key >> value; + if (stream.status() != QDataStream::Ok) { + LOG(("App Error: " + "Bad data for SessionSettings::addFromSerialized()")); + return; + } + hiddenPinnedMessages.emplace(DeserializePeerId(key), value); + } + } + } if (stream.status() != QDataStream::Ok) { LOG(("App Error: " "Bad data for SessionSettings::addFromSerialized()")); diff --git a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp index baf203087..9dfccc6f5 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp @@ -133,12 +133,10 @@ AdminLog::OwnedItem GenerateForwardedItem( Expects(history->peer->isUser()); using Flag = MTPDmessage::Flag; - // #TODO common global incrementable id for fake items, like clientMsgId. - static auto id = ServerMaxMsgId + (ServerMaxMsgId / 6); const auto flags = Flag::f_from_id | Flag::f_fwd_from; const auto item = MTP_message( MTP_flags(flags), - MTP_int(++id), + MTP_int(history->owner().nextNonHistoryEntryId()), peerToMTP(history->peer->id), peerToMTP(history->peer->id), MTP_messageFwdHeader( diff --git a/Telegram/SourceFiles/storage/details/storage_settings_scheme.cpp b/Telegram/SourceFiles/storage/details/storage_settings_scheme.cpp index 3b2216e21..c29849ac3 100644 --- a/Telegram/SourceFiles/storage/details/storage_settings_scheme.cpp +++ b/Telegram/SourceFiles/storage/details/storage_settings_scheme.cpp @@ -1074,14 +1074,14 @@ bool ReadSetting( } break; case dbiHiddenPinnedMessagesOld: { - auto v = QMap(); + auto v = QMap(); stream >> v; if (!CheckStreamStatus(stream)) return false; for (auto i = v.begin(), e = v.end(); i != e; ++i) { context.sessionSettings().setHiddenPinnedMessageId( DeserializePeerId(i.key()), - i.value()); + MsgId(i.value())); } context.legacyRead = true; } break; diff --git a/Telegram/SourceFiles/storage/storage_account.cpp b/Telegram/SourceFiles/storage/storage_account.cpp index 9f0f78ef0..5a1c72d61 100644 --- a/Telegram/SourceFiles/storage/storage_account.cpp +++ b/Telegram/SourceFiles/storage/storage_account.cpp @@ -54,8 +54,10 @@ constexpr auto kSinglePeerTypeChat = qint32(8 + 2); constexpr auto kSinglePeerTypeChannel = qint32(8 + 3); constexpr auto kSinglePeerTypeSelf = qint32(4); constexpr auto kSinglePeerTypeEmpty = qint32(0); -constexpr auto kMultiDraftTag = quint64(0xFFFFFFFFFFFFFF01ULL); -constexpr auto kMultiDraftCursorsTag = quint64(0xFFFFFFFFFFFFFF02ULL); +constexpr auto kMultiDraftTagOld = quint64(0xFFFF'FFFF'FFFF'FF01ULL); +constexpr auto kMultiDraftCursorsTagOld = quint64(0xFFFF'FFFF'FFFF'FF02ULL); +constexpr auto kMultiDraftTag = quint64(0xFFFF'FFFF'FFFF'FF03ULL); +constexpr auto kMultiDraftCursorsTag = quint64(0xFFFF'FFFF'FFFF'FF04ULL); enum { // Local Storage Keys lskUserMap = 0x00, @@ -1068,10 +1070,10 @@ void Account::writeDrafts(not_null history) { const TextWithTags &text, Data::PreviewState, auto&&) { // cursor - size += sizeof(qint32) // key + size += sizeof(qint64) // key + Serialize::stringSize(text.text) - + sizeof(quint32) + TextUtilities::SerializeTagsSize(text.tags) - + 2 * sizeof(qint32); // msgId, previewState + + sizeof(qint64) + TextUtilities::SerializeTagsSize(text.tags) + + sizeof(qint64) + sizeof(qint32); // msgId, previewState }; EnumerateDrafts( map, @@ -1096,7 +1098,7 @@ void Account::writeDrafts(not_null history) { << key.serialize() << text.text << TextUtilities::SerializeTags(text.tags) - << qint32(msgId) + << qint64(msgId.bare) << qint32(previewState); }; EnumerateDrafts( @@ -1143,7 +1145,7 @@ void Account::writeDraftCursors(not_null history) { auto size = int(sizeof(quint64) * 2 + sizeof(quint32) - + sizeof(qint32) * 4 * count); + + (sizeof(qint64) + sizeof(qint32) * 3) * count); EncryptedDescriptor data(size); data.stream @@ -1196,7 +1198,9 @@ void Account::readDraftCursors(PeerId peerId, Data::HistoryDrafts &map) { } quint64 tag = 0; draft.stream >> tag; - if (tag != kMultiDraftTag && tag != kMultiDraftCursorsTag) { + if (tag != kMultiDraftCursorsTag + && tag != kMultiDraftCursorsTagOld + && tag != kMultiDraftTagOld) { readDraftCursorsLegacy(peerId, draft, tag, map); return; } @@ -1209,13 +1213,19 @@ void Account::readDraftCursors(PeerId peerId, Data::HistoryDrafts &map) { return; } const auto keysWritten = (tag == kMultiDraftCursorsTag); + const auto keysOld = (tag == kMultiDraftCursorsTagOld); for (auto i = 0; i != count; ++i) { - qint32 keyValue = 0; + qint64 keyValue = 0; + qint32 keyValueOld = 0; if (keysWritten) { draft.stream >> keyValue; + } else if (keysOld) { + draft.stream >> keyValueOld; } const auto key = keysWritten ? Data::DraftKey::FromSerialized(keyValue) + : keysOld + ? Data::DraftKey::FromSerializedOld(keyValueOld) : Data::DraftKey::Local(); qint32 position = 0, anchor = 0, scroll = QFIXED_MAX; draft.stream >> position >> anchor >> scroll; @@ -1287,7 +1297,7 @@ void Account::readDraftsWithCursors(not_null history) { quint64 tag = 0; draft.stream >> tag; - if (tag != kMultiDraftTag) { + if (tag != kMultiDraftTag && tag != kMultiDraftTagOld) { readDraftsWithCursorsLegacy(history, draft, tag); return; } @@ -1302,12 +1312,18 @@ void Account::readDraftsWithCursors(not_null history) { return; } auto map = Data::HistoryDrafts(); + const auto keysOld = (tag == kMultiDraftTagOld); for (auto i = 0; i != count; ++i) { TextWithTags data; QByteArray tagsSerialized; - qint32 keyValue = 0, messageId = 0, uncheckedPreviewState = 0; + qint64 keyValue = 0; + qint32 keyValueOld = 0, messageId = 0, uncheckedPreviewState = 0; + if (keysOld) { + draft.stream >> keyValueOld; + } else { + draft.stream >> keyValue; + } draft.stream - >> keyValue >> data.text >> tagsSerialized >> messageId @@ -1321,7 +1337,9 @@ void Account::readDraftsWithCursors(not_null history) { case Data::PreviewState::EmptyOnEdit: previewState = Data::PreviewState(uncheckedPreviewState); } - const auto key = Data::DraftKey::FromSerialized(keyValue); + const auto key = keysOld + ? Data::DraftKey::FromSerializedOld(keyValueOld) + : Data::DraftKey::FromSerialized(keyValue); if (key && key != Data::DraftKey::Cloud()) { map.emplace(key, std::make_unique( data, diff --git a/Telegram/SourceFiles/support/support_autocomplete.cpp b/Telegram/SourceFiles/support/support_autocomplete.cpp index 174afa845..d3e5841ec 100644 --- a/Telegram/SourceFiles/support/support_autocomplete.cpp +++ b/Telegram/SourceFiles/support/support_autocomplete.cpp @@ -274,7 +274,6 @@ AdminLog::OwnedItem GenerateCommentItem( if (data.comment.isEmpty()) { return nullptr; } - const auto id = ServerMaxMsgId + (ServerMaxMsgId / 2); const auto flags = MessageFlag::HasFromId | MessageFlag::Outgoing | MessageFlag::FakeHistoryItem; @@ -282,7 +281,7 @@ AdminLog::OwnedItem GenerateCommentItem( const auto viaBotId = UserId(); const auto groupedId = uint64(); const auto item = history->makeMessage( - id, + history->owner().nextNonHistoryEntryId(), flags, replyTo, viaBotId, @@ -305,7 +304,7 @@ AdminLog::OwnedItem GenerateContactItem( const auto postAuthor = QString(); const auto groupedId = uint64(); const auto item = history->makeMessage( - (ServerMaxMsgId + (ServerMaxMsgId / 2) + 1), + history->owner().nextNonHistoryEntryId(), (MessageFlag::HasFromId | MessageFlag::Outgoing | MessageFlag::FakeHistoryItem),