1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #include "storage/storage_account.h"
9 
10 #include "storage/localstorage.h"
11 #include "storage/storage_domain.h"
12 #include "storage/storage_encryption.h"
13 #include "storage/storage_clear_legacy.h"
14 #include "storage/cache/storage_cache_types.h"
15 #include "storage/details/storage_file_utilities.h"
16 #include "storage/details/storage_settings_scheme.h"
17 #include "storage/serialize_common.h"
18 #include "storage/serialize_peer.h"
19 #include "storage/serialize_document.h"
20 #include "main/main_account.h"
21 #include "main/main_session.h"
22 #include "mtproto/mtproto_config.h"
23 #include "mtproto/mtproto_dc_options.h"
24 #include "mtproto/mtp_instance.h"
25 #include "history/history.h"
26 #include "core/application.h"
27 #include "core/file_location.h"
28 #include "data/stickers/data_stickers.h"
29 #include "data/data_session.h"
30 #include "data/data_document.h"
31 #include "data/data_user.h"
32 #include "data/data_drafts.h"
33 #include "export/export_settings.h"
34 #include "window/themes/window_theme.h"
35 
36 namespace Storage {
37 namespace {
38 
39 using namespace details;
40 using Database = Cache::Database;
41 
42 constexpr auto kDelayedWriteTimeout = crl::time(1000);
43 
44 constexpr auto kStickersVersionTag = quint32(-1);
45 constexpr auto kStickersSerializeVersion = 2;
46 constexpr auto kMaxSavedStickerSetsCount = 1000;
47 constexpr auto kDefaultStickerInstallDate = TimeId(1);
48 
49 constexpr auto kSinglePeerTypeUserOld = qint32(1);
50 constexpr auto kSinglePeerTypeChatOld = qint32(2);
51 constexpr auto kSinglePeerTypeChannelOld = qint32(3);
52 constexpr auto kSinglePeerTypeUser = qint32(8 + 1);
53 constexpr auto kSinglePeerTypeChat = qint32(8 + 2);
54 constexpr auto kSinglePeerTypeChannel = qint32(8 + 3);
55 constexpr auto kSinglePeerTypeSelf = qint32(4);
56 constexpr auto kSinglePeerTypeEmpty = qint32(0);
57 constexpr auto kMultiDraftTagOld = quint64(0xFFFF'FFFF'FFFF'FF01ULL);
58 constexpr auto kMultiDraftCursorsTagOld = quint64(0xFFFF'FFFF'FFFF'FF02ULL);
59 constexpr auto kMultiDraftTag = quint64(0xFFFF'FFFF'FFFF'FF03ULL);
60 constexpr auto kMultiDraftCursorsTag = quint64(0xFFFF'FFFF'FFFF'FF04ULL);
61 
62 enum { // Local Storage Keys
63 	lskUserMap = 0x00,
64 	lskDraft = 0x01, // data: PeerId peer
65 	lskDraftPosition = 0x02, // data: PeerId peer
66 	lskLegacyImages = 0x03, // legacy
67 	lskLocations = 0x04, // no data
68 	lskLegacyStickerImages = 0x05, // legacy
69 	lskLegacyAudios = 0x06, // legacy
70 	lskRecentStickersOld = 0x07, // no data
71 	lskBackgroundOldOld = 0x08, // no data
72 	lskUserSettings = 0x09, // no data
73 	lskRecentHashtagsAndBots = 0x0a, // no data
74 	lskStickersOld = 0x0b, // no data
75 	lskSavedPeersOld = 0x0c, // no data
76 	lskReportSpamStatusesOld = 0x0d, // no data
77 	lskSavedGifsOld = 0x0e, // no data
78 	lskSavedGifs = 0x0f, // no data
79 	lskStickersKeys = 0x10, // no data
80 	lskTrustedBots = 0x11, // no data
81 	lskFavedStickers = 0x12, // no data
82 	lskExportSettings = 0x13, // no data
83 	lskBackgroundOld = 0x14, // no data
84 	lskSelfSerialized = 0x15, // serialized self
85 	lskMasksKeys = 0x16, // no data
86 };
87 
EmptyMessageDraftSources()88 auto EmptyMessageDraftSources()
89 -> const base::flat_map<Data::DraftKey, MessageDraftSource> & {
90 	static const auto result = base::flat_map<
91 		Data::DraftKey,
92 		MessageDraftSource>();
93 	return result;
94 }
95 
ComputeDataNameKey(const QString & dataName)96 [[nodiscard]] FileKey ComputeDataNameKey(const QString &dataName) {
97 	// We dropped old test authorizations when migrated to multi auth.
98 	//const auto testAddition = (cTestMode() ? qsl(":/test/") : QString());
99 	const auto testAddition = QString();
100 	const auto dataNameUtf8 = (dataName + testAddition).toUtf8();
101 	FileKey dataNameHash[2] = { 0 };
102 	hashMd5(dataNameUtf8.constData(), dataNameUtf8.size(), dataNameHash);
103 	return dataNameHash[0];
104 }
105 
BaseGlobalPath()106 [[nodiscard]] QString BaseGlobalPath() {
107 	return cWorkingDir() + qsl("tdata/");
108 }
109 
ComputeDatabasePath(const QString & dataName)110 [[nodiscard]] QString ComputeDatabasePath(const QString &dataName) {
111 	return BaseGlobalPath()
112 		+ "user_" + dataName
113 		// We dropped old test authorizations when migrated to multi auth.
114 		//+ (cTestMode() ? "[test]" : "")
115 		+ '/';
116 }
117 
LegacyTempDirectory()118 [[nodiscard]] QString LegacyTempDirectory() {
119 	return cWorkingDir() + qsl("tdata/tdld/");
120 }
121 
122 } // namespace
123 
Account(not_null<Main::Account * > owner,const QString & dataName)124 Account::Account(not_null<Main::Account*> owner, const QString &dataName)
125 : _owner(owner)
126 , _dataName(dataName)
127 , _dataNameKey(ComputeDataNameKey(dataName))
128 , _basePath(BaseGlobalPath() + ToFilePart(_dataNameKey) + QChar('/'))
129 , _tempPath(BaseGlobalPath() + "temp_" + _dataName + QChar('/'))
130 , _databasePath(ComputeDatabasePath(dataName))
131 , _cacheTotalSizeLimit(Database::Settings().totalSizeLimit)
132 , _cacheBigFileTotalSizeLimit(Database::Settings().totalSizeLimit)
133 , _cacheTotalTimeLimit(Database::Settings().totalTimeLimit)
134 , _cacheBigFileTotalTimeLimit(Database::Settings().totalTimeLimit)
135 , _writeMapTimer([=] { writeMap(); })
__anon08530e130402null136 , _writeLocationsTimer([=] { writeLocations(); }) {
137 }
138 
~Account()139 Account::~Account() {
140 	if (_localKey && _mapChanged) {
141 		writeMap();
142 	}
143 }
144 
tempDirectory() const145 QString Account::tempDirectory() const {
146 	return _tempPath;
147 }
148 
legacyStart(const QByteArray & passcode)149 StartResult Account::legacyStart(const QByteArray &passcode) {
150 	const auto result = readMapWith(MTP::AuthKeyPtr(), passcode);
151 	if (result == ReadMapResult::Failed) {
152 		Assert(_localKey == nullptr);
153 	} else if (result == ReadMapResult::IncorrectPasscode) {
154 		return StartResult::IncorrectPasscodeLegacy;
155 	}
156 	clearLegacyFiles();
157 	return StartResult::Success;
158 }
159 
start(MTP::AuthKeyPtr localKey)160 std::unique_ptr<MTP::Config> Account::start(MTP::AuthKeyPtr localKey) {
161 	Expects(localKey != nullptr);
162 
163 	_localKey = std::move(localKey);
164 	readMapWith(_localKey);
165 	clearLegacyFiles();
166 	return readMtpConfig();
167 }
168 
startAdded(MTP::AuthKeyPtr localKey)169 void Account::startAdded(MTP::AuthKeyPtr localKey) {
170 	Expects(localKey != nullptr);
171 
172 	_localKey = std::move(localKey);
173 	clearLegacyFiles();
174 }
175 
clearLegacyFiles()176 void Account::clearLegacyFiles() {
177 	const auto weak = base::make_weak(_owner.get());
178 	ClearLegacyFiles(_basePath, [weak, this](
179 			FnMut<void(base::flat_set<QString>&&)> then) {
180 		crl::on_main(weak, [this, then = std::move(then)]() mutable {
181 			then(collectGoodNames());
182 		});
183 	});
184 }
185 
collectGoodNames() const186 base::flat_set<QString> Account::collectGoodNames() const {
187 	const auto keys = {
188 		_locationsKey,
189 		_settingsKey,
190 		_installedStickersKey,
191 		_featuredStickersKey,
192 		_recentStickersKey,
193 		_favedStickersKey,
194 		_archivedStickersKey,
195 		_recentStickersKeyOld,
196 		_savedGifsKey,
197 		_legacyBackgroundKeyNight,
198 		_legacyBackgroundKeyDay,
199 		_recentHashtagsAndBotsKey,
200 		_exportSettingsKey,
201 		_trustedBotsKey,
202 		_installedMasksKey,
203 		_recentMasksKey,
204 		_archivedMasksKey,
205 	};
206 	auto result = base::flat_set<QString>{
207 		"map0",
208 		"map1",
209 		"maps",
210 		"configs",
211 	};
212 	const auto push = [&](FileKey key) {
213 		if (!key) {
214 			return;
215 		}
216 		auto name = ToFilePart(key) + '0';
217 		result.emplace(name);
218 		name[name.size() - 1] = '1';
219 		result.emplace(name);
220 		name[name.size() - 1] = 's';
221 		result.emplace(name);
222 	};
223 	for (const auto &[key, value] : _draftsMap) {
224 		push(value);
225 	}
226 	for (const auto &[key, value] : _draftCursorsMap) {
227 		push(value);
228 	}
229 	for (const auto &value : keys) {
230 		push(value);
231 	}
232 	return result;
233 }
234 
readMapWith(MTP::AuthKeyPtr localKey,const QByteArray & legacyPasscode)235 Account::ReadMapResult Account::readMapWith(
236 		MTP::AuthKeyPtr localKey,
237 		const QByteArray &legacyPasscode) {
238 	auto ms = crl::now();
239 
240 	FileReadDescriptor mapData;
241 	if (!ReadFile(mapData, qsl("map"), _basePath)) {
242 		return ReadMapResult::Failed;
243 	}
244 	LOG(("App Info: reading map..."));
245 
246 	QByteArray legacySalt, legacyKeyEncrypted, mapEncrypted;
247 	mapData.stream >> legacySalt >> legacyKeyEncrypted >> mapEncrypted;
248 	if (!CheckStreamStatus(mapData.stream)) {
249 		return ReadMapResult::Failed;
250 	}
251 	if (!localKey) {
252 		if (legacySalt.size() != LocalEncryptSaltSize) {
253 			LOG(("App Error: bad salt in map file, size: %1").arg(legacySalt.size()));
254 			return ReadMapResult::Failed;
255 		}
256 		auto legacyPasscodeKey = CreateLegacyLocalKey(legacyPasscode, legacySalt);
257 
258 		EncryptedDescriptor keyData;
259 		if (!DecryptLocal(keyData, legacyKeyEncrypted, legacyPasscodeKey)) {
260 			LOG(("App Info: could not decrypt pass-protected key from map file, maybe bad password..."));
261 			return ReadMapResult::IncorrectPasscode;
262 		}
263 		auto key = Serialize::read<MTP::AuthKey::Data>(keyData.stream);
264 		if (keyData.stream.status() != QDataStream::Ok || !keyData.stream.atEnd()) {
265 			LOG(("App Error: could not read pass-protected key from map file"));
266 			return ReadMapResult::Failed;
267 		}
268 		localKey = std::make_shared<MTP::AuthKey>(key);
269 	}
270 
271 	EncryptedDescriptor map;
272 	if (!DecryptLocal(map, mapEncrypted, localKey)) {
273 		LOG(("App Error: could not decrypt map."));
274 		return ReadMapResult::Failed;
275 	}
276 	LOG(("App Info: reading encrypted map..."));
277 
278 	QByteArray selfSerialized;
279 	base::flat_map<PeerId, FileKey> draftsMap;
280 	base::flat_map<PeerId, FileKey> draftCursorsMap;
281 	base::flat_map<PeerId, bool> draftsNotReadMap;
282 	quint64 locationsKey = 0, reportSpamStatusesKey = 0, trustedBotsKey = 0;
283 	quint64 recentStickersKeyOld = 0;
284 	quint64 installedStickersKey = 0, featuredStickersKey = 0, recentStickersKey = 0, favedStickersKey = 0, archivedStickersKey = 0;
285 	quint64 installedMasksKey = 0, recentMasksKey = 0, archivedMasksKey = 0;
286 	quint64 savedGifsKey = 0;
287 	quint64 legacyBackgroundKeyDay = 0, legacyBackgroundKeyNight = 0;
288 	quint64 userSettingsKey = 0, recentHashtagsAndBotsKey = 0, exportSettingsKey = 0;
289 	while (!map.stream.atEnd()) {
290 		quint32 keyType;
291 		map.stream >> keyType;
292 		switch (keyType) {
293 		case lskDraft: {
294 			quint32 count = 0;
295 			map.stream >> count;
296 			for (quint32 i = 0; i < count; ++i) {
297 				FileKey key;
298 				quint64 peerIdSerialized;
299 				map.stream >> key >> peerIdSerialized;
300 				const auto peerId = DeserializePeerId(peerIdSerialized);
301 				draftsMap.emplace(peerId, key);
302 				draftsNotReadMap.emplace(peerId, true);
303 			}
304 		} break;
305 		case lskSelfSerialized: {
306 			map.stream >> selfSerialized;
307 		} break;
308 		case lskDraftPosition: {
309 			quint32 count = 0;
310 			map.stream >> count;
311 			for (quint32 i = 0; i < count; ++i) {
312 				FileKey key;
313 				quint64 peerIdSerialized;
314 				map.stream >> key >> peerIdSerialized;
315 				const auto peerId = DeserializePeerId(peerIdSerialized);
316 				draftCursorsMap.emplace(peerId, key);
317 			}
318 		} break;
319 		case lskLegacyImages:
320 		case lskLegacyStickerImages:
321 		case lskLegacyAudios: {
322 			quint32 count = 0;
323 			map.stream >> count;
324 			for (quint32 i = 0; i < count; ++i) {
325 				FileKey key;
326 				quint64 first, second;
327 				qint32 size;
328 				map.stream >> key >> first >> second >> size;
329 				// Just ignore the key, it will be removed as a leaked one.
330 			}
331 		} break;
332 		case lskLocations: {
333 			map.stream >> locationsKey;
334 		} break;
335 		case lskReportSpamStatusesOld: {
336 			map.stream >> reportSpamStatusesKey;
337 			ClearKey(reportSpamStatusesKey, _basePath);
338 		} break;
339 		case lskTrustedBots: {
340 			map.stream >> trustedBotsKey;
341 		} break;
342 		case lskRecentStickersOld: {
343 			map.stream >> recentStickersKeyOld;
344 		} break;
345 		case lskBackgroundOldOld: {
346 			map.stream >> (Window::Theme::IsNightMode()
347 				? legacyBackgroundKeyNight
348 				: legacyBackgroundKeyDay);
349 		} break;
350 		case lskBackgroundOld: {
351 			map.stream >> legacyBackgroundKeyDay >> legacyBackgroundKeyNight;
352 		} break;
353 		case lskUserSettings: {
354 			map.stream >> userSettingsKey;
355 		} break;
356 		case lskRecentHashtagsAndBots: {
357 			map.stream >> recentHashtagsAndBotsKey;
358 		} break;
359 		case lskStickersOld: {
360 			map.stream >> installedStickersKey;
361 		} break;
362 		case lskStickersKeys: {
363 			map.stream >> installedStickersKey >> featuredStickersKey >> recentStickersKey >> archivedStickersKey;
364 		} break;
365 		case lskFavedStickers: {
366 			map.stream >> favedStickersKey;
367 		} break;
368 		case lskSavedGifsOld: {
369 			quint64 key;
370 			map.stream >> key;
371 		} break;
372 		case lskSavedGifs: {
373 			map.stream >> savedGifsKey;
374 		} break;
375 		case lskSavedPeersOld: {
376 			quint64 key;
377 			map.stream >> key;
378 		} break;
379 		case lskExportSettings: {
380 			map.stream >> exportSettingsKey;
381 		} break;
382 		case lskMasksKeys: {
383 			map.stream
384 				>> installedMasksKey
385 				>> recentMasksKey
386 				>> archivedMasksKey;
387 		} break;
388 		default:
389 			LOG(("App Error: unknown key type in encrypted map: %1").arg(keyType));
390 			return ReadMapResult::Failed;
391 		}
392 		if (!CheckStreamStatus(map.stream)) {
393 			return ReadMapResult::Failed;
394 		}
395 	}
396 
397 	_localKey = std::move(localKey);
398 
399 	_draftsMap = draftsMap;
400 	_draftCursorsMap = draftCursorsMap;
401 	_draftsNotReadMap = draftsNotReadMap;
402 
403 	_locationsKey = locationsKey;
404 	_trustedBotsKey = trustedBotsKey;
405 	_recentStickersKeyOld = recentStickersKeyOld;
406 	_installedStickersKey = installedStickersKey;
407 	_featuredStickersKey = featuredStickersKey;
408 	_recentStickersKey = recentStickersKey;
409 	_favedStickersKey = favedStickersKey;
410 	_archivedStickersKey = archivedStickersKey;
411 	_savedGifsKey = savedGifsKey;
412 	_installedMasksKey = installedMasksKey;
413 	_recentMasksKey = recentMasksKey;
414 	_archivedMasksKey = archivedMasksKey;
415 	_legacyBackgroundKeyDay = legacyBackgroundKeyDay;
416 	_legacyBackgroundKeyNight = legacyBackgroundKeyNight;
417 	_settingsKey = userSettingsKey;
418 	_recentHashtagsAndBotsKey = recentHashtagsAndBotsKey;
419 	_exportSettingsKey = exportSettingsKey;
420 	_oldMapVersion = mapData.version;
421 
422 	if (_oldMapVersion < AppVersion) {
423 		writeMapDelayed();
424 	} else {
425 		_mapChanged = false;
426 	}
427 
428 	if (_locationsKey) {
429 		readLocations();
430 	}
431 	if (_legacyBackgroundKeyDay || _legacyBackgroundKeyNight) {
432 		Local::moveLegacyBackground(
433 			_basePath,
434 			_localKey,
435 			_legacyBackgroundKeyDay,
436 			_legacyBackgroundKeyNight);
437 	}
438 
439 	auto stored = readSessionSettings();
440 	readMtpData();
441 
442 	DEBUG_LOG(("selfSerialized set: %1").arg(selfSerialized.size()));
443 	_owner->setSessionFromStorage(
444 		std::move(stored),
445 		std::move(selfSerialized),
446 		_oldMapVersion);
447 
448 	LOG(("Map read time: %1").arg(crl::now() - ms));
449 
450 	return ReadMapResult::Success;
451 }
452 
writeMapDelayed()453 void Account::writeMapDelayed() {
454 	_mapChanged = true;
455 	_writeMapTimer.callOnce(kDelayedWriteTimeout);
456 }
457 
writeMapQueued()458 void Account::writeMapQueued() {
459 	_mapChanged = true;
460 	crl::on_main(_owner, [=] {
461 		writeMap();
462 	});
463 }
464 
writeMap()465 void Account::writeMap() {
466 	Expects(_localKey != nullptr);
467 
468 	_writeMapTimer.cancel();
469 	if (!_mapChanged) {
470 		return;
471 	}
472 	_mapChanged = false;
473 
474 	if (!QDir().exists(_basePath)) {
475 		QDir().mkpath(_basePath);
476 	}
477 
478 	FileWriteDescriptor map(u"map"_q, _basePath);
479 	map.writeData(QByteArray());
480 	map.writeData(QByteArray());
481 
482 	uint32 mapSize = 0;
483 	const auto self = [&] {
484 		if (!_owner->sessionExists()) {
485 			DEBUG_LOG(("AuthSelf Warning: Session does not exist."));
486 			return QByteArray();
487 		}
488 		const auto self = _owner->session().user();
489 		if (self->phone().isEmpty()) {
490 			DEBUG_LOG(("AuthSelf Error: Phone is empty."));
491 			return QByteArray();
492 		}
493 		auto result = QByteArray();
494 		result.reserve(Serialize::peerSize(self)
495 			+ Serialize::stringSize(self->about()));
496 		{
497 			QBuffer buffer(&result);
498 			buffer.open(QIODevice::WriteOnly);
499 			QDataStream stream(&buffer);
500 			Serialize::writePeer(stream, self);
501 			stream << self->about();
502 		}
503 		return result;
504 	}();
505 	if (!self.isEmpty()) mapSize += sizeof(quint32) + Serialize::bytearraySize(self);
506 	if (!_draftsMap.empty()) mapSize += sizeof(quint32) * 2 + _draftsMap.size() * sizeof(quint64) * 2;
507 	if (!_draftCursorsMap.empty()) mapSize += sizeof(quint32) * 2 + _draftCursorsMap.size() * sizeof(quint64) * 2;
508 	if (_locationsKey) mapSize += sizeof(quint32) + sizeof(quint64);
509 	if (_trustedBotsKey) mapSize += sizeof(quint32) + sizeof(quint64);
510 	if (_recentStickersKeyOld) mapSize += sizeof(quint32) + sizeof(quint64);
511 	if (_installedStickersKey || _featuredStickersKey || _recentStickersKey || _archivedStickersKey) {
512 		mapSize += sizeof(quint32) + 4 * sizeof(quint64);
513 	}
514 	if (_favedStickersKey) mapSize += sizeof(quint32) + sizeof(quint64);
515 	if (_savedGifsKey) mapSize += sizeof(quint32) + sizeof(quint64);
516 	if (_settingsKey) mapSize += sizeof(quint32) + sizeof(quint64);
517 	if (_recentHashtagsAndBotsKey) mapSize += sizeof(quint32) + sizeof(quint64);
518 	if (_exportSettingsKey) mapSize += sizeof(quint32) + sizeof(quint64);
519 	if (_installedMasksKey || _recentMasksKey || _archivedMasksKey) {
520 		mapSize += sizeof(quint32) + 3 * sizeof(quint64);
521 	}
522 
523 	EncryptedDescriptor mapData(mapSize);
524 	if (!self.isEmpty()) {
525 		mapData.stream << quint32(lskSelfSerialized) << self;
526 	}
527 	if (!_draftsMap.empty()) {
528 		mapData.stream << quint32(lskDraft) << quint32(_draftsMap.size());
529 		for (const auto &[key, value] : _draftsMap) {
530 			mapData.stream << quint64(value) << SerializePeerId(key);
531 		}
532 	}
533 	if (!_draftCursorsMap.empty()) {
534 		mapData.stream << quint32(lskDraftPosition) << quint32(_draftCursorsMap.size());
535 		for (const auto &[key, value] : _draftCursorsMap) {
536 			mapData.stream << quint64(value) << SerializePeerId(key);
537 		}
538 	}
539 	if (_locationsKey) {
540 		mapData.stream << quint32(lskLocations) << quint64(_locationsKey);
541 	}
542 	if (_trustedBotsKey) {
543 		mapData.stream << quint32(lskTrustedBots) << quint64(_trustedBotsKey);
544 	}
545 	if (_recentStickersKeyOld) {
546 		mapData.stream << quint32(lskRecentStickersOld) << quint64(_recentStickersKeyOld);
547 	}
548 	if (_installedStickersKey || _featuredStickersKey || _recentStickersKey || _archivedStickersKey) {
549 		mapData.stream << quint32(lskStickersKeys);
550 		mapData.stream << quint64(_installedStickersKey) << quint64(_featuredStickersKey) << quint64(_recentStickersKey) << quint64(_archivedStickersKey);
551 	}
552 	if (_favedStickersKey) {
553 		mapData.stream << quint32(lskFavedStickers) << quint64(_favedStickersKey);
554 	}
555 	if (_savedGifsKey) {
556 		mapData.stream << quint32(lskSavedGifs) << quint64(_savedGifsKey);
557 	}
558 	if (_settingsKey) {
559 		mapData.stream << quint32(lskUserSettings) << quint64(_settingsKey);
560 	}
561 	if (_recentHashtagsAndBotsKey) {
562 		mapData.stream << quint32(lskRecentHashtagsAndBots) << quint64(_recentHashtagsAndBotsKey);
563 	}
564 	if (_exportSettingsKey) {
565 		mapData.stream << quint32(lskExportSettings) << quint64(_exportSettingsKey);
566 	}
567 	if (_installedMasksKey || _recentMasksKey || _archivedMasksKey) {
568 		mapData.stream << quint32(lskMasksKeys);
569 		mapData.stream
570 			<< quint64(_installedMasksKey)
571 			<< quint64(_recentMasksKey)
572 			<< quint64(_archivedMasksKey);
573 	}
574 	map.writeEncrypted(mapData, _localKey);
575 
576 	_mapChanged = false;
577 }
578 
reset()579 void Account::reset() {
580 	auto names = collectGoodNames();
581 	_draftsMap.clear();
582 	_draftCursorsMap.clear();
583 	_draftsNotReadMap.clear();
584 	_locationsKey = _trustedBotsKey = 0;
585 	_recentStickersKeyOld = 0;
586 	_installedStickersKey = 0;
587 	_featuredStickersKey = 0;
588 	_recentStickersKey = 0;
589 	_favedStickersKey = 0;
590 	_archivedStickersKey = 0;
591 	_savedGifsKey = 0;
592 	_installedMasksKey = 0;
593 	_recentMasksKey = 0;
594 	_archivedMasksKey = 0;
595 	_legacyBackgroundKeyDay = _legacyBackgroundKeyNight = 0;
596 	_settingsKey = _recentHashtagsAndBotsKey = _exportSettingsKey = 0;
597 	_oldMapVersion = 0;
598 	_fileLocations.clear();
599 	_fileLocationPairs.clear();
600 	_fileLocationAliases.clear();
601 	_cacheTotalSizeLimit = Database::Settings().totalSizeLimit;
602 	_cacheTotalTimeLimit = Database::Settings().totalTimeLimit;
603 	_cacheBigFileTotalSizeLimit = Database::Settings().totalSizeLimit;
604 	_cacheBigFileTotalTimeLimit = Database::Settings().totalTimeLimit;
605 	_mapChanged = true;
606 	writeMap();
607 	writeMtpData();
608 
609 	crl::async([base = _basePath, temp = _tempPath, names = std::move(names)] {
610 		for (const auto &name : names) {
611 			if (!name.endsWith(qstr("map0"))
612 				&& !name.endsWith(qstr("map1"))
613 				&& !name.endsWith(qstr("maps"))
614 				&& !name.endsWith(qstr("configs"))) {
615 				QFile::remove(base + name);
616 			}
617 		}
618 		QDir(LegacyTempDirectory()).removeRecursively();
619 		QDir(temp).removeRecursively();
620 	});
621 
622 	Local::sync();
623 }
624 
writeLocations()625 void Account::writeLocations() {
626 	_writeLocationsTimer.cancel();
627 	if (!_locationsChanged) {
628 		return;
629 	}
630 	_locationsChanged = false;
631 
632 	if (_fileLocations.isEmpty()) {
633 		if (_locationsKey) {
634 			ClearKey(_locationsKey, _basePath);
635 			_locationsKey = 0;
636 			writeMapDelayed();
637 		}
638 	} else {
639 		if (!_locationsKey) {
640 			_locationsKey = GenerateKey(_basePath);
641 			writeMapQueued();
642 		}
643 		quint32 size = 0;
644 		for (auto i = _fileLocations.cbegin(), e = _fileLocations.cend(); i != e; ++i) {
645 			// location + type + namelen + name
646 			size += sizeof(quint64) * 2 + sizeof(quint32) + Serialize::stringSize(i.value().name());
647 			if (AppVersion > 9013) {
648 				// bookmark
649 				size += Serialize::bytearraySize(i.value().bookmark());
650 			}
651 			// date + size
652 			size += Serialize::dateTimeSize() + sizeof(quint32);
653 		}
654 
655 		//end mark
656 		size += sizeof(quint64) * 2 + sizeof(quint32) + Serialize::stringSize(QString());
657 		if (AppVersion > 9013) {
658 			size += Serialize::bytearraySize(QByteArray());
659 		}
660 		size += Serialize::dateTimeSize() + sizeof(quint32);
661 
662 		size += sizeof(quint32); // aliases count
663 		for (auto i = _fileLocationAliases.cbegin(), e = _fileLocationAliases.cend(); i != e; ++i) {
664 			// alias + location
665 			size += sizeof(quint64) * 2 + sizeof(quint64) * 2;
666 		}
667 
668 		EncryptedDescriptor data(size);
669 		auto legacyTypeField = 0;
670 		for (auto i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) {
671 			data.stream << quint64(i.key().first) << quint64(i.key().second) << quint32(legacyTypeField) << i.value().name();
672 			if (AppVersion > 9013) {
673 				data.stream << i.value().bookmark();
674 			}
675 			data.stream << i.value().modified << quint32(i.value().size);
676 		}
677 
678 		data.stream << quint64(0) << quint64(0) << quint32(0) << QString();
679 		if (AppVersion > 9013) {
680 			data.stream << QByteArray();
681 		}
682 		data.stream << QDateTime::currentDateTime() << quint32(0);
683 
684 		data.stream << quint32(_fileLocationAliases.size());
685 		for (auto i = _fileLocationAliases.cbegin(), e = _fileLocationAliases.cend(); i != e; ++i) {
686 			data.stream << quint64(i.key().first) << quint64(i.key().second) << quint64(i.value().first) << quint64(i.value().second);
687 		}
688 
689 		FileWriteDescriptor file(_locationsKey, _basePath);
690 		file.writeEncrypted(data, _localKey);
691 	}
692 }
693 
writeLocationsQueued()694 void Account::writeLocationsQueued() {
695 	_locationsChanged = true;
696 	crl::on_main(_owner, [=] {
697 		writeLocations();
698 	});
699 }
700 
writeLocationsDelayed()701 void Account::writeLocationsDelayed() {
702 	_locationsChanged = true;
703 	_writeLocationsTimer.callOnce(kDelayedWriteTimeout);
704 }
705 
readLocations()706 void Account::readLocations() {
707 	FileReadDescriptor locations;
708 	if (!ReadEncryptedFile(locations, _locationsKey, _basePath, _localKey)) {
709 		ClearKey(_locationsKey, _basePath);
710 		_locationsKey = 0;
711 		writeMapDelayed();
712 		return;
713 	}
714 
715 	bool endMarkFound = false;
716 	while (!locations.stream.atEnd()) {
717 		quint64 first, second;
718 		QByteArray bookmark;
719 		Core::FileLocation loc;
720 		quint32 legacyTypeField = 0;
721 		locations.stream >> first >> second >> legacyTypeField >> loc.fname;
722 		if (locations.version > 9013) {
723 			locations.stream >> bookmark;
724 		}
725 		locations.stream >> loc.modified >> loc.size;
726 		loc.setBookmark(bookmark);
727 
728 		if (!first && !second && !legacyTypeField && loc.fname.isEmpty() && !loc.size) { // end mark
729 			endMarkFound = true;
730 			break;
731 		}
732 
733 		MediaKey key(first, second);
734 
735 		_fileLocations.insert(key, loc);
736 		if (!loc.inMediaCache()) {
737 			_fileLocationPairs.insert(loc.fname, { key, loc });
738 		}
739 	}
740 
741 	if (endMarkFound) {
742 		quint32 cnt;
743 		locations.stream >> cnt;
744 		for (quint32 i = 0; i < cnt; ++i) {
745 			quint64 kfirst, ksecond, vfirst, vsecond;
746 			locations.stream >> kfirst >> ksecond >> vfirst >> vsecond;
747 			_fileLocationAliases.insert(MediaKey(kfirst, ksecond), MediaKey(vfirst, vsecond));
748 		}
749 
750 		if (!locations.stream.atEnd()) {
751 			quint32 webLocationsCount;
752 			locations.stream >> webLocationsCount;
753 			for (quint32 i = 0; i < webLocationsCount; ++i) {
754 				QString url;
755 				quint64 key;
756 				qint32 size;
757 				locations.stream >> url >> key >> size;
758 				ClearKey(key, _basePath);
759 			}
760 		}
761 	}
762 }
763 
writeSessionSettings()764 void Account::writeSessionSettings() {
765 	writeSessionSettings(nullptr);
766 }
767 
writeSessionSettings(Main::SessionSettings * stored)768 void Account::writeSessionSettings(Main::SessionSettings *stored) {
769 	if (_readingUserSettings) {
770 		LOG(("App Error: attempt to write settings while reading them!"));
771 		return;
772 	}
773 	LOG(("App Info: writing encrypted user settings..."));
774 
775 	if (!_settingsKey) {
776 		_settingsKey = GenerateKey(_basePath);
777 		writeMapQueued();
778 	}
779 
780 	auto userDataInstance = stored
781 		? stored
782 		: _owner->getSessionSettings();
783 	auto userData = userDataInstance
784 		? userDataInstance->serialize()
785 		: QByteArray();
786 
787 	auto recentStickers = cRecentStickersPreload();
788 	if (recentStickers.isEmpty() && _owner->sessionExists()) {
789 		const auto &stickers = _owner->session().data().stickers();
790 		recentStickers.reserve(stickers.getRecentPack().size());
791 		for (const auto &pair : std::as_const(stickers.getRecentPack())) {
792 			recentStickers.push_back(qMakePair(pair.first->id, pair.second));
793 		}
794 	}
795 
796 	uint32 size = 24 * (sizeof(quint32) + sizeof(qint32));
797 	size += sizeof(quint32);
798 	size += sizeof(quint32) + sizeof(qint32) + recentStickers.size() * (sizeof(uint64) + sizeof(ushort));
799 	size += sizeof(quint32) + 3 * sizeof(qint32);
800 	size += sizeof(quint32) + 2 * sizeof(qint32);
801 	size += sizeof(quint32) + sizeof(qint64) + sizeof(qint32);
802 	if (!userData.isEmpty()) {
803 		size += sizeof(quint32) + Serialize::bytearraySize(userData);
804 	}
805 
806 	EncryptedDescriptor data(size);
807 	data.stream << quint32(dbiUseExternalVideoPlayer) << qint32(cUseExternalVideoPlayer());
808 	data.stream << quint32(dbiCacheSettings) << qint64(_cacheTotalSizeLimit) << qint32(_cacheTotalTimeLimit) << qint64(_cacheBigFileTotalSizeLimit) << qint32(_cacheBigFileTotalTimeLimit);
809 	if (!userData.isEmpty()) {
810 		data.stream << quint32(dbiSessionSettings) << userData;
811 	}
812 	data.stream << quint32(dbiRecentStickers) << recentStickers;
813 
814 	FileWriteDescriptor file(_settingsKey, _basePath);
815 	file.writeEncrypted(data, _localKey);
816 }
817 
prepareReadSettingsContext() const818 ReadSettingsContext Account::prepareReadSettingsContext() const {
819 	return ReadSettingsContext{
820 		.legacyHasCustomDayBackground = (_legacyBackgroundKeyDay != 0)
821 	};
822 }
823 
readSessionSettings()824 std::unique_ptr<Main::SessionSettings> Account::readSessionSettings() {
825 	ReadSettingsContext context;
826 	FileReadDescriptor userSettings;
827 	if (!ReadEncryptedFile(userSettings, _settingsKey, _basePath, _localKey)) {
828 		LOG(("App Info: could not read encrypted user settings..."));
829 
830 		Local::readOldUserSettings(true, context);
831 		auto result = applyReadContext(std::move(context));
832 
833 		writeSessionSettings(result.get());
834 
835 		return result;
836 	}
837 
838 	LOG(("App Info: reading encrypted user settings..."));
839 	_readingUserSettings = true;
840 	while (!userSettings.stream.atEnd()) {
841 		quint32 blockId;
842 		userSettings.stream >> blockId;
843 		if (!CheckStreamStatus(userSettings.stream)) {
844 			_readingUserSettings = false;
845 			writeSessionSettings();
846 			return nullptr;
847 		}
848 
849 		if (!ReadSetting(blockId, userSettings.stream, userSettings.version, context)) {
850 			_readingUserSettings = false;
851 			writeSessionSettings();
852 			return nullptr;
853 		}
854 	}
855 	_readingUserSettings = false;
856 	LOG(("App Info: encrypted user settings read."));
857 
858 	auto result = applyReadContext(std::move(context));
859 	if (context.legacyRead) {
860 		writeSessionSettings(result.get());
861 	}
862 	return result;
863 }
864 
applyReadContext(ReadSettingsContext && context)865 std::unique_ptr<Main::SessionSettings> Account::applyReadContext(
866 		ReadSettingsContext &&context) {
867 	ApplyReadFallbackConfig(context);
868 
869 	if (context.cacheTotalSizeLimit) {
870 		_cacheTotalSizeLimit = context.cacheTotalSizeLimit;
871 		_cacheTotalTimeLimit = context.cacheTotalTimeLimit;
872 		_cacheBigFileTotalSizeLimit = context.cacheBigFileTotalSizeLimit;
873 		_cacheBigFileTotalTimeLimit = context.cacheBigFileTotalTimeLimit;
874 
875 		const auto &normal = Database::Settings();
876 		Assert(_cacheTotalSizeLimit > normal.maxDataSize);
877 		Assert(_cacheBigFileTotalSizeLimit > normal.maxDataSize);
878 	}
879 
880 	if (!context.mtpAuthorization.isEmpty()) {
881 		_owner->setMtpAuthorization(context.mtpAuthorization);
882 	} else {
883 		for (auto &key : context.mtpLegacyKeys) {
884 			_owner->setLegacyMtpKey(std::move(key));
885 		}
886 		if (context.mtpLegacyMainDcId) {
887 			_owner->setMtpMainDcId(context.mtpLegacyMainDcId);
888 			_owner->setSessionUserId(context.mtpLegacyUserId);
889 		}
890 	}
891 
892 	if (context.tileRead) {
893 		Window::Theme::Background()->setTileDayValue(context.tileDay);
894 		Window::Theme::Background()->setTileNightValue(context.tileNight);
895 	}
896 
897 	return std::move(context.sessionSettingsStorage);
898 }
899 
writeMtpData()900 void Account::writeMtpData() {
901 	Expects(_localKey != nullptr);
902 
903 	const auto serialized = _owner->serializeMtpAuthorization();
904 	const auto size = sizeof(quint32) + Serialize::bytearraySize(serialized);
905 
906 	FileWriteDescriptor mtp(ToFilePart(_dataNameKey), BaseGlobalPath());
907 	EncryptedDescriptor data(size);
908 	data.stream << quint32(dbiMtpAuthorization) << serialized;
909 	mtp.writeEncrypted(data, _localKey);
910 }
911 
readMtpData()912 void Account::readMtpData() {
913 	auto context = prepareReadSettingsContext();
914 
915 	FileReadDescriptor mtp;
916 	if (!ReadEncryptedFile(mtp, ToFilePart(_dataNameKey), BaseGlobalPath(), _localKey)) {
917 		if (_localKey) {
918 			Local::readOldMtpData(true, context);
919 			applyReadContext(std::move(context));
920 			writeMtpData();
921 		}
922 		return;
923 	}
924 
925 	LOG(("App Info: reading encrypted mtp data..."));
926 	while (!mtp.stream.atEnd()) {
927 		quint32 blockId;
928 		mtp.stream >> blockId;
929 		if (!CheckStreamStatus(mtp.stream)) {
930 			return writeMtpData();
931 		}
932 
933 		if (!ReadSetting(blockId, mtp.stream, mtp.version, context)) {
934 			return writeMtpData();
935 		}
936 	}
937 	applyReadContext(std::move(context));
938 }
939 
writeMtpConfig()940 void Account::writeMtpConfig() {
941 	Expects(_localKey != nullptr);
942 
943 	const auto serialized = _owner->mtp().config().serialize();
944 	const auto size = Serialize::bytearraySize(serialized);
945 
946 	FileWriteDescriptor file(u"config"_q, _basePath);
947 	EncryptedDescriptor data(size);
948 	data.stream << serialized;
949 	file.writeEncrypted(data, _localKey);
950 }
951 
readMtpConfig()952 std::unique_ptr<MTP::Config> Account::readMtpConfig() {
953 	Expects(_localKey != nullptr);
954 
955 	FileReadDescriptor file;
956 	if (!ReadEncryptedFile(file, "config", _basePath, _localKey)) {
957 		return nullptr;
958 	}
959 
960 	LOG(("App Info: reading encrypted mtp config..."));
961 	auto serialized = QByteArray();
962 	file.stream >> serialized;
963 	if (!CheckStreamStatus(file.stream)) {
964 		return nullptr;
965 	}
966 	return MTP::Config::FromSerialized(serialized);
967 }
968 
969 template <typename Callback>
EnumerateDrafts(const Data::HistoryDrafts & map,Data::Draft * cloudDraft,bool supportMode,const base::flat_map<Data::DraftKey,MessageDraftSource> & sources,Callback && callback)970 void EnumerateDrafts(
971 		const Data::HistoryDrafts &map,
972 		Data::Draft *cloudDraft,
973 		bool supportMode,
974 		const base::flat_map<Data::DraftKey, MessageDraftSource> &sources,
975 		Callback &&callback) {
976 	for (const auto &[key, draft] : map) {
977 		if (key == Data::DraftKey::Cloud() || sources.contains(key)) {
978 			continue;
979 		} else if (key == Data::DraftKey::Local()
980 			&& !supportMode
981 			&& Data::draftsAreEqual(draft.get(), cloudDraft)) {
982 			continue;
983 		}
984 		callback(
985 			key,
986 			draft->msgId,
987 			draft->textWithTags,
988 			draft->previewState,
989 			draft->cursor);
990 	}
991 	for (const auto &[key, source] : sources) {
992 		const auto draft = source.draft();
993 		const auto cursor = source.cursor();
994 		if (draft.msgId
995 			|| !draft.textWithTags.text.isEmpty()
996 			|| cursor != MessageCursor()) {
997 			callback(
998 				key,
999 				draft.msgId,
1000 				draft.textWithTags,
1001 				draft.previewState,
1002 				cursor);
1003 		}
1004 	}
1005 }
1006 
registerDraftSource(not_null<History * > history,Data::DraftKey key,MessageDraftSource source)1007 void Account::registerDraftSource(
1008 		not_null<History*> history,
1009 		Data::DraftKey key,
1010 		MessageDraftSource source) {
1011 	Expects(source.draft != nullptr);
1012 	Expects(source.cursor != nullptr);
1013 
1014 	_draftSources[history][key] = std::move(source);
1015 }
1016 
unregisterDraftSource(not_null<History * > history,Data::DraftKey key)1017 void Account::unregisterDraftSource(
1018 		not_null<History*> history,
1019 		Data::DraftKey key) {
1020 	const auto i = _draftSources.find(history);
1021 	if (i != _draftSources.end()) {
1022 		i->second.remove(key);
1023 		if (i->second.empty()) {
1024 			_draftSources.erase(i);
1025 		}
1026 	}
1027 }
1028 
writeDrafts(not_null<History * > history)1029 void Account::writeDrafts(not_null<History*> history) {
1030 	const auto peerId = history->peer->id;
1031 	const auto &map = history->draftsMap();
1032 	const auto cloudIt = map.find(Data::DraftKey::Cloud());
1033 	const auto cloudDraft = (cloudIt != end(map))
1034 		? cloudIt->second.get()
1035 		: nullptr;
1036 	const auto supportMode = _owner->session().supportMode();
1037 	const auto sourcesIt = _draftSources.find(history);
1038 	const auto &sources = (sourcesIt != _draftSources.end())
1039 		? sourcesIt->second
1040 		: EmptyMessageDraftSources();
1041 	auto count = 0;
1042 	EnumerateDrafts(
1043 		map,
1044 		cloudDraft,
1045 		supportMode,
1046 		sources,
1047 		[&](auto&&...) { ++count; });
1048 	if (!count) {
1049 		auto i = _draftsMap.find(peerId);
1050 		if (i != _draftsMap.cend()) {
1051 			ClearKey(i->second, _basePath);
1052 			_draftsMap.erase(i);
1053 			writeMapDelayed();
1054 		}
1055 
1056 		_draftsNotReadMap.remove(peerId);
1057 		return;
1058 	}
1059 
1060 	auto i = _draftsMap.find(peerId);
1061 	if (i == _draftsMap.cend()) {
1062 		i = _draftsMap.emplace(peerId, GenerateKey(_basePath)).first;
1063 		writeMapQueued();
1064 	}
1065 
1066 	auto size = int(sizeof(quint64) * 2 + sizeof(quint32));
1067 	const auto sizeCallback = [&](
1068 			auto&&, // key
1069 			MsgId, // msgId
1070 			const TextWithTags &text,
1071 			Data::PreviewState,
1072 			auto&&) { // cursor
1073 		size += sizeof(qint64) // key
1074 			+ Serialize::stringSize(text.text)
1075 			+ sizeof(qint64) + TextUtilities::SerializeTagsSize(text.tags)
1076 			+ sizeof(qint64) + sizeof(qint32); // msgId, previewState
1077 	};
1078 	EnumerateDrafts(
1079 		map,
1080 		cloudDraft,
1081 		supportMode,
1082 		sources,
1083 		sizeCallback);
1084 
1085 	EncryptedDescriptor data(size);
1086 	data.stream
1087 		<< quint64(kMultiDraftTag)
1088 		<< SerializePeerId(peerId)
1089 		<< quint32(count);
1090 
1091 	const auto writeCallback = [&](
1092 			const Data::DraftKey &key,
1093 			MsgId msgId,
1094 			const TextWithTags &text,
1095 			Data::PreviewState previewState,
1096 			auto&&) { // cursor
1097 		data.stream
1098 			<< key.serialize()
1099 			<< text.text
1100 			<< TextUtilities::SerializeTags(text.tags)
1101 			<< qint64(msgId.bare)
1102 			<< qint32(previewState);
1103 	};
1104 	EnumerateDrafts(
1105 		map,
1106 		cloudDraft,
1107 		supportMode,
1108 		sources,
1109 		writeCallback);
1110 
1111 	FileWriteDescriptor file(i->second, _basePath);
1112 	file.writeEncrypted(data, _localKey);
1113 
1114 	_draftsNotReadMap.remove(peerId);
1115 }
1116 
writeDraftCursors(not_null<History * > history)1117 void Account::writeDraftCursors(not_null<History*> history) {
1118 	const auto peerId = history->peer->id;
1119 	const auto &map = history->draftsMap();
1120 	const auto cloudIt = map.find(Data::DraftKey::Cloud());
1121 	const auto cloudDraft = (cloudIt != end(map))
1122 		? cloudIt->second.get()
1123 		: nullptr;
1124 	const auto supportMode = _owner->session().supportMode();
1125 	const auto sourcesIt = _draftSources.find(history);
1126 	const auto &sources = (sourcesIt != _draftSources.end())
1127 		? sourcesIt->second
1128 		: EmptyMessageDraftSources();
1129 	auto count = 0;
1130 	EnumerateDrafts(
1131 		map,
1132 		cloudDraft,
1133 		supportMode,
1134 		sources,
1135 		[&](auto&&...) { ++count; });
1136 	if (!count) {
1137 		clearDraftCursors(peerId);
1138 		return;
1139 	}
1140 	auto i = _draftCursorsMap.find(peerId);
1141 	if (i == _draftCursorsMap.cend()) {
1142 		i = _draftCursorsMap.emplace(peerId, GenerateKey(_basePath)).first;
1143 		writeMapQueued();
1144 	}
1145 
1146 	auto size = int(sizeof(quint64) * 2
1147 		+ sizeof(quint32)
1148 		+ (sizeof(qint64) + sizeof(qint32) * 3) * count);
1149 
1150 	EncryptedDescriptor data(size);
1151 	data.stream
1152 		<< quint64(kMultiDraftCursorsTag)
1153 		<< SerializePeerId(peerId)
1154 		<< quint32(count);
1155 
1156 	const auto writeCallback = [&](
1157 			const Data::DraftKey &key,
1158 			MsgId, // msgId
1159 			auto&&, // text
1160 			Data::PreviewState,
1161 			const MessageCursor &cursor) { // cursor
1162 		data.stream
1163 			<< key.serialize()
1164 			<< qint32(cursor.position)
1165 			<< qint32(cursor.anchor)
1166 			<< qint32(cursor.scroll);
1167 	};
1168 	EnumerateDrafts(
1169 		map,
1170 		cloudDraft,
1171 		supportMode,
1172 		sources,
1173 		writeCallback);
1174 
1175 	FileWriteDescriptor file(i->second, _basePath);
1176 	file.writeEncrypted(data, _localKey);
1177 }
1178 
clearDraftCursors(PeerId peerId)1179 void Account::clearDraftCursors(PeerId peerId) {
1180 	const auto i = _draftCursorsMap.find(peerId);
1181 	if (i != _draftCursorsMap.cend()) {
1182 		ClearKey(i->second, _basePath);
1183 		_draftCursorsMap.erase(i);
1184 		writeMapDelayed();
1185 	}
1186 }
1187 
readDraftCursors(PeerId peerId,Data::HistoryDrafts & map)1188 void Account::readDraftCursors(PeerId peerId, Data::HistoryDrafts &map) {
1189 	const auto j = _draftCursorsMap.find(peerId);
1190 	if (j == _draftCursorsMap.cend()) {
1191 		return;
1192 	}
1193 
1194 	FileReadDescriptor draft;
1195 	if (!ReadEncryptedFile(draft, j->second, _basePath, _localKey)) {
1196 		clearDraftCursors(peerId);
1197 		return;
1198 	}
1199 	quint64 tag = 0;
1200 	draft.stream >> tag;
1201 	if (tag != kMultiDraftCursorsTag
1202 		&& tag != kMultiDraftCursorsTagOld
1203 		&& tag != kMultiDraftTagOld) {
1204 		readDraftCursorsLegacy(peerId, draft, tag, map);
1205 		return;
1206 	}
1207 	quint64 draftPeerSerialized = 0;
1208 	quint32 count = 0;
1209 	draft.stream >> draftPeerSerialized >> count;
1210 	const auto draftPeer = DeserializePeerId(draftPeerSerialized);
1211 	if (!count || count > 1000 || draftPeer != peerId) {
1212 		clearDraftCursors(peerId);
1213 		return;
1214 	}
1215 	const auto keysWritten = (tag == kMultiDraftCursorsTag);
1216 	const auto keysOld = (tag == kMultiDraftCursorsTagOld);
1217 	for (auto i = 0; i != count; ++i) {
1218 		qint64 keyValue = 0;
1219 		qint32 keyValueOld = 0;
1220 		if (keysWritten) {
1221 			draft.stream >> keyValue;
1222 		} else if (keysOld) {
1223 			draft.stream >> keyValueOld;
1224 		}
1225 		const auto key = keysWritten
1226 			? Data::DraftKey::FromSerialized(keyValue)
1227 			: keysOld
1228 			? Data::DraftKey::FromSerializedOld(keyValueOld)
1229 			: Data::DraftKey::Local();
1230 		qint32 position = 0, anchor = 0, scroll = QFIXED_MAX;
1231 		draft.stream >> position >> anchor >> scroll;
1232 		if (const auto i = map.find(key); i != end(map)) {
1233 			i->second->cursor = MessageCursor(position, anchor, scroll);
1234 		}
1235 	}
1236 }
1237 
readDraftCursorsLegacy(PeerId peerId,details::FileReadDescriptor & draft,quint64 draftPeerSerialized,Data::HistoryDrafts & map)1238 void Account::readDraftCursorsLegacy(
1239 		PeerId peerId,
1240 		details::FileReadDescriptor &draft,
1241 		quint64 draftPeerSerialized,
1242 		Data::HistoryDrafts &map) {
1243 	qint32 localPosition = 0, localAnchor = 0, localScroll = QFIXED_MAX;
1244 	qint32 editPosition = 0, editAnchor = 0, editScroll = QFIXED_MAX;
1245 	draft.stream >> localPosition >> localAnchor >> localScroll;
1246 	if (!draft.stream.atEnd()) {
1247 		draft.stream >> editPosition >> editAnchor >> editScroll;
1248 	}
1249 
1250 	const auto draftPeer = DeserializePeerId(draftPeerSerialized);
1251 	if (draftPeer != peerId) {
1252 		clearDraftCursors(peerId);
1253 		return;
1254 	}
1255 
1256 	if (const auto i = map.find(Data::DraftKey::Local()); i != end(map)) {
1257 		i->second->cursor = MessageCursor(
1258 			localPosition,
1259 			localAnchor,
1260 			localScroll);
1261 	}
1262 	if (const auto i = map.find(Data::DraftKey::LocalEdit()); i != end(map)) {
1263 		i->second->cursor = MessageCursor(
1264 			editPosition,
1265 			editAnchor,
1266 			editScroll);
1267 	}
1268 }
1269 
readDraftsWithCursors(not_null<History * > history)1270 void Account::readDraftsWithCursors(not_null<History*> history) {
1271 	const auto guard = gsl::finally([&] {
1272 		if (const auto migrated = history->migrateFrom()) {
1273 			readDraftsWithCursors(migrated);
1274 			migrated->clearLocalEditDraft();
1275 			history->takeLocalDraft(migrated);
1276 		}
1277 	});
1278 
1279 	PeerId peerId = history->peer->id;
1280 	if (!_draftsNotReadMap.remove(peerId)) {
1281 		clearDraftCursors(peerId);
1282 		return;
1283 	}
1284 
1285 	const auto j = _draftsMap.find(peerId);
1286 	if (j == _draftsMap.cend()) {
1287 		clearDraftCursors(peerId);
1288 		return;
1289 	}
1290 	FileReadDescriptor draft;
1291 	if (!ReadEncryptedFile(draft, j->second, _basePath, _localKey)) {
1292 		ClearKey(j->second, _basePath);
1293 		_draftsMap.erase(j);
1294 		clearDraftCursors(peerId);
1295 		return;
1296 	}
1297 
1298 	quint64 tag = 0;
1299 	draft.stream >> tag;
1300 	if (tag != kMultiDraftTag && tag != kMultiDraftTagOld) {
1301 		readDraftsWithCursorsLegacy(history, draft, tag);
1302 		return;
1303 	}
1304 	quint32 count = 0;
1305 	quint64 draftPeerSerialized = 0;
1306 	draft.stream >> draftPeerSerialized >> count;
1307 	const auto draftPeer = DeserializePeerId(draftPeerSerialized);
1308 	if (!count || count > 1000 || draftPeer != peerId) {
1309 		ClearKey(j->second, _basePath);
1310 		_draftsMap.erase(j);
1311 		clearDraftCursors(peerId);
1312 		return;
1313 	}
1314 	auto map = Data::HistoryDrafts();
1315 	const auto keysOld = (tag == kMultiDraftTagOld);
1316 	for (auto i = 0; i != count; ++i) {
1317 		TextWithTags data;
1318 		QByteArray tagsSerialized;
1319 		qint64 keyValue = 0;
1320 		qint32 keyValueOld = 0, messageId = 0, uncheckedPreviewState = 0;
1321 		if (keysOld) {
1322 			draft.stream >> keyValueOld;
1323 		} else {
1324 			draft.stream >> keyValue;
1325 		}
1326 		draft.stream
1327 			>> data.text
1328 			>> tagsSerialized
1329 			>> messageId
1330 			>> uncheckedPreviewState;
1331 		data.tags = TextUtilities::DeserializeTags(
1332 			tagsSerialized,
1333 			data.text.size());
1334 		auto previewState = Data::PreviewState::Allowed;
1335 		switch (static_cast<Data::PreviewState>(uncheckedPreviewState)) {
1336 		case Data::PreviewState::Cancelled:
1337 		case Data::PreviewState::EmptyOnEdit:
1338 			previewState = Data::PreviewState(uncheckedPreviewState);
1339 		}
1340 		const auto key = keysOld
1341 			? Data::DraftKey::FromSerializedOld(keyValueOld)
1342 			: Data::DraftKey::FromSerialized(keyValue);
1343 		if (key && key != Data::DraftKey::Cloud()) {
1344 			map.emplace(key, std::make_unique<Data::Draft>(
1345 				data,
1346 				messageId,
1347 				MessageCursor(),
1348 				previewState));
1349 		}
1350 	}
1351 	if (draft.stream.status() != QDataStream::Ok) {
1352 		ClearKey(j->second, _basePath);
1353 		_draftsMap.erase(j);
1354 		clearDraftCursors(peerId);
1355 		return;
1356 	}
1357 	readDraftCursors(peerId, map);
1358 	history->setDraftsMap(std::move(map));
1359 }
1360 
readDraftsWithCursorsLegacy(not_null<History * > history,details::FileReadDescriptor & draft,quint64 draftPeerSerialized)1361 void Account::readDraftsWithCursorsLegacy(
1362 		not_null<History*> history,
1363 		details::FileReadDescriptor &draft,
1364 		quint64 draftPeerSerialized) {
1365 	TextWithTags msgData, editData;
1366 	QByteArray msgTagsSerialized, editTagsSerialized;
1367 	qint32 msgReplyTo = 0, msgPreviewCancelled = 0, editMsgId = 0, editPreviewCancelled = 0;
1368 	draft.stream >> msgData.text;
1369 	if (draft.version >= 9048) {
1370 		draft.stream >> msgTagsSerialized;
1371 	}
1372 	if (draft.version >= 7021) {
1373 		draft.stream >> msgReplyTo;
1374 		if (draft.version >= 8001) {
1375 			draft.stream >> msgPreviewCancelled;
1376 			if (!draft.stream.atEnd()) {
1377 				draft.stream >> editData.text;
1378 				if (draft.version >= 9048) {
1379 					draft.stream >> editTagsSerialized;
1380 				}
1381 				draft.stream >> editMsgId >> editPreviewCancelled;
1382 			}
1383 		}
1384 	}
1385 	const auto peerId = history->peer->id;
1386 	const auto draftPeer = DeserializePeerId(draftPeerSerialized);
1387 	if (draftPeer != peerId) {
1388 		const auto j = _draftsMap.find(peerId);
1389 		if (j != _draftsMap.cend()) {
1390 			ClearKey(j->second, _basePath);
1391 			_draftsMap.erase(j);
1392 		}
1393 		clearDraftCursors(peerId);
1394 		return;
1395 	}
1396 
1397 	msgData.tags = TextUtilities::DeserializeTags(
1398 		msgTagsSerialized,
1399 		msgData.text.size());
1400 	editData.tags = TextUtilities::DeserializeTags(
1401 		editTagsSerialized,
1402 		editData.text.size());
1403 
1404 	auto map = base::flat_map<Data::DraftKey, std::unique_ptr<Data::Draft>>();
1405 	if (!msgData.text.isEmpty() || msgReplyTo) {
1406 		map.emplace(Data::DraftKey::Local(), std::make_unique<Data::Draft>(
1407 			msgData,
1408 			msgReplyTo,
1409 			MessageCursor(),
1410 			(msgPreviewCancelled
1411 				? Data::PreviewState::Cancelled
1412 				: Data::PreviewState::Allowed)));
1413 	}
1414 	if (editMsgId) {
1415 		map.emplace(Data::DraftKey::LocalEdit(), std::make_unique<Data::Draft>(
1416 			editData,
1417 			editMsgId,
1418 			MessageCursor(),
1419 			(editPreviewCancelled
1420 				? Data::PreviewState::Cancelled
1421 				: Data::PreviewState::Allowed)));
1422 	}
1423 	readDraftCursors(peerId, map);
1424 	history->setDraftsMap(std::move(map));
1425 }
1426 
hasDraftCursors(PeerId peer)1427 bool Account::hasDraftCursors(PeerId peer) {
1428 	return _draftCursorsMap.contains(peer);
1429 }
1430 
hasDraft(PeerId peer)1431 bool Account::hasDraft(PeerId peer) {
1432 	return _draftsMap.contains(peer);
1433 }
1434 
writeFileLocation(MediaKey location,const Core::FileLocation & local)1435 void Account::writeFileLocation(MediaKey location, const Core::FileLocation &local) {
1436 	if (local.fname.isEmpty()) {
1437 		return;
1438 	}
1439 	if (!local.inMediaCache()) {
1440 		const auto aliasIt = _fileLocationAliases.constFind(location);
1441 		if (aliasIt != _fileLocationAliases.cend()) {
1442 			location = aliasIt.value();
1443 		}
1444 
1445 		const auto i = _fileLocationPairs.find(local.fname);
1446 		if (i != _fileLocationPairs.cend()) {
1447 			if (i.value().second == local) {
1448 				if (i.value().first != location) {
1449 					_fileLocationAliases.insert(location, i.value().first);
1450 					writeLocationsQueued();
1451 				}
1452 				return;
1453 			}
1454 			if (i.value().first != location) {
1455 				for (auto j = _fileLocations.find(i.value().first), e = _fileLocations.end(); (j != e) && (j.key() == i.value().first); ++j) {
1456 					if (j.value() == i.value().second) {
1457 						_fileLocations.erase(j);
1458 						break;
1459 					}
1460 				}
1461 				_fileLocationPairs.erase(i);
1462 			}
1463 		}
1464 		_fileLocationPairs.insert(local.fname, { location, local });
1465 	} else {
1466 		for (auto i = _fileLocations.find(location); (i != _fileLocations.end()) && (i.key() == location);) {
1467 			if (i.value().inMediaCache() || i.value().check()) {
1468 				return;
1469 			}
1470 			i = _fileLocations.erase(i);
1471 		}
1472 	}
1473 	_fileLocations.insert(location, local);
1474 	writeLocationsQueued();
1475 }
1476 
removeFileLocation(MediaKey location)1477 void Account::removeFileLocation(MediaKey location) {
1478 	auto i = _fileLocations.find(location);
1479 	if (i == _fileLocations.end()) {
1480 		return;
1481 	}
1482 	while (i != _fileLocations.end() && (i.key() == location)) {
1483 		i = _fileLocations.erase(i);
1484 	}
1485 	writeLocationsQueued();
1486 }
1487 
readFileLocation(MediaKey location)1488 Core::FileLocation Account::readFileLocation(MediaKey location) {
1489 	const auto aliasIt = _fileLocationAliases.constFind(location);
1490 	if (aliasIt != _fileLocationAliases.cend()) {
1491 		location = aliasIt.value();
1492 	}
1493 
1494 	for (auto i = _fileLocations.find(location); (i != _fileLocations.end()) && (i.key() == location);) {
1495 		if (!i.value().inMediaCache() && !i.value().check()) {
1496 			_fileLocationPairs.remove(i.value().fname);
1497 			i = _fileLocations.erase(i);
1498 			writeLocationsDelayed();
1499 			continue;
1500 		}
1501 		return i.value();
1502 	}
1503 	return Core::FileLocation();
1504 }
1505 
cacheKey() const1506 EncryptionKey Account::cacheKey() const {
1507 	Expects(_localKey != nullptr);
1508 
1509 	return EncryptionKey(bytes::make_vector(_localKey->data()));
1510 }
1511 
cacheBigFileKey() const1512 EncryptionKey Account::cacheBigFileKey() const {
1513 	return cacheKey();
1514 }
1515 
cachePath() const1516 QString Account::cachePath() const {
1517 	Expects(!_databasePath.isEmpty());
1518 
1519 	return _databasePath + "cache";
1520 }
1521 
cacheSettings() const1522 Cache::Database::Settings Account::cacheSettings() const {
1523 	auto result = Cache::Database::Settings();
1524 	result.clearOnWrongKey = true;
1525 	result.totalSizeLimit = _cacheTotalSizeLimit;
1526 	result.totalTimeLimit = _cacheTotalTimeLimit;
1527 	result.maxDataSize = kMaxFileInMemory;
1528 	return result;
1529 }
1530 
updateCacheSettings(Cache::Database::SettingsUpdate & update,Cache::Database::SettingsUpdate & updateBig)1531 void Account::updateCacheSettings(
1532 		Cache::Database::SettingsUpdate &update,
1533 		Cache::Database::SettingsUpdate &updateBig) {
1534 	Expects(update.totalSizeLimit > Database::Settings().maxDataSize);
1535 	Expects(update.totalTimeLimit >= 0);
1536 	Expects(updateBig.totalSizeLimit > Database::Settings().maxDataSize);
1537 	Expects(updateBig.totalTimeLimit >= 0);
1538 
1539 	if (_cacheTotalSizeLimit == update.totalSizeLimit
1540 		&& _cacheTotalTimeLimit == update.totalTimeLimit
1541 		&& _cacheBigFileTotalSizeLimit == updateBig.totalSizeLimit
1542 		&& _cacheBigFileTotalTimeLimit == updateBig.totalTimeLimit) {
1543 		return;
1544 	}
1545 	_cacheTotalSizeLimit = update.totalSizeLimit;
1546 	_cacheTotalTimeLimit = update.totalTimeLimit;
1547 	_cacheBigFileTotalSizeLimit = updateBig.totalSizeLimit;
1548 	_cacheBigFileTotalTimeLimit = updateBig.totalTimeLimit;
1549 	writeSessionSettings();
1550 }
1551 
cacheBigFilePath() const1552 QString Account::cacheBigFilePath() const {
1553 	Expects(!_databasePath.isEmpty());
1554 
1555 	return _databasePath + "media_cache";
1556 }
1557 
cacheBigFileSettings() const1558 Cache::Database::Settings Account::cacheBigFileSettings() const {
1559 	auto result = Cache::Database::Settings();
1560 	result.clearOnWrongKey = true;
1561 	result.totalSizeLimit = _cacheBigFileTotalSizeLimit;
1562 	result.totalTimeLimit = _cacheBigFileTotalTimeLimit;
1563 	result.maxDataSize = kMaxFileInMemory;
1564 	return result;
1565 }
1566 
writeStickerSet(QDataStream & stream,const Data::StickersSet & set)1567 void Account::writeStickerSet(
1568 		QDataStream &stream,
1569 		const Data::StickersSet &set) {
1570 	using SetFlag = Data::StickersSetFlag;
1571 	const auto writeInfo = [&](int count) {
1572 		stream
1573 			<< quint64(set.id)
1574 			<< quint64(set.accessHash)
1575 			<< quint64(set.hash)
1576 			<< set.title
1577 			<< set.shortName
1578 			<< qint32(count)
1579 			<< qint32(set.flags)
1580 			<< qint32(set.installDate);
1581 		Serialize::writeImageLocation(stream, set.thumbnailLocation());
1582 	};
1583 	if (set.flags & SetFlag::NotLoaded) {
1584 		writeInfo(-set.count);
1585 		return;
1586 	} else if (set.stickers.isEmpty()) {
1587 		return;
1588 	}
1589 
1590 	writeInfo(set.stickers.size());
1591 	for (const auto &sticker : set.stickers) {
1592 		Serialize::Document::writeToStream(stream, sticker);
1593 	}
1594 	stream << qint32(set.dates.size());
1595 	if (!set.dates.empty()) {
1596 		Assert(set.dates.size() == set.stickers.size());
1597 		for (const auto date : set.dates) {
1598 			stream << qint32(date);
1599 		}
1600 	}
1601 	stream << qint32(set.emoji.size());
1602 	for (auto j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) {
1603 		stream << j.key()->id() << qint32(j->size());
1604 		for (const auto sticker : *j) {
1605 			stream << quint64(sticker->id);
1606 		}
1607 	}
1608 }
1609 
1610 // In generic method _writeStickerSets() we look through all the sets and call a
1611 // callback on each set to see, if we write it, skip it or abort the whole write.
1612 enum class StickerSetCheckResult {
1613 	Write,
1614 	Skip,
1615 	Abort,
1616 };
1617 
1618 // CheckSet is a functor on Data::StickersSet, which returns a StickerSetCheckResult.
1619 template <typename CheckSet>
writeStickerSets(FileKey & stickersKey,CheckSet checkSet,const Data::StickersSetsOrder & order)1620 void Account::writeStickerSets(
1621 		FileKey &stickersKey,
1622 		CheckSet checkSet,
1623 		const Data::StickersSetsOrder &order) {
1624 	using SetFlag = Data::StickersSetFlag;
1625 
1626 	const auto &sets = _owner->session().data().stickers().sets();
1627 	if (sets.empty()) {
1628 		if (stickersKey) {
1629 			ClearKey(stickersKey, _basePath);
1630 			stickersKey = 0;
1631 			writeMapDelayed();
1632 		}
1633 		return;
1634 	}
1635 
1636 	// versionTag + version + count
1637 	quint32 size = sizeof(quint32) + sizeof(qint32) + sizeof(qint32);
1638 
1639 	int32 setsCount = 0;
1640 	for (const auto &[id, set] : sets) {
1641 		const auto raw = set.get();
1642 		auto result = checkSet(*raw);
1643 		if (result == StickerSetCheckResult::Abort) {
1644 			return;
1645 		} else if (result == StickerSetCheckResult::Skip) {
1646 			continue;
1647 		}
1648 
1649 		// id + accessHash + hash + title + shortName + stickersCount + flags + installDate
1650 		size += sizeof(quint64) * 3
1651 			+ Serialize::stringSize(raw->title)
1652 			+ Serialize::stringSize(raw->shortName)
1653 			+ sizeof(qint32) * 3
1654 			+ Serialize::imageLocationSize(raw->thumbnailLocation());
1655 		if (raw->flags & SetFlag::NotLoaded) {
1656 			continue;
1657 		}
1658 
1659 		for (const auto sticker : std::as_const(raw->stickers)) {
1660 			size += Serialize::Document::sizeInStream(sticker);
1661 		}
1662 
1663 		size += sizeof(qint32); // datesCount
1664 		if (!raw->dates.empty()) {
1665 			Assert(raw->stickers.size() == raw->dates.size());
1666 			size += raw->dates.size() * sizeof(qint32);
1667 		}
1668 
1669 		size += sizeof(qint32); // emojiCount
1670 		for (auto j = raw->emoji.cbegin(), e = raw->emoji.cend(); j != e; ++j) {
1671 			size += Serialize::stringSize(j.key()->id()) + sizeof(qint32) + (j->size() * sizeof(quint64));
1672 		}
1673 
1674 		++setsCount;
1675 	}
1676 	if (!setsCount && order.isEmpty()) {
1677 		if (stickersKey) {
1678 			ClearKey(stickersKey, _basePath);
1679 			stickersKey = 0;
1680 			writeMapDelayed();
1681 		}
1682 		return;
1683 	}
1684 	size += sizeof(qint32) + (order.size() * sizeof(quint64));
1685 
1686 	if (!stickersKey) {
1687 		stickersKey = GenerateKey(_basePath);
1688 		writeMapQueued();
1689 	}
1690 	EncryptedDescriptor data(size);
1691 	data.stream
1692 		<< quint32(kStickersVersionTag)
1693 		<< qint32(kStickersSerializeVersion)
1694 		<< qint32(setsCount);
1695 	for (const auto &[id, set] : sets) {
1696 		auto result = checkSet(*set);
1697 		if (result == StickerSetCheckResult::Abort) {
1698 			return;
1699 		} else if (result == StickerSetCheckResult::Skip) {
1700 			continue;
1701 		}
1702 		writeStickerSet(data.stream, *set);
1703 	}
1704 	data.stream << order;
1705 
1706 	FileWriteDescriptor file(stickersKey, _basePath);
1707 	file.writeEncrypted(data, _localKey);
1708 }
1709 
readStickerSets(FileKey & stickersKey,Data::StickersSetsOrder * outOrder,Data::StickersSetFlags readingFlags)1710 void Account::readStickerSets(
1711 		FileKey &stickersKey,
1712 		Data::StickersSetsOrder *outOrder,
1713 		Data::StickersSetFlags readingFlags) {
1714 	using SetFlag = Data::StickersSetFlag;
1715 
1716 	FileReadDescriptor stickers;
1717 	if (!ReadEncryptedFile(stickers, stickersKey, _basePath, _localKey)) {
1718 		ClearKey(stickersKey, _basePath);
1719 		stickersKey = 0;
1720 		writeMapDelayed();
1721 		return;
1722 	}
1723 
1724 	const auto failed = [&] {
1725 		ClearKey(stickersKey, _basePath);
1726 		stickersKey = 0;
1727 	};
1728 
1729 	auto &sets = _owner->session().data().stickers().setsRef();
1730 	if (outOrder) outOrder->clear();
1731 
1732 	quint32 versionTag = 0;
1733 	qint32 version = 0;
1734 	stickers.stream >> versionTag >> version;
1735 	if (versionTag != kStickersVersionTag
1736 		|| version != kStickersSerializeVersion) {
1737 		// Old data, without sticker set thumbnails.
1738 		return failed();
1739 	}
1740 	qint32 count = 0;
1741 	stickers.stream >> count;
1742 	if (!CheckStreamStatus(stickers.stream)
1743 		|| (count < 0)
1744 		|| (count > kMaxSavedStickerSetsCount)) {
1745 		return failed();
1746 	}
1747 	for (auto i = 0; i != count; ++i) {
1748 		quint64 setId = 0, setAccessHash = 0, setHash = 0;
1749 		QString setTitle, setShortName;
1750 		qint32 scnt = 0;
1751 		qint32 setInstallDate = 0;
1752 		Data::StickersSetFlags setFlags = 0;
1753 		qint32 setFlagsValue = 0;
1754 		ImageLocation setThumbnail;
1755 
1756 		stickers.stream
1757 			>> setId
1758 			>> setAccessHash
1759 			>> setHash
1760 			>> setTitle
1761 			>> setShortName
1762 			>> scnt
1763 			>> setFlagsValue
1764 			>> setInstallDate;
1765 		const auto thumbnail = Serialize::readImageLocation(
1766 			stickers.version,
1767 			stickers.stream);
1768 		if (!thumbnail || !CheckStreamStatus(stickers.stream)) {
1769 			return failed();
1770 		} else if (thumbnail->valid() && thumbnail->isLegacy()) {
1771 			// No thumb_version information in legacy location.
1772 			return failed();
1773 		} else {
1774 			setThumbnail = *thumbnail;
1775 		}
1776 
1777 		setFlags = Data::StickersSetFlags::from_raw(setFlagsValue);
1778 		if (setId == Data::Stickers::DefaultSetId) {
1779 			setTitle = tr::lng_stickers_default_set(tr::now);
1780 			setFlags |= SetFlag::Official | SetFlag::Special;
1781 		} else if (setId == Data::Stickers::CustomSetId) {
1782 			setTitle = qsl("Custom stickers");
1783 			setFlags |= SetFlag::Special;
1784 		} else if ((setId == Data::Stickers::CloudRecentSetId)
1785 				|| (setId == Data::Stickers::CloudRecentAttachedSetId)) {
1786 			setTitle = tr::lng_recent_stickers(tr::now);
1787 			setFlags |= SetFlag::Special;
1788 		} else if (setId == Data::Stickers::FavedSetId) {
1789 			setTitle = Lang::Hard::FavedSetTitle();
1790 			setFlags |= SetFlag::Special;
1791 		} else if (!setId) {
1792 			continue;
1793 		}
1794 
1795 		auto it = sets.find(setId);
1796 		if (it == sets.cend()) {
1797 			// We will set this flags from order lists when reading those stickers.
1798 			setFlags &= ~(SetFlag::Installed | SetFlag::Featured);
1799 			it = sets.emplace(setId, std::make_unique<Data::StickersSet>(
1800 				&_owner->session().data(),
1801 				setId,
1802 				setAccessHash,
1803 				setHash,
1804 				setTitle,
1805 				setShortName,
1806 				0,
1807 				setFlags,
1808 				setInstallDate)).first;
1809 			it->second->setThumbnail(
1810 				ImageWithLocation{ .location = setThumbnail });
1811 		}
1812 		const auto set = it->second.get();
1813 		const auto inputSet = set->identifier();
1814 		const auto fillStickers = set->stickers.isEmpty();
1815 
1816 		if (scnt < 0) { // disabled not loaded set
1817 			if (!set->count || fillStickers) {
1818 				set->count = -scnt;
1819 			}
1820 			continue;
1821 		}
1822 
1823 		if (fillStickers) {
1824 			set->stickers.reserve(scnt);
1825 			set->count = 0;
1826 		}
1827 
1828 		Serialize::Document::StickerSetInfo info(
1829 			setId,
1830 			setAccessHash,
1831 			setShortName);
1832 		base::flat_set<DocumentId> read;
1833 		for (int32 j = 0; j < scnt; ++j) {
1834 			auto document = Serialize::Document::readStickerFromStream(
1835 				&_owner->session(),
1836 				stickers.version,
1837 				stickers.stream, info);
1838 			if (!CheckStreamStatus(stickers.stream)) {
1839 				return failed();
1840 			} else if (!document
1841 				|| !document->sticker()
1842 				|| read.contains(document->id)) {
1843 				continue;
1844 			}
1845 			read.emplace(document->id);
1846 			if (fillStickers) {
1847 				set->stickers.push_back(document);
1848 				if (!(set->flags & SetFlag::Special)) {
1849 					if (!document->sticker()->set.id) {
1850 						document->sticker()->set = inputSet;
1851 					}
1852 				}
1853 				++set->count;
1854 			}
1855 		}
1856 
1857 		qint32 datesCount = 0;
1858 		stickers.stream >> datesCount;
1859 		if (datesCount > 0) {
1860 			if (datesCount != scnt) {
1861 				return failed();
1862 			}
1863 			const auto fillDates =
1864 				((set->id == Data::Stickers::CloudRecentSetId)
1865 					|| (set->id == Data::Stickers::CloudRecentAttachedSetId))
1866 				&& (set->stickers.size() == datesCount);
1867 			if (fillDates) {
1868 				set->dates.clear();
1869 				set->dates.reserve(datesCount);
1870 			}
1871 			for (auto i = 0; i != datesCount; ++i) {
1872 				qint32 date = 0;
1873 				stickers.stream >> date;
1874 				if (fillDates) {
1875 					set->dates.push_back(TimeId(date));
1876 				}
1877 			}
1878 		}
1879 
1880 		qint32 emojiCount = 0;
1881 		stickers.stream >> emojiCount;
1882 		if (!CheckStreamStatus(stickers.stream) || emojiCount < 0) {
1883 			return failed();
1884 		}
1885 		for (int32 j = 0; j < emojiCount; ++j) {
1886 			QString emojiString;
1887 			qint32 stickersCount;
1888 			stickers.stream >> emojiString >> stickersCount;
1889 			Data::StickersPack pack;
1890 			pack.reserve(stickersCount);
1891 			for (int32 k = 0; k < stickersCount; ++k) {
1892 				quint64 id;
1893 				stickers.stream >> id;
1894 				const auto doc = _owner->session().data().document(id);
1895 				if (!doc->sticker()) continue;
1896 
1897 				pack.push_back(doc);
1898 			}
1899 			if (fillStickers) {
1900 				if (auto emoji = Ui::Emoji::Find(emojiString)) {
1901 					emoji = emoji->original();
1902 					set->emoji.insert(emoji, pack);
1903 				}
1904 			}
1905 		}
1906 	}
1907 
1908 	// Read orders of installed and featured stickers.
1909 	if (outOrder) {
1910 		auto outOrderCount = quint32();
1911 		stickers.stream >> outOrderCount;
1912 		if (!CheckStreamStatus(stickers.stream) || outOrderCount > 1000) {
1913 			return failed();
1914 		}
1915 		outOrder->reserve(outOrderCount);
1916 		for (auto i = 0; i != outOrderCount; ++i) {
1917 			auto value = uint64();
1918 			stickers.stream >> value;
1919 			if (!CheckStreamStatus(stickers.stream)) {
1920 				outOrder->clear();
1921 				return failed();
1922 			}
1923 			outOrder->push_back(value);
1924 		}
1925 	}
1926 	if (!CheckStreamStatus(stickers.stream)) {
1927 		return failed();
1928 	}
1929 
1930 	// Set flags that we dropped above from the order.
1931 	if (readingFlags && outOrder) {
1932 		for (const auto setId : std::as_const(*outOrder)) {
1933 			auto it = sets.find(setId);
1934 			if (it != sets.cend()) {
1935 				const auto set = it->second.get();
1936 				set->flags |= readingFlags;
1937 				if ((readingFlags == SetFlag::Installed)
1938 					&& !set->installDate) {
1939 					set->installDate = kDefaultStickerInstallDate;
1940 				}
1941 			}
1942 		}
1943 	}
1944 }
1945 
writeInstalledStickers()1946 void Account::writeInstalledStickers() {
1947 	using SetFlag = Data::StickersSetFlag;
1948 
1949 	writeStickerSets(_installedStickersKey, [](const Data::StickersSet &set) {
1950 		if (set.id == Data::Stickers::CloudRecentSetId
1951 			|| set.id == Data::Stickers::FavedSetId
1952 			|| set.id == Data::Stickers::CloudRecentAttachedSetId) {
1953 			// separate files for them
1954 			return StickerSetCheckResult::Skip;
1955 		} else if (set.flags & SetFlag::Special) {
1956 			if (set.stickers.isEmpty()) { // all other special are "installed"
1957 				return StickerSetCheckResult::Skip;
1958 			}
1959 		} else if (!(set.flags & SetFlag::Installed)
1960 			|| (set.flags & SetFlag::Archived)) {
1961 			return StickerSetCheckResult::Skip;
1962 		} else if (set.flags & SetFlag::Masks) {
1963 			return StickerSetCheckResult::Skip;
1964 		} else if (set.flags & SetFlag::NotLoaded) {
1965 			// waiting to receive
1966 			return StickerSetCheckResult::Abort;
1967 		} else if (set.stickers.isEmpty()) {
1968 			return StickerSetCheckResult::Skip;
1969 		}
1970 		return StickerSetCheckResult::Write;
1971 	}, _owner->session().data().stickers().setsOrder());
1972 }
1973 
writeFeaturedStickers()1974 void Account::writeFeaturedStickers() {
1975 	using SetFlag = Data::StickersSetFlag;
1976 
1977 	writeStickerSets(_featuredStickersKey, [](const Data::StickersSet &set) {
1978 		if (set.id == Data::Stickers::CloudRecentSetId
1979 			|| set.id == Data::Stickers::FavedSetId
1980 			|| set.id == Data::Stickers::CloudRecentAttachedSetId) {
1981 			// separate files for them
1982 			return StickerSetCheckResult::Skip;
1983 		} else if (set.flags & SetFlag::Special) {
1984 			return StickerSetCheckResult::Skip;
1985 		} else if (!(set.flags & SetFlag::Featured)) {
1986 			return StickerSetCheckResult::Skip;
1987 		} else if (set.flags & SetFlag::NotLoaded) { // waiting to receive
1988 			return StickerSetCheckResult::Abort;
1989 		} else if (set.stickers.isEmpty()) {
1990 			return StickerSetCheckResult::Skip;
1991 		}
1992 		return StickerSetCheckResult::Write;
1993 	}, _owner->session().data().stickers().featuredSetsOrder());
1994 }
1995 
writeRecentStickers()1996 void Account::writeRecentStickers() {
1997 	writeStickerSets(_recentStickersKey, [](const Data::StickersSet &set) {
1998 		if (set.id != Data::Stickers::CloudRecentSetId
1999 			|| set.stickers.isEmpty()) {
2000 			return StickerSetCheckResult::Skip;
2001 		}
2002 		return StickerSetCheckResult::Write;
2003 	}, Data::StickersSetsOrder());
2004 }
2005 
writeFavedStickers()2006 void Account::writeFavedStickers() {
2007 	writeStickerSets(_favedStickersKey, [](const Data::StickersSet &set) {
2008 		if (set.id != Data::Stickers::FavedSetId || set.stickers.isEmpty()) {
2009 			return StickerSetCheckResult::Skip;
2010 		}
2011 		return StickerSetCheckResult::Write;
2012 	}, Data::StickersSetsOrder());
2013 }
2014 
writeArchivedStickers()2015 void Account::writeArchivedStickers() {
2016 	using SetFlag = Data::StickersSetFlag;
2017 
2018 	writeStickerSets(_archivedStickersKey, [](const Data::StickersSet &set) {
2019 		if (set.flags & SetFlag::Masks) {
2020 			return StickerSetCheckResult::Skip;
2021 		}
2022 		if (!(set.flags & SetFlag::Archived)
2023 			|| set.stickers.isEmpty()) {
2024 			return StickerSetCheckResult::Skip;
2025 		}
2026 		return StickerSetCheckResult::Write;
2027 	}, _owner->session().data().stickers().archivedSetsOrder());
2028 }
2029 
writeArchivedMasks()2030 void Account::writeArchivedMasks() {
2031 	using SetFlag = Data::StickersSetFlag;
2032 
2033 	writeStickerSets(_archivedStickersKey, [](const Data::StickersSet &set) {
2034 		if (!(set.flags & SetFlag::Masks)) {
2035 			return StickerSetCheckResult::Skip;
2036 		}
2037 		if (!(set.flags & SetFlag::Archived) || set.stickers.isEmpty()) {
2038 			return StickerSetCheckResult::Skip;
2039 		}
2040 		return StickerSetCheckResult::Write;
2041 	}, _owner->session().data().stickers().archivedMaskSetsOrder());
2042 }
2043 
writeInstalledMasks()2044 void Account::writeInstalledMasks() {
2045 	using SetFlag = Data::StickersSetFlag;
2046 
2047 	writeStickerSets(_installedMasksKey, [](const Data::StickersSet &set) {
2048 		if (!(set.flags & SetFlag::Masks) || set.stickers.isEmpty()) {
2049 			return StickerSetCheckResult::Skip;
2050 		}
2051 		return StickerSetCheckResult::Write;
2052 	}, _owner->session().data().stickers().maskSetsOrder());
2053 }
2054 
writeRecentMasks()2055 void Account::writeRecentMasks() {
2056 	writeStickerSets(_recentMasksKey, [](const Data::StickersSet &set) {
2057 		if (set.id != Data::Stickers::CloudRecentAttachedSetId
2058 			|| set.stickers.isEmpty()) {
2059 			return StickerSetCheckResult::Skip;
2060 		}
2061 		return StickerSetCheckResult::Write;
2062 	}, Data::StickersSetsOrder());
2063 }
2064 
importOldRecentStickers()2065 void Account::importOldRecentStickers() {
2066 	using SetFlag = Data::StickersSetFlag;
2067 
2068 	if (!_recentStickersKeyOld) {
2069 		return;
2070 	}
2071 
2072 	FileReadDescriptor stickers;
2073 	if (!ReadEncryptedFile(stickers, _recentStickersKeyOld, _basePath, _localKey)) {
2074 		ClearKey(_recentStickersKeyOld, _basePath);
2075 		_recentStickersKeyOld = 0;
2076 		writeMapDelayed();
2077 		return;
2078 	}
2079 
2080 	auto &sets = _owner->session().data().stickers().setsRef();
2081 	sets.clear();
2082 
2083 	auto &order = _owner->session().data().stickers().setsOrderRef();
2084 	order.clear();
2085 
2086 	auto &recent = cRefRecentStickers();
2087 	recent.clear();
2088 
2089 	const auto def = sets.emplace(
2090 		Data::Stickers::DefaultSetId,
2091 		std::make_unique<Data::StickersSet>(
2092 			&_owner->session().data(),
2093 			Data::Stickers::DefaultSetId,
2094 			uint64(0), // accessHash
2095 			uint64(0), // hash
2096 			tr::lng_stickers_default_set(tr::now),
2097 			QString(),
2098 			0, // count
2099 			(SetFlag::Official | SetFlag::Installed | SetFlag::Special),
2100 			kDefaultStickerInstallDate)).first->second.get();
2101 	const auto custom = sets.emplace(
2102 		Data::Stickers::CustomSetId,
2103 		std::make_unique<Data::StickersSet>(
2104 			&_owner->session().data(),
2105 			Data::Stickers::CustomSetId,
2106 			uint64(0), // accessHash
2107 			uint64(0), // hash
2108 			qsl("Custom stickers"),
2109 			QString(),
2110 			0, // count
2111 			(SetFlag::Installed | SetFlag::Special),
2112 			kDefaultStickerInstallDate)).first->second.get();
2113 
2114 	QMap<uint64, bool> read;
2115 	while (!stickers.stream.atEnd()) {
2116 		quint64 id, access;
2117 		QString name, mime, alt;
2118 		qint32 date, dc, size, width, height, type;
2119 		qint16 value;
2120 		stickers.stream >> id >> value >> access >> date >> name >> mime >> dc >> size >> width >> height >> type;
2121 		if (stickers.version >= 7021) {
2122 			stickers.stream >> alt;
2123 		}
2124 		if (!value || read.contains(id)) continue;
2125 		read.insert(id, true);
2126 
2127 		QVector<MTPDocumentAttribute> attributes;
2128 		if (!name.isEmpty()) attributes.push_back(MTP_documentAttributeFilename(MTP_string(name)));
2129 		if (type == AnimatedDocument) {
2130 			attributes.push_back(MTP_documentAttributeAnimated());
2131 		} else if (type == StickerDocument) {
2132 			attributes.push_back(MTP_documentAttributeSticker(MTP_flags(0), MTP_string(alt), MTP_inputStickerSetEmpty(), MTPMaskCoords()));
2133 		}
2134 		if (width > 0 && height > 0) {
2135 			attributes.push_back(MTP_documentAttributeImageSize(MTP_int(width), MTP_int(height)));
2136 		}
2137 
2138 		const auto doc = _owner->session().data().document(
2139 			id,
2140 			access,
2141 			QByteArray(),
2142 			date,
2143 			attributes,
2144 			mime,
2145 			InlineImageLocation(),
2146 			ImageWithLocation(),
2147 			ImageWithLocation(),
2148 			dc,
2149 			size);
2150 		if (!doc->sticker()) {
2151 			continue;
2152 		}
2153 
2154 		if (value > 0) {
2155 			def->stickers.push_back(doc);
2156 			++def->count;
2157 		} else {
2158 			custom->stickers.push_back(doc);
2159 			++custom->count;
2160 		}
2161 		if (qAbs(value) > 1
2162 			&& (recent.size()
2163 				< _owner->session().serverConfig().stickersRecentLimit)) {
2164 			recent.push_back(qMakePair(doc, qAbs(value)));
2165 		}
2166 	}
2167 	if (def->stickers.isEmpty()) {
2168 		sets.remove(Data::Stickers::DefaultSetId);
2169 	} else {
2170 		order.push_front(Data::Stickers::DefaultSetId);
2171 	}
2172 	if (custom->stickers.isEmpty()) {
2173 		sets.remove(Data::Stickers::CustomSetId);
2174 	}
2175 
2176 	writeInstalledStickers();
2177 	writeSessionSettings();
2178 
2179 	ClearKey(_recentStickersKeyOld, _basePath);
2180 	_recentStickersKeyOld = 0;
2181 	writeMapDelayed();
2182 }
2183 
readInstalledStickers()2184 void Account::readInstalledStickers() {
2185 	if (!_installedStickersKey) {
2186 		return importOldRecentStickers();
2187 	}
2188 
2189 	_owner->session().data().stickers().setsRef().clear();
2190 	readStickerSets(
2191 		_installedStickersKey,
2192 		&_owner->session().data().stickers().setsOrderRef(),
2193 		Data::StickersSetFlag::Installed);
2194 }
2195 
readFeaturedStickers()2196 void Account::readFeaturedStickers() {
2197 	readStickerSets(
2198 		_featuredStickersKey,
2199 		&_owner->session().data().stickers().featuredSetsOrderRef(),
2200 		Data::StickersSetFlag::Featured);
2201 
2202 	const auto &sets = _owner->session().data().stickers().sets();
2203 	const auto &order = _owner->session().data().stickers().featuredSetsOrder();
2204 	int unreadCount = 0;
2205 	for (const auto setId : order) {
2206 		auto it = sets.find(setId);
2207 		if (it != sets.cend()
2208 			&& (it->second->flags & Data::StickersSetFlag::Unread)) {
2209 			++unreadCount;
2210 		}
2211 	}
2212 	_owner->session().data().stickers().setFeaturedSetsUnreadCount(unreadCount);
2213 }
2214 
readRecentStickers()2215 void Account::readRecentStickers() {
2216 	readStickerSets(_recentStickersKey);
2217 }
2218 
readRecentMasks()2219 void Account::readRecentMasks() {
2220 	readStickerSets(_recentMasksKey);
2221 }
2222 
readFavedStickers()2223 void Account::readFavedStickers() {
2224 	readStickerSets(_favedStickersKey);
2225 }
2226 
readArchivedStickers()2227 void Account::readArchivedStickers() {
2228 	// TODO: refactor to support for multiple accounts.
2229 	static bool archivedStickersRead = false;
2230 	if (!archivedStickersRead) {
2231 		readStickerSets(
2232 			_archivedStickersKey,
2233 			&_owner->session().data().stickers().archivedSetsOrderRef());
2234 		archivedStickersRead = true;
2235 	}
2236 }
2237 
readArchivedMasks()2238 void Account::readArchivedMasks() {
2239 	// TODO: refactor to support for multiple accounts.
2240 	static bool archivedMasksRead = false;
2241 	if (!archivedMasksRead) {
2242 		readStickerSets(
2243 			_archivedMasksKey,
2244 			&_owner->session().data().stickers().archivedMaskSetsOrderRef());
2245 		archivedMasksRead = true;
2246 	}
2247 }
2248 
readInstalledMasks()2249 void Account::readInstalledMasks() {
2250 	readStickerSets(
2251 		_installedMasksKey,
2252 		&_owner->session().data().stickers().maskSetsOrderRef(),
2253 		Data::StickersSetFlag::Installed);
2254 }
2255 
writeSavedGifs()2256 void Account::writeSavedGifs() {
2257 	const auto &saved = _owner->session().data().stickers().savedGifs();
2258 	if (saved.isEmpty()) {
2259 		if (_savedGifsKey) {
2260 			ClearKey(_savedGifsKey, _basePath);
2261 			_savedGifsKey = 0;
2262 			writeMapDelayed();
2263 		}
2264 	} else {
2265 		quint32 size = sizeof(quint32); // count
2266 		for (const auto gif : saved) {
2267 			size += Serialize::Document::sizeInStream(gif);
2268 		}
2269 
2270 		if (!_savedGifsKey) {
2271 			_savedGifsKey = GenerateKey(_basePath);
2272 			writeMapQueued();
2273 		}
2274 		EncryptedDescriptor data(size);
2275 		data.stream << quint32(saved.size());
2276 		for (const auto gif : saved) {
2277 			Serialize::Document::writeToStream(data.stream, gif);
2278 		}
2279 		FileWriteDescriptor file(_savedGifsKey, _basePath);
2280 		file.writeEncrypted(data, _localKey);
2281 	}
2282 }
2283 
readSavedGifs()2284 void Account::readSavedGifs() {
2285 	if (!_savedGifsKey) return;
2286 
2287 	FileReadDescriptor gifs;
2288 	if (!ReadEncryptedFile(gifs, _savedGifsKey, _basePath, _localKey)) {
2289 		ClearKey(_savedGifsKey, _basePath);
2290 		_savedGifsKey = 0;
2291 		writeMapDelayed();
2292 		return;
2293 	}
2294 
2295 	auto &saved = _owner->session().data().stickers().savedGifsRef();
2296 	const auto failed = [&] {
2297 		ClearKey(_savedGifsKey, _basePath);
2298 		_savedGifsKey = 0;
2299 		saved.clear();
2300 	};
2301 	saved.clear();
2302 
2303 	quint32 cnt;
2304 	gifs.stream >> cnt;
2305 	saved.reserve(cnt);
2306 	OrderedSet<DocumentId> read;
2307 	for (uint32 i = 0; i < cnt; ++i) {
2308 		auto document = Serialize::Document::readFromStream(
2309 			&_owner->session(),
2310 			gifs.version,
2311 			gifs.stream);
2312 		if (!CheckStreamStatus(gifs.stream)) {
2313 			return failed();
2314 		} else if (!document || !document->isGifv()) {
2315 			continue;
2316 		}
2317 
2318 		if (read.contains(document->id)) continue;
2319 		read.insert(document->id);
2320 
2321 		saved.push_back(document);
2322 	}
2323 }
2324 
writeRecentHashtagsAndBots()2325 void Account::writeRecentHashtagsAndBots() {
2326 	const auto &write = cRecentWriteHashtags();
2327 	const auto &search = cRecentSearchHashtags();
2328 	const auto &bots = cRecentInlineBots();
2329 
2330 	if (write.isEmpty() && search.isEmpty() && bots.isEmpty()) {
2331 		readRecentHashtagsAndBots();
2332 	}
2333 	if (write.isEmpty() && search.isEmpty() && bots.isEmpty()) {
2334 		if (_recentHashtagsAndBotsKey) {
2335 			ClearKey(_recentHashtagsAndBotsKey, _basePath);
2336 			_recentHashtagsAndBotsKey = 0;
2337 			writeMapDelayed();
2338 		}
2339 		return;
2340 	}
2341 	if (!_recentHashtagsAndBotsKey) {
2342 		_recentHashtagsAndBotsKey = GenerateKey(_basePath);
2343 		writeMapQueued();
2344 	}
2345 	quint32 size = sizeof(quint32) * 3, writeCnt = 0, searchCnt = 0, botsCnt = cRecentInlineBots().size();
2346 	for (auto i = write.cbegin(), e = write.cend(); i != e;  ++i) {
2347 		if (!i->first.isEmpty()) {
2348 			size += Serialize::stringSize(i->first) + sizeof(quint16);
2349 			++writeCnt;
2350 		}
2351 	}
2352 	for (auto i = search.cbegin(), e = search.cend(); i != e; ++i) {
2353 		if (!i->first.isEmpty()) {
2354 			size += Serialize::stringSize(i->first) + sizeof(quint16);
2355 			++searchCnt;
2356 		}
2357 	}
2358 	for (auto i = bots.cbegin(), e = bots.cend(); i != e; ++i) {
2359 		size += Serialize::peerSize(*i);
2360 	}
2361 
2362 	EncryptedDescriptor data(size);
2363 	data.stream << quint32(writeCnt) << quint32(searchCnt);
2364 	for (auto i = write.cbegin(), e = write.cend(); i != e; ++i) {
2365 		if (!i->first.isEmpty()) data.stream << i->first << quint16(i->second);
2366 	}
2367 	for (auto i = search.cbegin(), e = search.cend(); i != e; ++i) {
2368 		if (!i->first.isEmpty()) data.stream << i->first << quint16(i->second);
2369 	}
2370 	data.stream << quint32(botsCnt);
2371 	for (auto i = bots.cbegin(), e = bots.cend(); i != e; ++i) {
2372 		Serialize::writePeer(data.stream, *i);
2373 	}
2374 	FileWriteDescriptor file(_recentHashtagsAndBotsKey, _basePath);
2375 	file.writeEncrypted(data, _localKey);
2376 }
2377 
readRecentHashtagsAndBots()2378 void Account::readRecentHashtagsAndBots() {
2379 	if (_recentHashtagsAndBotsWereRead) return;
2380 	_recentHashtagsAndBotsWereRead = true;
2381 
2382 	if (!_recentHashtagsAndBotsKey) return;
2383 
2384 	FileReadDescriptor hashtags;
2385 	if (!ReadEncryptedFile(hashtags, _recentHashtagsAndBotsKey, _basePath, _localKey)) {
2386 		ClearKey(_recentHashtagsAndBotsKey, _basePath);
2387 		_recentHashtagsAndBotsKey = 0;
2388 		writeMapDelayed();
2389 		return;
2390 	}
2391 
2392 	quint32 writeCount = 0, searchCount = 0, botsCount = 0;
2393 	hashtags.stream >> writeCount >> searchCount;
2394 
2395 	QString tag;
2396 	quint16 count;
2397 
2398 	RecentHashtagPack write, search;
2399 	RecentInlineBots bots;
2400 	if (writeCount) {
2401 		write.reserve(writeCount);
2402 		for (uint32 i = 0; i < writeCount; ++i) {
2403 			hashtags.stream >> tag >> count;
2404 			write.push_back(qMakePair(tag.trimmed(), count));
2405 		}
2406 	}
2407 	if (searchCount) {
2408 		search.reserve(searchCount);
2409 		for (uint32 i = 0; i < searchCount; ++i) {
2410 			hashtags.stream >> tag >> count;
2411 			search.push_back(qMakePair(tag.trimmed(), count));
2412 		}
2413 	}
2414 	cSetRecentWriteHashtags(write);
2415 	cSetRecentSearchHashtags(search);
2416 
2417 	if (!hashtags.stream.atEnd()) {
2418 		hashtags.stream >> botsCount;
2419 		if (botsCount) {
2420 			bots.reserve(botsCount);
2421 			for (auto i = 0; i < botsCount; ++i) {
2422 				const auto peer = Serialize::readPeer(
2423 					&_owner->session(),
2424 					hashtags.version,
2425 					hashtags.stream);
2426 				if (!peer) {
2427 					return; // Broken data.
2428 				} else if (peer->isUser()
2429 					&& peer->asUser()->isBot()
2430 					&& !peer->asUser()->botInfo->inlinePlaceholder.isEmpty()
2431 					&& !peer->asUser()->username.isEmpty()) {
2432 					bots.push_back(peer->asUser());
2433 				}
2434 			}
2435 		}
2436 		cSetRecentInlineBots(bots);
2437 	}
2438 }
2439 
saveRecentHashtags(Fn<RecentHashtagPack ()> getPack,const QString & text)2440 std::optional<RecentHashtagPack> Account::saveRecentHashtags(
2441 		Fn<RecentHashtagPack()> getPack,
2442 		const QString &text) {
2443 	auto found = false;
2444 	auto m = QRegularExpressionMatch();
2445 	auto recent = getPack();
2446 	for (auto i = 0, next = 0; (m = TextUtilities::RegExpHashtag().match(text, i)).hasMatch(); i = next) {
2447 		i = m.capturedStart();
2448 		next = m.capturedEnd();
2449 		if (m.hasMatch()) {
2450 			if (!m.capturedView(1).isEmpty()) {
2451 				++i;
2452 			}
2453 			if (!m.capturedView(2).isEmpty()) {
2454 				--next;
2455 			}
2456 		}
2457 		const auto tag = text.mid(i + 1, next - i - 1);
2458 		if (TextUtilities::RegExpHashtagExclude().match(tag).hasMatch()) {
2459 			continue;
2460 		}
2461 		if (!found
2462 			&& cRecentWriteHashtags().isEmpty()
2463 			&& cRecentSearchHashtags().isEmpty()) {
2464 			readRecentHashtagsAndBots();
2465 			recent = getPack();
2466 		}
2467 		found = true;
2468 		Local::incrementRecentHashtag(recent, tag);
2469 	}
2470 	return found ? base::make_optional(recent) : std::nullopt;
2471 }
2472 
saveRecentSentHashtags(const QString & text)2473 void Account::saveRecentSentHashtags(const QString &text) {
2474 	const auto result = saveRecentHashtags(
2475 		[] { return cRecentWriteHashtags(); },
2476 		text);
2477 	if (result) {
2478 		cSetRecentWriteHashtags(*result);
2479 		writeRecentHashtagsAndBots();
2480 	}
2481 }
2482 
saveRecentSearchHashtags(const QString & text)2483 void Account::saveRecentSearchHashtags(const QString &text) {
2484 	const auto result = saveRecentHashtags(
2485 		[] { return cRecentSearchHashtags(); },
2486 		text);
2487 	if (result) {
2488 		cSetRecentSearchHashtags(*result);
2489 		writeRecentHashtagsAndBots();
2490 	}
2491 }
2492 
writeExportSettings(const Export::Settings & settings)2493 void Account::writeExportSettings(const Export::Settings &settings) {
2494 	const auto check = Export::Settings();
2495 	if (settings.types == check.types
2496 		&& settings.fullChats == check.fullChats
2497 		&& settings.media.types == check.media.types
2498 		&& settings.media.sizeLimit == check.media.sizeLimit
2499 		&& settings.path == check.path
2500 		&& settings.format == check.format
2501 		&& settings.availableAt == check.availableAt
2502 		&& !settings.onlySinglePeer()) {
2503 		if (_exportSettingsKey) {
2504 			ClearKey(_exportSettingsKey, _basePath);
2505 			_exportSettingsKey = 0;
2506 			writeMapDelayed();
2507 		}
2508 		return;
2509 	}
2510 	if (!_exportSettingsKey) {
2511 		_exportSettingsKey = GenerateKey(_basePath);
2512 		writeMapQueued();
2513 	}
2514 	quint32 size = sizeof(quint32) * 6
2515 		+ Serialize::stringSize(settings.path)
2516 		+ sizeof(qint32) * 2 + sizeof(quint64);
2517 	EncryptedDescriptor data(size);
2518 	data.stream
2519 		<< quint32(settings.types)
2520 		<< quint32(settings.fullChats)
2521 		<< quint32(settings.media.types)
2522 		<< quint32(settings.media.sizeLimit)
2523 		<< quint32(settings.format)
2524 		<< settings.path
2525 		<< quint32(settings.availableAt);
2526 	settings.singlePeer.match([&](const MTPDinputPeerUser & user) {
2527 		data.stream
2528 			<< kSinglePeerTypeUser
2529 			<< quint64(user.vuser_id().v)
2530 			<< quint64(user.vaccess_hash().v);
2531 	}, [&](const MTPDinputPeerChat & chat) {
2532 		data.stream << kSinglePeerTypeChat << quint64(chat.vchat_id().v);
2533 	}, [&](const MTPDinputPeerChannel & channel) {
2534 		data.stream
2535 			<< kSinglePeerTypeChannel
2536 			<< quint64(channel.vchannel_id().v)
2537 			<< quint64(channel.vaccess_hash().v);
2538 	}, [&](const MTPDinputPeerSelf &) {
2539 		data.stream << kSinglePeerTypeSelf;
2540 	}, [&](const MTPDinputPeerEmpty &) {
2541 		data.stream << kSinglePeerTypeEmpty;
2542 	}, [&](const MTPDinputPeerUserFromMessage &) {
2543 		Unexpected("From message peer in single peer export settings.");
2544 	}, [&](const MTPDinputPeerChannelFromMessage &) {
2545 		Unexpected("From message peer in single peer export settings.");
2546 	});
2547 	data.stream << qint32(settings.singlePeerFrom);
2548 	data.stream << qint32(settings.singlePeerTill);
2549 
2550 	FileWriteDescriptor file(_exportSettingsKey, _basePath);
2551 	file.writeEncrypted(data, _localKey);
2552 }
2553 
readExportSettings()2554 Export::Settings Account::readExportSettings() {
2555 	FileReadDescriptor file;
2556 	if (!ReadEncryptedFile(file, _exportSettingsKey, _basePath, _localKey)) {
2557 		ClearKey(_exportSettingsKey, _basePath);
2558 		_exportSettingsKey = 0;
2559 		writeMapDelayed();
2560 		return Export::Settings();
2561 	}
2562 
2563 	quint32 types = 0, fullChats = 0;
2564 	quint32 mediaTypes = 0, mediaSizeLimit = 0;
2565 	quint32 format = 0, availableAt = 0;
2566 	QString path;
2567 	qint32 singlePeerType = 0, singlePeerBareIdOld = 0;
2568 	quint64 singlePeerBareId = 0;
2569 	quint64 singlePeerAccessHash = 0;
2570 	qint32 singlePeerFrom = 0, singlePeerTill = 0;
2571 	file.stream
2572 		>> types
2573 		>> fullChats
2574 		>> mediaTypes
2575 		>> mediaSizeLimit
2576 		>> format
2577 		>> path
2578 		>> availableAt;
2579 	if (!file.stream.atEnd()) {
2580 		file.stream >> singlePeerType;
2581 		switch (singlePeerType) {
2582 		case kSinglePeerTypeUserOld:
2583 		case kSinglePeerTypeChannelOld: {
2584 			file.stream >> singlePeerBareIdOld >> singlePeerAccessHash;
2585 		} break;
2586 		case kSinglePeerTypeChatOld: file.stream >> singlePeerBareIdOld; break;
2587 
2588 		case kSinglePeerTypeUser:
2589 		case kSinglePeerTypeChannel: {
2590 			file.stream >> singlePeerBareId >> singlePeerAccessHash;
2591 		} break;
2592 		case kSinglePeerTypeChat: file.stream >> singlePeerBareId; break;
2593 		case kSinglePeerTypeSelf:
2594 		case kSinglePeerTypeEmpty: break;
2595 		default: return Export::Settings();
2596 		}
2597 	}
2598 	if (!file.stream.atEnd()) {
2599 		file.stream >> singlePeerFrom >> singlePeerTill;
2600 	}
2601 	auto result = Export::Settings();
2602 	result.types = Export::Settings::Types::from_raw(types);
2603 	result.fullChats = Export::Settings::Types::from_raw(fullChats);
2604 	result.media.types = Export::MediaSettings::Types::from_raw(mediaTypes);
2605 	result.media.sizeLimit = mediaSizeLimit;
2606 	result.format = Export::Output::Format(format);
2607 	result.path = path;
2608 	result.availableAt = availableAt;
2609 	result.singlePeer = [&] {
2610 		switch (singlePeerType) {
2611 		case kSinglePeerTypeUserOld:
2612 			return MTP_inputPeerUser(
2613 				MTP_long(singlePeerBareIdOld),
2614 				MTP_long(singlePeerAccessHash));
2615 		case kSinglePeerTypeChatOld:
2616 			return MTP_inputPeerChat(MTP_long(singlePeerBareIdOld));
2617 		case kSinglePeerTypeChannelOld:
2618 			return MTP_inputPeerChannel(
2619 				MTP_long(singlePeerBareIdOld),
2620 				MTP_long(singlePeerAccessHash));
2621 
2622 		case kSinglePeerTypeUser:
2623 			return MTP_inputPeerUser(
2624 				MTP_long(singlePeerBareId),
2625 				MTP_long(singlePeerAccessHash));
2626 		case kSinglePeerTypeChat:
2627 			return MTP_inputPeerChat(MTP_long(singlePeerBareId));
2628 		case kSinglePeerTypeChannel:
2629 			return MTP_inputPeerChannel(
2630 				MTP_long(singlePeerBareId),
2631 				MTP_long(singlePeerAccessHash));
2632 		case kSinglePeerTypeSelf:
2633 			return MTP_inputPeerSelf();
2634 		case kSinglePeerTypeEmpty:
2635 			return MTP_inputPeerEmpty();
2636 		}
2637 		Unexpected("Type in export data single peer.");
2638 	}();
2639 	result.singlePeerFrom = singlePeerFrom;
2640 	result.singlePeerTill = singlePeerTill;
2641 	return (file.stream.status() == QDataStream::Ok && result.validate())
2642 		? result
2643 		: Export::Settings();
2644 }
2645 
writeSelf()2646 void Account::writeSelf() {
2647 	writeMapDelayed();
2648 }
2649 
readSelf(not_null<Main::Session * > session,const QByteArray & serialized,int32 streamVersion)2650 void Account::readSelf(
2651 		not_null<Main::Session*> session,
2652 		const QByteArray &serialized,
2653 		int32 streamVersion) {
2654 	QDataStream stream(serialized);
2655 	const auto user = session->user();
2656 	const auto wasLoadedStatus = user->loadedStatus();
2657 	user->setLoadedStatus(PeerData::LoadedStatus::Not);
2658 	const auto self = Serialize::readPeer(
2659 		session,
2660 		streamVersion,
2661 		stream);
2662 	if (!self || !self->isSelf() || self != user) {
2663 		user->setLoadedStatus(wasLoadedStatus);
2664 		return;
2665 	}
2666 
2667 	QString about;
2668 	stream >> about;
2669 	if (CheckStreamStatus(stream)) {
2670 		self->asUser()->setAbout(about);
2671 	}
2672 }
2673 
writeTrustedBots()2674 void Account::writeTrustedBots() {
2675 	if (_trustedBots.empty()) {
2676 		if (_trustedBotsKey) {
2677 			ClearKey(_trustedBotsKey, _basePath);
2678 			_trustedBotsKey = 0;
2679 			writeMapDelayed();
2680 		}
2681 		return;
2682 	}
2683 	if (!_trustedBotsKey) {
2684 		_trustedBotsKey = GenerateKey(_basePath);
2685 		writeMapQueued();
2686 	}
2687 	quint32 size = sizeof(qint32) + _trustedBots.size() * sizeof(quint64);
2688 	EncryptedDescriptor data(size);
2689 	data.stream << qint32(_trustedBots.size());
2690 	for (const auto &[peerId, mask] : _trustedBots) {
2691 		// value: 8 bit mask, 56 bit bot peer_id.
2692 		auto value = SerializePeerId(peerId);
2693 		Assert((value >> 56) == 0);
2694 		value |= (quint64(mask) << 56);
2695 		data.stream << value;
2696 	}
2697 
2698 	FileWriteDescriptor file(_trustedBotsKey, _basePath);
2699 	file.writeEncrypted(data, _localKey);
2700 }
2701 
readTrustedBots()2702 void Account::readTrustedBots() {
2703 	if (!_trustedBotsKey) return;
2704 
2705 	FileReadDescriptor trusted;
2706 	if (!ReadEncryptedFile(trusted, _trustedBotsKey, _basePath, _localKey)) {
2707 		ClearKey(_trustedBotsKey, _basePath);
2708 		_trustedBotsKey = 0;
2709 		writeMapDelayed();
2710 		return;
2711 	}
2712 
2713 	qint32 size = 0;
2714 	trusted.stream >> size;
2715 	for (int i = 0; i < size; ++i) {
2716 		auto value = quint64();
2717 		trusted.stream >> value;
2718 		const auto mask = base::flags<BotTrustFlag>::from_raw(
2719 			uchar(value >> 56));
2720 		const auto peerIdSerialized = value & ~(0xFFULL << 56);
2721 		const auto peerId = DeserializePeerId(peerIdSerialized);
2722 		_trustedBots.emplace(peerId, mask);
2723 	}
2724 }
2725 
markBotTrustedOpenGame(PeerId botId)2726 void Account::markBotTrustedOpenGame(PeerId botId) {
2727 	if (isBotTrustedOpenGame(botId)) {
2728 		return;
2729 	}
2730 	const auto i = _trustedBots.find(botId);
2731 	if (i == end(_trustedBots)) {
2732 		_trustedBots.emplace(botId, BotTrustFlag());
2733 	} else {
2734 		i->second &= ~BotTrustFlag::NoOpenGame;
2735 	}
2736 	writeTrustedBots();
2737 }
2738 
isBotTrustedOpenGame(PeerId botId)2739 bool Account::isBotTrustedOpenGame(PeerId botId) {
2740 	if (!_trustedBotsRead) {
2741 		readTrustedBots();
2742 		_trustedBotsRead = true;
2743 	}
2744 	const auto i = _trustedBots.find(botId);
2745 	return (i != end(_trustedBots))
2746 		&& ((i->second & BotTrustFlag::NoOpenGame) == 0);
2747 }
2748 
markBotTrustedPayment(PeerId botId)2749 void Account::markBotTrustedPayment(PeerId botId) {
2750 	if (isBotTrustedPayment(botId)) {
2751 		return;
2752 	}
2753 	const auto i = _trustedBots.find(botId);
2754 	if (i == end(_trustedBots)) {
2755 		_trustedBots.emplace(
2756 			botId,
2757 			BotTrustFlag::NoOpenGame | BotTrustFlag::Payment);
2758 	} else {
2759 		i->second |= BotTrustFlag::Payment;
2760 	}
2761 	writeTrustedBots();
2762 }
2763 
isBotTrustedPayment(PeerId botId)2764 bool Account::isBotTrustedPayment(PeerId botId) {
2765 	if (!_trustedBotsRead) {
2766 		readTrustedBots();
2767 		_trustedBotsRead = true;
2768 	}
2769 	const auto i = _trustedBots.find(botId);
2770 	return (i != end(_trustedBots))
2771 		&& ((i->second & BotTrustFlag::Payment) != 0);
2772 }
2773 
encrypt(const void * src,void * dst,uint32 len,const void * key128) const2774 bool Account::encrypt(
2775 		const void *src,
2776 		void *dst,
2777 		uint32 len,
2778 		const void *key128) const {
2779 	if (!_localKey) {
2780 		return false;
2781 	}
2782 	MTP::aesEncryptLocal(src, dst, len, _localKey, key128);
2783 	return true;
2784 }
2785 
decrypt(const void * src,void * dst,uint32 len,const void * key128) const2786 bool Account::decrypt(
2787 		const void *src,
2788 		void *dst,
2789 		uint32 len,
2790 		const void *key128) const {
2791 	if (!_localKey) {
2792 		return false;
2793 	}
2794 	MTP::aesDecryptLocal(src, dst, len, _localKey, key128);
2795 	return true;
2796 }
2797 
2798 } // namespace Storage
2799