2014-11-22 09:45:04 +00:00
/*
This file is part of Telegram Desktop ,
2018-01-03 10:23:14 +00:00
the official desktop application for the Telegram messaging service .
2014-11-22 09:45:04 +00:00
2018-01-03 10:23:14 +00:00
For license and copyright information please follow this link :
https : //github.com/telegramdesktop/tdesktop/blob/master/LEGAL
2014-11-22 09:45:04 +00:00
*/
2017-03-04 10:23:56 +00:00
# include "storage/localstorage.h"
2020-06-09 16:57:05 +00:00
//
2017-03-04 10:23:56 +00:00
# include "storage/serialize_common.h"
2020-06-09 16:57:05 +00:00
# include "storage/storage_account.h"
# include "storage/details/storage_file_utilities.h"
# include "storage/details/storage_settings_scheme.h"
2020-04-09 12:27:53 +00:00
# include "data/data_session.h"
2020-06-09 16:57:05 +00:00
# include "data/data_document.h"
2020-04-09 12:27:53 +00:00
# include "data/data_document_media.h"
2020-02-11 12:00:04 +00:00
# include "base/platform/base_platform_info.h"
2021-09-15 10:21:45 +00:00
# include "base/random.h"
2020-06-09 16:57:05 +00:00
# include "ui/effects/animation_value.h"
2018-04-26 16:14:21 +00:00
# include "core/update_checker.h"
2020-10-13 16:43:18 +00:00
# include "core/file_location.h"
# include "core/application.h"
2022-06-11 00:07:22 +00:00
# include "core/core_settings.h"
2019-02-13 12:36:59 +00:00
# include "media/audio/media_audio.h"
2020-06-17 09:36:25 +00:00
# include "mtproto/mtproto_config.h"
# include "mtproto/mtproto_dc_options.h"
2020-06-18 18:04:16 +00:00
# include "main/main_domain.h"
2020-06-17 09:36:25 +00:00
# include "main/main_account.h"
2019-07-24 11:45:24 +00:00
# include "main/main_session.h"
2019-08-26 16:36:23 +00:00
# include "window/themes/window_theme.h"
2020-09-30 09:11:44 +00:00
# include "lang/lang_instance.h"
2015-03-02 12:34:16 +00:00
2019-09-04 07:19:15 +00:00
# include <QtCore/QDirIterator>
2020-02-13 14:39:29 +00:00
# ifndef Q_OS_WIN
# include <unistd.h>
# endif // Q_OS_WIN
2020-06-09 16:57:05 +00:00
//extern "C" {
//#include <openssl/evp.h>
//} // extern "C"
2017-03-04 10:23:56 +00:00
2016-09-15 19:15:49 +00:00
namespace Local {
2014-11-22 09:45:04 +00:00
namespace {
2017-12-19 16:57:42 +00:00
constexpr auto kThemeFileSizeLimit = 5 * 1024 * 1024 ;
2019-02-19 06:57:53 +00:00
constexpr auto kFileLoaderQueueStopTimeout = crl : : time ( 5000 ) ;
2019-03-22 09:13:39 +00:00
2020-06-19 15:14:55 +00:00
constexpr auto kSavedBackgroundFormat = QImage : : Format_ARGB32_Premultiplied ;
constexpr auto kWallPaperLegacySerializeTagId = int32 ( - 111 ) ;
constexpr auto kWallPaperSerializeTagId = int32 ( - 112 ) ;
constexpr auto kWallPaperSidesLimit = 10'000 ;
2019-09-03 18:04:38 +00:00
const auto kThemeNewPathRelativeTag = qstr ( " special://new_tag " ) ;
2020-06-09 16:57:05 +00:00
using namespace Storage : : details ;
using Storage : : FileKey ;
2018-08-31 13:01:42 +00:00
using Database = Storage : : Cache : : Database ;
2014-11-22 09:45:04 +00:00
2018-08-27 11:35:58 +00:00
QString _basePath , _userBasePath , _userDbPath ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
TaskQueue * _localLoader = nullptr ;
2014-11-22 09:45:04 +00:00
2020-06-09 16:57:05 +00:00
QByteArray _settingsSalt ;
2017-02-25 16:44:02 +00:00
auto OldKey = MTP : : AuthKeyPtr ( ) ;
auto SettingsKey = MTP : : AuthKeyPtr ( ) ;
2016-10-28 12:44:28 +00:00
2018-07-19 14:58:40 +00:00
FileKey _themeKeyDay = 0 ;
FileKey _themeKeyNight = 0 ;
// Theme key legacy may be read in start() with settings.
2019-09-05 06:51:46 +00:00
// But it should be moved to keyDay or keyNight inside InitialLoadTheme()
2018-07-19 14:58:40 +00:00
// and never used after.
FileKey _themeKeyLegacy = 0 ;
2017-04-13 17:59:05 +00:00
FileKey _langPackKey = 0 ;
2018-10-30 11:23:54 +00:00
FileKey _languagesKey = 0 ;
2016-09-15 19:15:49 +00:00
2020-06-19 15:14:55 +00:00
FileKey _backgroundKeyDay = 0 ;
FileKey _backgroundKeyNight = 0 ;
bool _useGlobalBackgroundKeys = false ;
bool _backgroundCanWrite = true ;
2020-06-09 16:57:05 +00:00
int32 _oldSettingsVersion = 0 ;
2020-06-19 18:10:09 +00:00
bool _settingsRewriteNeeded = false ;
bool _settingsWriteAllowed = false ;
2016-09-15 19:15:49 +00:00
2017-03-28 12:30:38 +00:00
enum class WriteMapWhen {
Now ,
Fast ,
Soon ,
2016-09-15 19:15:49 +00:00
} ;
2020-06-17 09:36:25 +00:00
bool CheckStreamStatus ( QDataStream & stream ) {
if ( stream . status ( ) ! = QDataStream : : Ok ) {
LOG ( ( " Bad data stream status: %1 " ) . arg ( stream . status ( ) ) ) ;
return false ;
}
return true ;
}
[[nodiscard]] const MTP : : Config & LookupFallbackConfig ( ) {
static const auto lookupConfig = [ ] ( not_null < Main : : Account * > account ) {
const auto mtp = & account - > mtp ( ) ;
Remove unused variable
The following are commits related to removed variables.
apiwrap.cpp
e050e27: kSaveDraftBeforeQuitTimeout
app.cpp
113f665: serviceImageCacheSize
boxes/auto_download_box.cpp
a0c6104: checked(Source source, Type type)
boxes/background_preview_box.cpp
b6edf45: resultBytesPerPixel
fe21b5a: ms
boxes/calendar_box.cpp
ae97704: yearIndex, monthIndex
99bb093: ms
boxes/connection_box.cpp
f794d8d: ping
boxes/dictionaries_manager.cpp
8353867: session
boxes/peer_list_box.cpp
2ce2a14: grayedWidth
boxes/peers/add_participants_box.cpp
07e010d: chat, channel
boxes/self_destruction_box.cpp
fe9f02e: count
chat_helpers/emoji_suggestions_widget.cpp
a12bc60: is(QLatin1String string)
chat_helpers/field_autocomplete.cpp
8c7a35c: atwidth, hashwidth
chat_helpers/gifs_list_widget.cpp
ff65734: inlineItems
3d846fc: newSelected
d1687ab: kSaveDraftBeforeQuitTimeout
chat_helpers/stickers_dice_pack.cpp
c83e297: kZeroDiceDocumentId
chat_helpers/stickers_emoji_pack.cpp
d298953: length
chat_helpers/stickers_list_widget.cpp
eb75859: index, x
core/crash_reports.cpp
5940ae6: LaunchedDateTimeStr, LaunchedBinaryName
data/data_changes.cpp
3c4e959:clearRealtime
data/data_cloud_file.cpp
4b354b0: fromCloud, cacheTag
data/data_document_media.cpp
7db5359: kMaxVideoFrameArea
data/data_messages.cpp
794e315: wasCount
data/data_photo_media.cpp
e27d2bc: index
data/data_wall_paper.cpp
b6edf45: resultBytesPerPixel
data/data_types.cpp
aa8f62d: kWebDocumentCacheTag, kStorageCacheMask
history/admin_log/history_admin_log_inner.cpp
794e315: canDelete, canForward
history/history_location_manager.cpp
60f45ab: kCoordPrecision
9f90d3a: kMaxHttpRedirects
history/history_message.cpp
cedf8a6: kPinnedMessageTextLimit
history/history_widget.cpp
b305924: serviceColor
efa5fc4: hasForward
5e7aa4f: kTabbedSelectorToggleTooltipTimeoutMs, kTabbedSelectorToggleTooltipCount
history/view/history_view_context_menu.cpp
fe1a90b: isVideoLink, isVoiceLink, isAudioLink
settings.cpp
e2f54eb: defaultRecent
settings/settings_folders.cpp
e8bf5bb: kRefreshSuggestedTimeout
ui/filter_icon_panel.cpp
c4a0bc1: kDelayedHideTimeoutMs
window/themes/window_theme_preview.cpp
ef927c8: mutedCounter
-----
Modified variables
boxes/stickers_box.cpp
554eb3a: _rows[pressedIndex] -> set
data/data_notify_settings.cpp
734c410: muteForSeconds -> muteUntil
history/view/history_view_list_widget.cpp
07528be: _items[index] -> view
e5f3bed: fromState, tillState
history/history.cpp
cd3c1c6: kStatusShowClientsideRecordVideo -> kStatusShowClientsideRecordVoice
storage/download_manager_mtproto.cpp
ae8fb14: _queues[dcId] -> queue
storage/localstorage.cpp
357caf8: MTP::Environment::Production -> production
2020-07-02 10:42:30 +00:00
const auto production = MTP : : Environment : : Production ;
return ( mtp - > environment ( ) = = production )
2020-06-17 09:36:25 +00:00
? & mtp - > config ( )
: nullptr ;
} ;
const auto & app = Core : : App ( ) ;
2020-06-18 18:04:16 +00:00
const auto & domain = app . domain ( ) ;
if ( ! domain . started ( ) ) {
2020-06-17 09:36:25 +00:00
return app . fallbackProductionConfig ( ) ;
}
if ( const auto result = lookupConfig ( & app . activeAccount ( ) ) ) {
return * result ;
}
2020-06-18 18:04:16 +00:00
for ( const auto & [ _ , account ] : domain . accounts ( ) ) {
2020-06-17 09:36:25 +00:00
if ( const auto result = lookupConfig ( account . get ( ) ) ) {
return * result ;
}
}
return app . fallbackProductionConfig ( ) ;
}
2020-06-09 16:57:05 +00:00
void applyReadContext ( ReadSettingsContext & & context ) {
2020-06-17 09:36:25 +00:00
ApplyReadFallbackConfig ( context ) ;
2016-09-15 19:15:49 +00:00
2021-09-13 17:09:55 +00:00
DEBUG_LOG ( ( " Theme: applying context, legacy: %1, day: %2, night: %3 "
) . arg ( context . themeKeyLegacy
) . arg ( context . themeKeyDay
) . arg ( context . themeKeyNight ) ) ;
2020-06-09 16:57:05 +00:00
_themeKeyLegacy = context . themeKeyLegacy ;
_themeKeyDay = context . themeKeyDay ;
_themeKeyNight = context . themeKeyNight ;
2020-06-19 15:14:55 +00:00
_backgroundKeyDay = context . backgroundKeyDay ;
_backgroundKeyNight = context . backgroundKeyNight ;
_useGlobalBackgroundKeys = context . backgroundKeysRead ;
2020-06-09 16:57:05 +00:00
_langPackKey = context . langPackKey ;
_languagesKey = context . languagesKey ;
}
2019-06-22 10:36:35 +00:00
2020-06-09 16:57:05 +00:00
bool _readOldSettings ( bool remove , ReadSettingsContext & context ) {
bool result = false ;
QFile file ( cWorkingDir ( ) + qsl ( " tdata/config " ) ) ;
if ( file . open ( QIODevice : : ReadOnly ) ) {
LOG ( ( " App Info: reading old config... " ) ) ;
QDataStream stream ( & file ) ;
stream . setVersion ( QDataStream : : Qt_5_1 ) ;
2015-11-26 17:34:52 +00:00
2020-06-09 16:57:05 +00:00
qint32 version = 0 ;
while ( ! stream . atEnd ( ) ) {
quint32 blockId ;
stream > > blockId ;
if ( ! CheckStreamStatus ( stream ) ) break ;
2015-06-30 21:07:05 +00:00
2020-06-09 16:57:05 +00:00
if ( blockId = = dbiVersion ) {
stream > > version ;
if ( ! CheckStreamStatus ( stream ) ) break ;
2015-12-31 15:27:21 +00:00
2020-06-09 16:57:05 +00:00
if ( version > AppVersion ) break ;
} else if ( ! ReadSetting ( blockId , stream , version , context ) ) {
break ;
2015-12-31 15:27:21 +00:00
}
2014-12-05 13:44:27 +00:00
}
2020-06-09 16:57:05 +00:00
file . close ( ) ;
result = true ;
2016-09-15 19:15:49 +00:00
}
2020-06-09 16:57:05 +00:00
if ( remove ) file . remove ( ) ;
return result ;
2016-09-15 19:15:49 +00:00
}
2015-06-30 21:07:05 +00:00
2020-06-09 16:57:05 +00:00
void _readOldUserSettingsFields (
QIODevice * device ,
qint32 & version ,
ReadSettingsContext & context ) {
QDataStream stream ( device ) ;
stream . setVersion ( QDataStream : : Qt_5_1 ) ;
2016-09-15 19:15:49 +00:00
2020-06-09 16:57:05 +00:00
while ( ! stream . atEnd ( ) ) {
quint32 blockId ;
stream > > blockId ;
if ( ! CheckStreamStatus ( stream ) ) {
2016-09-15 19:15:49 +00:00
break ;
2014-12-05 13:44:27 +00:00
}
2015-06-30 21:07:05 +00:00
2020-06-09 16:57:05 +00:00
if ( blockId = = dbiVersion ) {
stream > > version ;
if ( ! CheckStreamStatus ( stream ) ) {
break ;
}
2015-12-31 15:27:21 +00:00
2020-06-09 16:57:05 +00:00
if ( version > AppVersion ) return ;
} else if ( blockId = = dbiEncryptedWithSalt ) {
QByteArray salt , data , decrypted ;
stream > > salt > > data ;
if ( ! CheckStreamStatus ( stream ) ) {
break ;
}
2014-12-05 13:44:27 +00:00
2020-06-09 16:57:05 +00:00
if ( salt . size ( ) ! = 32 ) {
LOG ( ( " App Error: bad salt in old user config encrypted part, size: %1 " ) . arg ( salt . size ( ) ) ) ;
continue ;
}
2020-06-15 16:25:02 +00:00
OldKey = CreateLegacyLocalKey ( QByteArray ( ) , salt ) ;
2015-09-09 08:19:25 +00:00
2020-06-09 16:57:05 +00:00
if ( data . size ( ) < = 16 | | ( data . size ( ) & 0x0F ) ) {
LOG ( ( " App Error: bad encrypted part size in old user config: %1 " ) . arg ( data . size ( ) ) ) ;
continue ;
}
uint32 fullDataLen = data . size ( ) - 16 ;
decrypted . resize ( fullDataLen ) ;
const char * dataKey = data . constData ( ) , * encrypted = data . constData ( ) + 16 ;
aesDecryptLocal ( encrypted , decrypted . data ( ) , fullDataLen , OldKey , dataKey ) ;
uchar sha1Buffer [ 20 ] ;
if ( memcmp ( hashSha1 ( decrypted . constData ( ) , decrypted . size ( ) , sha1Buffer ) , dataKey , 16 ) ) {
LOG ( ( " App Error: bad decrypt key, data from old user config not decrypted " ) ) ;
continue ;
}
uint32 dataLen = * ( const uint32 * ) decrypted . constData ( ) ;
if ( dataLen > uint32 ( decrypted . size ( ) ) | | dataLen < = fullDataLen - 16 | | dataLen < 4 ) {
LOG ( ( " App Error: bad decrypted part size in old user config: %1, fullDataLen: %2, decrypted size: %3 " ) . arg ( dataLen ) . arg ( fullDataLen ) . arg ( decrypted . size ( ) ) ) ;
continue ;
2015-09-09 08:19:25 +00:00
}
2020-06-09 16:57:05 +00:00
decrypted . resize ( dataLen ) ;
QBuffer decryptedStream ( & decrypted ) ;
decryptedStream . open ( QIODevice : : ReadOnly ) ;
decryptedStream . seek ( 4 ) ; // skip size
LOG ( ( " App Info: reading encrypted old user config... " ) ) ;
_readOldUserSettingsFields ( & decryptedStream , version , context ) ;
} else if ( ! ReadSetting ( blockId , stream , version , context ) ) {
return ;
2016-09-15 19:15:49 +00:00
}
}
}
2015-03-02 12:34:16 +00:00
2017-02-23 06:57:04 +00:00
bool _readOldUserSettings ( bool remove , ReadSettingsContext & context ) {
2016-09-15 19:15:49 +00:00
bool result = false ;
2020-06-17 09:36:25 +00:00
// We dropped old test authorizations when migrated to multi auth.
//const auto testPrefix = (cTestMode() ? qsl("_test") : QString());
const auto testPrefix = QString ( ) ;
QFile file ( cWorkingDir ( ) + cDataFile ( ) + testPrefix + qsl ( " _config " ) ) ;
2016-09-15 19:15:49 +00:00
if ( file . open ( QIODevice : : ReadOnly ) ) {
LOG ( ( " App Info: reading old user config... " ) ) ;
qint32 version = 0 ;
2017-02-23 06:57:04 +00:00
_readOldUserSettingsFields ( & file , version , context ) ;
2016-09-15 19:15:49 +00:00
file . close ( ) ;
result = true ;
}
if ( remove ) file . remove ( ) ;
return result ;
}
2015-03-02 12:34:16 +00:00
2020-06-09 16:57:05 +00:00
void _readOldMtpDataFields (
QIODevice * device ,
qint32 & version ,
ReadSettingsContext & context ) {
2016-09-15 19:15:49 +00:00
QDataStream stream ( device ) ;
stream . setVersion ( QDataStream : : Qt_5_1 ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
while ( ! stream . atEnd ( ) ) {
quint32 blockId ;
stream > > blockId ;
2020-06-09 16:57:05 +00:00
if ( ! CheckStreamStatus ( stream ) ) {
2016-09-15 19:15:49 +00:00
break ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
if ( blockId = = dbiVersion ) {
stream > > version ;
2020-06-09 16:57:05 +00:00
if ( ! CheckStreamStatus ( stream ) ) {
2016-09-15 19:15:49 +00:00
break ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
if ( version > AppVersion ) return ;
} else if ( blockId = = dbiEncrypted ) {
QByteArray data , decrypted ;
stream > > data ;
2020-06-09 16:57:05 +00:00
if ( ! CheckStreamStatus ( stream ) ) {
2016-09-15 19:15:49 +00:00
break ;
}
2015-03-02 12:34:16 +00:00
2017-02-25 16:44:02 +00:00
if ( ! OldKey ) {
2016-09-15 19:15:49 +00:00
LOG ( ( " MTP Error: reading old encrypted keys without old key! " ) ) ;
continue ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
if ( data . size ( ) < = 16 | | ( data . size ( ) & 0x0F ) ) {
LOG ( ( " MTP Error: bad encrypted part size in old keys: %1 " ) . arg ( data . size ( ) ) ) ;
continue ;
}
uint32 fullDataLen = data . size ( ) - 16 ;
decrypted . resize ( fullDataLen ) ;
const char * dataKey = data . constData ( ) , * encrypted = data . constData ( ) + 16 ;
2017-02-25 16:44:02 +00:00
aesDecryptLocal ( encrypted , decrypted . data ( ) , fullDataLen , OldKey , dataKey ) ;
2016-09-15 19:15:49 +00:00
uchar sha1Buffer [ 20 ] ;
if ( memcmp ( hashSha1 ( decrypted . constData ( ) , decrypted . size ( ) , sha1Buffer ) , dataKey , 16 ) ) {
LOG ( ( " MTP Error: bad decrypt key, data from old keys not decrypted " ) ) ;
continue ;
}
uint32 dataLen = * ( const uint32 * ) decrypted . constData ( ) ;
if ( dataLen > uint32 ( decrypted . size ( ) ) | | dataLen < = fullDataLen - 16 | | dataLen < 4 ) {
LOG ( ( " MTP Error: bad decrypted part size in old keys: %1, fullDataLen: %2, decrypted size: %3 " ) . arg ( dataLen ) . arg ( fullDataLen ) . arg ( decrypted . size ( ) ) ) ;
continue ;
}
decrypted . resize ( dataLen ) ;
QBuffer decryptedStream ( & decrypted ) ;
decryptedStream . open ( QIODevice : : ReadOnly ) ;
decryptedStream . seek ( 4 ) ; // skip size
LOG ( ( " App Info: reading encrypted old keys... " ) ) ;
2015-03-02 12:34:16 +00:00
2017-02-23 06:57:04 +00:00
_readOldMtpDataFields ( & decryptedStream , version , context ) ;
2020-06-09 16:57:05 +00:00
} else if ( ! ReadSetting ( blockId , stream , version , context ) ) {
2016-09-15 19:15:49 +00:00
return ;
}
}
}
2015-03-02 12:34:16 +00:00
2017-02-23 06:57:04 +00:00
bool _readOldMtpData ( bool remove , ReadSettingsContext & context ) {
2016-09-15 19:15:49 +00:00
bool result = false ;
2020-06-17 09:36:25 +00:00
// We dropped old test authorizations when migrated to multi auth.
//const auto testPostfix = (cTestMode() ? qsl("_test") : QString());
const auto testPostfix = QString ( ) ;
2020-06-09 16:57:05 +00:00
QFile file ( cWorkingDir ( ) + cDataFile ( ) + testPostfix ) ;
2016-09-15 19:15:49 +00:00
if ( file . open ( QIODevice : : ReadOnly ) ) {
LOG ( ( " App Info: reading old keys... " ) ) ;
qint32 version = 0 ;
2017-02-23 06:57:04 +00:00
_readOldMtpDataFields ( & file , version , context ) ;
2016-09-15 19:15:49 +00:00
file . close ( ) ;
result = true ;
}
if ( remove ) file . remove ( ) ;
return result ;
}
2015-03-02 12:34:16 +00:00
2020-06-09 16:57:05 +00:00
} // namespace
2015-03-02 12:34:16 +00:00
2020-10-07 09:00:31 +00:00
void sync ( ) {
Storage : : details : : Sync ( ) ;
}
2020-06-09 16:57:05 +00:00
void finish ( ) {
2020-06-16 06:42:47 +00:00
delete base : : take ( _localLoader ) ;
2020-10-07 09:00:31 +00:00
Storage : : details : : Finish ( ) ;
2020-06-09 16:57:05 +00:00
}
2015-03-02 12:34:16 +00:00
2020-06-09 16:57:05 +00:00
void InitialLoadTheme ( ) ;
bool ApplyDefaultNightMode ( ) ;
void readLangPack ( ) ;
2020-06-08 17:24:36 +00:00
2020-06-09 16:57:05 +00:00
void start ( ) {
2020-06-16 06:42:47 +00:00
Expects ( _basePath . isEmpty ( ) ) ;
2017-02-15 08:50:11 +00:00
2020-06-09 16:57:05 +00:00
_localLoader = new TaskQueue ( kFileLoaderQueueStopTimeout ) ;
2017-02-15 08:50:11 +00:00
2020-06-09 16:57:05 +00:00
_basePath = cWorkingDir ( ) + qsl ( " tdata/ " ) ;
if ( ! QDir ( ) . exists ( _basePath ) ) QDir ( ) . mkpath ( _basePath ) ;
2015-03-02 12:34:16 +00:00
2020-06-09 16:57:05 +00:00
ReadSettingsContext context ;
FileReadDescriptor settingsData ;
2020-06-17 09:36:25 +00:00
// We dropped old test authorizations when migrated to multi auth.
//const auto name = cTestMode() ? qsl("settings_test") : qsl("settings");
const auto name = u " settings " _q ;
if ( ! ReadFile ( settingsData , name , _basePath ) ) {
2020-06-09 16:57:05 +00:00
_readOldSettings ( true , context ) ;
_readOldUserSettings ( false , context ) ; // needed further in _readUserSettings
_readOldMtpData ( false , context ) ; // needed further in _readMtpData
applyReadContext ( std : : move ( context ) ) ;
2020-05-12 10:04:53 +00:00
2020-07-26 12:55:04 +00:00
_settingsRewriteNeeded = true ;
ApplyDefaultNightMode ( ) ;
2020-06-09 16:57:05 +00:00
return ;
2016-09-15 19:15:49 +00:00
}
2020-06-09 16:57:05 +00:00
LOG ( ( " App Info: reading settings... " ) ) ;
2015-03-02 12:34:16 +00:00
2020-06-09 16:57:05 +00:00
QByteArray salt , settingsEncrypted ;
settingsData . stream > > salt > > settingsEncrypted ;
if ( ! CheckStreamStatus ( settingsData . stream ) ) {
return writeSettings ( ) ;
}
2017-02-23 06:57:04 +00:00
2020-06-09 16:57:05 +00:00
if ( salt . size ( ) ! = LocalEncryptSaltSize ) {
LOG ( ( " App Error: bad salt in settings file, size: %1 " ) . arg ( salt . size ( ) ) ) ;
return writeSettings ( ) ;
}
2020-06-15 16:25:02 +00:00
SettingsKey = CreateLegacyLocalKey ( QByteArray ( ) , salt ) ;
2017-02-23 06:57:04 +00:00
2020-06-09 16:57:05 +00:00
EncryptedDescriptor settings ;
if ( ! DecryptLocal ( settings , settingsEncrypted , SettingsKey ) ) {
2020-07-01 10:16:36 +00:00
LOG ( ( " App Error: could not decrypt settings from settings file... " ) ) ;
2020-06-09 16:57:05 +00:00
return writeSettings ( ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2020-06-09 16:57:05 +00:00
LOG ( ( " App Info: reading encrypted settings... " ) ) ;
while ( ! settings . stream . atEnd ( ) ) {
2016-09-15 19:15:49 +00:00
quint32 blockId ;
2020-06-09 16:57:05 +00:00
settings . stream > > blockId ;
if ( ! CheckStreamStatus ( settings . stream ) ) {
return writeSettings ( ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2020-06-09 16:57:05 +00:00
if ( ! ReadSetting ( blockId , settings . stream , settingsData . version , context ) ) {
return writeSettings ( ) ;
2016-09-15 19:15:49 +00:00
}
}
2020-06-09 16:57:05 +00:00
_oldSettingsVersion = settingsData . version ;
_settingsSalt = salt ;
2020-06-15 09:35:35 +00:00
applyReadContext ( std : : move ( context ) ) ;
2020-06-29 17:34:08 +00:00
if ( context . legacyRead ) {
writeSettings ( ) ;
}
2020-06-15 09:35:35 +00:00
2020-06-09 16:57:05 +00:00
InitialLoadTheme ( ) ;
2020-06-19 15:51:51 +00:00
if ( context . tileRead & & _useGlobalBackgroundKeys ) {
Window : : Theme : : Background ( ) - > setTileDayValue ( context . tileDay ) ;
Window : : Theme : : Background ( ) - > setTileNightValue ( context . tileNight ) ;
}
2020-06-09 16:57:05 +00:00
readLangPack ( ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2020-06-09 16:57:05 +00:00
void writeSettings ( ) {
2020-06-19 18:10:09 +00:00
if ( ! _settingsWriteAllowed ) {
_settingsRewriteNeeded = true ;
2020-07-01 10:16:36 +00:00
// We need to generate SettingsKey anyway,
// for the moveLegacyBackground to work.
if ( SettingsKey ) {
return ;
}
2020-06-19 18:10:09 +00:00
}
2020-06-09 16:57:05 +00:00
if ( _basePath . isEmpty ( ) ) {
LOG ( ( " App Error: _basePath is empty in writeSettings() " ) ) ;
2016-09-15 19:15:49 +00:00
return ;
}
2016-02-21 14:27:54 +00:00
2020-06-09 16:57:05 +00:00
if ( ! QDir ( ) . exists ( _basePath ) ) QDir ( ) . mkpath ( _basePath ) ;
2015-03-02 12:34:16 +00:00
2020-06-17 09:36:25 +00:00
// We dropped old test authorizations when migrated to multi auth.
//const auto name = cTestMode() ? qsl("settings_test") : qsl("settings");
const auto name = u " settings " _q ;
FileWriteDescriptor settings ( name , _basePath ) ;
2020-06-09 16:57:05 +00:00
if ( _settingsSalt . isEmpty ( ) | | ! SettingsKey ) {
_settingsSalt . resize ( LocalEncryptSaltSize ) ;
2021-09-15 10:21:45 +00:00
base : : RandomFill ( _settingsSalt . data ( ) , _settingsSalt . size ( ) ) ;
2020-06-15 16:25:02 +00:00
SettingsKey = CreateLegacyLocalKey ( QByteArray ( ) , _settingsSalt ) ;
2020-06-09 16:57:05 +00:00
}
settings . writeData ( _settingsSalt ) ;
2015-03-02 12:34:16 +00:00
2020-07-01 10:16:36 +00:00
if ( ! _settingsWriteAllowed ) {
EncryptedDescriptor data ( 0 ) ;
settings . writeEncrypted ( data , SettingsKey ) ;
return ;
}
2020-06-17 09:36:25 +00:00
const auto configSerialized = LookupFallbackConfig ( ) . serialize ( ) ;
2020-06-09 16:57:05 +00:00
const auto applicationSettings = Core : : App ( ) . settings ( ) . serialize ( ) ;
2015-03-02 12:34:16 +00:00
2020-06-17 09:36:25 +00:00
quint32 size = 9 * ( sizeof ( quint32 ) + sizeof ( qint32 ) ) ;
size + = sizeof ( quint32 ) + Serialize : : bytearraySize ( configSerialized ) ;
2019-08-23 13:52:59 +00:00
size + = sizeof ( quint32 ) + Serialize : : bytearraySize ( applicationSettings ) ;
2020-06-09 16:57:05 +00:00
size + = sizeof ( quint32 ) + Serialize : : stringSize ( cDialogLastPath ( ) ) ;
2015-03-02 12:34:16 +00:00
2018-07-19 14:58:40 +00:00
// Theme keys and night mode.
size + = sizeof ( quint32 ) + sizeof ( quint64 ) * 2 + sizeof ( quint32 ) ;
2020-06-19 15:14:55 +00:00
size + = sizeof ( quint32 ) + sizeof ( quint64 ) * 2 ;
2017-04-13 17:59:05 +00:00
if ( _langPackKey ) {
size + = sizeof ( quint32 ) + sizeof ( quint64 ) ;
2016-10-28 12:44:28 +00:00
}
2017-08-02 15:07:28 +00:00
size + = sizeof ( quint32 ) + sizeof ( qint32 ) * 8 ;
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ( size ) ;
data . stream < < quint32 ( dbiAutoStart ) < < qint32 ( cAutoStart ( ) ) ;
data . stream < < quint32 ( dbiStartMinimized ) < < qint32 ( cStartMinimized ( ) ) ;
data . stream < < quint32 ( dbiSendToMenu ) < < qint32 ( cSendToMenu ( ) ) ;
data . stream < < quint32 ( dbiSeenTrayTooltip ) < < qint32 ( cSeenTrayTooltip ( ) ) ;
data . stream < < quint32 ( dbiAutoUpdate ) < < qint32 ( cAutoUpdate ( ) ) ;
data . stream < < quint32 ( dbiLastUpdateCheck ) < < qint32 ( cLastUpdateCheck ( ) ) ;
2018-10-15 11:44:48 +00:00
data . stream < < quint32 ( dbiScalePercent ) < < qint32 ( cConfigScale ( ) ) ;
2020-06-17 09:36:25 +00:00
data . stream < < quint32 ( dbiFallbackProductionConfig ) < < configSerialized ;
2019-08-23 13:52:59 +00:00
data . stream < < quint32 ( dbiApplicationSettings ) < < applicationSettings ;
2020-06-09 16:57:05 +00:00
data . stream < < quint32 ( dbiDialogLastPath ) < < cDialogLastPath ( ) ;
2018-09-20 17:56:45 +00:00
data . stream < < quint32 ( dbiAnimationsDisabled ) < < qint32 ( anim : : Disabled ( ) ? 1 : 0 ) ;
2015-03-02 12:34:16 +00:00
2018-07-19 14:58:40 +00:00
data . stream
< < quint32 ( dbiThemeKey )
< < quint64 ( _themeKeyDay )
< < quint64 ( _themeKeyNight )
< < quint32 ( Window : : Theme : : IsNightMode ( ) ? 1 : 0 ) ;
2020-06-19 15:14:55 +00:00
if ( _useGlobalBackgroundKeys ) {
data . stream
< < quint32 ( dbiBackgroundKey )
< < quint64 ( _backgroundKeyDay )
< < quint64 ( _backgroundKeyNight ) ;
data . stream
< < quint32 ( dbiTileBackground )
< < qint32 ( Window : : Theme : : Background ( ) - > tileDay ( ) ? 1 : 0 )
< < qint32 ( Window : : Theme : : Background ( ) - > tileNight ( ) ? 1 : 0 ) ;
}
2017-04-13 17:59:05 +00:00
if ( _langPackKey ) {
data . stream < < quint32 ( dbiLangPackKey ) < < quint64 ( _langPackKey ) ;
2016-10-28 12:44:28 +00:00
}
2018-10-30 11:23:54 +00:00
if ( _languagesKey ) {
data . stream < < quint32 ( dbiLanguagesKey ) < < quint64 ( _languagesKey ) ;
}
2015-03-02 12:34:16 +00:00
2017-02-25 16:44:02 +00:00
settings . writeEncrypted ( data , SettingsKey ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2020-06-19 15:14:55 +00:00
void rewriteSettingsIfNeeded ( ) {
2020-06-19 18:10:09 +00:00
if ( _settingsWriteAllowed ) {
2020-06-19 15:14:55 +00:00
return ;
}
2020-06-19 18:10:09 +00:00
_settingsWriteAllowed = true ;
if ( _oldSettingsVersion < AppVersion | | _settingsRewriteNeeded ) {
writeSettings ( ) ;
}
2020-06-19 15:14:55 +00:00
}
2018-05-03 06:39:10 +00:00
const QString & AutoupdatePrefix ( const QString & replaceWith = { } ) {
2018-07-11 22:14:44 +00:00
Expects ( ! Core : : UpdaterDisabled ( ) ) ;
2018-05-03 06:39:10 +00:00
static auto value = QString ( ) ;
2020-06-09 16:57:05 +00:00
if ( ! replaceWith . isEmpty ( ) ) {
value = replaceWith ;
2016-02-12 16:35:06 +00:00
}
2020-06-09 16:57:05 +00:00
return value ;
2016-09-15 19:15:49 +00:00
}
2016-02-12 16:35:06 +00:00
2020-06-09 16:57:05 +00:00
QString autoupdatePrefixFile ( ) {
Expects ( ! Core : : UpdaterDisabled ( ) ) ;
2017-08-02 15:07:28 +00:00
2020-06-09 16:57:05 +00:00
return cWorkingDir ( ) + " tdata/prefix " ;
2016-09-15 19:15:49 +00:00
}
2015-09-29 18:44:31 +00:00
2020-06-09 16:57:05 +00:00
const QString & readAutoupdatePrefixRaw ( ) {
Expects ( ! Core : : UpdaterDisabled ( ) ) ;
const auto & result = AutoupdatePrefix ( ) ;
if ( ! result . isEmpty ( ) ) {
return result ;
}
QFile f ( autoupdatePrefixFile ( ) ) ;
if ( f . open ( QIODevice : : ReadOnly ) ) {
const auto value = QString : : fromUtf8 ( f . readAll ( ) ) ;
if ( ! value . isEmpty ( ) ) {
return AutoupdatePrefix ( value ) ;
2016-01-09 12:51:42 +00:00
}
2015-05-21 10:44:26 +00:00
}
2021-09-13 13:33:31 +00:00
return AutoupdatePrefix ( " https://td.telegram.org " ) ;
2016-09-15 19:15:49 +00:00
}
2016-07-21 10:09:47 +00:00
2020-06-09 16:57:05 +00:00
void writeAutoupdatePrefix ( const QString & prefix ) {
if ( Core : : UpdaterDisabled ( ) ) {
return ;
}
2015-06-01 10:58:46 +00:00
2020-06-09 16:57:05 +00:00
const auto current = readAutoupdatePrefixRaw ( ) ;
if ( current ! = prefix ) {
AutoupdatePrefix ( prefix ) ;
QFile f ( autoupdatePrefixFile ( ) ) ;
if ( f . open ( QIODevice : : WriteOnly ) ) {
f . write ( prefix . toUtf8 ( ) ) ;
f . close ( ) ;
2015-05-19 15:46:45 +00:00
}
2020-06-09 16:57:05 +00:00
if ( cAutoUpdate ( ) ) {
Core : : UpdateChecker checker ;
checker . start ( ) ;
2015-06-28 12:37:10 +00:00
}
2015-05-19 15:46:45 +00:00
}
2016-09-15 19:15:49 +00:00
}
2015-05-19 15:46:45 +00:00
2020-06-09 16:57:05 +00:00
QString readAutoupdatePrefix ( ) {
Expects ( ! Core : : UpdaterDisabled ( ) ) ;
2015-05-19 15:46:45 +00:00
2020-06-09 16:57:05 +00:00
auto result = readAutoupdatePrefixRaw ( ) ;
return result . replace ( QRegularExpression ( " /+$ " ) , QString ( ) ) ;
}
2016-06-27 16:25:21 +00:00
2020-06-19 15:14:55 +00:00
void writeBackground ( const Data : : WallPaper & paper , const QImage & image ) {
2020-06-29 16:07:56 +00:00
Expects ( _settingsWriteAllowed ) ;
2020-06-19 15:14:55 +00:00
if ( ! _backgroundCanWrite ) {
return ;
}
_useGlobalBackgroundKeys = true ;
auto & backgroundKey = Window : : Theme : : IsNightMode ( )
? _backgroundKeyNight
: _backgroundKeyDay ;
auto imageData = QByteArray ( ) ;
if ( ! image . isNull ( ) ) {
const auto width = qint32 ( image . width ( ) ) ;
const auto height = qint32 ( image . height ( ) ) ;
const auto perpixel = ( image . depth ( ) > > 3 ) ;
const auto srcperline = image . bytesPerLine ( ) ;
const auto srcsize = srcperline * height ;
const auto dstperline = width * perpixel ;
const auto dstsize = dstperline * height ;
const auto copy = ( image . format ( ) ! = kSavedBackgroundFormat )
? image . convertToFormat ( kSavedBackgroundFormat )
: image ;
imageData . resize ( 2 * sizeof ( qint32 ) + dstsize ) ;
auto dst = bytes : : make_detached_span ( imageData ) ;
bytes : : copy ( dst , bytes : : object_as_span ( & width ) ) ;
dst = dst . subspan ( sizeof ( qint32 ) ) ;
bytes : : copy ( dst , bytes : : object_as_span ( & height ) ) ;
dst = dst . subspan ( sizeof ( qint32 ) ) ;
const auto src = bytes : : make_span ( image . constBits ( ) , srcsize ) ;
if ( srcsize = = dstsize ) {
bytes : : copy ( dst , src ) ;
} else {
for ( auto y = 0 ; y ! = height ; + + y ) {
bytes : : copy ( dst , src . subspan ( y * srcperline , dstperline ) ) ;
dst = dst . subspan ( dstperline ) ;
}
}
}
if ( ! backgroundKey ) {
backgroundKey = GenerateKey ( _basePath ) ;
writeSettings ( ) ;
}
const auto serialized = paper . serialize ( ) ;
quint32 size = sizeof ( qint32 )
+ Serialize : : bytearraySize ( serialized )
+ Serialize : : bytearraySize ( imageData ) ;
EncryptedDescriptor data ( size ) ;
data . stream
< < qint32 ( kWallPaperSerializeTagId )
< < serialized
< < imageData ;
FileWriteDescriptor file ( backgroundKey , _basePath ) ;
file . writeEncrypted ( data , SettingsKey ) ;
}
bool readBackground ( ) {
FileReadDescriptor bg ;
auto & backgroundKey = Window : : Theme : : IsNightMode ( )
? _backgroundKeyNight
: _backgroundKeyDay ;
if ( ! ReadEncryptedFile ( bg , backgroundKey , _basePath , SettingsKey ) ) {
if ( backgroundKey ) {
ClearKey ( backgroundKey , _basePath ) ;
backgroundKey = 0 ;
writeSettings ( ) ;
}
return false ;
}
qint32 legacyId = 0 ;
bg . stream > > legacyId ;
const auto paper = [ & ] {
if ( legacyId = = kWallPaperLegacySerializeTagId ) {
quint64 id = 0 ;
quint64 accessHash = 0 ;
quint32 flags = 0 ;
QString slug ;
bg . stream
> > id
> > accessHash
> > flags
> > slug ;
return Data : : WallPaper : : FromLegacySerialized (
id ,
accessHash ,
flags ,
slug ) ;
} else if ( legacyId = = kWallPaperSerializeTagId ) {
QByteArray serialized ;
bg . stream > > serialized ;
return Data : : WallPaper : : FromSerialized ( serialized ) ;
} else {
return Data : : WallPaper : : FromLegacyId ( legacyId ) ;
}
} ( ) ;
if ( bg . stream . status ( ) ! = QDataStream : : Ok | | ! paper ) {
return false ;
}
QByteArray imageData ;
bg . stream > > imageData ;
const auto isOldEmptyImage = ( bg . stream . status ( ) ! = QDataStream : : Ok ) ;
if ( isOldEmptyImage
| | Data : : IsLegacy1DefaultWallPaper ( * paper )
2021-08-31 19:10:39 +00:00
| | ( Data : : IsLegacy2DefaultWallPaper ( * paper ) & & bg . version < 3000000 )
| | ( Data : : IsLegacy3DefaultWallPaper ( * paper ) & & bg . version < 3000000 )
| | ( Data : : IsLegacy4DefaultWallPaper ( * paper ) & & bg . version < 3000000 )
2020-06-19 15:14:55 +00:00
| | Data : : IsDefaultWallPaper ( * paper ) ) {
_backgroundCanWrite = false ;
2021-08-31 19:10:39 +00:00
if ( isOldEmptyImage | | bg . version < 3000000 ) {
2020-06-19 15:14:55 +00:00
Window : : Theme : : Background ( ) - > set ( Data : : DefaultWallPaper ( ) ) ;
} else {
Window : : Theme : : Background ( ) - > set ( * paper ) ;
}
_backgroundCanWrite = true ;
return true ;
} else if ( Data : : IsThemeWallPaper ( * paper ) & & imageData . isEmpty ( ) ) {
_backgroundCanWrite = false ;
Window : : Theme : : Background ( ) - > set ( * paper ) ;
_backgroundCanWrite = true ;
return true ;
}
auto image = QImage ( ) ;
if ( legacyId = = kWallPaperSerializeTagId ) {
const auto perpixel = 4 ;
auto src = bytes : : make_span ( imageData ) ;
auto width = qint32 ( ) ;
auto height = qint32 ( ) ;
if ( src . size ( ) > 2 * sizeof ( qint32 ) ) {
bytes : : copy (
bytes : : object_as_span ( & width ) ,
src . subspan ( 0 , sizeof ( qint32 ) ) ) ;
src = src . subspan ( sizeof ( qint32 ) ) ;
bytes : : copy (
bytes : : object_as_span ( & height ) ,
src . subspan ( 0 , sizeof ( qint32 ) ) ) ;
src = src . subspan ( sizeof ( qint32 ) ) ;
if ( width + height < = kWallPaperSidesLimit
& & src . size ( ) = = width * height * perpixel ) {
image = QImage (
width ,
height ,
QImage : : Format_ARGB32_Premultiplied ) ;
if ( ! image . isNull ( ) ) {
const auto srcperline = width * perpixel ;
const auto srcsize = srcperline * height ;
const auto dstperline = image . bytesPerLine ( ) ;
const auto dstsize = dstperline * height ;
Assert ( srcsize = = dstsize ) ;
bytes : : copy (
bytes : : make_span ( image . bits ( ) , dstsize ) ,
src ) ;
}
}
}
} else {
auto buffer = QBuffer ( & imageData ) ;
auto reader = QImageReader ( & buffer ) ;
reader . setAutoTransform ( true ) ;
if ( ! reader . read ( & image ) ) {
image = QImage ( ) ;
}
}
2021-08-12 09:32:30 +00:00
if ( ! image . isNull ( ) | | ! paper - > backgroundColors ( ) . empty ( ) ) {
2020-06-19 15:14:55 +00:00
_backgroundCanWrite = false ;
Window : : Theme : : Background ( ) - > set ( * paper , std : : move ( image ) ) ;
_backgroundCanWrite = true ;
return true ;
}
return false ;
}
void moveLegacyBackground (
const QString & fromBasePath ,
const MTP : : AuthKeyPtr & fromLocalKey ,
uint64 legacyBackgroundKeyDay ,
uint64 legacyBackgroundKeyNight ) {
if ( _useGlobalBackgroundKeys
| | ( ! legacyBackgroundKeyDay & & ! legacyBackgroundKeyNight ) ) {
return ;
}
const auto move = [ & ] ( uint64 from , FileKey & to ) {
if ( ! from | | to ) {
return ;
}
to = GenerateKey ( _basePath ) ;
FileReadDescriptor read ;
if ( ! ReadEncryptedFile ( read , from , fromBasePath , fromLocalKey ) ) {
return ;
}
EncryptedDescriptor data ;
data . data = read . data ;
FileWriteDescriptor write ( to , _basePath ) ;
write . writeEncrypted ( data , SettingsKey ) ;
} ;
move ( legacyBackgroundKeyDay , _backgroundKeyDay ) ;
move ( legacyBackgroundKeyNight , _backgroundKeyNight ) ;
2020-06-26 09:23:10 +00:00
_useGlobalBackgroundKeys = true ;
2020-06-19 18:10:09 +00:00
_settingsRewriteNeeded = true ;
2020-06-19 15:14:55 +00:00
}
2020-06-09 16:57:05 +00:00
void reset ( ) {
if ( _localLoader ) {
_localLoader - > stop ( ) ;
}
2016-01-09 12:51:42 +00:00
2020-06-09 16:57:05 +00:00
Window : : Theme : : Background ( ) - > reset ( ) ;
_oldSettingsVersion = 0 ;
2020-06-19 15:51:51 +00:00
Core : : App ( ) . settings ( ) . resetOnLastLogout ( ) ;
writeSettings ( ) ;
2020-06-09 16:57:05 +00:00
}
2016-07-21 10:09:47 +00:00
2020-06-09 16:57:05 +00:00
int32 oldSettingsVersion ( ) {
return _oldSettingsVersion ;
2016-09-15 19:15:49 +00:00
}
2016-01-09 12:51:42 +00:00
2020-06-09 16:57:05 +00:00
class CountWaveformTask : public Task {
public :
CountWaveformTask ( not_null < Data : : DocumentMedia * > media )
: _doc ( media - > owner ( ) )
, _loc ( _doc - > location ( true ) )
, _data ( media - > bytes ( ) )
, _wavemax ( 0 ) {
if ( _data . isEmpty ( ) & & ! _loc . accessEnable ( ) ) {
_doc = nullptr ;
}
2018-07-19 14:58:40 +00:00
}
2020-06-09 16:57:05 +00:00
void process ( ) override {
if ( ! _doc ) return ;
2015-06-28 12:37:10 +00:00
2020-06-09 16:57:05 +00:00
_waveform = audioCountWaveform ( _loc , _data ) ;
_wavemax = _waveform . empty ( )
? char ( 0 )
: * ranges : : max_element ( _waveform ) ;
2017-01-18 10:26:33 +00:00
}
2020-06-09 16:57:05 +00:00
void finish ( ) override {
if ( const auto voice = _doc ? _doc - > voice ( ) : nullptr ) {
if ( ! _waveform . isEmpty ( ) ) {
voice - > waveform = _waveform ;
voice - > wavemax = _wavemax ;
}
if ( voice - > waveform . isEmpty ( ) ) {
voice - > waveform . resize ( 1 ) ;
voice - > waveform [ 0 ] = - 2 ;
voice - > wavemax = 0 ;
} else if ( voice - > waveform [ 0 ] < 0 ) {
voice - > waveform [ 0 ] = - 2 ;
voice - > wavemax = 0 ;
2019-01-29 07:29:38 +00:00
}
2020-06-10 10:49:10 +00:00
_doc - > owner ( ) . requestDocumentViewRepaint ( _doc ) ;
2018-07-19 14:58:40 +00:00
}
2016-09-15 19:15:49 +00:00
}
2020-06-09 16:57:05 +00:00
~ CountWaveformTask ( ) {
if ( _data . isEmpty ( ) & & _doc ) {
_loc . accessDisable ( ) ;
}
2016-09-15 19:15:49 +00:00
}
2015-05-19 15:46:45 +00:00
2020-06-09 16:57:05 +00:00
protected :
DocumentData * _doc = nullptr ;
2020-10-13 16:43:18 +00:00
Core : : FileLocation _loc ;
2020-06-09 16:57:05 +00:00
QByteArray _data ;
VoiceWaveform _waveform ;
char _wavemax ;
2015-05-19 15:46:45 +00:00
2020-06-09 16:57:05 +00:00
} ;
2016-06-27 16:25:21 +00:00
2020-06-09 16:57:05 +00:00
void countVoiceWaveform ( not_null < Data : : DocumentMedia * > media ) {
const auto document = media - > owner ( ) ;
if ( const auto voice = document - > voice ( ) ) {
if ( _localLoader ) {
voice - > waveform . resize ( 1 + sizeof ( TaskId ) ) ;
voice - > waveform [ 0 ] = - 1 ; // counting
TaskId taskId = _localLoader - > addTask (
std : : make_unique < CountWaveformTask > ( media ) ) ;
memcpy ( voice - > waveform . data ( ) + 1 , & taskId , sizeof ( taskId ) ) ;
2019-01-16 17:26:26 +00:00
}
2019-01-16 12:25:29 +00:00
}
2020-06-09 16:57:05 +00:00
}
2019-01-28 13:59:49 +00:00
2020-06-09 16:57:05 +00:00
void cancelTask ( TaskId id ) {
if ( _localLoader ) {
_localLoader - > cancelTask ( id ) ;
2016-07-21 10:09:47 +00:00
}
2016-09-15 19:15:49 +00:00
}
2016-07-21 10:09:47 +00:00
2018-07-19 14:58:40 +00:00
Window : : Theme : : Saved readThemeUsingKey ( FileKey key ) {
2019-09-03 18:04:38 +00:00
using namespace Window : : Theme ;
2016-10-28 12:44:28 +00:00
FileReadDescriptor theme ;
2020-06-09 16:57:05 +00:00
if ( ! ReadEncryptedFile ( theme , key , _basePath , SettingsKey ) ) {
2021-09-13 17:09:55 +00:00
DEBUG_LOG ( ( " Theme: Could not read file for key: %1 " ) . arg ( key ) ) ;
2018-07-19 14:58:40 +00:00
return { } ;
2016-10-28 12:44:28 +00:00
}
2019-09-03 18:04:38 +00:00
auto tag = QString ( ) ;
auto result = Saved ( ) ;
auto & object = result . object ;
auto & cache = result . cache ;
2021-04-01 21:04:10 +00:00
auto field1 = qint32 ( ) ;
auto field2 = quint32 ( ) ;
2019-09-03 18:04:38 +00:00
theme . stream > > object . content ;
theme . stream > > tag > > object . pathAbsolute ;
if ( tag = = kThemeNewPathRelativeTag ) {
2019-09-05 05:18:21 +00:00
theme . stream
> > object . pathRelative
> > object . cloud . id
> > object . cloud . accessHash
> > object . cloud . slug
> > object . cloud . title
> > object . cloud . documentId
2021-04-01 21:04:10 +00:00
> > field1 ;
2019-09-03 18:04:38 +00:00
} else {
object . pathRelative = tag ;
}
2016-10-28 12:44:28 +00:00
if ( theme . stream . status ( ) ! = QDataStream : : Ok ) {
2021-09-13 17:09:55 +00:00
DEBUG_LOG ( ( " Theme: Bad status for key: %1, tag: %2 "
) . arg ( key
) . arg ( tag ) ) ;
2018-07-19 14:58:40 +00:00
return { } ;
2016-10-28 12:44:28 +00:00
}
2017-02-03 20:07:26 +00:00
2019-09-03 18:04:38 +00:00
auto ignoreCache = false ;
2019-09-05 05:18:21 +00:00
if ( ! object . cloud . id ) {
2019-09-05 07:42:06 +00:00
auto file = QFile ( object . pathRelative ) ;
2019-09-03 18:04:38 +00:00
if ( object . pathRelative . isEmpty ( ) | | ! file . exists ( ) ) {
file . setFileName ( object . pathAbsolute ) ;
}
if ( ! file . fileName ( ) . isEmpty ( )
& & file . exists ( )
& & file . open ( QIODevice : : ReadOnly ) ) {
if ( file . size ( ) > kThemeFileSizeLimit ) {
LOG ( ( " Error: theme file too large: %1 "
" (should be less than 5 MB, got %2) "
) . arg ( file . fileName ( )
) . arg ( file . size ( ) ) ) ;
return { } ;
}
auto fileContent = file . readAll ( ) ;
file . close ( ) ;
if ( object . content ! = fileContent ) {
object . content = fileContent ;
ignoreCache = true ;
}
2016-10-28 12:44:28 +00:00
}
}
2021-04-01 21:04:10 +00:00
int32 cachePaletteChecksum = 0 ;
int32 cacheContentChecksum = 0 ;
QByteArray cacheColors ;
QByteArray cacheBackground ;
theme . stream
> > cachePaletteChecksum
> > cacheContentChecksum
> > cacheColors
> > cacheBackground
> > field2 ;
2019-09-03 18:04:38 +00:00
if ( ! ignoreCache ) {
2016-10-28 12:44:28 +00:00
if ( theme . stream . status ( ) ! = QDataStream : : Ok ) {
2021-09-13 17:09:55 +00:00
DEBUG_LOG ( ( " Theme: Bad status for cache, key: %1, tag: %2 "
) . arg ( key
) . arg ( tag ) ) ;
2018-07-19 14:58:40 +00:00
return { } ;
2016-10-28 12:44:28 +00:00
}
2021-04-01 21:04:10 +00:00
cache . paletteChecksum = cachePaletteChecksum ;
cache . contentChecksum = cacheContentChecksum ;
cache . colors = std : : move ( cacheColors ) ;
cache . background = std : : move ( cacheBackground ) ;
cache . tiled = ( ( field2 & quint32 ( 0xFF ) ) = = 1 ) ;
}
if ( tag = = kThemeNewPathRelativeTag ) {
object . cloud . createdBy = UserId (
( ( quint64 ( field2 ) > > 8 ) < < 32 ) | quint64 ( quint32 ( field1 ) ) ) ;
2016-10-28 12:44:28 +00:00
}
2018-07-19 14:58:40 +00:00
return result ;
}
2019-09-05 06:51:46 +00:00
std : : optional < QString > InitialLoadThemeUsingKey ( FileKey key ) {
2018-07-19 14:58:40 +00:00
auto read = readThemeUsingKey ( key ) ;
2019-09-03 18:04:38 +00:00
const auto result = read . object . pathAbsolute ;
2021-09-13 17:09:55 +00:00
if ( read . object . content . isEmpty ( ) ) {
DEBUG_LOG ( ( " Theme: Could not read content for key: %1 " ) . arg ( key ) ) ;
}
2019-09-03 18:04:38 +00:00
if ( read . object . content . isEmpty ( )
2019-09-05 06:51:46 +00:00
| | ! Window : : Theme : : Initialize ( std : : move ( read ) ) ) {
2021-09-13 17:09:55 +00:00
DEBUG_LOG ( ( " Theme: Could not initialized for key: %1 " ) . arg ( key ) ) ;
2019-09-05 06:51:46 +00:00
return std : : nullopt ;
2019-09-03 18:04:38 +00:00
}
return result ;
2016-10-28 12:44:28 +00:00
}
2018-07-19 14:58:40 +00:00
void writeTheme ( const Window : : Theme : : Saved & saved ) {
2019-09-03 18:04:38 +00:00
using namespace Window : : Theme ;
2018-07-21 13:54:00 +00:00
if ( _themeKeyLegacy ) {
2021-09-13 17:09:55 +00:00
DEBUG_LOG ( ( " Theme: skipping write, because legacy: %1 "
) . arg ( _themeKeyLegacy ) ) ;
2018-07-21 13:54:00 +00:00
return ;
}
2019-09-03 18:04:38 +00:00
auto & themeKey = IsNightMode ( )
2018-07-19 14:58:40 +00:00
? _themeKeyNight
: _themeKeyDay ;
2021-09-13 17:09:55 +00:00
DEBUG_LOG ( ( " Theme: writing (night: %1), key_day: %2, key_night: %3 "
) . arg ( Logs : : b ( IsNightMode ( ) )
) . arg ( _themeKeyDay
) . arg ( _themeKeyNight ) ) ;
2019-09-03 18:04:38 +00:00
if ( saved . object . content . isEmpty ( ) ) {
2018-07-19 14:58:40 +00:00
if ( themeKey ) {
2021-09-13 17:09:55 +00:00
if ( IsNightMode ( ) ) {
DEBUG_LOG ( ( " Theme: cleared for night mode. " ) ) ;
SetNightModeValue ( false ) ;
}
2020-06-09 16:57:05 +00:00
ClearKey ( themeKey , _basePath ) ;
2018-07-19 14:58:40 +00:00
themeKey = 0 ;
2016-12-20 13:03:51 +00:00
writeSettings ( ) ;
}
return ;
}
2017-02-03 20:07:26 +00:00
2018-07-19 14:58:40 +00:00
if ( ! themeKey ) {
2020-06-09 16:57:05 +00:00
themeKey = GenerateKey ( _basePath ) ;
2016-10-28 12:44:28 +00:00
writeSettings ( ) ;
}
2019-09-03 18:04:38 +00:00
const auto & object = saved . object ;
const auto & cache = saved . cache ;
const auto tag = QString ( kThemeNewPathRelativeTag ) ;
2019-09-05 05:18:21 +00:00
quint32 size = Serialize : : bytearraySize ( object . content )
+ Serialize : : stringSize ( tag )
+ Serialize : : stringSize ( object . pathAbsolute )
+ Serialize : : stringSize ( object . pathRelative )
+ sizeof ( uint64 ) * 3
+ Serialize : : stringSize ( object . cloud . slug )
+ Serialize : : stringSize ( object . cloud . title )
+ sizeof ( qint32 )
+ sizeof ( qint32 ) * 2
+ Serialize : : bytearraySize ( cache . colors )
+ Serialize : : bytearraySize ( cache . background )
+ sizeof ( quint32 ) ;
2021-04-01 21:04:10 +00:00
const auto bareCreatedById = object . cloud . createdBy . bare ;
Assert ( ( bareCreatedById & PeerId : : kChatTypeMask ) = = bareCreatedById ) ;
const auto field1 = qint32 ( quint32 ( bareCreatedById & 0xFFFFFFFFULL ) ) ;
const auto field2 = quint32 ( cache . tiled ? 1 : 0 )
| ( quint32 ( bareCreatedById > > 32 ) < < 8 ) ;
2016-10-28 12:44:28 +00:00
EncryptedDescriptor data ( size ) ;
2019-09-03 18:04:38 +00:00
data . stream
2019-09-05 05:18:21 +00:00
< < object . content
< < tag
< < object . pathAbsolute
< < object . pathRelative
< < object . cloud . id
< < object . cloud . accessHash
< < object . cloud . slug
< < object . cloud . title
< < object . cloud . documentId
2021-04-01 21:04:10 +00:00
< < field1
2019-09-03 18:04:38 +00:00
< < cache . paletteChecksum
< < cache . contentChecksum
< < cache . colors
< < cache . background
2021-04-01 21:04:10 +00:00
< < field2 ;
2016-10-28 12:44:28 +00:00
2020-06-09 16:57:05 +00:00
FileWriteDescriptor file ( themeKey , _basePath ) ;
2017-02-25 16:44:02 +00:00
file . writeEncrypted ( data , SettingsKey ) ;
2016-10-28 12:44:28 +00:00
}
2016-12-20 13:03:51 +00:00
void clearTheme ( ) {
2018-07-19 14:58:40 +00:00
writeTheme ( Window : : Theme : : Saved ( ) ) ;
2016-12-20 13:03:51 +00:00
}
2019-09-05 06:51:46 +00:00
void InitialLoadTheme ( ) {
2018-07-19 14:58:40 +00:00
const auto key = ( _themeKeyLegacy ! = 0 )
? _themeKeyLegacy
: ( Window : : Theme : : IsNightMode ( )
? _themeKeyNight
: _themeKeyDay ) ;
2021-09-13 17:09:55 +00:00
DEBUG_LOG ( ( " Theme: initial load (night: %1), "
" key_legacy: %2, key_day: %3, key_night: %4 "
) . arg ( Logs : : b ( Window : : Theme : : IsNightMode ( ) )
) . arg ( _themeKeyLegacy
) . arg ( _themeKeyDay
) . arg ( _themeKeyNight ) ) ;
2018-07-19 14:58:40 +00:00
if ( ! key ) {
2021-09-13 17:09:55 +00:00
if ( Window : : Theme : : IsNightMode ( ) ) {
DEBUG_LOG ( ( " Theme: zero key for night mode. " ) ) ;
Window : : Theme : : SetNightModeValue ( false ) ;
}
2018-07-19 14:58:40 +00:00
return ;
2019-09-05 06:51:46 +00:00
} else if ( const auto path = InitialLoadThemeUsingKey ( key ) ) {
2021-09-13 17:09:55 +00:00
DEBUG_LOG ( ( " Theme: loaded with result: %1 " ) . arg ( * path ) ) ;
2018-07-19 14:58:40 +00:00
if ( _themeKeyLegacy ) {
2019-09-05 06:51:46 +00:00
Window : : Theme : : SetNightModeValue ( * path
2018-07-19 14:58:40 +00:00
= = Window : : Theme : : NightThemePath ( ) ) ;
( Window : : Theme : : IsNightMode ( )
? _themeKeyNight
: _themeKeyDay ) = base : : take ( _themeKeyLegacy ) ;
2021-09-13 17:09:55 +00:00
DEBUG_LOG ( ( " Theme: now (night: %1), "
" key_legacy: %2, key_day: %3, key_night: %4 (path: %5) "
) . arg ( Logs : : b ( Window : : Theme : : IsNightMode ( ) )
) . arg ( _themeKeyLegacy
) . arg ( _themeKeyDay
) . arg ( _themeKeyNight
) . arg ( * path ) ) ;
2018-07-19 14:58:40 +00:00
}
} else {
2021-09-13 17:09:55 +00:00
DEBUG_LOG ( ( " Theme: could not load, clearing.. " ) ) ;
2016-12-20 13:03:51 +00:00
clearTheme ( ) ;
2016-10-28 12:44:28 +00:00
}
}
2020-02-11 12:00:04 +00:00
bool ApplyDefaultNightMode ( ) {
const auto NightByDefault = Platform : : IsMacStoreBuild ( ) ;
if ( ! NightByDefault
| | Window : : Theme : : IsNightMode ( )
| | _themeKeyDay
| | _themeKeyNight
| | _themeKeyLegacy ) {
return false ;
}
2020-07-26 12:55:04 +00:00
Core : : App ( ) . startSettingsAndBackground ( ) ;
2020-02-11 12:00:04 +00:00
Window : : Theme : : ToggleNightMode ( ) ;
Window : : Theme : : KeepApplied ( ) ;
return true ;
}
2018-07-19 14:58:40 +00:00
Window : : Theme : : Saved readThemeAfterSwitch ( ) {
const auto key = Window : : Theme : : IsNightMode ( )
? _themeKeyNight
: _themeKeyDay ;
return readThemeUsingKey ( key ) ;
2016-12-20 13:03:51 +00:00
}
2017-04-13 17:59:05 +00:00
void readLangPack ( ) {
FileReadDescriptor langpack ;
2020-06-09 16:57:05 +00:00
if ( ! _langPackKey | | ! ReadEncryptedFile ( langpack , _langPackKey , _basePath , SettingsKey ) ) {
2017-04-13 17:59:05 +00:00
return ;
}
auto data = QByteArray ( ) ;
langpack . stream > > data ;
if ( langpack . stream . status ( ) = = QDataStream : : Ok ) {
2020-09-30 09:11:44 +00:00
Lang : : GetInstance ( ) . fillFromSerialized ( data , langpack . version ) ;
2017-04-13 17:59:05 +00:00
}
}
void writeLangPack ( ) {
2020-09-30 09:11:44 +00:00
auto langpack = Lang : : GetInstance ( ) . serialize ( ) ;
2017-04-13 17:59:05 +00:00
if ( ! _langPackKey ) {
2020-06-09 16:57:05 +00:00
_langPackKey = GenerateKey ( _basePath ) ;
2017-04-13 17:59:05 +00:00
writeSettings ( ) ;
}
EncryptedDescriptor data ( Serialize : : bytearraySize ( langpack ) ) ;
data . stream < < langpack ;
2020-06-09 16:57:05 +00:00
FileWriteDescriptor file ( _langPackKey , _basePath ) ;
2017-04-13 17:59:05 +00:00
file . writeEncrypted ( data , SettingsKey ) ;
}
2018-11-01 07:10:15 +00:00
void saveRecentLanguages ( const std : : vector < Lang : : Language > & list ) {
if ( list . empty ( ) ) {
if ( _languagesKey ) {
2020-06-09 16:57:05 +00:00
ClearKey ( _languagesKey , _basePath ) ;
2018-11-01 07:10:15 +00:00
_languagesKey = 0 ;
writeSettings ( ) ;
}
2018-10-30 11:23:54 +00:00
return ;
}
auto size = sizeof ( qint32 ) ;
for ( const auto & language : list ) {
size + = Serialize : : stringSize ( language . id )
+ Serialize : : stringSize ( language . pluralId )
+ Serialize : : stringSize ( language . baseId )
+ Serialize : : stringSize ( language . name )
+ Serialize : : stringSize ( language . nativeName ) ;
}
if ( ! _languagesKey ) {
2020-06-09 16:57:05 +00:00
_languagesKey = GenerateKey ( _basePath ) ;
2018-10-30 11:23:54 +00:00
writeSettings ( ) ;
}
EncryptedDescriptor data ( size ) ;
data . stream < < qint32 ( list . size ( ) ) ;
for ( const auto & language : list ) {
data . stream
< < language . id
< < language . pluralId
< < language . baseId
< < language . name
< < language . nativeName ;
}
2020-06-09 16:57:05 +00:00
FileWriteDescriptor file ( _languagesKey , _basePath ) ;
2018-10-30 11:23:54 +00:00
file . writeEncrypted ( data , SettingsKey ) ;
}
2018-11-01 07:10:15 +00:00
void pushRecentLanguage ( const Lang : : Language & language ) {
if ( language . id . startsWith ( ' # ' ) ) {
return ;
}
auto list = readRecentLanguages ( ) ;
list . erase (
ranges : : remove_if (
list ,
[ & ] ( const Lang : : Language & v ) { return ( v . id = = language . id ) ; } ) ,
end ( list ) ) ;
list . insert ( list . begin ( ) , language ) ;
saveRecentLanguages ( list ) ;
}
void removeRecentLanguage ( const QString & id ) {
auto list = readRecentLanguages ( ) ;
list . erase (
ranges : : remove_if (
list ,
[ & ] ( const Lang : : Language & v ) { return ( v . id = = id ) ; } ) ,
end ( list ) ) ;
saveRecentLanguages ( list ) ;
}
std : : vector < Lang : : Language > readRecentLanguages ( ) {
2018-10-30 11:23:54 +00:00
FileReadDescriptor languages ;
2020-06-09 16:57:05 +00:00
if ( ! _languagesKey | | ! ReadEncryptedFile ( languages , _languagesKey , _basePath , SettingsKey ) ) {
2018-10-30 11:23:54 +00:00
return { } ;
}
qint32 count = 0 ;
languages . stream > > count ;
if ( count < = 0 ) {
return { } ;
}
2018-11-01 07:10:15 +00:00
auto result = std : : vector < Lang : : Language > ( ) ;
2018-10-30 11:23:54 +00:00
result . reserve ( count ) ;
for ( auto i = 0 ; i ! = count ; + + i ) {
auto language = Lang : : Language ( ) ;
languages . stream
> > language . id
> > language . pluralId
> > language . baseId
> > language . name
> > language . nativeName ;
result . push_back ( language ) ;
}
if ( languages . stream . status ( ) ! = QDataStream : : Ok ) {
return { } ;
}
return result ;
}
2019-09-05 20:21:44 +00:00
Window : : Theme : : Object ReadThemeContent ( ) {
2019-09-05 07:42:06 +00:00
using namespace Window : : Theme ;
2019-09-05 20:21:44 +00:00
2019-09-05 07:42:06 +00:00
auto & themeKey = IsNightMode ( ) ? _themeKeyNight : _themeKeyDay ;
2018-07-19 14:58:40 +00:00
if ( ! themeKey ) {
2019-09-05 20:21:44 +00:00
return Object ( ) ;
2017-02-03 20:07:26 +00:00
}
FileReadDescriptor theme ;
2020-06-09 16:57:05 +00:00
if ( ! ReadEncryptedFile ( theme , themeKey , _basePath , SettingsKey ) ) {
2019-09-05 20:21:44 +00:00
return Object ( ) ;
2017-02-03 20:07:26 +00:00
}
2019-09-05 20:21:44 +00:00
QByteArray content ;
2019-08-26 16:36:23 +00:00
QString pathRelative , pathAbsolute ;
2019-09-05 20:21:44 +00:00
theme . stream > > content > > pathRelative > > pathAbsolute ;
2017-02-03 20:07:26 +00:00
if ( theme . stream . status ( ) ! = QDataStream : : Ok ) {
2019-09-05 20:21:44 +00:00
return Object ( ) ;
2017-02-03 20:07:26 +00:00
}
2019-09-05 20:21:44 +00:00
auto result = Object ( ) ;
result . pathAbsolute = pathAbsolute ;
result . content = content ;
return result ;
2017-02-03 20:07:26 +00:00
}
2018-06-26 15:34:38 +00:00
void incrementRecentHashtag ( RecentHashtagPack & recent , const QString & tag ) {
auto i = recent . begin ( ) , e = recent . end ( ) ;
for ( ; i ! = e ; + + i ) {
if ( i - > first = = tag ) {
+ + i - > second ;
if ( qAbs ( i - > second ) > 0x4000 ) {
for ( auto j = recent . begin ( ) ; j ! = e ; + + j ) {
if ( j - > second > 1 ) {
j - > second / = 2 ;
} else if ( j - > second > 0 ) {
j - > second = 1 ;
}
}
}
for ( ; i ! = recent . begin ( ) ; - - i ) {
if ( qAbs ( ( i - 1 ) - > second ) > qAbs ( i - > second ) ) {
break ;
}
qSwap ( * i , * ( i - 1 ) ) ;
}
break ;
}
}
if ( i = = e ) {
while ( recent . size ( ) > = 64 ) recent . pop_back ( ) ;
recent . push_back ( qMakePair ( tag , 1 ) ) ;
for ( i = recent . end ( ) - 1 ; i ! = recent . begin ( ) ; - - i ) {
if ( ( i - 1 ) - > second > i - > second ) {
break ;
}
qSwap ( * i , * ( i - 1 ) ) ;
}
}
}
2020-06-09 16:57:05 +00:00
bool readOldMtpData ( bool remove , ReadSettingsContext & context ) {
return _readOldMtpData ( remove , context ) ;
2016-09-15 19:15:49 +00:00
}
2014-11-22 09:45:04 +00:00
2020-06-09 16:57:05 +00:00
bool readOldUserSettings ( bool remove , ReadSettingsContext & context ) {
return _readOldUserSettings ( remove , context ) ;
2016-09-15 19:15:49 +00:00
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
} // namespace Local