From 08bddc55791366590aae3c66684e16471976b28a Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Thu, 25 Apr 2019 16:45:15 +0400
Subject: [PATCH] Move messages data to AuthSession.

---
 Telegram/SourceFiles/apiwrap.cpp              |  80 ++---
 Telegram/SourceFiles/app.cpp                  | 261 --------------
 Telegram/SourceFiles/app.h                    |  31 +-
 .../boxes/background_preview_box.cpp          |   2 +-
 Telegram/SourceFiles/boxes/confirm_box.cpp    |   8 +-
 .../SourceFiles/boxes/edit_caption_box.cpp    |   3 +-
 Telegram/SourceFiles/boxes/share_box.cpp      |  10 +-
 .../calls/calls_box_controller.cpp            |  18 +-
 .../SourceFiles/chat_helpers/bot_keyboard.cpp |   4 +-
 Telegram/SourceFiles/core/application.cpp     |   2 +-
 Telegram/SourceFiles/data/data_document.cpp   |   4 +-
 Telegram/SourceFiles/data/data_folder.cpp     |   2 +-
 Telegram/SourceFiles/data/data_photo.cpp      |   2 +-
 .../data/data_search_controller.cpp           |   2 +-
 Telegram/SourceFiles/data/data_session.cpp    | 318 +++++++++++++++++-
 Telegram/SourceFiles/data/data_session.h      |  80 +++++
 .../SourceFiles/data/data_shared_media.cpp    |   2 +-
 Telegram/SourceFiles/data/data_types.cpp      |   6 +-
 .../dialogs/dialogs_inner_widget.cpp          |   2 +-
 .../admin_log/history_admin_log_inner.cpp     |  10 +-
 .../admin_log/history_admin_log_item.cpp      |  16 +-
 Telegram/SourceFiles/history/history.cpp      |  32 +-
 Telegram/SourceFiles/history/history.h        |   8 +-
 .../history/history_inner_widget.cpp          |  30 +-
 Telegram/SourceFiles/history/history_item.cpp |  45 +--
 .../history/history_item_components.cpp       |  20 +-
 .../SourceFiles/history/history_message.cpp   |   6 +-
 .../SourceFiles/history/history_service.cpp   |  10 +-
 .../SourceFiles/history/history_widget.cpp    |  70 ++--
 .../history/media/history_media_contact.cpp   |   3 +-
 .../view/history_view_context_menu.cpp        |  14 +-
 .../history/view/history_view_list_widget.cpp |  28 +-
 .../history/view/history_view_message.cpp     |   5 +-
 Telegram/SourceFiles/info/info_top_bar.cpp    |   6 +-
 .../info/media/info_media_list_widget.cpp     |  12 +-
 .../inline_bots/inline_bot_send_data.cpp      |   2 +-
 Telegram/SourceFiles/mainwidget.cpp           |  37 +-
 .../SourceFiles/media/audio/media_audio.cpp   |   5 +-
 .../media/player/media_player_float.cpp       |   2 +-
 .../media/player/media_player_instance.cpp    |   8 +-
 .../media/player/media_player_panel.cpp       |   4 +-
 .../media/player/media_player_widget.cpp      |   7 +-
 .../media/view/media_view_group_thumbs.cpp    |   6 +-
 .../media/view/media_view_overlay_widget.cpp  |  24 +-
 .../settings/settings_privacy_controllers.cpp |   6 +-
 .../SourceFiles/storage/localimageloader.cpp  |   4 +-
 .../support/support_autocomplete.cpp          |   7 +-
 .../window/notifications_manager.cpp          |   8 +-
 .../SourceFiles/window/window_controller.cpp  |   2 +-
 49 files changed, 684 insertions(+), 590 deletions(-)

diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index 0de22d61a..d9595bc2a 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -589,10 +589,12 @@ void ApiWrap::resolveMessageDatas() {
 }
 
 void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId requestId) {
-	auto handleResult = [&](auto &&result) {
+	const auto handleResult = [&](auto &&result) {
 		_session->data().processUsers(result.vusers);
 		_session->data().processChats(result.vchats);
-		App::feedMsgs(result.vmessages, NewMessageExisting);
+		_session->data().processMessages(
+			result.vmessages,
+			NewMessageType::Existing);
 	};
 	switch (msgs.type()) {
 	case mtpc_messages_messages:
@@ -1034,7 +1036,7 @@ void ApiWrap::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) {
 	const auto &data = dialogs.c_messages_peerDialogs();
 	_session->data().processUsers(data.vusers);
 	_session->data().processChats(data.vchats);
-	App::feedMsgs(data.vmessages, NewMessageLast);
+	_session->data().processMessages(data.vmessages, NewMessageType::Last);
 	for (const auto &dialog : data.vdialogs.v) {
 		dialog.match([&](const MTPDdialog &data) {
 			if (const auto peerId = peerFromMTP(data.vpeer)) {
@@ -1879,7 +1881,7 @@ void ApiWrap::deleteAllFromUser(
 		: QVector<MsgId>();
 	const auto channelId = peerToChannel(channel->id);
 	for (const auto msgId : ids) {
-		if (const auto item = App::histItemById(channelId, msgId)) {
+		if (const auto item = _session->data().message(channelId, msgId)) {
 			item->destroy();
 		}
 	}
@@ -3008,7 +3010,7 @@ void ApiWrap::refreshFileReference(
 		handler(UpdatedFileReferences());
 	};
 	origin.data.match([&](Data::FileOriginMessage data) {
-		if (const auto item = App::histItemById(data)) {
+		if (const auto item = _session->data().message(data)) {
 			if (const auto channel = item->history()->peer->asChannel()) {
 				request(MTPchannels_GetMessages(
 					channel->inputChannel,
@@ -3116,7 +3118,7 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
 	for (const auto [position, index] : indices) {
 		const auto item = _session->data().addNewMessage(
 			v->at(index),
-			NewMessageExisting);
+			NewMessageType::Existing);
 		if (item) {
 			_session->data().requestItemResize(item);
 		}
@@ -3572,7 +3574,7 @@ void ApiWrap::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
 				MTPint(),
 				MTPstring(),
 				MTPlong()),
-			NewMessageUnread);
+			NewMessageType::Unread);
 	} break;
 
 	case mtpc_updateShortChatMessage: {
@@ -3596,7 +3598,7 @@ void ApiWrap::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
 				MTPint(),
 				MTPstring(),
 				MTPlong()),
-			NewMessageUnread);
+			NewMessageType::Unread);
 	} break;
 
 	case mtpc_updateShortSentMessage: {
@@ -3614,13 +3616,13 @@ void ApiWrap::applyUpdateNoPtsCheck(const MTPUpdate &update) {
 		auto &d = update.c_updateNewMessage();
 		auto needToAdd = true;
 		if (d.vmessage.type() == mtpc_message) { // index forwarded messages to links _overview
-			if (App::checkEntitiesAndViewsUpdate(d.vmessage.c_message())) { // already in blocks
+			if (_session->data().checkEntitiesAndViewsUpdate(d.vmessage.c_message())) { // already in blocks
 				LOG(("Skipping message, because it is already in blocks!"));
 				needToAdd = false;
 			}
 		}
 		if (needToAdd) {
-			_session->data().addNewMessage(d.vmessage, NewMessageUnread);
+			_session->data().addNewMessage(d.vmessage, NewMessageType::Unread);
 		}
 	} break;
 
@@ -3628,7 +3630,7 @@ void ApiWrap::applyUpdateNoPtsCheck(const MTPUpdate &update) {
 		const auto &d = update.c_updateReadMessagesContents();
 		auto possiblyReadMentions = base::flat_set<MsgId>();
 		for (const auto &msgId : d.vmessages.v) {
-			if (const auto item = App::histItemById(NoChannel, msgId.v)) {
+			if (const auto item = _session->data().message(NoChannel, msgId.v)) {
 				if (item->isUnreadMedia() || item->isUnreadMention()) {
 					item->markMediaRead();
 					_session->data().requestItemRepaint(item);
@@ -3696,31 +3698,31 @@ void ApiWrap::applyUpdateNoPtsCheck(const MTPUpdate &update) {
 
 	case mtpc_updateDeleteMessages: {
 		auto &d = update.c_updateDeleteMessages();
-		App::feedWereDeleted(NoChannel, d.vmessages.v);
+		_session->data().processMessagesDeleted(NoChannel, d.vmessages.v);
 	} break;
 
 	case mtpc_updateNewChannelMessage: {
 		auto &d = update.c_updateNewChannelMessage();
 		auto needToAdd = true;
 		if (d.vmessage.type() == mtpc_message) { // index forwarded messages to links _overview
-			if (App::checkEntitiesAndViewsUpdate(d.vmessage.c_message())) { // already in blocks
+			if (_session->data().checkEntitiesAndViewsUpdate(d.vmessage.c_message())) { // already in blocks
 				LOG(("Skipping message, because it is already in blocks!"));
 				needToAdd = false;
 			}
 		}
 		if (needToAdd) {
-			_session->data().addNewMessage(d.vmessage, NewMessageUnread);
+			_session->data().addNewMessage(d.vmessage, NewMessageType::Unread);
 		}
 	} break;
 
 	case mtpc_updateEditChannelMessage: {
 		auto &d = update.c_updateEditChannelMessage();
-		App::updateEditedMessage(d.vmessage);
+		_session->data().updateEditedMessage(d.vmessage);
 	} break;
 
 	case mtpc_updateEditMessage: {
 		auto &d = update.c_updateEditMessage();
-		App::updateEditedMessage(d.vmessage);
+		_session->data().updateEditedMessage(d.vmessage);
 	} break;
 
 	case mtpc_updateChannelWebPage: {
@@ -3730,7 +3732,7 @@ void ApiWrap::applyUpdateNoPtsCheck(const MTPUpdate &update) {
 
 	case mtpc_updateDeleteChannelMessages: {
 		auto &d = update.c_updateDeleteChannelMessages();
-		App::feedWereDeleted(d.vchannel_id.v, d.vmessages.v);
+		_session->data().processMessagesDeleted(d.vchannel_id.v, d.vmessages.v);
 	} break;
 
 	default: Unexpected("Type in applyUpdateNoPtsCheck()");
@@ -3800,9 +3802,9 @@ void ApiWrap::requestMessageAfterDate(
 			return nullptr;
 		};
 
-		if (auto list = getMessagesList()) {
-			App::feedMsgs(*list, NewMessageExisting);
-			for (auto &message : *list) {
+		if (const auto list = getMessagesList()) {
+			_session->data().processMessages(*list, NewMessageType::Existing);
+			for (const auto &message : *list) {
 				if (DateFromMessage(message) >= offsetDate) {
 					callback(IdFromMessage(message));
 					return;
@@ -3922,8 +3924,10 @@ void ApiWrap::checkForUnreadMentions(
 		const base::flat_set<MsgId> &possiblyReadMentions,
 		ChannelData *channel) {
 	for (auto msgId : possiblyReadMentions) {
-		requestMessageData(channel, msgId, [](ChannelData *channel, MsgId msgId) {
-			if (auto item = App::histItemById(channel, msgId)) {
+		requestMessageData(channel, msgId, [=](
+				ChannelData *channel,
+				MsgId msgId) {
+			if (const auto item = _session->data().message(channel, msgId)) {
 				if (item->mentionsMe()) {
 					item->markMediaRead();
 				}
@@ -4474,7 +4478,7 @@ void ApiWrap::forwardMessages(
 					messageFromId,
 					messagePostAuthor,
 					message);
-				App::historyRegRandom(randomId, newId);
+				_session->data().registerMessageRandomId(randomId, newId);
 			}
 		}
 		const auto newFrom = item->history()->peer;
@@ -4573,7 +4577,7 @@ void ApiWrap::sendSharedContact(
 			MTPint(),
 			MTP_string(messagePostAuthor),
 			MTPlong()),
-		NewMessageUnread);
+		NewMessageType::Unread);
 
 	const auto media = MTP_inputMediaContact(
 		MTP_string(phone),
@@ -4700,7 +4704,7 @@ void ApiWrap::sendUploadedPhoto(
 		FullMsgId localId,
 		const MTPInputFile &file,
 		bool silent) {
-	if (const auto item = App::histItemById(localId)) {
+	if (const auto item = _session->data().message(localId)) {
 		const auto media = MTP_inputMediaUploadedPhoto(
 			MTP_flags(0),
 			file,
@@ -4719,7 +4723,7 @@ void ApiWrap::sendUploadedDocument(
 		const MTPInputFile &file,
 		const std::optional<MTPInputFile> &thumb,
 		bool silent) {
-	if (const auto item = App::histItemById(localId)) {
+	if (const auto item = _session->data().message(localId)) {
 		auto media = item->media();
 		if (auto document = media ? media->document() : nullptr) {
 			const auto groupId = item->groupId();
@@ -4753,7 +4757,7 @@ void ApiWrap::editUploadedFile(
 		const std::optional<MTPInputFile> &thumb,
 		bool silent,
 		bool isDocument) {
-	const auto item = App::histItemById(localId);
+	const auto item = _session->data().message(localId);
 	if (!item) {
 		return;
 	}
@@ -4882,8 +4886,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
 
 		TextUtilities::Trim(sending);
 
-		App::historyRegRandom(randomId, newId);
-		App::historyRegSentData(randomId, peer->id, sending.text);
+		_session->data().registerMessageRandomId(randomId, newId);
+		_session->data().registerMessageSentData(randomId, peer->id, sending.text);
 
 		MTPstring msgText(MTP_string(sending.text));
 		auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_entities;
@@ -4950,7 +4954,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
 				MTPint(),
 				MTP_string(messagePostAuthor),
 				MTPlong()),
-			NewMessageUnread);
+			NewMessageType::Unread);
 		history->sendRequestId = request(MTPmessages_SendMessage(
 			MTP_flags(sendFlags),
 			peer->input,
@@ -5053,7 +5057,7 @@ void ApiWrap::sendInlineResult(
 	UserId messageViaBotId = bot ? peerToUser(bot->id) : 0;
 	MsgId messageId = newId.msg;
 
-	App::historyRegRandom(randomId, newId);
+	_session->data().registerMessageRandomId(randomId, newId);
 
 	data->addToHistory(
 		history,
@@ -5137,7 +5141,7 @@ void ApiWrap::sendExistingDocument(
 	const auto replyTo = options.replyTo;
 	const auto captionText = caption.text;
 
-	App::historyRegRandom(randomId, newId);
+	_session->data().registerMessageRandomId(randomId, newId);
 
 	history->addNewDocument(
 		newId.msg,
@@ -5210,7 +5214,7 @@ void ApiWrap::uploadAlbumMedia(
 		item->history()->peer->input,
 		media
 	)).done([=](const MTPMessageMedia &result) {
-		const auto item = App::histItemById(localId);
+		const auto item = _session->data().message(localId);
 		if (!item) {
 			failed();
 			return;
@@ -5276,7 +5280,7 @@ void ApiWrap::sendMedia(
 		const MTPInputMedia &media,
 		bool silent) {
 	const auto randomId = rand_value<uint64>();
-	App::historyRegRandom(randomId, item->fullId());
+	_session->data().registerMessageRandomId(randomId, item->fullId());
 
 	sendMediaWithRandomId(item, media, silent, randomId);
 }
@@ -5327,7 +5331,7 @@ void ApiWrap::sendAlbumWithUploaded(
 		const MTPInputMedia &media) {
 	const auto localId = item->fullId();
 	const auto randomId = rand_value<uint64>();
-	App::historyRegRandom(randomId, localId);
+	_session->data().registerMessageRandomId(randomId, localId);
 
 	const auto albumIt = _sendingAlbums.find(groupId.raw());
 	Assert(albumIt != _sendingAlbums.end());
@@ -5367,7 +5371,7 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
 		if (!item.media) {
 			return;
 		} else if (!sample) {
-			sample = App::histItemById(item.msgId);
+			sample = _session->data().message(item.msgId);
 		}
 		medias.push_back(*item.media);
 	}
@@ -5813,7 +5817,7 @@ void ApiWrap::sendPollVotes(
 	if (_pollVotesRequestIds.contains(itemId)) {
 		return;
 	}
-	const auto item = App::histItemById(itemId);
+	const auto item = _session->data().message(itemId);
 	const auto media = item ? item->media() : nullptr;
 	const auto poll = media ? media->poll() : nullptr;
 	if (!item) {
@@ -5823,7 +5827,7 @@ void ApiWrap::sendPollVotes(
 	const auto showSending = poll && !options.empty();
 	const auto hideSending = [=] {
 		if (showSending) {
-			if (const auto item = App::histItemById(itemId)) {
+			if (const auto item = _session->data().message(itemId)) {
 				poll->sendingVote = QByteArray();
 				_session->data().requestItemRepaint(item);
 			}
diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index 16f332818..cbab3e830 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -53,21 +53,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 namespace {
 	App::LaunchState _launchState = App::Launched;
 
-	using DependentItemsSet = OrderedSet<HistoryItem*>;
-	using DependentItems = QMap<HistoryItem*, DependentItemsSet>;
-	DependentItems dependentItems;
-
-	using MsgsData = QHash<MsgId, HistoryItem*>;
-	MsgsData msgsData;
-	using ChannelMsgsData = QMap<ChannelId, MsgsData>;
-	ChannelMsgsData channelMsgsData;
-
-	using RandomData = QMap<uint64, FullMsgId>;
-	RandomData randomData;
-
-	using SentData = QMap<uint64, QPair<PeerId, QString>>;
-	SentData sentData;
-
 	HistoryView::Element *hoveredItem = nullptr,
 		*pressedItem = nullptr,
 		*hoveredLinkItem = nullptr,
@@ -129,55 +114,6 @@ namespace App {
 		return nullptr;
 	}
 
-	bool checkEntitiesAndViewsUpdate(const MTPDmessage &m) {
-		auto peerId = peerFromMTP(m.vto_id);
-		if (m.has_from_id() && peerId == Auth().userPeerId()) {
-			peerId = peerFromUser(m.vfrom_id);
-		}
-		if (const auto existing = App::histItemById(peerToChannel(peerId), m.vid.v)) {
-			auto text = qs(m.vmessage);
-			auto entities = m.has_entities()
-				? TextUtilities::EntitiesFromMTP(m.ventities.v)
-				: EntitiesInText();
-			existing->setText({ text, entities });
-			existing->updateSentMedia(m.has_media() ? &m.vmedia : nullptr);
-			existing->updateReplyMarkup(m.has_reply_markup()
-				? (&m.vreply_markup)
-				: nullptr);
-			existing->updateForwardedInfo(m.has_fwd_from()
-				? &m.vfwd_from
-				: nullptr);
-			existing->setViewsCount(m.has_views() ? m.vviews.v : -1);
-			existing->indexAsNewItem();
-			Auth().data().requestItemTextRefresh(existing);
-			if (existing->mainView()) {
-				App::checkSavedGif(existing);
-				return true;
-			}
-			return false;
-		}
-		return false;
-	}
-
-	void updateEditedMessage(const MTPMessage &m) {
-		m.match([](const MTPDmessageEmpty &) {
-		}, [&m](const auto &message) {
-			auto peerId = peerFromMTP(message.vto_id);
-			if (message.has_from_id() && peerId == Auth().userPeerId()) {
-				peerId = peerFromUser(message.vfrom_id);
-			}
-			const auto existing = App::histItemById(
-				peerToChannel(peerId),
-				message.vid.v);
-			if (existing) {
-				if (existing->isLocalUpdateMedia()) {
-					checkEntitiesAndViewsUpdate(m.c_message());
-				}
-				existing->applyEdition(message);
-			}
-		});
-	}
-
 	void addSavedGif(DocumentData *doc) {
 		auto &saved = Auth().data().savedGifsRef();
 		int32 index = saved.indexOf(doc);
@@ -205,72 +141,6 @@ namespace App {
 		}
 	}
 
-	void feedMsgs(const QVector<MTPMessage> &msgs, NewMessageType type) {
-		auto indices = base::flat_map<uint64, int>();
-		for (int i = 0, l = msgs.size(); i != l; ++i) {
-			const auto &msg = msgs[i];
-			if (msg.type() == mtpc_message) {
-				const auto &data = msg.c_message();
-				if (type == NewMessageUnread) { // new message, index my forwarded messages to links overview
-					if (checkEntitiesAndViewsUpdate(data)) { // already in blocks
-						LOG(("Skipping message, because it is already in blocks!"));
-						continue;
-					}
-				}
-			}
-			const auto msgId = IdFromMessage(msg);
-			indices.emplace((uint64(uint32(msgId)) << 32) | uint64(i), i);
-		}
-		for (const auto [position, index] : indices) {
-			Auth().data().addNewMessage(msgs[index], type);
-		}
-	}
-
-	void feedMsgs(const MTPVector<MTPMessage> &msgs, NewMessageType type) {
-		return feedMsgs(msgs.v, type);
-	}
-
-	inline MsgsData *fetchMsgsData(ChannelId channelId, bool insert = true) {
-		if (channelId == NoChannel) return &msgsData;
-		ChannelMsgsData::iterator i = channelMsgsData.find(channelId);
-		if (i == channelMsgsData.cend()) {
-			if (insert) {
-				i = channelMsgsData.insert(channelId, MsgsData());
-			} else {
-				return 0;
-			}
-		}
-		return &(*i);
-	}
-
-	void feedWereDeleted(
-			ChannelId channelId,
-			const QVector<MTPint> &msgsIds) {
-		const auto data = fetchMsgsData(channelId, false);
-		if (!data) return;
-
-		const auto affectedHistory = (channelId != NoChannel)
-			? Auth().data().history(peerFromChannel(channelId)).get()
-			: nullptr;
-
-		auto historiesToCheck = base::flat_set<not_null<History*>>();
-		for (const auto msgId : msgsIds) {
-			auto j = data->constFind(msgId.v);
-			if (j != data->cend()) {
-				const auto history = (*j)->history();
-				(*j)->destroy();
-				if (!history->chatListMessageKnown()) {
-					historiesToCheck.emplace(history);
-				}
-			} else if (affectedHistory) {
-				affectedHistory->unknownMessageDeleted(msgId.v);
-			}
-		}
-		for (const auto history : historiesToCheck) {
-			history->requestChatListMessage();
-		}
-	}
-
 	void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink) {
 		if (const auto user = Auth().data().userLoaded(userId.v)) {
 			const auto wasShowPhone = (user->contactStatus() == UserData::ContactStatus::CanAdd);
@@ -314,137 +184,6 @@ namespace App {
 		return peer ? ((forDialogs && peer->isUser() && !peer->asUser()->nameOrPhone.isEmpty()) ? peer->asUser()->nameOrPhone : peer->name) : lang(lng_deleted);
 	}
 
-	HistoryItem *histItemById(ChannelId channelId, MsgId itemId) {
-		if (!itemId) return nullptr;
-
-		const auto data = fetchMsgsData(channelId, false);
-		if (!data) return nullptr;
-
-		const auto i = data->constFind(itemId);
-		return (i != data->cend()) ? i.value() : nullptr;
-	}
-
-	HistoryItem *histItemById(const ChannelData *channel, MsgId itemId) {
-		return histItemById(channel ? peerToChannel(channel->id) : 0, itemId);
-	}
-
-	void historyRegItem(not_null<HistoryItem*> item) {
-		const auto data = fetchMsgsData(item->channelId());
-		const auto i = data->constFind(item->id);
-		if (i == data->cend()) {
-			data->insert(item->id, item);
-		} else if (i.value() != item) {
-			LOG(("App Error: trying to historyRegItem() an already registered item"));
-			i.value()->destroy();
-			data->insert(item->id, item);
-		}
-	}
-
-	void historyUnregItem(not_null<HistoryItem*> item) {
-		const auto data = fetchMsgsData(item->channelId(), false);
-		if (!data) return;
-
-		const auto i = data->find(item->id);
-		if (i != data->cend()) {
-			if (i.value() == item) {
-				data->erase(i);
-			}
-		}
-		const auto j = ::dependentItems.find(item);
-		if (j != ::dependentItems.cend()) {
-			DependentItemsSet items;
-			std::swap(items, j.value());
-			::dependentItems.erase(j);
-
-			for_const (auto dependent, items) {
-				dependent->dependencyItemRemoved(item);
-			}
-		}
-		item->history()->session().notifications().clearFromItem(item);
-	}
-
-	void historyUpdateDependent(not_null<HistoryItem*> item) {
-		const auto j = ::dependentItems.find(item);
-		if (j != ::dependentItems.cend()) {
-			for_const (const auto dependent, j.value()) {
-				dependent->updateDependencyItem();
-			}
-		}
-		if (App::main()) {
-			App::main()->itemEdited(item);
-		}
-	}
-
-	void historyClearMsgs() {
-		::dependentItems.clear();
-		const auto oldData = base::take(msgsData);
-		const auto oldChannelData = base::take(channelMsgsData);
-		for (const auto item : oldData) {
-			delete item;
-		}
-		for (const auto &data : oldChannelData) {
-			for (const auto item : data) {
-				delete item;
-			}
-		}
-
-		clearMousedItems();
-	}
-
-	void historyClearItems() {
-		randomData.clear();
-		sentData.clear();
-		cSetSavedPeers(SavedPeers());
-		cSetSavedPeersByTime(SavedPeersByTime());
-		cSetRecentInlineBots(RecentInlineBots());
-		cSetRecentStickers(RecentStickerPack());
-		cSetReportSpamStatuses(ReportSpamStatuses());
-	}
-
-	void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency) {
-		::dependentItems[dependency].insert(dependent);
-	}
-
-	void historyUnregDependency(HistoryItem *dependent, HistoryItem *dependency) {
-		auto i = ::dependentItems.find(dependency);
-		if (i != ::dependentItems.cend()) {
-			i.value().remove(dependent);
-			if (i.value().isEmpty()) {
-				::dependentItems.erase(i);
-			}
-		}
-	}
-
-	void historyRegRandom(uint64 randomId, const FullMsgId &itemId) {
-		randomData.insert(randomId, itemId);
-	}
-
-	void historyUnregRandom(uint64 randomId) {
-		randomData.remove(randomId);
-	}
-
-	FullMsgId histItemByRandom(uint64 randomId) {
-		RandomData::const_iterator i = randomData.constFind(randomId);
-		if (i != randomData.cend()) {
-			return i.value();
-		}
-		return FullMsgId();
-	}
-
-	void historyRegSentData(uint64 randomId, const PeerId &peerId, const QString &text) {
-		sentData.insert(randomId, qMakePair(peerId, text));
-	}
-
-	void historyUnregSentData(uint64 randomId) {
-		sentData.remove(randomId);
-	}
-
-	void histSentDataByItem(uint64 randomId, PeerId &peerId, QString &text) {
-		QPair<PeerId, QString> d = sentData.value(randomId);
-		peerId = d.first;
-		text = d.second;
-	}
-
 	void prepareCorners(RoundCorners index, int32 radius, const QBrush &brush, const style::color *shadow = nullptr, QImage *cors = nullptr) {
 		Expects(::corners.size() > index);
 		int32 r = radius * cIntRetinaFactor(), s = st::msgShadow * cIntRetinaFactor();
diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h
index c1fd3b628..293c7a6e2 100644
--- a/Telegram/SourceFiles/app.h
+++ b/Telegram/SourceFiles/app.h
@@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "data/data_types.h"
 
-enum NewMessageType : char;
 enum class ImageRoundRadius;
 class MainWindow;
 class MainWidget;
@@ -66,38 +65,10 @@ namespace App {
 
 	QString formatPhone(QString phone);
 
-	bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached
-	void updateEditedMessage(const MTPMessage &m);
 	void addSavedGif(DocumentData *doc);
 	void checkSavedGif(HistoryItem *item);
-	void feedMsgs(const QVector<MTPMessage> &msgs, NewMessageType type);
-	void feedMsgs(const MTPVector<MTPMessage> &msgs, NewMessageType type);
-	void feedWereDeleted(ChannelId channelId, const QVector<MTPint> &msgsIds);
-	void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink);
-
 	[[nodiscard]] QString peerName(const PeerData *peer, bool forDialogs = false);
-
-	[[nodiscard]] HistoryItem *histItemById(ChannelId channelId, MsgId itemId);
-	[[nodiscard]] HistoryItem *histItemById(
-		const ChannelData *channel,
-		MsgId itemId);
-	[[nodiscard]] inline HistoryItem *histItemById(const FullMsgId &msgId) {
-		return histItemById(msgId.channel, msgId.msg);
-	}
-	void historyRegItem(not_null<HistoryItem*> item);
-	void historyUnregItem(not_null<HistoryItem*> item);
-	void historyUpdateDependent(not_null<HistoryItem*> item);
-	void historyClearMsgs();
-	void historyClearItems();
-	void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency);
-	void historyUnregDependency(HistoryItem *dependent, HistoryItem *dependency);
-
-	void historyRegRandom(uint64 randomId, const FullMsgId &itemId);
-	void historyUnregRandom(uint64 randomId);
-	FullMsgId histItemByRandom(uint64 randomId);
-	void historyRegSentData(uint64 randomId, const PeerId &peerId, const QString &text);
-	void historyUnregSentData(uint64 randomId);
-	void histSentDataByItem(uint64 randomId, PeerId &peerId, QString &text);
+	void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink);
 
 	void hoveredItem(HistoryView::Element *item);
 	HistoryView::Element *hoveredItem();
diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp
index 1b6ccace9..f89f18ee3 100644
--- a/Telegram/SourceFiles/boxes/background_preview_box.cpp
+++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp
@@ -285,7 +285,7 @@ AdminLog::OwnedItem GenerateTextItem(
 		| (out ? Flag::f_out : Flag(0));
 	const auto replyTo = 0;
 	const auto viaBotId = 0;
-	const auto item = new HistoryMessage(
+	const auto item = history->owner().makeMessage(
 		history,
 		++id,
 		flags,
diff --git a/Telegram/SourceFiles/boxes/confirm_box.cpp b/Telegram/SourceFiles/boxes/confirm_box.cpp
index beb886628..8045fe502 100644
--- a/Telegram/SourceFiles/boxes/confirm_box.cpp
+++ b/Telegram/SourceFiles/boxes/confirm_box.cpp
@@ -576,7 +576,7 @@ void DeleteMessagesBox::prepare() {
 PeerData *DeleteMessagesBox::checkFromSinglePeer() const {
 	auto result = (PeerData*)nullptr;
 	for (const auto fullId : std::as_const(_ids)) {
-		if (const auto item = App::histItemById(fullId)) {
+		if (const auto item = Auth().data().message(fullId)) {
 			const auto peer = item->history()->peer;
 			if (!result) {
 				result = peer;
@@ -606,8 +606,8 @@ auto DeleteMessagesBox::revokeText(not_null<PeerData*> peer) const
 
 	const auto items = ranges::view::all(
 		_ids
-	) | ranges::view::transform([](FullMsgId id) {
-		return App::histItemById(id);
+	) | ranges::view::transform([&](FullMsgId id) {
+		return peer->owner().message(id);
 	}) | ranges::view::filter([](HistoryItem *item) {
 		return (item != nullptr);
 	}) | ranges::to_vector;
@@ -754,7 +754,7 @@ void DeleteMessagesBox::deleteAndClear() {
 
 	base::flat_map<not_null<PeerData*>, QVector<MTPint>> idsByPeer;
 	for (const auto itemId : _ids) {
-		if (const auto item = App::histItemById(itemId)) {
+		if (const auto item = Auth().data().message(itemId)) {
 			const auto history = item->history();
 			const auto wasOnServer = IsServerMsgId(item->id);
 			const auto wasLast = (history->lastMessage() == item);
diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp
index 0102ca310..cf3b18148 100644
--- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp
+++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp
@@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "data/data_media_types.h"
 #include "data/data_photo.h"
 #include "data/data_user.h"
+#include "data/data_session.h"
 #include "history/history.h"
 #include "history/history_item.h"
 #include "lang/lang_keys.h"
@@ -876,7 +877,7 @@ void EditCaptionBox::setInnerFocus() {
 void EditCaptionBox::save() {
 	if (_saveRequestId) return;
 
-	const auto item = App::histItemById(_msgId);
+	const auto item = Auth().data().message(_msgId);
 	if (!item) {
 		_error = lang(lng_edit_deleted);
 		update();
diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp
index 2fe6d7c97..cbd197673 100644
--- a/Telegram/SourceFiles/boxes/share_box.cpp
+++ b/Telegram/SourceFiles/boxes/share_box.cpp
@@ -1126,12 +1126,14 @@ void ShareGameScoreByHash(const QString &hash) {
 		return;
 	}
 
-	if (auto item = App::histItemById(channelId, msgId)) {
+	if (const auto item = Auth().data().message(channelId, msgId)) {
 		FastShareMessage(item);
 	} else {
-		auto resolveMessageAndShareScore = [msgId](ChannelData *channel) {
-			Auth().api().requestMessageData(channel, msgId, [](ChannelData *channel, MsgId msgId) {
-				if (auto item = App::histItemById(channel, msgId)) {
+		auto resolveMessageAndShareScore = [=](ChannelData *channel) {
+			Auth().api().requestMessageData(channel, msgId, [](
+					ChannelData *channel,
+					MsgId msgId) {
+				if (const auto item = Auth().data().message(channel, msgId)) {
 					FastShareMessage(item);
 				} else {
 					Ui::show(Box<InformBox>(lang(lng_edit_deleted)));
diff --git a/Telegram/SourceFiles/calls/calls_box_controller.cpp b/Telegram/SourceFiles/calls/calls_box_controller.cpp
index f4acda1bb..43da31657 100644
--- a/Telegram/SourceFiles/calls/calls_box_controller.cpp
+++ b/Telegram/SourceFiles/calls/calls_box_controller.cpp
@@ -206,8 +206,8 @@ void BoxController::Row::stopLastActionRipple() {
 
 void BoxController::prepare() {
 	Auth().data().itemRemoved(
-	) | rpl::start_with_next([this](auto item) {
-		if (auto row = rowForItem(item)) {
+	) | rpl::start_with_next([=](not_null<const HistoryItem*> item) {
+		if (const auto row = rowForItem(item)) {
 			row->itemRemoved(item);
 			if (!row->hasItems()) {
 				delegate()->peerListRemoveRow(row);
@@ -218,8 +218,8 @@ void BoxController::prepare() {
 			delegate()->peerListRefreshRows();
 		}
 	}, lifetime());
-	subscribe(Current().newServiceMessage(), [this](const FullMsgId &msgId) {
-		if (auto item = App::histItemById(msgId)) {
+	subscribe(Current().newServiceMessage(), [=](FullMsgId msgId) {
+		if (const auto item = Auth().data().message(msgId)) {
 			insertRow(item, InsertWay::Prepend);
 		}
 	});
@@ -301,10 +301,12 @@ void BoxController::receivedCalls(const QVector<MTPMessage> &result) {
 	}
 
 	for (const auto &message : result) {
-		auto msgId = IdFromMessage(message);
-		auto peerId = PeerFromMessage(message);
-		if (auto peer = Auth().data().peerLoaded(peerId)) {
-			auto item = Auth().data().addNewMessage(message, NewMessageExisting);
+		const auto msgId = IdFromMessage(message);
+		const auto peerId = PeerFromMessage(message);
+		if (const auto peer = Auth().data().peerLoaded(peerId)) {
+			const auto item = Auth().data().addNewMessage(
+				message,
+				NewMessageType::Existing);
 			insertRow(item, InsertWay::Append);
 		} else {
 			LOG(("API Error: a search results with not loaded peer %1").arg(peerId));
diff --git a/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp b/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp
index 7011ac901..84af36b0f 100644
--- a/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp
+++ b/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp
@@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/history.h"
 #include "history/history_item_components.h"
 #include "data/data_user.h"
+#include "data/data_session.h"
+#include "auth_session.h"
 #include "styles/style_widgets.h"
 #include "styles/style_history.h"
 
@@ -145,7 +147,7 @@ void BotKeyboard::leaveEventHook(QEvent *e) {
 }
 
 bool BotKeyboard::moderateKeyActivate(int key) {
-	if (const auto item = App::histItemById(_wasForMsgId)) {
+	if (const auto item = Auth().data().message(_wasForMsgId)) {
 		if (const auto markup = item->Get<HistoryMessageReplyMarkup>()) {
 			if (key >= Qt::Key_1 && key <= Qt::Key_9) {
 				const auto index = int(key - Qt::Key_1);
diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp
index ef74de534..286023f36 100644
--- a/Telegram/SourceFiles/core/application.cpp
+++ b/Telegram/SourceFiles/core/application.cpp
@@ -230,7 +230,7 @@ bool Application::hideMediaView() {
 }
 
 void Application::showPhoto(not_null<const PhotoOpenClickHandler*> link) {
-	const auto item = App::histItemById(link->context());
+	const auto item = Auth().data().message(link->context());
 	const auto peer = link->peer();
 	return (!item && peer)
 		? showPhoto(link->photo(), peer)
diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp
index b1a7443f1..4d4b9ac72 100644
--- a/Telegram/SourceFiles/data/data_document.cpp
+++ b/Telegram/SourceFiles/data/data_document.cpp
@@ -384,7 +384,7 @@ void DocumentCancelClickHandler::onClickImpl() const {
 	if (!data->date) return;
 
 	if (data->uploading()) {
-		if (const auto item = App::histItemById(context())) {
+		if (const auto item = data->owner().message(context())) {
 			App::main()->cancelUploadLayer(item);
 		}
 	} else {
@@ -1601,7 +1601,7 @@ base::binary_guard ReadImageAsync(
 //			DocumentSaveClickHandler::Save(
 //				(contextId ? contextId : Data::FileOrigin()),
 //				document,
-//				App::histItemById(contextId));
+//				document->owner().message(contextId));
 //		};
 //		Ui::show(Box<ConfirmBox>(
 //			lang(lng_player_cant_stream),
diff --git a/Telegram/SourceFiles/data/data_folder.cpp b/Telegram/SourceFiles/data/data_folder.cpp
index 31bdd17b1..22dcb98ca 100644
--- a/Telegram/SourceFiles/data/data_folder.cpp
+++ b/Telegram/SourceFiles/data/data_folder.cpp
@@ -324,7 +324,7 @@ void Folder::applyDialog(const MTPDdialogFolder &data) {
 		const auto fullId = FullMsgId(
 			peerToChannel(peerId),
 			data.vtop_message.v);
-		history->setFolder(this, App::histItemById(fullId));
+		history->setFolder(this, owner().message(fullId));
 	} else {
 		_chatsList.clear();
 		updateChatListExistence();
diff --git a/Telegram/SourceFiles/data/data_photo.cpp b/Telegram/SourceFiles/data/data_photo.cpp
index 0c33d0e24..9ffbd57f3 100644
--- a/Telegram/SourceFiles/data/data_photo.cpp
+++ b/Telegram/SourceFiles/data/data_photo.cpp
@@ -264,7 +264,7 @@ void PhotoCancelClickHandler::onClickImpl() const {
 	if (!data->date) return;
 
 	if (data->uploading()) {
-		if (const auto item = App::histItemById(context())) {
+		if (const auto item = data->owner().message(context())) {
 			App::main()->cancelUploadLayer(item);
 		}
 	} else {
diff --git a/Telegram/SourceFiles/data/data_search_controller.cpp b/Telegram/SourceFiles/data/data_search_controller.cpp
index 89934361d..dd2b973fd 100644
--- a/Telegram/SourceFiles/data/data_search_controller.cpp
+++ b/Telegram/SourceFiles/data/data_search_controller.cpp
@@ -148,7 +148,7 @@ SearchResult ParseSearchResult(
 		return result;
 	}
 
-	auto addType = NewMessageExisting;
+	const auto addType = NewMessageType::Existing;
 	result.messageIds.reserve(messages->size());
 	for (const auto &message : *messages) {
 		if (auto item = peer->owner().addNewMessage(message, addType)) {
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index d9975a529..33c449d8a 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -184,10 +184,18 @@ void Session::clear() {
 	for (const auto &[peerId, history] : _histories) {
 		history->clear(History::ClearType::Unload);
 	}
-	App::historyClearMsgs();
+	_dependentMessages.clear();
+	base::take(_messages);
+	base::take(_channelMessages);
+	_messageByRandomId.clear();
+	_sentMessagesData.clear();
+	cSetSavedPeers(SavedPeers());
+	cSetSavedPeersByTime(SavedPeersByTime());
+	cSetRecentInlineBots(RecentInlineBots());
+	cSetRecentStickers(RecentStickerPack());
+	cSetReportSpamStatuses(ReportSpamStatuses());
+	App::clearMousedItems();
 	_histories.clear();
-
-	App::historyClearItems();
 }
 
 not_null<PeerData*> Session::peer(PeerId id) {
@@ -1093,16 +1101,28 @@ rpl::producer<not_null<const ViewElement*>> Session::viewLayoutChanged() const {
 	return _viewLayoutChanges.events();
 }
 
+void Session::changeMessageId(ChannelId channel, MsgId wasId, MsgId nowId) {
+	const auto list = messagesListForInsert(channel);
+	auto i = list->find(wasId);
+	Assert(i != list->end());
+	auto owned = std::move(i->second);
+	list->erase(i);
+	list->emplace(nowId, std::move(owned));
+}
+
 void Session::notifyItemIdChange(IdChange event) {
+	const auto item = event.item;
+	changeMessageId(item->history()->channelId(), event.oldId, item->id);
+
 	_itemIdChanges.fire_copy(event);
 
 	const auto refreshViewDataId = [](not_null<ViewElement*> view) {
 		view->refreshDataId();
 	};
-	enumerateItemViews(event.item, refreshViewDataId);
-	if (const auto group = groups().find(event.item)) {
+	enumerateItemViews(item, refreshViewDataId);
+	if (const auto group = groups().find(item)) {
 		const auto leader = group->items.back();
-		if (leader != event.item) {
+		if (leader != item) {
 			enumerateItemViews(leader, refreshViewDataId);
 		}
 	}
@@ -1309,8 +1329,8 @@ HistoryItemsList Session::idsToItems(
 		const MessageIdsList &ids) const {
 	return ranges::view::all(
 		ids
-	) | ranges::view::transform([](const FullMsgId &fullId) {
-		return App::histItemById(fullId);
+	) | ranges::view::transform([&](const FullMsgId &fullId) {
+		return message(fullId);
 	}) | ranges::view::filter([](HistoryItem *item) {
 		return item != nullptr;
 	}) | ranges::view::transform([](HistoryItem *item) {
@@ -1377,7 +1397,7 @@ void Session::applyDialogs(
 		const QVector<MTPMessage> &messages,
 		const QVector<MTPDialog> &dialogs,
 		std::optional<int> count) {
-	App::feedMsgs(messages, NewMessageLast);
+	processMessages(messages, NewMessageType::Last);
 	for (const auto &dialog : dialogs) {
 		dialog.match([&](const auto &data) {
 			applyDialog(requestFolder, data);
@@ -1481,6 +1501,278 @@ void Session::reorderTwoPinnedChats(
 	chatsList(key1.entry()->folder())->pinned()->reorder(key1, key2);
 }
 
+bool Session::checkEntitiesAndViewsUpdate(const MTPDmessage &data) {
+	const auto peer = [&] {
+		const auto result = peerFromMTP(data.vto_id);
+		return (data.has_from_id() && result == session().userPeerId())
+			? peerFromUser(data.vfrom_id)
+			: result;
+	}();
+	if (const auto existing = message(peerToChannel(peer), data.vid.v)) {
+		{
+			auto text = qs(data.vmessage);
+			auto entities = data.has_entities()
+				? TextUtilities::EntitiesFromMTP(data.ventities.v)
+				: EntitiesInText();
+			existing->setText({ std::move(text), std::move(entities) });
+		}
+		existing->updateSentMedia(data.has_media() ? &data.vmedia : nullptr);
+		existing->updateReplyMarkup(data.has_reply_markup()
+			? &data.vreply_markup
+			: nullptr);
+		existing->updateForwardedInfo(data.has_fwd_from()
+			? &data.vfwd_from
+			: nullptr);
+		existing->setViewsCount(data.has_views() ? data.vviews.v : -1);
+		existing->indexAsNewItem();
+		requestItemTextRefresh(existing);
+		if (existing->mainView()) {
+			App::checkSavedGif(existing);
+			return true;
+		}
+		return false;
+	}
+	return false;
+}
+
+void Session::updateEditedMessage(const MTPMessage &data) {
+	const auto existing = data.match([](const MTPDmessageEmpty &)
+			-> HistoryItem* {
+		return nullptr;
+	}, [&](const auto &data) {
+		const auto peer = [&] {
+			const auto result = peerFromMTP(data.vto_id);
+			return (data.has_from_id() && result == session().userPeerId())
+				? peerFromUser(data.vfrom_id)
+				: result;
+		}();
+		return message(peerToChannel(peer), data.vid.v);
+	});
+	if (!existing) {
+		return;
+	}
+	if (existing->isLocalUpdateMedia() && data.type() == mtpc_message) {
+		checkEntitiesAndViewsUpdate(data.c_message());
+	}
+	data.match([](const MTPDmessageEmpty &) {
+	}, [&](const auto &data) {
+		existing->applyEdition(data);
+	});
+}
+
+void Session::processMessages(
+		const QVector<MTPMessage> &data,
+		NewMessageType type) {
+	auto indices = base::flat_map<uint64, int>();
+	for (int i = 0, l = data.size(); i != l; ++i) {
+		const auto &message = data[i];
+		if (message.type() == mtpc_message) {
+			const auto &data = message.c_message();
+			// new message, index my forwarded messages to links overview
+			if ((type == NewMessageType::Unread)
+				&& checkEntitiesAndViewsUpdate(data)) {
+				continue;
+			}
+		}
+		const auto id = IdFromMessage(message);
+		indices.emplace((uint64(uint32(id)) << 32) | uint64(i), i);
+	}
+	for (const auto [position, index] : indices) {
+		addNewMessage(data[index], type);
+	}
+}
+
+void Session::processMessages(
+		const MTPVector<MTPMessage> &data,
+		NewMessageType type) {
+	processMessages(data.v, type);
+}
+
+const Session::Messages *Session::messagesList(ChannelId channelId) const {
+	if (channelId == NoChannel) {
+		return &_messages;
+	}
+	const auto i = _channelMessages.find(channelId);
+	return (i != end(_channelMessages)) ? &i->second : nullptr;
+}
+
+auto Session::messagesListForInsert(ChannelId channelId)
+-> not_null<Messages*> {
+	return (channelId == NoChannel)
+		? &_messages
+		: &_channelMessages[channelId];
+}
+
+HistoryItem *Session::registerMessage(std::unique_ptr<HistoryItem> item) {
+	Expects(item != nullptr);
+
+	const auto result = item.get();
+	const auto list = messagesListForInsert(result->channelId());
+	const auto i = list->find(result->id);
+	if (i != list->end()) {
+		LOG(("App Error: Trying to re-registerMessage()."));
+		i->second->destroy();
+	}
+	list->emplace(result->id, std::move(item));
+	return result;
+}
+
+void Session::processMessagesDeleted(
+		ChannelId channelId,
+		const QVector<MTPint> &data) {
+	const auto list = messagesList(channelId);
+	const auto affected = (channelId != NoChannel)
+		? historyLoaded(peerFromChannel(channelId))
+		: nullptr;
+	if (!list && !affected) {
+		return;
+	}
+
+	auto historiesToCheck = base::flat_set<not_null<History*>>();
+	for (const auto messageId : data) {
+		const auto i = list ? list->find(messageId.v) : Messages::iterator();
+		if (list && i != list->end()) {
+			const auto history = i->second->history();
+			destroyMessage(i->second.get());
+			if (!history->chatListMessageKnown()) {
+				historiesToCheck.emplace(history);
+			}
+		} else if (affected) {
+			affected->unknownMessageDeleted(messageId.v);
+		}
+	}
+	for (const auto history : historiesToCheck) {
+		history->requestChatListMessage();
+	}
+}
+
+void Session::destroyMessage(not_null<HistoryItem*> item) {
+	Expects(!item->isLogEntry() || !item->mainView());
+
+	if (!item->isLogEntry()) {
+		// All this must be done for all items manually in History::clear()!
+		item->eraseFromUnreadMentions();
+		if (IsServerMsgId(item->id)) {
+			if (const auto types = item->sharedMediaTypes()) {
+				session().storage().remove(Storage::SharedMediaRemoveOne(
+					item->history()->peer->id,
+					types,
+					item->id));
+			}
+		} else {
+			session().api().cancelLocalItem(item);
+		}
+		item->history()->itemRemoved(item);
+	}
+	const auto list = messagesListForInsert(item->history()->channelId());
+	list->erase(item->id);
+}
+
+HistoryItem *Session::message(ChannelId channelId, MsgId itemId) const {
+	if (!itemId) {
+		return nullptr;
+	}
+
+	const auto data = messagesList(channelId);
+	if (!data) {
+		return nullptr;
+	}
+
+	const auto i = data->find(itemId);
+	return (i != data->end()) ? i->second.get() : nullptr;
+}
+
+HistoryItem *Session::message(
+		const ChannelData *channel,
+		MsgId itemId) const {
+	return message(channel ? peerToChannel(channel->id) : 0, itemId);
+}
+
+HistoryItem *Session::message(FullMsgId itemId) const {
+	return message(itemId.channel, itemId.msg);
+}
+
+//void historyUnregItem(not_null<HistoryItem*> item) {
+//	const auto data = fetchMsgsData(item->channelId(), false);
+//	if (!data) return;
+//
+//	const auto i = data->find(item->id);
+//	if (i != data->cend()) {
+//		if (i.value() == item) {
+//			data->erase(i);
+//		}
+//	}
+//	const auto j = ::dependentItems.find(item);
+//	if (j != ::dependentItems.cend()) {
+//		DependentItemsSet items;
+//		std::swap(items, j.value());
+//		::dependentItems.erase(j);
+//
+//		for_const (auto dependent, items) {
+//			dependent->dependencyItemRemoved(item);
+//		}
+//	}
+//	item->history()->session().notifications().clearFromItem(item);
+//}
+
+void Session::updateDependentMessages(not_null<HistoryItem*> item) {
+	const auto i = _dependentMessages.find(item);
+	if (i != end(_dependentMessages)) {
+		for (const auto dependent : i->second) {
+			dependent->updateDependencyItem();
+		}
+	}
+	if (App::main()) {
+		App::main()->itemEdited(item);
+	}
+}
+
+void Session::registerDependentMessage(
+		not_null<HistoryItem*> dependent,
+		not_null<HistoryItem*> dependency) {
+	_dependentMessages[dependency].emplace(dependent);
+}
+
+void Session::unregisterDependentMessage(
+		not_null<HistoryItem*> dependent,
+		not_null<HistoryItem*> dependency) {
+	const auto i = _dependentMessages.find(dependency);
+	if (i != end(_dependentMessages)) {
+		if (i->second.remove(dependent) && i->second.empty()) {
+			_dependentMessages.erase(i);
+		}
+	}
+}
+
+void Session::registerMessageRandomId(uint64 randomId, FullMsgId itemId) {
+	_messageByRandomId.emplace(randomId, itemId);
+}
+
+void Session::unregisterMessageRandomId(uint64 randomId) {
+	_messageByRandomId.remove(randomId);
+}
+
+FullMsgId Session::messageIdByRandomId(uint64 randomId) const {
+	const auto i = _messageByRandomId.find(randomId);
+	return (i != end(_messageByRandomId)) ? i->second : FullMsgId();
+}
+
+void Session::registerMessageSentData(
+		uint64 randomId,
+		PeerId peerId,
+		const QString &text) {
+	_sentMessagesData.emplace(randomId, SentData{ peerId, text });
+}
+
+void Session::unregisterMessageSentData(uint64 randomId) {
+	_sentMessagesData.remove(randomId);
+}
+
+Session::SentData Session::messageSentData(uint64 randomId) const {
+	const auto i = _sentMessagesData.find(randomId);
+	return (i != end(_sentMessagesData)) ? i->second : SentData();
+}
+
 NotifySettings &Session::defaultNotifySettings(
 		not_null<const PeerData*> peer) {
 	return peer->isUser()
@@ -1561,7 +1853,7 @@ HistoryItem *Session::addNewMessage(
 	}
 
 	const auto result = history(peerId)->addNewMessage(data, type);
-	if (result && type == NewMessageUnread) {
+	if (result && type == NewMessageType::Unread) {
 		CheckForSwitchInlineButton(result);
 	}
 	return result;
@@ -1665,10 +1957,10 @@ void Session::selfDestructIn(not_null<HistoryItem*> item, crl::time delay) {
 }
 
 void Session::checkSelfDestructItems() {
-	auto now = crl::now();
+	const auto now = crl::now();
 	auto nextDestructIn = crl::time(0);
 	for (auto i = _selfDestructItems.begin(); i != _selfDestructItems.cend();) {
-		if (auto item = App::histItemById(*i)) {
+		if (const auto item = message(*i)) {
 			if (auto destructIn = item->getSelfDestructIn(now)) {
 				if (nextDestructIn > 0) {
 					accumulate_min(nextDestructIn, destructIn);
@@ -3194,7 +3486,7 @@ void Session::insertCheckedServiceNotification(
 				MTPint(),
 				MTPstring(),
 				MTPlong()),
-			NewMessageUnread);
+			NewMessageType::Unread);
 	}
 	sendHistoryChangeNotifications();
 }
diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h
index 136a98a55..355a4261d 100644
--- a/Telegram/SourceFiles/data/data_session.h
+++ b/Telegram/SourceFiles/data/data_session.h
@@ -20,9 +20,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 class Image;
 class HistoryItem;
+class HistoryMessage;
+class HistoryService;
 class BoxContent;
 struct WebPageCollage;
 enum class WebPageType;
+enum class NewMessageType;
 
 namespace HistoryView {
 struct Group;
@@ -58,6 +61,11 @@ class Session final {
 public:
 	using ViewElement = HistoryView::Element;
 
+	struct SentData {
+		PeerId peerId = 0;
+		QString text;
+	};
+
 	explicit Session(not_null<AuthSession*> session);
 	~Session();
 
@@ -314,6 +322,62 @@ public:
 		const Dialogs::Key &key1,
 		const Dialogs::Key &key2);
 
+	template <typename ...Args>
+	not_null<HistoryMessage*> makeMessage(Args &&...args) {
+		return static_cast<HistoryMessage*>(
+			registerMessage(
+				std::make_unique<HistoryMessage>(
+					std::forward<Args>(args)...)));
+	}
+
+	template <typename ...Args>
+	not_null<HistoryService*> makeServiceMessage(Args &&...args) {
+		return static_cast<HistoryService*>(
+			registerMessage(
+				std::make_unique<HistoryService>(
+					std::forward<Args>(args)...)));
+	}
+	void destroyMessage(not_null<HistoryItem*> item);
+
+	// Returns true if item found and it is not detached.
+	bool checkEntitiesAndViewsUpdate(const MTPDmessage &data);
+	void updateEditedMessage(const MTPMessage &data);
+	void processMessages(
+		const QVector<MTPMessage> &data,
+		NewMessageType type);
+	void processMessages(
+		const MTPVector<MTPMessage> &data,
+		NewMessageType type);
+	void processMessagesDeleted(
+		ChannelId channelId,
+		const QVector<MTPint> &data);
+
+	[[nodiscard]] HistoryItem *message(
+		ChannelId channelId,
+		MsgId itemId) const;
+	[[nodiscard]] HistoryItem *message(
+		const ChannelData *channel,
+		MsgId itemId) const;
+	[[nodiscard]] HistoryItem *message(FullMsgId itemId) const;
+
+	void updateDependentMessages(not_null<HistoryItem*> item);
+	void registerDependentMessage(
+		not_null<HistoryItem*> dependent,
+		not_null<HistoryItem*> dependency);
+	void unregisterDependentMessage(
+		not_null<HistoryItem*> dependent,
+		not_null<HistoryItem*> dependency);
+
+	void registerMessageRandomId(uint64 randomId, FullMsgId itemId);
+	void unregisterMessageRandomId(uint64 randomId);
+	[[nodiscard]] FullMsgId messageIdByRandomId(uint64 randomId) const;
+	void registerMessageSentData(
+		uint64 randomId,
+		PeerId peerId,
+		const QString &text);
+	void unregisterMessageSentData(uint64 randomId);
+	[[nodiscard]] SentData messageSentData(uint64 randomId) const;
+
 	void photoLoadSettingsChanged();
 	void documentLoadSettingsChanged();
 
@@ -590,6 +654,8 @@ public:
 	void clearLocalStorage();
 
 private:
+	using Messages = std::unordered_map<MsgId, std::unique_ptr<HistoryItem>>;
+
 	void suggestStartExport();
 
 	void setupContactViewsViewer();
@@ -607,6 +673,11 @@ private:
 		Data::Folder *requestFolder,
 		const MTPDdialogFolder &data);
 
+	const Messages *messagesList(ChannelId channelId) const;
+	not_null<Messages*> messagesListForInsert(ChannelId channelId);
+	HistoryItem *registerMessage(std::unique_ptr<HistoryItem> item);
+	void changeMessageId(ChannelId channel, MsgId wasId, MsgId nowId);
+
 	void photoApplyFields(
 		not_null<PhotoData*> photo,
 		const MTPPhoto &data);
@@ -767,6 +838,15 @@ private:
 	Dialogs::IndexedList _contactsList;
 	Dialogs::IndexedList _contactsNoChatsList;
 
+	Messages _messages;
+	std::map<ChannelId, Messages> _channelMessages;
+	std::map<
+		not_null<HistoryItem*>,
+		base::flat_set<not_null<HistoryItem*>>> _dependentMessages;
+
+	base::flat_map<uint64, FullMsgId> _messageByRandomId;
+	base::flat_map<uint64, SentData> _sentMessagesData;
+
 	base::Timer _selfDestructTimer;
 	std::vector<FullMsgId> _selfDestructItems;
 
diff --git a/Telegram/SourceFiles/data/data_shared_media.cpp b/Telegram/SourceFiles/data/data_shared_media.cpp
index 743827816..e3304688c 100644
--- a/Telegram/SourceFiles/data/data_shared_media.cpp
+++ b/Telegram/SourceFiles/data/data_shared_media.cpp
@@ -331,7 +331,7 @@ std::optional<bool> SharedMediaWithLastSlice::IsLastIsolated(
 		return false;
 	}
 	return LastFullMsgId(ending ? *ending : slice)
-		| [](FullMsgId msgId) {	return App::histItemById(msgId); }
+		| [](FullMsgId msgId) {	return Auth().data().message(msgId); }
 		| [](HistoryItem *item) { return item ? item->media() : nullptr; }
 		| [](Data::Media *media) { return media ? media->photo() : nullptr; }
 		| [](PhotoData *photo) { return photo ? photo->id : 0; }
diff --git a/Telegram/SourceFiles/data/data_types.cpp b/Telegram/SourceFiles/data/data_types.cpp
index d99ca53bf..7261da286 100644
--- a/Telegram/SourceFiles/data/data_types.cpp
+++ b/Telegram/SourceFiles/data/data_types.cpp
@@ -9,10 +9,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "data/data_document.h"
 #include "data/data_file_origin.h"
+#include "data/data_session.h"
 #include "ui/image/image_source.h"
 #include "ui/widgets/input_fields.h"
 #include "storage/cache/storage_cache_types.h"
 #include "base/openssl_help.h"
+#include "auth_session.h"
 
 namespace Data {
 namespace {
@@ -207,9 +209,7 @@ void MessageCursor::applyTo(not_null<Ui::InputField*> field) {
 }
 
 HistoryItem *FileClickHandler::getActionItem() const {
-	return context()
-		? App::histItemById(context())
-		: nullptr;
+	return Auth().data().message(context());
 }
 
 PeerId PeerFromMessage(const MTPmessage &message) {
diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
index 07728439b..660298b89 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
@@ -1840,7 +1840,7 @@ bool InnerWidget::searchReceived(
 			if (lastDate) {
 				const auto item = session().data().addNewMessage(
 					message,
-					NewMessageExisting);
+					NewMessageType::Existing);
 				const auto history = item->history();
 				if (!uniquePeers || !hasHistoryInResults(history)) {
 					_searchResults.push_back(
diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp
index f0b0171c6..c9c1e83a4 100644
--- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp
+++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp
@@ -506,7 +506,7 @@ bool InnerWidget::elementUnderCursor(
 void InnerWidget::elementAnimationAutoplayAsync(
 		not_null<const HistoryView::Element*> view) {
 	crl::on_main(this, [this, msgId = view->data()->fullId()] {
-		if (const auto item = App::histItemById(msgId)) {
+		if (const auto item = Auth().data().message(msgId)) {
 			if (const auto view = viewForItem(item)) {
 				if (const auto media = view->media()) {
 					media->autoplayAnimation();
@@ -1125,9 +1125,9 @@ void InnerWidget::showContextInFolder(not_null<DocumentData*> document) {
 }
 
 void InnerWidget::openContextGif(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
-		if (auto media = item->media()) {
-			if (auto document = media->document()) {
+	if (const auto item = Auth().data().message(itemId)) {
+		if (const auto media = item->media()) {
+			if (const auto document = media->document()) {
 				Core::App().showDocument(document, item);
 			}
 		}
@@ -1135,7 +1135,7 @@ void InnerWidget::openContextGif(FullMsgId itemId) {
 }
 
 void InnerWidget::copyContextText(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		SetClipboardText(HistoryItemText(item));
 	}
 }
diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp
index 83cf32264..2cd53af05 100644
--- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp
+++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp
@@ -365,7 +365,7 @@ void GenerateItems(
 	auto addSimpleServiceMessage = [&](const QString &text, PhotoData *photo = nullptr) {
 		auto message = HistoryService::PreparedText { text };
 		message.links.push_back(fromLink);
-		addPart(new HistoryService(history, idManager->next(), date, message, 0, peerToUser(from->id), photo));
+		addPart(history->owner().makeServiceMessage(history, idManager->next(), date, message, MTPDmessage::Flags(0), peerToUser(from->id), photo));
 	};
 
 	auto createChangeTitle = [&](const MTPDchannelAdminLogEventActionChangeTitle &action) {
@@ -386,7 +386,7 @@ void GenerateItems(
 		auto bodyReplyTo = 0;
 		auto bodyViaBotId = 0;
 		auto newDescription = PrepareText(newValue, QString());
-		auto body = new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), newDescription);
+		auto body = history->owner().makeMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), newDescription);
 		if (!oldValue.isEmpty()) {
 			auto oldDescription = PrepareText(oldValue, QString());
 			body->addLogEntryOriginal(id, lang(lng_admin_log_previous_description), oldDescription);
@@ -407,7 +407,7 @@ void GenerateItems(
 		auto bodyReplyTo = 0;
 		auto bodyViaBotId = 0;
 		auto newLink = newValue.isEmpty() ? TextWithEntities() : PrepareText(Core::App().createInternalLinkFull(newValue), QString());
-		auto body = new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), newLink);
+		auto body = history->owner().makeMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), newLink);
 		if (!oldValue.isEmpty()) {
 			auto oldLink = PrepareText(Core::App().createInternalLinkFull(oldValue), QString());
 			body->addLogEntryOriginal(id, lang(lng_admin_log_previous_link), oldLink);
@@ -513,7 +513,7 @@ void GenerateItems(
 		auto bodyReplyTo = 0;
 		auto bodyViaBotId = 0;
 		auto bodyText = GenerateParticipantChangeText(channel, action.vparticipant);
-		addPart(new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), bodyText));
+		addPart(history->owner().makeMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), bodyText));
 	};
 
 	auto createParticipantToggleBan = [&](const MTPDchannelAdminLogEventActionParticipantToggleBan &action) {
@@ -521,7 +521,7 @@ void GenerateItems(
 		auto bodyReplyTo = 0;
 		auto bodyViaBotId = 0;
 		auto bodyText = GenerateParticipantChangeText(channel, action.vnew_participant, &action.vprev_participant);
-		addPart(new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), bodyText));
+		addPart(history->owner().makeMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), bodyText));
 	};
 
 	auto createParticipantToggleAdmin = [&](const MTPDchannelAdminLogEventActionParticipantToggleAdmin &action) {
@@ -529,7 +529,7 @@ void GenerateItems(
 		auto bodyReplyTo = 0;
 		auto bodyViaBotId = 0;
 		auto bodyText = GenerateParticipantChangeText(channel, action.vnew_participant, &action.vprev_participant);
-		addPart(new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), bodyText));
+		addPart(history->owner().makeMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), bodyText));
 	};
 
 	auto createChangeStickerSet = [&](const MTPDchannelAdminLogEventActionChangeStickerSet &action) {
@@ -550,7 +550,7 @@ void GenerateItems(
 			auto message = HistoryService::PreparedText { text };
 			message.links.push_back(fromLink);
 			message.links.push_back(setLink);
-			addPart(new HistoryService(history, idManager->next(), date, message, 0, peerToUser(from->id)));
+			addPart(history->owner().makeServiceMessage(history, idManager->next(), date, message, MTPDmessage::Flags(0), peerToUser(from->id)));
 		}
 	};
 
@@ -567,7 +567,7 @@ void GenerateItems(
 		auto bodyReplyTo = 0;
 		auto bodyViaBotId = 0;
 		auto bodyText = GenerateDefaultBannedRightsChangeText(channel, action.vnew_banned_rights, action.vprev_banned_rights);
-		addPart(new HistoryMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), bodyText));
+		addPart(history->owner().makeMessage(history, idManager->next(), bodyFlags, bodyReplyTo, bodyViaBotId, date, peerToUser(from->id), QString(), bodyText));
 	};
 
 	auto createStopPoll = [&](const MTPDchannelAdminLogEventActionStopPoll &action) {
diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp
index 328f0b152..1f93f60f3 100644
--- a/Telegram/SourceFiles/history/history.cpp
+++ b/Telegram/SourceFiles/history/history.cpp
@@ -577,7 +577,7 @@ HistoryItem *History::createItem(
 		return nullptr;
 	}
 
-	if (const auto result = App::histItemById(channelId(), messageId)) {
+	if (const auto result = owner().message(channelId(), messageId)) {
 		if (detachExistingItem) {
 			result->removeMainView();
 		}
@@ -620,13 +620,13 @@ not_null<HistoryItem*> History::addNewService(
 HistoryItem *History::addNewMessage(
 		const MTPMessage &msg,
 		NewMessageType type) {
-	if (type == NewMessageExisting) {
+	if (type == NewMessageType::Existing) {
 		return addToHistory(msg);
 	}
 	if (!loadedAtBottom() || peer->migrateTo()) {
 		if (const auto item = addToHistory(msg)) {
 			setLastMessage(item);
-			if (type == NewMessageUnread) {
+			if (type == NewMessageType::Unread) {
 				newItemAdded(item);
 				if (!folderKnown()) {
 					session().api().requestDialogEntry(this);
@@ -643,20 +643,20 @@ HistoryItem *History::addNewMessage(
 HistoryItem *History::addNewToLastBlock(
 		const MTPMessage &msg,
 		NewMessageType type) {
-	Expects(type != NewMessageExisting);
+	Expects(type != NewMessageType::Existing);
 
-	const auto detachExistingItem = (type != NewMessageLast);
+	const auto detachExistingItem = (type != NewMessageType::Last);
 	const auto item = createItem(msg, detachExistingItem);
 	if (!item || item->mainView()) {
 		return item;
 	}
-	const auto newUnreadMessage = (type == NewMessageUnread);
+	const auto newUnreadMessage = (type == NewMessageType::Unread);
 	if (newUnreadMessage) {
 		applyMessageChanges(item, msg);
 	}
 	const auto result = addNewItem(item, newUnreadMessage);
 	checkForLoadedAtTop(result);
-	if (type == NewMessageLast) {
+	if (type == NewMessageType::Last) {
 		// When we add just one last item, like we do while loading dialogs,
 		// we want to remove a single added grouped media, otherwise it will
 		// jump once we open the message history (first we show only that
@@ -698,7 +698,7 @@ not_null<HistoryItem*> History::addNewForwarded(
 		const QString &postAuthor,
 		not_null<HistoryMessage*> original) {
 	return addNewItem(
-		new HistoryMessage(
+		owner().makeMessage(
 			this,
 			id,
 			flags,
@@ -721,7 +721,7 @@ not_null<HistoryItem*> History::addNewDocument(
 		const TextWithEntities &caption,
 		const MTPReplyMarkup &markup) {
 	return addNewItem(
-		new HistoryMessage(
+		owner().makeMessage(
 			this,
 			id,
 			flags,
@@ -748,7 +748,7 @@ not_null<HistoryItem*> History::addNewPhoto(
 		const TextWithEntities &caption,
 		const MTPReplyMarkup &markup) {
 	return addNewItem(
-		new HistoryMessage(
+		owner().makeMessage(
 			this,
 			id,
 			flags,
@@ -774,7 +774,7 @@ not_null<HistoryItem*> History::addNewGame(
 		not_null<GameData*> game,
 		const MTPReplyMarkup &markup) {
 	return addNewItem(
-		new HistoryMessage(
+		owner().makeMessage(
 			this,
 			id,
 			flags,
@@ -2137,7 +2137,7 @@ bool History::isReadyFor(MsgId msgId) {
 		}
 		return loadedAtBottom();
 	}
-	HistoryItem *item = App::histItemById(channelId(), msgId);
+	const auto item = owner().message(channelId(), msgId);
 	return item && (item->history() == this) && item->mainView();
 }
 
@@ -2393,7 +2393,9 @@ void History::setFakeChatListMessageFrom(const MTPmessages_Messages &data) {
 		// Other (non equal to the last one) message not found.
 		return;
 	}
-	const auto item = owner().addNewMessage(*other, NewMessageExisting);
+	const auto item = owner().addNewMessage(
+		*other,
+		NewMessageType::Existing);
 	if (!item || item->isGroupMigrate()) {
 		// Not better than the last one.
 		return;
@@ -2497,7 +2499,7 @@ void History::applyDialog(
 			const auto topMessageId = FullMsgId(
 				peerToChannel(channel->id),
 				data.vtop_message.v);
-			if (const auto item = App::histItemById(topMessageId)) {
+			if (const auto item = owner().message(topMessageId)) {
 				if (item->date() <= channel->date) {
 					session().api().requestSelfParticipant(channel);
 				}
@@ -2592,7 +2594,7 @@ void History::applyDialogTopMessage(MsgId topMessageId) {
 		const auto itemId = FullMsgId(
 			channelId(),
 			topMessageId);
-		if (const auto item = App::histItemById(itemId)) {
+		if (const auto item = owner().message(itemId)) {
 			setLastMessage(item);
 		} else {
 			setLastMessage(nullptr);
diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h
index 2c7bd6802..e5067d2b6 100644
--- a/Telegram/SourceFiles/history/history.h
+++ b/Telegram/SourceFiles/history/history.h
@@ -44,10 +44,10 @@ namespace AdminLog {
 class LocalIdManager;
 } // namespace AdminLog
 
-enum NewMessageType : char {
-	NewMessageUnread,
-	NewMessageLast,
-	NewMessageExisting,
+enum class NewMessageType {
+	Unread,
+	Last,
+	Existing,
 };
 
 enum class UnreadMentionType {
diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp
index 203f5af7e..e98e7ddf4 100644
--- a/Telegram/SourceFiles/history/history_inner_widget.cpp
+++ b/Telegram/SourceFiles/history/history_inner_widget.cpp
@@ -1620,7 +1620,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
 			}
 			if (IsServerMsgId(item->id) && !item->serviceMsg()) {
 				_menu->addAction(lang(lng_context_select_msg), [=] {
-					if (const auto item = App::histItemById(itemId)) {
+					if (const auto item = Auth().data().message(itemId)) {
 						if (const auto view = item->mainView()) {
 							changeSelection(&_selected, item, SelectAction::Select);
 							repaintItem(item);
@@ -1755,7 +1755,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
 			}
 			if (item->id > 0 && !item->serviceMsg()) {
 				_menu->addAction(lang(lng_context_select_msg), [=] {
-					if (const auto item = App::histItemById(itemId)) {
+					if (const auto item = Auth().data().message(itemId)) {
 						if (const auto view = item->mainView()) {
 							changeSelectionAsGroup(&_selected, item, SelectAction::Select);
 							repaintItem(view);
@@ -1770,7 +1770,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
 				&& !App::mousedItem()->data()->serviceMsg()) {
 				const auto itemId = App::mousedItem()->data()->fullId();
 				_menu->addAction(lang(lng_context_select_msg), [=] {
-					if (const auto item = App::histItemById(itemId)) {
+					if (const auto item = Auth().data().message(itemId)) {
 						if (const auto view = item->mainView()) {
 							changeSelectionAsGroup(&_selected, item, SelectAction::Select);
 							repaintItem(item);
@@ -1844,7 +1844,7 @@ void HistoryInner::saveDocumentToFile(
 }
 
 void HistoryInner::openContextGif(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		if (const auto media = item->media()) {
 			if (const auto document = media->document()) {
 				Core::App().showDocument(document, item);
@@ -1854,7 +1854,7 @@ void HistoryInner::openContextGif(FullMsgId itemId) {
 }
 
 void HistoryInner::saveContextGif(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		if (const auto media = item->media()) {
 			if (const auto document = media->document()) {
 				Auth().api().toggleSavedGif(document, item->fullId(), true);
@@ -1864,7 +1864,7 @@ void HistoryInner::saveContextGif(FullMsgId itemId) {
 }
 
 void HistoryInner::copyContextText(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		if (const auto group = Auth().data().groups().find(item)) {
 			SetClipboardText(HistoryGroupText(group));
 		} else {
@@ -2459,7 +2459,7 @@ void HistoryInner::mouseActionUpdate() {
 			dragState = TextState(nullptr, _botAbout->info->text.getState(
 				point - _botAbout->rect.topLeft() - QPoint(st::msgPadding.left(), st::msgPadding.top() + st::botDescSkip + st::msgNameFont->height),
 				_botAbout->width));
-			_dragStateItem = App::histItemById(dragState.itemId);
+			_dragStateItem = Auth().data().message(dragState.itemId);
 			lnkhost = _botAbout.get();
 		}
 	} else if (item) {
@@ -2517,7 +2517,7 @@ void HistoryInner::mouseActionUpdate() {
 						dragState = TextState(
 							nullptr,
 							_scrollDateLink);
-						_dragStateItem = App::histItemById(dragState.itemId);
+						_dragStateItem = Auth().data().message(dragState.itemId);
 						lnkhost = view;
 					}
 				}
@@ -2533,7 +2533,7 @@ void HistoryInner::mouseActionUpdate() {
 				selectingText = false;
 			}
 			dragState = view->textState(m, request);
-			_dragStateItem = App::histItemById(dragState.itemId);
+			_dragStateItem = Auth().data().message(dragState.itemId);
 			lnkhost = view;
 			if (!dragState.link && m.x() >= st::historyPhotoLeft && m.x() < st::historyPhotoLeft + st::msgPhotoSize) {
 				if (auto msg = item->toHistoryMessage()) {
@@ -2553,7 +2553,7 @@ void HistoryInner::mouseActionUpdate() {
 								dragState = TextState(nullptr, from
 									? from->openLink()
 									: hiddenUserpicLink(message->fullId()));
-								_dragStateItem = App::histItemById(dragState.itemId);
+								_dragStateItem = Auth().data().message(dragState.itemId);
 								lnkhost = view;
 								return false;
 							}
@@ -2939,13 +2939,13 @@ void HistoryInner::forwardItem(FullMsgId itemId) {
 }
 
 void HistoryInner::forwardAsGroup(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		Window::ShowForwardMessagesBox(Auth().data().itemOrItsGroup(item));
 	}
 }
 
 void HistoryInner::deleteItem(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		deleteItem(item);
 	}
 }
@@ -2967,7 +2967,7 @@ bool HistoryInner::hasPendingResizedItems() const {
 }
 
 void HistoryInner::deleteAsGroup(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		const auto group = Auth().data().groups().find(item);
 		if (!group) {
 			return deleteItem(item);
@@ -2982,7 +2982,7 @@ void HistoryInner::reportItem(FullMsgId itemId) {
 }
 
 void HistoryInner::reportAsGroup(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		const auto group = Auth().data().groups().find(item);
 		if (!group) {
 			return reportItem(itemId);
@@ -3157,7 +3157,7 @@ not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
 		void elementAnimationAutoplayAsync(
 				not_null<const HistoryView::Element*> view) override {
 			crl::on_main(&Auth(), [msgId = view->data()->fullId()] {
-				if (const auto item = App::histItemById(msgId)) {
+				if (const auto item = Auth().data().message(msgId)) {
 					if (const auto view = item->mainView()) {
 						if (const auto media = view->media()) {
 							media->autoplayAnimation();
diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp
index a0f6faa32..743030d71 100644
--- a/Telegram/SourceFiles/history/history_item.cpp
+++ b/Telegram/SourceFiles/history/history_item.cpp
@@ -69,7 +69,7 @@ not_null<HistoryItem*> CreateUnsupportedMessage(
 		EntityInText(EntityType::Italic, 0, text.text.size()));
 	flags &= ~MTPDmessage::Flag::f_post_author;
 	flags |= MTPDmessage_ClientFlag::f_is_unsupported;
-	return new HistoryMessage(
+	return history->owner().makeMessage(
 		history,
 		msgId,
 		flags,
@@ -169,7 +169,6 @@ HistoryItem::HistoryItem(
 , _from(from ? history->owner().user(from) : history->peer)
 , _flags(flags)
 , _date(date) {
-	App::historyRegItem(this);
 }
 
 TimeId HistoryItem::date() const {
@@ -193,7 +192,7 @@ void HistoryItem::finishEdition(int oldKeyboardTop) {
 	//	}
 	//}
 
-	App::historyUpdateDependent(this);
+	_history->owner().updateDependentMessages(this);
 }
 
 void HistoryItem::setGroupId(MessageGroupId groupId) {
@@ -335,24 +334,7 @@ UserData *HistoryItem::getMessageBot() const {
 };
 
 void HistoryItem::destroy() {
-	if (isLogEntry()) {
-		Assert(!mainView());
-	} else {
-		// All this must be done for all items manually in History::clear()!
-		eraseFromUnreadMentions();
-		if (IsServerMsgId(id)) {
-			if (const auto types = sharedMediaTypes()) {
-				_history->session().storage().remove(Storage::SharedMediaRemoveOne(
-					_history->peer->id,
-					types,
-					id));
-			}
-		} else {
-			_history->session().api().cancelLocalItem(this);
-		}
-		_history->itemRemoved(this);
-	}
-	delete this;
+	_history->owner().destroyMessage(this);
 }
 
 void HistoryItem::refreshMainView() {
@@ -415,11 +397,10 @@ void HistoryItem::indexAsNewItem() {
 void HistoryItem::setRealId(MsgId newId) {
 	Expects(!IsServerMsgId(id));
 
-	App::historyUnregItem(this);
 	const auto oldId = std::exchange(id, newId);
-	App::historyRegItem(this);
+	_history->owner().notifyItemIdChange({ this, oldId });
 
-	// We don't need to call Notify::replyMarkupUpdated(this) and update keyboard
+	// We don't call Notify::replyMarkupUpdated(this) and update keyboard
 	// in history widget, because it can't exist for an outgoing message.
 	// Only inline keyboards can be in outgoing messages.
 	if (const auto markup = inlineReplyMarkup()) {
@@ -428,7 +409,6 @@ void HistoryItem::setRealId(MsgId newId) {
 		}
 	}
 
-	_history->owner().notifyItemIdChange({ this, oldId });
 	_history->owner().requestItemRepaint(this);
 }
 
@@ -758,7 +738,6 @@ void HistoryItem::drawInDialog(
 
 HistoryItem::~HistoryItem() {
 	_history->owner().notifyItemRemoved(this);
-	App::historyUnregItem(this);
 }
 
 QDateTime ItemDateTime(not_null<const HistoryItem*> item) {
@@ -780,7 +759,7 @@ ClickHandlerPtr goToMessageClickHandler(
 		FullMsgId returnToId) {
 	return std::make_shared<LambdaClickHandler>([=] {
 		if (const auto main = App::main()) {
-			if (const auto returnTo = App::histItemById(returnToId)) {
+			if (const auto returnTo = peer->owner().message(returnToId)) {
 				if (returnTo->history()->peer == peer) {
 					main->pushReplyReturn(returnTo);
 				}
@@ -813,7 +792,7 @@ not_null<HistoryItem*> HistoryItem::Create(
 			const auto text = HistoryService::PreparedText {
 				lang(lng_message_empty)
 			};
-			return new HistoryService(
+			return history->owner().makeServiceMessage(
 				history,
 				data.vid.v,
 				data.vdate.v,
@@ -821,18 +800,18 @@ not_null<HistoryItem*> HistoryItem::Create(
 				data.vflags.v,
 				data.has_from_id() ? data.vfrom_id.v : UserId(0));
 		} else if (checked == MediaCheckResult::HasTimeToLive) {
-			return new HistoryService(history, data);
+			return history->owner().makeServiceMessage(history, data);
 		}
-		return new HistoryMessage(history, data);
+		return history->owner().makeMessage(history, data);
 	}, [&](const MTPDmessageService &data) -> HistoryItem* {
 		if (data.vaction.type() == mtpc_messageActionPhoneCall) {
-			return new HistoryMessage(history, data);
+			return history->owner().makeMessage(history, data);
 		}
-		return new HistoryService(history, data);
+		return history->owner().makeServiceMessage(history, data);
 	}, [&](const MTPDmessageEmpty &data) -> HistoryItem* {
 		const auto text = HistoryService::PreparedText{
 			lang(lng_message_empty)
 		};
-		return new HistoryService(history, data.vid.v, TimeId(0), text);
+		return history->owner().makeServiceMessage(history, data.vid.v, TimeId(0), text);
 	});
 }
diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp
index 748e5af9c..04f087379 100644
--- a/Telegram/SourceFiles/history/history_item_components.cpp
+++ b/Telegram/SourceFiles/history/history_item_components.cpp
@@ -165,14 +165,18 @@ bool HistoryMessageReply::updateData(
 		}
 	}
 	if (!replyToMsg) {
-		replyToMsg = App::histItemById(holder->channelId(), replyToMsgId);
+		replyToMsg = holder->history()->owner().message(
+			holder->channelId(),
+			replyToMsgId);
 		if (replyToMsg) {
 			if (replyToMsg->isEmpty()) {
 				// Really it is deleted.
 				replyToMsg = nullptr;
 				force = true;
 			} else {
-				App::historyRegDependency(holder, replyToMsg);
+				holder->history()->owner().registerDependentMessage(
+					holder,
+					replyToMsg);
 			}
 		}
 	}
@@ -211,7 +215,9 @@ void HistoryMessageReply::setReplyToLinkFrom(
 void HistoryMessageReply::clearData(not_null<HistoryMessage*> holder) {
 	replyToVia = nullptr;
 	if (replyToMsg) {
-		App::historyUnregDependency(holder, replyToMsg);
+		holder->history()->owner().unregisterDependentMessage(
+			holder,
+			replyToMsg);
 		replyToMsg = nullptr;
 	}
 	replyToMsgId = 0;
@@ -359,10 +365,10 @@ QString ReplyMarkupClickHandler::copyToClipboardContextItemText() const {
 // Note: it is possible that we will point to the different button
 // than the one was used when constructing the handler, but not a big deal.
 const HistoryMessageMarkupButton *ReplyMarkupClickHandler::getButton() const {
-	if (auto item = App::histItemById(_itemId)) {
-		if (auto markup = item->Get<HistoryMessageReplyMarkup>()) {
+	if (const auto item = Auth().data().message(_itemId)) {
+		if (const auto markup = item->Get<HistoryMessageReplyMarkup>()) {
 			if (_row < markup->rows.size()) {
-				auto &row = markup->rows[_row];
+				const auto &row = markup->rows[_row];
 				if (_column < row.size()) {
 					return &row[_column];
 				}
@@ -373,7 +379,7 @@ const HistoryMessageMarkupButton *ReplyMarkupClickHandler::getButton() const {
 }
 
 void ReplyMarkupClickHandler::onClickImpl() const {
-	if (const auto item = App::histItemById(_itemId)) {
+	if (const auto item = Auth().data().message(_itemId)) {
 		App::activateBotCommand(item, _row, _column);
 	}
 }
diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp
index 22d2aa67d..2ccd0e654 100644
--- a/Telegram/SourceFiles/history/history_message.cpp
+++ b/Telegram/SourceFiles/history/history_message.cpp
@@ -102,8 +102,8 @@ void FastShareMessage(not_null<HistoryItem*> item) {
 		&& (item->media()->game() != nullptr);
 	const auto canCopyLink = item->hasDirectLink() || isGame;
 
-	auto copyCallback = [data]() {
-		if (auto item = App::histItemById(data->msgIds[0])) {
+	auto copyCallback = [=]() {
+		if (auto item = Auth().data().message(data->msgIds[0])) {
 			if (item->hasDirectLink()) {
 				HistoryView::CopyPostLink(item->fullId());
 			} else if (const auto bot = item->getMessageBot()) {
@@ -230,7 +230,7 @@ void FastShareMessage(not_null<HistoryItem*> item) {
 Fn<void(ChannelData*, MsgId)> HistoryDependentItemCallback(
 		const FullMsgId &msgId) {
 	return [dependent = msgId](ChannelData *channel, MsgId msgId) {
-		if (auto item = App::histItemById(dependent)) {
+		if (auto item = Auth().data().message(dependent)) {
 			item->updateDependencyItem();
 		}
 	};
diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp
index a7b7b2bf7..2437de446 100644
--- a/Telegram/SourceFiles/history/history_service.cpp
+++ b/Telegram/SourceFiles/history/history_service.cpp
@@ -330,14 +330,14 @@ bool HistoryService::updateDependent(bool force) {
 	}
 	auto gotDependencyItem = false;
 	if (!dependent->msg) {
-		dependent->msg = App::histItemById(channelId(), dependent->msgId);
+		dependent->msg = history()->owner().message(channelId(), dependent->msgId);
 		if (dependent->msg) {
 			if (dependent->msg->isEmpty()) {
 				// Really it is deleted.
 				dependent->msg = nullptr;
 				force = true;
 			} else {
-				App::historyRegDependency(this, dependent->msg);
+				history()->owner().registerDependentMessage(this, dependent->msg);
 				gotDependencyItem = true;
 			}
 		}
@@ -732,13 +732,13 @@ void HistoryService::updateDependentText() {
 		// #TODO feeds search results
 		main->repaintDialogRow({ history(), fullId() });
 	}
-	App::historyUpdateDependent(this);
+	history()->owner().updateDependentMessages(this);
 }
 
 void HistoryService::clearDependency() {
-	if (auto dependent = GetDependentData()) {
+	if (const auto dependent = GetDependentData()) {
 		if (dependent->msg) {
-			App::historyUnregDependency(this, dependent->msg);
+			history()->owner().unregisterDependentMessage(this, dependent->msg);
 		}
 	}
 }
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index 4fe11d1dc..40b50983c 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -639,8 +639,8 @@ void HistoryWidget::scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId
 		return;
 	}
 
-	auto from = App::histItemById(fromId);
-	auto to = App::histItemById(toId);
+	auto from = Auth().data().message(fromId);
+	auto to = Auth().data().message(toId);
 	if (!from || !to) {
 		return;
 	}
@@ -668,7 +668,7 @@ void HistoryWidget::animatedScrollToItem(MsgId msgId) {
 		updateListSize();
 	}
 
-	auto to = App::histItemById(_channel, msgId);
+	auto to = Auth().data().message(_channel, msgId);
 	if (_list->itemTop(to) < 0) {
 		return;
 	}
@@ -729,7 +729,7 @@ void HistoryWidget::animatedScrollToY(int scrollTo, HistoryItem *attachTo) {
 void HistoryWidget::scrollToAnimationCallback(
 		FullMsgId attachToId,
 		int relativeTo) {
-	auto itemTop = _list->itemTop(App::histItemById(attachToId));
+	auto itemTop = _list->itemTop(Auth().data().message(attachToId));
 	if (itemTop < 0) {
 		_scrollToAnimation.stop();
 	} else {
@@ -1405,18 +1405,18 @@ void HistoryWidget::setReplyReturns(PeerId peer, const QList<MsgId> &replyReturn
 	if (_replyReturns.isEmpty()) {
 		_replyReturn = nullptr;
 	} else if (_replyReturns.back() < 0 && -_replyReturns.back() < ServerMaxMsgId) {
-		_replyReturn = App::histItemById(0, -_replyReturns.back());
+		_replyReturn = Auth().data().message(0, -_replyReturns.back());
 	} else {
-		_replyReturn = App::histItemById(_channel, _replyReturns.back());
+		_replyReturn = Auth().data().message(_channel, _replyReturns.back());
 	}
 	while (!_replyReturns.isEmpty() && !_replyReturn) {
 		_replyReturns.pop_back();
 		if (_replyReturns.isEmpty()) {
 			_replyReturn = nullptr;
 		} else if (_replyReturns.back() < 0 && -_replyReturns.back() < ServerMaxMsgId) {
-			_replyReturn = App::histItemById(0, -_replyReturns.back());
+			_replyReturn = Auth().data().message(0, -_replyReturns.back());
 		} else {
-			_replyReturn = App::histItemById(_channel, _replyReturns.back());
+			_replyReturn = Auth().data().message(_channel, _replyReturns.back());
 		}
 	}
 }
@@ -1428,9 +1428,9 @@ void HistoryWidget::calcNextReplyReturn() {
 		if (_replyReturns.isEmpty()) {
 			_replyReturn = nullptr;
 		} else if (_replyReturns.back() < 0 && -_replyReturns.back() < ServerMaxMsgId) {
-			_replyReturn = App::histItemById(0, -_replyReturns.back());
+			_replyReturn = Auth().data().message(0, -_replyReturns.back());
 		} else {
-			_replyReturn = App::histItemById(_channel, _replyReturns.back());
+			_replyReturn = Auth().data().message(_channel, _replyReturns.back());
 		}
 	}
 	if (!_replyReturn) {
@@ -2765,7 +2765,7 @@ void HistoryWidget::saveEditMsg() {
 	TextUtilities::PrepareForSending(left, prepareFlags);
 
 	if (!TextUtilities::CutPart(sending, left, MaxMessageSize)) {
-		if (const auto item = App::histItemById(_channel, _editMsgId)) {
+		if (const auto item = Auth().data().message(_channel, _editMsgId)) {
 			const auto suggestModerateActions = false;
 			Ui::show(Box<DeleteMessagesBox>(item, suggestModerateActions));
 		} else {
@@ -3322,7 +3322,7 @@ void HistoryWidget::botCallbackDone(
 		BotCallbackInfo info,
 		const MTPmessages_BotCallbackAnswer &answer,
 		mtpRequestId req) {
-	auto item = App::histItemById(info.msgId);
+	auto item = Auth().data().message(info.msgId);
 	if (item) {
 		if (const auto markup = item->Get<HistoryMessageReplyMarkup>()) {
 			if (info.row < markup->rows.size()
@@ -3362,7 +3362,7 @@ bool HistoryWidget::botCallbackFail(
 		const RPCError &error,
 		mtpRequestId req) {
 	// show error?
-	if (const auto item = App::histItemById(info.msgId)) {
+	if (const auto item = Auth().data().message(info.msgId)) {
 		if (const auto markup = item->Get<HistoryMessageReplyMarkup>()) {
 			if (info.row < markup->rows.size()
 				&& info.col < markup->rows[info.row].size()) {
@@ -3648,7 +3648,7 @@ void HistoryWidget::onKbToggle(bool manual) {
 		_field->setMaxHeight(st::historyComposeFieldMaxHeight);
 
 		_kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard->forceReply())
-			? App::histItemById(_keyboard->forMsgId())
+			? Auth().data().message(_keyboard->forMsgId())
 			: nullptr;
 		if (_kbReplyTo && !_editMsgId && !_replyToId && fieldEnabled) {
 			updateReplyToName();
@@ -3667,7 +3667,7 @@ void HistoryWidget::onKbToggle(bool manual) {
 		_field->setMaxHeight(st::historyComposeFieldMaxHeight - maxh);
 
 		_kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard->forceReply())
-			? App::histItemById(_keyboard->forMsgId())
+			? Auth().data().message(_keyboard->forMsgId())
 			: nullptr;
 		if (_kbReplyTo && !_editMsgId && !_replyToId) {
 			updateReplyToName();
@@ -4262,7 +4262,7 @@ void HistoryWidget::sendFileConfirmed(
 	file->edit = isEditing;
 	Auth().uploader().upload(newId, file);
 
-	const auto itemToEdit = isEditing ? App::histItemById(newId) : nullptr;
+	const auto itemToEdit = isEditing ? Auth().data().message(newId) : nullptr;
 
 	const auto history = Auth().data().history(file->to.peer);
 	const auto peer = history->peer;
@@ -4347,7 +4347,7 @@ void HistoryWidget::sendFileConfirmed(
 			itemToEdit->savePreviousMedia();
 			itemToEdit->applyEdition(mtpMessage.c_message());
 		} else {
-			history->addNewMessage(mtpMessage, NewMessageUnread);
+			history->addNewMessage(mtpMessage, NewMessageType::Unread);
 		}
 	} else if (file->type == SendMediaType::File) {
 		const auto documentFlags = MTPDmessageMediaDocument::Flag::f_document | 0;
@@ -4378,7 +4378,7 @@ void HistoryWidget::sendFileConfirmed(
 			itemToEdit->savePreviousMedia();
 			itemToEdit->applyEdition(mtpMessage.c_message());
 		} else {
-			history->addNewMessage(mtpMessage, NewMessageUnread);
+			history->addNewMessage(mtpMessage, NewMessageType::Unread);
 		}
 	} else if (file->type == SendMediaType::Audio) {
 		if (!peer->isChannel() || peer->isMegagroup()) {
@@ -4407,7 +4407,7 @@ void HistoryWidget::sendFileConfirmed(
 				MTPint(),
 				MTP_string(messagePostAuthor),
 				MTP_long(groupId)),
-			NewMessageUnread);
+			NewMessageType::Unread);
 		// Voices can't be edited.
 	} else {
 		Unexpected("Type in sendFilesConfirmed.");
@@ -4464,7 +4464,7 @@ void HistoryWidget::thumbDocumentUploaded(
 }
 
 void HistoryWidget::photoProgress(const FullMsgId &newId) {
-	if (const auto item = App::histItemById(newId)) {
+	if (const auto item = Auth().data().message(newId)) {
 		const auto photo = item->media()
 			? item->media()->photo()
 			: nullptr;
@@ -4474,7 +4474,7 @@ void HistoryWidget::photoProgress(const FullMsgId &newId) {
 }
 
 void HistoryWidget::documentProgress(const FullMsgId &newId) {
-	if (const auto item = App::histItemById(newId)) {
+	if (const auto item = Auth().data().message(newId)) {
 		const auto media = item->media();
 		const auto document = media ? media->document() : nullptr;
 		const auto sendAction = (document && document->isVoiceMessage())
@@ -4493,7 +4493,7 @@ void HistoryWidget::documentProgress(const FullMsgId &newId) {
 }
 
 void HistoryWidget::photoFailed(const FullMsgId &newId) {
-	if (const auto item = App::histItemById(newId)) {
+	if (const auto item = Auth().data().message(newId)) {
 		updateSendAction(
 			item->history(),
 			SendAction::Type::UploadPhoto,
@@ -4503,7 +4503,7 @@ void HistoryWidget::photoFailed(const FullMsgId &newId) {
 }
 
 void HistoryWidget::documentFailed(const FullMsgId &newId) {
-	if (const auto item = App::histItemById(newId)) {
+	if (const auto item = Auth().data().message(newId)) {
 		const auto media = item->media();
 		const auto document = media ? media->document() : nullptr;
 		const auto sendAction = (document && document->isVoiceMessage())
@@ -5021,7 +5021,7 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
 		changed = _keyboard->updateMarkup(_replyEditMsg, force);
 	} else {
 		const auto keyboardItem = _history->lastKeyboardId
-			? App::histItemById(_channel, _history->lastKeyboardId)
+			? Auth().data().message(_channel, _history->lastKeyboardId)
 			: nullptr;
 		changed = _keyboard->updateMarkup(keyboardItem, force);
 	}
@@ -5051,7 +5051,7 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
 			_field->setMaxHeight(st::historyComposeFieldMaxHeight - maxh);
 			_kbShown = hasMarkup;
 			_kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard->forceReply())
-				? App::histItemById(_keyboard->forMsgId())
+				? Auth().data().message(_keyboard->forMsgId())
 				: nullptr;
 			if (_kbReplyTo && !_replyToId) {
 				updateReplyToName();
@@ -5287,7 +5287,7 @@ void HistoryWidget::replyToPreviousMessage() {
 	const auto fullId = FullMsgId(
 		_history->channelId(),
 		_replyToId);
-	if (const auto item = App::histItemById(fullId)) {
+	if (const auto item = Auth().data().message(fullId)) {
 		if (const auto view = item->mainView()) {
 			if (const auto previousView = view->previousInBlocks()) {
 				const auto previous = previousView->data();
@@ -5308,7 +5308,7 @@ void HistoryWidget::replyToNextMessage() {
 	const auto fullId = FullMsgId(
 		_history->channelId(),
 		_replyToId);
-	if (const auto item = App::histItemById(fullId)) {
+	if (const auto item = Auth().data().message(fullId)) {
 		if (const auto view = item->mainView()) {
 			if (const auto nextView = view->nextInBlocks()) {
 				const auto next = nextView->data();
@@ -5392,7 +5392,7 @@ void HistoryWidget::updatePinnedBar(bool force) {
 
 	Assert(_history != nullptr);
 	if (!_pinnedBar->msg) {
-		_pinnedBar->msg = App::histItemById(_history->channelId(), _pinnedBar->msgId);
+		_pinnedBar->msg = Auth().data().message(_history->channelId(), _pinnedBar->msgId);
 	}
 	if (_pinnedBar->msg) {
 		_pinnedBar->text.setText(
@@ -5594,7 +5594,7 @@ bool HistoryWidget::sendExistingPhoto(
 		_history->sendRequestId);
 	App::main()->finishForwarding(_history);
 
-	App::historyRegRandom(randomId, newId);
+	_history->owner().registerMessageRandomId(randomId, newId);
 
 	hideSelectorControlsAnimated();
 
@@ -5626,7 +5626,7 @@ void HistoryWidget::clearFieldText(
 }
 
 void HistoryWidget::replyToMessage(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		replyToMessage(item);
 	}
 }
@@ -5679,7 +5679,7 @@ void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
 }
 
 void HistoryWidget::editMessage(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		editMessage(item);
 	}
 }
@@ -5749,7 +5749,7 @@ void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
 }
 
 void HistoryWidget::pinMessage(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		if (item->canPin()) {
 			Ui::show(Box<PinMessageBox>(item->history()->peer, item->id));
 		}
@@ -6222,9 +6222,9 @@ void HistoryWidget::clearSelected() {
 
 HistoryItem *HistoryWidget::getItemFromHistoryOrMigrated(MsgId genericMsgId) const {
 	if (genericMsgId < 0 && -genericMsgId < ServerMaxMsgId && _migrated) {
-		return App::histItemById(_migrated->channelId(), -genericMsgId);
+		return Auth().data().message(_migrated->channelId(), -genericMsgId);
 	}
-	return App::histItemById(_channel, genericMsgId);
+	return Auth().data().message(_channel, genericMsgId);
 }
 
 MessageIdsList HistoryWidget::getSelectedItems() const {
@@ -6286,7 +6286,7 @@ void HistoryWidget::updateReplyEditTexts(bool force) {
 		}
 	}
 	if (!_replyEditMsg) {
-		_replyEditMsg = App::histItemById(_channel, _editMsgId ? _editMsgId : _replyToId);
+		_replyEditMsg = Auth().data().message(_channel, _editMsgId ? _editMsgId : _replyToId);
 	}
 	if (_replyEditMsg) {
 		updateReplyEditText(_replyEditMsg);
diff --git a/Telegram/SourceFiles/history/media/history_media_contact.cpp b/Telegram/SourceFiles/history/media/history_media_contact.cpp
index bc03593b1..b0a897981 100644
--- a/Telegram/SourceFiles/history/media/history_media_contact.cpp
+++ b/Telegram/SourceFiles/history/media/history_media_contact.cpp
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "data/data_session.h"
 #include "data/data_user.h"
 #include "data/data_media_types.h"
+#include "auth_session.h"
 #include "styles/style_history.h"
 
 namespace {
@@ -42,7 +43,7 @@ ClickHandlerPtr sendMessageClickHandler(PeerData *peer) {
 
 ClickHandlerPtr addContactClickHandler(not_null<HistoryItem*> item) {
 	return std::make_shared<LambdaClickHandler>([fullId = item->fullId()] {
-		if (const auto item = App::histItemById(fullId)) {
+		if (const auto item = Auth().data().message(fullId)) {
 			if (const auto media = item->media()) {
 				if (const auto contact = media->sharedContact()) {
 					Ui::show(Box<AddContactBox>(
diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp
index 31200d5ad..16fc759d4 100644
--- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp
@@ -105,7 +105,7 @@ void AddPhotoActions(
 }
 
 void OpenGif(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		if (const auto media = item->media()) {
 			if (const auto document = media->document()) {
 				Core::App().showDocument(document, item);
@@ -264,7 +264,7 @@ bool AddForwardMessageAction(
 	}
 	const auto itemId = item->fullId();
 	menu->addAction(lang(lng_context_forward_msg), [=] {
-		if (const auto item = App::histItemById(itemId)) {
+		if (const auto item = Auth().data().message(itemId)) {
 			Window::ShowForwardMessagesBox(asGroup
 				? Auth().data().itemOrItsGroup(item)
 				: MessageIdsList{ 1, itemId });
@@ -329,7 +329,7 @@ bool AddDeleteMessageAction(
 	}
 	const auto itemId = item->fullId();
 	menu->addAction(lang(lng_context_delete_msg), [=] {
-		if (const auto item = App::histItemById(itemId)) {
+		if (const auto item = Auth().data().message(itemId)) {
 			if (asGroup) {
 				if (const auto group = Auth().data().groups().find(item)) {
 					Ui::show(Box<DeleteMessagesBox>(
@@ -385,7 +385,7 @@ bool AddSelectMessageAction(
 	const auto itemId = item->fullId();
 	const auto asGroup = (request.pointState != PointState::GroupPart);
 	menu->addAction(lang(lng_context_select_msg), [=] {
-		if (const auto item = App::histItemById(itemId)) {
+		if (const auto item = Auth().data().message(itemId)) {
 			if (asGroup) {
 				list->selectItemAsGroup(item);
 			} else {
@@ -490,7 +490,7 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
 		if (!link && (view->hasVisibleText() || mediaHasTextForCopy)) {
 			const auto asGroup = (request.pointState != PointState::GroupPart);
 			result->addAction(lang(lng_context_copy_text), [=] {
-				if (const auto item = App::histItemById(itemId)) {
+				if (const auto item = Auth().data().message(itemId)) {
 					if (asGroup) {
 						if (const auto group = Auth().data().groups().find(item)) {
 							SetClipboardText(HistoryGroupText(group));
@@ -509,7 +509,7 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
 }
 
 void CopyPostLink(FullMsgId itemId) {
-	const auto item = App::histItemById(itemId);
+	const auto item = Auth().data().message(itemId);
 	if (!item || !item->hasDirectLink()) {
 		return;
 	}
@@ -527,7 +527,7 @@ void CopyPostLink(FullMsgId itemId) {
 void StopPoll(FullMsgId itemId) {
 	const auto stop = [=] {
 		Ui::hideLayer();
-		if (const auto item = App::histItemById(itemId)) {
+		if (const auto item = Auth().data().message(itemId)) {
 			item->history()->session().api().closePoll(item);
 		}
 	};
diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp
index 018e8bf15..2ce8990d8 100644
--- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp
@@ -317,7 +317,7 @@ void ListWidget::refreshRows() {
 	_items.clear();
 	_items.reserve(_slice.ids.size());
 	for (const auto &fullId : _slice.ids) {
-		if (const auto item = App::histItemById(fullId)) {
+		if (const auto item = Auth().data().message(fullId)) {
 			_items.push_back(enforceViewForItem(item));
 		}
 	}
@@ -398,7 +398,7 @@ void ListWidget::animatedScrollTo(
 void ListWidget::scrollToAnimationCallback(
 		FullMsgId attachToId,
 		int relativeTo) {
-	const auto attachTo = App::histItemById(attachToId);
+	const auto attachTo = Auth().data().message(attachToId);
 	const auto attachToView = viewForItem(attachTo);
 	if (!attachToView) {
 		_scrollToAnimation.stop();
@@ -424,7 +424,7 @@ bool ListWidget::isBelowPosition(Data::MessagePosition position) const {
 }
 
 void ListWidget::highlightMessage(FullMsgId itemId) {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		if (const auto view = viewForItem(item)) {
 			_highlightStart = crl::now();
 			_highlightedMessageId = itemId;
@@ -436,7 +436,7 @@ void ListWidget::highlightMessage(FullMsgId itemId) {
 }
 
 void ListWidget::updateHighlightedMessage() {
-	if (const auto item = App::histItemById(_highlightedMessageId)) {
+	if (const auto item = Auth().data().message(_highlightedMessageId)) {
 		if (const auto view = viewForItem(item)) {
 			repaintItem(view);
 			auto duration = st::activeFadeInDuration + st::activeFadeOutDuration;
@@ -488,7 +488,7 @@ void ListWidget::restoreScrollState() {
 }
 
 Element *ListWidget::viewForItem(FullMsgId itemId) const {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		return viewForItem(item);
 	}
 	return nullptr;
@@ -1382,7 +1382,7 @@ void ListWidget::applyDragSelection(SelectedMap &applyTo) const {
 			if (applyTo.size() >= MaxSelectedItems) {
 				break;
 			} else if (!applyTo.contains(itemId)) {
-				if (const auto item = App::histItemById(itemId)) {
+				if (const auto item = Auth().data().message(itemId)) {
 					addToSelection(applyTo, item);
 				}
 			}
@@ -1440,7 +1440,7 @@ TextForMimeData ListWidget::getSelectedText() const {
 	};
 
 	for (const auto [itemId, data] : selected) {
-		if (const auto item = App::histItemById(itemId)) {
+		if (const auto item = Auth().data().message(itemId)) {
 			if (const auto group = Auth().data().groups().find(item)) {
 				if (groups.contains(group)) {
 					continue;
@@ -1683,7 +1683,7 @@ void ListWidget::updateDragSelection() {
 	} else if (_items.empty() || !_overElement || !_selectEnabled) {
 		return;
 	}
-	const auto pressItem = App::histItemById(_pressState.itemId);
+	const auto pressItem = Auth().data().message(_pressState.itemId);
 	if (!pressItem) {
 		return;
 	}
@@ -2000,7 +2000,7 @@ void ListWidget::mouseActionFinish(
 		return;
 	}
 	if (needItemSelectionToggle) {
-		if (const auto item = App::histItemById(pressState.itemId)) {
+		if (const auto item = Auth().data().message(pressState.itemId)) {
 			clearTextSelection();
 			if (pressState.pointState == PointState::GroupPart) {
 				changeSelection(
@@ -2133,7 +2133,7 @@ void ListWidget::mouseActionUpdate() {
 						dragState = TextState(
 							nullptr,
 							_scrollDateLink);
-						_overItemExact = App::histItemById(dragState.itemId);
+						_overItemExact = Auth().data().message(dragState.itemId);
 						lnkhost = view;
 					}
 				}
@@ -2143,7 +2143,7 @@ void ListWidget::mouseActionUpdate() {
 		});
 		if (!dragState.link) {
 			dragState = view->textState(itemPoint, request);
-			_overItemExact = App::histItemById(dragState.itemId);
+			_overItemExact = Auth().data().message(dragState.itemId);
 			lnkhost = view;
 			if (!dragState.link
 				&& itemPoint.x() >= st::historyPhotoLeft
@@ -2164,7 +2164,7 @@ void ListWidget::mouseActionUpdate() {
 							dragState = TextState(nullptr, from
 								? from->openLink()
 								: hiddenUserpicLink(message->fullId()));
-							_overItemExact = App::histItemById(dragState.itemId);
+							_overItemExact = Auth().data().message(dragState.itemId);
 							lnkhost = view;
 							return false;
 						}
@@ -2220,7 +2220,7 @@ void ListWidget::mouseActionUpdate() {
 	// Voice message seek support.
 	if (_pressState.pointState != PointState::Outside
 		&& ClickHandler::getPressed()) {
-		if (const auto item = App::histItemById(_pressState.itemId)) {
+		if (const auto item = Auth().data().message(_pressState.itemId)) {
 			if (const auto view = viewForItem(item)) {
 				auto adjustedPoint = mapPointToItem(point, view);
 				view->updatePressed(adjustedPoint);
@@ -2261,7 +2261,7 @@ std::unique_ptr<QMimeData> ListWidget::prepareDrag() {
 		return nullptr;
 	}
 
-	const auto pressedItem = App::histItemById(_pressState.itemId);
+	const auto pressedItem = Auth().data().message(_pressState.itemId);
 	const auto pressedView = viewForItem(pressedItem);
 	const auto uponSelected = pressedView && isInsideSelection(
 		pressedView,
diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp
index a7680b416..c0a047f2b 100644
--- a/Telegram/SourceFiles/history/view/history_view_message.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_message.cpp
@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "lang/lang_keys.h"
 #include "mainwidget.h"
 #include "mainwindow.h"
+#include "auth_session.h"
 #include "window/window_controller.h"
 #include "layout.h"
 #include "styles/style_widgets.h"
@@ -1456,7 +1457,7 @@ ClickHandlerPtr Message::rightActionLink() const {
 		const auto savedFromPeer = forwarded ? forwarded->savedFromPeer : nullptr;
 		const auto savedFromMsgId = forwarded ? forwarded->savedFromMsgId : 0;
 		_rightActionLink = std::make_shared<LambdaClickHandler>([=] {
-			if (const auto item = App::histItemById(itemId)) {
+			if (const auto item = Auth().data().message(itemId)) {
 				if (savedFromPeer && savedFromMsgId) {
 					App::wnd()->controller()->showPeerHistory(
 						savedFromPeer,
@@ -1475,7 +1476,7 @@ ClickHandlerPtr Message::fastReplyLink() const {
 	if (!_fastReplyLink) {
 		const auto itemId = data()->fullId();
 		_fastReplyLink = std::make_shared<LambdaClickHandler>([=] {
-			if (const auto item = App::histItemById(itemId)) {
+			if (const auto item = Auth().data().message(itemId)) {
 				if (const auto main = App::main()) {
 					main->replyToItem(item);
 				}
diff --git a/Telegram/SourceFiles/info/info_top_bar.cpp b/Telegram/SourceFiles/info/info_top_bar.cpp
index b83a9b8d8..06e660818 100644
--- a/Telegram/SourceFiles/info/info_top_bar.cpp
+++ b/Telegram/SourceFiles/info/info_top_bar.cpp
@@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "boxes/confirm_box.h"
 #include "boxes/peer_list_controllers.h"
 #include "mainwidget.h"
+#include "auth_session.h"
 #include "ui/widgets/buttons.h"
 #include "ui/widgets/labels.h"
 #include "ui/widgets/input_fields.h"
@@ -25,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/wrap/padding_wrap.h"
 #include "ui/search_field_controller.h"
 #include "window/window_peer_menu.h"
+#include "data/data_session.h"
 #include "data/data_channel.h"
 #include "data/data_user.h"
 #include "styles/style_info.h"
@@ -511,8 +513,8 @@ MessageIdsList TopBar::collectItems() const {
 		_selectedItems.list
 	) | ranges::view::transform([](auto &&item) {
 		return item.msgId;
-	}) | ranges::view::filter([](const FullMsgId &msgId) {
-		return App::histItemById(msgId) != nullptr;
+	}) | ranges::view::filter([](FullMsgId msgId) {
+		return Auth().data().message(msgId) != nullptr;
 	}) | ranges::to_vector;
 }
 
diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp
index f4c57efc0..bd6dff00d 100644
--- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp
+++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp
@@ -838,7 +838,7 @@ BaseLayout *ListWidget::getExistingLayout(
 std::unique_ptr<BaseLayout> ListWidget::createLayout(
 		UniversalMsgId universalId,
 		Type type) {
-	auto item = App::histItemById(computeFullId(universalId));
+	auto item = Auth().data().message(computeFullId(universalId));
 	if (!item) {
 		return nullptr;
 	}
@@ -1179,7 +1179,7 @@ void ListWidget::showContextMenu(
 		mouseActionUpdate(e->globalPos());
 	}
 
-	auto item = App::histItemById(computeFullId(_overState.itemId));
+	auto item = Auth().data().message(computeFullId(_overState.itemId));
 	if (!item || !_overState.inside) {
 		return;
 	}
@@ -1228,7 +1228,7 @@ void ListWidget::showContextMenu(
 	_contextMenu->addAction(
 		lang(lng_context_to_msg),
 		[itemFullId] {
-			if (auto item = App::histItemById(itemFullId)) {
+			if (auto item = Auth().data().message(itemFullId)) {
 				Ui::showPeerHistoryAtItem(item);
 			}
 		});
@@ -1380,7 +1380,7 @@ void ListWidget::forwardSelected() {
 }
 
 void ListWidget::forwardItem(UniversalMsgId universalId) {
-	if (const auto item = App::histItemById(computeFullId(universalId))) {
+	if (const auto item = Auth().data().message(computeFullId(universalId))) {
 		forwardItems({ 1, item->fullId() });
 	}
 }
@@ -1408,7 +1408,7 @@ void ListWidget::deleteSelected() {
 }
 
 void ListWidget::deleteItem(UniversalMsgId universalId) {
-	if (const auto item = App::histItemById(computeFullId(universalId))) {
+	if (const auto item = Auth().data().message(computeFullId(universalId))) {
 		deleteItems({ 1, item->fullId() });
 	}
 }
@@ -1512,7 +1512,7 @@ bool ListWidget::changeItemSelection(
 			universalId,
 			selection);
 		if (ok) {
-			auto item = App::histItemById(computeFullId(universalId));
+			auto item = Auth().data().message(computeFullId(universalId));
 			if (!item) {
 				selected.erase(iterator);
 				return false;
diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp
index f19de835c..b4977fc9e 100644
--- a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp
+++ b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp
@@ -58,7 +58,7 @@ void SendDataCommon::addToHistory(
 			MTPint(),
 			MTP_string(postAuthor),
 			MTPlong()),
-		NewMessageUnread);
+		NewMessageType::Unread);
 }
 
 QString SendDataCommon::getErrorOnSend(
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index b782bf85a..71b723ae2 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -842,7 +842,7 @@ void MainWidget::cancelUploadLayer(not_null<HistoryItem*> item) {
 	session().uploader().pause(itemId);
 	const auto stopUpload = [=] {
 		Ui::hideLayer();
-		if (const auto item = App::histItemById(itemId)) {
+		if (const auto item = session().data().message(itemId)) {
 			const auto history = item->history();
 			if (!IsServerMsgId(itemId.msg)) {
 				item->destroy();
@@ -1035,7 +1035,7 @@ void MainWidget::handleAudioUpdate(const Media::Player::TrackState &state) {
 		closeBothPlayers();
 	}
 
-	if (const auto item = App::histItemById(state.id.contextId())) {
+	if (const auto item = session().data().message(state.id.contextId())) {
 		session().data().requestItemRepaint(item);
 	}
 	if (const auto items = InlineBots::Layout::documentItems()) {
@@ -1514,7 +1514,7 @@ void MainWidget::viewsIncrementDone(QVector<MTPint> ids, const MTPVector<MTPint>
 				PeerData *peer = i.key();
 				ChannelId channel = peerToChannel(peer->id);
 				for (int32 j = 0, l = ids.size(); j < l; ++j) {
-					if (HistoryItem *item = App::histItemById(channel, ids.at(j).v)) {
+					if (HistoryItem *item = session().data().message(channel, ids.at(j).v)) {
 						item->setViewsCount(v.at(j).v);
 					}
 				}
@@ -2913,7 +2913,9 @@ void MainWidget::feedChannelDifference(
 
 	_handlingChannelDifference = true;
 	feedMessageIds(data.vother_updates);
-	App::feedMsgs(data.vnew_messages, NewMessageUnread);
+	session().data().processMessages(
+		data.vnew_messages,
+		NewMessageType::Unread);
 	feedUpdateVector(data.vother_updates, true);
 	_handlingChannelDifference = false;
 }
@@ -3060,7 +3062,7 @@ void MainWidget::feedDifference(
 	session().data().processUsers(users);
 	session().data().processChats(chats);
 	feedMessageIds(other);
-	App::feedMsgs(msgs, NewMessageUnread);
+	session().data().processMessages(msgs, NewMessageType::Unread);
 	feedUpdateVector(other, true);
 }
 
@@ -3264,7 +3266,7 @@ void MainWidget::openPeerByName(
 			}
 			const auto returnToId = clickFromMessageId;
 			InvokeQueued(this, [=] {
-				if (const auto returnTo = App::histItemById(returnToId)) {
+				if (const auto returnTo = session().data().message(returnToId)) {
 					if (returnTo->history()->peer == peer) {
 						pushReplyReturn(returnTo);
 					}
@@ -3770,13 +3772,13 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
 		} else if (randomId) {
 			PeerId peerId = 0;
 			QString text;
-			App::histSentDataByItem(randomId, peerId, text);
+			session().data().registerMessageSentData(randomId, peerId, text);
 
 			const auto wasAlready = (peerId != 0)
-				&& (App::histItemById(peerToChannel(peerId), d.vid.v) != nullptr);
+				&& (session().data().message(peerToChannel(peerId), d.vid.v) != nullptr);
 			feedUpdate(MTP_updateMessageID(d.vid, MTP_long(randomId))); // ignore real date
 			if (peerId) {
-				if (auto item = App::histItemById(peerToChannel(peerId), d.vid.v)) {
+				if (auto item = session().data().message(peerToChannel(peerId), d.vid.v)) {
 					if (d.has_entities() && !MentionUsersLoaded(&session(), d.ventities)) {
 						session().api().requestMessageData(
 							item->history()->peer->asChannel(),
@@ -3865,11 +3867,12 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 
 	case mtpc_updateMessageID: {
 		const auto &d = update.c_updateMessageID();
-		if (const auto fullId = App::histItemByRandom(d.vrandom_id.v)) {
-			const auto channel = fullId.channel;
+		const auto randomId = d.vrandom_id.v;
+		if (const auto id = session().data().messageIdByRandomId(randomId)) {
+			const auto channel = id.channel;
 			const auto newId = d.vid.v;
-			if (const auto local = App::histItemById(fullId)) {
-				const auto existing = App::histItemById(channel, newId);
+			if (const auto local = session().data().message(id)) {
+				const auto existing = session().data().message(channel, newId);
 				if (existing && !local->mainView()) {
 					const auto history = local->history();
 					local->destroy();
@@ -3881,9 +3884,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 					local->setRealId(d.vid.v);
 				}
 			}
-			App::historyUnregRandom(d.vrandom_id.v);
+			session().data().unregisterMessageRandomId(randomId);
 		}
-		App::historyUnregSentData(d.vrandom_id.v);
+		session().data().unregisterMessageSentData(randomId);
 	} break;
 
 	// Message contents being read.
@@ -3904,7 +3907,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 		}
 		auto possiblyReadMentions = base::flat_set<MsgId>();
 		for_const (auto &msgId, d.vmessages.v) {
-			if (auto item = App::histItemById(channel, msgId.v)) {
+			if (auto item = session().data().message(channel, msgId.v)) {
 				if (item->isUnreadMedia() || item->isUnreadMention()) {
 					item->markMediaRead();
 					session().data().requestItemRepaint(item);
@@ -4401,7 +4404,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 
 	case mtpc_updateChannelMessageViews: {
 		auto &d = update.c_updateChannelMessageViews();
-		if (auto item = App::histItemById(d.vchannel_id.v, d.vid.v)) {
+		if (auto item = session().data().message(d.vchannel_id.v, d.vid.v)) {
 			item->setViewsCount(d.vviews.v);
 		}
 	} break;
diff --git a/Telegram/SourceFiles/media/audio/media_audio.cpp b/Telegram/SourceFiles/media/audio/media_audio.cpp
index a74fa6dfe..0ac35790b 100644
--- a/Telegram/SourceFiles/media/audio/media_audio.cpp
+++ b/Telegram/SourceFiles/media/audio/media_audio.cpp
@@ -14,9 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "media/streaming/media_streaming_utility.h"
 #include "data/data_document.h"
 #include "data/data_file_origin.h"
+#include "data/data_session.h"
 #include "platform/platform_audio.h"
 #include "core/application.h"
-#include "facades.h"
+#include "auth_session.h"
 
 #include <AL/al.h>
 #include <AL/alc.h>
@@ -813,7 +814,7 @@ void Mixer::play(
 			DocumentOpenClickHandler::Open(
 				audio.contextId(),
 				audio.audio(),
-				App::histItemById(audio.contextId()));
+				Auth().data().message(audio.contextId()));
 		} else {
 			onError(audio);
 		}
diff --git a/Telegram/SourceFiles/media/player/media_player_float.cpp b/Telegram/SourceFiles/media/player/media_player_float.cpp
index a2d5d861c..00a9226d7 100644
--- a/Telegram/SourceFiles/media/player/media_player_float.cpp
+++ b/Telegram/SourceFiles/media/player/media_player_float.cpp
@@ -360,7 +360,7 @@ void FloatController::checkCurrent() {
 	if (last) {
 		last->widget->detach();
 	}
-	if (const auto item = App::histItemById(fullId)) {
+	if (const auto item = Auth().data().message(fullId)) {
 		if (const auto media = item->media()) {
 			if (const auto document = media->document()) {
 				if (document->isVideoMessage()) {
diff --git a/Telegram/SourceFiles/media/player/media_player_instance.cpp b/Telegram/SourceFiles/media/player/media_player_instance.cpp
index bb07e22d6..60df88388 100644
--- a/Telegram/SourceFiles/media/player/media_player_instance.cpp
+++ b/Telegram/SourceFiles/media/player/media_player_instance.cpp
@@ -150,9 +150,7 @@ void Instance::setCurrent(const AudioMsgId &audioId) {
 		data->current = audioId;
 		data->isPlaying = false;
 
-		const auto history = data->history;
-		const auto migrated = data->migrated;
-		const auto item = App::histItemById(data->current.contextId());
+		const auto item = Auth().data().message(data->current.contextId());
 		if (item) {
 			data->history = item->history()->migrateToOrMe();
 			data->migrated = data->history->migrateFrom();
@@ -273,7 +271,7 @@ HistoryItem *Instance::itemByIndex(not_null<Data*> data, int index) {
 		return nullptr;
 	}
 	const auto fullId = (*data->playlistSlice)[index];
-	return App::histItemById(fullId);
+	return Auth().data().message(fullId);
 }
 
 bool Instance::moveInPlaylist(
@@ -716,7 +714,7 @@ HistoryItem *Instance::roundVideoItem() const {
 	const auto data = getData(AudioMsgId::Type::Voice);
 	return (data->streamed
 		&& !data->streamed->info.video.size.isEmpty())
-		? App::histItemById(data->streamed->id.contextId())
+		? Auth().data().message(data->streamed->id.contextId())
 		: nullptr;
 
 }
diff --git a/Telegram/SourceFiles/media/player/media_player_panel.cpp b/Telegram/SourceFiles/media/player/media_player_panel.cpp
index 45b3f2cd8..413b9f896 100644
--- a/Telegram/SourceFiles/media/player/media_player_panel.cpp
+++ b/Telegram/SourceFiles/media/player/media_player_panel.cpp
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "info/media/info_media_list_widget.h"
 #include "history/history.h"
 #include "history/history_item.h"
+#include "data/data_session.h"
 #include "data/data_document.h"
 #include "data/data_media_types.h"
 #include "data/data_channel.h"
@@ -18,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/widgets/shadow.h"
 #include "ui/widgets/scroll_area.h"
 #include "mainwindow.h"
+#include "auth_session.h"
 #include "styles/style_overview.h"
 #include "styles/style_widgets.h"
 #include "styles/style_media_player.h"
@@ -225,7 +227,7 @@ void Panel::refreshList() {
 	const auto current = instance()->current(AudioMsgId::Type::Song);
 	const auto contextId = current.contextId();
 	const auto peer = [&]() -> PeerData* {
-		const auto item = contextId ? App::histItemById(contextId) : nullptr;
+		const auto item = contextId ? Auth().data().message(contextId) : nullptr;
 		const auto media = item ? item->media() : nullptr;
 		const auto document = media ? media->document() : nullptr;
 		if (!document || !document->isSharedMediaMusic()) {
diff --git a/Telegram/SourceFiles/media/player/media_player_widget.cpp b/Telegram/SourceFiles/media/player/media_player_widget.cpp
index 218cf4ed7..8ad4c1fd1 100644
--- a/Telegram/SourceFiles/media/player/media_player_widget.cpp
+++ b/Telegram/SourceFiles/media/player/media_player_widget.cpp
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "media/player/media_player_widget.h"
 
 #include "data/data_document.h"
+#include "data/data_session.h"
 #include "ui/widgets/labels.h"
 #include "ui/widgets/continuous_sliders.h"
 #include "ui/widgets/shadow.h"
@@ -24,7 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/history_item.h"
 #include "storage/localstorage.h"
 #include "layout.h"
-#include "facades.h"
+#include "auth_session.h"
 
 namespace Media {
 namespace Player {
@@ -296,7 +297,7 @@ void Widget::mouseReleaseEvent(QMouseEvent *e) {
 		if (_labelsOver == downLabels) {
 			if (_type == AudioMsgId::Type::Voice) {
 				auto current = instance()->current(_type);
-				if (auto item = App::histItemById(current.contextId())) {
+				if (auto item = Auth().data().message(current.contextId())) {
 					Ui::showPeerHistoryAtItem(item);
 				}
 			}
@@ -509,7 +510,7 @@ void Widget::handleSongChange() {
 
 	TextWithEntities textWithEntities;
 	if (document->isVoiceMessage() || document->isVideoMessage()) {
-		if (const auto item = App::histItemById(current.contextId())) {
+		if (const auto item = Auth().data().message(current.contextId())) {
 			const auto name = App::peerName(item->fromOriginal());
 			const auto date = [item] {
 				const auto parsed = ItemDateTime(item);
diff --git a/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp b/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp
index 2bace1d44..ffd63e399 100644
--- a/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp
+++ b/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp
@@ -64,7 +64,7 @@ Context ComputeContext(const SharedMediaWithLastSlice &slice, int index) {
 		}
 		return std::nullopt;
 	} else if (const auto msgId = base::get_if<FullMsgId>(&value)) {
-		if (const auto item = App::histItemById(*msgId)) {
+		if (const auto item = Auth().data().message(*msgId)) {
 			if (!item->toHistoryMessage()) {
 				return item->history()->peer->id;
 			} else if (const auto groupId = item->groupId()) {
@@ -518,7 +518,7 @@ auto GroupThumbs::createThumb(Key key)
 		const auto photo = Auth().data().photo(*photoId);
 		return createThumb(key, photo->thumbnail());
 	} else if (const auto msgId = base::get_if<FullMsgId>(&key)) {
-		if (const auto item = App::histItemById(*msgId)) {
+		if (const auto item = Auth().data().message(*msgId)) {
 			if (const auto media = item->media()) {
 				if (const auto photo = media->photo()) {
 					return createThumb(key, photo->thumbnail());
@@ -530,7 +530,7 @@ auto GroupThumbs::createThumb(Key key)
 		return createThumb(key, nullptr);
 	} else if (const auto collageKey = base::get_if<CollageKey>(&key)) {
 		if (const auto itemId = base::get_if<FullMsgId>(&_context)) {
-			if (const auto item = App::histItemById(*itemId)) {
+			if (const auto item = Auth().data().message(*itemId)) {
 				if (const auto media = item->media()) {
 					if (const auto page = media->webpage()) {
 						return createThumb(
diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp
index c86571630..031de4066 100644
--- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp
+++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp
@@ -515,7 +515,7 @@ void OverlayWidget::updateControls() {
 
 	const auto dNow = QDateTime::currentDateTime();
 	const auto d = [&] {
-		if (const auto item = App::histItemById(_msgid)) {
+		if (const auto item = Auth().data().message(_msgid)) {
 			return ItemDateTime(item);
 		} else if (_photo) {
 			return ParseDateTime(_photo->date);
@@ -1038,7 +1038,7 @@ void OverlayWidget::onScreenResized(int screen) {
 }
 
 void OverlayWidget::onToMessage() {
-	if (const auto item = App::histItemById(_msgid)) {
+	if (const auto item = Auth().data().message(_msgid)) {
 		close();
 		Ui::showPeerHistoryAtItem(item);
 	}
@@ -1124,7 +1124,7 @@ void OverlayWidget::onDocClick() {
 		DocumentOpenClickHandler::Open(
 			fileOrigin(),
 			_doc,
-			App::histItemById(_msgid));
+			Auth().data().message(_msgid));
 		if (_doc->loading() && !_radial.animating()) {
 			_radial.start(_doc->progress());
 		}
@@ -1216,7 +1216,7 @@ void OverlayWidget::onShowInFolder() {
 }
 
 void OverlayWidget::onForward() {
-	auto item = App::histItemById(_msgid);
+	auto item = Auth().data().message(_msgid);
 	if (!item || !IsServerMsgId(item->id) || item->serviceMsg()) {
 		return;
 	}
@@ -1241,7 +1241,7 @@ void OverlayWidget::onDelete() {
 
 	if (deletingPeerPhoto()) {
 		App::main()->deletePhotoLayer(_photo);
-	} else if (const auto item = App::histItemById(_msgid)) {
+	} else if (const auto item = Auth().data().message(_msgid)) {
 		const auto suggestModerateActions = true;
 		Ui::show(Box<DeleteMessagesBox>(item, suggestModerateActions));
 	}
@@ -1277,7 +1277,7 @@ void OverlayWidget::onAttachedStickers() {
 
 std::optional<OverlayWidget::SharedMediaType> OverlayWidget::sharedMediaType() const {
 	using Type = SharedMediaType;
-	if (const auto item = App::histItemById(_msgid)) {
+	if (const auto item = Auth().data().message(_msgid)) {
 		if (const auto media = item->media()) {
 			if (media->webpage()) {
 				return std::nullopt;
@@ -1465,7 +1465,7 @@ void OverlayWidget::handleUserPhotosUpdate(UserPhotosSlice &&update) {
 }
 
 std::optional<OverlayWidget::CollageKey> OverlayWidget::collageKey() const {
-	if (const auto item = App::histItemById(_msgid)) {
+	if (const auto item = Auth().data().message(_msgid)) {
 		if (const auto media = item->media()) {
 			if (const auto page = media->webpage()) {
 				for (const auto &item : page->collage.items) {
@@ -1511,7 +1511,7 @@ void OverlayWidget::validateCollage() {
 	if (const auto key = collageKey()) {
 		_collage = std::make_unique<Collage>(*key);
 		_collageData = WebPageCollage();
-		if (const auto item = App::histItemById(_msgid)) {
+		if (const auto item = Auth().data().message(_msgid)) {
 			if (const auto media = item->media()) {
 				if (const auto page = media->webpage()) {
 					_collageData = page->collage;
@@ -1755,7 +1755,7 @@ void OverlayWidget::redisplayContent() {
 	if (isHidden()) {
 		return;
 	}
-	const auto item = App::histItemById(_msgid);
+	const auto item = Auth().data().message(_msgid);
 	if (_photo) {
 		displayPhoto(_photo, item);
 	} else {
@@ -2243,7 +2243,7 @@ void OverlayWidget::playbackPauseResume() {
 	Expects(_streamed != nullptr);
 
 	_streamed->resumeOnCallEnd = false;
-	if (const auto item = App::histItemById(_msgid)) {
+	if (const auto item = Auth().data().message(_msgid)) {
 		if (_streamed->player.failed()) {
 			clearStreaming();
 			initStreaming();
@@ -3033,7 +3033,7 @@ OverlayWidget::Entity OverlayWidget::entityForSharedMedia(int index) const {
 OverlayWidget::Entity OverlayWidget::entityForCollage(int index) const {
 	Expects(_collageData.has_value());
 
-	const auto item = App::histItemById(_msgid);
+	const auto item = Auth().data().message(_msgid);
 	const auto &items = _collageData->items;
 	if (!item || index < 0 || index >= items.size()) {
 		return { std::nullopt, nullptr };
@@ -3047,7 +3047,7 @@ OverlayWidget::Entity OverlayWidget::entityForCollage(int index) const {
 }
 
 OverlayWidget::Entity OverlayWidget::entityForItemId(const FullMsgId &itemId) const {
-	if (const auto item = App::histItemById(itemId)) {
+	if (const auto item = Auth().data().message(itemId)) {
 		if (const auto media = item->media()) {
 			if (const auto photo = media->photo()) {
 				return { photo, item };
diff --git a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp
index 922270e2d..a090b5419 100644
--- a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp
+++ b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp
@@ -141,9 +141,9 @@ AdminLog::OwnedItem GenerateForwardedItem(
 		MTPint(), // edit_date
 		MTPstring(), // post_author
 		MTPlong() // grouped_id
-	).match([&](const MTPDmessage & data) {
-		return new HistoryMessage(history, data);
-	}, [](auto &&) -> HistoryMessage* {
+	).match([&](const MTPDmessage &data) {
+		return history->owner().makeMessage(history, data);
+	}, [](auto &&) -> not_null<HistoryMessage*> {
 		Unexpected("Type in GenerateForwardedItem.");
 	});
 
diff --git a/Telegram/SourceFiles/storage/localimageloader.cpp b/Telegram/SourceFiles/storage/localimageloader.cpp
index d0155fa96..71e6a4137 100644
--- a/Telegram/SourceFiles/storage/localimageloader.cpp
+++ b/Telegram/SourceFiles/storage/localimageloader.cpp
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "storage/localimageloader.h"
 
 #include "data/data_document.h"
+#include "data/data_session.h"
 #include "core/file_utilities.h"
 #include "core/mime_type.h"
 #include "media/audio/media_audio.h"
@@ -20,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "storage/storage_media_prepare.h"
 #include "mainwidget.h"
 #include "mainwindow.h"
+#include "auth_session.h"
 
 namespace {
 
@@ -474,7 +476,7 @@ void SendingAlbum::removeItem(not_null<HistoryItem*> item) {
 	if (moveCaption) {
 		const auto caption = item->originalText();
 		const auto firstId = items.front().msgId;
-		if (const auto first = App::histItemById(firstId)) {
+		if (const auto first = Auth().data().message(firstId)) {
 			// We don't need to finishEdition() here, because the whole
 			// album will be rebuilt after one item was removed from it.
 			first->setText(caption);
diff --git a/Telegram/SourceFiles/support/support_autocomplete.cpp b/Telegram/SourceFiles/support/support_autocomplete.cpp
index 690d5d2c0..b9ed85507 100644
--- a/Telegram/SourceFiles/support/support_autocomplete.cpp
+++ b/Telegram/SourceFiles/support/support_autocomplete.cpp
@@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/view/history_view_service_message.h"
 #include "history/history_message.h"
 #include "lang/lang_keys.h"
+#include "data/data_session.h"
 #include "auth_session.h"
 #include "apiwrap.h"
 #include "styles/style_chat_helpers.h"
@@ -271,7 +272,7 @@ AdminLog::OwnedItem GenerateCommentItem(
 	const auto flags = Flag::f_entities | Flag::f_from_id | Flag::f_out;
 	const auto replyTo = 0;
 	const auto viaBotId = 0;
-	const auto item = new HistoryMessage(
+	const auto item = history->owner().makeMessage(
 		history,
 		id,
 		flags,
@@ -315,7 +316,9 @@ AdminLog::OwnedItem GenerateContactItem(
 		MTP_int(0),
 		MTP_string(QString()),
 		MTP_long(0));
-	const auto item = new HistoryMessage(history, message.c_message());
+	const auto item = history->owner().makeMessage(
+		history,
+		message.c_message());
 	return AdminLog::OwnedItem(delegate, item);
 }
 
diff --git a/Telegram/SourceFiles/window/notifications_manager.cpp b/Telegram/SourceFiles/window/notifications_manager.cpp
index a382dfc5b..e102a5321 100644
--- a/Telegram/SourceFiles/window/notifications_manager.cpp
+++ b/Telegram/SourceFiles/window/notifications_manager.cpp
@@ -192,7 +192,7 @@ void System::checkDelayed() {
 			const auto fullId = FullMsgId(
 				history->channelId(),
 				i.value().msg);
-			if (const auto item = App::histItemById(fullId)) {
+			if (const auto item = Auth().data().message(fullId)) {
 				if (!item->notificationReady()) {
 					loaded = false;
 				}
@@ -214,7 +214,7 @@ void System::checkDelayed() {
 }
 
 void System::showGrouped() {
-	if (const auto lastItem = App::histItemById(_lastHistoryItemId)) {
+	if (const auto lastItem = Auth().data().message(_lastHistoryItemId)) {
 		_waitForAllGroupedTimer.cancel();
 		_manager->showNotification(lastItem, _lastForwardedCount);
 		_lastForwardedCount = 0;
@@ -229,7 +229,7 @@ void System::showNext() {
 		if (!_lastHistoryItemId || !item) {
 			return false;
 		}
-		if (const auto lastItem = App::histItemById(_lastHistoryItemId)) {
+		if (const auto lastItem = Auth().data().message(_lastHistoryItemId)) {
 			return (lastItem->groupId() == item->groupId() || lastItem->author() == item->author());
 		}
 		return false;
@@ -474,7 +474,7 @@ void Manager::openNotificationMessage(
 			|| !IsServerMsgId(messageId)) {
 			return false;
 		}
-		const auto item = App::histItemById(history->channelId(), messageId);
+		const auto item = Auth().data().message(history->channelId(), messageId);
 		if (!item || !item->mentionsMe()) {
 			return false;
 		}
diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp
index 9d2778746..c84110d69 100644
--- a/Telegram/SourceFiles/window/window_controller.cpp
+++ b/Telegram/SourceFiles/window/window_controller.cpp
@@ -189,7 +189,7 @@ bool Controller::jumpToChatListEntry(Dialogs::RowDescriptor row) {
 		Ui::showPeerHistory(history, row.fullId.msg);
 		return true;
 	//} else if (const auto feed = row.key.feed()) { // #feed
-	//	if (const auto item = App::histItemById(row.fullId)) {
+	//	if (const auto item = Auth().data().message(row.fullId)) {
 	//		showSection(HistoryFeed::Memento(feed, item->position()));
 	//	} else {
 	//		showSection(HistoryFeed::Memento(feed));