2014-05-30 08:53:19 +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-05-30 08:53:19 +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-05-30 08:53:19 +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-05-30 08:53:19 +00:00
*/
# pragma once
2016-04-12 21:31:28 +00:00
# include "core/basic_types.h"
2014-05-30 08:53:19 +00:00
2016-03-24 08:57:11 +00:00
namespace MTP {
2015-02-19 11:30:16 +00:00
2016-03-24 08:57:11 +00:00
// type DcId represents actual data center id, while in most cases
// we use some shifted ids, like DcId() + X * DCShift
2017-02-25 16:44:02 +00:00
using DcId = int32 ;
2017-02-27 18:47:29 +00:00
using ShiftedDcId = int32 ;
2014-05-30 08:53:19 +00:00
2017-03-09 18:13:55 +00:00
} // namespace MTP
2014-05-30 08:53:19 +00:00
2017-02-25 16:44:02 +00:00
using mtpPrime = int32 ;
using mtpRequestId = int32 ;
using mtpMsgId = uint64 ;
using mtpPingId = uint64 ;
2014-05-30 08:53:19 +00:00
2017-02-25 16:44:02 +00:00
using mtpBuffer = QVector < mtpPrime > ;
using mtpTypeId = uint32 ;
2014-05-30 08:53:19 +00:00
class mtpRequestData ;
class mtpRequest : public QSharedPointer < mtpRequestData > {
public :
mtpRequest ( ) {
}
explicit mtpRequest ( mtpRequestData * ptr ) : QSharedPointer < mtpRequestData > ( ptr ) {
}
2014-11-14 23:23:35 +00:00
uint32 innerLength ( ) const ;
2014-05-30 08:53:19 +00:00
void write ( mtpBuffer & to ) const ;
2017-02-25 16:44:02 +00:00
using ResponseType = void ; // don't know real response type =(
2014-05-30 08:53:19 +00:00
} ;
class mtpRequestData : public mtpBuffer {
public :
// in toSend: = 0 - must send in container, > 0 - can send without container
// in haveSent: = 0 - container with msgIds, > 0 - when was sent
2016-12-01 19:20:33 +00:00
TimeMs msDate ;
2014-11-14 23:23:35 +00:00
2014-05-30 08:53:19 +00:00
mtpRequestId requestId ;
2014-11-05 17:43:32 +00:00
mtpRequest after ;
2014-11-14 23:23:35 +00:00
bool needsLayer ;
2014-05-30 08:53:19 +00:00
2014-11-14 23:23:35 +00:00
mtpRequestData ( bool /* sure*/ ) : msDate ( 0 ) , requestId ( 0 ) , needsLayer ( false ) {
2014-05-30 08:53:19 +00:00
}
2014-11-05 17:43:32 +00:00
static mtpRequest prepare ( uint32 requestSize , uint32 maxSize = 0 ) {
if ( ! maxSize ) maxSize = requestSize ;
2014-05-30 08:53:19 +00:00
mtpRequest result ( new mtpRequestData ( true ) ) ;
2014-11-05 17:43:32 +00:00
result - > reserve ( 8 + maxSize + _padding ( maxSize ) ) ; // 2: salt, 2: session_id, 2: msg_id, 1: seq_no, 1: message_length
2014-05-30 08:53:19 +00:00
result - > resize ( 7 ) ;
result - > push_back ( requestSize < < 2 ) ;
return result ;
}
static void padding ( mtpRequest & request ) {
if ( request - > size ( ) < 9 ) return ;
2014-11-14 23:23:35 +00:00
uint32 requestSize = ( request . innerLength ( ) > > 2 ) , padding = _padding ( requestSize ) , fullSize = 8 + requestSize + padding ; // 2: salt, 2: session_id, 2: msg_id, 1: seq_no, 1: message_length
2014-05-30 08:53:19 +00:00
if ( uint32 ( request - > size ( ) ) ! = fullSize ) {
request - > resize ( fullSize ) ;
if ( padding ) {
memset_rand ( request - > data ( ) + ( fullSize - padding ) , padding * sizeof ( mtpPrime ) ) ;
}
}
}
static uint32 messageSize ( const mtpRequest & request ) {
if ( request - > size ( ) < 9 ) return 0 ;
2014-11-14 23:23:35 +00:00
return 4 + ( request . innerLength ( ) > > 2 ) ; // 2: msg_id, 1: seq_no, q: message_length
2014-05-30 08:53:19 +00:00
}
static bool isSentContainer ( const mtpRequest & request ) ; // "request-like" wrap for msgIds vector
static bool isStateRequest ( const mtpRequest & request ) ;
static bool needAck ( const mtpRequest & request ) ;
static bool needAckByType ( mtpTypeId type ) ;
private :
static uint32 _padding ( uint32 requestSize ) {
return ( ( 8 + requestSize ) & 0x03 ) ? ( 4 - ( ( 8 + requestSize ) & 0x03 ) ) : 0 ;
}
} ;
2014-11-14 23:23:35 +00:00
inline uint32 mtpRequest : : innerLength ( ) const { // for template MTP requests and MTPBoxed instanciation
2014-05-30 08:53:19 +00:00
mtpRequestData * value = data ( ) ;
if ( ! value | | value - > size ( ) < 9 ) return 0 ;
return value - > at ( 7 ) ;
}
inline void mtpRequest : : write ( mtpBuffer & to ) const {
mtpRequestData * value = data ( ) ;
if ( ! value | | value - > size ( ) < 9 ) return ;
2014-11-14 23:23:35 +00:00
uint32 was = to . size ( ) , s = innerLength ( ) / sizeof ( mtpPrime ) ;
2014-05-30 08:53:19 +00:00
to . resize ( was + s ) ;
memcpy ( to . data ( ) + was , value - > constData ( ) + 8 , s * sizeof ( mtpPrime ) ) ;
}
class mtpResponse : public mtpBuffer {
public :
mtpResponse ( ) {
}
mtpResponse ( const mtpBuffer & v ) : mtpBuffer ( v ) {
}
mtpResponse & operator = ( const mtpBuffer & v ) {
mtpBuffer : : operator = ( v ) ;
return ( * this ) ;
}
bool needAck ( ) const {
if ( size ( ) < 8 ) return false ;
uint32 seqNo = * ( uint32 * ) ( constData ( ) + 6 ) ;
return ( seqNo & 0x01 ) ? true : false ;
}
} ;
2017-02-25 16:44:02 +00:00
using mtpPreRequestMap = QMap < mtpRequestId , mtpRequest > ;
using mtpRequestMap = QMap < mtpMsgId , mtpRequest > ;
using mtpMsgIdsSet = QMap < mtpMsgId , bool > ;
2014-05-30 08:53:19 +00:00
class mtpRequestIdsMap : public QMap < mtpMsgId , mtpRequestId > {
public :
2017-02-25 16:44:02 +00:00
using ParentType = QMap < mtpMsgId , mtpRequestId > ;
2014-05-30 08:53:19 +00:00
mtpMsgId min ( ) const {
return size ( ) ? cbegin ( ) . key ( ) : 0 ;
}
mtpMsgId max ( ) const {
ParentType : : const_iterator e ( cend ( ) ) ;
return size ( ) ? ( - - e ) . key ( ) : 0 ;
}
} ;
2017-02-25 16:44:02 +00:00
using mtpResponseMap = QMap < mtpRequestId , mtpResponse > ;
2014-05-30 08:53:19 +00:00
class mtpErrorUnexpected : public Exception {
public :
2015-10-03 10:09:09 +00:00
mtpErrorUnexpected ( mtpTypeId typeId , const QString & type ) : Exception ( QString ( " MTP Unexpected type id #%1 read in %2 " ) . arg ( uint32 ( typeId ) , 0 , 16 ) . arg ( type ) , false ) { // maybe api changed?..
2014-05-30 08:53:19 +00:00
}
} ;
class mtpErrorInsufficient : public Exception {
public :
mtpErrorInsufficient ( ) : Exception ( " MTP Insufficient bytes in input buffer " ) {
}
} ;
class mtpErrorBadTypeId : public Exception {
public :
mtpErrorBadTypeId ( mtpTypeId typeId , const QString & type ) : Exception ( QString ( " MTP Bad type id %1 passed to constructor of %2 " ) . arg ( typeId ) . arg ( type ) ) {
}
} ;
2017-03-11 17:03:36 +00:00
namespace MTP {
namespace internal {
class TypeData {
2014-05-30 08:53:19 +00:00
public :
2017-03-11 17:03:36 +00:00
TypeData ( ) = default ;
TypeData ( const TypeData & other ) = delete ;
TypeData ( TypeData & & other ) = delete ;
TypeData & operator = ( const TypeData & other ) = delete ;
TypeData & operator = ( TypeData & & other ) = delete ;
2017-03-13 15:40:21 +00:00
virtual ~ TypeData ( ) {
}
private :
2017-03-11 17:03:36 +00:00
void incrementCounter ( ) const {
_counter . ref ( ) ;
}
bool decrementCounter ( ) const {
return _counter . deref ( ) ;
2014-05-30 08:53:19 +00:00
}
2017-03-13 15:40:21 +00:00
friend class TypeDataOwner ;
2014-05-30 08:53:19 +00:00
2017-03-11 17:03:36 +00:00
mutable QAtomicInt _counter = { 1 } ;
2014-05-30 08:53:19 +00:00
} ;
2017-03-11 17:03:36 +00:00
class TypeDataOwner {
2014-05-30 08:53:19 +00:00
public :
2017-03-11 17:03:36 +00:00
TypeDataOwner ( TypeDataOwner & & other ) : _data ( base : : take ( other . _data ) ) {
}
TypeDataOwner ( const TypeDataOwner & other ) : _data ( other . _data ) {
incrementCounter ( ) ;
}
TypeDataOwner & operator = ( TypeDataOwner & & other ) {
if ( other . _data ! = _data ) {
decrementCounter ( ) ;
_data = base : : take ( other . _data ) ;
}
return * this ;
}
TypeDataOwner & operator = ( const TypeDataOwner & other ) {
if ( other . _data ! = _data ) {
setData ( other . _data ) ;
incrementCounter ( ) ;
}
return * this ;
}
~ TypeDataOwner ( ) {
decrementCounter ( ) ;
}
2014-05-30 08:53:19 +00:00
protected :
2017-03-11 17:03:36 +00:00
TypeDataOwner ( ) = default ;
TypeDataOwner ( const TypeData * data ) : _data ( data ) {
}
void setData ( const TypeData * data ) {
decrementCounter ( ) ;
_data = data ;
}
template < typename DataType >
const DataType & queryData ( ) const {
// Unsafe cast, type should be checked by the caller.
t_assert ( _data ! = nullptr ) ;
return static_cast < const DataType & > ( * _data ) ;
}
private :
void incrementCounter ( ) {
if ( _data ) {
_data - > incrementCounter ( ) ;
}
}
void decrementCounter ( ) {
if ( _data & & ! _data - > decrementCounter ( ) ) {
delete base : : take ( _data ) ;
}
2014-05-30 08:53:19 +00:00
}
2017-03-11 17:03:36 +00:00
const TypeData * _data = nullptr ;
2017-03-09 18:13:55 +00:00
2014-05-30 08:53:19 +00:00
} ;
2017-03-11 17:03:36 +00:00
} // namespace internal
} // namespace MTP
2014-05-30 08:53:19 +00:00
enum {
// core types
mtpc_int = 0xa8509bda ,
mtpc_long = 0x22076cba ,
mtpc_int128 = 0x4bb5362b ,
mtpc_int256 = 0x929c32f ,
mtpc_double = 0x2210c154 ,
mtpc_string = 0xb5286e24 ,
mtpc_vector = 0x1cb5c415 ,
// layers
mtpc_invokeWithLayer1 = 0x53835315 ,
mtpc_invokeWithLayer2 = 0x289dd1f6 ,
mtpc_invokeWithLayer3 = 0xb7475268 ,
mtpc_invokeWithLayer4 = 0xdea0d430 ,
mtpc_invokeWithLayer5 = 0x417a57ae ,
mtpc_invokeWithLayer6 = 0x3a64d54d ,
mtpc_invokeWithLayer7 = 0xa5be56d3 ,
mtpc_invokeWithLayer8 = 0xe9abd9fd ,
mtpc_invokeWithLayer9 = 0x76715a63 ,
mtpc_invokeWithLayer10 = 0x39620c41 ,
mtpc_invokeWithLayer11 = 0xa6b88fdf ,
mtpc_invokeWithLayer12 = 0xdda60d3c ,
mtpc_invokeWithLayer13 = 0x427c8ea2 ,
mtpc_invokeWithLayer14 = 0x2b9b08fa ,
2014-07-04 11:12:54 +00:00
mtpc_invokeWithLayer15 = 0xb4418b64 ,
2014-10-22 18:39:03 +00:00
mtpc_invokeWithLayer16 = 0xcf5f0987 ,
mtpc_invokeWithLayer17 = 0x50858a19 ,
mtpc_invokeWithLayer18 = 0x1c900537 ,
2014-05-30 08:53:19 +00:00
// manually parsed
mtpc_rpc_result = 0xf35c6d01 ,
mtpc_msg_container = 0x73f1f8dc ,
// mtpc_msg_copy = 0xe06046b2,
mtpc_gzip_packed = 0x3072cfa1
} ;
2014-06-14 19:32:11 +00:00
static const mtpTypeId mtpc_bytes = mtpc_string ;
2016-03-19 16:55:15 +00:00
static const mtpTypeId mtpc_flags = mtpc_int ;
2014-06-14 19:32:11 +00:00
static const mtpTypeId mtpc_core_message = - 1 ; // undefined type, but is used
static const mtpTypeId mtpLayers [ ] = {
2015-10-23 16:06:56 +00:00
mtpTypeId ( mtpc_invokeWithLayer1 ) ,
mtpTypeId ( mtpc_invokeWithLayer2 ) ,
mtpTypeId ( mtpc_invokeWithLayer3 ) ,
mtpTypeId ( mtpc_invokeWithLayer4 ) ,
mtpTypeId ( mtpc_invokeWithLayer5 ) ,
mtpTypeId ( mtpc_invokeWithLayer6 ) ,
mtpTypeId ( mtpc_invokeWithLayer7 ) ,
mtpTypeId ( mtpc_invokeWithLayer8 ) ,
mtpTypeId ( mtpc_invokeWithLayer9 ) ,
mtpTypeId ( mtpc_invokeWithLayer10 ) ,
mtpTypeId ( mtpc_invokeWithLayer11 ) ,
mtpTypeId ( mtpc_invokeWithLayer12 ) ,
mtpTypeId ( mtpc_invokeWithLayer13 ) ,
mtpTypeId ( mtpc_invokeWithLayer14 ) ,
mtpTypeId ( mtpc_invokeWithLayer15 ) ,
mtpTypeId ( mtpc_invokeWithLayer16 ) ,
mtpTypeId ( mtpc_invokeWithLayer17 ) ,
mtpTypeId ( mtpc_invokeWithLayer18 ) ,
2015-10-19 21:16:17 +00:00
} ;
static const uint32 mtpLayerMaxSingle = sizeof ( mtpLayers ) / sizeof ( mtpLayers [ 0 ] ) ;
2014-05-30 08:53:19 +00:00
template < typename bareT >
class MTPBoxed : public bareT {
public :
2017-03-09 19:15:31 +00:00
MTPBoxed ( ) = default ;
2014-05-30 08:53:19 +00:00
MTPBoxed ( const bareT & v ) : bareT ( v ) {
}
MTPBoxed ( const MTPBoxed < bareT > & v ) : bareT ( v ) {
}
MTPBoxed < bareT > & operator = ( const bareT & v ) {
* ( ( bareT * ) this ) = v ;
return * this ;
}
MTPBoxed < bareT > & operator = ( const MTPBoxed < bareT > & v ) {
* ( ( bareT * ) this ) = v ;
return * this ;
}
2014-11-14 23:23:35 +00:00
uint32 innerLength ( ) const {
return sizeof ( mtpTypeId ) + bareT : : innerLength ( ) ;
2014-05-30 08:53:19 +00:00
}
void read ( const mtpPrime * & from , const mtpPrime * end , mtpTypeId cons = 0 ) {
if ( from + 1 > end ) throw mtpErrorInsufficient ( ) ;
cons = ( mtpTypeId ) * ( from + + ) ;
bareT : : read ( from , end , cons ) ;
}
void write ( mtpBuffer & to ) const {
to . push_back ( bareT : : type ( ) ) ;
bareT : : write ( to ) ;
}
} ;
template < typename T >
class MTPBoxed < MTPBoxed < T > > {
typename T : : CantMakeBoxedBoxedType v ;
} ;
class MTPint {
public :
2017-03-09 19:15:31 +00:00
int32 v = 0 ;
2014-05-30 08:53:19 +00:00
2017-03-09 19:15:31 +00:00
MTPint ( ) = default ;
2014-05-30 08:53:19 +00:00
2014-11-14 23:23:35 +00:00
uint32 innerLength ( ) const {
2014-05-30 08:53:19 +00:00
return sizeof ( int32 ) ;
}
mtpTypeId type ( ) const {
return mtpc_int ;
}
void read ( const mtpPrime * & from , const mtpPrime * end , mtpTypeId cons = mtpc_int ) {
if ( from + 1 > end ) throw mtpErrorInsufficient ( ) ;
if ( cons ! = mtpc_int ) throw mtpErrorUnexpected ( cons , " MTPint " ) ;
v = ( int32 ) * ( from + + ) ;
}
void write ( mtpBuffer & to ) const {
to . push_back ( ( mtpPrime ) v ) ;
}
private :
explicit MTPint ( int32 val ) : v ( val ) {
}
friend MTPint MTP_int ( int32 v ) ;
} ;
inline MTPint MTP_int ( int32 v ) {
return MTPint ( v ) ;
}
2017-02-25 16:44:02 +00:00
using MTPInt = MTPBoxed < MTPint > ;
2014-05-30 08:53:19 +00:00
2016-03-19 16:55:15 +00:00
template < typename Flags >
class MTPflags {
public :
2017-03-09 19:15:31 +00:00
Flags v = Flags ( 0 ) ;
2016-03-19 16:55:15 +00:00
static_assert ( sizeof ( Flags ) = = sizeof ( int32 ) , " MTPflags are allowed only wrapping int32 flag types! " ) ;
2017-03-09 19:15:31 +00:00
MTPflags ( ) = default ;
2016-03-19 16:55:15 +00:00
uint32 innerLength ( ) const {
return sizeof ( Flags ) ;
}
mtpTypeId type ( ) const {
return mtpc_flags ;
}
void read ( const mtpPrime * & from , const mtpPrime * end , mtpTypeId cons = mtpc_flags ) {
if ( from + 1 > end ) throw mtpErrorInsufficient ( ) ;
if ( cons ! = mtpc_flags ) throw mtpErrorUnexpected ( cons , " MTPflags " ) ;
v = static_cast < Flags > ( * ( from + + ) ) ;
}
void write ( mtpBuffer & to ) const {
to . push_back ( static_cast < mtpPrime > ( v ) ) ;
}
private :
explicit MTPflags ( Flags val ) : v ( val ) {
}
template < typename T >
friend MTPflags < T > MTP_flags ( T v ) ;
} ;
template < typename T >
inline MTPflags < T > MTP_flags ( T v ) {
return MTPflags < T > ( v ) ;
}
template < typename Flags >
using MTPFlags = MTPBoxed < MTPflags < Flags > > ;
2014-05-30 08:53:19 +00:00
inline bool operator = = ( const MTPint & a , const MTPint & b ) {
return a . v = = b . v ;
}
inline bool operator ! = ( const MTPint & a , const MTPint & b ) {
return a . v ! = b . v ;
}
class MTPlong {
public :
2017-03-09 19:15:31 +00:00
uint64 v = 0 ;
2014-05-30 08:53:19 +00:00
2017-03-09 19:15:31 +00:00
MTPlong ( ) = default ;
2014-05-30 08:53:19 +00:00
2014-11-14 23:23:35 +00:00
uint32 innerLength ( ) const {
2014-05-30 08:53:19 +00:00
return sizeof ( uint64 ) ;
}
mtpTypeId type ( ) const {
return mtpc_long ;
}
void read ( const mtpPrime * & from , const mtpPrime * end , mtpTypeId cons = mtpc_long ) {
if ( from + 2 > end ) throw mtpErrorInsufficient ( ) ;
if ( cons ! = mtpc_long ) throw mtpErrorUnexpected ( cons , " MTPlong " ) ;
v = ( uint64 ) ( ( ( uint32 * ) from ) [ 0 ] ) | ( ( uint64 ) ( ( ( uint32 * ) from ) [ 1 ] ) < < 32 ) ;
from + = 2 ;
}
void write ( mtpBuffer & to ) const {
to . push_back ( ( mtpPrime ) ( v & 0xFFFFFFFFL ) ) ;
to . push_back ( ( mtpPrime ) ( v > > 32 ) ) ;
}
private :
explicit MTPlong ( uint64 val ) : v ( val ) {
}
friend MTPlong MTP_long ( uint64 v ) ;
} ;
inline MTPlong MTP_long ( uint64 v ) {
return MTPlong ( v ) ;
}
2017-02-25 16:44:02 +00:00
using MTPLong = MTPBoxed < MTPlong > ;
2014-05-30 08:53:19 +00:00
inline bool operator = = ( const MTPlong & a , const MTPlong & b ) {
return a . v = = b . v ;
}
inline bool operator ! = ( const MTPlong & a , const MTPlong & b ) {
return a . v ! = b . v ;
}
class MTPint128 {
public :
2017-03-09 19:15:31 +00:00
uint64 l = 0 ;
uint64 h = 0 ;
2014-05-30 08:53:19 +00:00
2017-03-09 19:15:31 +00:00
MTPint128 ( ) = default ;
2014-05-30 08:53:19 +00:00
2014-11-14 23:23:35 +00:00
uint32 innerLength ( ) const {
2014-05-30 08:53:19 +00:00
return sizeof ( uint64 ) + sizeof ( uint64 ) ;
}
mtpTypeId type ( ) const {
return mtpc_int128 ;
}
void read ( const mtpPrime * & from , const mtpPrime * end , mtpTypeId cons = mtpc_int128 ) {
if ( from + 4 > end ) throw mtpErrorInsufficient ( ) ;
if ( cons ! = mtpc_int128 ) throw mtpErrorUnexpected ( cons , " MTPint128 " ) ;
l = ( uint64 ) ( ( ( uint32 * ) from ) [ 0 ] ) | ( ( uint64 ) ( ( ( uint32 * ) from ) [ 1 ] ) < < 32 ) ;
h = ( uint64 ) ( ( ( uint32 * ) from ) [ 2 ] ) | ( ( uint64 ) ( ( ( uint32 * ) from ) [ 3 ] ) < < 32 ) ;
from + = 4 ;
}
void write ( mtpBuffer & to ) const {
to . push_back ( ( mtpPrime ) ( l & 0xFFFFFFFFL ) ) ;
to . push_back ( ( mtpPrime ) ( l > > 32 ) ) ;
to . push_back ( ( mtpPrime ) ( h & 0xFFFFFFFFL ) ) ;
to . push_back ( ( mtpPrime ) ( h > > 32 ) ) ;
}
private :
explicit MTPint128 ( uint64 low , uint64 high ) : l ( low ) , h ( high ) {
}
friend MTPint128 MTP_int128 ( uint64 l , uint64 h ) ;
} ;
inline MTPint128 MTP_int128 ( uint64 l , uint64 h ) {
return MTPint128 ( l , h ) ;
}
2017-02-25 16:44:02 +00:00
using MTPInt128 = MTPBoxed < MTPint128 > ;
2014-05-30 08:53:19 +00:00
inline bool operator = = ( const MTPint128 & a , const MTPint128 & b ) {
return a . l = = b . l & & a . h = = b . h ;
}
inline bool operator ! = ( const MTPint128 & a , const MTPint128 & b ) {
return a . l ! = b . l | | a . h ! = b . h ;
}
class MTPint256 {
public :
MTPint128 l ;
MTPint128 h ;
2017-03-09 19:15:31 +00:00
MTPint256 ( ) = default ;
2014-05-30 08:53:19 +00:00
2014-11-14 23:23:35 +00:00
uint32 innerLength ( ) const {
return l . innerLength ( ) + h . innerLength ( ) ;
2014-05-30 08:53:19 +00:00
}
mtpTypeId type ( ) const {
return mtpc_int256 ;
}
void read ( const mtpPrime * & from , const mtpPrime * end , mtpTypeId cons = mtpc_int256 ) {
if ( cons ! = mtpc_int256 ) throw mtpErrorUnexpected ( cons , " MTPint256 " ) ;
l . read ( from , end ) ;
h . read ( from , end ) ;
}
void write ( mtpBuffer & to ) const {
l . write ( to ) ;
h . write ( to ) ;
}
private :
explicit MTPint256 ( MTPint128 low , MTPint128 high ) : l ( low ) , h ( high ) {
}
friend MTPint256 MTP_int256 ( const MTPint128 & l , const MTPint128 & h ) ;
} ;
inline MTPint256 MTP_int256 ( const MTPint128 & l , const MTPint128 & h ) {
return MTPint256 ( l , h ) ;
}
2017-02-25 16:44:02 +00:00
using MTPInt256 = MTPBoxed < MTPint256 > ;
2014-05-30 08:53:19 +00:00
inline bool operator = = ( const MTPint256 & a , const MTPint256 & b ) {
return a . l = = b . l & & a . h = = b . h ;
}
inline bool operator ! = ( const MTPint256 & a , const MTPint256 & b ) {
return a . l ! = b . l | | a . h ! = b . h ;
}
class MTPdouble {
public :
2017-03-09 19:15:31 +00:00
float64 v = 0. ;
2016-01-11 15:43:29 +00:00
2017-03-09 19:15:31 +00:00
MTPdouble ( ) = default ;
2014-05-30 08:53:19 +00:00
2014-11-14 23:23:35 +00:00
uint32 innerLength ( ) const {
2014-05-30 08:53:19 +00:00
return sizeof ( float64 ) ;
}
mtpTypeId type ( ) const {
return mtpc_double ;
}
void read ( const mtpPrime * & from , const mtpPrime * end , mtpTypeId cons = mtpc_double ) {
if ( from + 2 > end ) throw mtpErrorInsufficient ( ) ;
if ( cons ! = mtpc_double ) throw mtpErrorUnexpected ( cons , " MTPdouble " ) ;
* ( uint64 * ) ( & v ) = ( uint64 ) ( ( ( uint32 * ) from ) [ 0 ] ) | ( ( uint64 ) ( ( ( uint32 * ) from ) [ 1 ] ) < < 32 ) ;
from + = 2 ;
}
void write ( mtpBuffer & to ) const {
uint64 iv = * ( uint64 * ) ( & v ) ;
to . push_back ( ( mtpPrime ) ( iv & 0xFFFFFFFFL ) ) ;
to . push_back ( ( mtpPrime ) ( iv > > 32 ) ) ;
}
private :
explicit MTPdouble ( float64 val ) : v ( val ) {
}
friend MTPdouble MTP_double ( float64 v ) ;
} ;
inline MTPdouble MTP_double ( float64 v ) {
return MTPdouble ( v ) ;
}
2017-02-25 16:44:02 +00:00
using MTPDouble = MTPBoxed < MTPdouble > ;
2014-05-30 08:53:19 +00:00
inline bool operator = = ( const MTPdouble & a , const MTPdouble & b ) {
return a . v = = b . v ;
}
inline bool operator ! = ( const MTPdouble & a , const MTPdouble & b ) {
return a . v ! = b . v ;
}
2017-03-10 19:46:28 +00:00
class MTPstring ;
using MTPbytes = MTPstring ;
2014-05-30 08:53:19 +00:00
2017-03-10 19:46:28 +00:00
class MTPstring {
2014-05-30 08:53:19 +00:00
public :
2017-03-09 19:15:31 +00:00
MTPstring ( ) = default ;
2014-05-30 08:53:19 +00:00
2014-11-14 23:23:35 +00:00
uint32 innerLength ( ) const {
2017-03-10 19:46:28 +00:00
uint32 l = v . length ( ) ;
2014-05-30 08:53:19 +00:00
if ( l < 254 ) {
l + = 1 ;
} else {
l + = 4 ;
}
uint32 d = l & 0x03 ;
if ( d ) l + = ( 4 - d ) ;
return l ;
}
mtpTypeId type ( ) const {
return mtpc_string ;
}
void read ( const mtpPrime * & from , const mtpPrime * end , mtpTypeId cons = mtpc_string ) {
if ( from + 1 > end ) throw mtpErrorInsufficient ( ) ;
if ( cons ! = mtpc_string ) throw mtpErrorUnexpected ( cons , " MTPstring " ) ;
uint32 l ;
const uchar * buf = ( const uchar * ) from ;
if ( buf [ 0 ] = = 254 ) {
l = ( uint32 ) buf [ 1 ] + ( ( uint32 ) buf [ 2 ] < < 8 ) + ( ( uint32 ) buf [ 3 ] < < 16 ) ;
buf + = 4 ;
from + = ( ( l + 4 ) > > 2 ) + ( ( ( l + 4 ) & 0x03 ) ? 1 : 0 ) ;
} else {
l = ( uint32 ) buf [ 0 ] ;
+ + buf ;
from + = ( ( l + 1 ) > > 2 ) + ( ( ( l + 1 ) & 0x03 ) ? 1 : 0 ) ;
}
if ( from > end ) throw mtpErrorInsufficient ( ) ;
2016-01-11 15:43:29 +00:00
2017-03-10 19:46:28 +00:00
v = QByteArray ( reinterpret_cast < const char * > ( buf ) , l ) ;
2014-05-30 08:53:19 +00:00
}
void write ( mtpBuffer & to ) const {
2017-03-10 19:46:28 +00:00
uint32 l = v . length ( ) , s = l + ( ( l < 254 ) ? 1 : 4 ) , was = to . size ( ) ;
2014-05-30 08:53:19 +00:00
if ( s & 0x03 ) {
s + = 4 ;
}
s > > = 2 ;
to . resize ( was + s ) ;
char * buf = ( char * ) & to [ was ] ;
if ( l < 254 ) {
uchar sl = ( uchar ) l ;
* ( buf + + ) = * ( char * ) ( & sl ) ;
} else {
* ( buf + + ) = ( char ) 254 ;
* ( buf + + ) = ( char ) ( l & 0xFF ) ;
* ( buf + + ) = ( char ) ( ( l > > 8 ) & 0xFF ) ;
* ( buf + + ) = ( char ) ( ( l > > 16 ) & 0xFF ) ;
}
2017-03-10 19:46:28 +00:00
memcpy ( buf , v . constData ( ) , l ) ;
2014-05-30 08:53:19 +00:00
}
2017-03-10 19:46:28 +00:00
QByteArray v ;
2014-05-30 08:53:19 +00:00
private :
2017-03-10 19:46:28 +00:00
explicit MTPstring ( QByteArray & & data ) : v ( std : : move ( data ) ) {
2014-05-30 08:53:19 +00:00
}
2016-09-29 11:37:16 +00:00
friend MTPstring MTP_string ( const std : : string & v ) ;
2014-05-30 08:53:19 +00:00
friend MTPstring MTP_string ( const QString & v ) ;
friend MTPstring MTP_string ( const char * v ) ;
2016-04-01 10:23:40 +00:00
2017-03-10 19:46:28 +00:00
friend MTPbytes MTP_bytes ( const QByteArray & v ) ;
friend MTPbytes MTP_bytes ( QByteArray & & v ) ;
2017-03-09 18:13:55 +00:00
2014-05-30 08:53:19 +00:00
} ;
2017-03-10 19:46:28 +00:00
using MTPString = MTPBoxed < MTPstring > ;
using MTPBytes = MTPBoxed < MTPbytes > ;
2016-09-29 11:37:16 +00:00
inline MTPstring MTP_string ( const std : : string & v ) {
2017-03-10 19:46:28 +00:00
return MTPstring ( QByteArray ( v . data ( ) , v . size ( ) ) ) ;
2014-05-30 08:53:19 +00:00
}
inline MTPstring MTP_string ( const QString & v ) {
2017-03-10 19:46:28 +00:00
return MTPstring ( v . toUtf8 ( ) ) ;
2014-05-30 08:53:19 +00:00
}
inline MTPstring MTP_string ( const char * v ) {
2017-03-10 19:46:28 +00:00
return MTPstring ( QByteArray ( v , strlen ( v ) ) ) ;
2014-05-30 08:53:19 +00:00
}
2016-04-07 16:49:15 +00:00
MTPstring MTP_string ( const QByteArray & v ) = delete ;
2016-04-01 10:23:40 +00:00
inline MTPbytes MTP_bytes ( const QByteArray & v ) {
2017-03-10 19:46:28 +00:00
return MTPbytes ( QByteArray ( v ) ) ;
}
inline MTPbytes MTP_bytes ( QByteArray & & v ) {
return MTPbytes ( std : : move ( v ) ) ;
2016-04-01 10:23:40 +00:00
}
2014-05-30 08:53:19 +00:00
inline bool operator = = ( const MTPstring & a , const MTPstring & b ) {
2017-03-10 19:46:28 +00:00
return a . v = = b . v ;
2014-05-30 08:53:19 +00:00
}
inline bool operator ! = ( const MTPstring & a , const MTPstring & b ) {
2017-03-10 19:46:28 +00:00
return a . v ! = b . v ;
2014-05-30 08:53:19 +00:00
}
inline QString qs ( const MTPstring & v ) {
2017-03-10 19:46:28 +00:00
return QString : : fromUtf8 ( v . v ) ;
2015-01-02 14:55:24 +00:00
}
inline QByteArray qba ( const MTPstring & v ) {
2017-03-10 19:46:28 +00:00
return v . v ;
2014-05-30 08:53:19 +00:00
}
template < typename T >
2017-03-10 19:46:28 +00:00
class MTPvector {
2014-05-30 08:53:19 +00:00
public :
2017-03-09 19:15:31 +00:00
MTPvector ( ) = default ;
2014-05-30 08:53:19 +00:00
2014-11-14 23:23:35 +00:00
uint32 innerLength ( ) const {
2014-05-30 08:53:19 +00:00
uint32 result ( sizeof ( uint32 ) ) ;
2017-03-10 19:46:28 +00:00
for_const ( auto & item , v ) {
2017-03-09 18:13:55 +00:00
result + = item . innerLength ( ) ;
2014-05-30 08:53:19 +00:00
}
return result ;
}
mtpTypeId type ( ) const {
return mtpc_vector ;
}
void read ( const mtpPrime * & from , const mtpPrime * end , mtpTypeId cons = mtpc_vector ) {
if ( from + 1 > end ) throw mtpErrorInsufficient ( ) ;
if ( cons ! = mtpc_vector ) throw mtpErrorUnexpected ( cons , " MTPvector " ) ;
2017-03-09 19:15:31 +00:00
auto count = static_cast < uint32 > ( * ( from + + ) ) ;
2014-05-30 08:53:19 +00:00
2017-03-09 19:15:31 +00:00
auto vector = QVector < T > ( count , T ( ) ) ;
for ( auto & item : vector ) {
item . read ( from , end ) ;
2014-05-30 08:53:19 +00:00
}
2017-03-10 19:46:28 +00:00
v = std : : move ( vector ) ;
2014-05-30 08:53:19 +00:00
}
void write ( mtpBuffer & to ) const {
2017-03-10 19:46:28 +00:00
to . push_back ( v . size ( ) ) ;
for_const ( auto & item , v ) {
2017-03-09 18:13:55 +00:00
item . write ( to ) ;
2014-05-30 08:53:19 +00:00
}
}
2017-03-10 19:46:28 +00:00
QVector < T > v ;
2014-05-30 08:53:19 +00:00
private :
2017-03-10 19:46:28 +00:00
explicit MTPvector ( QVector < T > & & data ) : v ( std : : move ( data ) ) {
2014-05-30 08:53:19 +00:00
}
2016-03-20 08:16:35 +00:00
template < typename U >
friend MTPvector < U > MTP_vector ( uint32 count ) ;
template < typename U >
friend MTPvector < U > MTP_vector ( uint32 count , const U & value ) ;
template < typename U >
friend MTPvector < U > MTP_vector ( const QVector < U > & v ) ;
2017-03-09 18:13:55 +00:00
template < typename U >
friend MTPvector < U > MTP_vector ( QVector < U > & & v ) ;
2014-05-30 08:53:19 +00:00
} ;
template < typename T >
inline MTPvector < T > MTP_vector ( uint32 count ) {
2017-03-10 19:46:28 +00:00
return MTPvector < T > ( QVector < T > ( count ) ) ;
2014-05-30 08:53:19 +00:00
}
template < typename T >
2014-11-05 17:43:32 +00:00
inline MTPvector < T > MTP_vector ( uint32 count , const T & value ) {
2017-03-10 19:46:28 +00:00
return MTPvector < T > ( QVector < T > ( count , value ) ) ;
2014-11-05 17:43:32 +00:00
}
template < typename T >
2014-05-30 08:53:19 +00:00
inline MTPvector < T > MTP_vector ( const QVector < T > & v ) {
2017-03-10 19:46:28 +00:00
return MTPvector < T > ( QVector < T > ( v ) ) ;
2017-03-09 18:13:55 +00:00
}
template < typename T >
inline MTPvector < T > MTP_vector ( QVector < T > & & v ) {
2017-03-10 19:46:28 +00:00
return MTPvector < T > ( std : : move ( v ) ) ;
2014-05-30 08:53:19 +00:00
}
template < typename T >
2016-03-19 16:55:15 +00:00
using MTPVector = MTPBoxed < MTPvector < T > > ;
2014-05-30 08:53:19 +00:00
template < typename T >
inline bool operator = = ( const MTPvector < T > & a , const MTPvector < T > & b ) {
return a . c_vector ( ) . v = = b . c_vector ( ) . v ;
}
template < typename T >
inline bool operator ! = ( const MTPvector < T > & a , const MTPvector < T > & b ) {
return a . c_vector ( ) . v ! = b . c_vector ( ) . v ;
}
// Human-readable text serialization
2014-10-20 22:49:37 +00:00
template < typename Type >
QString mtpWrapNumber ( Type number , int32 base = 10 ) {
return QString : : number ( number , base ) ;
}
2014-05-30 08:53:19 +00:00
2014-10-20 22:49:37 +00:00
struct MTPStringLogger {
MTPStringLogger ( ) : p ( new char [ MTPDebugBufferSize ] ) , size ( 0 ) , alloced ( MTPDebugBufferSize ) {
}
~ MTPStringLogger ( ) {
delete [ ] p ;
}
2014-05-30 08:53:19 +00:00
2014-10-20 22:49:37 +00:00
MTPStringLogger & add ( const QString & data ) {
2017-03-09 18:13:55 +00:00
auto d = data . toUtf8 ( ) ;
2014-10-20 22:49:37 +00:00
return add ( d . constData ( ) , d . size ( ) ) ;
}
2014-05-30 08:53:19 +00:00
2014-10-20 22:49:37 +00:00
MTPStringLogger & add ( const char * data , int32 len = - 1 ) {
if ( len < 0 ) len = strlen ( data ) ;
if ( ! len ) return ( * this ) ;
2014-05-30 08:53:19 +00:00
2014-10-25 09:25:18 +00:00
ensureLength ( len ) ;
2014-10-20 22:49:37 +00:00
memcpy ( p + size , data , len ) ;
size + = len ;
return ( * this ) ;
}
2014-10-25 09:25:18 +00:00
MTPStringLogger & addSpaces ( int32 level ) {
int32 len = level * 2 ;
if ( ! len ) return ( * this ) ;
ensureLength ( len ) ;
for ( char * ptr = p + size , * end = ptr + len ; ptr ! = end ; + + ptr ) {
* ptr = ' ' ;
}
size + = len ;
return ( * this ) ;
}
void ensureLength ( int32 add ) {
if ( size + add < = alloced ) return ;
int32 newsize = size + add ;
if ( newsize % MTPDebugBufferSize ) newsize + = MTPDebugBufferSize - ( newsize % MTPDebugBufferSize ) ;
char * b = new char [ newsize ] ;
memcpy ( b , p , size ) ;
alloced = newsize ;
2016-03-24 13:27:34 +00:00
delete [ ] p ;
2014-10-25 09:25:18 +00:00
p = b ;
}
2014-10-20 22:49:37 +00:00
char * p ;
int32 size , alloced ;
} ;
2014-05-30 08:53:19 +00:00
2014-10-20 22:49:37 +00:00
void mtpTextSerializeType ( MTPStringLogger & to , const mtpPrime * & from , const mtpPrime * end , mtpPrime cons = 0 , uint32 level = 0 , mtpPrime vcons = 0 ) ;
2014-05-30 08:53:19 +00:00
2014-10-20 22:49:37 +00:00
void mtpTextSerializeCore ( MTPStringLogger & to , const mtpPrime * & from , const mtpPrime * end , mtpTypeId cons , uint32 level , mtpPrime vcons = 0 ) ;
2014-05-30 08:53:19 +00:00
2014-10-20 22:49:37 +00:00
inline QString mtpTextSerialize ( const mtpPrime * & from , const mtpPrime * end ) {
MTPStringLogger to ;
2015-10-03 10:09:09 +00:00
try {
mtpTextSerializeType ( to , from , end , mtpc_core_message ) ;
} catch ( Exception & e ) {
to . add ( " [ERROR] ( " ) . add ( e . what ( ) ) . add ( " ) " ) ;
}
2014-10-20 22:49:37 +00:00
return QString : : fromUtf8 ( to . p , to . size ) ;
2014-05-30 08:53:19 +00:00
}
2016-03-23 18:43:12 +00:00
# include "mtproto/scheme_auto.h"
2015-10-29 00:16:52 +00:00
inline MTPbool MTP_bool ( bool v ) {
return v ? MTP_boolTrue ( ) : MTP_boolFalse ( ) ;
}
inline bool mtpIsTrue ( const MTPBool & v ) {
return v . type ( ) = = mtpc_boolTrue ;
}
inline bool mtpIsFalse ( const MTPBool & v ) {
return ! mtpIsTrue ( v ) ;
}
2016-03-19 16:55:15 +00:00
// we must validate that MTProto scheme flags don't intersect with client side flags
// and define common bit operators which allow use Type_ClientFlag together with Type::Flag
# define DEFINE_MTP_CLIENT_FLAGS(Type) \
static_assert ( static_cast < int32 > ( Type : : Flag : : MAX_FIELD ) < static_cast < int32 > ( Type # # _ClientFlag : : MIN_FIELD ) , \
" MTProto flags conflict with client side flags! " ) ; \
inline Type : : Flags qFlags ( Type # # _ClientFlag v ) { return Type : : Flags ( static_cast < int32 > ( v ) ) ; } \
inline Type : : Flags operator & ( Type : : Flags i , Type # # _ClientFlag v ) { return i & qFlags ( v ) ; } \
inline Type : : Flags operator & ( Type # # _ClientFlag i , Type # # _ClientFlag v ) { return qFlags ( i ) & v ; } \
inline Type : : Flags & operator & = ( Type : : Flags & i , Type # # _ClientFlag v ) { return i & = qFlags ( v ) ; } \
inline Type : : Flags operator | ( Type : : Flags i , Type # # _ClientFlag v ) { return i | qFlags ( v ) ; } \
2016-09-29 11:37:16 +00:00
inline Type : : Flags operator | ( Type : : Flag i , Type # # _ClientFlag v ) { return i | qFlags ( v ) ; } \
2016-03-19 16:55:15 +00:00
inline Type : : Flags operator | ( Type # # _ClientFlag i , Type # # _ClientFlag v ) { return qFlags ( i ) | v ; } \
inline Type : : Flags operator | ( Type # # _ClientFlag i , Type : : Flag v ) { return qFlags ( i ) | v ; } \
inline Type : : Flags & operator | = ( Type : : Flags & i , Type # # _ClientFlag v ) { return i | = qFlags ( v ) ; } \
inline Type : : Flags operator ~ ( Type # # _ClientFlag v ) { return ~ qFlags ( v ) ; }
// we use the same flags field for some additional client side flags
enum class MTPDmessage_ClientFlag : int32 {
// message has links for "shared links" indexing
f_has_text_links = ( 1 < < 30 ) ,
// message is a group migrate (group -> supergroup) service message
f_is_group_migrate = ( 1 < < 29 ) ,
// message needs initDimensions() + resize() + paint()
f_pending_init_dimensions = ( 1 < < 28 ) ,
// message needs resize() + paint()
f_pending_resize = ( 1 < < 27 ) ,
// message needs paint()
f_pending_paint = ( 1 < < 26 ) ,
2016-03-21 18:40:00 +00:00
// message is attached to previous one when displaying the history
f_attach_to_previous = ( 1 < < 25 ) ,
2016-11-18 16:27:47 +00:00
// message is attached to next one when displaying the history
f_attach_to_next = ( 1 < < 24 ) ,
2016-04-06 08:00:37 +00:00
// message was sent from inline bot, need to re-set media when sent
2016-11-18 16:27:47 +00:00
f_from_inline_bot = ( 1 < < 23 ) ,
2016-04-06 08:00:37 +00:00
2016-04-08 14:16:52 +00:00
// message has a switch inline keyboard button, need to return to inline
2016-11-18 16:27:47 +00:00
f_has_switch_inline_button = ( 1 < < 22 ) ,
2016-04-08 14:16:52 +00:00
2016-05-20 16:01:06 +00:00
// message is generated on the client side and should be unread
2016-11-18 16:27:47 +00:00
f_clientside_unread = ( 1 < < 21 ) ,
2016-05-20 16:01:06 +00:00
2016-03-19 16:55:15 +00:00
// update this when adding new client side flags
2016-11-18 16:27:47 +00:00
MIN_FIELD = ( 1 < < 21 ) ,
2016-03-19 16:55:15 +00:00
} ;
DEFINE_MTP_CLIENT_FLAGS ( MTPDmessage )
enum class MTPDreplyKeyboardMarkup_ClientFlag : int32 {
// none (zero) markup
f_zero = ( 1 < < 30 ) ,
// markup just wants a text reply
f_force_reply = ( 1 < < 29 ) ,
2016-04-06 08:00:37 +00:00
// markup keyboard is inline
f_inline = ( 1 < < 28 ) ,
2016-04-08 14:16:52 +00:00
// markup has a switch inline keyboard button
f_has_switch_inline_button = ( 1 < < 27 ) ,
2016-03-19 16:55:15 +00:00
// update this when adding new client side flags
2016-04-08 14:16:52 +00:00
MIN_FIELD = ( 1 < < 27 ) ,
2016-03-19 16:55:15 +00:00
} ;
DEFINE_MTP_CLIENT_FLAGS ( MTPDreplyKeyboardMarkup )
enum class MTPDstickerSet_ClientFlag : int32 {
// old value for sticker set is not yet loaded flag
f_not_loaded__old = ( 1 < < 31 ) ,
// sticker set is not yet loaded
f_not_loaded = ( 1 < < 30 ) ,
2016-06-27 16:25:21 +00:00
// sticker set is one of featured (should be saved locally)
f_featured = ( 1 < < 29 ) ,
2016-06-28 18:05:38 +00:00
// sticker set is an unread featured set
f_unread = ( 1 < < 28 ) ,
2016-07-15 15:58:52 +00:00
// special set like recent or custom stickers
f_special = ( 1 < < 27 ) ,
2016-03-19 16:55:15 +00:00
// update this when adding new client side flags
2016-07-15 15:58:52 +00:00
MIN_FIELD = ( 1 < < 27 ) ,
2015-10-29 00:16:52 +00:00
} ;
2016-03-19 16:55:15 +00:00
DEFINE_MTP_CLIENT_FLAGS ( MTPDstickerSet )
2015-10-29 00:16:52 +00:00
2016-02-18 16:36:33 +00:00
extern const MTPReplyMarkup MTPnullMarkup ;
extern const MTPVector < MTPMessageEntity > MTPnullEntities ;
extern const MTPMessageFwdHeader MTPnullFwdHeader ;
2015-12-02 17:17:53 +00:00
2016-02-18 16:36:33 +00:00
QString stickerSetTitle ( const MTPDstickerSet & s ) ;
2016-03-24 08:57:11 +00:00
inline bool mtpRequestData : : isSentContainer ( const mtpRequest & request ) { // "request-like" wrap for msgIds vector
if ( request - > size ( ) < 9 ) return false ;
return ( ! request - > msDate & & ! ( * request ) [ 6 ] ) ; // msDate = 0, seqNo = 0
}
inline bool mtpRequestData : : isStateRequest ( const mtpRequest & request ) {
if ( request - > size ( ) < 9 ) return false ;
return ( mtpTypeId ( ( * request ) [ 8 ] ) = = mtpc_msgs_state_req ) ;
}
inline bool mtpRequestData : : needAck ( const mtpRequest & request ) {
if ( request - > size ( ) < 9 ) return false ;
return mtpRequestData : : needAckByType ( ( * request ) [ 8 ] ) ;
}
inline bool mtpRequestData : : needAckByType ( mtpTypeId type ) {
switch ( type ) {
case mtpc_msg_container :
case mtpc_msgs_ack :
case mtpc_http_wait :
case mtpc_bad_msg_notification :
case mtpc_msgs_all_info :
case mtpc_msgs_state_info :
case mtpc_msg_detailed_info :
case mtpc_msg_new_detailed_info :
return false ;
}
return true ;
}