2014-11-22 09:45:04 +00:00
/*
This file is part of Telegram Desktop ,
2014-12-01 10:47:38 +00:00
the official desktop version of Telegram messaging app , see https : //telegram.org
2014-11-22 09:45:04 +00:00
Telegram Desktop is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
It is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2015-10-03 13:16:42 +00:00
In addition , as a special exception , the copyright holders give permission
to link the code of portions of this program with the OpenSSL library .
2014-11-22 09:45:04 +00:00
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2017-01-11 18:31:31 +00:00
Copyright ( c ) 2014 - 2017 John Preston , https : //desktop.telegram.org
2014-11-22 09:45:04 +00:00
*/
2017-03-04 10:23:56 +00:00
# include "storage/localstorage.h"
2014-11-22 09:45:04 +00:00
2017-03-04 10:23:56 +00:00
# include "storage/serialize_document.h"
# include "storage/serialize_common.h"
2017-12-11 14:45:29 +00:00
# include "chat_helpers/stickers.h"
2016-06-09 14:31:10 +00:00
# include "data/data_drafts.h"
2017-02-03 20:07:26 +00:00
# include "window/themes/window_theme.h"
2016-05-25 12:09:05 +00:00
# include "observer_peer.h"
2015-08-07 12:11:50 +00:00
# include "mainwidget.h"
2016-04-12 21:31:28 +00:00
# include "mainwindow.h"
2017-04-13 08:27:10 +00:00
# include "lang/lang_keys.h"
2016-09-16 12:49:36 +00:00
# include "media/media_audio.h"
2016-11-15 11:56:49 +00:00
# include "ui/widgets/input_fields.h"
2017-02-23 06:57:04 +00:00
# include "mtproto/dc_options.h"
2017-02-23 10:59:19 +00:00
# include "messenger.h"
2016-10-07 07:58:34 +00:00
# include "application.h"
2016-04-12 21:31:28 +00:00
# include "apiwrap.h"
2017-02-23 09:32:28 +00:00
# include "auth_session.h"
2017-04-09 18:06:06 +00:00
# include "window/window_controller.h"
2017-08-31 16:28:58 +00:00
# include "base/flags.h"
2015-03-02 12:34:16 +00:00
2017-03-04 10:23:56 +00:00
# include <openssl/evp.h>
2016-09-15 19:15:49 +00:00
namespace Local {
2014-11-22 09:45:04 +00:00
namespace {
2016-10-28 12:44:28 +00:00
constexpr int kThemeFileSizeLimit = 5 * 1024 * 1024 ;
2016-09-16 12:49:36 +00:00
using FileKey = quint64 ;
2014-11-22 09:45:04 +00:00
2016-10-28 12:44:28 +00:00
constexpr char tdfMagic [ ] = { ' T ' , ' D ' , ' F ' , ' $ ' } ;
constexpr int tdfMagicLen = sizeof ( tdfMagic ) ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
QString toFilePart ( FileKey val ) {
QString result ;
result . reserve ( 0x10 ) ;
for ( int32 i = 0 ; i < 0x10 ; + + i ) {
uchar v = ( val & 0x0F ) ;
result . push_back ( ( v < 0x0A ) ? ( ' 0 ' + v ) : ( ' A ' + ( v - 0x0A ) ) ) ;
val > > = 4 ;
}
return result ;
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
QString _basePath , _userBasePath ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
bool _started = false ;
internal : : Manager * _manager = nullptr ;
TaskQueue * _localLoader = nullptr ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
bool _working ( ) {
return _manager & & ! _basePath . isEmpty ( ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
bool _userWorking ( ) {
return _manager & & ! _basePath . isEmpty ( ) & & ! _userBasePath . isEmpty ( ) ;
}
2015-03-02 12:34:16 +00:00
2016-10-28 12:44:28 +00:00
enum class FileOption {
2017-09-03 18:36:06 +00:00
User = ( 1 < < 0 ) ,
Safe = ( 1 < < 1 ) ,
2016-09-15 19:15:49 +00:00
} ;
2017-08-31 16:28:58 +00:00
using FileOptions = base : : flags < FileOption > ;
inline constexpr auto is_flag_type ( FileOption ) { return true ; } ;
2016-09-15 19:15:49 +00:00
2016-10-28 12:44:28 +00:00
bool keyAlreadyUsed ( QString & name , FileOptions options = FileOption : : User | FileOption : : Safe ) {
2016-09-15 19:15:49 +00:00
name + = ' 0 ' ;
if ( QFileInfo ( name ) . exists ( ) ) return true ;
2016-10-28 12:44:28 +00:00
if ( options & ( FileOption : : Safe ) ) {
2016-09-15 19:15:49 +00:00
name [ name . size ( ) - 1 ] = ' 1 ' ;
return QFileInfo ( name ) . exists ( ) ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
return false ;
}
2014-11-22 09:45:04 +00:00
2016-10-28 12:44:28 +00:00
FileKey genKey ( FileOptions options = FileOption : : User | FileOption : : Safe ) {
if ( options & FileOption : : User ) {
2016-09-15 19:15:49 +00:00
if ( ! _userWorking ( ) ) return 0 ;
} else {
if ( ! _working ( ) ) return 0 ;
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
FileKey result ;
2016-10-28 12:44:28 +00:00
QString base = ( options & FileOption : : User ) ? _userBasePath : _basePath , path ;
2016-09-15 19:15:49 +00:00
path . reserve ( base . size ( ) + 0x11 ) ;
path + = base ;
do {
result = rand_value < FileKey > ( ) ;
path . resize ( base . size ( ) ) ;
path + = toFilePart ( result ) ;
} while ( ! result | | keyAlreadyUsed ( path , options ) ) ;
return result ;
}
2014-11-22 09:45:04 +00:00
2016-10-28 12:44:28 +00:00
void clearKey ( const FileKey & key , FileOptions options = FileOption : : User | FileOption : : Safe ) {
if ( options & FileOption : : User ) {
2016-09-15 19:15:49 +00:00
if ( ! _userWorking ( ) ) return ;
} else {
if ( ! _working ( ) ) return ;
2014-11-22 09:45:04 +00:00
}
2016-10-28 12:44:28 +00:00
QString base = ( options & FileOption : : User ) ? _userBasePath : _basePath , name ;
2016-09-15 19:15:49 +00:00
name . reserve ( base . size ( ) + 0x11 ) ;
name . append ( base ) . append ( toFilePart ( key ) ) . append ( ' 0 ' ) ;
QFile : : remove ( name ) ;
2016-10-28 12:44:28 +00:00
if ( options & FileOption : : Safe ) {
2016-09-15 19:15:49 +00:00
name [ name . size ( ) - 1 ] = ' 1 ' ;
2014-11-22 09:45:04 +00:00
QFile : : remove ( name ) ;
}
2016-09-15 19:15:49 +00:00
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
bool _checkStreamStatus ( QDataStream & stream ) {
if ( stream . status ( ) ! = QDataStream : : Ok ) {
LOG ( ( " Bad data stream status: %1 " ) . arg ( stream . status ( ) ) ) ;
return false ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
return true ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
QByteArray _settingsSalt , _passKeySalt , _passKeyEncrypted ;
2014-11-22 09:45:04 +00:00
2017-02-22 15:18:26 +00:00
constexpr auto kLocalKeySize = MTP : : AuthKey : : kSize ;
2017-02-25 16:44:02 +00:00
auto OldKey = MTP : : AuthKeyPtr ( ) ;
auto SettingsKey = MTP : : AuthKeyPtr ( ) ;
auto PassKey = MTP : : AuthKeyPtr ( ) ;
auto LocalKey = MTP : : AuthKeyPtr ( ) ;
void createLocalKey ( const QByteArray & pass , QByteArray * salt , MTP : : AuthKeyPtr * result ) {
2017-04-24 12:16:38 +00:00
auto key = MTP : : AuthKey : : Data { { gsl : : byte { } } } ;
2017-02-25 16:44:02 +00:00
auto iterCount = pass . size ( ) ? LocalEncryptIterCount : LocalEncryptNoPwdIterCount ; // dont slow down for no password
auto newSalt = QByteArray ( ) ;
2016-09-15 19:15:49 +00:00
if ( ! salt ) {
newSalt . resize ( LocalEncryptSaltSize ) ;
memset_rand ( newSalt . data ( ) , newSalt . size ( ) ) ;
salt = & newSalt ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
cSetLocalSalt ( newSalt ) ;
2014-11-22 09:45:04 +00:00
}
2017-02-22 15:18:26 +00:00
PKCS5_PBKDF2_HMAC_SHA1 ( pass . constData ( ) , pass . size ( ) , ( uchar * ) salt - > data ( ) , salt - > size ( ) , iterCount , key . size ( ) , ( uchar * ) key . data ( ) ) ;
2014-11-22 09:45:04 +00:00
2017-02-25 16:44:02 +00:00
* result = std : : make_shared < MTP : : AuthKey > ( key ) ;
2016-09-15 19:15:49 +00:00
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
struct FileReadDescriptor {
FileReadDescriptor ( ) : version ( 0 ) {
}
int32 version ;
QByteArray data ;
QBuffer buffer ;
QDataStream stream ;
~ FileReadDescriptor ( ) {
if ( version ) {
stream . setDevice ( 0 ) ;
2014-11-22 09:45:04 +00:00
if ( buffer . isOpen ( ) ) buffer . close ( ) ;
buffer . setBuffer ( 0 ) ;
}
2016-09-15 19:15:49 +00:00
}
} ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
struct EncryptedDescriptor {
EncryptedDescriptor ( ) {
}
EncryptedDescriptor ( uint32 size ) {
uint32 fullSize = sizeof ( uint32 ) + size ;
if ( fullSize & 0x0F ) fullSize + = 0x10 - ( fullSize & 0x0F ) ;
data . reserve ( fullSize ) ;
data . resize ( sizeof ( uint32 ) ) ;
buffer . setBuffer ( & data ) ;
buffer . open ( QIODevice : : WriteOnly ) ;
buffer . seek ( sizeof ( uint32 ) ) ;
stream . setDevice ( & buffer ) ;
stream . setVersion ( QDataStream : : Qt_5_1 ) ;
}
QByteArray data ;
QBuffer buffer ;
QDataStream stream ;
void finish ( ) {
if ( stream . device ( ) ) stream . setDevice ( 0 ) ;
if ( buffer . isOpen ( ) ) buffer . close ( ) ;
buffer . setBuffer ( 0 ) ;
}
~ EncryptedDescriptor ( ) {
finish ( ) ;
}
} ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
struct FileWriteDescriptor {
2016-10-28 12:44:28 +00:00
FileWriteDescriptor ( const FileKey & key , FileOptions options = FileOption : : User | FileOption : : Safe ) {
2016-09-15 19:15:49 +00:00
init ( toFilePart ( key ) , options ) ;
}
2016-10-28 12:44:28 +00:00
FileWriteDescriptor ( const QString & name , FileOptions options = FileOption : : User | FileOption : : Safe ) {
2016-09-15 19:15:49 +00:00
init ( name , options ) ;
}
2016-10-28 12:44:28 +00:00
void init ( const QString & name , FileOptions options ) {
if ( options & FileOption : : User ) {
2016-09-15 19:15:49 +00:00
if ( ! _userWorking ( ) ) return ;
2015-03-02 12:34:16 +00:00
} else {
2016-09-15 19:15:49 +00:00
if ( ! _working ( ) ) return ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
// detect order of read attempts and file version
2014-11-22 09:45:04 +00:00
QString toTry [ 2 ] ;
2016-10-28 12:44:28 +00:00
toTry [ 0 ] = ( ( options & FileOption : : User ) ? _userBasePath : _basePath ) + name + ' 0 ' ;
if ( options & FileOption : : Safe ) {
toTry [ 1 ] = ( ( options & FileOption : : User ) ? _userBasePath : _basePath ) + name + ' 1 ' ;
2014-11-22 09:45:04 +00:00
QFileInfo toTry0 ( toTry [ 0 ] ) ;
2016-09-15 19:15:49 +00:00
QFileInfo toTry1 ( toTry [ 1 ] ) ;
2014-11-22 09:45:04 +00:00
if ( toTry0 . exists ( ) ) {
if ( toTry1 . exists ( ) ) {
QDateTime mod0 = toTry0 . lastModified ( ) , mod1 = toTry1 . lastModified ( ) ;
2016-09-15 19:15:49 +00:00
if ( mod0 > mod1 ) {
2014-11-22 09:45:04 +00:00
qSwap ( toTry [ 0 ] , toTry [ 1 ] ) ;
}
} else {
2016-09-15 19:15:49 +00:00
qSwap ( toTry [ 0 ] , toTry [ 1 ] ) ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
toDelete = toTry [ 1 ] ;
} else if ( toTry1 . exists ( ) ) {
toDelete = toTry [ 1 ] ;
2014-11-22 09:45:04 +00:00
}
}
2016-09-15 19:15:49 +00:00
file . setFileName ( toTry [ 0 ] ) ;
if ( file . open ( QIODevice : : WriteOnly ) ) {
file . write ( tdfMagic , tdfMagicLen ) ;
qint32 version = AppVersion ;
file . write ( ( const char * ) & version , sizeof ( version ) ) ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
stream . setDevice ( & file ) ;
stream . setVersion ( QDataStream : : Qt_5_1 ) ;
}
}
bool writeData ( const QByteArray & data ) {
if ( ! file . isOpen ( ) ) return false ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
stream < < data ;
quint32 len = data . isNull ( ) ? 0xffffffff : data . size ( ) ;
if ( QSysInfo : : ByteOrder ! = QSysInfo : : BigEndian ) {
len = qbswap ( len ) ;
}
md5 . feed ( & len , sizeof ( len ) ) ;
md5 . feed ( data . constData ( ) , data . size ( ) ) ;
dataSize + = sizeof ( len ) + data . size ( ) ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
return true ;
}
2017-02-25 16:44:02 +00:00
static QByteArray prepareEncrypted ( EncryptedDescriptor & data , const MTP : : AuthKeyPtr & key = LocalKey ) {
2016-09-15 19:15:49 +00:00
data . finish ( ) ;
QByteArray & toEncrypt ( data . data ) ;
// prepare for encryption
uint32 size = toEncrypt . size ( ) , fullSize = size ;
if ( fullSize & 0x0F ) {
fullSize + = 0x10 - ( fullSize & 0x0F ) ;
toEncrypt . resize ( fullSize ) ;
memset_rand ( toEncrypt . data ( ) + size , fullSize - size ) ;
}
* ( uint32 * ) toEncrypt . data ( ) = size ;
QByteArray encrypted ( 0x10 + fullSize , Qt : : Uninitialized ) ; // 128bit of sha1 - key128, sizeof(data), data
hashSha1 ( toEncrypt . constData ( ) , toEncrypt . size ( ) , encrypted . data ( ) ) ;
2017-02-25 16:44:02 +00:00
MTP : : aesEncryptLocal ( toEncrypt . constData ( ) , encrypted . data ( ) + 0x10 , fullSize , key , encrypted . constData ( ) ) ;
2016-09-15 19:15:49 +00:00
return encrypted ;
}
2017-02-25 16:44:02 +00:00
bool writeEncrypted ( EncryptedDescriptor & data , const MTP : : AuthKeyPtr & key = LocalKey ) {
2016-09-15 19:15:49 +00:00
return writeData ( prepareEncrypted ( data , key ) ) ;
}
void finish ( ) {
if ( ! file . isOpen ( ) ) return ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
stream . setDevice ( 0 ) ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
md5 . feed ( & dataSize , sizeof ( dataSize ) ) ;
qint32 version = AppVersion ;
md5 . feed ( & version , sizeof ( version ) ) ;
md5 . feed ( tdfMagic , tdfMagicLen ) ;
file . write ( ( const char * ) md5 . result ( ) , 0x10 ) ;
file . close ( ) ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
if ( ! toDelete . isEmpty ( ) ) {
QFile : : remove ( toDelete ) ;
}
}
QFile file ;
QDataStream stream ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
QString toDelete ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
HashMd5 md5 ;
2016-10-28 12:44:28 +00:00
int32 dataSize = 0 ;
2016-09-15 19:15:49 +00:00
~ FileWriteDescriptor ( ) {
finish ( ) ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
} ;
2014-11-22 09:45:04 +00:00
2016-10-28 12:44:28 +00:00
bool readFile ( FileReadDescriptor & result , const QString & name , FileOptions options = FileOption : : User | FileOption : : Safe ) {
if ( options & FileOption : : User ) {
2016-09-15 19:15:49 +00:00
if ( ! _userWorking ( ) ) return false ;
} else {
if ( ! _working ( ) ) return false ;
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
// detect order of read attempts
QString toTry [ 2 ] ;
2016-10-28 12:44:28 +00:00
toTry [ 0 ] = ( ( options & FileOption : : User ) ? _userBasePath : _basePath ) + name + ' 0 ' ;
if ( options & FileOption : : Safe ) {
2016-09-15 19:15:49 +00:00
QFileInfo toTry0 ( toTry [ 0 ] ) ;
if ( toTry0 . exists ( ) ) {
2016-10-28 12:44:28 +00:00
toTry [ 1 ] = ( ( options & FileOption : : User ) ? _userBasePath : _basePath ) + name + ' 1 ' ;
2016-09-15 19:15:49 +00:00
QFileInfo toTry1 ( toTry [ 1 ] ) ;
if ( toTry1 . exists ( ) ) {
QDateTime mod0 = toTry0 . lastModified ( ) , mod1 = toTry1 . lastModified ( ) ;
if ( mod0 < mod1 ) {
qSwap ( toTry [ 0 ] , toTry [ 1 ] ) ;
}
} else {
toTry [ 1 ] = QString ( ) ;
}
} else {
toTry [ 0 ] [ toTry [ 0 ] . size ( ) - 1 ] = ' 1 ' ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
}
for ( int32 i = 0 ; i < 2 ; + + i ) {
QString fname ( toTry [ i ] ) ;
if ( fname . isEmpty ( ) ) break ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
QFile f ( fname ) ;
if ( ! f . open ( QIODevice : : ReadOnly ) ) {
DEBUG_LOG ( ( " App Info: failed to open '%1' for reading " ) . arg ( name ) ) ;
continue ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
// check magic
char magic [ tdfMagicLen ] ;
if ( f . read ( magic , tdfMagicLen ) ! = tdfMagicLen ) {
DEBUG_LOG ( ( " App Info: failed to read magic from '%1' " ) . arg ( name ) ) ;
continue ;
}
if ( memcmp ( magic , tdfMagic , tdfMagicLen ) ) {
DEBUG_LOG ( ( " App Info: bad magic %1 in '%2' " ) . arg ( Logs : : mb ( magic , tdfMagicLen ) . str ( ) ) . arg ( name ) ) ;
continue ;
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
// read app version
qint32 version ;
if ( f . read ( ( char * ) & version , sizeof ( version ) ) ! = sizeof ( version ) ) {
DEBUG_LOG ( ( " App Info: failed to read version from '%1' " ) . arg ( name ) ) ;
continue ;
}
if ( version > AppVersion ) {
DEBUG_LOG ( ( " App Info: version too big %1 for '%2', my version %3 " ) . arg ( version ) . arg ( name ) . arg ( AppVersion ) ) ;
continue ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
// read data
QByteArray bytes = f . read ( f . size ( ) ) ;
int32 dataSize = bytes . size ( ) - 16 ;
if ( dataSize < 0 ) {
DEBUG_LOG ( ( " App Info: bad file '%1', could not read sign part " ) . arg ( name ) ) ;
continue ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
// check signature
HashMd5 md5 ;
md5 . feed ( bytes . constData ( ) , dataSize ) ;
md5 . feed ( & dataSize , sizeof ( dataSize ) ) ;
md5 . feed ( & version , sizeof ( version ) ) ;
md5 . feed ( magic , tdfMagicLen ) ;
if ( memcmp ( md5 . result ( ) , bytes . constData ( ) + dataSize , 16 ) ) {
DEBUG_LOG ( ( " App Info: bad file '%1', signature did not match " ) . arg ( name ) ) ;
continue ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
bytes . resize ( dataSize ) ;
result . data = bytes ;
bytes = QByteArray ( ) ;
result . version = version ;
2014-11-22 09:45:04 +00:00
result . buffer . setBuffer ( & result . data ) ;
result . buffer . open ( QIODevice : : ReadOnly ) ;
result . stream . setDevice ( & result . buffer ) ;
result . stream . setVersion ( QDataStream : : Qt_5_1 ) ;
2016-09-15 19:15:49 +00:00
if ( ( i = = 0 & & ! toTry [ 1 ] . isEmpty ( ) ) | | i = = 1 ) {
QFile : : remove ( toTry [ 1 - i ] ) ;
}
2014-11-22 09:45:04 +00:00
return true ;
}
2016-09-15 19:15:49 +00:00
return false ;
}
2014-11-22 09:45:04 +00:00
2017-02-25 16:44:02 +00:00
bool decryptLocal ( EncryptedDescriptor & result , const QByteArray & encrypted , const MTP : : AuthKeyPtr & key = LocalKey ) {
2016-09-15 19:15:49 +00:00
if ( encrypted . size ( ) < = 16 | | ( encrypted . size ( ) & 0x0F ) ) {
LOG ( ( " App Error: bad encrypted part size: %1 " ) . arg ( encrypted . size ( ) ) ) ;
return false ;
}
uint32 fullLen = encrypted . size ( ) - 16 ;
QByteArray decrypted ;
decrypted . resize ( fullLen ) ;
const char * encryptedKey = encrypted . constData ( ) , * encryptedData = encrypted . constData ( ) + 16 ;
2017-02-25 16:44:02 +00:00
aesDecryptLocal ( encryptedData , decrypted . data ( ) , fullLen , key , encryptedKey ) ;
2016-09-15 19:15:49 +00:00
uchar sha1Buffer [ 20 ] ;
if ( memcmp ( hashSha1 ( decrypted . constData ( ) , decrypted . size ( ) , sha1Buffer ) , encryptedKey , 16 ) ) {
LOG ( ( " App Info: bad decrypt key, data not decrypted - incorrect password? " ) ) ;
return false ;
}
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
uint32 dataLen = * ( const uint32 * ) decrypted . constData ( ) ;
if ( dataLen > uint32 ( decrypted . size ( ) ) | | dataLen < = fullLen - 16 | | dataLen < sizeof ( uint32 ) ) {
LOG ( ( " App Error: bad decrypted part size: %1, fullLen: %2, decrypted size: %3 " ) . arg ( dataLen ) . arg ( fullLen ) . arg ( decrypted . size ( ) ) ) ;
return false ;
}
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
decrypted . resize ( dataLen ) ;
result . data = decrypted ;
decrypted = QByteArray ( ) ;
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
result . buffer . setBuffer ( & result . data ) ;
result . buffer . open ( QIODevice : : ReadOnly ) ;
result . buffer . seek ( sizeof ( uint32 ) ) ; // skip len
result . stream . setDevice ( & result . buffer ) ;
result . stream . setVersion ( QDataStream : : Qt_5_1 ) ;
2015-01-02 14:55:24 +00:00
2016-09-15 19:15:49 +00:00
return true ;
}
2015-03-02 12:34:16 +00:00
2017-02-25 16:44:02 +00:00
bool readEncryptedFile ( FileReadDescriptor & result , const QString & name , FileOptions options = FileOption : : User | FileOption : : Safe , const MTP : : AuthKeyPtr & key = LocalKey ) {
2016-09-15 19:15:49 +00:00
if ( ! readFile ( result , name , options ) ) {
return false ;
}
QByteArray encrypted ;
result . stream > > encrypted ;
2015-08-07 12:11:50 +00:00
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ;
if ( ! decryptLocal ( data , encrypted , key ) ) {
result . stream . setDevice ( 0 ) ;
if ( result . buffer . isOpen ( ) ) result . buffer . close ( ) ;
result . buffer . setBuffer ( 0 ) ;
result . data = QByteArray ( ) ;
result . version = 0 ;
return false ;
}
2014-12-05 13:44:27 +00:00
2016-09-15 19:15:49 +00:00
result . stream . setDevice ( 0 ) ;
if ( result . buffer . isOpen ( ) ) result . buffer . close ( ) ;
result . buffer . setBuffer ( 0 ) ;
result . data = data . data ;
result . buffer . setBuffer ( & result . data ) ;
result . buffer . open ( QIODevice : : ReadOnly ) ;
result . buffer . seek ( data . buffer . pos ( ) ) ;
result . stream . setDevice ( & result . buffer ) ;
result . stream . setVersion ( QDataStream : : Qt_5_1 ) ;
return true ;
}
2014-12-05 13:44:27 +00:00
2017-02-25 16:44:02 +00:00
bool readEncryptedFile ( FileReadDescriptor & result , const FileKey & fkey , FileOptions options = FileOption : : User | FileOption : : Safe , const MTP : : AuthKeyPtr & key = LocalKey ) {
2016-09-15 19:15:49 +00:00
return readEncryptedFile ( result , toFilePart ( fkey ) , options , key ) ;
}
2014-12-05 13:44:27 +00:00
2016-09-15 19:15:49 +00:00
FileKey _dataNameKey = 0 ;
enum { // Local Storage Keys
lskUserMap = 0x00 ,
lskDraft = 0x01 , // data: PeerId peer
lskDraftPosition = 0x02 , // data: PeerId peer
lskImages = 0x03 , // data: StorageKey location
lskLocations = 0x04 , // no data
lskStickerImages = 0x05 , // data: StorageKey location
lskAudios = 0x06 , // data: StorageKey location
lskRecentStickersOld = 0x07 , // no data
lskBackground = 0x08 , // no data
lskUserSettings = 0x09 , // no data
lskRecentHashtagsAndBots = 0x0a , // no data
lskStickersOld = 0x0b , // no data
lskSavedPeers = 0x0c , // no data
lskReportSpamStatuses = 0x0d , // no data
lskSavedGifsOld = 0x0e , // no data
lskSavedGifs = 0x0f , // no data
lskStickersKeys = 0x10 , // no data
lskTrustedBots = 0x11 , // no data
2017-08-02 15:07:28 +00:00
lskFavedStickers = 0x12 , // no data
2016-09-15 19:15:49 +00:00
} ;
enum {
dbiKey = 0x00 ,
dbiUser = 0x01 ,
2017-02-24 17:15:41 +00:00
dbiDcOptionOldOld = 0x02 ,
2016-09-15 19:15:49 +00:00
dbiChatSizeMax = 0x03 ,
dbiMutePeer = 0x04 ,
dbiSendKey = 0x05 ,
dbiAutoStart = 0x06 ,
dbiStartMinimized = 0x07 ,
dbiSoundNotify = 0x08 ,
dbiWorkMode = 0x09 ,
dbiSeenTrayTooltip = 0x0a ,
dbiDesktopNotify = 0x0b ,
dbiAutoUpdate = 0x0c ,
dbiLastUpdateCheck = 0x0d ,
dbiWindowPosition = 0x0e ,
2017-06-27 22:03:37 +00:00
dbiConnectionTypeOld = 0x0f ,
2016-09-15 19:15:49 +00:00
// 0x10 reserved
dbiDefaultAttach = 0x11 ,
dbiCatsAndDogs = 0x12 ,
dbiReplaceEmojis = 0x13 ,
dbiAskDownloadPath = 0x14 ,
dbiDownloadPathOld = 0x15 ,
dbiScale = 0x16 ,
dbiEmojiTabOld = 0x17 ,
2017-02-15 08:50:11 +00:00
dbiRecentEmojiOldOld = 0x18 ,
2016-09-15 19:15:49 +00:00
dbiLoggedPhoneNumber = 0x19 ,
dbiMutedPeers = 0x1a ,
// 0x1b reserved
dbiNotifyView = 0x1c ,
dbiSendToMenu = 0x1d ,
dbiCompressPastedImage = 0x1e ,
2017-04-13 17:59:05 +00:00
dbiLangOld = 0x1f ,
dbiLangFileOld = 0x20 ,
2016-09-15 19:15:49 +00:00
dbiTileBackground = 0x21 ,
dbiAutoLock = 0x22 ,
dbiDialogLastPath = 0x23 ,
2017-02-15 08:50:11 +00:00
dbiRecentEmojiOld = 0x24 ,
dbiEmojiVariantsOld = 0x25 ,
2016-09-15 19:15:49 +00:00
dbiRecentStickers = 0x26 ,
2017-02-24 17:15:41 +00:00
dbiDcOptionOld = 0x27 ,
2016-09-15 19:15:49 +00:00
dbiTryIPv6 = 0x28 ,
dbiSongVolume = 0x29 ,
2016-10-03 15:07:50 +00:00
dbiWindowsNotificationsOld = 0x30 ,
2016-09-15 19:15:49 +00:00
dbiIncludeMuted = 0x31 ,
dbiMegagroupSizeMax = 0x32 ,
dbiDownloadPath = 0x33 ,
dbiAutoDownload = 0x34 ,
dbiSavedGifsLimit = 0x35 ,
2017-03-28 12:30:38 +00:00
dbiShowingSavedGifsOld = 0x36 ,
2016-09-15 19:15:49 +00:00
dbiAutoPlay = 0x37 ,
dbiAdaptiveForWide = 0x38 ,
dbiHiddenPinnedMessages = 0x39 ,
2017-02-15 08:50:11 +00:00
dbiRecentEmoji = 0x3a ,
dbiEmojiVariants = 0x3b ,
2016-09-15 19:15:49 +00:00
dbiDialogsMode = 0x40 ,
dbiModerateMode = 0x41 ,
dbiVideoVolume = 0x42 ,
dbiStickersRecentLimit = 0x43 ,
2016-10-03 15:07:50 +00:00
dbiNativeNotifications = 0x44 ,
2016-10-06 16:41:09 +00:00
dbiNotificationsCount = 0x45 ,
dbiNotificationsCorner = 0x46 ,
2017-04-13 17:59:05 +00:00
dbiThemeKey = 0x47 ,
2017-11-05 13:57:51 +00:00
dbiDialogsWidthRatioOld = 0x48 ,
2017-02-17 12:50:27 +00:00
dbiUseExternalVideoPlayer = 0x49 ,
2017-02-23 06:57:04 +00:00
dbiDcOptions = 0x4a ,
2017-02-24 17:15:41 +00:00
dbiMtpAuthorization = 0x4b ,
2017-03-28 12:30:38 +00:00
dbiLastSeenWarningSeenOld = 0x4c ,
dbiAuthSessionData = 0x4d ,
2017-04-13 17:59:05 +00:00
dbiLangPackKey = 0x4e ,
2017-06-27 22:03:37 +00:00
dbiConnectionType = 0x4f ,
2017-08-02 15:07:28 +00:00
dbiStickersFavedLimit = 0x50 ,
2016-09-15 19:15:49 +00:00
dbiEncryptedWithSalt = 333 ,
dbiEncrypted = 444 ,
// 500-600 reserved
dbiVersion = 666 ,
} ;
typedef QMap < PeerId , FileKey > DraftsMap ;
DraftsMap _draftsMap , _draftCursorsMap ;
typedef QMap < PeerId , bool > DraftsNotReadMap ;
DraftsNotReadMap _draftsNotReadMap ;
typedef QPair < FileKey , qint32 > FileDesc ; // file, size
typedef QMultiMap < MediaKey , FileLocation > FileLocations ;
FileLocations _fileLocations ;
typedef QPair < MediaKey , FileLocation > FileLocationPair ;
typedef QMap < QString , FileLocationPair > FileLocationPairs ;
FileLocationPairs _fileLocationPairs ;
typedef QMap < MediaKey , MediaKey > FileLocationAliases ;
FileLocationAliases _fileLocationAliases ;
typedef QMap < QString , FileDesc > WebFilesMap ;
WebFilesMap _webFilesMap ;
uint64 _storageWebFilesSize = 0 ;
FileKey _locationsKey = 0 , _reportSpamStatusesKey = 0 , _trustedBotsKey = 0 ;
using TrustedBots = OrderedSet < uint64 > ;
TrustedBots _trustedBots ;
bool _trustedBotsRead = false ;
FileKey _recentStickersKeyOld = 0 ;
2017-08-02 15:07:28 +00:00
FileKey _installedStickersKey = 0 , _featuredStickersKey = 0 , _recentStickersKey = 0 , _favedStickersKey = 0 , _archivedStickersKey = 0 ;
2016-09-15 19:15:49 +00:00
FileKey _savedGifsKey = 0 ;
FileKey _backgroundKey = 0 ;
bool _backgroundWasRead = false ;
2016-10-28 12:44:28 +00:00
bool _backgroundCanWrite = true ;
2016-11-01 20:59:51 +00:00
FileKey _themeKey = 0 ;
2017-06-29 19:09:10 +00:00
QString _themeAbsolutePath ;
2017-02-03 20:07:26 +00:00
QString _themePaletteAbsolutePath ;
2016-09-15 19:15:49 +00:00
bool _readingUserSettings = false ;
FileKey _userSettingsKey = 0 ;
FileKey _recentHashtagsAndBotsKey = 0 ;
bool _recentHashtagsAndBotsWereRead = false ;
FileKey _savedPeersKey = 0 ;
2017-04-13 17:59:05 +00:00
FileKey _langPackKey = 0 ;
2016-09-15 19:15:49 +00:00
typedef QMap < StorageKey , FileDesc > StorageMap ;
StorageMap _imagesMap , _stickerImagesMap , _audiosMap ;
2017-12-03 16:51:19 +00:00
qint64 _storageImagesSize = 0 , _storageStickersSize = 0 , _storageAudiosSize = 0 ;
2016-09-15 19:15:49 +00:00
bool _mapChanged = false ;
int32 _oldMapVersion = 0 , _oldSettingsVersion = 0 ;
2017-03-28 12:30:38 +00:00
enum class WriteMapWhen {
Now ,
Fast ,
Soon ,
2016-09-15 19:15:49 +00:00
} ;
2017-11-05 13:57:51 +00:00
std : : unique_ptr < AuthSessionData > StoredAuthSessionCache ;
AuthSessionData & GetStoredAuthSessionCache ( ) {
2017-04-09 18:06:06 +00:00
if ( ! StoredAuthSessionCache ) {
2017-11-05 13:57:51 +00:00
StoredAuthSessionCache = std : : make_unique < AuthSessionData > ( ) ;
2017-03-28 12:30:38 +00:00
}
2017-04-09 18:06:06 +00:00
return * StoredAuthSessionCache ;
2017-03-28 12:30:38 +00:00
}
void _writeMap ( WriteMapWhen when = WriteMapWhen : : Soon ) ;
2016-09-15 19:15:49 +00:00
2017-03-28 12:30:38 +00:00
void _writeLocations ( WriteMapWhen when = WriteMapWhen : : Soon ) {
if ( when ! = WriteMapWhen : : Now ) {
_manager - > writeLocations ( when = = WriteMapWhen : : Fast ) ;
2016-09-15 19:15:49 +00:00
return ;
}
if ( ! _working ( ) ) return ;
2015-09-09 08:19:25 +00:00
2016-09-15 19:15:49 +00:00
_manager - > writingLocations ( ) ;
if ( _fileLocations . isEmpty ( ) & & _webFilesMap . isEmpty ( ) ) {
if ( _locationsKey ) {
clearKey ( _locationsKey ) ;
_locationsKey = 0 ;
_mapChanged = true ;
_writeMap ( ) ;
2014-12-05 13:44:27 +00:00
}
2016-09-15 19:15:49 +00:00
} else {
if ( ! _locationsKey ) {
_locationsKey = genKey ( ) ;
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Fast ) ;
2016-09-15 19:15:49 +00:00
}
quint32 size = 0 ;
for ( FileLocations : : const_iterator i = _fileLocations . cbegin ( ) , e = _fileLocations . cend ( ) ; i ! = e ; + + i ) {
// location + type + namelen + name
size + = sizeof ( quint64 ) * 2 + sizeof ( quint32 ) + Serialize : : stringSize ( i . value ( ) . name ( ) ) ;
2015-11-26 17:34:52 +00:00
if ( AppVersion > 9013 ) {
2016-09-15 19:15:49 +00:00
// bookmark
size + = Serialize : : bytearraySize ( i . value ( ) . bookmark ( ) ) ;
2015-11-26 17:34:52 +00:00
}
2016-09-15 19:15:49 +00:00
// date + size
2016-05-05 16:04:17 +00:00
size + = Serialize : : dateTimeSize ( ) + sizeof ( quint32 ) ;
2016-09-15 19:15:49 +00:00
}
2015-11-26 17:34:52 +00:00
2016-09-15 19:15:49 +00:00
//end mark
size + = sizeof ( quint64 ) * 2 + sizeof ( quint32 ) + Serialize : : stringSize ( QString ( ) ) ;
if ( AppVersion > 9013 ) {
size + = Serialize : : bytearraySize ( QByteArray ( ) ) ;
}
size + = Serialize : : dateTimeSize ( ) + sizeof ( quint32 ) ;
2015-06-30 21:07:05 +00:00
2016-09-15 19:15:49 +00:00
size + = sizeof ( quint32 ) ; // aliases count
for ( FileLocationAliases : : const_iterator i = _fileLocationAliases . cbegin ( ) , e = _fileLocationAliases . cend ( ) ; i ! = e ; + + i ) {
// alias + location
size + = sizeof ( quint64 ) * 2 + sizeof ( quint64 ) * 2 ;
}
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
size + = sizeof ( quint32 ) ; // web files count
for ( WebFilesMap : : const_iterator i = _webFilesMap . cbegin ( ) , e = _webFilesMap . cend ( ) ; i ! = e ; + + i ) {
// url + filekey + size
size + = Serialize : : stringSize ( i . key ( ) ) + sizeof ( quint64 ) + sizeof ( qint32 ) ;
}
2015-11-26 17:34:52 +00:00
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ( size ) ;
2017-03-04 11:28:21 +00:00
auto legacyTypeField = 0 ;
2016-09-15 19:15:49 +00:00
for ( FileLocations : : const_iterator i = _fileLocations . cbegin ( ) ; i ! = _fileLocations . cend ( ) ; + + i ) {
2017-03-04 11:28:21 +00:00
data . stream < < quint64 ( i . key ( ) . first ) < < quint64 ( i . key ( ) . second ) < < quint32 ( legacyTypeField ) < < i . value ( ) . name ( ) ;
2015-11-26 17:34:52 +00:00
if ( AppVersion > 9013 ) {
2016-09-15 19:15:49 +00:00
data . stream < < i . value ( ) . bookmark ( ) ;
2015-12-31 15:27:21 +00:00
}
2016-09-15 19:15:49 +00:00
data . stream < < i . value ( ) . modified < < quint32 ( i . value ( ) . size ) ;
}
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
data . stream < < quint64 ( 0 ) < < quint64 ( 0 ) < < quint32 ( 0 ) < < QString ( ) ;
if ( AppVersion > 9013 ) {
data . stream < < QByteArray ( ) ;
2014-12-05 13:44:27 +00:00
}
2016-09-15 19:15:49 +00:00
data . stream < < QDateTime : : currentDateTime ( ) < < quint32 ( 0 ) ;
2014-12-05 13:44:27 +00:00
2016-09-15 19:15:49 +00:00
data . stream < < quint32 ( _fileLocationAliases . size ( ) ) ;
for ( FileLocationAliases : : const_iterator i = _fileLocationAliases . cbegin ( ) , e = _fileLocationAliases . cend ( ) ; i ! = e ; + + i ) {
data . stream < < quint64 ( i . key ( ) . first ) < < quint64 ( i . key ( ) . second ) < < quint64 ( i . value ( ) . first ) < < quint64 ( i . value ( ) . second ) ;
2014-12-05 13:44:27 +00:00
}
2016-09-15 19:15:49 +00:00
data . stream < < quint32 ( _webFilesMap . size ( ) ) ;
for ( WebFilesMap : : const_iterator i = _webFilesMap . cbegin ( ) , e = _webFilesMap . cend ( ) ; i ! = e ; + + i ) {
data . stream < < i . key ( ) < < quint64 ( i . value ( ) . first ) < < qint32 ( i . value ( ) . second ) ;
}
2014-12-05 13:44:27 +00:00
2016-09-15 19:15:49 +00:00
FileWriteDescriptor file ( _locationsKey ) ;
file . writeEncrypted ( data ) ;
}
}
2015-06-30 21:07:05 +00:00
2016-09-15 19:15:49 +00:00
void _readLocations ( ) {
FileReadDescriptor locations ;
if ( ! readEncryptedFile ( locations , _locationsKey ) ) {
clearKey ( _locationsKey ) ;
_locationsKey = 0 ;
_writeMap ( ) ;
return ;
}
2014-12-05 13:44:27 +00:00
2016-09-15 19:15:49 +00:00
bool endMarkFound = false ;
while ( ! locations . stream . atEnd ( ) ) {
quint64 first , second ;
QByteArray bookmark ;
FileLocation loc ;
2017-03-04 11:28:21 +00:00
quint32 legacyTypeField = 0 ;
locations . stream > > first > > second > > legacyTypeField > > loc . fname ;
2016-09-15 19:15:49 +00:00
if ( locations . version > 9013 ) {
locations . stream > > bookmark ;
}
locations . stream > > loc . modified > > loc . size ;
loc . setBookmark ( bookmark ) ;
2017-03-04 11:28:21 +00:00
if ( ! first & & ! second & & ! legacyTypeField & & loc . fname . isEmpty ( ) & & ! loc . size ) { // end mark
2016-09-15 19:15:49 +00:00
endMarkFound = true ;
break ;
2014-12-05 13:44:27 +00:00
}
2015-06-30 21:07:05 +00:00
2016-09-15 19:15:49 +00:00
MediaKey key ( first , second ) ;
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
_fileLocations . insert ( key , loc ) ;
_fileLocationPairs . insert ( loc . fname , FileLocationPair ( key , loc ) ) ;
2014-12-05 13:44:27 +00:00
}
2016-09-15 19:15:49 +00:00
if ( endMarkFound ) {
quint32 cnt ;
locations . stream > > cnt ;
for ( quint32 i = 0 ; i < cnt ; + + i ) {
quint64 kfirst , ksecond , vfirst , vsecond ;
locations . stream > > kfirst > > ksecond > > vfirst > > vsecond ;
_fileLocationAliases . insert ( MediaKey ( kfirst , ksecond ) , MediaKey ( vfirst , vsecond ) ) ;
}
2015-09-09 08:19:25 +00:00
2016-09-15 19:15:49 +00:00
if ( ! locations . stream . atEnd ( ) ) {
_storageWebFilesSize = 0 ;
_webFilesMap . clear ( ) ;
2015-09-09 08:19:25 +00:00
2016-09-15 19:15:49 +00:00
quint32 webLocationsCount ;
locations . stream > > webLocationsCount ;
for ( quint32 i = 0 ; i < webLocationsCount ; + + i ) {
QString url ;
quint64 key ;
qint32 size ;
locations . stream > > url > > key > > size ;
_webFilesMap . insert ( url , FileDesc ( key , size ) ) ;
_storageWebFilesSize + = size ;
2015-09-09 08:19:25 +00:00
}
}
}
2016-09-15 19:15:49 +00:00
}
2015-09-09 08:19:25 +00:00
2016-09-15 19:15:49 +00:00
void _writeReportSpamStatuses ( ) {
if ( ! _working ( ) ) return ;
if ( cReportSpamStatuses ( ) . isEmpty ( ) ) {
if ( _reportSpamStatusesKey ) {
2015-09-09 08:19:25 +00:00
clearKey ( _reportSpamStatusesKey ) ;
_reportSpamStatusesKey = 0 ;
2016-09-15 19:15:49 +00:00
_mapChanged = true ;
2015-09-09 08:19:25 +00:00
_writeMap ( ) ;
}
2016-09-15 19:15:49 +00:00
} else {
if ( ! _reportSpamStatusesKey ) {
_reportSpamStatusesKey = genKey ( ) ;
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Fast ) ;
2016-09-15 19:15:49 +00:00
}
const ReportSpamStatuses & statuses ( cReportSpamStatuses ( ) ) ;
2015-09-09 08:19:25 +00:00
2016-09-15 19:15:49 +00:00
quint32 size = sizeof ( qint32 ) ;
for ( ReportSpamStatuses : : const_iterator i = statuses . cbegin ( ) , e = statuses . cend ( ) ; i ! = e ; + + i ) {
// peer + status
size + = sizeof ( quint64 ) + sizeof ( qint32 ) ;
}
2015-09-09 08:19:25 +00:00
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ( size ) ;
data . stream < < qint32 ( statuses . size ( ) ) ;
for ( ReportSpamStatuses : : const_iterator i = statuses . cbegin ( ) , e = statuses . cend ( ) ; i ! = e ; + + i ) {
data . stream < < quint64 ( i . key ( ) ) < < qint32 ( i . value ( ) ) ;
2015-09-09 08:19:25 +00:00
}
2016-09-15 19:15:49 +00:00
FileWriteDescriptor file ( _reportSpamStatusesKey ) ;
file . writeEncrypted ( data ) ;
2015-09-09 08:19:25 +00:00
}
2016-09-15 19:15:49 +00:00
}
2015-09-09 08:19:25 +00:00
2016-09-15 19:15:49 +00:00
void _readReportSpamStatuses ( ) {
FileReadDescriptor statuses ;
if ( ! readEncryptedFile ( statuses , _reportSpamStatusesKey ) ) {
clearKey ( _reportSpamStatusesKey ) ;
_reportSpamStatusesKey = 0 ;
_writeMap ( ) ;
return ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
ReportSpamStatuses & map ( cRefReportSpamStatuses ( ) ) ;
map . clear ( ) ;
2015-06-10 12:48:26 +00:00
2016-09-15 19:15:49 +00:00
qint32 size = 0 ;
statuses . stream > > size ;
for ( int32 i = 0 ; i < size ; + + i ) {
quint64 peer = 0 ;
qint32 status = 0 ;
statuses . stream > > peer > > status ;
map . insert ( peer , DBIPeerReportSpamStatus ( status ) ) ;
}
}
2015-12-27 21:37:48 +00:00
2017-02-23 06:57:04 +00:00
struct ReadSettingsContext {
2017-04-13 17:59:05 +00:00
int legacyLanguageId = Lang : : kLegacyLanguageNone ;
QString legacyLanguageFile ;
2017-02-23 06:57:04 +00:00
MTP : : DcOptions dcOptions ;
} ;
2017-03-23 16:11:35 +00:00
void applyReadContext ( ReadSettingsContext & & context ) {
Messenger : : Instance ( ) . dcOptions ( ) - > addFromOther ( std : : move ( context . dcOptions ) ) ;
2017-04-13 17:59:05 +00:00
if ( context . legacyLanguageId ! = Lang : : kLegacyLanguageNone ) {
Lang : : Current ( ) . fillFromLegacy ( context . legacyLanguageId , context . legacyLanguageFile ) ;
writeLangPack ( ) ;
}
2017-02-23 06:57:04 +00:00
}
bool _readSetting ( quint32 blockId , QDataStream & stream , int version , ReadSettingsContext & context ) {
2016-09-15 19:15:49 +00:00
switch ( blockId ) {
2017-02-24 17:15:41 +00:00
case dbiDcOptionOldOld : {
2016-09-15 19:15:49 +00:00
quint32 dcId , port ;
QString host , ip ;
stream > > dcId > > host > > ip > > port ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-02-23 06:57:04 +00:00
context . dcOptions . constructAddOne ( dcId , 0 , ip . toStdString ( ) , port ) ;
2016-09-15 19:15:49 +00:00
} break ;
2017-02-24 17:15:41 +00:00
case dbiDcOptionOld : {
2016-09-15 19:15:49 +00:00
quint32 dcIdWithShift , port ;
qint32 flags ;
QString ip ;
stream > > dcIdWithShift > > flags > > ip > > port ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-09-26 11:49:16 +00:00
context . dcOptions . constructAddOne ( dcIdWithShift , MTPDdcOption : : Flags : : from_raw ( flags ) , ip . toStdString ( ) , port ) ;
2017-02-23 06:57:04 +00:00
} break ;
case dbiDcOptions : {
2017-02-24 17:15:41 +00:00
auto serialized = QByteArray ( ) ;
2017-02-23 06:57:04 +00:00
stream > > serialized ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
context . dcOptions . constructFromSerialized ( serialized ) ;
2016-09-15 19:15:49 +00:00
} break ;
case dbiChatSizeMax : {
qint32 maxSize ;
stream > > maxSize ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetChatSizeMax ( maxSize ) ;
} break ;
case dbiSavedGifsLimit : {
qint32 limit ;
stream > > limit ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetSavedGifsLimit ( limit ) ;
} break ;
case dbiStickersRecentLimit : {
qint32 limit ;
stream > > limit ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetStickersRecentLimit ( limit ) ;
} break ;
2017-08-02 15:07:28 +00:00
case dbiStickersFavedLimit : {
qint32 limit ;
stream > > limit ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetStickersFavedLimit ( limit ) ;
} break ;
2016-09-15 19:15:49 +00:00
case dbiMegagroupSizeMax : {
qint32 maxSize ;
stream > > maxSize ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetMegagroupSizeMax ( maxSize ) ;
} break ;
case dbiUser : {
quint32 dcId ;
2017-02-23 09:32:28 +00:00
qint32 userId ;
stream > > userId > > dcId ;
2016-09-15 19:15:49 +00:00
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-02-23 09:32:28 +00:00
DEBUG_LOG ( ( " MTP Info: user found, dc %1, uid %2 " ) . arg ( dcId ) . arg ( userId ) ) ;
2017-02-24 17:15:41 +00:00
Messenger : : Instance ( ) . setMtpMainDcId ( dcId ) ;
2017-04-06 19:02:40 +00:00
Messenger : : Instance ( ) . setAuthSessionUserId ( userId ) ;
2016-09-15 19:15:49 +00:00
} break ;
case dbiKey : {
qint32 dcId ;
stream > > dcId ;
2017-04-24 12:16:38 +00:00
auto key = Serialize : : read < MTP : : AuthKey : : Data > ( stream ) ;
2016-09-15 19:15:49 +00:00
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-02-24 17:15:41 +00:00
Messenger : : Instance ( ) . setMtpKey ( dcId , key ) ;
} break ;
case dbiMtpAuthorization : {
auto serialized = QByteArray ( ) ;
stream > > serialized ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Messenger : : Instance ( ) . setMtpAuthorization ( serialized ) ;
2016-09-15 19:15:49 +00:00
} break ;
case dbiAutoStart : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
cSetAutoStart ( v = = 1 ) ;
} break ;
case dbiStartMinimized : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
cSetStartMinimized ( v = = 1 ) ;
} break ;
case dbiSendToMenu : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
cSetSendToMenu ( v = = 1 ) ;
} break ;
2017-02-17 12:50:27 +00:00
case dbiUseExternalVideoPlayer : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
cSetUseExternalVideoPlayer ( v = = 1 ) ;
} break ;
2016-09-15 19:15:49 +00:00
case dbiSoundNotify : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetSoundNotify ( v = = 1 ) ;
} break ;
case dbiAutoDownload : {
qint32 photo , audio , gif ;
stream > > photo > > audio > > gif ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
cSetAutoDownloadPhoto ( photo ) ;
cSetAutoDownloadAudio ( audio ) ;
cSetAutoDownloadGif ( gif ) ;
} break ;
case dbiAutoPlay : {
qint32 gif ;
stream > > gif ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
cSetAutoPlayGif ( gif = = 1 ) ;
} break ;
case dbiDialogsMode : {
qint32 enabled , modeInt ;
stream > > enabled > > modeInt ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetDialogsModeEnabled ( enabled = = 1 ) ;
2017-04-09 18:06:06 +00:00
auto mode = Dialogs : : Mode : : All ;
2016-09-15 19:15:49 +00:00
if ( enabled ) {
mode = static_cast < Dialogs : : Mode > ( modeInt ) ;
if ( mode ! = Dialogs : : Mode : : All & & mode ! = Dialogs : : Mode : : Important ) {
mode = Dialogs : : Mode : : All ;
}
}
Global : : SetDialogsMode ( mode ) ;
} break ;
case dbiModerateMode : {
qint32 enabled ;
stream > > enabled ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetModerateModeEnabled ( enabled = = 1 ) ;
} break ;
case dbiIncludeMuted : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetIncludeMuted ( v = = 1 ) ;
} break ;
2017-03-28 12:30:38 +00:00
case dbiShowingSavedGifsOld : {
2016-09-15 19:15:49 +00:00
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
} break ;
case dbiDesktopNotify : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetDesktopNotify ( v = = 1 ) ;
if ( App : : wnd ( ) ) App : : wnd ( ) - > updateTrayMenu ( ) ;
} break ;
2016-10-03 15:07:50 +00:00
case dbiWindowsNotificationsOld : {
2016-09-15 19:15:49 +00:00
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2016-10-03 15:07:50 +00:00
} break ;
2016-09-15 19:15:49 +00:00
2016-10-03 15:07:50 +00:00
case dbiNativeNotifications : {
2016-09-15 19:15:49 +00:00
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2016-10-03 15:07:50 +00:00
Global : : SetNativeNotifications ( v = = 1 ) ;
2016-09-15 19:15:49 +00:00
} break ;
2016-10-06 16:41:09 +00:00
case dbiNotificationsCount : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetNotificationsCount ( ( v > 0 ? v : 3 ) ) ;
} break ;
case dbiNotificationsCorner : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetNotificationsCorner ( static_cast < Notify : : ScreenCorner > ( ( v > = 0 & & v < 4 ) ? v : 2 ) ) ;
2016-09-15 19:15:49 +00:00
} break ;
2017-11-05 13:57:51 +00:00
case dbiDialogsWidthRatioOld : {
2017-01-14 18:50:16 +00:00
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-11-05 13:57:51 +00:00
GetStoredAuthSessionCache ( ) . setDialogsWidthRatio ( v / 1000000. ) ;
2017-01-14 18:50:16 +00:00
} break ;
2017-03-28 12:30:38 +00:00
case dbiLastSeenWarningSeenOld : {
2017-03-17 18:44:55 +00:00
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-11-05 13:57:51 +00:00
GetStoredAuthSessionCache ( ) . setLastSeenWarningSeen ( v = = 1 ) ;
2017-03-28 12:30:38 +00:00
} break ;
case dbiAuthSessionData : {
QByteArray v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-11-05 13:57:51 +00:00
GetStoredAuthSessionCache ( ) . constructFromSerialized ( v ) ;
2017-03-17 18:44:55 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case dbiWorkMode : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-03-04 19:36:59 +00:00
auto newMode = [ v ] {
switch ( v ) {
case dbiwmTrayOnly : return dbiwmTrayOnly ;
case dbiwmWindowOnly : return dbiwmWindowOnly ;
} ;
return dbiwmWindowAndTray ;
2016-09-15 19:15:49 +00:00
} ;
2017-03-04 19:36:59 +00:00
Global : : RefWorkMode ( ) . set ( newMode ( ) ) ;
2016-09-15 19:15:49 +00:00
} break ;
2017-06-27 22:03:37 +00:00
case dbiConnectionTypeOld : {
2016-09-15 19:15:49 +00:00
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
switch ( v ) {
case dbictHttpProxy :
case dbictTcpProxy : {
ProxyData p ;
qint32 port ;
stream > > p . host > > port > > p . user > > p . password ;
2016-07-18 15:39:10 +00:00
if ( ! _checkStreamStatus ( stream ) ) return false ;
2016-09-15 19:15:49 +00:00
p . port = uint32 ( port ) ;
Global : : SetConnectionProxy ( p ) ;
Global : : SetConnectionType ( DBIConnectionType ( v ) ) ;
2016-07-18 15:39:10 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case dbictHttpAuto :
default : Global : : SetConnectionType ( dbictAuto ) ; break ;
} ;
2017-06-27 22:03:37 +00:00
Global : : SetLastProxyType ( Global : : ConnectionType ( ) ) ;
} break ;
case dbiConnectionType : {
ProxyData p ;
qint32 connectionType , lastProxyType , port ;
stream > > connectionType > > lastProxyType > > p . host > > port > > p . user > > p . password ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
p . port = port ;
switch ( connectionType ) {
case dbictHttpProxy :
case dbictTcpProxy : {
Global : : SetConnectionType ( DBIConnectionType ( lastProxyType ) ) ;
} break ;
case dbictHttpAuto :
default : Global : : SetConnectionType ( dbictAuto ) ; break ;
} ;
switch ( lastProxyType ) {
case dbictHttpProxy :
case dbictTcpProxy : {
Global : : SetLastProxyType ( DBIConnectionType ( lastProxyType ) ) ;
Global : : SetConnectionProxy ( p ) ;
} break ;
case dbictHttpAuto :
default : {
Global : : SetLastProxyType ( dbictAuto ) ;
Global : : SetConnectionProxy ( ProxyData ( ) ) ;
} break ;
}
2016-09-15 19:15:49 +00:00
} break ;
2017-04-13 17:59:05 +00:00
case dbiThemeKey : {
2016-11-01 20:59:51 +00:00
quint64 themeKey = 0 ;
stream > > themeKey ;
2016-10-28 12:44:28 +00:00
if ( ! _checkStreamStatus ( stream ) ) return false ;
_themeKey = themeKey ;
} break ;
2017-04-13 17:59:05 +00:00
case dbiLangPackKey : {
quint64 langPackKey = 0 ;
stream > > langPackKey ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
_langPackKey = langPackKey ;
} break ;
2016-09-15 19:15:49 +00:00
case dbiTryIPv6 : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetTryIPv6 ( v = = 1 ) ;
} break ;
case dbiSeenTrayTooltip : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
cSetSeenTrayTooltip ( v = = 1 ) ;
} break ;
case dbiAutoUpdate : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
cSetAutoUpdate ( v = = 1 ) ;
2016-10-18 07:56:38 +00:00
# ifndef TDESKTOP_DISABLE_AUTOUPDATE
2016-10-07 07:58:34 +00:00
if ( ! cAutoUpdate ( ) ) {
Sandbox : : stopUpdate ( ) ;
}
2016-10-18 07:56:38 +00:00
# endif // !TDESKTOP_DISABLE_AUTOUPDATE
2016-09-15 19:15:49 +00:00
} break ;
case dbiLastUpdateCheck : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
cSetLastUpdateCheck ( v ) ;
} break ;
case dbiScale : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
DBIScale s = cRealScale ( ) ;
switch ( v ) {
case dbisAuto : s = dbisAuto ; break ;
case dbisOne : s = dbisOne ; break ;
case dbisOneAndQuarter : s = dbisOneAndQuarter ; break ;
case dbisOneAndHalf : s = dbisOneAndHalf ; break ;
case dbisTwo : s = dbisTwo ; break ;
}
if ( cRetina ( ) ) s = dbisOne ;
cSetConfigScale ( s ) ;
cSetRealScale ( s ) ;
} break ;
2017-04-13 17:59:05 +00:00
case dbiLangOld : {
2016-09-15 19:15:49 +00:00
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-04-13 17:59:05 +00:00
context . legacyLanguageId = v ;
2016-09-15 19:15:49 +00:00
} break ;
2017-04-13 17:59:05 +00:00
case dbiLangFileOld : {
2016-09-15 19:15:49 +00:00
QString v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-04-13 17:59:05 +00:00
context . legacyLanguageFile = v ;
2016-09-15 19:15:49 +00:00
} break ;
case dbiWindowPosition : {
2017-07-03 12:23:41 +00:00
auto position = TWindowPos ( ) ;
stream > > position . x > > position . y > > position . w > > position . h ;
stream > > position . moncrc > > position . maximized ;
2016-09-15 19:15:49 +00:00
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-07-03 12:23:41 +00:00
DEBUG_LOG ( ( " Window Pos: Read from storage %1, %2, %3, %4 (maximized %5) " ) . arg ( position . x ) . arg ( position . y ) . arg ( position . w ) . arg ( position . h ) . arg ( Logs : : b ( position . maximized ) ) ) ;
cSetWindowPos ( position ) ;
2016-09-15 19:15:49 +00:00
} break ;
case dbiLoggedPhoneNumber : {
QString v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
cSetLoggedPhoneNumber ( v ) ;
} break ;
case dbiMutePeer : { // deprecated
quint64 peerId ;
stream > > peerId ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
} break ;
case dbiMutedPeers : { // deprecated
quint32 count ;
stream > > count ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2016-07-18 15:39:10 +00:00
2016-09-15 19:15:49 +00:00
for ( uint32 i = 0 ; i < count ; + + i ) {
quint64 peerId ;
stream > > peerId ;
}
if ( ! _checkStreamStatus ( stream ) ) return false ;
} break ;
2015-11-03 17:49:10 +00:00
2016-09-15 19:15:49 +00:00
case dbiSendKey : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2015-11-03 17:49:10 +00:00
2016-09-15 19:15:49 +00:00
cSetCtrlEnter ( v = = dbiskCtrlEnter ) ;
if ( App : : main ( ) ) App : : main ( ) - > ctrlEnterSubmitUpdated ( ) ;
} break ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
case dbiCatsAndDogs : { // deprecated
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
} break ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
case dbiTileBackground : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
bool tile = ( version < 8005 & & ! _backgroundKey ) ? false : ( v = = 1 ) ;
2016-10-28 12:44:28 +00:00
Window : : Theme : : Background ( ) - > setTile ( tile ) ;
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
case dbiAdaptiveForWide : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
Global : : SetAdaptiveForWide ( v = = 1 ) ;
} break ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
case dbiAutoLock : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
Global : : SetAutoLock ( v ) ;
Global : : RefLocalPasscodeChanged ( ) . notify ( ) ;
} break ;
case dbiReplaceEmojis : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
cSetReplaceEmojis ( v = = 1 ) ;
} break ;
case dbiDefaultAttach : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
} break ;
case dbiNotifyView : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
switch ( v ) {
case dbinvShowNothing : Global : : SetNotifyView ( dbinvShowNothing ) ; break ;
case dbinvShowName : Global : : SetNotifyView ( dbinvShowName ) ; break ;
default : Global : : SetNotifyView ( dbinvShowPreview ) ; break ;
}
} break ;
case dbiAskDownloadPath : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
Global : : SetAskDownloadPath ( v = = 1 ) ;
} break ;
case dbiDownloadPathOld : {
QString v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-02-03 10:17:40 +00:00
# ifndef OS_WIN_STORE
2016-09-15 19:15:49 +00:00
if ( ! v . isEmpty ( ) & & v ! = qstr ( " tmp " ) & & ! v . endsWith ( ' / ' ) ) v + = ' / ' ;
Global : : SetDownloadPath ( v ) ;
Global : : SetDownloadPathBookmark ( QByteArray ( ) ) ;
Global : : RefDownloadPathChanged ( ) . notify ( ) ;
2017-02-03 10:17:40 +00:00
# endif // OS_WIN_STORE
2016-09-15 19:15:49 +00:00
} break ;
case dbiDownloadPath : {
QString v ;
QByteArray bookmark ;
stream > > v > > bookmark ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2017-02-03 10:17:40 +00:00
# ifndef OS_WIN_STORE
2016-09-15 19:15:49 +00:00
if ( ! v . isEmpty ( ) & & v ! = qstr ( " tmp " ) & & ! v . endsWith ( ' / ' ) ) v + = ' / ' ;
Global : : SetDownloadPath ( v ) ;
Global : : SetDownloadPathBookmark ( bookmark ) ;
psDownloadPathEnableAccess ( ) ;
Global : : RefDownloadPathChanged ( ) . notify ( ) ;
2017-02-03 10:17:40 +00:00
# endif // OS_WIN_STORE
2016-09-15 19:15:49 +00:00
} break ;
case dbiCompressPastedImage : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
cSetCompressPastedImage ( v = = 1 ) ;
} break ;
case dbiEmojiTabOld : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
// deprecated
} break ;
2017-02-15 08:50:11 +00:00
case dbiRecentEmojiOldOld : {
RecentEmojiPreloadOldOld v ;
2016-09-15 19:15:49 +00:00
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
if ( ! v . isEmpty ( ) ) {
2017-02-15 08:50:11 +00:00
RecentEmojiPreload p ;
2016-09-15 19:15:49 +00:00
p . reserve ( v . size ( ) ) ;
2017-02-15 08:50:11 +00:00
for ( auto & item : v ) {
auto oldKey = uint64 ( item . first ) ;
switch ( oldKey ) {
case 0xD83CDDEFLLU : oldKey = 0xD83CDDEFD83CDDF5LLU ; break ;
case 0xD83CDDF0LLU : oldKey = 0xD83CDDF0D83CDDF7LLU ; break ;
case 0xD83CDDE9LLU : oldKey = 0xD83CDDE9D83CDDEALLU ; break ;
case 0xD83CDDE8LLU : oldKey = 0xD83CDDE8D83CDDF3LLU ; break ;
case 0xD83CDDFALLU : oldKey = 0xD83CDDFAD83CDDF8LLU ; break ;
case 0xD83CDDEBLLU : oldKey = 0xD83CDDEBD83CDDF7LLU ; break ;
case 0xD83CDDEALLU : oldKey = 0xD83CDDEAD83CDDF8LLU ; break ;
case 0xD83CDDEELLU : oldKey = 0xD83CDDEED83CDDF9LLU ; break ;
case 0xD83CDDF7LLU : oldKey = 0xD83CDDF7D83CDDFALLU ; break ;
case 0xD83CDDECLLU : oldKey = 0xD83CDDECD83CDDE7LLU ; break ;
}
auto id = Ui : : Emoji : : IdFromOldKey ( oldKey ) ;
if ( ! id . isEmpty ( ) ) {
p . push_back ( qMakePair ( id , item . second ) ) ;
}
}
cSetRecentEmojiPreload ( p ) ;
}
} break ;
case dbiRecentEmojiOld : {
RecentEmojiPreloadOld v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
if ( ! v . isEmpty ( ) ) {
RecentEmojiPreload p ;
p . reserve ( v . size ( ) ) ;
for ( auto & item : v ) {
auto id = Ui : : Emoji : : IdFromOldKey ( item . first ) ;
if ( ! id . isEmpty ( ) ) {
p . push_back ( qMakePair ( id , item . second ) ) ;
2016-09-15 19:15:49 +00:00
}
}
2017-02-15 08:50:11 +00:00
cSetRecentEmojiPreload ( p ) ;
2016-09-15 19:15:49 +00:00
}
} break ;
2015-03-02 12:34:16 +00:00
2017-02-15 08:50:11 +00:00
case dbiRecentEmoji : {
RecentEmojiPreload v ;
2016-09-15 19:15:49 +00:00
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2015-03-02 12:34:16 +00:00
2017-02-15 08:50:11 +00:00
cSetRecentEmojiPreload ( v ) ;
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
case dbiRecentStickers : {
RecentStickerPreload v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
cSetRecentStickersPreload ( v ) ;
} break ;
2015-03-02 12:34:16 +00:00
2017-02-15 08:50:11 +00:00
case dbiEmojiVariantsOld : {
EmojiColorVariantsOld v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
EmojiColorVariants variants ;
for ( auto i = v . cbegin ( ) , e = v . cend ( ) ; i ! = e ; + + i ) {
auto id = Ui : : Emoji : : IdFromOldKey ( static_cast < uint64 > ( i . key ( ) ) ) ;
if ( ! id . isEmpty ( ) ) {
auto index = Ui : : Emoji : : ColorIndexFromOldKey ( i . value ( ) ) ;
if ( index > = 0 ) {
variants . insert ( id , index ) ;
}
}
}
cSetEmojiVariants ( variants ) ;
} break ;
2016-09-15 19:15:49 +00:00
case dbiEmojiVariants : {
EmojiColorVariants v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
cSetEmojiVariants ( v ) ;
} break ;
2015-12-23 21:19:57 +00:00
2016-09-15 19:15:49 +00:00
case dbiHiddenPinnedMessages : {
Global : : HiddenPinnedMessagesMap v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2015-12-27 21:37:48 +00:00
2016-09-15 19:15:49 +00:00
Global : : SetHiddenPinnedMessages ( v ) ;
} break ;
2015-12-27 21:37:48 +00:00
2016-09-15 19:15:49 +00:00
case dbiDialogLastPath : {
QString path ;
stream > > path ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2016-04-11 10:59:01 +00:00
2016-09-15 19:15:49 +00:00
cSetDialogLastPath ( path ) ;
} break ;
2016-04-11 10:59:01 +00:00
2016-09-15 19:15:49 +00:00
case dbiSongVolume : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2016-06-22 18:41:13 +00:00
2016-09-15 19:15:49 +00:00
Global : : SetSongVolume ( snap ( v / 1e6 , 0. , 1. ) ) ;
} break ;
2016-06-22 18:41:13 +00:00
2016-09-15 19:15:49 +00:00
case dbiVideoVolume : {
qint32 v ;
stream > > v ;
if ( ! _checkStreamStatus ( stream ) ) return false ;
2015-08-28 15:15:56 +00:00
2016-09-15 19:15:49 +00:00
Global : : SetVideoVolume ( snap ( v / 1e6 , 0. , 1. ) ) ;
} break ;
2015-08-28 15:15:56 +00:00
2016-09-15 19:15:49 +00:00
default :
LOG ( ( " App Error: unknown blockId in _readSetting: %1 " ) . arg ( blockId ) ) ;
return false ;
}
2015-12-27 21:37:48 +00:00
2016-09-15 19:15:49 +00:00
return true ;
}
2015-12-27 21:37:48 +00:00
2017-02-23 06:57:04 +00:00
bool _readOldSettings ( bool remove , ReadSettingsContext & context ) {
2016-09-15 19:15:49 +00:00
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-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
qint32 version = 0 ;
while ( ! stream . atEnd ( ) ) {
quint32 blockId ;
stream > > blockId ;
if ( ! _checkStreamStatus ( stream ) ) break ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
if ( blockId = = dbiVersion ) {
stream > > version ;
if ( ! _checkStreamStatus ( stream ) ) break ;
2015-08-11 19:50:48 +00:00
2016-09-15 19:15:49 +00:00
if ( version > AppVersion ) break ;
2017-02-23 06:57:04 +00:00
} else if ( ! _readSetting ( blockId , stream , version , context ) ) {
2016-09-15 19:15:49 +00:00
break ;
2015-08-19 13:54:17 +00:00
}
2016-09-15 19:15:49 +00:00
}
file . close ( ) ;
result = true ;
}
if ( remove ) file . remove ( ) ;
return result ;
}
2015-08-11 19:50:48 +00:00
2017-02-23 06:57:04 +00:00
void _readOldUserSettingsFields ( 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 ;
if ( ! _checkStreamStatus ( stream ) ) {
break ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
if ( blockId = = dbiVersion ) {
stream > > version ;
if ( ! _checkStreamStatus ( stream ) ) {
break ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
if ( version > AppVersion ) return ;
} else if ( blockId = = dbiEncryptedWithSalt ) {
QByteArray salt , data , decrypted ;
stream > > salt > > data ;
if ( ! _checkStreamStatus ( stream ) ) {
break ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
if ( salt . size ( ) ! = 32 ) {
LOG ( ( " App Error: bad salt in old user config encrypted part, size: %1 " ) . arg ( salt . size ( ) ) ) ;
continue ;
}
2015-06-25 18:04:40 +00:00
2017-02-25 16:44:02 +00:00
createLocalKey ( QByteArray ( ) , & salt , & OldKey ) ;
2015-06-25 18:04:40 +00:00
2016-09-15 19:15:49 +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 ;
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 ( ( " 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 ;
}
decrypted . resize ( dataLen ) ;
QBuffer decryptedStream ( & decrypted ) ;
decryptedStream . open ( QIODevice : : ReadOnly ) ;
decryptedStream . seek ( 4 ) ; // skip size
LOG ( ( " App Info: reading encrypted old user config... " ) ) ;
2015-03-02 12:34:16 +00:00
2017-02-23 06:57:04 +00:00
_readOldUserSettingsFields ( & decryptedStream , version , context ) ;
} 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 _readOldUserSettings ( bool remove , ReadSettingsContext & context ) {
2016-09-15 19:15:49 +00:00
bool result = false ;
QFile file ( cWorkingDir ( ) + cDataFile ( ) + ( cTestMode ( ) ? qsl ( " _test " ) : QString ( ) ) + qsl ( " _config " ) ) ;
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
2017-02-23 06:57:04 +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 ;
if ( ! _checkStreamStatus ( stream ) ) {
break ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
if ( blockId = = dbiVersion ) {
stream > > version ;
if ( ! _checkStreamStatus ( stream ) ) {
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 ;
if ( ! _checkStreamStatus ( stream ) ) {
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 ) ;
} 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 ;
QFile file ( cWorkingDir ( ) + cDataFile ( ) + ( cTestMode ( ) ? qsl ( " _test " ) : QString ( ) ) ) ;
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
2016-09-15 19:15:49 +00:00
void _writeUserSettings ( ) {
if ( _readingUserSettings ) {
LOG ( ( " App Error: attempt to write settings while reading them! " ) ) ;
return ;
}
LOG ( ( " App Info: writing encrypted user settings... " ) ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
if ( ! _userSettingsKey ) {
_userSettingsKey = genKey ( ) ;
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Fast ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2017-02-15 08:50:11 +00:00
auto recentEmojiPreloadData = cRecentEmojiPreload ( ) ;
if ( recentEmojiPreloadData . isEmpty ( ) ) {
2017-03-28 12:30:38 +00:00
recentEmojiPreloadData . reserve ( Ui : : Emoji : : GetRecent ( ) . size ( ) ) ;
for ( auto & item : Ui : : Emoji : : GetRecent ( ) ) {
2017-02-15 08:50:11 +00:00
recentEmojiPreloadData . push_back ( qMakePair ( item . first - > id ( ) , item . second ) ) ;
}
}
2017-11-05 13:57:51 +00:00
auto userDataInstance = StoredAuthSessionCache ? StoredAuthSessionCache . get ( ) : Messenger : : Instance ( ) . getAuthSessionData ( ) ;
2017-03-28 12:30:38 +00:00
auto userData = userDataInstance ? userDataInstance - > serialize ( ) : QByteArray ( ) ;
2017-02-15 08:50:11 +00:00
2017-01-14 18:50:16 +00:00
uint32 size = 21 * ( sizeof ( quint32 ) + sizeof ( qint32 ) ) ;
2016-09-15 19:15:49 +00:00
size + = sizeof ( quint32 ) + Serialize : : stringSize ( Global : : AskDownloadPath ( ) ? QString ( ) : Global : : DownloadPath ( ) ) + Serialize : : bytearraySize ( Global : : AskDownloadPath ( ) ? QByteArray ( ) : Global : : DownloadPathBookmark ( ) ) ;
2017-02-15 08:50:11 +00:00
size + = sizeof ( quint32 ) + sizeof ( qint32 ) ;
for ( auto & item : recentEmojiPreloadData ) {
size + = Serialize : : stringSize ( item . first ) + sizeof ( item . second ) ;
}
2016-09-15 19:15:49 +00:00
size + = sizeof ( quint32 ) + sizeof ( qint32 ) + cEmojiVariants ( ) . size ( ) * ( sizeof ( uint32 ) + sizeof ( uint64 ) ) ;
2017-12-11 14:45:29 +00:00
size + = sizeof ( quint32 ) + sizeof ( qint32 ) + ( Stickers : : GetRecentPack ( ) . isEmpty ( ) ? Stickers : : GetRecentPack ( ) . size ( ) : cRecentStickersPreload ( ) . size ( ) ) * ( sizeof ( uint64 ) + sizeof ( ushort ) ) ;
2016-09-15 19:15:49 +00:00
size + = sizeof ( quint32 ) + Serialize : : stringSize ( cDialogLastPath ( ) ) ;
size + = sizeof ( quint32 ) + 3 * sizeof ( qint32 ) ;
size + = sizeof ( quint32 ) + 2 * sizeof ( qint32 ) ;
if ( ! Global : : HiddenPinnedMessages ( ) . isEmpty ( ) ) {
size + = sizeof ( quint32 ) + sizeof ( qint32 ) + Global : : HiddenPinnedMessages ( ) . size ( ) * ( sizeof ( PeerId ) + sizeof ( MsgId ) ) ;
}
2017-03-28 12:30:38 +00:00
if ( ! userData . isEmpty ( ) ) {
size + = sizeof ( quint32 ) + Serialize : : bytearraySize ( userData ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ( size ) ;
data . stream < < quint32 ( dbiSendKey ) < < qint32 ( cCtrlEnter ( ) ? dbiskCtrlEnter : dbiskEnter ) ;
2016-11-02 14:44:33 +00:00
data . stream < < quint32 ( dbiTileBackground ) < < qint32 ( Window : : Theme : : Background ( ) - > tileForSave ( ) ? 1 : 0 ) ;
2016-09-15 19:15:49 +00:00
data . stream < < quint32 ( dbiAdaptiveForWide ) < < qint32 ( Global : : AdaptiveForWide ( ) ? 1 : 0 ) ;
data . stream < < quint32 ( dbiAutoLock ) < < qint32 ( Global : : AutoLock ( ) ) ;
data . stream < < quint32 ( dbiReplaceEmojis ) < < qint32 ( cReplaceEmojis ( ) ? 1 : 0 ) ;
data . stream < < quint32 ( dbiSoundNotify ) < < qint32 ( Global : : SoundNotify ( ) ) ;
data . stream < < quint32 ( dbiIncludeMuted ) < < qint32 ( Global : : IncludeMuted ( ) ) ;
data . stream < < quint32 ( dbiDesktopNotify ) < < qint32 ( Global : : DesktopNotify ( ) ) ;
data . stream < < quint32 ( dbiNotifyView ) < < qint32 ( Global : : NotifyView ( ) ) ;
2016-10-03 15:07:50 +00:00
data . stream < < quint32 ( dbiNativeNotifications ) < < qint32 ( Global : : NativeNotifications ( ) ) ;
2016-10-06 16:41:09 +00:00
data . stream < < quint32 ( dbiNotificationsCount ) < < qint32 ( Global : : NotificationsCount ( ) ) ;
data . stream < < quint32 ( dbiNotificationsCorner ) < < qint32 ( Global : : NotificationsCorner ( ) ) ;
2016-09-15 19:15:49 +00:00
data . stream < < quint32 ( dbiAskDownloadPath ) < < qint32 ( Global : : AskDownloadPath ( ) ) ;
data . stream < < quint32 ( dbiDownloadPath ) < < ( Global : : AskDownloadPath ( ) ? QString ( ) : Global : : DownloadPath ( ) ) < < ( Global : : AskDownloadPath ( ) ? QByteArray ( ) : Global : : DownloadPathBookmark ( ) ) ;
data . stream < < quint32 ( dbiCompressPastedImage ) < < qint32 ( cCompressPastedImage ( ) ) ;
data . stream < < quint32 ( dbiDialogLastPath ) < < cDialogLastPath ( ) ;
data . stream < < quint32 ( dbiSongVolume ) < < qint32 ( qRound ( Global : : SongVolume ( ) * 1e6 ) ) ;
data . stream < < quint32 ( dbiVideoVolume ) < < qint32 ( qRound ( Global : : VideoVolume ( ) * 1e6 ) ) ;
data . stream < < quint32 ( dbiAutoDownload ) < < qint32 ( cAutoDownloadPhoto ( ) ) < < qint32 ( cAutoDownloadAudio ( ) ) < < qint32 ( cAutoDownloadGif ( ) ) ;
data . stream < < quint32 ( dbiDialogsMode ) < < qint32 ( Global : : DialogsModeEnabled ( ) ? 1 : 0 ) < < static_cast < qint32 > ( Global : : DialogsMode ( ) ) ;
data . stream < < quint32 ( dbiModerateMode ) < < qint32 ( Global : : ModerateModeEnabled ( ) ? 1 : 0 ) ;
data . stream < < quint32 ( dbiAutoPlay ) < < qint32 ( cAutoPlayGif ( ) ? 1 : 0 ) ;
2017-02-17 12:50:27 +00:00
data . stream < < quint32 ( dbiUseExternalVideoPlayer ) < < qint32 ( cUseExternalVideoPlayer ( ) ) ;
2017-03-28 12:30:38 +00:00
if ( ! userData . isEmpty ( ) ) {
data . stream < < quint32 ( dbiAuthSessionData ) < < userData ;
}
2016-09-15 19:15:49 +00:00
{
2017-02-15 08:50:11 +00:00
data . stream < < quint32 ( dbiRecentEmoji ) < < recentEmojiPreloadData ;
2016-09-15 19:15:49 +00:00
}
data . stream < < quint32 ( dbiEmojiVariants ) < < cEmojiVariants ( ) ;
{
2017-12-11 14:45:29 +00:00
auto v = cRecentStickersPreload ( ) ;
2016-09-15 19:15:49 +00:00
if ( v . isEmpty ( ) ) {
2017-12-11 14:45:29 +00:00
v . reserve ( Stickers : : GetRecentPack ( ) . size ( ) ) ;
for_const ( auto & pair , Stickers : : GetRecentPack ( ) ) {
v . push_back ( qMakePair ( pair . first - > id , pair . second ) ) ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
}
data . stream < < quint32 ( dbiRecentStickers ) < < v ;
}
if ( ! Global : : HiddenPinnedMessages ( ) . isEmpty ( ) ) {
data . stream < < quint32 ( dbiHiddenPinnedMessages ) < < Global : : HiddenPinnedMessages ( ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
FileWriteDescriptor file ( _userSettingsKey ) ;
file . writeEncrypted ( data ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
void _readUserSettings ( ) {
2017-02-23 06:57:04 +00:00
ReadSettingsContext context ;
2016-09-15 19:15:49 +00:00
FileReadDescriptor userSettings ;
if ( ! readEncryptedFile ( userSettings , _userSettingsKey ) ) {
LOG ( ( " App Info: could not read encrypted user settings... " ) ) ;
2017-02-23 06:57:04 +00:00
_readOldUserSettings ( true , context ) ;
2017-03-23 16:11:35 +00:00
applyReadContext ( std : : move ( context ) ) ;
2017-02-23 06:57:04 +00:00
2016-09-15 19:15:49 +00:00
return _writeUserSettings ( ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
LOG ( ( " App Info: reading encrypted user settings... " ) ) ;
_readingUserSettings = true ;
while ( ! userSettings . stream . atEnd ( ) ) {
quint32 blockId ;
userSettings . stream > > blockId ;
if ( ! _checkStreamStatus ( userSettings . stream ) ) {
_readingUserSettings = false ;
return _writeUserSettings ( ) ;
}
2015-03-02 12:34:16 +00:00
2017-02-23 06:57:04 +00:00
if ( ! _readSetting ( blockId , userSettings . stream , userSettings . version , context ) ) {
2016-09-15 19:15:49 +00:00
_readingUserSettings = false ;
return _writeUserSettings ( ) ;
}
}
_readingUserSettings = false ;
LOG ( ( " App Info: encrypted user settings read. " ) ) ;
2017-02-23 06:57:04 +00:00
2017-03-23 16:11:35 +00:00
applyReadContext ( std : : move ( context ) ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
void _writeMtpData ( ) {
2016-10-28 12:44:28 +00:00
FileWriteDescriptor mtp ( toFilePart ( _dataNameKey ) , FileOption : : Safe ) ;
2017-02-25 16:44:02 +00:00
if ( ! LocalKey ) {
2016-09-15 19:15:49 +00:00
LOG ( ( " App Error: localkey not created in _writeMtpData() " ) ) ;
return ;
}
2016-02-21 14:27:54 +00:00
2017-02-24 17:15:41 +00:00
auto mtpAuthorizationSerialized = Messenger : : Instance ( ) . serializeMtpAuthorization ( ) ;
2016-02-21 14:27:54 +00:00
2017-02-24 17:15:41 +00:00
quint32 size = sizeof ( quint32 ) + Serialize : : bytearraySize ( mtpAuthorizationSerialized ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ( size ) ;
2017-02-24 17:15:41 +00:00
data . stream < < quint32 ( dbiMtpAuthorization ) < < mtpAuthorizationSerialized ;
2017-01-01 16:45:20 +00:00
mtp . writeEncrypted ( data ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
void _readMtpData ( ) {
2017-02-23 06:57:04 +00:00
ReadSettingsContext context ;
2016-09-15 19:15:49 +00:00
FileReadDescriptor mtp ;
2016-10-28 12:44:28 +00:00
if ( ! readEncryptedFile ( mtp , toFilePart ( _dataNameKey ) , FileOption : : Safe ) ) {
2017-02-25 16:44:02 +00:00
if ( LocalKey ) {
2017-02-23 06:57:04 +00:00
_readOldMtpData ( true , context ) ;
2017-03-23 16:11:35 +00:00
applyReadContext ( std : : move ( context ) ) ;
2017-02-23 06:57:04 +00:00
2016-09-15 19:15:49 +00:00
_writeMtpData ( ) ;
}
return ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
LOG ( ( " App Info: reading encrypted mtp data... " ) ) ;
while ( ! mtp . stream . atEnd ( ) ) {
quint32 blockId ;
mtp . stream > > blockId ;
if ( ! _checkStreamStatus ( mtp . stream ) ) {
return _writeMtpData ( ) ;
}
2015-03-02 12:34:16 +00:00
2017-02-23 06:57:04 +00:00
if ( ! _readSetting ( blockId , mtp . stream , mtp . version , context ) ) {
2016-09-15 19:15:49 +00:00
return _writeMtpData ( ) ;
}
}
2017-03-23 16:11:35 +00:00
applyReadContext ( std : : move ( context ) ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
ReadMapState _readMap ( const QByteArray & pass ) {
2016-12-01 19:20:33 +00:00
auto ms = getms ( ) ;
2016-09-15 19:15:49 +00:00
QByteArray dataNameUtf8 = ( cDataFile ( ) + ( cTestMode ( ) ? qsl ( " :/test/ " ) : QString ( ) ) ) . toUtf8 ( ) ;
FileKey dataNameHash [ 2 ] ;
hashMd5 ( dataNameUtf8 . constData ( ) , dataNameUtf8 . size ( ) , dataNameHash ) ;
_dataNameKey = dataNameHash [ 0 ] ;
_userBasePath = _basePath + toFilePart ( _dataNameKey ) + QChar ( ' / ' ) ;
FileReadDescriptor mapData ;
if ( ! readFile ( mapData , qsl ( " map " ) ) ) {
return ReadMapFailed ;
}
LOG ( ( " App Info: reading map... " ) ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
QByteArray salt , keyEncrypted , mapEncrypted ;
mapData . stream > > salt > > keyEncrypted > > mapEncrypted ;
if ( ! _checkStreamStatus ( mapData . stream ) ) {
return ReadMapFailed ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
if ( salt . size ( ) ! = LocalEncryptSaltSize ) {
LOG ( ( " App Error: bad salt in map file, size: %1 " ) . arg ( salt . size ( ) ) ) ;
return ReadMapFailed ;
}
2017-02-25 16:44:02 +00:00
createLocalKey ( pass , & salt , & PassKey ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
EncryptedDescriptor keyData , map ;
2017-02-25 16:44:02 +00:00
if ( ! decryptLocal ( keyData , keyEncrypted , PassKey ) ) {
2016-09-15 19:15:49 +00:00
LOG ( ( " App Info: could not decrypt pass-protected key from map file, maybe bad password... " ) ) ;
return ReadMapPassNeeded ;
}
2017-04-24 12:16:38 +00:00
auto key = Serialize : : read < MTP : : AuthKey : : Data > ( keyData . stream ) ;
if ( keyData . stream . status ( ) ! = QDataStream : : Ok | | ! keyData . stream . atEnd ( ) ) {
2016-09-15 19:15:49 +00:00
LOG ( ( " App Error: could not read pass-protected key from map file " ) ) ;
return ReadMapFailed ;
}
2017-02-25 16:44:02 +00:00
LocalKey = std : : make_shared < MTP : : AuthKey > ( key ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
_passKeyEncrypted = keyEncrypted ;
_passKeySalt = salt ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
if ( ! decryptLocal ( map , mapEncrypted ) ) {
LOG ( ( " App Error: could not decrypt map. " ) ) ;
return ReadMapFailed ;
}
LOG ( ( " App Info: reading encrypted map... " ) ) ;
DraftsMap draftsMap , draftCursorsMap ;
DraftsNotReadMap draftsNotReadMap ;
StorageMap imagesMap , stickerImagesMap , audiosMap ;
qint64 storageImagesSize = 0 , storageStickersSize = 0 , storageAudiosSize = 0 ;
quint64 locationsKey = 0 , reportSpamStatusesKey = 0 , trustedBotsKey = 0 ;
quint64 recentStickersKeyOld = 0 ;
2017-08-02 15:07:28 +00:00
quint64 installedStickersKey = 0 , featuredStickersKey = 0 , recentStickersKey = 0 , favedStickersKey = 0 , archivedStickersKey = 0 ;
2016-09-15 19:15:49 +00:00
quint64 savedGifsKey = 0 ;
quint64 backgroundKey = 0 , userSettingsKey = 0 , recentHashtagsAndBotsKey = 0 , savedPeersKey = 0 ;
while ( ! map . stream . atEnd ( ) ) {
quint32 keyType ;
map . stream > > keyType ;
switch ( keyType ) {
case lskDraft : {
quint32 count = 0 ;
map . stream > > count ;
for ( quint32 i = 0 ; i < count ; + + i ) {
FileKey key ;
quint64 p ;
map . stream > > key > > p ;
draftsMap . insert ( p , key ) ;
draftsNotReadMap . insert ( p , true ) ;
}
2015-11-26 17:34:52 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case lskDraftPosition : {
quint32 count = 0 ;
map . stream > > count ;
for ( quint32 i = 0 ; i < count ; + + i ) {
FileKey key ;
quint64 p ;
map . stream > > key > > p ;
draftCursorsMap . insert ( p , key ) ;
}
2015-03-02 12:34:16 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case lskImages : {
quint32 count = 0 ;
map . stream > > count ;
for ( quint32 i = 0 ; i < count ; + + i ) {
FileKey key ;
quint64 first , second ;
qint32 size ;
map . stream > > key > > first > > second > > size ;
imagesMap . insert ( StorageKey ( first , second ) , FileDesc ( key , size ) ) ;
storageImagesSize + = size ;
}
2015-03-02 12:34:16 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case lskStickerImages : {
quint32 count = 0 ;
map . stream > > count ;
for ( quint32 i = 0 ; i < count ; + + i ) {
FileKey key ;
quint64 first , second ;
qint32 size ;
map . stream > > key > > first > > second > > size ;
stickerImagesMap . insert ( StorageKey ( first , second ) , FileDesc ( key , size ) ) ;
storageStickersSize + = size ;
}
2015-05-08 12:45:14 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case lskAudios : {
quint32 count = 0 ;
map . stream > > count ;
for ( quint32 i = 0 ; i < count ; + + i ) {
FileKey key ;
quint64 first , second ;
qint32 size ;
map . stream > > key > > first > > second > > size ;
audiosMap . insert ( StorageKey ( first , second ) , FileDesc ( key , size ) ) ;
storageAudiosSize + = size ;
2015-03-02 12:34:16 +00:00
}
} break ;
2016-09-15 19:15:49 +00:00
case lskLocations : {
map . stream > > locationsKey ;
2015-03-02 12:34:16 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case lskReportSpamStatuses : {
map . stream > > reportSpamStatusesKey ;
2015-05-19 15:46:45 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case lskTrustedBots : {
map . stream > > trustedBotsKey ;
2015-05-08 12:45:14 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case lskRecentStickersOld : {
map . stream > > recentStickersKeyOld ;
2016-03-10 10:15:21 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case lskBackground : {
map . stream > > backgroundKey ;
2015-03-24 15:49:07 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case lskUserSettings : {
map . stream > > userSettingsKey ;
2016-07-12 14:11:59 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case lskRecentHashtagsAndBots : {
map . stream > > recentHashtagsAndBotsKey ;
2015-07-03 08:47:16 +00:00
} break ;
2016-09-15 19:15:49 +00:00
case lskStickersOld : {
map . stream > > installedStickersKey ;
} break ;
case lskStickersKeys : {
map . stream > > installedStickersKey > > featuredStickersKey > > recentStickersKey > > archivedStickersKey ;
} break ;
2017-08-02 15:07:28 +00:00
case lskFavedStickers : {
map . stream > > favedStickersKey ;
} break ;
2016-09-15 19:15:49 +00:00
case lskSavedGifsOld : {
quint64 key ;
map . stream > > key ;
} break ;
case lskSavedGifs : {
map . stream > > savedGifsKey ;
} break ;
case lskSavedPeers : {
map . stream > > savedPeersKey ;
} break ;
default :
LOG ( ( " App Error: unknown key type in encrypted map: %1 " ) . arg ( keyType ) ) ;
return ReadMapFailed ;
}
if ( ! _checkStreamStatus ( map . stream ) ) {
return ReadMapFailed ;
}
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
_draftsMap = draftsMap ;
_draftCursorsMap = draftCursorsMap ;
_draftsNotReadMap = draftsNotReadMap ;
_imagesMap = imagesMap ;
_storageImagesSize = storageImagesSize ;
_stickerImagesMap = stickerImagesMap ;
_storageStickersSize = storageStickersSize ;
_audiosMap = audiosMap ;
_storageAudiosSize = storageAudiosSize ;
_locationsKey = locationsKey ;
_reportSpamStatusesKey = reportSpamStatusesKey ;
_trustedBotsKey = trustedBotsKey ;
_recentStickersKeyOld = recentStickersKeyOld ;
_installedStickersKey = installedStickersKey ;
_featuredStickersKey = featuredStickersKey ;
_recentStickersKey = recentStickersKey ;
2017-08-02 15:07:28 +00:00
_favedStickersKey = favedStickersKey ;
2016-09-15 19:15:49 +00:00
_archivedStickersKey = archivedStickersKey ;
_savedGifsKey = savedGifsKey ;
_savedPeersKey = savedPeersKey ;
_backgroundKey = backgroundKey ;
_userSettingsKey = userSettingsKey ;
_recentHashtagsAndBotsKey = recentHashtagsAndBotsKey ;
_oldMapVersion = mapData . version ;
if ( _oldMapVersion < AppVersion ) {
_mapChanged = true ;
_writeMap ( ) ;
} else {
_mapChanged = false ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
if ( _locationsKey ) {
_readLocations ( ) ;
}
if ( _reportSpamStatusesKey ) {
_readReportSpamStatuses ( ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
_readUserSettings ( ) ;
_readMtpData ( ) ;
2015-03-02 12:34:16 +00:00
2017-04-09 18:06:06 +00:00
Messenger : : Instance ( ) . setAuthSessionFromStorage ( std : : move ( StoredAuthSessionCache ) ) ;
2017-03-28 12:30:38 +00:00
2016-09-15 19:15:49 +00:00
LOG ( ( " Map read time: %1 " ) . arg ( getms ( ) - ms ) ) ;
if ( _oldSettingsVersion < AppVersion ) {
writeSettings ( ) ;
}
return ReadMapDone ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
void _writeMap ( WriteMapWhen when ) {
2017-03-28 12:30:38 +00:00
if ( when ! = WriteMapWhen : : Now ) {
_manager - > writeMap ( when = = WriteMapWhen : : Fast ) ;
2016-09-15 19:15:49 +00:00
return ;
}
_manager - > writingMap ( ) ;
if ( ! _mapChanged ) return ;
if ( _userBasePath . isEmpty ( ) ) {
LOG ( ( " App Error: _userBasePath is empty in writeMap() " ) ) ;
return ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
if ( ! QDir ( ) . exists ( _userBasePath ) ) QDir ( ) . mkpath ( _userBasePath ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
FileWriteDescriptor map ( qsl ( " map " ) ) ;
if ( _passKeySalt . isEmpty ( ) | | _passKeyEncrypted . isEmpty ( ) ) {
2017-02-22 15:18:26 +00:00
QByteArray pass ( kLocalKeySize , Qt : : Uninitialized ) , salt ( LocalEncryptSaltSize , Qt : : Uninitialized ) ;
2016-09-15 19:15:49 +00:00
memset_rand ( pass . data ( ) , pass . size ( ) ) ;
memset_rand ( salt . data ( ) , salt . size ( ) ) ;
2017-02-25 16:44:02 +00:00
createLocalKey ( pass , & salt , & LocalKey ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
_passKeySalt . resize ( LocalEncryptSaltSize ) ;
memset_rand ( _passKeySalt . data ( ) , _passKeySalt . size ( ) ) ;
2017-02-25 16:44:02 +00:00
createLocalKey ( QByteArray ( ) , & _passKeySalt , & PassKey ) ;
2015-03-02 12:34:16 +00:00
2017-02-22 15:18:26 +00:00
EncryptedDescriptor passKeyData ( kLocalKeySize ) ;
2017-02-25 16:44:02 +00:00
LocalKey - > write ( passKeyData . stream ) ;
_passKeyEncrypted = FileWriteDescriptor : : prepareEncrypted ( passKeyData , PassKey ) ;
2016-09-15 19:15:49 +00:00
}
map . writeData ( _passKeySalt ) ;
map . writeData ( _passKeyEncrypted ) ;
uint32 mapSize = 0 ;
if ( ! _draftsMap . isEmpty ( ) ) mapSize + = sizeof ( quint32 ) * 2 + _draftsMap . size ( ) * sizeof ( quint64 ) * 2 ;
if ( ! _draftCursorsMap . isEmpty ( ) ) mapSize + = sizeof ( quint32 ) * 2 + _draftCursorsMap . size ( ) * sizeof ( quint64 ) * 2 ;
if ( ! _imagesMap . isEmpty ( ) ) mapSize + = sizeof ( quint32 ) * 2 + _imagesMap . size ( ) * ( sizeof ( quint64 ) * 3 + sizeof ( qint32 ) ) ;
if ( ! _stickerImagesMap . isEmpty ( ) ) mapSize + = sizeof ( quint32 ) * 2 + _stickerImagesMap . size ( ) * ( sizeof ( quint64 ) * 3 + sizeof ( qint32 ) ) ;
if ( ! _audiosMap . isEmpty ( ) ) mapSize + = sizeof ( quint32 ) * 2 + _audiosMap . size ( ) * ( sizeof ( quint64 ) * 3 + sizeof ( qint32 ) ) ;
if ( _locationsKey ) mapSize + = sizeof ( quint32 ) + sizeof ( quint64 ) ;
if ( _reportSpamStatusesKey ) mapSize + = sizeof ( quint32 ) + sizeof ( quint64 ) ;
if ( _trustedBotsKey ) mapSize + = sizeof ( quint32 ) + sizeof ( quint64 ) ;
if ( _recentStickersKeyOld ) mapSize + = sizeof ( quint32 ) + sizeof ( quint64 ) ;
if ( _installedStickersKey | | _featuredStickersKey | | _recentStickersKey | | _archivedStickersKey ) {
mapSize + = sizeof ( quint32 ) + 4 * sizeof ( quint64 ) ;
}
2017-08-02 15:07:28 +00:00
if ( _favedStickersKey ) mapSize + = sizeof ( quint32 ) + sizeof ( quint64 ) ;
2016-09-15 19:15:49 +00:00
if ( _savedGifsKey ) mapSize + = sizeof ( quint32 ) + sizeof ( quint64 ) ;
if ( _savedPeersKey ) mapSize + = sizeof ( quint32 ) + sizeof ( quint64 ) ;
if ( _backgroundKey ) mapSize + = sizeof ( quint32 ) + sizeof ( quint64 ) ;
if ( _userSettingsKey ) mapSize + = sizeof ( quint32 ) + sizeof ( quint64 ) ;
if ( _recentHashtagsAndBotsKey ) mapSize + = sizeof ( quint32 ) + sizeof ( quint64 ) ;
EncryptedDescriptor mapData ( mapSize ) ;
if ( ! _draftsMap . isEmpty ( ) ) {
mapData . stream < < quint32 ( lskDraft ) < < quint32 ( _draftsMap . size ( ) ) ;
for ( DraftsMap : : const_iterator i = _draftsMap . cbegin ( ) , e = _draftsMap . cend ( ) ; i ! = e ; + + i ) {
mapData . stream < < quint64 ( i . value ( ) ) < < quint64 ( i . key ( ) ) ;
2015-03-02 12:34:16 +00:00
}
}
2016-09-15 19:15:49 +00:00
if ( ! _draftCursorsMap . isEmpty ( ) ) {
mapData . stream < < quint32 ( lskDraftPosition ) < < quint32 ( _draftCursorsMap . size ( ) ) ;
for ( DraftsMap : : const_iterator i = _draftCursorsMap . cbegin ( ) , e = _draftCursorsMap . cend ( ) ; i ! = e ; + + i ) {
mapData . stream < < quint64 ( i . value ( ) ) < < quint64 ( i . key ( ) ) ;
}
}
if ( ! _imagesMap . isEmpty ( ) ) {
mapData . stream < < quint32 ( lskImages ) < < quint32 ( _imagesMap . size ( ) ) ;
for ( StorageMap : : const_iterator i = _imagesMap . cbegin ( ) , e = _imagesMap . cend ( ) ; i ! = e ; + + i ) {
mapData . stream < < quint64 ( i . value ( ) . first ) < < quint64 ( i . key ( ) . first ) < < quint64 ( i . key ( ) . second ) < < qint32 ( i . value ( ) . second ) ;
}
}
if ( ! _stickerImagesMap . isEmpty ( ) ) {
mapData . stream < < quint32 ( lskStickerImages ) < < quint32 ( _stickerImagesMap . size ( ) ) ;
for ( StorageMap : : const_iterator i = _stickerImagesMap . cbegin ( ) , e = _stickerImagesMap . cend ( ) ; i ! = e ; + + i ) {
mapData . stream < < quint64 ( i . value ( ) . first ) < < quint64 ( i . key ( ) . first ) < < quint64 ( i . key ( ) . second ) < < qint32 ( i . value ( ) . second ) ;
2015-03-02 12:34:16 +00:00
}
}
2016-09-15 19:15:49 +00:00
if ( ! _audiosMap . isEmpty ( ) ) {
mapData . stream < < quint32 ( lskAudios ) < < quint32 ( _audiosMap . size ( ) ) ;
for ( StorageMap : : const_iterator i = _audiosMap . cbegin ( ) , e = _audiosMap . cend ( ) ; i ! = e ; + + i ) {
mapData . stream < < quint64 ( i . value ( ) . first ) < < quint64 ( i . key ( ) . first ) < < quint64 ( i . key ( ) . second ) < < qint32 ( i . value ( ) . second ) ;
}
}
if ( _locationsKey ) {
mapData . stream < < quint32 ( lskLocations ) < < quint64 ( _locationsKey ) ;
}
if ( _reportSpamStatusesKey ) {
mapData . stream < < quint32 ( lskReportSpamStatuses ) < < quint64 ( _reportSpamStatusesKey ) ;
}
if ( _trustedBotsKey ) {
mapData . stream < < quint32 ( lskTrustedBots ) < < quint64 ( _trustedBotsKey ) ;
}
if ( _recentStickersKeyOld ) {
mapData . stream < < quint32 ( lskRecentStickersOld ) < < quint64 ( _recentStickersKeyOld ) ;
}
if ( _installedStickersKey | | _featuredStickersKey | | _recentStickersKey | | _archivedStickersKey ) {
mapData . stream < < quint32 ( lskStickersKeys ) ;
mapData . stream < < quint64 ( _installedStickersKey ) < < quint64 ( _featuredStickersKey ) < < quint64 ( _recentStickersKey ) < < quint64 ( _archivedStickersKey ) ;
}
2017-08-02 15:07:28 +00:00
if ( _favedStickersKey ) {
mapData . stream < < quint32 ( lskFavedStickers ) < < quint64 ( _favedStickersKey ) ;
}
2016-09-15 19:15:49 +00:00
if ( _savedGifsKey ) {
mapData . stream < < quint32 ( lskSavedGifs ) < < quint64 ( _savedGifsKey ) ;
}
if ( _savedPeersKey ) {
mapData . stream < < quint32 ( lskSavedPeers ) < < quint64 ( _savedPeersKey ) ;
}
if ( _backgroundKey ) {
mapData . stream < < quint32 ( lskBackground ) < < quint64 ( _backgroundKey ) ;
}
if ( _userSettingsKey ) {
mapData . stream < < quint32 ( lskUserSettings ) < < quint64 ( _userSettingsKey ) ;
}
if ( _recentHashtagsAndBotsKey ) {
mapData . stream < < quint32 ( lskRecentHashtagsAndBots ) < < quint64 ( _recentHashtagsAndBotsKey ) ;
}
map . writeEncrypted ( mapData ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
_mapChanged = false ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
} // namespace
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
void finish ( ) {
if ( _manager ) {
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Now ) ;
2016-09-15 19:15:49 +00:00
_manager - > finish ( ) ;
_manager - > deleteLater ( ) ;
_manager = 0 ;
2016-10-28 12:44:28 +00:00
delete base : : take ( _localLoader ) ;
2016-09-15 19:15:49 +00:00
}
}
2015-03-02 12:34:16 +00:00
2016-10-28 12:44:28 +00:00
void readTheme ( ) ;
2017-04-13 17:59:05 +00:00
void readLangPack ( ) ;
2016-10-28 12:44:28 +00:00
2016-09-15 19:15:49 +00:00
void start ( ) {
2017-04-13 17:59:05 +00:00
Expects ( ! _manager ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
_manager = new internal : : Manager ( ) ;
_localLoader = new TaskQueue ( 0 , FileLoaderQueueStopTimeout ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
_basePath = cWorkingDir ( ) + qsl ( " tdata/ " ) ;
if ( ! QDir ( ) . exists ( _basePath ) ) QDir ( ) . mkpath ( _basePath ) ;
2015-03-02 12:34:16 +00:00
2017-02-23 06:57:04 +00:00
ReadSettingsContext context ;
2016-09-15 19:15:49 +00:00
FileReadDescriptor settingsData ;
2016-10-28 12:44:28 +00:00
if ( ! readFile ( settingsData , cTestMode ( ) ? qsl ( " settings_test " ) : qsl ( " settings " ) , FileOption : : Safe ) ) {
2017-02-23 06:57:04 +00:00
_readOldSettings ( true , context ) ;
_readOldUserSettings ( false , context ) ; // needed further in _readUserSettings
_readOldMtpData ( false , context ) ; // needed further in _readMtpData
2017-03-23 16:11:35 +00:00
applyReadContext ( std : : move ( context ) ) ;
2017-02-23 06:57:04 +00:00
2016-09-15 19:15:49 +00:00
return writeSettings ( ) ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
LOG ( ( " App Info: reading settings... " ) ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
QByteArray salt , settingsEncrypted ;
settingsData . stream > > salt > > settingsEncrypted ;
if ( ! _checkStreamStatus ( settingsData . stream ) ) {
return writeSettings ( ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
if ( salt . size ( ) ! = LocalEncryptSaltSize ) {
LOG ( ( " App Error: bad salt in settings file, size: %1 " ) . arg ( salt . size ( ) ) ) ;
return writeSettings ( ) ;
2015-03-02 12:34:16 +00:00
}
2017-02-25 16:44:02 +00:00
createLocalKey ( QByteArray ( ) , & salt , & SettingsKey ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
EncryptedDescriptor settings ;
2017-02-25 16:44:02 +00:00
if ( ! decryptLocal ( settings , settingsEncrypted , SettingsKey ) ) {
2016-09-15 19:15:49 +00:00
LOG ( ( " App Error: could not decrypt settings from settings file, maybe bad passcode... " ) ) ;
return writeSettings ( ) ;
}
2017-02-23 06:57:04 +00:00
2016-09-15 19:15:49 +00:00
LOG ( ( " App Info: reading encrypted settings... " ) ) ;
while ( ! settings . stream . atEnd ( ) ) {
quint32 blockId ;
settings . stream > > blockId ;
if ( ! _checkStreamStatus ( settings . stream ) ) {
return writeSettings ( ) ;
2016-09-15 10:26:31 +00:00
}
2017-02-23 06:57:04 +00:00
if ( ! _readSetting ( blockId , settings . stream , settingsData . version , context ) ) {
2016-09-15 19:15:49 +00:00
return writeSettings ( ) ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
_oldSettingsVersion = settingsData . version ;
_settingsSalt = salt ;
2016-10-28 12:44:28 +00:00
readTheme ( ) ;
2017-04-13 17:59:05 +00:00
readLangPack ( ) ;
2017-02-23 06:57:04 +00:00
2017-03-23 16:11:35 +00:00
applyReadContext ( std : : move ( context ) ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
void writeSettings ( ) {
if ( _basePath . isEmpty ( ) ) {
LOG ( ( " App Error: _basePath is empty in writeSettings() " ) ) ;
return ;
}
if ( ! QDir ( ) . exists ( _basePath ) ) QDir ( ) . mkpath ( _basePath ) ;
2016-10-28 12:44:28 +00:00
FileWriteDescriptor settings ( cTestMode ( ) ? qsl ( " settings_test " ) : qsl ( " settings " ) , FileOption : : Safe ) ;
2017-02-25 16:44:02 +00:00
if ( _settingsSalt . isEmpty ( ) | | ! SettingsKey ) {
2016-09-15 19:15:49 +00:00
_settingsSalt . resize ( LocalEncryptSaltSize ) ;
memset_rand ( _settingsSalt . data ( ) , _settingsSalt . size ( ) ) ;
2017-02-25 16:44:02 +00:00
createLocalKey ( QByteArray ( ) , & _settingsSalt , & SettingsKey ) ;
2016-09-15 19:15:49 +00:00
}
settings . writeData ( _settingsSalt ) ;
2017-02-23 10:59:19 +00:00
auto dcOptionsSerialized = Messenger : : Instance ( ) . dcOptions ( ) - > serialize ( ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
quint32 size = 12 * ( sizeof ( quint32 ) + sizeof ( qint32 ) ) ;
2017-02-23 06:57:04 +00:00
size + = sizeof ( quint32 ) + Serialize : : bytearraySize ( dcOptionsSerialized ) ;
2015-03-02 12:34:16 +00:00
2017-06-27 22:03:37 +00:00
auto & proxy = Global : : ConnectionProxy ( ) ;
size + = sizeof ( quint32 ) + sizeof ( qint32 ) + sizeof ( qint32 ) ;
size + = Serialize : : stringSize ( proxy . host ) + sizeof ( qint32 ) + Serialize : : stringSize ( proxy . user ) + Serialize : : stringSize ( proxy . password ) ;
2016-11-01 20:59:51 +00:00
if ( _themeKey ) {
2017-04-13 17:59:05 +00:00
size + = sizeof ( quint32 ) + sizeof ( quint64 ) ;
}
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 ( dbiChatSizeMax ) < < qint32 ( Global : : ChatSizeMax ( ) ) ;
data . stream < < quint32 ( dbiMegagroupSizeMax ) < < qint32 ( Global : : MegagroupSizeMax ( ) ) ;
data . stream < < quint32 ( dbiSavedGifsLimit ) < < qint32 ( Global : : SavedGifsLimit ( ) ) ;
data . stream < < quint32 ( dbiStickersRecentLimit ) < < qint32 ( Global : : StickersRecentLimit ( ) ) ;
2017-08-02 15:07:28 +00:00
data . stream < < quint32 ( dbiStickersFavedLimit ) < < qint32 ( Global : : StickersFavedLimit ( ) ) ;
2016-09-15 19:15:49 +00:00
data . stream < < quint32 ( dbiAutoStart ) < < qint32 ( cAutoStart ( ) ) ;
data . stream < < quint32 ( dbiStartMinimized ) < < qint32 ( cStartMinimized ( ) ) ;
data . stream < < quint32 ( dbiSendToMenu ) < < qint32 ( cSendToMenu ( ) ) ;
2017-03-04 19:36:59 +00:00
data . stream < < quint32 ( dbiWorkMode ) < < qint32 ( Global : : WorkMode ( ) . value ( ) ) ;
2016-09-15 19:15:49 +00:00
data . stream < < quint32 ( dbiSeenTrayTooltip ) < < qint32 ( cSeenTrayTooltip ( ) ) ;
data . stream < < quint32 ( dbiAutoUpdate ) < < qint32 ( cAutoUpdate ( ) ) ;
data . stream < < quint32 ( dbiLastUpdateCheck ) < < qint32 ( cLastUpdateCheck ( ) ) ;
data . stream < < quint32 ( dbiScale ) < < qint32 ( cConfigScale ( ) ) ;
2017-02-23 06:57:04 +00:00
data . stream < < quint32 ( dbiDcOptions ) < < dcOptionsSerialized ;
2015-03-02 12:34:16 +00:00
2017-06-27 22:03:37 +00:00
data . stream < < quint32 ( dbiConnectionType ) < < qint32 ( Global : : ConnectionType ( ) ) < < qint32 ( Global : : LastProxyType ( ) ) ;
data . stream < < proxy . host < < qint32 ( proxy . port ) < < proxy . user < < proxy . password ;
2016-09-15 19:15:49 +00:00
data . stream < < quint32 ( dbiTryIPv6 ) < < qint32 ( Global : : TryIPv6 ( ) ) ;
2016-11-01 20:59:51 +00:00
if ( _themeKey ) {
2017-04-13 17:59:05 +00:00
data . stream < < quint32 ( dbiThemeKey ) < < quint64 ( _themeKey ) ;
}
if ( _langPackKey ) {
data . stream < < quint32 ( dbiLangPackKey ) < < quint64 ( _langPackKey ) ;
2016-10-28 12:44:28 +00:00
}
2015-03-02 12:34:16 +00:00
2017-07-03 12:23:41 +00:00
auto position = cWindowPos ( ) ;
data . stream < < quint32 ( dbiWindowPosition ) < < qint32 ( position . x ) < < qint32 ( position . y ) < < qint32 ( position . w ) < < qint32 ( position . h ) ;
data . stream < < qint32 ( position . moncrc ) < < qint32 ( position . maximized ) ;
DEBUG_LOG ( ( " Window Pos: Writing to storage %1, %2, %3, %4 (maximized %5) " ) . arg ( position . x ) . arg ( position . y ) . arg ( position . w ) . arg ( position . h ) . arg ( Logs : : b ( position . maximized ) ) ) ;
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
2016-09-15 19:15:49 +00:00
void writeUserSettings ( ) {
_writeUserSettings ( ) ;
}
void writeMtpData ( ) {
_writeMtpData ( ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
void reset ( ) {
if ( _localLoader ) {
_localLoader - > stop ( ) ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
_passKeySalt . clear ( ) ; // reset passcode, local key
_draftsMap . clear ( ) ;
_draftCursorsMap . clear ( ) ;
_fileLocations . clear ( ) ;
_fileLocationPairs . clear ( ) ;
_fileLocationAliases . clear ( ) ;
_imagesMap . clear ( ) ;
_draftsNotReadMap . clear ( ) ;
_stickerImagesMap . clear ( ) ;
_audiosMap . clear ( ) ;
_storageImagesSize = _storageStickersSize = _storageAudiosSize = 0 ;
_webFilesMap . clear ( ) ;
_storageWebFilesSize = 0 ;
_locationsKey = _reportSpamStatusesKey = _trustedBotsKey = 0 ;
_recentStickersKeyOld = 0 ;
2017-08-02 15:07:28 +00:00
_installedStickersKey = _featuredStickersKey = _recentStickersKey = _favedStickersKey = _archivedStickersKey = 0 ;
2016-09-15 19:15:49 +00:00
_savedGifsKey = 0 ;
_backgroundKey = _userSettingsKey = _recentHashtagsAndBotsKey = _savedPeersKey = 0 ;
_oldMapVersion = _oldSettingsVersion = 0 ;
2017-04-09 18:06:06 +00:00
StoredAuthSessionCache . reset ( ) ;
2016-09-15 19:15:49 +00:00
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Now ) ;
2016-09-15 19:15:49 +00:00
_writeMtpData ( ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
bool checkPasscode ( const QByteArray & passcode ) {
2017-02-25 16:44:02 +00:00
auto checkKey = MTP : : AuthKeyPtr ( ) ;
2017-02-22 15:18:26 +00:00
createLocalKey ( passcode , & _passKeySalt , & checkKey ) ;
2017-02-25 16:44:02 +00:00
return checkKey - > equals ( PassKey ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
void setPasscode ( const QByteArray & passcode ) {
2017-02-25 16:44:02 +00:00
createLocalKey ( passcode , & _passKeySalt , & PassKey ) ;
2016-09-15 19:15:49 +00:00
2017-02-22 15:18:26 +00:00
EncryptedDescriptor passKeyData ( kLocalKeySize ) ;
2017-02-25 16:44:02 +00:00
LocalKey - > write ( passKeyData . stream ) ;
_passKeyEncrypted = FileWriteDescriptor : : prepareEncrypted ( passKeyData , PassKey ) ;
2016-09-15 19:15:49 +00:00
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Now ) ;
2016-09-15 19:15:49 +00:00
Global : : SetLocalPasscode ( ! passcode . isEmpty ( ) ) ;
Global : : RefLocalPasscodeChanged ( ) . notify ( ) ;
}
ReadMapState readMap ( const QByteArray & pass ) {
ReadMapState result = _readMap ( pass ) ;
if ( result = = ReadMapFailed ) {
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Now ) ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
return result ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
int32 oldMapVersion ( ) {
return _oldMapVersion ;
}
int32 oldSettingsVersion ( ) {
return _oldSettingsVersion ;
}
2014-12-03 13:10:32 +00:00
2016-09-15 19:15:49 +00:00
void writeDrafts ( const PeerId & peer , const MessageDraft & localDraft , const MessageDraft & editDraft ) {
if ( ! _working ( ) ) return ;
if ( localDraft . msgId < = 0 & & localDraft . textWithTags . text . isEmpty ( ) & & editDraft . msgId < = 0 ) {
auto i = _draftsMap . find ( peer ) ;
if ( i ! = _draftsMap . cend ( ) ) {
clearKey ( i . value ( ) ) ;
_draftsMap . erase ( i ) ;
2014-12-16 16:53:23 +00:00
_mapChanged = true ;
2014-12-12 22:32:06 +00:00
_writeMap ( ) ;
}
2014-12-03 13:10:32 +00:00
2016-09-15 19:15:49 +00:00
_draftsNotReadMap . remove ( peer ) ;
} else {
auto i = _draftsMap . constFind ( peer ) ;
if ( i = = _draftsMap . cend ( ) ) {
i = _draftsMap . insert ( peer , genKey ( ) ) ;
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Fast ) ;
2015-09-09 08:19:25 +00:00
}
2014-12-05 13:44:27 +00:00
2016-11-15 11:56:49 +00:00
auto msgTags = Ui : : FlatTextarea : : serializeTagsList ( localDraft . textWithTags . tags ) ;
auto editTags = Ui : : FlatTextarea : : serializeTagsList ( editDraft . textWithTags . tags ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
int size = sizeof ( quint64 ) ;
size + = Serialize : : stringSize ( localDraft . textWithTags . text ) + Serialize : : bytearraySize ( msgTags ) + 2 * sizeof ( qint32 ) ;
size + = Serialize : : stringSize ( editDraft . textWithTags . text ) + Serialize : : bytearraySize ( editTags ) + 2 * sizeof ( qint32 ) ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ( size ) ;
data . stream < < quint64 ( peer ) ;
data . stream < < localDraft . textWithTags . text < < msgTags ;
data . stream < < qint32 ( localDraft . msgId ) < < qint32 ( localDraft . previewCancelled ? 1 : 0 ) ;
data . stream < < editDraft . textWithTags . text < < editTags ;
data . stream < < qint32 ( editDraft . msgId ) < < qint32 ( editDraft . previewCancelled ? 1 : 0 ) ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
FileWriteDescriptor file ( i . value ( ) ) ;
file . writeEncrypted ( data ) ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
_draftsNotReadMap . remove ( peer ) ;
2014-11-22 09:45:04 +00:00
}
}
2016-09-15 19:15:49 +00:00
void clearDraftCursors ( const PeerId & peer ) {
DraftsMap : : iterator i = _draftCursorsMap . find ( peer ) ;
if ( i ! = _draftCursorsMap . cend ( ) ) {
clearKey ( i . value ( ) ) ;
_draftCursorsMap . erase ( i ) ;
_mapChanged = true ;
_writeMap ( ) ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
void _readDraftCursors ( const PeerId & peer , MessageCursor & localCursor , MessageCursor & editCursor ) {
DraftsMap : : iterator j = _draftCursorsMap . find ( peer ) ;
if ( j = = _draftCursorsMap . cend ( ) ) {
return ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
FileReadDescriptor draft ;
if ( ! readEncryptedFile ( draft , j . value ( ) ) ) {
clearDraftCursors ( peer ) ;
return ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
quint64 draftPeer ;
qint32 localPosition = 0 , localAnchor = 0 , localScroll = QFIXED_MAX ;
qint32 editPosition = 0 , editAnchor = 0 , editScroll = QFIXED_MAX ;
draft . stream > > draftPeer > > localPosition > > localAnchor > > localScroll ;
if ( ! draft . stream . atEnd ( ) ) {
draft . stream > > editPosition > > editAnchor > > editScroll ;
2014-12-05 13:44:27 +00:00
}
2016-09-15 19:15:49 +00:00
if ( draftPeer ! = peer ) {
clearDraftCursors ( peer ) ;
return ;
2014-12-05 13:44:27 +00:00
}
2016-09-15 19:15:49 +00:00
localCursor = MessageCursor ( localPosition , localAnchor , localScroll ) ;
editCursor = MessageCursor ( editPosition , editAnchor , editScroll ) ;
}
void readDraftsWithCursors ( History * h ) {
PeerId peer = h - > peer - > id ;
if ( ! _draftsNotReadMap . remove ( peer ) ) {
clearDraftCursors ( peer ) ;
return ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
DraftsMap : : iterator j = _draftsMap . find ( peer ) ;
if ( j = = _draftsMap . cend ( ) ) {
clearDraftCursors ( peer ) ;
return ;
}
FileReadDescriptor draft ;
if ( ! readEncryptedFile ( draft , j . value ( ) ) ) {
clearKey ( j . value ( ) ) ;
_draftsMap . erase ( j ) ;
clearDraftCursors ( peer ) ;
return ;
2014-12-05 13:44:27 +00:00
}
2016-09-15 19:15:49 +00:00
quint64 draftPeer = 0 ;
TextWithTags msgData , editData ;
QByteArray msgTagsSerialized , editTagsSerialized ;
qint32 msgReplyTo = 0 , msgPreviewCancelled = 0 , editMsgId = 0 , editPreviewCancelled = 0 ;
draft . stream > > draftPeer > > msgData . text ;
if ( draft . version > = 9048 ) {
draft . stream > > msgTagsSerialized ;
}
if ( draft . version > = 7021 ) {
draft . stream > > msgReplyTo ;
if ( draft . version > = 8001 ) {
draft . stream > > msgPreviewCancelled ;
if ( ! draft . stream . atEnd ( ) ) {
draft . stream > > editData . text ;
if ( draft . version > = 9048 ) {
draft . stream > > editTagsSerialized ;
}
draft . stream > > editMsgId > > editPreviewCancelled ;
}
2014-11-22 09:45:04 +00:00
}
}
2016-09-15 19:15:49 +00:00
if ( draftPeer ! = peer ) {
clearKey ( j . value ( ) ) ;
_draftsMap . erase ( j ) ;
clearDraftCursors ( peer ) ;
return ;
}
2014-11-22 09:45:04 +00:00
2016-11-15 11:56:49 +00:00
msgData . tags = Ui : : FlatTextarea : : deserializeTagsList ( msgTagsSerialized , msgData . text . size ( ) ) ;
editData . tags = Ui : : FlatTextarea : : deserializeTagsList ( editTagsSerialized , editData . text . size ( ) ) ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
MessageCursor msgCursor , editCursor ;
_readDraftCursors ( peer , msgCursor , editCursor ) ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
if ( ! h - > localDraft ( ) ) {
if ( msgData . text . isEmpty ( ) & & ! msgReplyTo ) {
h - > clearLocalDraft ( ) ;
} else {
2017-02-21 13:45:56 +00:00
h - > setLocalDraft ( std : : make_unique < Data : : Draft > ( msgData , msgReplyTo , msgCursor , msgPreviewCancelled ) ) ;
2014-11-22 09:45:04 +00:00
}
}
2016-09-15 19:15:49 +00:00
if ( ! editMsgId ) {
h - > clearEditDraft ( ) ;
} else {
2017-02-21 13:45:56 +00:00
h - > setEditDraft ( std : : make_unique < Data : : Draft > ( editData , editMsgId , editCursor , editPreviewCancelled ) ) ;
2016-09-15 19:15:49 +00:00
}
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
void writeDraftCursors ( const PeerId & peer , const MessageCursor & msgCursor , const MessageCursor & editCursor ) {
if ( ! _working ( ) ) return ;
2016-01-11 15:43:29 +00:00
2016-09-15 19:15:49 +00:00
if ( msgCursor = = MessageCursor ( ) & & editCursor = = MessageCursor ( ) ) {
clearDraftCursors ( peer ) ;
} else {
DraftsMap : : const_iterator i = _draftCursorsMap . constFind ( peer ) ;
if ( i = = _draftCursorsMap . cend ( ) ) {
i = _draftCursorsMap . insert ( peer , genKey ( ) ) ;
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Fast ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ( sizeof ( quint64 ) + sizeof ( qint32 ) * 3 ) ;
data . stream < < quint64 ( peer ) < < qint32 ( msgCursor . position ) < < qint32 ( msgCursor . anchor ) < < qint32 ( msgCursor . scroll ) ;
data . stream < < qint32 ( editCursor . position ) < < qint32 ( editCursor . anchor ) < < qint32 ( editCursor . scroll ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
FileWriteDescriptor file ( i . value ( ) ) ;
file . writeEncrypted ( data ) ;
}
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
bool hasDraftCursors ( const PeerId & peer ) {
return _draftCursorsMap . contains ( peer ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
bool hasDraft ( const PeerId & peer ) {
return _draftsMap . contains ( peer ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
void writeFileLocation ( MediaKey location , const FileLocation & local ) {
if ( local . fname . isEmpty ( ) ) return ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
FileLocationAliases : : const_iterator aliasIt = _fileLocationAliases . constFind ( location ) ;
if ( aliasIt ! = _fileLocationAliases . cend ( ) ) {
location = aliasIt . value ( ) ;
}
FileLocationPairs : : iterator i = _fileLocationPairs . find ( local . fname ) ;
if ( i ! = _fileLocationPairs . cend ( ) ) {
if ( i . value ( ) . second = = local ) {
if ( i . value ( ) . first ! = location ) {
_fileLocationAliases . insert ( location , i . value ( ) . first ) ;
2017-03-28 12:30:38 +00:00
_writeLocations ( WriteMapWhen : : Fast ) ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
return ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
if ( i . value ( ) . first ! = location ) {
for ( FileLocations : : iterator j = _fileLocations . find ( i . value ( ) . first ) , e = _fileLocations . end ( ) ; ( j ! = e ) & & ( j . key ( ) = = i . value ( ) . first ) ; ) {
if ( j . value ( ) = = i . value ( ) . second ) {
_fileLocations . erase ( j ) ;
break ;
}
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
_fileLocationPairs . erase ( i ) ;
}
}
_fileLocations . insert ( location , local ) ;
_fileLocationPairs . insert ( local . fname , FileLocationPair ( location , local ) ) ;
2017-03-28 12:30:38 +00:00
_writeLocations ( WriteMapWhen : : Fast ) ;
2016-09-15 19:15:49 +00:00
}
FileLocation readFileLocation ( MediaKey location , bool check ) {
FileLocationAliases : : const_iterator aliasIt = _fileLocationAliases . constFind ( location ) ;
if ( aliasIt ! = _fileLocationAliases . cend ( ) ) {
location = aliasIt . value ( ) ;
}
2015-06-10 12:48:26 +00:00
2016-09-15 19:15:49 +00:00
FileLocations : : iterator i = _fileLocations . find ( location ) ;
for ( FileLocations : : iterator i = _fileLocations . find ( location ) ; ( i ! = _fileLocations . end ( ) ) & & ( i . key ( ) = = location ) ; ) {
if ( check ) {
if ( ! i . value ( ) . check ( ) ) {
_fileLocationPairs . remove ( i . value ( ) . fname ) ;
i = _fileLocations . erase ( i ) ;
_writeLocations ( ) ;
continue ;
2015-06-10 12:48:26 +00:00
}
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
return i . value ( ) ;
}
return FileLocation ( ) ;
}
qint32 _storageImageSize ( qint32 rawlen ) {
// fulllen + storagekey + type + len + data
qint32 result = sizeof ( uint32 ) + sizeof ( quint64 ) * 2 + sizeof ( quint32 ) + sizeof ( quint32 ) + rawlen ;
if ( result & 0x0F ) result + = 0x10 - ( result & 0x0F ) ;
result + = tdfMagicLen + sizeof ( qint32 ) + sizeof ( quint32 ) + 0x10 + 0x10 ; // magic + version + len of encrypted + part of sha1 + md5
return result ;
}
qint32 _storageStickerSize ( qint32 rawlen ) {
// fulllen + storagekey + len + data
qint32 result = sizeof ( uint32 ) + sizeof ( quint64 ) * 2 + sizeof ( quint32 ) + rawlen ;
if ( result & 0x0F ) result + = 0x10 - ( result & 0x0F ) ;
result + = tdfMagicLen + sizeof ( qint32 ) + sizeof ( quint32 ) + 0x10 + 0x10 ; // magic + version + len of encrypted + part of sha1 + md5
return result ;
}
qint32 _storageAudioSize ( qint32 rawlen ) {
// fulllen + storagekey + len + data
qint32 result = sizeof ( uint32 ) + sizeof ( quint64 ) * 2 + sizeof ( quint32 ) + rawlen ;
if ( result & 0x0F ) result + = 0x10 - ( result & 0x0F ) ;
result + = tdfMagicLen + sizeof ( qint32 ) + sizeof ( quint32 ) + 0x10 + 0x10 ; // magic + version + len of encrypted + part of sha1 + md5
return result ;
}
void writeImage ( const StorageKey & location , const ImagePtr & image ) {
if ( image - > isNull ( ) | | ! image - > loaded ( ) ) return ;
if ( _imagesMap . constFind ( location ) ! = _imagesMap . cend ( ) ) return ;
2017-03-04 11:28:21 +00:00
image - > forget ( ) ;
writeImage ( location , StorageImageSaved ( image - > savedData ( ) ) , false ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
void writeImage ( const StorageKey & location , const StorageImageSaved & image , bool overwrite ) {
if ( ! _working ( ) ) return ;
qint32 size = _storageImageSize ( image . data . size ( ) ) ;
StorageMap : : const_iterator i = _imagesMap . constFind ( location ) ;
if ( i = = _imagesMap . cend ( ) ) {
2016-10-28 12:44:28 +00:00
i = _imagesMap . insert ( location , FileDesc ( genKey ( FileOption : : User ) , size ) ) ;
2016-09-15 19:15:49 +00:00
_storageImagesSize + = size ;
_mapChanged = true ;
_writeMap ( ) ;
} else if ( ! overwrite ) {
return ;
}
2017-03-04 11:28:21 +00:00
auto legacyTypeField = 0 ;
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ( sizeof ( quint64 ) * 2 + sizeof ( quint32 ) + sizeof ( quint32 ) + image . data . size ( ) ) ;
2017-03-04 11:28:21 +00:00
data . stream < < quint64 ( location . first ) < < quint64 ( location . second ) < < quint32 ( legacyTypeField ) < < image . data ;
2016-10-28 12:44:28 +00:00
FileWriteDescriptor file ( i . value ( ) . first , FileOption : : User ) ;
2016-09-15 19:15:49 +00:00
file . writeEncrypted ( data ) ;
if ( i . value ( ) . second ! = size ) {
_storageImagesSize + = size ;
_storageImagesSize - = i . value ( ) . second ;
_imagesMap [ location ] . second = size ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
}
class AbstractCachedLoadTask : public Task {
public :
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
AbstractCachedLoadTask ( const FileKey & key , const StorageKey & location , bool readImageFlag , mtpFileLoader * loader ) :
_key ( key ) , _location ( location ) , _readImageFlag ( readImageFlag ) , _loader ( loader ) , _result ( 0 ) {
}
void process ( ) {
FileReadDescriptor image ;
2016-10-28 12:44:28 +00:00
if ( ! readEncryptedFile ( image , _key , FileOption : : User ) ) {
2015-03-02 12:34:16 +00:00
return ;
}
2016-09-15 19:15:49 +00:00
QByteArray imageData ;
quint64 locFirst , locSecond ;
2017-03-04 11:28:21 +00:00
quint32 legacyTypeField = 0 ;
readFromStream ( image . stream , locFirst , locSecond , imageData ) ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
// we're saving files now before we have actual location
//if (locFirst != _location.first || locSecond != _location.second) {
// return;
//}
2015-03-02 12:34:16 +00:00
2017-03-04 11:28:21 +00:00
_result = new Result ( imageData , _readImageFlag ) ;
2016-09-15 19:15:49 +00:00
}
void finish ( ) {
if ( _result ) {
_loader - > localLoaded ( _result - > image , _result - > format , _result - > pixmap ) ;
} else {
clearInMap ( ) ;
_loader - > localLoaded ( StorageImageSaved ( ) ) ;
2015-05-14 16:50:04 +00:00
}
2016-09-15 19:15:49 +00:00
}
2017-03-04 11:28:21 +00:00
virtual void readFromStream ( QDataStream & stream , quint64 & first , quint64 & second , QByteArray & data ) = 0 ;
2016-09-15 19:15:49 +00:00
virtual void clearInMap ( ) = 0 ;
virtual ~ AbstractCachedLoadTask ( ) {
2016-10-07 16:45:45 +00:00
delete base : : take ( _result ) ;
2016-09-15 19:15:49 +00:00
}
2015-05-14 16:50:04 +00:00
2016-09-15 19:15:49 +00:00
protected :
FileKey _key ;
StorageKey _location ;
bool _readImageFlag ;
struct Result {
2017-03-04 11:28:21 +00:00
Result ( const QByteArray & data , bool readImageFlag ) : image ( data ) {
2016-09-15 19:15:49 +00:00
if ( readImageFlag ) {
2017-03-04 11:28:21 +00:00
auto realFormat = QByteArray ( ) ;
pixmap = App : : pixmapFromImageInPlace ( App : : readImage ( data , & realFormat , false ) ) ;
2016-09-15 19:15:49 +00:00
if ( ! pixmap . isNull ( ) ) {
2017-03-04 11:28:21 +00:00
format = realFormat ;
2016-09-15 19:15:49 +00:00
}
2015-06-10 12:48:26 +00:00
}
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
StorageImageSaved image ;
QByteArray format ;
QPixmap pixmap ;
2017-03-04 11:28:21 +00:00
2016-09-15 19:15:49 +00:00
} ;
mtpFileLoader * _loader ;
Result * _result ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
} ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
class ImageLoadTask : public AbstractCachedLoadTask {
public :
ImageLoadTask ( const FileKey & key , const StorageKey & location , mtpFileLoader * loader ) :
AbstractCachedLoadTask ( key , location , true , loader ) {
}
2017-03-04 11:28:21 +00:00
void readFromStream ( QDataStream & stream , quint64 & first , quint64 & second , QByteArray & data ) override {
qint32 legacyTypeField = 0 ;
stream > > first > > second > > legacyTypeField > > data ;
2016-09-15 19:15:49 +00:00
}
2017-03-04 19:36:59 +00:00
void clearInMap ( ) override {
2016-09-15 19:15:49 +00:00
StorageMap : : iterator j = _imagesMap . find ( _location ) ;
if ( j ! = _imagesMap . cend ( ) & & j - > first = = _key ) {
2016-10-28 12:44:28 +00:00
clearKey ( _key , FileOption : : User ) ;
2016-09-15 19:15:49 +00:00
_storageImagesSize - = j - > second ;
_imagesMap . erase ( j ) ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
}
} ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
TaskId startImageLoad ( const StorageKey & location , mtpFileLoader * loader ) {
StorageMap : : const_iterator j = _imagesMap . constFind ( location ) ;
if ( j = = _imagesMap . cend ( ) | | ! _localLoader ) {
return 0 ;
}
2016-11-28 15:45:07 +00:00
return _localLoader - > addTask ( MakeShared < ImageLoadTask > ( j - > first , location , loader ) ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
int32 hasImages ( ) {
return _imagesMap . size ( ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
qint64 storageImagesSize ( ) {
return _storageImagesSize ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
void writeStickerImage ( const StorageKey & location , const QByteArray & sticker , bool overwrite ) {
if ( ! _working ( ) ) return ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
qint32 size = _storageStickerSize ( sticker . size ( ) ) ;
StorageMap : : const_iterator i = _stickerImagesMap . constFind ( location ) ;
if ( i = = _stickerImagesMap . cend ( ) ) {
2016-10-28 12:44:28 +00:00
i = _stickerImagesMap . insert ( location , FileDesc ( genKey ( FileOption : : User ) , size ) ) ;
2016-09-15 19:15:49 +00:00
_storageStickersSize + = size ;
_mapChanged = true ;
_writeMap ( ) ;
} else if ( ! overwrite ) {
return ;
}
EncryptedDescriptor data ( sizeof ( quint64 ) * 2 + sizeof ( quint32 ) + sizeof ( quint32 ) + sticker . size ( ) ) ;
data . stream < < quint64 ( location . first ) < < quint64 ( location . second ) < < sticker ;
2016-10-28 12:44:28 +00:00
FileWriteDescriptor file ( i . value ( ) . first , FileOption : : User ) ;
2016-09-15 19:15:49 +00:00
file . writeEncrypted ( data ) ;
if ( i . value ( ) . second ! = size ) {
_storageStickersSize + = size ;
_storageStickersSize - = i . value ( ) . second ;
_stickerImagesMap [ location ] . second = size ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
class StickerImageLoadTask : public AbstractCachedLoadTask {
public :
StickerImageLoadTask ( const FileKey & key , const StorageKey & location , mtpFileLoader * loader ) :
AbstractCachedLoadTask ( key , location , true , loader ) {
}
2017-03-04 11:28:21 +00:00
void readFromStream ( QDataStream & stream , quint64 & first , quint64 & second , QByteArray & data ) {
2016-09-15 19:15:49 +00:00
stream > > first > > second > > data ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
void clearInMap ( ) {
auto j = _stickerImagesMap . find ( _location ) ;
if ( j ! = _stickerImagesMap . cend ( ) & & j - > first = = _key ) {
2016-10-28 12:44:28 +00:00
clearKey ( j . value ( ) . first , FileOption : : User ) ;
2016-09-15 19:15:49 +00:00
_storageStickersSize - = j . value ( ) . second ;
_stickerImagesMap . erase ( j ) ;
}
}
} ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
TaskId startStickerImageLoad ( const StorageKey & location , mtpFileLoader * loader ) {
auto j = _stickerImagesMap . constFind ( location ) ;
if ( j = = _stickerImagesMap . cend ( ) | | ! _localLoader ) {
return 0 ;
2015-03-02 12:34:16 +00:00
}
2016-11-28 15:45:07 +00:00
return _localLoader - > addTask ( MakeShared < StickerImageLoadTask > ( j - > first , location , loader ) ) ;
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
bool willStickerImageLoad ( const StorageKey & location ) {
return _stickerImagesMap . constFind ( location ) ! = _stickerImagesMap . cend ( ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
bool copyStickerImage ( const StorageKey & oldLocation , const StorageKey & newLocation ) {
auto i = _stickerImagesMap . constFind ( oldLocation ) ;
if ( i = = _stickerImagesMap . cend ( ) ) {
return false ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
_stickerImagesMap . insert ( newLocation , i . value ( ) ) ;
_mapChanged = true ;
_writeMap ( ) ;
return true ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
int32 hasStickers ( ) {
return _stickerImagesMap . size ( ) ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
qint64 storageStickersSize ( ) {
return _storageStickersSize ;
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
void writeAudio ( const StorageKey & location , const QByteArray & audio , bool overwrite ) {
if ( ! _working ( ) ) return ;
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
qint32 size = _storageAudioSize ( audio . size ( ) ) ;
StorageMap : : const_iterator i = _audiosMap . constFind ( location ) ;
if ( i = = _audiosMap . cend ( ) ) {
2016-10-28 12:44:28 +00:00
i = _audiosMap . insert ( location , FileDesc ( genKey ( FileOption : : User ) , size ) ) ;
2016-09-15 19:15:49 +00:00
_storageAudiosSize + = size ;
2015-03-02 12:34:16 +00:00
_mapChanged = true ;
2016-09-15 19:15:49 +00:00
_writeMap ( ) ;
} else if ( ! overwrite ) {
return ;
}
EncryptedDescriptor data ( sizeof ( quint64 ) * 2 + sizeof ( quint32 ) + sizeof ( quint32 ) + audio . size ( ) ) ;
data . stream < < quint64 ( location . first ) < < quint64 ( location . second ) < < audio ;
2016-10-28 12:44:28 +00:00
FileWriteDescriptor file ( i . value ( ) . first , FileOption : : User ) ;
2016-09-15 19:15:49 +00:00
file . writeEncrypted ( data ) ;
if ( i . value ( ) . second ! = size ) {
_storageAudiosSize + = size ;
_storageAudiosSize - = i . value ( ) . second ;
_audiosMap [ location ] . second = size ;
2015-03-02 12:34:16 +00:00
}
2016-09-15 19:15:49 +00:00
}
2015-03-02 12:34:16 +00:00
2016-09-15 19:15:49 +00:00
class AudioLoadTask : public AbstractCachedLoadTask {
public :
AudioLoadTask ( const FileKey & key , const StorageKey & location , mtpFileLoader * loader ) :
AbstractCachedLoadTask ( key , location , false , loader ) {
}
2017-03-04 11:28:21 +00:00
void readFromStream ( QDataStream & stream , quint64 & first , quint64 & second , QByteArray & data ) {
2016-09-15 19:15:49 +00:00
stream > > first > > second > > data ;
}
void clearInMap ( ) {
auto j = _audiosMap . find ( _location ) ;
if ( j ! = _audiosMap . cend ( ) & & j - > first = = _key ) {
2016-10-28 12:44:28 +00:00
clearKey ( j . value ( ) . first , FileOption : : User ) ;
2016-09-15 19:15:49 +00:00
_storageAudiosSize - = j . value ( ) . second ;
_audiosMap . erase ( j ) ;
2014-11-22 09:45:04 +00:00
}
}
2016-09-15 19:15:49 +00:00
} ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
TaskId startAudioLoad ( const StorageKey & location , mtpFileLoader * loader ) {
auto j = _audiosMap . constFind ( location ) ;
if ( j = = _audiosMap . cend ( ) | | ! _localLoader ) {
return 0 ;
2014-12-03 13:10:32 +00:00
}
2016-11-28 15:45:07 +00:00
return _localLoader - > addTask ( MakeShared < AudioLoadTask > ( j - > first , location , loader ) ) ;
2016-09-15 19:15:49 +00:00
}
2014-12-03 13:10:32 +00:00
2016-09-15 19:15:49 +00:00
bool copyAudio ( const StorageKey & oldLocation , const StorageKey & newLocation ) {
auto i = _audiosMap . constFind ( oldLocation ) ;
if ( i = = _audiosMap . cend ( ) ) {
return false ;
2015-08-13 15:11:07 +00:00
}
2016-09-15 19:15:49 +00:00
_audiosMap . insert ( newLocation , i . value ( ) ) ;
_mapChanged = true ;
_writeMap ( ) ;
return true ;
}
2015-08-13 15:11:07 +00:00
2016-09-15 19:15:49 +00:00
int32 hasAudios ( ) {
return _audiosMap . size ( ) ;
}
2016-05-05 16:04:17 +00:00
2016-09-15 19:15:49 +00:00
qint64 storageAudiosSize ( ) {
return _storageAudiosSize ;
}
2016-02-25 10:32:31 +00:00
2016-09-15 19:15:49 +00:00
qint32 _storageWebFileSize ( const QString & url , qint32 rawlen ) {
// fulllen + url + len + data
qint32 result = sizeof ( uint32 ) + Serialize : : stringSize ( url ) + sizeof ( quint32 ) + rawlen ;
if ( result & 0x0F ) result + = 0x10 - ( result & 0x0F ) ;
result + = tdfMagicLen + sizeof ( qint32 ) + sizeof ( quint32 ) + 0x10 + 0x10 ; // magic + version + len of encrypted + part of sha1 + md5
return result ;
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
void writeWebFile ( const QString & url , const QByteArray & content , bool overwrite ) {
if ( ! _working ( ) ) return ;
qint32 size = _storageWebFileSize ( url , content . size ( ) ) ;
WebFilesMap : : const_iterator i = _webFilesMap . constFind ( url ) ;
if ( i = = _webFilesMap . cend ( ) ) {
2016-10-28 12:44:28 +00:00
i = _webFilesMap . insert ( url , FileDesc ( genKey ( FileOption : : User ) , size ) ) ;
2016-09-15 19:15:49 +00:00
_storageWebFilesSize + = size ;
_writeLocations ( ) ;
} else if ( ! overwrite ) {
return ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ( Serialize : : stringSize ( url ) + sizeof ( quint32 ) + sizeof ( quint32 ) + content . size ( ) ) ;
data . stream < < url < < content ;
2016-10-28 12:44:28 +00:00
FileWriteDescriptor file ( i . value ( ) . first , FileOption : : User ) ;
2016-09-15 19:15:49 +00:00
file . writeEncrypted ( data ) ;
if ( i . value ( ) . second ! = size ) {
_storageWebFilesSize + = size ;
_storageWebFilesSize - = i . value ( ) . second ;
_webFilesMap [ url ] . second = size ;
2016-02-25 10:32:31 +00:00
}
2016-09-15 19:15:49 +00:00
}
2016-02-25 10:32:31 +00:00
2016-09-15 19:15:49 +00:00
class WebFileLoadTask : public Task {
public :
WebFileLoadTask ( const FileKey & key , const QString & url , webFileLoader * loader )
: _key ( key )
, _url ( url )
, _loader ( loader )
, _result ( 0 ) {
}
void process ( ) {
FileReadDescriptor image ;
2016-10-28 12:44:28 +00:00
if ( ! readEncryptedFile ( image , _key , FileOption : : User ) ) {
2016-02-25 10:32:31 +00:00
return ;
}
2016-09-15 19:15:49 +00:00
QByteArray imageData ;
QString url ;
image . stream > > url > > imageData ;
2016-02-25 10:32:31 +00:00
2017-03-04 11:28:21 +00:00
_result = new Result ( imageData ) ;
2016-09-15 19:15:49 +00:00
}
void finish ( ) {
if ( _result ) {
_loader - > localLoaded ( _result - > image , _result - > format , _result - > pixmap ) ;
} else {
WebFilesMap : : iterator j = _webFilesMap . find ( _url ) ;
if ( j ! = _webFilesMap . cend ( ) & & j - > first = = _key ) {
2016-10-28 12:44:28 +00:00
clearKey ( j . value ( ) . first , FileOption : : User ) ;
2016-09-15 19:15:49 +00:00
_storageWebFilesSize - = j . value ( ) . second ;
_webFilesMap . erase ( j ) ;
}
_loader - > localLoaded ( StorageImageSaved ( ) ) ;
2016-02-25 10:32:31 +00:00
}
2016-09-15 19:15:49 +00:00
}
virtual ~ WebFileLoadTask ( ) {
2016-10-07 16:45:45 +00:00
delete base : : take ( _result ) ;
2016-02-25 10:32:31 +00:00
}
2016-09-15 19:15:49 +00:00
protected :
FileKey _key ;
QString _url ;
struct Result {
2017-03-04 11:28:21 +00:00
explicit Result ( const QByteArray & data ) : image ( data ) {
2016-09-15 19:15:49 +00:00
QByteArray guessFormat ;
pixmap = App : : pixmapFromImageInPlace ( App : : readImage ( data , & guessFormat , false ) ) ;
if ( ! pixmap . isNull ( ) ) {
format = guessFormat ;
}
2016-02-25 10:32:31 +00:00
}
2016-09-15 19:15:49 +00:00
StorageImageSaved image ;
QByteArray format ;
QPixmap pixmap ;
2017-03-04 11:28:21 +00:00
2016-09-15 19:15:49 +00:00
} ;
webFileLoader * _loader ;
Result * _result ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
} ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
TaskId startWebFileLoad ( const QString & url , webFileLoader * loader ) {
WebFilesMap : : const_iterator j = _webFilesMap . constFind ( url ) ;
if ( j = = _webFilesMap . cend ( ) | | ! _localLoader ) {
return 0 ;
}
2016-11-28 15:45:07 +00:00
return _localLoader - > addTask ( MakeShared < WebFileLoadTask > ( j - > first , url , loader ) ) ;
2016-09-15 19:15:49 +00:00
}
2016-02-25 10:32:31 +00:00
2016-09-15 19:15:49 +00:00
int32 hasWebFiles ( ) {
return _webFilesMap . size ( ) ;
}
2016-05-05 16:04:17 +00:00
2016-09-15 19:15:49 +00:00
qint64 storageWebFilesSize ( ) {
return _storageWebFilesSize ;
}
2016-02-25 10:32:31 +00:00
2016-09-15 19:15:49 +00:00
class CountWaveformTask : public Task {
public :
CountWaveformTask ( DocumentData * doc )
: _doc ( doc )
, _loc ( doc - > location ( true ) )
, _data ( doc - > data ( ) )
, _wavemax ( 0 ) {
if ( _data . isEmpty ( ) & & ! _loc . accessEnable ( ) ) {
_doc = 0 ;
}
}
void process ( ) {
if ( ! _doc ) return ;
_waveform = audioCountWaveform ( _loc , _data ) ;
uchar wavemax = 0 ;
for ( int32 i = 0 , l = _waveform . size ( ) ; i < l ; + + i ) {
uchar waveat = _waveform . at ( i ) ;
if ( wavemax < waveat ) wavemax = waveat ;
}
_wavemax = wavemax ;
}
void finish ( ) {
2017-12-10 10:26:58 +00:00
if ( const auto voice = _doc ? _doc - > voice ( ) : nullptr ) {
2016-09-15 19:15:49 +00:00
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 ;
}
2016-09-27 13:37:18 +00:00
auto & items = App : : documentItems ( ) ;
auto i = items . constFind ( _doc ) ;
2016-09-15 19:15:49 +00:00
if ( i ! = items . cend ( ) ) {
2016-09-27 13:37:18 +00:00
for_const ( auto item , i . value ( ) ) {
2017-10-05 15:35:52 +00:00
Auth ( ) . data ( ) . requestItemRepaint ( item ) ;
2016-09-15 19:15:49 +00:00
}
2016-06-03 18:24:27 +00:00
}
2016-02-25 10:32:31 +00:00
}
2016-09-15 19:15:49 +00:00
}
virtual ~ CountWaveformTask ( ) {
if ( _data . isEmpty ( ) & & _doc ) {
_loc . accessDisable ( ) ;
2016-02-25 10:32:31 +00:00
}
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
protected :
DocumentData * _doc ;
FileLocation _loc ;
QByteArray _data ;
VoiceWaveform _waveform ;
char _wavemax ;
2016-02-25 10:32:31 +00:00
2016-09-15 19:15:49 +00:00
} ;
2016-02-25 10:32:31 +00:00
2016-09-15 19:15:49 +00:00
void countVoiceWaveform ( DocumentData * document ) {
2017-12-10 10:26:58 +00:00
if ( const auto voice = document - > voice ( ) ) {
2016-09-15 19:15:49 +00:00
if ( _localLoader ) {
voice - > waveform . resize ( 1 + sizeof ( TaskId ) ) ;
voice - > waveform [ 0 ] = - 1 ; // counting
2016-11-28 15:45:07 +00:00
TaskId taskId = _localLoader - > addTask ( MakeShared < CountWaveformTask > ( document ) ) ;
2016-09-15 19:15:49 +00:00
memcpy ( voice - > waveform . data ( ) + 1 , & taskId , sizeof ( taskId ) ) ;
2014-11-22 09:45:04 +00:00
}
}
2016-09-15 19:15:49 +00:00
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
void cancelTask ( TaskId id ) {
if ( _localLoader ) {
_localLoader - > cancelTask ( id ) ;
2016-05-31 09:46:31 +00:00
}
2016-09-15 19:15:49 +00:00
}
2016-05-31 09:46:31 +00:00
2016-09-15 19:15:49 +00:00
void _writeStickerSet ( QDataStream & stream , const Stickers : : Set & set ) {
bool notLoaded = ( set . flags & MTPDstickerSet_ClientFlag : : f_not_loaded ) ;
if ( notLoaded ) {
stream < < quint64 ( set . id ) < < quint64 ( set . access ) < < set . title < < set . shortName < < qint32 ( - set . count ) < < qint32 ( set . hash ) < < qint32 ( set . flags ) ;
return ;
} else {
if ( set . stickers . isEmpty ( ) ) return ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
stream < < quint64 ( set . id ) < < quint64 ( set . access ) < < set . title < < set . shortName < < qint32 ( set . stickers . size ( ) ) < < qint32 ( set . hash ) < < qint32 ( set . flags ) ;
2017-11-05 17:07:27 +00:00
for ( auto j = set . stickers . cbegin ( ) , e = set . stickers . cend ( ) ; j ! = e ; + + j ) {
2016-09-15 19:15:49 +00:00
Serialize : : Document : : writeToStream ( stream , * j ) ;
}
2014-12-05 13:44:27 +00:00
2016-09-15 19:15:49 +00:00
if ( AppVersion > 9018 ) {
stream < < qint32 ( set . emoji . size ( ) ) ;
2017-02-15 08:50:11 +00:00
for ( auto j = set . emoji . cbegin ( ) , e = set . emoji . cend ( ) ; j ! = e ; + + j ) {
stream < < j . key ( ) - > id ( ) < < qint32 ( j - > size ( ) ) ;
2016-09-15 19:15:49 +00:00
for ( int32 k = 0 , l = j - > size ( ) ; k < l ; + + k ) {
stream < < quint64 ( j - > at ( k ) - > id ) ;
}
2015-06-30 21:07:05 +00:00
}
2016-09-15 19:15:49 +00:00
}
}
2015-06-30 21:07:05 +00:00
2016-09-15 19:15:49 +00:00
// In generic method _writeStickerSets() we look through all the sets and call a
// callback on each set to see, if we write it, skip it or abort the whole write.
enum class StickerSetCheckResult {
Write ,
Skip ,
Abort ,
} ;
// CheckSet is a functor on Stickers::Set, which returns a StickerSetCheckResult.
template < typename CheckSet >
void _writeStickerSets ( FileKey & stickersKey , CheckSet checkSet , const Stickers : : Order & order ) {
if ( ! _working ( ) ) return ;
2017-11-05 17:07:27 +00:00
auto & sets = Auth ( ) . data ( ) . stickerSets ( ) ;
2016-09-15 19:15:49 +00:00
if ( sets . isEmpty ( ) ) {
if ( stickersKey ) {
clearKey ( stickersKey ) ;
stickersKey = 0 ;
_mapChanged = true ;
2014-12-05 13:44:27 +00:00
}
2016-09-15 19:15:49 +00:00
_writeMap ( ) ;
return ;
2014-12-05 13:44:27 +00:00
}
2016-09-15 19:15:49 +00:00
int32 setsCount = 0 ;
QByteArray hashToWrite ;
quint32 size = sizeof ( quint32 ) + Serialize : : bytearraySize ( hashToWrite ) ;
for_const ( auto & set , sets ) {
auto result = checkSet ( set ) ;
if ( result = = StickerSetCheckResult : : Abort ) {
return ;
} else if ( result = = StickerSetCheckResult : : Skip ) {
continue ;
}
2014-12-05 13:44:27 +00:00
2016-09-15 19:15:49 +00:00
// id + access + title + shortName + stickersCount + hash + flags
size + = sizeof ( quint64 ) * 2 + Serialize : : stringSize ( set . title ) + Serialize : : stringSize ( set . shortName ) + sizeof ( quint32 ) + sizeof ( qint32 ) * 2 ;
for_const ( auto & sticker , set . stickers ) {
size + = Serialize : : Document : : sizeInStream ( sticker ) ;
2015-06-30 21:07:05 +00:00
}
2016-09-15 19:15:49 +00:00
size + = sizeof ( qint32 ) ; // emojiCount
for ( auto j = set . emoji . cbegin ( ) , e = set . emoji . cend ( ) ; j ! = e ; + + j ) {
2017-02-15 08:50:11 +00:00
size + = Serialize : : stringSize ( j . key ( ) - > id ( ) ) + sizeof ( qint32 ) + ( j - > size ( ) * sizeof ( quint64 ) ) ;
2014-12-05 13:44:27 +00:00
}
2016-09-15 19:15:49 +00:00
+ + setsCount ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
if ( ! setsCount & & order . isEmpty ( ) ) {
if ( stickersKey ) {
clearKey ( stickersKey ) ;
stickersKey = 0 ;
_mapChanged = true ;
}
_writeMap ( ) ;
return ;
2015-01-02 14:55:24 +00:00
}
2016-09-15 19:15:49 +00:00
size + = sizeof ( qint32 ) + ( order . size ( ) * sizeof ( quint64 ) ) ;
2015-01-02 14:55:24 +00:00
2016-09-15 19:15:49 +00:00
if ( ! stickersKey ) {
stickersKey = genKey ( ) ;
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Fast ) ;
2016-09-15 19:15:49 +00:00
}
EncryptedDescriptor data ( size ) ;
data . stream < < quint32 ( setsCount ) < < hashToWrite ;
for_const ( auto & set , sets ) {
auto result = checkSet ( set ) ;
if ( result = = StickerSetCheckResult : : Abort ) {
return ;
} else if ( result = = StickerSetCheckResult : : Skip ) {
continue ;
}
_writeStickerSet ( data . stream , set ) ;
2015-01-02 14:55:24 +00:00
}
2016-09-15 19:15:49 +00:00
data . stream < < order ;
2015-01-02 14:55:24 +00:00
2016-09-15 19:15:49 +00:00
FileWriteDescriptor file ( stickersKey ) ;
file . writeEncrypted ( data ) ;
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
void _readStickerSets ( FileKey & stickersKey , Stickers : : Order * outOrder = nullptr , MTPDstickerSet : : Flags readingFlags = 0 ) {
FileReadDescriptor stickers ;
if ( ! readEncryptedFile ( stickers , stickersKey ) ) {
clearKey ( stickersKey ) ;
stickersKey = 0 ;
_writeMap ( ) ;
return ;
2014-11-22 09:45:04 +00:00
}
2017-08-31 16:28:58 +00:00
bool readingInstalled = ( readingFlags = = MTPDstickerSet : : Flag : : f_installed ) ;
2014-11-22 09:45:04 +00:00
2017-11-05 17:07:27 +00:00
auto & sets = Auth ( ) . data ( ) . stickerSetsRef ( ) ;
2016-09-15 19:15:49 +00:00
if ( outOrder ) outOrder - > clear ( ) ;
quint32 cnt ;
QByteArray hash ;
stickers . stream > > cnt > > hash ; // ignore hash, it is counted
if ( readingInstalled & & stickers . version < 8019 ) { // bad data in old caches
cnt + = 2 ; // try to read at least something
}
for ( uint32 i = 0 ; i < cnt ; + + i ) {
quint64 setId = 0 , setAccess = 0 ;
QString setTitle , setShortName ;
qint32 scnt = 0 ;
stickers . stream > > setId > > setAccess > > setTitle > > setShortName > > scnt ;
2017-08-31 16:28:58 +00:00
qint32 setHash = 0 ;
MTPDstickerSet : : Flags setFlags = 0 ;
2016-09-15 19:15:49 +00:00
if ( stickers . version > 8033 ) {
2017-08-31 16:28:58 +00:00
qint32 setFlagsValue = 0 ;
stickers . stream > > setHash > > setFlagsValue ;
2017-09-26 11:49:16 +00:00
setFlags = MTPDstickerSet : : Flags : : from_raw ( setFlagsValue ) ;
2017-08-31 16:28:58 +00:00
if ( setFlags & MTPDstickerSet_ClientFlag : : f_not_loaded__old ) {
setFlags & = ~ MTPDstickerSet_ClientFlag : : f_not_loaded__old ;
setFlags | = MTPDstickerSet_ClientFlag : : f_not_loaded ;
2016-09-15 19:15:49 +00:00
}
}
if ( readingInstalled & & stickers . version < 9061 ) {
2017-08-31 16:28:58 +00:00
setFlags | = MTPDstickerSet : : Flag : : f_installed ;
2016-09-15 19:15:49 +00:00
}
if ( setId = = Stickers : : DefaultSetId ) {
setTitle = lang ( lng_stickers_default_set ) ;
2017-05-15 07:33:31 +00:00
setFlags | = MTPDstickerSet : : Flag : : f_official | MTPDstickerSet_ClientFlag : : f_special ;
2016-09-15 19:15:49 +00:00
if ( readingInstalled & & outOrder & & stickers . version < 9061 ) {
outOrder - > push_front ( setId ) ;
}
} else if ( setId = = Stickers : : CustomSetId ) {
2016-11-22 09:48:13 +00:00
setTitle = qsl ( " Custom stickers " ) ;
2017-08-31 16:28:58 +00:00
setFlags | = MTPDstickerSet_ClientFlag : : f_special ;
2016-09-15 19:15:49 +00:00
} else if ( setId = = Stickers : : CloudRecentSetId ) {
setTitle = lang ( lng_recent_stickers ) ;
2017-08-31 16:28:58 +00:00
setFlags | = MTPDstickerSet_ClientFlag : : f_special ;
2017-08-02 15:07:28 +00:00
} else if ( setId = = Stickers : : FavedSetId ) {
2017-09-28 20:11:10 +00:00
setTitle = Lang : : Hard : : FavedSetTitle ( ) ;
2017-08-31 16:28:58 +00:00
setFlags | = MTPDstickerSet_ClientFlag : : f_special ;
2016-09-15 19:15:49 +00:00
} else if ( setId ) {
if ( readingInstalled & & outOrder & & stickers . version < 9061 ) {
outOrder - > push_back ( setId ) ;
}
} else {
continue ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
auto it = sets . find ( setId ) ;
if ( it = = sets . cend ( ) ) {
// We will set this flags from order lists when reading those stickers.
setFlags & = ~ ( MTPDstickerSet : : Flag : : f_installed | MTPDstickerSet_ClientFlag : : f_featured ) ;
it = sets . insert ( setId , Stickers : : Set ( setId , setAccess , setTitle , setShortName , 0 , setHash , MTPDstickerSet : : Flags ( setFlags ) ) ) ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
auto & set = it . value ( ) ;
auto inputSet = MTP_inputStickerSetID ( MTP_long ( set . id ) , MTP_long ( set . access ) ) ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
if ( scnt < 0 ) { // disabled not loaded set
if ( ! set . count | | set . stickers . isEmpty ( ) ) {
set . count = - scnt ;
}
continue ;
}
2015-09-29 18:44:31 +00:00
2016-09-15 19:15:49 +00:00
bool fillStickers = set . stickers . isEmpty ( ) ;
if ( fillStickers ) {
set . stickers . reserve ( scnt ) ;
set . count = 0 ;
2015-09-29 18:44:31 +00:00
}
2016-09-15 19:15:49 +00:00
Serialize : : Document : : StickerSetInfo info ( setId , setAccess , setShortName ) ;
OrderedSet < DocumentId > read ;
for ( int32 j = 0 ; j < scnt ; + + j ) {
auto document = Serialize : : Document : : readStickerFromStream ( stickers . version , stickers . stream , info ) ;
if ( ! document | | ! document - > sticker ( ) ) continue ;
2015-09-29 18:44:31 +00:00
2016-09-15 19:15:49 +00:00
if ( read . contains ( document - > id ) ) continue ;
read . insert ( document - > id ) ;
2015-09-29 18:44:31 +00:00
2016-09-15 19:15:49 +00:00
if ( fillStickers ) {
set . stickers . push_back ( document ) ;
if ( ! ( set . flags & MTPDstickerSet_ClientFlag : : f_special ) ) {
if ( document - > sticker ( ) - > set . type ( ) ! = mtpc_inputStickerSetID ) {
document - > sticker ( ) - > set = inputSet ;
2015-10-01 14:05:05 +00:00
}
2016-09-15 19:15:49 +00:00
}
+ + set . count ;
}
}
if ( stickers . version > 9018 ) {
qint32 emojiCount ;
stickers . stream > > emojiCount ;
for ( int32 j = 0 ; j < emojiCount ; + + j ) {
QString emojiString ;
qint32 stickersCount ;
stickers . stream > > emojiString > > stickersCount ;
2017-11-05 17:07:27 +00:00
Stickers : : Pack pack ;
2016-09-15 19:15:49 +00:00
pack . reserve ( stickersCount ) ;
for ( int32 k = 0 ; k < stickersCount ; + + k ) {
quint64 id ;
stickers . stream > > id ;
DocumentData * doc = App : : document ( id ) ;
if ( ! doc | | ! doc - > sticker ( ) ) continue ;
pack . push_back ( doc ) ;
}
if ( fillStickers ) {
2017-02-15 08:50:11 +00:00
if ( auto emoji = Ui : : Emoji : : Find ( emojiString ) ) {
emoji = emoji - > original ( ) ;
set . emoji . insert ( emoji , pack ) ;
2015-10-01 14:05:05 +00:00
}
2015-09-29 18:44:31 +00:00
}
}
2015-09-29 15:29:21 +00:00
}
}
2016-09-15 19:15:49 +00:00
// Read orders of installed and featured stickers.
if ( outOrder & & stickers . version > = 9061 ) {
stickers . stream > > * outOrder ;
2015-01-02 14:55:24 +00:00
}
2016-09-15 19:15:49 +00:00
// Set flags that we dropped above from the order.
if ( readingFlags & & outOrder ) {
for_const ( auto setId , * outOrder ) {
auto it = sets . find ( setId ) ;
if ( it ! = sets . cend ( ) ) {
it - > flags | = readingFlags ;
2015-10-01 14:05:05 +00:00
}
}
2015-01-02 14:55:24 +00:00
}
2016-09-15 19:15:49 +00:00
}
2015-01-02 14:55:24 +00:00
2016-09-15 19:15:49 +00:00
void writeInstalledStickers ( ) {
if ( ! Global : : started ( ) ) return ;
2015-12-23 19:23:14 +00:00
2016-09-15 19:15:49 +00:00
_writeStickerSets ( _installedStickersKey , [ ] ( const Stickers : : Set & set ) {
2017-08-02 15:07:28 +00:00
if ( set . id = = Stickers : : CloudRecentSetId | | set . id = = Stickers : : FavedSetId ) { // separate files for them
2016-09-15 19:15:49 +00:00
return StickerSetCheckResult : : Skip ;
} else if ( set . flags & MTPDstickerSet_ClientFlag : : f_special ) {
if ( set . stickers . isEmpty ( ) ) { // all other special are "installed"
return StickerSetCheckResult : : Skip ;
}
} else if ( ! ( set . flags & MTPDstickerSet : : Flag : : f_installed ) | | ( set . flags & MTPDstickerSet : : Flag : : f_archived ) ) {
return StickerSetCheckResult : : Skip ;
} else if ( set . flags & MTPDstickerSet_ClientFlag : : f_not_loaded ) { // waiting to receive
return StickerSetCheckResult : : Abort ;
} else if ( set . stickers . isEmpty ( ) ) {
return StickerSetCheckResult : : Skip ;
2015-12-31 05:34:43 +00:00
}
2016-09-15 19:15:49 +00:00
return StickerSetCheckResult : : Write ;
2017-11-05 17:07:27 +00:00
} , Auth ( ) . data ( ) . stickerSetsOrder ( ) ) ;
2016-09-15 19:15:49 +00:00
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
void writeFeaturedStickers ( ) {
if ( ! Global : : started ( ) ) return ;
_writeStickerSets ( _featuredStickersKey , [ ] ( const Stickers : : Set & set ) {
2017-08-02 15:07:28 +00:00
if ( set . id = = Stickers : : CloudRecentSetId | | set . id = = Stickers : : FavedSetId ) { // separate files for them
2016-09-15 19:15:49 +00:00
return StickerSetCheckResult : : Skip ;
} else if ( set . flags & MTPDstickerSet_ClientFlag : : f_special ) {
return StickerSetCheckResult : : Skip ;
} else if ( ! ( set . flags & MTPDstickerSet_ClientFlag : : f_featured ) ) {
return StickerSetCheckResult : : Skip ;
} else if ( set . flags & MTPDstickerSet_ClientFlag : : f_not_loaded ) { // waiting to receive
return StickerSetCheckResult : : Abort ;
} else if ( set . stickers . isEmpty ( ) ) {
return StickerSetCheckResult : : Skip ;
}
return StickerSetCheckResult : : Write ;
2017-11-05 17:07:27 +00:00
} , Auth ( ) . data ( ) . featuredStickerSetsOrder ( ) ) ;
2016-09-15 19:15:49 +00:00
}
2015-01-02 14:55:24 +00:00
2016-09-15 19:15:49 +00:00
void writeRecentStickers ( ) {
if ( ! Global : : started ( ) ) return ;
2015-01-02 14:55:24 +00:00
2016-09-15 19:15:49 +00:00
_writeStickerSets ( _recentStickersKey , [ ] ( const Stickers : : Set & set ) {
if ( set . id ! = Stickers : : CloudRecentSetId | | set . stickers . isEmpty ( ) ) {
return StickerSetCheckResult : : Skip ;
2015-01-02 14:55:24 +00:00
}
2016-09-15 19:15:49 +00:00
return StickerSetCheckResult : : Write ;
} , Stickers : : Order ( ) ) ;
}
2015-01-02 14:55:24 +00:00
2017-08-02 15:07:28 +00:00
void writeFavedStickers ( ) {
if ( ! Global : : started ( ) ) return ;
_writeStickerSets ( _favedStickersKey , [ ] ( const Stickers : : Set & set ) {
if ( set . id ! = Stickers : : FavedSetId | | set . stickers . isEmpty ( ) ) {
return StickerSetCheckResult : : Skip ;
}
return StickerSetCheckResult : : Write ;
} , Stickers : : Order ( ) ) ;
}
2016-09-15 19:15:49 +00:00
void writeArchivedStickers ( ) {
if ( ! Global : : started ( ) ) return ;
2015-09-29 15:29:21 +00:00
2016-09-15 19:15:49 +00:00
_writeStickerSets ( _archivedStickersKey , [ ] ( const Stickers : : Set & set ) {
if ( ! ( set . flags & MTPDstickerSet : : Flag : : f_archived ) | | set . stickers . isEmpty ( ) ) {
return StickerSetCheckResult : : Skip ;
2015-01-02 14:55:24 +00:00
}
2016-09-15 19:15:49 +00:00
return StickerSetCheckResult : : Write ;
2017-11-05 17:07:27 +00:00
} , Auth ( ) . data ( ) . archivedStickerSetsOrder ( ) ) ;
2016-09-15 19:15:49 +00:00
}
2015-01-02 14:55:24 +00:00
2016-09-15 19:15:49 +00:00
void importOldRecentStickers ( ) {
if ( ! _recentStickersKeyOld ) return ;
FileReadDescriptor stickers ;
if ( ! readEncryptedFile ( stickers , _recentStickersKeyOld ) ) {
clearKey ( _recentStickersKeyOld ) ;
_recentStickersKeyOld = 0 ;
2016-04-10 14:53:01 +00:00
_writeMap ( ) ;
2016-09-15 19:15:49 +00:00
return ;
2016-04-09 05:57:55 +00:00
}
2017-11-05 17:07:27 +00:00
auto & sets = Auth ( ) . data ( ) . stickerSetsRef ( ) ;
2016-09-15 19:15:49 +00:00
sets . clear ( ) ;
2015-01-02 14:55:24 +00:00
2017-11-05 17:07:27 +00:00
auto & order = Auth ( ) . data ( ) . stickerSetsOrderRef ( ) ;
2016-09-15 19:15:49 +00:00
order . clear ( ) ;
2015-01-02 14:55:24 +00:00
2016-09-15 19:15:49 +00:00
auto & recent = cRefRecentStickers ( ) ;
recent . clear ( ) ;
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
auto & def = sets . insert ( Stickers : : DefaultSetId , Stickers : : Set ( Stickers : : DefaultSetId , 0 , lang ( lng_stickers_default_set ) , QString ( ) , 0 , 0 , MTPDstickerSet : : Flag : : f_official | MTPDstickerSet : : Flag : : f_installed | MTPDstickerSet_ClientFlag : : f_special ) ) . value ( ) ;
2016-11-22 09:48:13 +00:00
auto & custom = sets . insert ( Stickers : : CustomSetId , Stickers : : Set ( Stickers : : CustomSetId , 0 , qsl ( " Custom stickers " ) , QString ( ) , 0 , 0 , MTPDstickerSet : : Flag : : f_installed | MTPDstickerSet_ClientFlag : : f_special ) ) . value ( ) ;
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
QMap < uint64 , bool > read ;
while ( ! stickers . stream . atEnd ( ) ) {
quint64 id , access ;
QString name , mime , alt ;
qint32 date , dc , size , width , height , type ;
qint16 value ;
stickers . stream > > id > > value > > access > > date > > name > > mime > > dc > > size > > width > > height > > type ;
if ( stickers . version > = 7021 ) {
stickers . stream > > alt ;
2015-12-31 15:27:21 +00:00
}
2016-09-15 19:15:49 +00:00
if ( ! value | | read . contains ( id ) ) continue ;
read . insert ( id , true ) ;
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
QVector < MTPDocumentAttribute > attributes ;
if ( ! name . isEmpty ( ) ) attributes . push_back ( MTP_documentAttributeFilename ( MTP_string ( name ) ) ) ;
if ( type = = AnimatedDocument ) {
attributes . push_back ( MTP_documentAttributeAnimated ( ) ) ;
} else if ( type = = StickerDocument ) {
2017-03-25 15:42:01 +00:00
attributes . push_back ( MTP_documentAttributeSticker ( MTP_flags ( 0 ) , MTP_string ( alt ) , MTP_inputStickerSetEmpty ( ) , MTPMaskCoords ( ) ) ) ;
2016-09-15 19:15:49 +00:00
}
if ( width > 0 & & height > 0 ) {
attributes . push_back ( MTP_documentAttributeImageSize ( MTP_int ( width ) , MTP_int ( height ) ) ) ;
2015-12-31 15:27:21 +00:00
}
2016-09-15 19:15:49 +00:00
DocumentData * doc = App : : documentSet ( id , 0 , access , 0 , date , attributes , mime , ImagePtr ( ) , dc , size , StorageImageLocation ( ) ) ;
if ( ! doc - > sticker ( ) ) continue ;
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
if ( value > 0 ) {
def . stickers . push_back ( doc ) ;
+ + def . count ;
} else {
custom . stickers . push_back ( doc ) ;
+ + custom . count ;
2015-12-31 15:27:21 +00:00
}
2016-09-15 19:15:49 +00:00
if ( recent . size ( ) < Global : : StickersRecentLimit ( ) & & qAbs ( value ) > 1 ) {
recent . push_back ( qMakePair ( doc , qAbs ( value ) ) ) ;
2015-12-31 15:27:21 +00:00
}
2016-09-15 19:15:49 +00:00
}
if ( def . stickers . isEmpty ( ) ) {
sets . remove ( Stickers : : DefaultSetId ) ;
} else {
order . push_front ( Stickers : : DefaultSetId ) ;
}
if ( custom . stickers . isEmpty ( ) ) sets . remove ( Stickers : : CustomSetId ) ;
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
writeInstalledStickers ( ) ;
writeUserSettings ( ) ;
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
clearKey ( _recentStickersKeyOld ) ;
_recentStickersKeyOld = 0 ;
_writeMap ( ) ;
}
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
void readInstalledStickers ( ) {
if ( ! _installedStickersKey ) {
return importOldRecentStickers ( ) ;
2015-12-31 15:27:21 +00:00
}
2017-11-05 17:07:27 +00:00
Auth ( ) . data ( ) . stickerSetsRef ( ) . clear ( ) ;
_readStickerSets ( _installedStickersKey , & Auth ( ) . data ( ) . stickerSetsOrderRef ( ) , MTPDstickerSet : : Flag : : f_installed ) ;
2016-09-15 19:15:49 +00:00
}
2015-12-31 15:27:21 +00:00
2016-09-15 19:15:49 +00:00
void readFeaturedStickers ( ) {
2017-11-05 17:07:27 +00:00
_readStickerSets ( _featuredStickersKey , & Auth ( ) . data ( ) . featuredStickerSetsOrderRef ( ) , MTPDstickerSet : : Flags ( ) | MTPDstickerSet_ClientFlag : : f_featured ) ;
2016-02-12 16:35:06 +00:00
2017-11-05 17:07:27 +00:00
auto & sets = Auth ( ) . data ( ) . stickerSets ( ) ;
2016-09-15 19:15:49 +00:00
int unreadCount = 0 ;
2017-11-05 17:07:27 +00:00
for_const ( auto setId , Auth ( ) . data ( ) . featuredStickerSetsOrder ( ) ) {
2016-09-15 19:15:49 +00:00
auto it = sets . constFind ( setId ) ;
if ( it ! = sets . cend ( ) & & ( it - > flags & MTPDstickerSet_ClientFlag : : f_unread ) ) {
+ + unreadCount ;
2016-02-12 16:35:06 +00:00
}
2016-09-15 19:15:49 +00:00
}
2017-11-05 17:07:27 +00:00
Auth ( ) . data ( ) . setFeaturedStickerSetsUnreadCount ( unreadCount ) ;
2016-09-15 19:15:49 +00:00
}
2016-02-12 16:35:06 +00:00
2016-09-15 19:15:49 +00:00
void readRecentStickers ( ) {
_readStickerSets ( _recentStickersKey ) ;
}
2016-02-12 16:35:06 +00:00
2017-08-02 15:07:28 +00:00
void readFavedStickers ( ) {
_readStickerSets ( _favedStickersKey ) ;
}
2016-09-15 19:15:49 +00:00
void readArchivedStickers ( ) {
static bool archivedStickersRead = false ;
if ( ! archivedStickersRead ) {
2017-11-05 17:07:27 +00:00
_readStickerSets ( _archivedStickersKey , & Auth ( ) . data ( ) . archivedStickerSetsOrderRef ( ) ) ;
2016-09-15 19:15:49 +00:00
archivedStickersRead = true ;
}
}
2016-02-12 16:35:06 +00:00
2017-08-02 15:07:28 +00:00
int32 countDocumentVectorHash ( const QVector < DocumentData * > vector ) {
uint32 acc = 0 ;
for_const ( auto doc , vector ) {
auto docId = doc - > id ;
acc = ( acc * 20261 ) + uint32 ( docId > > 32 ) ;
acc = ( acc * 20261 ) + uint32 ( docId & 0xFFFFFFFF ) ;
}
return int32 ( acc & 0x7FFFFFFF ) ;
}
int32 countSpecialStickerSetHash ( uint64 setId ) {
2017-11-05 17:07:27 +00:00
auto & sets = Auth ( ) . data ( ) . stickerSets ( ) ;
2017-08-02 15:07:28 +00:00
auto it = sets . constFind ( setId ) ;
if ( it ! = sets . cend ( ) ) {
return countDocumentVectorHash ( it - > stickers ) ;
}
return 0 ;
}
2016-09-15 19:15:49 +00:00
int32 countStickersHash ( bool checkOutdatedInfo ) {
uint32 acc = 0 ;
bool foundOutdated = false ;
2017-11-05 17:07:27 +00:00
auto & sets = Auth ( ) . data ( ) . stickerSets ( ) ;
auto & order = Auth ( ) . data ( ) . stickerSetsOrder ( ) ;
2016-09-15 19:15:49 +00:00
for ( auto i = order . cbegin ( ) , e = order . cend ( ) ; i ! = e ; + + i ) {
auto j = sets . constFind ( * i ) ;
if ( j ! = sets . cend ( ) ) {
if ( j - > id = = Stickers : : DefaultSetId ) {
foundOutdated = true ;
} else if ( ! ( j - > flags & MTPDstickerSet_ClientFlag : : f_special )
& & ! ( j - > flags & MTPDstickerSet : : Flag : : f_archived ) ) {
acc = ( acc * 20261 ) + j - > hash ;
2016-02-12 16:35:06 +00:00
}
}
}
2016-09-15 19:15:49 +00:00
return ( ! checkOutdatedInfo | | ! foundOutdated ) ? int32 ( acc & 0x7FFFFFFF ) : 0 ;
}
2016-02-12 16:35:06 +00:00
2016-09-15 19:15:49 +00:00
int32 countRecentStickersHash ( ) {
2017-08-02 15:07:28 +00:00
return countSpecialStickerSetHash ( Stickers : : CloudRecentSetId ) ;
}
int32 countFavedStickersHash ( ) {
return countSpecialStickerSetHash ( Stickers : : FavedSetId ) ;
2016-09-15 19:15:49 +00:00
}
2015-09-29 18:44:31 +00:00
2016-09-15 19:15:49 +00:00
int32 countFeaturedStickersHash ( ) {
uint32 acc = 0 ;
2017-11-05 17:07:27 +00:00
auto & sets = Auth ( ) . data ( ) . stickerSets ( ) ;
auto & featured = Auth ( ) . data ( ) . featuredStickerSetsOrder ( ) ;
2016-09-15 19:15:49 +00:00
for_const ( auto setId , featured ) {
acc = ( acc * 20261 ) + uint32 ( setId > > 32 ) ;
acc = ( acc * 20261 ) + uint32 ( setId & 0xFFFFFFFF ) ;
2016-01-09 12:51:42 +00:00
2016-09-15 19:15:49 +00:00
auto it = sets . constFind ( setId ) ;
if ( it ! = sets . cend ( ) & & ( it - > flags & MTPDstickerSet_ClientFlag : : f_unread ) ) {
acc = ( acc * 20261 ) + 1U ;
2016-01-09 12:51:42 +00:00
}
2015-05-21 10:44:26 +00:00
}
2016-09-15 19:15:49 +00:00
return int32 ( acc & 0x7FFFFFFF ) ;
}
2015-05-21 10:44:26 +00:00
2016-09-15 19:15:49 +00:00
int32 countSavedGifsHash ( ) {
2017-11-05 17:07:27 +00:00
return countDocumentVectorHash ( Auth ( ) . data ( ) . savedGifs ( ) ) ;
2016-09-15 19:15:49 +00:00
}
2016-07-21 10:09:47 +00:00
2016-09-15 19:15:49 +00:00
void writeSavedGifs ( ) {
if ( ! _working ( ) ) return ;
2016-06-27 16:25:21 +00:00
2017-11-05 17:07:27 +00:00
auto & saved = Auth ( ) . data ( ) . savedGifs ( ) ;
2016-09-15 19:15:49 +00:00
if ( saved . isEmpty ( ) ) {
if ( _savedGifsKey ) {
clearKey ( _savedGifsKey ) ;
_savedGifsKey = 0 ;
_mapChanged = true ;
2015-01-02 14:55:24 +00:00
}
2016-09-15 19:15:49 +00:00
_writeMap ( ) ;
} else {
quint32 size = sizeof ( quint32 ) ; // count
for_const ( auto gif , saved ) {
size + = Serialize : : Document : : sizeInStream ( gif ) ;
2015-01-02 14:55:24 +00:00
}
2015-06-01 10:58:46 +00:00
2016-09-15 19:15:49 +00:00
if ( ! _savedGifsKey ) {
_savedGifsKey = genKey ( ) ;
2016-07-21 10:09:47 +00:00
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Fast ) ;
2015-05-19 15:46:45 +00:00
}
2016-07-21 10:09:47 +00:00
EncryptedDescriptor data ( size ) ;
2016-09-15 19:15:49 +00:00
data . stream < < quint32 ( saved . size ( ) ) ;
for_const ( auto gif , saved ) {
Serialize : : Document : : writeToStream ( data . stream , gif ) ;
2015-06-28 12:37:10 +00:00
}
2016-09-15 19:15:49 +00:00
FileWriteDescriptor file ( _savedGifsKey ) ;
2016-07-21 10:09:47 +00:00
file . writeEncrypted ( data ) ;
2015-05-19 15:46:45 +00:00
}
2016-09-15 19:15:49 +00:00
}
2015-05-19 15:46:45 +00:00
2016-09-15 19:15:49 +00:00
void readSavedGifs ( ) {
if ( ! _savedGifsKey ) return ;
2015-05-19 15:46:45 +00:00
2016-09-15 19:15:49 +00:00
FileReadDescriptor gifs ;
if ( ! readEncryptedFile ( gifs , _savedGifsKey ) ) {
clearKey ( _savedGifsKey ) ;
_savedGifsKey = 0 ;
_writeMap ( ) ;
return ;
}
2016-06-27 16:25:21 +00:00
2017-11-05 17:07:27 +00:00
auto & saved = Auth ( ) . data ( ) . savedGifsRef ( ) ;
2016-09-15 19:15:49 +00:00
saved . clear ( ) ;
2015-05-19 15:46:45 +00:00
2016-09-15 19:15:49 +00:00
quint32 cnt ;
gifs . stream > > cnt ;
saved . reserve ( cnt ) ;
OrderedSet < DocumentId > read ;
for ( uint32 i = 0 ; i < cnt ; + + i ) {
2017-04-02 10:25:54 +00:00
auto document = Serialize : : Document : : readFromStream ( gifs . version , gifs . stream ) ;
if ( ! document | | ! document - > isGifv ( ) ) continue ;
2016-01-09 12:51:42 +00:00
2016-09-15 19:15:49 +00:00
if ( read . contains ( document - > id ) ) continue ;
read . insert ( document - > id ) ;
2016-07-21 10:09:47 +00:00
2016-09-15 19:15:49 +00:00
saved . push_back ( document ) ;
}
}
2016-01-09 12:51:42 +00:00
2016-09-15 19:15:49 +00:00
void writeBackground ( int32 id , const QImage & img ) {
2016-10-28 12:44:28 +00:00
if ( ! _working ( ) | | ! _backgroundCanWrite ) return ;
2015-06-28 12:37:10 +00:00
2017-02-25 16:44:02 +00:00
if ( ! LocalKey ) {
2017-01-18 10:26:33 +00:00
LOG ( ( " App Error: localkey not created in writeBackground() " ) ) ;
return ;
}
2016-10-28 12:44:28 +00:00
QByteArray bmp ;
2016-09-15 19:15:49 +00:00
if ( ! img . isNull ( ) ) {
2016-10-28 12:44:28 +00:00
QBuffer buf ( & bmp ) ;
2016-09-15 19:15:49 +00:00
if ( ! img . save ( & buf , " BMP " ) ) return ;
}
if ( ! _backgroundKey ) {
_backgroundKey = genKey ( ) ;
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Fast ) ;
2016-09-15 19:15:49 +00:00
}
2016-10-28 12:44:28 +00:00
quint32 size = sizeof ( qint32 ) + sizeof ( quint32 ) + ( bmp . isEmpty ( ) ? 0 : ( sizeof ( quint32 ) + bmp . size ( ) ) ) ;
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ( size ) ;
2016-11-07 15:24:28 +00:00
data . stream < < qint32 ( id ) < < bmp ;
2015-05-19 15:46:45 +00:00
2016-09-15 19:15:49 +00:00
FileWriteDescriptor file ( _backgroundKey ) ;
file . writeEncrypted ( data ) ;
}
2015-05-19 15:46:45 +00:00
2016-09-15 19:15:49 +00:00
bool readBackground ( ) {
2016-11-01 20:59:51 +00:00
if ( _backgroundWasRead ) {
2016-10-28 12:44:28 +00:00
return false ;
}
2016-09-15 19:15:49 +00:00
_backgroundWasRead = true ;
2016-01-09 11:24:16 +00:00
2016-09-15 19:15:49 +00:00
FileReadDescriptor bg ;
if ( ! readEncryptedFile ( bg , _backgroundKey ) ) {
clearKey ( _backgroundKey ) ;
_backgroundKey = 0 ;
_writeMap ( ) ;
return false ;
}
2016-06-27 16:25:21 +00:00
2016-09-15 19:15:49 +00:00
QByteArray pngData ;
qint32 id ;
2016-11-07 15:24:28 +00:00
bg . stream > > id > > pngData ;
auto oldEmptyImage = ( bg . stream . status ( ) ! = QDataStream : : Ok ) ;
if ( oldEmptyImage
| | id = = Window : : Theme : : kInitialBackground
| | id = = Window : : Theme : : kDefaultBackground ) {
2016-10-28 12:44:28 +00:00
_backgroundCanWrite = false ;
2016-11-07 15:24:28 +00:00
if ( oldEmptyImage | | bg . version < 8005 ) {
2016-10-28 12:44:28 +00:00
Window : : Theme : : Background ( ) - > setImage ( Window : : Theme : : kDefaultBackground ) ;
2016-11-07 15:24:28 +00:00
Window : : Theme : : Background ( ) - > setTile ( false ) ;
2016-09-15 19:15:49 +00:00
} else {
2016-10-28 12:44:28 +00:00
Window : : Theme : : Background ( ) - > setImage ( id ) ;
2016-07-14 11:59:55 +00:00
}
2016-10-28 12:44:28 +00:00
_backgroundCanWrite = true ;
2016-09-15 19:15:49 +00:00
return true ;
2016-12-30 13:53:51 +00:00
} else if ( id = = Window : : Theme : : kThemeBackground & & pngData . isEmpty ( ) ) {
_backgroundCanWrite = false ;
Window : : Theme : : Background ( ) - > setImage ( id ) ;
_backgroundCanWrite = true ;
return true ;
2016-09-15 19:15:49 +00:00
}
2016-06-27 16:25:21 +00:00
2016-10-28 12:44:28 +00:00
QImage image ;
2016-09-15 19:15:49 +00:00
QBuffer buf ( & pngData ) ;
QImageReader reader ( & buf ) ;
# ifndef OS_MAC_OLD
reader . setAutoTransform ( true ) ;
# endif // OS_MAC_OLD
2016-10-28 12:44:28 +00:00
if ( reader . read ( & image ) ) {
_backgroundCanWrite = false ;
2017-02-21 13:45:56 +00:00
Window : : Theme : : Background ( ) - > setImage ( id , std : : move ( image ) ) ;
2016-10-28 12:44:28 +00:00
_backgroundCanWrite = true ;
2016-09-15 19:15:49 +00:00
return true ;
2016-07-21 10:09:47 +00:00
}
2016-09-15 19:15:49 +00:00
return false ;
}
2016-07-21 10:09:47 +00:00
2016-10-28 12:44:28 +00:00
bool readThemeUsingKey ( FileKey key ) {
FileReadDescriptor theme ;
2017-02-25 16:44:02 +00:00
if ( ! readEncryptedFile ( theme , key , FileOption : : Safe , SettingsKey ) ) {
2016-10-28 12:44:28 +00:00
return false ;
}
QByteArray themeContent ;
QString pathRelative , pathAbsolute ;
Window : : Theme : : Cached cache ;
theme . stream > > themeContent ;
theme . stream > > pathRelative > > pathAbsolute ;
if ( theme . stream . status ( ) ! = QDataStream : : Ok ) {
return false ;
}
2017-02-03 20:07:26 +00:00
2017-06-29 19:09:10 +00:00
_themeAbsolutePath = pathAbsolute ;
2017-02-03 20:07:26 +00:00
_themePaletteAbsolutePath = Window : : Theme : : IsPaletteTestingPath ( pathAbsolute ) ? pathAbsolute : QString ( ) ;
2016-10-28 12:44:28 +00:00
QFile file ( pathRelative ) ;
if ( pathRelative . isEmpty ( ) | | ! file . exists ( ) ) {
file . setFileName ( pathAbsolute ) ;
}
auto changed = false ;
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 false ;
}
auto fileContent = file . readAll ( ) ;
file . close ( ) ;
if ( themeContent ! = fileContent ) {
themeContent = fileContent ;
changed = true ;
}
}
if ( ! changed ) {
quint32 backgroundIsTiled = 0 ;
theme . stream > > cache . paletteChecksum > > cache . contentChecksum > > cache . colors > > cache . background > > backgroundIsTiled ;
cache . tiled = ( backgroundIsTiled = = 1 ) ;
if ( theme . stream . status ( ) ! = QDataStream : : Ok ) {
return false ;
}
}
return Window : : Theme : : Load ( pathRelative , pathAbsolute , themeContent , cache ) ;
}
void writeTheme ( const QString & pathRelative , const QString & pathAbsolute , const QByteArray & content , const Window : : Theme : : Cached & cache ) {
2016-12-20 13:03:51 +00:00
if ( content . isEmpty ( ) ) {
2017-06-29 19:09:10 +00:00
_themeAbsolutePath = _themePaletteAbsolutePath = QString ( ) ;
2016-12-20 13:03:51 +00:00
if ( _themeKey ) {
clearKey ( _themeKey ) ;
_themeKey = 0 ;
writeSettings ( ) ;
}
return ;
}
2017-02-03 20:07:26 +00:00
2017-06-29 19:09:10 +00:00
_themeAbsolutePath = pathAbsolute ;
2017-02-03 20:07:26 +00:00
_themePaletteAbsolutePath = Window : : Theme : : IsPaletteTestingPath ( pathAbsolute ) ? pathAbsolute : QString ( ) ;
2016-11-01 20:59:51 +00:00
if ( ! _themeKey ) {
2017-04-13 17:59:05 +00:00
_themeKey = genKey ( FileOption : : Safe ) ;
2016-10-28 12:44:28 +00:00
writeSettings ( ) ;
}
auto backgroundTiled = static_cast < quint32 > ( cache . tiled ? 1 : 0 ) ;
quint32 size = Serialize : : bytearraySize ( content ) ;
size + = Serialize : : stringSize ( pathRelative ) + Serialize : : stringSize ( pathAbsolute ) ;
size + = sizeof ( int32 ) * 2 + Serialize : : bytearraySize ( cache . colors ) + Serialize : : bytearraySize ( cache . background ) + sizeof ( quint32 ) ;
EncryptedDescriptor data ( size ) ;
data . stream < < content ;
data . stream < < pathRelative < < pathAbsolute ;
data . stream < < cache . paletteChecksum < < cache . contentChecksum < < cache . colors < < cache . background < < backgroundTiled ;
2016-11-01 20:59:51 +00:00
FileWriteDescriptor file ( _themeKey , FileOption : : Safe ) ;
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 ( ) {
writeTheme ( QString ( ) , QString ( ) , QByteArray ( ) , Window : : Theme : : Cached ( ) ) ;
}
2016-10-28 12:44:28 +00:00
void readTheme ( ) {
2016-11-01 20:59:51 +00:00
if ( _themeKey & & ! readThemeUsingKey ( _themeKey ) ) {
2016-12-20 13:03:51 +00:00
clearTheme ( ) ;
2016-10-28 12:44:28 +00:00
}
}
2016-12-20 13:03:51 +00:00
bool hasTheme ( ) {
return ( _themeKey ! = 0 ) ;
}
2017-04-13 17:59:05 +00:00
void readLangPack ( ) {
FileReadDescriptor langpack ;
if ( ! _langPackKey | | ! readEncryptedFile ( langpack , _langPackKey , FileOption : : Safe , SettingsKey ) ) {
return ;
}
auto data = QByteArray ( ) ;
langpack . stream > > data ;
if ( langpack . stream . status ( ) = = QDataStream : : Ok ) {
Lang : : Current ( ) . fillFromSerialized ( data ) ;
}
}
void writeLangPack ( ) {
auto langpack = Lang : : Current ( ) . serialize ( ) ;
if ( ! _langPackKey ) {
_langPackKey = genKey ( FileOption : : Safe ) ;
writeSettings ( ) ;
}
EncryptedDescriptor data ( Serialize : : bytearraySize ( langpack ) ) ;
data . stream < < langpack ;
FileWriteDescriptor file ( _langPackKey , FileOption : : Safe ) ;
file . writeEncrypted ( data , SettingsKey ) ;
}
2017-02-03 20:07:26 +00:00
QString themePaletteAbsolutePath ( ) {
return _themePaletteAbsolutePath ;
}
2017-06-29 19:09:10 +00:00
QString themeAbsolutePath ( ) {
return _themeAbsolutePath ;
}
2017-02-03 20:07:26 +00:00
bool copyThemeColorsToPalette ( const QString & path ) {
if ( ! _themeKey ) {
return false ;
}
FileReadDescriptor theme ;
2017-02-25 16:44:02 +00:00
if ( ! readEncryptedFile ( theme , _themeKey , FileOption : : Safe , SettingsKey ) ) {
2017-02-03 20:07:26 +00:00
return false ;
}
QByteArray themeContent ;
theme . stream > > themeContent ;
if ( theme . stream . status ( ) ! = QDataStream : : Ok ) {
return false ;
}
return Window : : Theme : : CopyColorsToPalette ( path , themeContent ) ;
}
2016-09-15 19:15:49 +00:00
uint32 _peerSize ( PeerData * peer ) {
uint32 result = sizeof ( quint64 ) + sizeof ( quint64 ) + Serialize : : storageImageLocationSize ( ) ;
if ( peer - > isUser ( ) ) {
UserData * user = peer - > asUser ( ) ;
2016-09-10 20:54:59 +00:00
2016-09-15 19:15:49 +00:00
// first + last + phone + username + access
result + = Serialize : : stringSize ( user - > firstName ) + Serialize : : stringSize ( user - > lastName ) + Serialize : : stringSize ( user - > phone ( ) ) + Serialize : : stringSize ( user - > username ) + sizeof ( quint64 ) ;
2016-07-21 10:09:47 +00:00
2016-09-15 19:15:49 +00:00
// flags
if ( AppVersion > = 9012 ) {
result + = sizeof ( qint32 ) ;
}
2016-09-10 20:54:59 +00:00
2016-09-15 19:15:49 +00:00
// onlineTill + contact + botInfoVersion
result + = sizeof ( qint32 ) + sizeof ( qint32 ) + sizeof ( qint32 ) ;
} else if ( peer - > isChat ( ) ) {
ChatData * chat = peer - > asChat ( ) ;
2016-07-21 10:09:47 +00:00
2017-09-26 11:49:16 +00:00
// name + count + date + version + admin + old forbidden + left + inviteLink
result + = Serialize : : stringSize ( chat - > name ) + sizeof ( qint32 ) + sizeof ( qint32 ) + sizeof ( qint32 ) + sizeof ( qint32 ) + sizeof ( qint32 ) + sizeof ( quint32 ) + Serialize : : stringSize ( chat - > inviteLink ( ) ) ;
2016-09-15 19:15:49 +00:00
} else if ( peer - > isChannel ( ) ) {
ChannelData * channel = peer - > asChannel ( ) ;
2016-09-10 20:54:59 +00:00
2017-09-26 11:49:16 +00:00
// name + access + date + version + old forbidden + flags + inviteLink
result + = Serialize : : stringSize ( channel - > name ) + sizeof ( quint64 ) + sizeof ( qint32 ) + sizeof ( qint32 ) + sizeof ( qint32 ) + sizeof ( quint32 ) + Serialize : : stringSize ( channel - > inviteLink ( ) ) ;
2016-07-21 10:09:47 +00:00
}
2016-09-15 19:15:49 +00:00
return result ;
}
2016-07-21 10:09:47 +00:00
2016-09-15 19:15:49 +00:00
void _writePeer ( QDataStream & stream , PeerData * peer ) {
2017-12-05 06:41:43 +00:00
stream < < quint64 ( peer - > id ) < < quint64 ( peer - > userpicPhotoId ( ) ) ;
2017-11-20 19:54:05 +00:00
Serialize : : writeStorageImageLocation ( stream , peer - > userpicLocation ( ) ) ;
2017-12-05 06:41:43 +00:00
if ( const auto user = peer - > asUser ( ) ) {
2017-09-26 11:49:16 +00:00
stream < < user - > firstName < < user - > lastName < < user - > phone ( ) < < user - > username < < quint64 ( user - > accessHash ( ) ) ;
2016-09-15 19:15:49 +00:00
if ( AppVersion > = 9012 ) {
2017-09-26 11:49:16 +00:00
stream < < qint32 ( user - > flags ( ) ) ;
2016-09-15 19:15:49 +00:00
}
if ( AppVersion > = 9016 ) {
stream < < ( user - > botInfo ? user - > botInfo - > inlinePlaceholder : QString ( ) ) ;
}
stream < < qint32 ( user - > onlineTill ) < < qint32 ( user - > contact ) < < qint32 ( user - > botInfo ? user - > botInfo - > version : - 1 ) ;
2017-12-05 06:41:43 +00:00
} else if ( const auto chat = peer - > asChat ( ) ) {
2016-09-15 19:15:49 +00:00
stream < < chat - > name < < qint32 ( chat - > count ) < < qint32 ( chat - > date ) < < qint32 ( chat - > version ) < < qint32 ( chat - > creator ) ;
2017-09-26 11:49:16 +00:00
stream < < qint32 ( 0 ) < < quint32 ( chat - > flags ( ) ) < < chat - > inviteLink ( ) ;
2017-12-05 06:41:43 +00:00
} else if ( auto channel = peer - > asChannel ( ) ) {
2016-09-15 19:15:49 +00:00
stream < < channel - > name < < quint64 ( channel - > access ) < < qint32 ( channel - > date ) < < qint32 ( channel - > version ) ;
2017-09-26 11:49:16 +00:00
stream < < qint32 ( 0 ) < < quint32 ( channel - > flags ( ) ) < < channel - > inviteLink ( ) ;
2015-01-02 14:55:24 +00:00
}
2016-09-15 19:15:49 +00:00
}
2015-01-02 14:55:24 +00:00
2016-09-15 19:15:49 +00:00
PeerData * _readPeer ( FileReadDescriptor & from , int32 fileVersion = 0 ) {
quint64 peerId = 0 , photoId = 0 ;
from . stream > > peerId > > photoId ;
2015-01-02 14:55:24 +00:00
2017-11-20 19:54:05 +00:00
auto photoLoc = Serialize : : readStorageImageLocation ( from . stream ) ;
2015-06-01 10:58:46 +00:00
2016-09-15 19:15:49 +00:00
PeerData * result = App : : peerLoaded ( peerId ) ;
bool wasLoaded = ( result ! = nullptr ) ;
if ( ! wasLoaded ) {
result = App : : peer ( peerId ) ;
result - > loadedStatus = PeerData : : FullLoaded ;
}
2017-12-05 06:41:43 +00:00
if ( const auto user = result - > asUser ( ) ) {
2016-09-15 19:15:49 +00:00
QString first , last , phone , username , inlinePlaceholder ;
quint64 access ;
qint32 flags = 0 , onlineTill , contact , botInfoVersion ;
from . stream > > first > > last > > phone > > username > > access ;
if ( from . version > = 9012 ) {
from . stream > > flags ;
}
if ( from . version > = 9016 | | fileVersion > = 9016 ) {
from . stream > > inlinePlaceholder ;
}
from . stream > > onlineTill > > contact > > botInfoVersion ;
2015-05-21 10:44:26 +00:00
2017-08-04 14:54:32 +00:00
bool showPhone = ! isServiceUser ( user - > id ) & & ( user - > id ! = Auth ( ) . userPeerId ( ) ) & & ( contact < = 0 ) ;
2016-09-15 19:15:49 +00:00
QString pname = ( showPhone & & ! phone . isEmpty ( ) ) ? App : : formatPhone ( phone ) : QString ( ) ;
2015-05-19 15:46:45 +00:00
2016-09-15 19:15:49 +00:00
if ( ! wasLoaded ) {
user - > setPhone ( phone ) ;
user - > setName ( first , last , pname , username ) ;
2015-01-02 14:55:24 +00:00
2017-09-26 11:49:16 +00:00
user - > setFlags ( MTPDuser : : Flags : : from_raw ( flags ) ) ;
user - > setAccessHash ( access ) ;
2016-09-15 19:15:49 +00:00
user - > onlineTill = onlineTill ;
user - > contact = contact ;
user - > setBotInfoVersion ( botInfoVersion ) ;
if ( ! inlinePlaceholder . isEmpty ( ) & & user - > botInfo ) {
user - > botInfo - > inlinePlaceholder = inlinePlaceholder ;
2015-01-02 14:55:24 +00:00
}
2017-08-04 14:54:32 +00:00
if ( user - > id = = Auth ( ) . userPeerId ( ) ) {
2016-09-15 19:15:49 +00:00
user - > input = MTP_inputPeerSelf ( ) ;
user - > inputUser = MTP_inputUserSelf ( ) ;
2015-05-19 15:46:45 +00:00
} else {
2017-09-26 11:49:16 +00:00
user - > input = MTP_inputPeerUser ( MTP_int ( peerToUser ( user - > id ) ) , MTP_long ( user - > accessHash ( ) ) ) ;
user - > inputUser = MTP_inputUser ( MTP_int ( peerToUser ( user - > id ) ) , MTP_long ( user - > accessHash ( ) ) ) ;
2016-07-21 10:09:47 +00:00
}
2015-05-19 15:46:45 +00:00
}
2017-12-05 06:41:43 +00:00
} else if ( const auto chat = result - > asChat ( ) ) {
2016-09-15 19:15:49 +00:00
QString name , inviteLink ;
2017-09-26 11:49:16 +00:00
qint32 count , date , version , creator , oldForbidden ;
quint32 flagsData , flags ;
from . stream > > name > > count > > date > > version > > creator > > oldForbidden > > flagsData > > inviteLink ;
2016-09-15 19:15:49 +00:00
if ( from . version > = 9012 ) {
flags = flagsData ;
2015-06-28 12:37:10 +00:00
} else {
2016-09-15 19:15:49 +00:00
// flagsData was haveLeft
2017-09-26 11:49:16 +00:00
flags = ( flagsData = = 1 )
? MTPDchat : : Flags ( MTPDchat : : Flag : : f_left )
: MTPDchat : : Flags ( 0 ) ;
}
if ( oldForbidden ) {
flags | = quint32 ( MTPDchat_ClientFlag : : f_forbidden ) ;
2015-06-28 12:37:10 +00:00
}
2016-09-15 19:15:49 +00:00
if ( ! wasLoaded ) {
chat - > setName ( name ) ;
chat - > count = count ;
chat - > date = date ;
chat - > version = version ;
chat - > creator = creator ;
2017-09-26 11:49:16 +00:00
chat - > setFlags ( MTPDchat : : Flags : : from_raw ( flags ) ) ;
2016-09-15 19:15:49 +00:00
chat - > setInviteLink ( inviteLink ) ;
2015-05-19 15:46:45 +00:00
2016-09-15 19:15:49 +00:00
chat - > input = MTP_inputPeerChat ( MTP_int ( peerToChat ( chat - > id ) ) ) ;
chat - > inputChat = MTP_int ( peerToChat ( chat - > id ) ) ;
2015-05-19 15:46:45 +00:00
}
2017-12-05 06:41:43 +00:00
} else if ( const auto channel = result - > asChannel ( ) ) {
2016-09-15 19:15:49 +00:00
QString name , inviteLink ;
quint64 access ;
2017-09-26 11:49:16 +00:00
qint32 date , version , oldForbidden ;
quint32 flags ;
from . stream > > name > > access > > date > > version > > oldForbidden > > flags > > inviteLink ;
if ( oldForbidden ) {
flags | = quint32 ( MTPDchannel_ClientFlag : : f_forbidden ) ;
}
2016-09-15 19:15:49 +00:00
if ( ! wasLoaded ) {
channel - > setName ( name , QString ( ) ) ;
channel - > access = access ;
channel - > date = date ;
channel - > version = version ;
2017-09-26 11:49:16 +00:00
channel - > setFlags ( MTPDchannel : : Flags : : from_raw ( flags ) ) ;
2016-09-15 19:15:49 +00:00
channel - > setInviteLink ( inviteLink ) ;
2016-01-09 11:24:16 +00:00
2016-09-15 19:15:49 +00:00
channel - > input = MTP_inputPeerChannel ( MTP_int ( peerToChannel ( channel - > id ) ) , MTP_long ( access ) ) ;
channel - > inputChannel = MTP_inputChannel ( MTP_int ( peerToChannel ( channel - > id ) ) , MTP_long ( access ) ) ;
2015-01-02 14:55:24 +00:00
}
2015-12-27 21:37:48 +00:00
}
2017-12-05 06:41:43 +00:00
if ( ! wasLoaded ) {
result - > setUserpic (
photoId ,
photoLoc ,
photoLoc . isNull ( ) ? ImagePtr ( ) : ImagePtr ( photoLoc ) ) ;
}
2016-09-15 19:15:49 +00:00
return result ;
}
2015-12-27 21:37:48 +00:00
2016-09-15 19:15:49 +00:00
void writeRecentHashtagsAndBots ( ) {
if ( ! _working ( ) ) return ;
2015-01-02 14:55:24 +00:00
2016-09-15 19:15:49 +00:00
const RecentHashtagPack & write ( cRecentWriteHashtags ( ) ) , & search ( cRecentSearchHashtags ( ) ) ;
const RecentInlineBots & bots ( cRecentInlineBots ( ) ) ;
if ( write . isEmpty ( ) & & search . isEmpty ( ) & & bots . isEmpty ( ) ) readRecentHashtagsAndBots ( ) ;
if ( write . isEmpty ( ) & & search . isEmpty ( ) & & bots . isEmpty ( ) ) {
if ( _recentHashtagsAndBotsKey ) {
clearKey ( _recentHashtagsAndBotsKey ) ;
_recentHashtagsAndBotsKey = 0 ;
_mapChanged = true ;
2016-06-27 16:25:21 +00:00
}
2016-09-15 19:15:49 +00:00
_writeMap ( ) ;
} else {
if ( ! _recentHashtagsAndBotsKey ) {
_recentHashtagsAndBotsKey = genKey ( ) ;
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Fast ) ;
2015-12-27 21:37:48 +00:00
}
2016-09-15 19:15:49 +00:00
quint32 size = sizeof ( quint32 ) * 3 , writeCnt = 0 , searchCnt = 0 , botsCnt = cRecentInlineBots ( ) . size ( ) ;
for ( RecentHashtagPack : : const_iterator i = write . cbegin ( ) , e = write . cend ( ) ; i ! = e ; + + i ) {
if ( ! i - > first . isEmpty ( ) ) {
size + = Serialize : : stringSize ( i - > first ) + sizeof ( quint16 ) ;
+ + writeCnt ;
2015-12-27 21:37:48 +00:00
}
2016-09-15 19:15:49 +00:00
}
for ( RecentHashtagPack : : const_iterator i = search . cbegin ( ) , e = search . cend ( ) ; i ! = e ; + + i ) {
if ( ! i - > first . isEmpty ( ) ) {
size + = Serialize : : stringSize ( i - > first ) + sizeof ( quint16 ) ;
+ + searchCnt ;
2015-12-27 21:37:48 +00:00
}
}
2016-09-15 19:15:49 +00:00
for ( RecentInlineBots : : const_iterator i = bots . cbegin ( ) , e = bots . cend ( ) ; i ! = e ; + + i ) {
size + = _peerSize ( * i ) ;
2015-12-27 21:37:48 +00:00
}
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ( size ) ;
data . stream < < quint32 ( writeCnt ) < < quint32 ( searchCnt ) ;
for ( RecentHashtagPack : : const_iterator i = write . cbegin ( ) , e = write . cend ( ) ; i ! = e ; + + i ) {
if ( ! i - > first . isEmpty ( ) ) data . stream < < i - > first < < quint16 ( i - > second ) ;
2015-12-02 17:17:53 +00:00
}
2016-09-15 19:15:49 +00:00
for ( RecentHashtagPack : : const_iterator i = search . cbegin ( ) , e = search . cend ( ) ; i ! = e ; + + i ) {
if ( ! i - > first . isEmpty ( ) ) data . stream < < i - > first < < quint16 ( i - > second ) ;
2015-02-03 15:02:46 +00:00
}
2016-09-15 19:15:49 +00:00
data . stream < < quint32 ( botsCnt ) ;
for ( RecentInlineBots : : const_iterator i = bots . cbegin ( ) , e = bots . cend ( ) ; i ! = e ; + + i ) {
_writePeer ( data . stream , * i ) ;
2015-02-03 15:02:46 +00:00
}
2016-09-15 19:15:49 +00:00
FileWriteDescriptor file ( _recentHashtagsAndBotsKey ) ;
2015-02-03 15:02:46 +00:00
file . writeEncrypted ( data ) ;
}
2016-09-15 19:15:49 +00:00
}
2015-02-03 15:02:46 +00:00
2016-09-15 19:15:49 +00:00
void readRecentHashtagsAndBots ( ) {
if ( _recentHashtagsAndBotsWereRead ) return ;
_recentHashtagsAndBotsWereRead = true ;
2015-02-03 15:02:46 +00:00
2016-09-15 19:15:49 +00:00
if ( ! _recentHashtagsAndBotsKey ) return ;
2015-02-03 15:02:46 +00:00
2016-09-15 19:15:49 +00:00
FileReadDescriptor hashtags ;
if ( ! readEncryptedFile ( hashtags , _recentHashtagsAndBotsKey ) ) {
clearKey ( _recentHashtagsAndBotsKey ) ;
_recentHashtagsAndBotsKey = 0 ;
_writeMap ( ) ;
return ;
2015-02-03 15:02:46 +00:00
}
2015-03-24 10:00:27 +00:00
2016-09-15 19:15:49 +00:00
quint32 writeCount = 0 , searchCount = 0 , botsCount = 0 ;
hashtags . stream > > writeCount > > searchCount ;
2015-09-03 10:48:40 +00:00
2016-09-15 19:15:49 +00:00
QString tag ;
quint16 count ;
2015-10-29 15:52:39 +00:00
2016-09-15 19:15:49 +00:00
RecentHashtagPack write , search ;
RecentInlineBots bots ;
if ( writeCount ) {
write . reserve ( writeCount ) ;
for ( uint32 i = 0 ; i < writeCount ; + + i ) {
hashtags . stream > > tag > > count ;
write . push_back ( qMakePair ( tag . trimmed ( ) , count ) ) ;
2015-08-07 12:11:50 +00:00
}
}
2016-09-15 19:15:49 +00:00
if ( searchCount ) {
search . reserve ( searchCount ) ;
for ( uint32 i = 0 ; i < searchCount ; + + i ) {
hashtags . stream > > tag > > count ;
search . push_back ( qMakePair ( tag . trimmed ( ) , count ) ) ;
2015-08-07 12:11:50 +00:00
}
}
2016-09-15 19:15:49 +00:00
cSetRecentWriteHashtags ( write ) ;
cSetRecentSearchHashtags ( search ) ;
if ( ! hashtags . stream . atEnd ( ) ) {
hashtags . stream > > botsCount ;
if ( botsCount ) {
bots . reserve ( botsCount ) ;
for ( uint32 i = 0 ; i < botsCount ; + + i ) {
PeerData * peer = _readPeer ( hashtags , 9016 ) ;
if ( peer & & peer - > isUser ( ) & & peer - > asUser ( ) - > botInfo & & ! peer - > asUser ( ) - > botInfo - > inlinePlaceholder . isEmpty ( ) & & ! peer - > asUser ( ) - > username . isEmpty ( ) ) {
bots . push_back ( peer - > asUser ( ) ) ;
2016-01-01 15:08:56 +00:00
}
}
2015-08-07 12:11:50 +00:00
}
2016-09-15 19:15:49 +00:00
cSetRecentInlineBots ( bots ) ;
2015-08-07 12:11:50 +00:00
}
2016-09-15 19:15:49 +00:00
}
2015-08-07 12:11:50 +00:00
2016-09-15 19:15:49 +00:00
void writeSavedPeers ( ) {
if ( ! _working ( ) ) return ;
2016-01-01 14:48:32 +00:00
2016-09-15 19:15:49 +00:00
const SavedPeers & saved ( cSavedPeers ( ) ) ;
if ( saved . isEmpty ( ) ) {
if ( _savedPeersKey ) {
clearKey ( _savedPeersKey ) ;
_savedPeersKey = 0 ;
_mapChanged = true ;
}
_writeMap ( ) ;
} else {
if ( ! _savedPeersKey ) {
_savedPeersKey = genKey ( ) ;
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Fast ) ;
2016-09-15 19:15:49 +00:00
}
quint32 size = sizeof ( quint32 ) ;
for ( SavedPeers : : const_iterator i = saved . cbegin ( ) ; i ! = saved . cend ( ) ; + + i ) {
size + = _peerSize ( i . key ( ) ) + Serialize : : dateTimeSize ( ) ;
}
2016-01-01 14:48:32 +00:00
2016-09-15 19:15:49 +00:00
EncryptedDescriptor data ( size ) ;
data . stream < < quint32 ( saved . size ( ) ) ;
for ( SavedPeers : : const_iterator i = saved . cbegin ( ) ; i ! = saved . cend ( ) ; + + i ) {
_writePeer ( data . stream , i . key ( ) ) ;
data . stream < < i . value ( ) ;
2016-01-01 14:48:32 +00:00
}
2016-09-15 19:15:49 +00:00
FileWriteDescriptor file ( _savedPeersKey ) ;
file . writeEncrypted ( data ) ;
}
}
2016-01-01 14:48:32 +00:00
2016-09-15 19:15:49 +00:00
void readSavedPeers ( ) {
if ( ! _savedPeersKey ) return ;
2016-01-01 14:48:32 +00:00
2016-09-15 19:15:49 +00:00
FileReadDescriptor saved ;
if ( ! readEncryptedFile ( saved , _savedPeersKey ) ) {
clearKey ( _savedPeersKey ) ;
_savedPeersKey = 0 ;
_writeMap ( ) ;
return ;
}
if ( saved . version = = 9011 ) { // broken dev version
clearKey ( _savedPeersKey ) ;
_savedPeersKey = 0 ;
_writeMap ( ) ;
return ;
}
2016-01-01 14:48:32 +00:00
2016-09-15 19:15:49 +00:00
quint32 count = 0 ;
saved . stream > > count ;
cRefSavedPeers ( ) . clear ( ) ;
cRefSavedPeersByTime ( ) . clear ( ) ;
QList < PeerData * > peers ;
peers . reserve ( count ) ;
for ( uint32 i = 0 ; i < count ; + + i ) {
PeerData * peer = _readPeer ( saved ) ;
if ( ! peer ) break ;
QDateTime t ;
saved . stream > > t ;
cRefSavedPeers ( ) . insert ( peer , t ) ;
cRefSavedPeersByTime ( ) . insert ( t , peer ) ;
peers . push_back ( peer ) ;
}
2016-01-01 14:48:32 +00:00
2017-08-04 14:54:32 +00:00
Auth ( ) . api ( ) . requestPeers ( peers ) ;
2016-09-15 19:15:49 +00:00
}
2016-01-01 14:48:32 +00:00
2016-09-15 19:15:49 +00:00
void addSavedPeer ( PeerData * peer , const QDateTime & position ) {
auto & savedPeers = cRefSavedPeers ( ) ;
auto i = savedPeers . find ( peer ) ;
if ( i = = savedPeers . cend ( ) ) {
savedPeers . insert ( peer , position ) ;
} else if ( i . value ( ) ! = position ) {
cRefSavedPeersByTime ( ) . remove ( i . value ( ) , peer ) ;
i . value ( ) = position ;
cRefSavedPeersByTime ( ) . insert ( i . value ( ) , peer ) ;
2016-01-01 14:48:32 +00:00
}
2016-09-15 19:15:49 +00:00
writeSavedPeers ( ) ;
}
2016-01-01 14:48:32 +00:00
2016-09-15 19:15:49 +00:00
void removeSavedPeer ( PeerData * peer ) {
auto & savedPeers = cRefSavedPeers ( ) ;
if ( savedPeers . isEmpty ( ) ) return ;
2015-08-07 12:11:50 +00:00
2016-09-15 19:15:49 +00:00
auto i = savedPeers . find ( peer ) ;
if ( i ! = savedPeers . cend ( ) ) {
cRefSavedPeersByTime ( ) . remove ( i . value ( ) , peer ) ;
savedPeers . erase ( i ) ;
2015-08-07 12:11:50 +00:00
2016-09-15 19:15:49 +00:00
writeSavedPeers ( ) ;
2015-08-07 12:11:50 +00:00
}
2016-09-15 19:15:49 +00:00
}
2015-08-07 12:11:50 +00:00
2016-09-15 19:15:49 +00:00
void writeReportSpamStatuses ( ) {
_writeReportSpamStatuses ( ) ;
}
2015-08-07 12:11:50 +00:00
2016-09-15 19:15:49 +00:00
void writeTrustedBots ( ) {
if ( ! _working ( ) ) return ;
if ( _trustedBots . isEmpty ( ) ) {
if ( _trustedBotsKey ) {
clearKey ( _trustedBotsKey ) ;
_trustedBotsKey = 0 ;
_mapChanged = true ;
2015-08-07 12:11:50 +00:00
_writeMap ( ) ;
}
2016-09-15 19:15:49 +00:00
} else {
if ( ! _trustedBotsKey ) {
_trustedBotsKey = genKey ( ) ;
_mapChanged = true ;
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Fast ) ;
2015-11-22 13:24:17 +00:00
}
2016-09-15 19:15:49 +00:00
quint32 size = sizeof ( qint32 ) + _trustedBots . size ( ) * sizeof ( quint64 ) ;
EncryptedDescriptor data ( size ) ;
data . stream < < qint32 ( _trustedBots . size ( ) ) ;
for_const ( auto botId , _trustedBots ) {
data . stream < < quint64 ( botId ) ;
2015-08-07 12:11:50 +00:00
}
2016-05-25 12:09:05 +00:00
2016-09-15 19:15:49 +00:00
FileWriteDescriptor file ( _trustedBotsKey ) ;
file . writeEncrypted ( data ) ;
2015-08-07 12:11:50 +00:00
}
2016-09-15 19:15:49 +00:00
}
2015-08-07 12:11:50 +00:00
2016-09-15 19:15:49 +00:00
void readTrustedBots ( ) {
if ( ! _trustedBotsKey ) return ;
2015-08-07 12:11:50 +00:00
2016-09-15 19:15:49 +00:00
FileReadDescriptor trusted ;
if ( ! readEncryptedFile ( trusted , _trustedBotsKey ) ) {
clearKey ( _trustedBotsKey ) ;
_trustedBotsKey = 0 ;
_writeMap ( ) ;
return ;
2015-08-07 12:11:50 +00:00
}
2016-09-15 19:15:49 +00:00
qint32 size = 0 ;
trusted . stream > > size ;
for ( int i = 0 ; i < size ; + + i ) {
quint64 botId = 0 ;
trusted . stream > > botId ;
_trustedBots . insert ( botId ) ;
2015-09-07 15:53:46 +00:00
}
2016-09-15 19:15:49 +00:00
}
2015-09-07 15:53:46 +00:00
2016-09-15 19:15:49 +00:00
void makeBotTrusted ( UserData * bot ) {
if ( ! isBotTrusted ( bot ) ) {
_trustedBots . insert ( bot - > id ) ;
writeTrustedBots ( ) ;
2016-09-07 09:04:57 +00:00
}
2016-09-15 19:15:49 +00:00
}
2016-09-07 09:04:57 +00:00
2016-09-15 19:15:49 +00:00
bool isBotTrusted ( UserData * bot ) {
if ( ! _trustedBotsRead ) {
readTrustedBots ( ) ;
_trustedBotsRead = true ;
2016-09-07 09:04:57 +00:00
}
2016-09-15 19:15:49 +00:00
return _trustedBots . contains ( bot - > id ) ;
}
2016-09-07 09:04:57 +00:00
2016-09-15 19:15:49 +00:00
bool encrypt ( const void * src , void * dst , uint32 len , const void * key128 ) {
2017-02-25 16:44:02 +00:00
if ( ! LocalKey ) {
2016-09-15 19:15:49 +00:00
return false ;
}
2017-02-25 16:44:02 +00:00
MTP : : aesEncryptLocal ( src , dst , len , LocalKey , key128 ) ;
2016-09-15 19:15:49 +00:00
return true ;
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
bool decrypt ( const void * src , void * dst , uint32 len , const void * key128 ) {
2017-02-25 16:44:02 +00:00
if ( ! LocalKey ) {
2016-09-15 19:15:49 +00:00
return false ;
2014-11-22 09:45:04 +00:00
}
2017-02-25 16:44:02 +00:00
MTP : : aesDecryptLocal ( src , dst , len , LocalKey , key128 ) ;
2016-09-15 19:15:49 +00:00
return true ;
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
struct ClearManagerData {
QThread * thread ;
StorageMap images , stickers , audios ;
WebFilesMap webFiles ;
QMutex mutex ;
QList < int > tasks ;
bool working ;
} ;
ClearManager : : ClearManager ( ) : data ( new ClearManagerData ( ) ) {
data - > thread = new QThread ( ) ;
data - > working = true ;
}
bool ClearManager : : addTask ( int task ) {
QMutexLocker lock ( & data - > mutex ) ;
if ( ! data - > working ) return false ;
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
if ( ! data - > tasks . isEmpty ( ) & & ( data - > tasks . at ( 0 ) = = ClearManagerAll ) ) return true ;
if ( task = = ClearManagerAll ) {
data - > tasks . clear ( ) ;
if ( ! _imagesMap . isEmpty ( ) ) {
_imagesMap . clear ( ) ;
_storageImagesSize = 0 ;
_mapChanged = true ;
}
if ( ! _stickerImagesMap . isEmpty ( ) ) {
_stickerImagesMap . clear ( ) ;
_storageStickersSize = 0 ;
_mapChanged = true ;
}
if ( ! _audiosMap . isEmpty ( ) ) {
_audiosMap . clear ( ) ;
_storageAudiosSize = 0 ;
_mapChanged = true ;
}
if ( ! _draftsMap . isEmpty ( ) ) {
_draftsMap . clear ( ) ;
_mapChanged = true ;
}
if ( ! _draftCursorsMap . isEmpty ( ) ) {
_draftCursorsMap . clear ( ) ;
_mapChanged = true ;
}
if ( _locationsKey ) {
_locationsKey = 0 ;
_mapChanged = true ;
}
if ( _reportSpamStatusesKey ) {
_reportSpamStatusesKey = 0 ;
_mapChanged = true ;
}
if ( _trustedBotsKey ) {
_trustedBotsKey = 0 ;
_mapChanged = true ;
}
if ( _recentStickersKeyOld ) {
_recentStickersKeyOld = 0 ;
_mapChanged = true ;
}
if ( _installedStickersKey | | _featuredStickersKey | | _recentStickersKey | | _archivedStickersKey ) {
_installedStickersKey = _featuredStickersKey = _recentStickersKey = _archivedStickersKey = 0 ;
_mapChanged = true ;
}
if ( _recentHashtagsAndBotsKey ) {
_recentHashtagsAndBotsKey = 0 ;
_mapChanged = true ;
}
if ( _savedPeersKey ) {
_savedPeersKey = 0 ;
_mapChanged = true ;
}
_writeMap ( ) ;
} else {
if ( task & ClearManagerStorage ) {
if ( data - > images . isEmpty ( ) ) {
data - > images = _imagesMap ;
} else {
for ( StorageMap : : const_iterator i = _imagesMap . cbegin ( ) , e = _imagesMap . cend ( ) ; i ! = e ; + + i ) {
StorageKey k = i . key ( ) ;
while ( data - > images . constFind ( k ) ! = data - > images . cend ( ) ) {
+ + k . second ;
}
data - > images . insert ( k , i . value ( ) ) ;
}
}
2015-01-02 14:55:24 +00:00
if ( ! _imagesMap . isEmpty ( ) ) {
_imagesMap . clear ( ) ;
_storageImagesSize = 0 ;
_mapChanged = true ;
}
2016-09-15 19:15:49 +00:00
if ( data - > stickers . isEmpty ( ) ) {
data - > stickers = _stickerImagesMap ;
} else {
for ( StorageMap : : const_iterator i = _stickerImagesMap . cbegin ( ) , e = _stickerImagesMap . cend ( ) ; i ! = e ; + + i ) {
StorageKey k = i . key ( ) ;
while ( data - > stickers . constFind ( k ) ! = data - > stickers . cend ( ) ) {
+ + k . second ;
}
data - > stickers . insert ( k , i . value ( ) ) ;
}
}
2015-05-19 15:46:45 +00:00
if ( ! _stickerImagesMap . isEmpty ( ) ) {
_stickerImagesMap . clear ( ) ;
2015-01-02 14:55:24 +00:00
_storageStickersSize = 0 ;
_mapChanged = true ;
}
2016-09-15 19:15:49 +00:00
if ( data - > webFiles . isEmpty ( ) ) {
data - > webFiles = _webFilesMap ;
} else {
for ( WebFilesMap : : const_iterator i = _webFilesMap . cbegin ( ) , e = _webFilesMap . cend ( ) ; i ! = e ; + + i ) {
QString k = i . key ( ) ;
while ( data - > webFiles . constFind ( k ) ! = data - > webFiles . cend ( ) ) {
k + = ' # ' ;
2016-01-01 07:42:06 +00:00
}
2016-09-15 19:15:49 +00:00
data - > webFiles . insert ( k , i . value ( ) ) ;
2016-01-01 07:42:06 +00:00
}
2016-09-15 19:15:49 +00:00
}
if ( ! _webFilesMap . isEmpty ( ) ) {
_webFilesMap . clear ( ) ;
_storageWebFilesSize = 0 ;
_writeLocations ( ) ;
}
if ( data - > audios . isEmpty ( ) ) {
data - > audios = _audiosMap ;
} else {
for ( StorageMap : : const_iterator i = _audiosMap . cbegin ( ) , e = _audiosMap . cend ( ) ; i ! = e ; + + i ) {
StorageKey k = i . key ( ) ;
while ( data - > audios . constFind ( k ) ! = data - > audios . cend ( ) ) {
+ + k . second ;
2015-01-02 14:55:24 +00:00
}
2016-09-15 19:15:49 +00:00
data - > audios . insert ( k , i . value ( ) ) ;
2015-01-02 14:55:24 +00:00
}
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
if ( ! _audiosMap . isEmpty ( ) ) {
_audiosMap . clear ( ) ;
_storageAudiosSize = 0 ;
_mapChanged = true ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
_writeMap ( ) ;
2014-11-22 09:45:04 +00:00
}
for ( int32 i = 0 , l = data - > tasks . size ( ) ; i < l ; + + i ) {
if ( data - > tasks . at ( i ) = = task ) return true ;
}
}
2016-09-15 19:15:49 +00:00
data - > tasks . push_back ( task ) ;
return true ;
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
bool ClearManager : : hasTask ( ClearManagerTask task ) {
QMutexLocker lock ( & data - > mutex ) ;
if ( data - > tasks . isEmpty ( ) ) return false ;
if ( data - > tasks . at ( 0 ) = = ClearManagerAll ) return true ;
for ( int32 i = 0 , l = data - > tasks . size ( ) ; i < l ; + + i ) {
if ( data - > tasks . at ( i ) = = task ) return true ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
return false ;
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
void ClearManager : : start ( ) {
moveToThread ( data - > thread ) ;
connect ( data - > thread , SIGNAL ( started ( ) ) , this , SLOT ( onStart ( ) ) ) ;
connect ( data - > thread , SIGNAL ( finished ( ) ) , data - > thread , SLOT ( deleteLater ( ) ) ) ;
connect ( data - > thread , SIGNAL ( finished ( ) ) , this , SLOT ( deleteLater ( ) ) ) ;
data - > thread - > start ( ) ;
}
2016-08-28 19:16:23 +00:00
2016-09-15 19:15:49 +00:00
void ClearManager : : stop ( ) {
{
QMutexLocker lock ( & data - > mutex ) ;
data - > tasks . clear ( ) ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
auto thread = data - > thread ;
thread - > quit ( ) ;
thread - > wait ( ) ;
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
ClearManager : : ~ ClearManager ( ) {
delete data ;
}
void ClearManager : : onStart ( ) {
while ( true ) {
int task = 0 ;
bool result = false ;
StorageMap images , stickers , audios ;
WebFilesMap webFiles ;
{
QMutexLocker lock ( & data - > mutex ) ;
if ( data - > tasks . isEmpty ( ) ) {
data - > working = false ;
break ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
task = data - > tasks . at ( 0 ) ;
images = data - > images ;
stickers = data - > stickers ;
audios = data - > audios ;
webFiles = data - > webFiles ;
}
switch ( task ) {
case ClearManagerAll : {
result = QDir ( cTempDir ( ) ) . removeRecursively ( ) ;
QDirIterator di ( _userBasePath , QDir : : AllEntries | QDir : : Hidden | QDir : : System | QDir : : NoDotAndDotDot ) ;
while ( di . hasNext ( ) ) {
di . next ( ) ;
const QFileInfo & fi = di . fileInfo ( ) ;
if ( fi . isDir ( ) & & ! fi . isSymLink ( ) ) {
if ( ! QDir ( di . filePath ( ) ) . removeRecursively ( ) ) result = false ;
} else {
QString path = di . filePath ( ) ;
if ( ! path . endsWith ( qstr ( " map0 " ) ) & & ! path . endsWith ( qstr ( " map1 " ) ) ) {
if ( ! QFile : : remove ( di . filePath ( ) ) ) result = false ;
2015-03-02 12:34:16 +00:00
}
}
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
} break ;
case ClearManagerDownloads :
result = QDir ( cTempDir ( ) ) . removeRecursively ( ) ;
break ;
case ClearManagerStorage :
for ( StorageMap : : const_iterator i = images . cbegin ( ) , e = images . cend ( ) ; i ! = e ; + + i ) {
2016-10-28 12:44:28 +00:00
clearKey ( i . value ( ) . first , FileOption : : User ) ;
2016-09-15 19:15:49 +00:00
}
for ( StorageMap : : const_iterator i = stickers . cbegin ( ) , e = stickers . cend ( ) ; i ! = e ; + + i ) {
2016-10-28 12:44:28 +00:00
clearKey ( i . value ( ) . first , FileOption : : User ) ;
2016-09-15 19:15:49 +00:00
}
for ( StorageMap : : const_iterator i = audios . cbegin ( ) , e = audios . cend ( ) ; i ! = e ; + + i ) {
2016-10-28 12:44:28 +00:00
clearKey ( i . value ( ) . first , FileOption : : User ) ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
for ( WebFilesMap : : const_iterator i = webFiles . cbegin ( ) , e = webFiles . cend ( ) ; i ! = e ; + + i ) {
2016-10-28 12:44:28 +00:00
clearKey ( i . value ( ) . first , FileOption : : User ) ;
2016-09-15 19:15:49 +00:00
}
result = true ;
break ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
{
QMutexLocker lock ( & data - > mutex ) ;
if ( ! data - > tasks . isEmpty ( ) & & data - > tasks . at ( 0 ) = = task ) {
data - > tasks . pop_front ( ) ;
}
if ( data - > tasks . isEmpty ( ) ) {
data - > working = false ;
}
if ( result ) {
emit succeed ( task , data - > working ? 0 : this ) ;
} else {
emit failed ( task , data - > working ? 0 : this ) ;
}
if ( ! data - > working ) break ;
}
}
}
namespace internal {
Manager : : Manager ( ) {
_mapWriteTimer . setSingleShot ( true ) ;
connect ( & _mapWriteTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( mapWriteTimeout ( ) ) ) ;
_locationsWriteTimer . setSingleShot ( true ) ;
connect ( & _locationsWriteTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( locationsWriteTimeout ( ) ) ) ;
}
void Manager : : writeMap ( bool fast ) {
if ( ! _mapWriteTimer . isActive ( ) | | fast ) {
_mapWriteTimer . start ( fast ? 1 : WriteMapTimeout ) ;
} else if ( _mapWriteTimer . remainingTime ( ) < = 0 ) {
mapWriteTimeout ( ) ;
}
}
void Manager : : writingMap ( ) {
_mapWriteTimer . stop ( ) ;
}
void Manager : : writeLocations ( bool fast ) {
if ( ! _locationsWriteTimer . isActive ( ) | | fast ) {
_locationsWriteTimer . start ( fast ? 1 : WriteMapTimeout ) ;
} else if ( _locationsWriteTimer . remainingTime ( ) < = 0 ) {
locationsWriteTimeout ( ) ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
}
void Manager : : writingLocations ( ) {
_locationsWriteTimer . stop ( ) ;
}
void Manager : : mapWriteTimeout ( ) {
2017-03-28 12:30:38 +00:00
_writeMap ( WriteMapWhen : : Now ) ;
2016-09-15 19:15:49 +00:00
}
2014-11-22 09:45:04 +00:00
2016-09-15 19:15:49 +00:00
void Manager : : locationsWriteTimeout ( ) {
2017-03-28 12:30:38 +00:00
_writeLocations ( WriteMapWhen : : Now ) ;
2014-11-22 09:45:04 +00:00
}
2016-09-15 19:15:49 +00:00
void Manager : : finish ( ) {
if ( _mapWriteTimer . isActive ( ) ) {
mapWriteTimeout ( ) ;
}
if ( _locationsWriteTimer . isActive ( ) ) {
locationsWriteTimeout ( ) ;
}
}
} // namespace internal
} // namespace Local